├── .gitignore ├── README.md ├── db.sqlite3 ├── did_django_google_waypoints ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-37.pyc │ ├── settings.cpython-37.pyc │ ├── urls.cpython-37.pyc │ └── wsgi.cpython-37.pyc ├── asgi.py ├── settings.py ├── urls.py └── wsgi.py ├── main ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-37.pyc │ ├── admin.cpython-37.pyc │ ├── apps.cpython-37.pyc │ ├── mixins.cpython-37.pyc │ ├── models.cpython-37.pyc │ ├── urls.cpython-37.pyc │ └── views.cpython-37.pyc ├── admin.py ├── apps.py ├── migrations │ ├── __init__.py │ └── __pycache__ │ │ └── __init__.cpython-37.pyc ├── mixins.py ├── models.py ├── templates │ └── main │ │ ├── base.html │ │ ├── map.html │ │ ├── partials │ │ └── logo.html │ │ └── route.html ├── tests.py ├── urls.py └── views.py ├── manage.py ├── requirements.txt └── static ├── branding ├── did-logo.gif ├── did_logo.gif ├── did_logo.jpg ├── did_logo.mp4 └── did_logo.png ├── google_maps.js ├── google_places.js ├── main.css └── main.js /.gitignore: -------------------------------------------------------------------------------- 1 | settings.ini -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # did_django_google_waypoints 2 | Django project that uses Googles APIs to auto populate fields, display maps and routes for multiple waypoints 3 | 4 | 1) cd to development directory 5 | 2) mkvirtualenv did_django_google_maps_api 6 | 3) mkdir did_django_google_maps_api 7 | 4) clone repository to new directory 8 | 5) pip install -r requirements.txt 9 | 6) Create and update settings.ini with your email API information 10 | 11 | API_KEY = "XXX" 12 | 13 | 14 | 7) python manage.py makemigrations 15 | 8) python manage.py migrate 16 | 9) python manage.py runserver 17 | 10) https://localhost:8000 - Bob's your uncle!! 18 | 19 | Note: 20 | 21 | Don't forget to activate the following Google API's 22 | 23 | Places API 24 | Maps Javascript API 25 | Directions API 26 | Distance Matrix API 27 | Geocoding API 28 | 29 | 30 | -------------------------------------------------------------------------------- /db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/db.sqlite3 -------------------------------------------------------------------------------- /did_django_google_waypoints/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/did_django_google_waypoints/__init__.py -------------------------------------------------------------------------------- /did_django_google_waypoints/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/did_django_google_waypoints/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /did_django_google_waypoints/__pycache__/settings.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/did_django_google_waypoints/__pycache__/settings.cpython-37.pyc -------------------------------------------------------------------------------- /did_django_google_waypoints/__pycache__/urls.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/did_django_google_waypoints/__pycache__/urls.cpython-37.pyc -------------------------------------------------------------------------------- /did_django_google_waypoints/__pycache__/wsgi.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/did_django_google_waypoints/__pycache__/wsgi.cpython-37.pyc -------------------------------------------------------------------------------- /did_django_google_waypoints/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for did_django_google_waypoints project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'did_django_google_waypoints.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /did_django_google_waypoints/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for did_django_google_waypoints project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.2.2. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.2/ref/settings/ 11 | """ 12 | 13 | from pathlib import Path 14 | import os 15 | from decouple import config 16 | 17 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 18 | BASE_DIR = Path(__file__).resolve().parent.parent 19 | 20 | 21 | # Quick-start development settings - unsuitable for production 22 | # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ 23 | 24 | # SECURITY WARNING: keep the secret key used in production secret! 25 | SECRET_KEY = 'django-insecure-76-s$==ou!m4&tyq#mv0i2@n&*o)))-uw-ckquz%j*vg48()n7' 26 | 27 | # SECURITY WARNING: don't run with debug turned on in production! 28 | DEBUG = True 29 | 30 | ALLOWED_HOSTS = [] 31 | 32 | 33 | # Application definition 34 | 35 | INSTALLED_APPS = [ 36 | 'django.contrib.admin', 37 | 'django.contrib.auth', 38 | 'django.contrib.contenttypes', 39 | 'django.contrib.sessions', 40 | 'django.contrib.messages', 41 | 'django.contrib.staticfiles', 42 | 'main' 43 | ] 44 | 45 | MIDDLEWARE = [ 46 | 'django.middleware.security.SecurityMiddleware', 47 | 'django.contrib.sessions.middleware.SessionMiddleware', 48 | 'django.middleware.common.CommonMiddleware', 49 | 'django.middleware.csrf.CsrfViewMiddleware', 50 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 51 | 'django.contrib.messages.middleware.MessageMiddleware', 52 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 53 | ] 54 | 55 | ROOT_URLCONF = 'did_django_google_waypoints.urls' 56 | 57 | TEMPLATES = [ 58 | { 59 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 60 | 'DIRS': [], 61 | 'APP_DIRS': True, 62 | 'OPTIONS': { 63 | 'context_processors': [ 64 | 'django.template.context_processors.debug', 65 | 'django.template.context_processors.request', 66 | 'django.contrib.auth.context_processors.auth', 67 | 'django.contrib.messages.context_processors.messages', 68 | ], 69 | }, 70 | }, 71 | ] 72 | 73 | WSGI_APPLICATION = 'did_django_google_waypoints.wsgi.application' 74 | 75 | 76 | # Database 77 | # https://docs.djangoproject.com/en/3.2/ref/settings/#databases 78 | 79 | DATABASES = { 80 | 'default': { 81 | 'ENGINE': 'django.db.backends.sqlite3', 82 | 'NAME': BASE_DIR / 'db.sqlite3', 83 | } 84 | } 85 | 86 | 87 | # Password validation 88 | # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators 89 | 90 | AUTH_PASSWORD_VALIDATORS = [ 91 | { 92 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 93 | }, 94 | { 95 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 96 | }, 97 | { 98 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 99 | }, 100 | { 101 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 102 | }, 103 | ] 104 | 105 | 106 | # Internationalization 107 | # https://docs.djangoproject.com/en/3.2/topics/i18n/ 108 | 109 | LANGUAGE_CODE = 'en-gb' 110 | 111 | TIME_ZONE = 'UTC' 112 | 113 | USE_I18N = True 114 | 115 | USE_L10N = True 116 | 117 | USE_TZ = True 118 | 119 | 120 | # Static files (CSS, JavaScript, Images) 121 | # https://docs.djangoproject.com/en/3.2/howto/static-files/ 122 | STATICFILES_DIRS = [ 123 | os.path.join(BASE_DIR, "static") 124 | ] 125 | STATIC_URL = '/static/' 126 | STATIC_ROOT = os.path.join(BASE_DIR, "static_cdn") 127 | 128 | # Default primary key field type 129 | # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field 130 | 131 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 132 | 133 | API_KEY = config("API_KEY") 134 | -------------------------------------------------------------------------------- /did_django_google_waypoints/urls.py: -------------------------------------------------------------------------------- 1 | """did_django_google_waypoints URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.2/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path, include 18 | from django.conf import settings 19 | from django.conf.urls.static import static 20 | 21 | 22 | urlpatterns = [ 23 | path('', include('main.urls', namespace="main")), 24 | path('admin/', admin.site.urls), 25 | ] 26 | 27 | if settings.DEBUG: 28 | urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) -------------------------------------------------------------------------------- /did_django_google_waypoints/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for did_django_google_waypoints project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'did_django_google_waypoints.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /main/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/main/__init__.py -------------------------------------------------------------------------------- /main/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/main/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /main/__pycache__/admin.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/main/__pycache__/admin.cpython-37.pyc -------------------------------------------------------------------------------- /main/__pycache__/apps.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/main/__pycache__/apps.cpython-37.pyc -------------------------------------------------------------------------------- /main/__pycache__/mixins.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/main/__pycache__/mixins.cpython-37.pyc -------------------------------------------------------------------------------- /main/__pycache__/models.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/main/__pycache__/models.cpython-37.pyc -------------------------------------------------------------------------------- /main/__pycache__/urls.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/main/__pycache__/urls.cpython-37.pyc -------------------------------------------------------------------------------- /main/__pycache__/views.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/main/__pycache__/views.cpython-37.pyc -------------------------------------------------------------------------------- /main/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /main/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class MainConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'main' 7 | -------------------------------------------------------------------------------- /main/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/main/migrations/__init__.py -------------------------------------------------------------------------------- /main/migrations/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/main/migrations/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /main/mixins.py: -------------------------------------------------------------------------------- 1 | from django.conf import settings 2 | import requests 3 | import json 4 | import datetime 5 | from humanfriendly import format_timespan 6 | 7 | 8 | ''' 9 | Handles directions from Google 10 | ''' 11 | def Directions(*args, **kwargs): 12 | 13 | lat_a = kwargs.get("lat_a") 14 | long_a = kwargs.get("long_a") 15 | lat_b = kwargs.get("lat_b") 16 | long_b = kwargs.get("long_b") 17 | lat_c = kwargs.get("lat_c") 18 | long_c = kwargs.get("long_c") 19 | lat_d = kwargs.get("lat_d") 20 | long_d = kwargs.get("long_d") 21 | 22 | origin = f'{lat_a},{long_a}' 23 | destination = f'{lat_b},{long_b}' 24 | waypoints = f'{lat_c},{long_c}|{lat_d},{long_d}' 25 | 26 | result = requests.get( 27 | 'https://maps.googleapis.com/maps/api/directions/json?', 28 | params={ 29 | 'origin': origin, 30 | 'destination': destination, 31 | 'waypoints': waypoints, 32 | "key": settings.API_KEY 33 | }) 34 | 35 | directions = result.json() 36 | 37 | if directions["status"] == "OK": 38 | 39 | routes = directions["routes"][0]["legs"] 40 | 41 | 42 | distance = 0 43 | duration = 0 44 | route_list = [] 45 | 46 | for route in range(len(routes)): 47 | 48 | distance += int(routes[route]["distance"]["value"]) 49 | duration += int(routes[route]["duration"]["value"]) 50 | 51 | route_step = { 52 | 'origin': routes[route]["start_address"], 53 | 'destination': routes[route]["end_address"], 54 | 'distance': routes[route]["distance"]["text"], 55 | 'duration': routes[route]["duration"]["text"], 56 | 57 | 'steps': [ 58 | [ 59 | s["distance"]["text"], 60 | s["duration"]["text"], 61 | s["html_instructions"], 62 | 63 | ] 64 | for s in routes[route]["steps"]] 65 | } 66 | 67 | 68 | route_list.append(route_step) 69 | 70 | 71 | return { 72 | "origin": origin, 73 | "destination": destination, 74 | "distance": f"{round(distance/1000, 2)} Km", 75 | "duration": format_timespan(duration), 76 | "route": route_list 77 | } -------------------------------------------------------------------------------- /main/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /main/templates/main/base.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {% block extend_head %} 15 | 16 | {% endblock %} 17 | 18 | 19 | 20 | 21 | 22 | {% block extend_nav %} 23 | 24 | {% endblock %} 25 | 26 |
27 | 28 | {% include 'main/partials/logo.html' %} 29 | 30 | {% block content %} 31 | 32 | {% endblock %} 33 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | {% block extend_footer %} 41 | 42 | {% endblock %} 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /main/templates/main/map.html: -------------------------------------------------------------------------------- 1 | {% extends 'main/base.html' %} 2 | {% load static %} 3 | 4 | 5 | {% block extend_head %} 6 | 7 | 8 | 9 | 10 | 11 | {% endblock %} 12 | 13 | {% block extend_nav %} 14 | 15 | 19 | 20 | {% endblock %} 21 | 22 | 23 | {% block content %} 24 | 25 |

Django Google Maps Waypoints API Demo - Map

26 | 27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
Field
Start{{directions.origin}}
Destination{{directions.destination}}
Duration{{directions.duration}}
Distance{{directions.distance}}
Directionsclick here
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | {% for leg in directions.route %} 71 | 72 | 73 | 74 | 75 | 76 | {% for dist, dur, text in leg.steps %} 77 | 78 | 79 | 80 | 81 | 82 | {% endfor %} 83 | {% endfor %} 84 | 85 | 86 | 87 |
88 | 89 |
90 | 91 |
92 | 93 | 94 |
95 | 96 | {% endblock %} 97 | 98 | {% block extend_footer %} 99 | 100 | 101 | 117 | 118 | 119 | 120 | 121 | {% endblock %} -------------------------------------------------------------------------------- /main/templates/main/partials/logo.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 6 | -------------------------------------------------------------------------------- /main/templates/main/route.html: -------------------------------------------------------------------------------- 1 | {% extends 'main/base.html' %} 2 | {% load static %} 3 | 4 | 5 | {% block extend_head %} 6 | 7 | 8 | 9 | {% endblock %} 10 | 11 | {% block extend_nav %} 12 | 13 | 17 | 18 | {% endblock %} 19 | 20 | 21 | {% block content %} 22 | 23 |

Django Google Maps Waypoints API Demo - Routing

24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
53 | 54 | {% endblock %} 55 | 56 | {% block extend_footer %} 57 | 58 | 59 | 64 | 65 | 66 | 67 | 68 | {% endblock %} -------------------------------------------------------------------------------- /main/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /main/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | app_name = "main" 5 | 6 | 7 | urlpatterns = [ 8 | path('', views.route, name="route"), 9 | path('map', views.map, name="map"), 10 | ] 11 | -------------------------------------------------------------------------------- /main/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render, redirect, reverse 2 | from django.conf import settings 3 | 4 | from .mixins import Directions 5 | ''' 6 | Basic view for routing 7 | ''' 8 | def route(request): 9 | 10 | context = {"google_api_key": settings.API_KEY} 11 | return render(request, 'main/route.html', context) 12 | 13 | 14 | ''' 15 | Basic view for displaying a map 16 | ''' 17 | def map(request): 18 | 19 | lat_a = request.GET.get("lat_a", None) 20 | long_a = request.GET.get("long_a", None) 21 | lat_b = request.GET.get("lat_b", None) 22 | long_b = request.GET.get("long_b", None) 23 | lat_c = request.GET.get("lat_c", None) 24 | long_c = request.GET.get("long_c", None) 25 | lat_d = request.GET.get("lat_d", None) 26 | long_d = request.GET.get("long_d", None) 27 | 28 | 29 | #only call API if all 4 addresses are added 30 | if lat_a and lat_b and lat_c and lat_d: 31 | directions = Directions( 32 | lat_a= lat_a, 33 | long_a=long_a, 34 | lat_b = lat_b, 35 | long_b=long_b, 36 | lat_c= lat_c, 37 | long_c=long_c, 38 | lat_d = lat_d, 39 | long_d=long_d 40 | ) 41 | else: 42 | return redirect(reverse('main:route')) 43 | 44 | context = { 45 | "google_api_key": settings.API_KEY, 46 | "lat_a": lat_a, 47 | "long_a": long_a, 48 | "lat_b": lat_b, 49 | "long_b": long_b, 50 | "lat_c": lat_c, 51 | "long_c": long_c, 52 | "lat_d": lat_d, 53 | "long_d": long_d, 54 | "origin": f'{lat_a}, {long_a}', 55 | "destination": f'{lat_b}, {long_b}', 56 | "directions": directions, 57 | 58 | } 59 | return render(request, 'main/map.html', context) 60 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'did_django_google_waypoints.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.3.4 2 | certifi==2020.12.5 3 | chardet==4.0.0 4 | Django==3.2.2 5 | django-decouple==2.1 6 | humanfriendly==9.1 7 | idna==2.10 8 | pyreadline==2.1 9 | pytz==2021.1 10 | requests==2.25.1 11 | sqlparse==0.4.1 12 | typing-extensions==3.10.0.0 13 | urllib3==1.26.4 14 | -------------------------------------------------------------------------------- /static/branding/did-logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/static/branding/did-logo.gif -------------------------------------------------------------------------------- /static/branding/did_logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/static/branding/did_logo.gif -------------------------------------------------------------------------------- /static/branding/did_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/static/branding/did_logo.jpg -------------------------------------------------------------------------------- /static/branding/did_logo.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/static/branding/did_logo.mp4 -------------------------------------------------------------------------------- /static/branding/did_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobby-didcoding/did_django_google_waypoints/7da71f9befcf76599b15baf15cded4485cc03e90/static/branding/did_logo.png -------------------------------------------------------------------------------- /static/google_maps.js: -------------------------------------------------------------------------------- 1 | 2 | $.getScript( "https://maps.googleapis.com/maps/api/js?key=" + google_api_key + "&libraries=places") 3 | .done(function( script, textStatus ) { 4 | google.maps.event.addDomListener(window, "load", initMap) 5 | 6 | }) 7 | 8 | 9 | function initMap() { 10 | var directionsService = new google.maps.DirectionsService; 11 | var directionsDisplay = new google.maps.DirectionsRenderer; 12 | var map = new google.maps.Map(document.getElementById('map-route'), { 13 | zoom: 7, 14 | center: {lat: lat_a, lng: long_a} 15 | }); 16 | directionsDisplay.setMap(map); 17 | calculateAndDisplayRoute(directionsService, directionsDisplay); 18 | 19 | } 20 | 21 | const waypts = [ 22 | {location: {lat: lat_c, lng: long_c}, 23 | stopover: true}, 24 | {location: {lat: lat_d, lng: long_d}, 25 | stopover: true} 26 | ]; 27 | 28 | function calculateAndDisplayRoute(directionsService, directionsDisplay) { 29 | directionsService.route({ 30 | origin: origin, 31 | destination: destination, 32 | waypoints: waypts, 33 | optimizeWaypoints: true, 34 | travelMode: google.maps.TravelMode.DRIVING, 35 | }, function(response, status) { 36 | if (status === 'OK') { 37 | directionsDisplay.setDirections(response); 38 | 39 | 40 | } else { 41 | 42 | alert('Directions request failed due to ' + status); 43 | window.location.assign("/route") 44 | } 45 | }); 46 | } -------------------------------------------------------------------------------- /static/google_places.js: -------------------------------------------------------------------------------- 1 | 2 | $.getScript( "https://maps.googleapis.com/maps/api/js?key=" + google_api_key + "&libraries=places") 3 | .done(function( script, textStatus ) { 4 | google.maps.event.addDomListener(window, "load", initAutocomplete()) 5 | 6 | }) 7 | 8 | var auto_fields = ['a', 'b', 'c', 'd'] 9 | 10 | function initAutocomplete() { 11 | 12 | for (i = 0; i < auto_fields.length; i++) { 13 | var field = auto_fields[i] 14 | window['autocomplete_'+field] = new google.maps.places.Autocomplete( 15 | document.getElementById('id-google-address-' + field), 16 | { 17 | types: ['address'], 18 | componentRestrictions: {'country': ['uk']}, 19 | }) 20 | } 21 | 22 | autocomplete_a.addListener('place_changed', function(){ 23 | onPlaceChanged('a') 24 | }); 25 | autocomplete_b.addListener('place_changed', function(){ 26 | onPlaceChanged('b') 27 | }); 28 | autocomplete_c.addListener('place_changed', function(){ 29 | onPlaceChanged('c') 30 | }); 31 | autocomplete_d.addListener('place_changed', function(){ 32 | onPlaceChanged('d') 33 | }); 34 | } 35 | 36 | 37 | function onPlaceChanged (addy){ 38 | 39 | var auto = window['autocomplete_'+addy] 40 | var el_id = 'id-google-address-'+addy 41 | var lat_id = 'id-lat-' + addy 42 | var long_id = 'id-long-' + addy 43 | 44 | var geocoder = new google.maps.Geocoder() 45 | var address = document.getElementById(el_id).value 46 | 47 | geocoder.geocode( { 'address': address}, function(results, status) { 48 | 49 | if (status == google.maps.GeocoderStatus.OK) { 50 | var latitude = results[0].geometry.location.lat(); 51 | var longitude = results[0].geometry.location.lng(); 52 | 53 | $('#' + lat_id).val(latitude) 54 | $('#' + long_id).val(longitude) 55 | 56 | CalcRoute() 57 | } 58 | }); 59 | } 60 | 61 | 62 | function validateForm() { 63 | var valid = true; 64 | $('.geo').each(function () { 65 | if ($(this).val() === '') { 66 | valid = false; 67 | return false; 68 | } 69 | }); 70 | return valid 71 | } 72 | 73 | 74 | function CalcRoute(){ 75 | 76 | if ( validateForm() == true){ 77 | var params = { 78 | lat_a: $('#id-lat-a').val(), 79 | long_a: $('#id-long-a').val(), 80 | lat_b: $('#id-lat-b').val(), 81 | long_b: $('#id-long-b').val(), 82 | lat_c: $('#id-lat-c').val(), 83 | long_c: $('#id-long-c').val(), 84 | lat_d: $('#id-lat-d').val(), 85 | long_d: $('#id-long-d').val(), 86 | }; 87 | 88 | var esc = encodeURIComponent; 89 | var query = Object.keys(params) 90 | .map(k => esc(k) + '=' + esc(params[k])) 91 | .join('&'); 92 | 93 | url = '/map?' + query 94 | window.location.assign(url) 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /static/main.css: -------------------------------------------------------------------------------- 1 | body {font-family: 'Courier Prime', monospace;} 2 | * {box-sizing: border-box;} 3 | 4 | body { 5 | 6 | margin: 0; 7 | } 8 | 9 | body, html, .map-container { 10 | height: 100%; 11 | } 12 | 13 | #map-route { 14 | height: 75%; 15 | } 16 | 17 | .logo { 18 | width: 150px; 19 | padding: 8px; 20 | } 21 | 22 | 23 | ul.sidenav { 24 | list-style-type: none; 25 | margin: 0; 26 | padding: 0; 27 | width: 25%; 28 | background-color: #f1f1f1; 29 | position: fixed; 30 | height: 100%; 31 | overflow: auto; 32 | } 33 | 34 | ul.sidenav li a { 35 | display: block; 36 | color: #000; 37 | padding: 8px 16px; 38 | text-decoration: none; 39 | } 40 | 41 | ul.sidenav li a.active { 42 | background-color: #9c07b6; 43 | color: white; 44 | } 45 | 46 | ul.sidenav li a:hover:not(.active) { 47 | background-color: #555; 48 | color: white; 49 | } 50 | 51 | .div-container { 52 | 53 | margin-left: 25%; 54 | padding: 1px 16px; 55 | height: 1000px; 56 | } 57 | 58 | @media screen and (max-width: 900px) { 59 | ul.sidenav { 60 | width: 100%; 61 | height: auto; 62 | position: relative; 63 | } 64 | 65 | ul.sidenav li a { 66 | float: left; 67 | padding: 15px; 68 | } 69 | 70 | .div-container {margin-left: 0;} 71 | } 72 | 73 | @media screen and (max-width: 400px) { 74 | ul.sidenav li a { 75 | text-align: center; 76 | float: none; 77 | } 78 | } 79 | 80 | input[type=text], input[type=email], input[type=password], select, textarea { 81 | width: 100%; 82 | padding: 12px; 83 | border: 1px solid #ccc; 84 | border-radius: 4px; 85 | box-sizing: border-box; 86 | margin-top: 6px; 87 | margin-bottom: 16px; 88 | resize: vertical; 89 | } 90 | 91 | 92 | ::-webkit-input-placeholder { /* Edge */ 93 | color: #9c07b6; 94 | font-family: 'Courier Prime', monospace; 95 | } 96 | 97 | :-ms-input-placeholder { /* Internet Explorer */ 98 | color: #9c07b6; 99 | font-family: 'Courier Prime', monospace; 100 | } 101 | 102 | ::placeholder { 103 | color: #9c07b6; 104 | font-family: 'Courier Prime', monospace; 105 | } 106 | 107 | select.selection option, 108 | { 109 | color: #9c07b6; 110 | font-family: 'Courier Prime', monospace; 111 | } 112 | 113 | input, select{ 114 | color: #9c07b6; 115 | font-family: 'Courier Prime', monospace; 116 | 117 | } 118 | 119 | /* The container */ 120 | .check-container { 121 | display: block; 122 | position: relative; 123 | padding-left: 35px; 124 | margin-bottom: 12px; 125 | cursor: pointer; 126 | -webkit-user-select: none; 127 | -moz-user-select: none; 128 | -ms-user-select: none; 129 | user-select: none; 130 | } 131 | 132 | /* Hide the browser's default checkbox */ 133 | .check-container input { 134 | position: absolute; 135 | opacity: 0; 136 | cursor: pointer; 137 | height: 0; 138 | width: 0; 139 | } 140 | 141 | /* Create a custom checkbox */ 142 | .checkmark { 143 | position: absolute; 144 | top: 0; 145 | left: 0; 146 | height: 15px; 147 | width: 15px; 148 | background-color: #fff; 149 | } 150 | 151 | /* On mouse-over, add a grey background color */ 152 | .check-container:hover input ~ .checkmark { 153 | background-color: #ccc; 154 | } 155 | 156 | /* When the checkbox is checked, add a green background */ 157 | .check-container input:checked ~ .checkmark { 158 | background-color: #9c07b6; 159 | } 160 | 161 | /* Create the checkmark/indicator (hidden when not checked) */ 162 | .check-container:after { 163 | content: ""; 164 | position: absolute; 165 | display: none; 166 | } 167 | 168 | /* Show the checkmark when checked */ 169 | .check-container input:checked ~ .checkmark:after { 170 | display: block; 171 | } 172 | 173 | /* Style the checkmark/indicator */ 174 | .check-container .checkmark:after { 175 | left: 9px; 176 | top: 5px; 177 | width: 5px; 178 | height: 10px; 179 | border: solid white; 180 | border-width: 0 3px 3px 0; 181 | -webkit-transform: rotate(45deg); 182 | -ms-transform: rotate(45deg); 183 | transform: rotate(45deg); 184 | } 185 | 186 | .switch { 187 | position: relative; 188 | display: inline-block; 189 | width: 60px; 190 | height: 34px; 191 | } 192 | 193 | /* Hide default HTML checkbox */ 194 | .switch input { 195 | opacity: 0; 196 | width: 0; 197 | height: 0; 198 | } 199 | 200 | /* The slider */ 201 | .slider { 202 | position: absolute; 203 | cursor: pointer; 204 | top: 0; 205 | left: 0; 206 | right: 0; 207 | bottom: 0; 208 | background-color: #ccc; 209 | -webkit-transition: .4s; 210 | transition: .4s; 211 | } 212 | 213 | .slider:before { 214 | position: absolute; 215 | content: ""; 216 | height: 26px; 217 | width: 26px; 218 | left: 4px; 219 | bottom: 4px; 220 | background-color: white; 221 | -webkit-transition: .4s; 222 | transition: .4s; 223 | } 224 | 225 | input:checked + .slider { 226 | background-color: #9c07b6; 227 | } 228 | 229 | input:focus + .slider { 230 | box-shadow: 0 0 1px #9c07b6; 231 | } 232 | 233 | input:checked + .slider:before { 234 | -webkit-transform: translateX(26px); 235 | -ms-transform: translateX(26px); 236 | transform: translateX(26px); 237 | } 238 | 239 | /* Rounded sliders */ 240 | .slider.round { 241 | border-radius: 34px; 242 | } 243 | 244 | .slider.round:before { 245 | border-radius: 50%; 246 | } 247 | 248 | button[type=submit] { 249 | background-color: #9c07b6; 250 | color: white; 251 | padding: 12px 20px; 252 | border: none; 253 | border-radius: 4px; 254 | cursor: pointer; 255 | } 256 | 257 | button[type=submit]:hover { 258 | background-color: #730786; 259 | } 260 | 261 | .container { 262 | border-radius: 5px; 263 | background-color: #f2f2f2; 264 | padding: 20px; 265 | } 266 | 267 | table { 268 | font-family: 'Courier Prime', monospace; 269 | border-collapse: collapse; 270 | width: 100%; 271 | } 272 | 273 | table td, table th { 274 | border: 1px solid #ddd; 275 | padding: 8px; 276 | } 277 | 278 | table tr:hover {background-color: #ddd;} 279 | 280 | table th { 281 | padding-top: 12px; 282 | padding-bottom: 12px; 283 | text-align: left; 284 | background-color: #9c07b6; 285 | color: white; 286 | } 287 | 288 | .selected { 289 | background-color: #730786; 290 | color: #FFF; 291 | } 292 | 293 | #payment-form { 294 | width: 100%; 295 | } 296 | 297 | /* style inputs and link buttons */ 298 | input, select, 299 | .btn { 300 | width: 100%; 301 | padding: 12px; 302 | border: none; 303 | border-radius: 4px; 304 | margin: 5px 0; 305 | opacity: 0.85; 306 | display: inline-block; 307 | font-size: 17px; 308 | line-height: 20px; 309 | text-decoration: none; /* remove underline from anchors */ 310 | } 311 | 312 | input:hover, 313 | .btn:hover { 314 | opacity: 1; 315 | } -------------------------------------------------------------------------------- /static/main.js: -------------------------------------------------------------------------------- 1 | function DirectionsToggle(){ 2 | var el = $('#dir-toggle'); 3 | var dir_table = $('#dir-table') 4 | if (dir_table.attr("hidden") == "hidden") { 5 | dir_table.fadeIn() 6 | dir_table.removeAttr("hidden") 7 | el.html('hide here') 8 | } else { 9 | dir_table.fadeOut() 10 | dir_table.attr("hidden", "hidden") 11 | el.html('click here') 12 | } 13 | } 14 | 15 | // 99978 16 | 17 | --------------------------------------------------------------------------------