From 674fdfdd2ede403fb865c25ee1d152f5b8663675 Mon Sep 17 00:00:00 2001 From: Paolo Pasquali Date: Fri, 30 Jun 2017 12:21:34 +0200 Subject: [PATCH 01/70] Add charts app --- charts-prj/__init__.py | 0 charts-prj/settings.py | 58 ++ charts-prj/static/README | 8 + charts-prj/static/css/site_base.css | 0 charts-prj/static/img/README | 0 charts-prj/static/js/README | 0 charts-prj/templates/_actions.html | 24 + charts-prj/templates/geonode_base.html | 4 + charts-prj/templates/site_base.html | 12 + charts-prj/templates/site_index.html | 15 + charts-prj/testing_settings.py | 109 +++ charts-prj/urls.py | 13 + charts-prj/wsgi.py | 31 + charts_app/__init__.py | 0 charts_app/admin.py | 10 + charts_app/migrations/0001_initial.py | 27 + charts_app/migrations/__init__.py | 0 charts_app/models.py | 53 ++ charts_app/templates/donut_chart_v1.html | 68 ++ charts_app/templates/donut_chart_v2.html | 169 +++++ charts_app/templates/pie_chart_v1.html | 65 ++ charts_app/templates/pie_chart_v2.html | 67 ++ charts_app/tests.py | 3 + charts_app/urls.py | 15 + charts_app/views.py | 123 +++ haitidata/settings.py | 4 +- haitidata/static/css/haitidata.css | 31 +- haitidata/static/css/index.css | 45 ++ haitidata/static/js/bar.js | 184 +++++ haitidata/static/js/csv.js | 151 ++++ haitidata/static/js/donut.js | 415 ++++++++++ haitidata/static/js/line.js | 179 +++++ haitidata/static/js/pie.js | 416 ++++++++++ haitidata/static/less/haitidata.less | 37 +- .../templates/charts_app/chart_base.html | 12 + .../charts_app/chart_confirm_delete.html | 5 + .../templates/charts_app/chart_detail.html | 106 +++ .../templates/charts_app/chart_form.html | 87 +++ .../charts_app/chart_main_script.html | 24 + .../charts_app/chart_update_form.html | 94 +++ .../{layers => layers-paolo}/layer_base.html | 0 .../layer_change_poc.html | 0 .../templates/layers-paolo/layer_detail.html | 708 ++++++++++++++++++ .../layers-paolo/layer_detail.html.save | 601 +++++++++++++++ .../layer_geoext_map.html | 0 .../layer_granule_remove.html | 0 .../layer_leaflet_map.html | 0 .../{layers => layers-paolo}/layer_list.html | 0 .../{layers => layers-paolo}/layer_map.html | 0 .../layer_metadata.html | 0 .../layer_metadata_detail.html | 0 .../layer_ol3_map.html | 0 .../layer_remove.html | 0 .../layer_replace.html | 0 .../layer_style_manage.html | 0 .../wps_execute_gs_aggregate.xml | 0 .../wps_execute_gs_unique.xml | 0 haitidata/templates/layers/layer_detail.html | 258 ++++++- haitidata/templates/site_base.html | 148 ++-- haitidata/urls.py | 5 +- wfs_harvest/__init__.py | 0 wfs_harvest/admin.py | 3 + wfs_harvest/migrations/__init__.py | 0 wfs_harvest/models.py | 3 + .../templates/wfs-harvest/field_choice.html | 41 + wfs_harvest/tests.py | 20 + wfs_harvest/urls.py | 8 + wfs_harvest/utils.py | 56 ++ wfs_harvest/views.py | 69 ++ 69 files changed, 4472 insertions(+), 112 deletions(-) create mode 100644 charts-prj/__init__.py create mode 100644 charts-prj/settings.py create mode 100644 charts-prj/static/README create mode 100644 charts-prj/static/css/site_base.css create mode 100644 charts-prj/static/img/README create mode 100644 charts-prj/static/js/README create mode 100644 charts-prj/templates/_actions.html create mode 100644 charts-prj/templates/geonode_base.html create mode 100644 charts-prj/templates/site_base.html create mode 100644 charts-prj/templates/site_index.html create mode 100644 charts-prj/testing_settings.py create mode 100644 charts-prj/urls.py create mode 100644 charts-prj/wsgi.py create mode 100644 charts_app/__init__.py create mode 100644 charts_app/admin.py create mode 100644 charts_app/migrations/0001_initial.py create mode 100644 charts_app/migrations/__init__.py create mode 100644 charts_app/models.py create mode 100644 charts_app/templates/donut_chart_v1.html create mode 100644 charts_app/templates/donut_chart_v2.html create mode 100644 charts_app/templates/pie_chart_v1.html create mode 100644 charts_app/templates/pie_chart_v2.html create mode 100644 charts_app/tests.py create mode 100644 charts_app/urls.py create mode 100644 charts_app/views.py create mode 100644 haitidata/static/css/index.css create mode 100644 haitidata/static/js/bar.js create mode 100644 haitidata/static/js/csv.js create mode 100644 haitidata/static/js/donut.js create mode 100644 haitidata/static/js/line.js create mode 100644 haitidata/static/js/pie.js create mode 100644 haitidata/templates/charts_app/chart_base.html create mode 100644 haitidata/templates/charts_app/chart_confirm_delete.html create mode 100644 haitidata/templates/charts_app/chart_detail.html create mode 100644 haitidata/templates/charts_app/chart_form.html create mode 100644 haitidata/templates/charts_app/chart_main_script.html create mode 100644 haitidata/templates/charts_app/chart_update_form.html rename haitidata/templates/{layers => layers-paolo}/layer_base.html (100%) rename haitidata/templates/{layers => layers-paolo}/layer_change_poc.html (100%) create mode 100644 haitidata/templates/layers-paolo/layer_detail.html create mode 100644 haitidata/templates/layers-paolo/layer_detail.html.save rename haitidata/templates/{layers => layers-paolo}/layer_geoext_map.html (100%) rename haitidata/templates/{layers => layers-paolo}/layer_granule_remove.html (100%) rename haitidata/templates/{layers => layers-paolo}/layer_leaflet_map.html (100%) rename haitidata/templates/{layers => layers-paolo}/layer_list.html (100%) rename haitidata/templates/{layers => layers-paolo}/layer_map.html (100%) rename haitidata/templates/{layers => layers-paolo}/layer_metadata.html (100%) rename haitidata/templates/{layers => layers-paolo}/layer_metadata_detail.html (100%) rename haitidata/templates/{layers => layers-paolo}/layer_ol3_map.html (100%) rename haitidata/templates/{layers => layers-paolo}/layer_remove.html (100%) rename haitidata/templates/{layers => layers-paolo}/layer_replace.html (100%) rename haitidata/templates/{layers => layers-paolo}/layer_style_manage.html (100%) rename haitidata/templates/{layers => layers-paolo}/wps_execute_gs_aggregate.xml (100%) rename haitidata/templates/{layers => layers-paolo}/wps_execute_gs_unique.xml (100%) create mode 100644 wfs_harvest/__init__.py create mode 100644 wfs_harvest/admin.py create mode 100644 wfs_harvest/migrations/__init__.py create mode 100644 wfs_harvest/models.py create mode 100644 wfs_harvest/templates/wfs-harvest/field_choice.html create mode 100644 wfs_harvest/tests.py create mode 100644 wfs_harvest/urls.py create mode 100644 wfs_harvest/utils.py create mode 100644 wfs_harvest/views.py diff --git a/charts-prj/__init__.py b/charts-prj/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/charts-prj/settings.py b/charts-prj/settings.py new file mode 100644 index 0000000..19b5894 --- /dev/null +++ b/charts-prj/settings.py @@ -0,0 +1,58 @@ +""" +Django settings for charts project. + +Generated by 'django-admin startproject' using Django 1.8.7. + +For more information on this file, see +https://docs.djangoproject.com/en/1.8/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.8/ref/settings/ +""" + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +import os +from geonode.settings import * + +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +SITENAME = 'charts-prj' + +LOCAL_ROOT = os.path.abspath(os.path.dirname(__file__)) + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '*u(5zzp_wjj!^!w4$h@e#jv!*y02z17lb8gu-l)j+*79p^r8%(' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +# Application definition + +INSTALLED_APPS = INSTALLED_APPS + ( + 'charts_app', + 'wfs_harvest' +) + +WSGI_APPLICATION = 'charts-prj.wsgi.application' + +# Additional directories which hold static files +STATICFILES_DIRS.append( + os.path.join(LOCAL_ROOT, "static"), +) + +# Location of url mappings +ROOT_URLCONF = 'charts-prj.urls' + +# Location of locale files +LOCALE_PATHS = ( + os.path.join(LOCAL_ROOT, 'locale'), + ) + LOCALE_PATHS + +TEMPLATES[0]['DIRS'].insert(0, os.path.join(LOCAL_ROOT, "templates")) + +MAX_CSV_RECORDS = 20000 + +ALLOWED_HOSTS = ['*'] +PROXY_ALLOWED_HOSTS = ['*'] diff --git a/charts-prj/static/README b/charts-prj/static/README new file mode 100644 index 0000000..a0fd00c --- /dev/null +++ b/charts-prj/static/README @@ -0,0 +1,8 @@ +This directory is used to store static assets for your project. User media files +(FileFields/ImageFields) are not stored here. + +The convention for this directory is: + + * css/ — stores CSS files + * js/ — stores Javascript files + * img/ — stores image files diff --git a/charts-prj/static/css/site_base.css b/charts-prj/static/css/site_base.css new file mode 100644 index 0000000..e69de29 diff --git a/charts-prj/static/img/README b/charts-prj/static/img/README new file mode 100644 index 0000000..e69de29 diff --git a/charts-prj/static/js/README b/charts-prj/static/js/README new file mode 100644 index 0000000..e69de29 diff --git a/charts-prj/templates/_actions.html b/charts-prj/templates/_actions.html new file mode 100644 index 0000000..7e96144 --- /dev/null +++ b/charts-prj/templates/_actions.html @@ -0,0 +1,24 @@ +{% load i18n %} + diff --git a/charts-prj/templates/geonode_base.html b/charts-prj/templates/geonode_base.html new file mode 100644 index 0000000..80d77ad --- /dev/null +++ b/charts-prj/templates/geonode_base.html @@ -0,0 +1,4 @@ +{% extends "site_base.html" %} + +{% load i18n %} +{% load staticfiles %} diff --git a/charts-prj/templates/site_base.html b/charts-prj/templates/site_base.html new file mode 100644 index 0000000..e6eab01 --- /dev/null +++ b/charts-prj/templates/site_base.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} +{% block extra_head %} + +{% endblock %} +{% block extra_tab %} +{% comment %} +Add Tab for Third Party Apps +
  • + App +
  • +{% endcomment %} +{% endblock %} diff --git a/charts-prj/templates/site_index.html b/charts-prj/templates/site_index.html new file mode 100644 index 0000000..b0d3f4e --- /dev/null +++ b/charts-prj/templates/site_index.html @@ -0,0 +1,15 @@ +{% extends 'index.html' %} +{% load i18n %} +{% comment %} +This is where you can override the hero area block. You can simply modify the content below or replace it wholesale to meet your own needs. +{% endcomment %} + {% block hero %} +
    +
    +

    {% trans "Welcome to the charts GeoNode" %}

    +

    {% blocktrans %}GeoNode is an open source platform for sharing geospatial data and maps.{% endblocktrans %}

    +

    {% blocktrans %}If you have any questions about the software or service, join our mailing list.{% endblocktrans %}

    + {% trans 'Need help?' %} {% trans 'Getting Started' %} +
    +
    + {% endblock %} diff --git a/charts-prj/testing_settings.py b/charts-prj/testing_settings.py new file mode 100644 index 0000000..cb93e74 --- /dev/null +++ b/charts-prj/testing_settings.py @@ -0,0 +1,109 @@ +""" +Django settings for pippo project. + +Generated by 'django-admin startproject' using Django 1.8.7. + +For more information on this file, see +https://docs.djangoproject.com/en/1.8/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.8/ref/settings/ +""" + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +import os + +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '5i81&t!#h$4ie!-kg$&@5b-1j*)d9@(6)8g8o4kg*xw3i2e=@t' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = ( + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', +) + +MIDDLEWARE_CLASSES = ( + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'django.middleware.security.SecurityMiddleware', +) + +ROOT_URLCONF = 'charts-prj.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'charts-prj.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/1.8/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} + + +# Internationalization +# https://docs.djangoproject.com/en/1.8/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.8/howto/static-files/ + +STATIC_URL = '/static/' + +ANONYMOUS_USER_ID = 1 + +LOCAL_MEDIA_URL = '' +API_INCLUDE_REGIONS_COUNT = '' +HAYSTACK_SEARCH = '' +RESOURCE_PUBLISHING = '' \ No newline at end of file diff --git a/charts-prj/urls.py b/charts-prj/urls.py new file mode 100644 index 0000000..ee7151d --- /dev/null +++ b/charts-prj/urls.py @@ -0,0 +1,13 @@ +from django.conf.urls import patterns, url +from django.views.generic import TemplateView + +from geonode.urls import * + +urlpatterns = patterns('', + url(r'^/?$', + TemplateView.as_view(template_name='site_index.html'), + name='home'), + ) + urlpatterns + [ + url(r'^chart/', include('charts_app.urls')), + url(r'^table/', include('wfs_harvest.urls')), + ] diff --git a/charts-prj/wsgi.py b/charts-prj/wsgi.py new file mode 100644 index 0000000..6147efb --- /dev/null +++ b/charts-prj/wsgi.py @@ -0,0 +1,31 @@ +""" +WSGI config for charts project. + +This module contains the WSGI application used by Django's development server +and any production WSGI deployments. It should expose a module-level variable +named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover +this application via the ``WSGI_APPLICATION`` setting. + +Usually you will have the standard Django WSGI application here, but it also +might make sense to replace the whole Django WSGI application with a custom one +that later delegates to the Django one. For example, you could introduce WSGI +middleware here, or combine a Django application with an application of another +framework. + +""" +import os +import sys + +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "charts-prj.settings") + +# This application object is used by any WSGI server configured to use this +# file. This includes Django's development server, if the WSGI_APPLICATION +# setting points here. +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() + +# Apply WSGI middleware here. +# from helloworld.wsgi import HelloWorldApplication +# application = HelloWorldApplication(application) diff --git a/charts_app/__init__.py b/charts_app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/charts_app/admin.py b/charts_app/admin.py new file mode 100644 index 0000000..05e7ad9 --- /dev/null +++ b/charts_app/admin.py @@ -0,0 +1,10 @@ +from django.contrib import admin + +from .models import Chart + + +class ChartAdmin(admin.ModelAdmin): + list_display = ['id', 'title'] + + +admin.site.register(Chart, ChartAdmin) diff --git a/charts_app/migrations/0001_initial.py b/charts_app/migrations/0001_initial.py new file mode 100644 index 0000000..04f3248 --- /dev/null +++ b/charts_app/migrations/0001_initial.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('layers', '24_to_26'), + ] + + operations = [ + migrations.CreateModel( + name='Chart', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('title', models.CharField(max_length=128, blank=True)), + ('category', models.CharField(max_length=200)), + ('quantity', models.CharField(max_length=200)), + ('type', models.SmallIntegerField(default=0, choices=[(0, b'Bar chart'), (1, b'Pie chart'), (2, b'Donut chart')])), + ('aggr_type', models.SmallIntegerField(default=3, choices=[(0, b'Sum'), (1, b'Mean'), (2, b'Category count'), (3, b'Max'), (4, b'Min')])), + ('abstract', models.TextField(blank=True)), + ('layer', models.ForeignKey(to='layers.Layer')), + ], + ), + ] diff --git a/charts_app/migrations/__init__.py b/charts_app/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/charts_app/models.py b/charts_app/models.py new file mode 100644 index 0000000..298ff2b --- /dev/null +++ b/charts_app/models.py @@ -0,0 +1,53 @@ +from django.db import models +from django.core.urlresolvers import reverse +from django.core.exceptions import ValidationError +from django.utils.translation import ugettext_lazy as _ +from django.conf import settings + +from geonode.layers.models import Layer + +from wfs_harvest.utils import get_featno + + +def validate_wfs(value): + lyr = Layer.objects.get(pk=value) + if lyr.service_type != 'WFS': + raise ValidationError(_('%(lyr_title)s is not a WFS layer'), + code='not_a_wfs', + params={'lyr_title': lyr.title}) + + feat_no = get_featno(value) + if feat_no > settings.MAX_CSV_RECORDS: + raise ValidationError(_('%(lyr_title)s has too many features; ' + 'chart functionality is not available ' + 'for very large datasets'), + code='too_many_records', + params={'lyr_title': lyr.title}) + + +class Chart(models.Model): + CHART_TYPES = ( + (0, 'Bar chart'), + (1, 'Pie chart'), + (2, 'Donut chart'), + (3, 'Line chart') + ) + + AGGREGATION_TYPES = ( + (0, 'Sum'), + (1, 'Mean'), + (2, 'Category count'), + (3, 'Max'), + (4, 'Min'), + ) + + layer = models.ForeignKey(Layer, validators=[validate_wfs]) + title = models.CharField(max_length=128, blank=True) + category = models.CharField(max_length=200) + quantity = models.CharField(max_length=200) + type = models.SmallIntegerField(choices=CHART_TYPES, default=0) + aggr_type = models.SmallIntegerField(choices=AGGREGATION_TYPES, default=3) + abstract = models.TextField(blank=True) + + def get_absolute_url(self): + return reverse('chart_detail', kwargs={'pk': self.pk}) diff --git a/charts_app/templates/donut_chart_v1.html b/charts_app/templates/donut_chart_v1.html new file mode 100644 index 0000000..286f532 --- /dev/null +++ b/charts_app/templates/donut_chart_v1.html @@ -0,0 +1,68 @@ + + +Donut Chart v1 +

    Simple Donut Chart v1

    +

    Zero values excluded

    +

    D3js version 4, use canvas

    + + + + \ No newline at end of file diff --git a/charts_app/templates/donut_chart_v2.html b/charts_app/templates/donut_chart_v2.html new file mode 100644 index 0000000..c371272 --- /dev/null +++ b/charts_app/templates/donut_chart_v2.html @@ -0,0 +1,169 @@ + + +Donut Chart v2 +

    Simple Donut Chart v2

    +

    Zero values excluded, label with ticks

    +

    D3js version 3, use svg

    + + + + + \ No newline at end of file diff --git a/charts_app/templates/pie_chart_v1.html b/charts_app/templates/pie_chart_v1.html new file mode 100644 index 0000000..10e08c5 --- /dev/null +++ b/charts_app/templates/pie_chart_v1.html @@ -0,0 +1,65 @@ + + +Pie Chart v1 +

    Simple Pie Chart v1

    +

    All data

    +

    D3js version 4, use svg

    + + + + diff --git a/charts_app/templates/pie_chart_v2.html b/charts_app/templates/pie_chart_v2.html new file mode 100644 index 0000000..7a93002 --- /dev/null +++ b/charts_app/templates/pie_chart_v2.html @@ -0,0 +1,67 @@ + + +Pie Chart v2 +

    Simple Pie Chart v2

    +

    Zero values excluded

    +

    D3js version 4, use svg

    + + + + diff --git a/charts_app/tests.py b/charts_app/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/charts_app/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/charts_app/urls.py b/charts_app/urls.py new file mode 100644 index 0000000..9d7ab99 --- /dev/null +++ b/charts_app/urls.py @@ -0,0 +1,15 @@ +from django.conf.urls import url + +from . import views + +urlpatterns = [url(r'^sample_csv$', views.get_csv, name='get_csv'), + url(r'^sample_csv2$', views.get_csv_aggr, name='get_csv2'), + url(r'^pie_chart_v1$', views.pie_chart_v1), + url(r'^donut_chart_v1$', views.donut_chart_v1), + url(r'^pie_chart_v2$', views.pie_chart_v2), + url(r'^donut_chart_v2$', views.donut_chart_v2), + url(r'^(?P[0-9]+)/$', views.ChartDetailView.as_view(), name='chart_detail'), + url(r'^add/(?P[0-9]+)/$', views.ChartCreate.as_view(), name='chart_add'), + url(r'^(?P[0-9]+)/update/$', views.ChartUpdate.as_view(), name='chart_update'), + url(r'^(?P[0-9]+)/delete/$', views.ChartDelete.as_view(), name='chart_delete') + ] diff --git a/charts_app/views.py b/charts_app/views.py new file mode 100644 index 0000000..d646bc6 --- /dev/null +++ b/charts_app/views.py @@ -0,0 +1,123 @@ +import csv + +from django.http import HttpResponse +from django.shortcuts import render +from django.views.generic.detail import DetailView +from django.views.generic.edit import CreateView, UpdateView, DeleteView + +from geonode.layers.models import Layer + +from .models import Chart +from wfs_harvest.utils import get_fields + + +class ChartDetailView(DetailView): + model = Chart + + +class ChartCreate(CreateView): + model = Chart + fields = '__all__' + + def get_initial(self): + layer_id = self.kwargs['layer_id'] + initial = self.initial.copy() + initial['layer'] = layer_id + return initial + + def get_context_data(self, **kwargs): + layer_id = self.kwargs['layer_id'] + layer = Layer.objects.get(pk=layer_id) + fieldnames, num_fieldnames = get_fields(layer_id) + ctx = super(ChartCreate, self).get_context_data(**kwargs) + ctx['fieldnames'] = fieldnames + ctx['num_fieldnames'] = num_fieldnames + ctx['layer'] = layer + return ctx + + +class ChartUpdate(UpdateView): + model = Chart + fields = '__all__' + template_name_suffix = '_update_form' + + +class ChartDelete(DeleteView): + model = Chart + success_url = '/' + + +def get_csv(request): + response = HttpResponse(content_type='text/csv') + response['Content-Disposition'] = 'attachment; filename="table.csv"' + + writer = csv.writer(response) + writer.writerow(['name', 'area']) + writer.writerow(['Af', 3.51]) + writer.writerow(['Ems / ems', 0.00]) + writer.writerow(['Ep / ep', 0.00]) + writer.writerow(['Lmst', 4.88]) + writer.writerow(['Mpb', 18.93]) + writer.writerow(['Pf', 30.53]) + writer.writerow(['Ppf', 6.84]) + writer.writerow(['Qa', 0.49]) + writer.writerow(['Qhac', 5.91]) + writer.writerow(['Qhad', 0.00]) + writer.writerow(['Qham', 11.01]) + writer.writerow(['Qht1', 1.10]) + writer.writerow(['Qht2', 27.60]) + writer.writerow(['Qpf', 34.40]) + writer.writerow(['Qphf', 42.30]) + + return response + +def get_csv_aggr(request): + response = HttpResponse(content_type='text/csv') + response['Content-Disposition'] = 'attachment; filename="table.csv"' + + writer = csv.writer(response) + writer.writerow(['name', 'area']) + writer.writerow(['Af', 3.51]) + writer.writerow(['Ems / ems', 0.00]) + writer.writerow(['Ep / ep', 0.00]) + writer.writerow(['Lmst', 4.88]) + writer.writerow(['Mpb', 18.93]) + writer.writerow(['Pf', 30.53]) + writer.writerow(['Ppf', 6.84]) + writer.writerow(['Qa', 0.49]) + writer.writerow(['Qhac', 5.91]) + writer.writerow(['Qhad', 0.00]) + writer.writerow(['Qham', 11.01]) + writer.writerow(['Qht1', 1.10]) + writer.writerow(['Qht2', 27.60]) + writer.writerow(['Qphf', 42.30]) + writer.writerow(['Af', 6.58]) + writer.writerow(['Qa', 30.78]) + writer.writerow(['Af', 16.58]) + + return response + + +def pie_chart_v1(request): + return render(request, 'pie_chart_v1.html') + + +def donut_chart_v1(request): + return render(request, 'donut_chart_v1.html') + + +def pie_chart_v2(request): + qdict = request.GET + typename = qdict['lyrname'] + category_field = qdict['category'] + quantity_field = qdict['quantity'] + context = { + 'lyrname': typename, + 'category': category_field, + 'quantity': quantity_field + } + return render(request, 'pie_chart_v2.html', context) + + +def donut_chart_v2(request): + return render(request, 'donut_chart_v2.html') diff --git a/haitidata/settings.py b/haitidata/settings.py index f747c50..e1470c1 100644 --- a/haitidata/settings.py +++ b/haitidata/settings.py @@ -53,7 +53,7 @@ LOCALE_PATHS = ( os.path.join(LOCAL_ROOT, 'locale'), ) + LOCALE_PATHS -INSTALLED_APPS = INSTALLED_APPS + ('haitidata', 'osgeo_importer', 'geonode-client') +INSTALLED_APPS = INSTALLED_APPS + ('haitidata', 'osgeo_importer', 'geonode-client', 'charts_app', 'wfs_harvest') LAYER_PREVIEW_LIBRARY = 'react' @@ -111,6 +111,8 @@ BROKER_URL = "amqp://guest@localhost:5672" CELERY_ALWAYS_EAGER = True IMPORT_TASK_SOFT_TIME_LIMIT = 90 +MAX_CSV_RECORDS = 20000 + SOCIAL_ORIGINS = [{ "label":"paper-plane-o", diff --git a/haitidata/static/css/haitidata.css b/haitidata/static/css/haitidata.css index f8b16d4..6427289 100644 --- a/haitidata/static/css/haitidata.css +++ b/haitidata/static/css/haitidata.css @@ -6882,7 +6882,7 @@ form input { max-height: none; } .navbar-header i { - color: white; + color: #ff5722; font-size: 2em; } .navbar-header button { @@ -7327,6 +7327,35 @@ footer select { .grid-spacer { margin-top: 30px; } +#accordion .panel { + border-radius: 0; + border-top: 2px solid #b0bec5; + line-height: 1em; +} +#accordion .panel-heading { + background: none; + border: 0; +} +#accordion .panel-body img { + margin-bottom: 1em; +} +#accordion .panel-body small { + color: #78909c; + font-size: 0.825em; +} +#accordion .panel-body form { + font-size: 0.825em; +} +#accordion .panel-body form .form-control { + background: none; + color: #546e7a; + font-size: 0.825em; + height: 24px; + line-height: 1; + -webkit-appearance: none; + -webkit-box-shadow: none; + box-shadow: none; +} /* ------ OSGeo Importer ------------------------------ */ body.importer h4 { diff --git a/haitidata/static/css/index.css b/haitidata/static/css/index.css new file mode 100644 index 0000000..ef34317 --- /dev/null +++ b/haitidata/static/css/index.css @@ -0,0 +1,45 @@ +body { + font-family: 'Roboto', sans-serif; + color: #333333; +} + +/* Add shadow effect to chart. If you don't like it, get rid of it. */ +svg { + -webkit-filter: drop-shadow( 0px 3px 3px rgba(0,0,0,.3) ); + filter: drop-shadow( 0px 3px 3px rgba(0,0,0,.25) ); +} + +/*Styling for the lines connecting the labels to the slices*/ +polyline{ + opacity: .3; + stroke: black; + stroke-width: 2px; + fill: none; +} + +/* Make the percentage on the text labels bold*/ +.labelName tspan { + font-style: normal; + font-weight: 700; +} + +/* In biology we generally italicise species names. */ +.labelName { + font-size: 0.9em; + font-style: italic; +} + +/* Tooltip for line chart */ + +div.tooltip { + position: absolute; + text-align: center; + width: 60px; + height: 28px; + padding: 2px; + font: 12px sans-serif; + background: lightsteelblue; + border: 0px; + border-radius: 8px; + pointer-events: none; +} \ No newline at end of file diff --git a/haitidata/static/js/bar.js b/haitidata/static/js/bar.js new file mode 100644 index 0000000..fa88539 --- /dev/null +++ b/haitidata/static/js/bar.js @@ -0,0 +1,184 @@ +function barChart(cat, qnt, title, abs){ + var width = 900, + height = 500, + padding = 5, + xScale = d3.scaleBand(), + yScale = d3.scaleLinear(), + colour = d3.scaleOrdinal(d3.schemeCategory20), + x, + y, + margin = { top: 30, bottom: 30, left: 30, right: 150 }, + floatFormat = d3.format("." + d3.precisionFixed(0.5) + "f"), + xAxis = d3.axisBottom(xScale), + yAxis = d3.axisLeft(yScale); + + function my(selection){ + + selection.each(function(data) { + + var svg = selection.append('svg') + .attr("id", "chart_svg") + .attr("width", width) + .attr("height", height); + + var g = svg.selectAll("g") + .data([1]); + g = g.enter().append("g") + .merge(g) + .attr("transform", + "translate(" + margin.left + "," + margin.top +")"); + + + var innerWidth = width - margin.left - margin.right ; + var innerHeight = function(){ return height - margin.top - margin.bottom} ; + + + xScale + .domain(data.map(function (d){ return d[x]; })) + .range([0, (innerWidth - margin.right)]); + + + // X axis + var xAxisG = g.selectAll(".x-axis").data([1]); + xAxisG.enter().append("g") + .attr("class", "x-axis") + .merge(xAxisG) + .attr("transform", "translate(0," + innerHeight() +")") + .call(xAxis); + + // labels X axis + // rotate text if is longer than... + + d3.select(this).select(".x-axis").selectAll("text").each(function(){ + if (this.getBBox().width > (xScale.bandwidth() - (padding*2))) + d3.selectAll("text").attr("transform", "rotate(-90)") + .attr("y", 0) + .attr("x", -10) + .attr("dy", ".35em") + .style("text-anchor", "end"); + }); + + // adjust margin and x axis title + var maxh = 0; + d3.select(this).select(".x-axis").selectAll("text").each(function(){ + if (this.getBBox().width > maxh) + maxh = this.getBBox().width; + }); + margin.bottom = margin.bottom + maxh; + d3.select(".x-axis").attr("transform", "translate(0," + (innerHeight()) + ")"); + + + g.append("text") + .attr("transform", "translate(" + (innerWidth/2) + ", " + (innerHeight() + margin.bottom - 5) + ")") + .style("font-size", "12px") + .style("text-anchor", "middle") + .text(cat); + + yScale + .domain([0, d3.max(data, function (d){ return d[y] ;})]) + .range([innerHeight(), 0]); + + // Y axis + var yAxisG = g.selectAll(".y-axis").data([1]); + yAxisG.enter().append("g") + .attr("class", "y-axis") + .merge(yAxisG) + .call(yAxis); + + //labels Y axis + var maxw = 0; + d3.select(this).select(".y-axis").selectAll("text").each(function(){ + if (this.getBBox().width > maxw) { + maxw = this.getBBox().width; + } + }); + margin.left = margin.left + maxw; + g.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); + + var yLabel = function(){ + if (title == "Count"){ + return "Count"; + } else { + return qnt; + }}; + + g.append("text") + .attr("transform", "rotate(-90)") + .attr("x", 0 - (innerHeight()/2)) + .attr("y", 0 - (margin.left)) + .attr("dy", "1em") + .style("font-size", "12px") + .style("text-anchor", "middle") + .text(yLabel); + + // bars + var rects = g.selectAll("rect") + .data(data); + rects.exit().remove(); + rects.enter().append("rect") + .merge(rects) + .attr("x", function (d){ return xScale(d[x]) + padding; }) + .attr("y", function (d){ return yScale(d[y]); }) + .attr("fill", function(d) { return colour(xScale(d[x])); }) + .attr("width", xScale.bandwidth() - (padding*2)) + .attr("height", function (d){ + return innerHeight() - yScale(d.value); + }); + + //chart legend + var legend = svg.selectAll(".legend") + .data(data) + .enter().append("g") + .attr("class", "legend") + .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); + + legend.append("rect") + .attr("x", width - 18) + .attr("width", 18) + .attr("height", 18) + .style("fill", function(d) { return colour(xScale(d[x]))} ); + + legend.append("text") + .attr("x", width - 24) + .attr("y", 9) + .attr("dy", ".35em") + .style("text-anchor", "end") + .text(function (d){ return d[x] + ": " + floatFormat(d[y]); }); + +/* //chart abstract + var abstract = svg.selectAll(".abstract").data(data).enter().append("g") + .attr("class", "abstract") + .attr("transform", "translate(0," + 450 + ")"); + + abstract.append("text") + .attr("x", width - 24) + .attr("y", 9) + .attr("dy", ".35em") + .style("text-anchor", "end") + .text(abs);*/ + + }); + } + + my.x = function (_){ + return arguments.length ? (x = _, my) : x; + }; + + my.y = function (_){ + return arguments.length ? (y = _, my) : y; + }; + + my.width = function (_){ + return arguments.length ? (width = _, my) : width; + }; + + my.height = function (_){ + return arguments.length ? (height = _, my) : height; + }; + + my.padding = function (_){ + return arguments.length ? (xScale.padding(_), my) : xScale.padding(); + }; + + return my; + } diff --git a/haitidata/static/js/csv.js b/haitidata/static/js/csv.js new file mode 100644 index 0000000..97de904 --- /dev/null +++ b/haitidata/static/js/csv.js @@ -0,0 +1,151 @@ +var getCsv = function(csv_link, category, quantity, agg, chartType, abs){ + var data = []; + d3.csv(csv_link, function(error, csv) { + if (error) throw error; + csv.forEach(function(row){ + var qnty_v; var ctgy_v; var i = 0; + while (i < Object.keys(row).length){ + if (Object.keys(row)[i] == quantity){ + qnty_v = +Object.values(row)[i] + } else if (Object.keys(row)[i] == category){ + if (Object.values(row)[i].length >= 20){ + + ctgy_v = Object.values(row)[i].substring(0, 17) + "..."; + } else { + ctgy_v = Object.values(row)[i]; + }; + } + i++; + }; + data.push({qnty : qnty_v , ctgy : ctgy_v }); + }) + + + var dropZeros = function(dato){ + return dato.filter(function(d){ + if (d.qnty !== 0){ + return d.qnty; + }}) + }; + + function groupData_sum(dato){ + return d3.nest().key(function(d) {return d.ctgy;}) + .rollup(function(v) {return d3.sum(v, function(d) {return d.qnty;});}) + .entries(dato); + }; + + function groupData_mean(dato){ + return d3.nest().key(function(d) {return d.ctgy;}) + .rollup(function(v) {return d3.mean(v, function(d) {return d.qnty;});}) + .entries(dato); + }; + + function groupData_min(dato){ + return d3.nest().key(function(d) {return d.ctgy;}) + .rollup(function(v) {return d3.min(v, function(d) {return d.qnty;});}) + .entries(dato); + }; + + function groupData_max(dato){ + return d3.nest().key(function(d) {return d.ctgy;}) + .rollup(function(v) {return d3.max(v, function(d) {return d.qnty;});}) + .entries(dato); + }; + + function groupData_count(dato){ + return d3.nest().key(function(d) {return d.ctgy;}) + .rollup(function(v) { return v.length;}) + .entries(dato); + }; + + function descendent(a,b){ + if (a.value < b.value) return 1; + if (a.value > b.value) return -1; + return 0; + } + + + var title; + var dati; + function aggregateData(data, agg){ + + if (agg == 0){ + dati = groupData_sum(dropZeros(data)).sort(descendent); + title = "Sum"; + } else if (agg == 1){ + dati = groupData_mean(data).sort(descendent); + title = "Mean"; + } else if (agg == 2){ + dati = groupData_count(data).sort(descendent); + title = "Count"; + } else if (agg == 3){ + dati = groupData_max(dropZeros(data)).sort(descendent); + title = "Maximum"; + } else if (agg == 4){ + dati = groupData_min(dropZeros(data)).sort(descendent);; + title = "Minimum"; + }; + return dati; + }; + + function create(chartType){ + if (chartType == 0){ + aggregateData(data, agg); + if (dati.length > 20){ + while (dati.length >= 21) { dati.pop(); }; + window.alert("Output limited to 20 categories"); + }; + var bar = barChart(category, quantity, title, abs) + .x('key') + .y('value') + d3.select("#chart_area") + .datum(dati) + .call(bar); + } else if (chartType == 1){ + aggregateData(data, agg) + if (dati.length > 10){ + while (dati.length >= 11) { dati.pop(); }; + window.alert("Output limited to 10 categories"); + }; + var pie = pieChart(category, quantity, title, abs) + .variable('value') + .category('key') + d3.select('#chart_area') + .datum(dati) + .call(pie); + } else if (chartType == 2){ + aggregateData(data, agg) + if (dati.length > 10){ + while (dati.length >= 11) { dati.pop(); }; + window.alert("Output limited to 10 categories"); + }; + var donut = donutChart(category, quantity, title, abs) + .variable('value') + .category('key') + d3.select('#chart_area') + .datum(dati) + .call(donut); + } else if (chartType == 3){ + aggregateData(data, agg) + if (dati.length > 20){ + while (dati.length >= 21) { dati.pop(); }; + window.alert("Output limited to 20 categories"); + }; + var line = lineChart(category, quantity, title, abs) + .x('key') + .y('value') + d3.select('#chart_area') + .datum(dati) + .call(line); + } + }; + + create(chartType); + }); +}; + + + + + + diff --git a/haitidata/static/js/donut.js b/haitidata/static/js/donut.js new file mode 100644 index 0000000..bac5c5d --- /dev/null +++ b/haitidata/static/js/donut.js @@ -0,0 +1,415 @@ +function donutChart(cat, qnt, title){ + var width = 900, + height = 500, + margin = {top: 70, right: 10, bottom: 10, left: 10}, + colour = d3.scaleOrdinal(d3.schemeCategory20c), // colour scheme + variable, // value in data that will dictate proportions on chart + category, // compare data by + padAngle = 0.015, // effectively dictates the gap between slices + transTime, // transition time + updateData, + floatFormat = d3.format("." + d3.precisionFixed(0.5) + "f"), + cornerRadius = 3; // sets how rounded the corners are on each slice + + function chart(selection){ + selection.each(function() { + // generate chart + // =========================================================================================== + // Set up constructors for making donut. See https://github.com/d3/d3-shape/blob/master/README.md + var radius = Math.min(width, (height - margin.top)) / 2; + + // creates a new pie generator + var pie = d3.pie() + .value(function(d) { return floatFormat(d[variable]); }) + .sort(null); + + // contructs and arc generator. This will be used for the donut. The difference between outer and inner + // radius will dictate the thickness of the donut + var arc = d3.arc() + .outerRadius(radius * 0.8) + .innerRadius(radius * 0.6) + .cornerRadius(cornerRadius) + .padAngle(padAngle); + + // this arc is used for aligning the text labels + var outerArc = d3.arc() + .outerRadius(radius * 0.83) + .innerRadius(radius * 0.83); + // =========================================================================================== + + // =========================================================================================== + // append the svg object to the selection + // var svg = selection.append('svg') + var svg = selection.append('svg') + .attr("id", "chart_svg") + .attr('width', width + margin.left + margin.right) + .attr('height', height + margin.top + margin.bottom) + .append('g') + .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')'); + // =========================================================================================== + + // =========================================================================================== + // g elements to keep elements within svg modular + svg.append('g').attr('class', 'slices'); + svg.append('g').attr('class', 'labelName'); + svg.append('g').attr('class', 'lines'); + // =========================================================================================== + + // =========================================================================================== + // add and colour the donut slices + var path = svg.select('.slices') + .selectAll('path') + .data(pie) + .enter().append('path') + .attr('fill', function(d) { return colour(d.data[category]); }) + .attr('d', arc); + // =========================================================================================== + + // =========================================================================================== + // add text labels + var occupedLabel = []; + var label = svg.select('.labelName').selectAll('text') + .data(pie) + .enter().append('text') + .attr('dy', '.35em') + .html(updateLabelText) + .attr('transform', labelTransform) + .style('text-anchor', function(d) { + // if slice centre is on the left, anchor text to start, otherwise anchor to end + return (midAngle(d)) < Math.PI ? 'start' : 'end'; + }); + // =========================================================================================== + + // =========================================================================================== + // add lines connecting labels to slice. A polyline creates straight lines connecting several points + var occupedPoint = []; + var polyline = svg.select('.lines') + .selectAll('polyline') + .data(pie) + .enter().append('polyline') + .attr('points', calculatePoints); + // =========================================================================================== + + // =========================================================================================== + // add tooltip to mouse events on slices and labels + d3.selectAll('.labelName text, .slices path').call(toolTip); + // =========================================================================================== + + // =========================================================================================== + // FUNCTION TO UPDATE CHART + updateData = function() { + + var updatePath = d3.select('.slices').selectAll('path'); + var updateLines = d3.select('.lines').selectAll('polyline'); + var updateLabels = d3.select('.labelName').selectAll('text'); + + var data0 = path.data(), // store the current data before updating to the new + data1 = pie(data); + + // update data attached to the slices, labels, and polylines. the key function assigns the data to + // the correct element, rather than in order of how the data appears. This means that if a category + // already exists in the chart, it will have its data updated rather than removed and re-added. + updatePath = updatePath.data(data1, key); + updateLines = updateLines.data(data1, key); + updateLabels = updateLabels.data(data1, key); + + // adds new slices/lines/labels + updatePath.enter().append('path') + .each(function(d, i) { this._current = findNeighborArc(i, data0, data1, key) || d; }) + .attr('fill', function(d) { return colour(d.data[category]); }) + .attr('d', arc); + + updateLines.enter().append('polyline') + .each(function(d, i) { this._current = findNeighborArc(i, data0, data1, key) || d; }) + .attr('points', calculatePoints); + + updateLabels.enter().append('text') + .each(function(d, i) { this._current = findNeighborArc(i, data0, data1, key) || d; }) + .html(updateLabelText) + .attr('transform', labelTransform) + .style('text-anchor', function(d) { return (midAngle(d)) < Math.PI ? 'start' : 'end'; }); + + // removes slices/labels/lines that are not in the current dataset + updatePath.exit() + .transition() + .duration(transTime) + .attrTween("d", arcTween) + .remove(); + + updateLines.exit() + .transition() + .duration(transTime) + .attrTween("points", pointTween) + .remove(); + + updateLabels.exit() + .remove(); + + // animates the transition from old angle to new angle for slices/lines/labels + updatePath.transition().duration(transTime) + .attrTween('d', arcTween); + + updateLines.transition().duration(transTime) + .attrTween('points', pointTween); + + updateLabels.transition().duration(transTime) + .attrTween('transform', labelTween) + .styleTween('text-anchor', labelStyleTween); + + updateLabels.html(updateLabelText); // update the label text + + // add tooltip to mouse events on slices and labels + d3.selectAll('.labelName text, .slices path').call(toolTip); + + }; + // =========================================================================================== + // Functions + // calculates the angle for the middle of a slice + function midAngle(d) { return d.startAngle + (d.endAngle - d.startAngle) / 2; } + + // function that creates and adds the tool tip to a selected element + function toolTip(selection) { + + // add tooltip (svg circle element) when mouse enters label or slice + selection.on('mouseenter', function (data) { + + svg.append('text') + .attr('class', 'toolCircle') + .attr('dy', -15) // hard-coded. can adjust this to adjust text vertical alignment in tooltip + .html(toolTipHTML(data)) // add text to the circle. + .style('font-size', '.9em') + .style('text-anchor', 'middle'); // centres text in tooltip + + svg.append('circle') + .attr('class', 'toolCircle') + .attr('r', radius * 0.55) // radius of tooltip circle + .style('fill', colour(data.data[category])) // colour based on category mouse is over + .style('fill-opacity', 0.35); + + }); + + // remove the tooltip when mouse leaves the slice/label + selection.on('mouseout', function () { + d3.selectAll('.toolCircle').remove(); + }); + } + + // function to create the HTML string for the tool tip. Loops through each key in data object + // and returns the html string key: value + function toolTipHTML(data) { + + var tip = '', + i = 0; + + for (var key in data.data) { + + // if value is a number, format it as float + var value = (!isNaN(parseFloat(data.data[key]))) ? parseFloat(data.data[key]) : data.data[key]; + qnt = (title == "Count" ? "Count" : qnt); + + // leave off 'dy' attr for first tspan so the 'dy' attr on text element works. The 'dy' attr on + // tspan effectively imitates a line break. + if (i === 0) tip += '' + cat + ': ' + value + ''; + else tip += '' + qnt + ': ' + value + ''; + i++; + } + + return tip; + } + + // calculate the points for the polyline to pass through + function calculatePoints(d) { + // see label transform function for explanations of these three lines. + var pos = outerArc.centroid(d); + var rev_pos = outerArc.centroid(d); + pos[0] = radius * 0.95 * (midAngle(d) < Math.PI ? 1 : -1); + // verify label conflict: if overlaps move up of 10 + if (pos[0] < 0 && pos[1] < 0) { + var i = 0; + if (occupedPoint.length >= 1){ + for (i = 0; i < occupedPoint.length; i++){ + if (pos[1] <= (occupedPoint[i] + 10) && (pos[1] >= (occupedPoint[i] - 10))){ + pos[1] = pos[1] - 20; + rev_pos[1] = rev_pos[1] - 20; + } + } + } occupedPoint.push(pos[1]); + } + return [arc.centroid(d), rev_pos, pos] + } + + function labelTransform(d) { + // effectively computes the centre of the slice. + // see https://github.com/d3/d3-shape/blob/master/README.md#arc_centroid + var pos = outerArc.centroid(d); + // verify label conflict: if overlaps move up of 10 + if (pos[0] < 0 && pos[1] < 0) { + var i = 0; + if (occupedLabel.length >= 1){ + for (i = 0; i < occupedLabel.length; i++){ + if (pos[1] <= (occupedLabel[i] + 10) && (pos[1] >= (occupedLabel[i] - 10))){ + pos[1] = pos[1] - 20; + } + } + } occupedLabel.push(pos[1]); + } + // changes the point to be on left or right depending on where label is. + pos[0] = radius * 0.95 * (midAngle(d) < Math.PI ? 1 : -1); + return 'translate(' + pos + ')'; + } + + function updateLabelText(d) { + return d.data[category] + ': ' + floatFormat(d.data[variable]) + ''; + } + + // function that calculates transition path for label and also it's text anchoring + function labelStyleTween(d) { + this._current = this._current || d; + var interpolate = d3.interpolate(this._current, d); + this._current = interpolate(0); + return function(t){ + var d2 = interpolate(t); + return midAngle(d2) < Math.PI ? 'start':'end'; + }; + } + + function labelTween(d) { + this._current = this._current || d; + var interpolate = d3.interpolate(this._current, d); + this._current = interpolate(0); + return function(t){ + var d2 = interpolate(t), + pos = outerArc.centroid(d2); // computes the midpoint [x,y] of the centre line that would be + // generated by the given arguments. It is defined as startangle + endangle/2 and innerR + outerR/2 + pos[0] = radius * (midAngle(d2) < Math.PI ? 1 : -1); // aligns the labels on the sides + return 'translate(' + pos + ')'; + }; + } + + function pointTween(d) { + this._current = this._current || d; + var interpolate = d3.interpolate(this._current, d); + this._current = interpolate(0); + return function(t){ + var d2 = interpolate(t), + pos = outerArc.centroid(d2); + pos[0] = radius * 0.95 * (midAngle(d2) < Math.PI ? 1 : -1); + return [arc.centroid(d2), outerArc.centroid(d2), pos]; + }; + } + + // function to calculate the tween for an arc's transition. + // see http://bl.ocks.org/mbostock/5100636 for a thorough explanation. + function arcTween(d) { + var i = d3.interpolate(this._current, d); + this._current = i(0); + return function(t) { return arc(i(t)); }; + } + + function findNeighborArc(i, data0, data1, key) { + var d; + return (d = findPreceding(i, data0, data1, key)) ? {startAngle: d.endAngle, endAngle: d.endAngle} + : (d = findFollowing(i, data0, data1, key)) ? {startAngle: d.startAngle, endAngle: d.startAngle} + : null; + } + // Find the element in data0 that joins the highest preceding element in data1. + function findPreceding(i, data0, data1, key) { + var m = data0.length; + while (--i >= 0) { + var k = key(data1[i]); + for (var j = 0; j < m; ++j) { + if (key(data0[j]) === k) return data0[j]; + } + } + } + + function key(d) { + return d.data[category]; + } + + // Find the element in data0 that joins the lowest following element in data1. + function findFollowing(i, data0, data1, key) { + var n = data1.length, m = data0.length; + while (++i < n) { + var k = key(data1[i]); + for (var j = 0; j < m; ++j) { + if (key(data0[j]) === k) return data0[j]; + } + } + } + + // =========================================================================================== + + }); + } + + // getter and setter functions. See Mike Bostocks post "Towards Reusable Charts" for a tutorial on how this works. + chart.width = function(value) { + if (!arguments.length) return width; + width = value; + return chart; + }; + + chart.height = function(value) { + if (!arguments.length) return height; + height = value; + return chart; + }; + + chart.margin = function(value) { + if (!arguments.length) return margin; + margin = value; + return chart; + }; + + chart.radius = function(value) { + if (!arguments.length) return radius; + radius = value; + return chart; + }; + + chart.padAngle = function(value) { + if (!arguments.length) return padAngle; + padAngle = value; + return chart; + }; + + chart.cornerRadius = function(value) { + if (!arguments.length) return cornerRadius; + cornerRadius = value; + return chart; + }; + + chart.colour = function(value) { + if (!arguments.length) return colour; + colour = value; + return chart; + }; + + chart.variable = function(value) { + if (!arguments.length) return variable; + variable = value; + return chart; + }; + + chart.category = function(value) { + if (!arguments.length) return category; + category = value; + return chart; + }; + + chart.transTime = function(value) { + if (!arguments.length) return transTime; + transTime = value; + return chart; + }; + + chart.data = function(value) { + if (!arguments.length) return data; + data = value; + if (typeof updateData === 'function') updateData(); + return chart; + }; + + return chart; +} \ No newline at end of file diff --git a/haitidata/static/js/line.js b/haitidata/static/js/line.js new file mode 100644 index 0000000..e00908f --- /dev/null +++ b/haitidata/static/js/line.js @@ -0,0 +1,179 @@ +function lineChart(cat, qnt, title){ + var width = 900, + height = 500, + xScale = d3.scaleBand(), + yScale = d3.scaleLinear(), + colour = "steelblue", + x, + y, + margin = { top: 30, bottom: 30, left: 30, right: 30 }, + floatFormat = d3.format("." + d3.precisionFixed(0.5) + "f"), + xAxis = d3.axisBottom(xScale), + yAxis = d3.axisLeft(yScale); + + function my(selection){ + + selection.each(function(data) { + + var svg = selection.append('svg') + .attr("id", "chart_svg") + .attr("width", width) + .attr("height", height); + + var g = svg.selectAll("g") + .data([1]); + g = g.enter().append("g") + .merge(g) + .attr("transform", + "translate(" + margin.left + "," + margin.top +")"); + + + var innerWidth = width - margin.left - margin.right ; + var innerHeight = function(){ return height - margin.top - margin.bottom} ; + + + xScale + .domain(data.map(function (d){ return d[x]; })) + .range([0, (innerWidth - margin.right)]); + + + // X axis + var xAxisG = g.selectAll(".x-axis").data([1]); + xAxisG.enter().append("g") + .attr("class", "x-axis") + .merge(xAxisG) + .attr("transform", "translate(0," + innerHeight() +")") + .call(xAxis); + + // labels X axis + // rotate text if is longer than... + + d3.select(this).select(".x-axis").selectAll("text").each(function(){ + if (this.getBBox().width > xScale.bandwidth()) + d3.selectAll("text").attr("transform", "rotate(-90)") + .attr("y", 0) + .attr("x", -10) + .attr("dy", ".35em") + .style("text-anchor", "end"); + }); + + // adjust margin and x axis title + var maxh = 0; + d3.select(this).select(".x-axis").selectAll("text").each(function(){ + if (this.getBBox().width > maxh) + maxh = this.getBBox().width; + }); + margin.bottom = margin.bottom + maxh; + d3.select(".x-axis").attr("transform", "translate(0," + (innerHeight()) + ")"); + + + g.append("text") + .attr("transform", "translate(" + (innerWidth/2) + ", " + (innerHeight() + margin.bottom - 5) + ")") + .style("font-size", "12px") + .style("text-anchor", "middle") + .text(cat); + + yScale + .domain([0, d3.max(data, function (d){ return d[y] ;})]) + .range([innerHeight(), 0]); + + // Y axis + var yAxisG = g.selectAll(".y-axis").data([1]); + yAxisG.enter().append("g") + .attr("class", "y-axis") + .merge(yAxisG) + .call(yAxis); + + //labels Y axis + var maxw = 0; + d3.select(this).select(".y-axis").selectAll("text").each(function(){ + if (this.getBBox().width > maxw) { + maxw = this.getBBox().width; + } + }); + margin.left = margin.left + maxw; + g.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); + + var yLabel = function(){ + if (title == "Count"){ + return "Count"; + } else { + return qnt; + }}; + + g.append("text") + .attr("transform", "rotate(-90)") + .attr("x", 0 - (innerHeight()/2)) + .attr("y", 0 - (margin.left)) + .attr("dy", "1em") + .style("font-size", "12px") + .style("text-anchor", "middle") + .text(yLabel); + //div for tooltip + var div = d3.select("body").append("div") + .attr("class", "tooltip") + .style("opacity", 0); + + + // lines + var line = d3.line() + .x(function(d) { return xScale(d[x]); }) + .y(function(d) { return yScale(d[y]); }); + + + g.append("path") + .data([data]) + .attr("fill", "none") + .attr("stroke", "steelblue") + .attr("stroke-linejoin", "round") + .attr("stroke-linecap", "round") + .attr("stroke-width", 1.5) + .attr("transform", "translate(" + (xScale.bandwidth() /2) + ", 0)") + .attr("d", line); + + g.selectAll("dot") + .data(data) + .enter().append("circle") + .attr("r", 3.5) + .attr("transform", "translate(" + (xScale.bandwidth() /2) + ", 0)") + .attr("cx", function(d) { return xScale(d[x]); }) + .attr("cy", function(d) { return yScale(d[y]); }) + .on("mouseover", function(d){ + div.transition() + .duration(200) + .style("opacity", 1); + div.html(cat + ": " + d.key + "
    " + yLabel() + ": " + d.value) + .style("left", (d3.event.pageX) + "px") + .style("top", (d3.event.pageY - 40) + "px"); + }) + .on("mouseout", function(d) { + div.transition() + .duration(500) + .style("opacity", 0); + }); + + }); + } + + my.x = function (_){ + return arguments.length ? (x = _, my) : x; + }; + + my.y = function (_){ + return arguments.length ? (y = _, my) : y; + }; + + my.width = function (_){ + return arguments.length ? (width = _, my) : width; + }; + + my.height = function (_){ + return arguments.length ? (height = _, my) : height; + }; + + my.padding = function (_){ + return arguments.length ? (xScale.padding(_), my) : xScale.padding(); + }; + + return my; + } \ No newline at end of file diff --git a/haitidata/static/js/pie.js b/haitidata/static/js/pie.js new file mode 100644 index 0000000..a3ddc7c --- /dev/null +++ b/haitidata/static/js/pie.js @@ -0,0 +1,416 @@ +function pieChart(cat, qnt, title){ + var width = 900, + height = 500, + margin = {top: 80, right: 100, bottom: 10, left: 10}, + colour = d3.scaleOrdinal(d3.schemeCategory20c), // colour scheme + variable, // value in data that will dictate proportions on chart + category, // compare data by + padAngle = 0.015, // effectively dictates the gap between slices + transTime, // transition time + updateData, + floatFormat = d3.format("." + d3.precisionFixed(0.5) + "f"), + cornerRadius = 3; // sets how rounded the corners are on each slice + + function chart(selection){ + selection.each(function() { + // generate chart + // =========================================================================================== + // Set up constructors for making donut. See https://github.com/d3/d3-shape/blob/master/README.md + var radius = Math.min(width, (height - margin.top)) / 2; + + // creates a new pie generator + var pie = d3.pie() + .value(function(d) { return floatFormat(d[variable]); }) + .sort(null); + + // contructs and arc generator. This will be used for the donut. The difference between outer and inner + // radius will dictate the thickness of the donut + var arc = d3.arc() + .outerRadius(radius * 0.8) + .innerRadius(2) + .cornerRadius(cornerRadius) + .padAngle(padAngle); + + // this arc is used for aligning the text labels + var outerArc = d3.arc() + .outerRadius(radius * 0.83) + .innerRadius(radius * 0.83); + // =========================================================================================== + + // =========================================================================================== + // append the svg object to the selection + var svg = selection.append('svg') + .attr("id", "chart_svg") + .attr('width', width + margin.left + margin.right) + .attr('height', height + margin.top + margin.bottom) + .append('g') + .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')'); + // =========================================================================================== + + // =========================================================================================== + // g elements to keep elements within svg modular + svg.append('g').attr('class', 'slices'); + svg.append('g').attr('class', 'labelName'); + svg.append('g').attr('class', 'lines'); + // =========================================================================================== + + // =========================================================================================== + // add and colour the donut slices + var path = svg.select('.slices') + .selectAll('path') + .data(pie) + .enter().append('path') + .attr('fill', function(d) { return colour(d.data[category]); }) + .attr('d', arc); + // =========================================================================================== + + // =========================================================================================== + // add text labels + var occupedLabel = []; + var label = svg.select('.labelName').selectAll('text') + .data(pie) + .enter().append('text') + .attr('dy', '.35em') + .html(updateLabelText) + .attr('transform', labelTransform) + .style('text-anchor', function(d) { + // if slice centre is on the left, anchor text to start, otherwise anchor to end + return (midAngle(d)) < Math.PI ? 'start' : 'end'; + }); + // =========================================================================================== + + // =========================================================================================== + // add lines connecting labels to slice. A polyline creates straight lines connecting several points + var occupedPoint = []; + var polyline = svg.select('.lines') + .selectAll('polyline') + .data(pie) + .enter().append('polyline') + .attr('points', calculatePoints); + // =========================================================================================== + + // =========================================================================================== + // add tooltip to mouse events on slices and labels + d3.selectAll('.labelName text, .slices path').call(toolTip); + // =========================================================================================== + + // =========================================================================================== + // FUNCTION TO UPDATE CHART + updateData = function() { + + var updatePath = d3.select('.slices').selectAll('path'); + var updateLines = d3.select('.lines').selectAll('polyline'); + var updateLabels = d3.select('.labelName').selectAll('text'); + + var data0 = path.data(), // store the current data before updating to the new + data1 = pie(data); + + // update data attached to the slices, labels, and polylines. the key function assigns the data to + // the correct element, rather than in order of how the data appears. This means that if a category + // already exists in the chart, it will have its data updated rather than removed and re-added. + updatePath = updatePath.data(data1, key); + updateLines = updateLines.data(data1, key); + updateLabels = updateLabels.data(data1, key); + + // adds new slices/lines/labels + updatePath.enter().append('path') + .each(function(d, i) { this._current = findNeighborArc(i, data0, data1, key) || d; }) + .attr('fill', function(d) { return colour(d.data[category]); }) + .attr('d', arc); + + updateLines.enter().append('polyline') + .each(function(d, i) { this._current = findNeighborArc(i, data0, data1, key) || d; }) + .attr('points', calculatePoints); + + updateLabels.enter().append('text') + .each(function(d, i) { this._current = findNeighborArc(i, data0, data1, key) || d; }) + .html(updateLabelText) + .attr('transform', labelTransform) + .style('text-anchor', function(d) { return (midAngle(d)) < Math.PI ? 'start' : 'end'; }); + + // removes slices/labels/lines that are not in the current dataset + updatePath.exit() + .transition() + .duration(transTime) + .attrTween("d", arcTween) + .remove(); + + updateLines.exit() + .transition() + .duration(transTime) + .attrTween("points", pointTween) + .remove(); + + updateLabels.exit() + .remove(); + + // animates the transition from old angle to new angle for slices/lines/labels + updatePath.transition().duration(transTime) + .attrTween('d', arcTween); + + updateLines.transition().duration(transTime) + .attrTween('points', pointTween); + + updateLabels.transition().duration(transTime) + .attrTween('transform', labelTween) + .styleTween('text-anchor', labelStyleTween); + + updateLabels.html(updateLabelText); // update the label text + + // add tooltip to mouse events on slices and labels + d3.selectAll('.labelName text, .slices path').call(toolTip); + + }; + // =========================================================================================== + // Functions + // calculates the angle for the middle of a slice + function midAngle(d) { return d.startAngle + (d.endAngle - d.startAngle) / 2}; + + // function that creates and adds the tool tip to a selected element + function toolTip(selection) { + + // add tooltip (svg circle element) when mouse enters label or slice + selection.on('mouseenter', function (data) { + + svg.append('rect') + .attr('transform', "translate(250, -200)") + .attr('class', 'toolRect') + .attr("width", 190) + .attr("height", 60) + .style('fill', colour(data.data[category])) // colour based on category mouse is over + .style('fill-opacity', 0.35); + + svg.append('text') + .attr('transform', "translate(400,-175)") + .attr('class', 'toolRect') + .html(toolTipHTML(data)) // add text to the rect + .style('font-size', '.9em') + .style('text-anchor', 'end'); // centres text in tooltip + }); + + // remove the tooltip when mouse leaves the slice/label + selection.on('mouseout', function () { + d3.selectAll('.toolRect').remove(); + }); + } + + // function to create the HTML string for the tool tip. Loops through each key in data object + // and returns the html string key: value + function toolTipHTML(data) { + + var tip = '', + i = 0; + + for (var key in data.data) { + + // if value is a number, format it as a float + var value = (!isNaN(data.data[key])) ? parseFloat(data.data[key]) : data.data[key]; + qnt = (title == "Count" ? "Count" : qnt); + + // leave off 'dy' attr for first tspan so the 'dy' attr on text element works. The 'dy' attr on + // tspan effectively imitates a line break. + if (i === 0) tip += '' + cat + ': ' + value + ''; + else tip += '' + qnt + ': ' + parseFloat(value) + ''; + i++; + } + + return tip; + } + + // calculate the points for the polyline to pass through + function calculatePoints(d) { + // see label transform function for explanations of these three lines. + var pos = outerArc.centroid(d); + var rev_pos = outerArc.centroid(d); + pos[0] = radius * 0.95 * (midAngle(d) < Math.PI ? 1 : -1); + // verify label conflict: if overlaps move up of 10 + if (pos[0] < 0 && pos[1] < 0) { + var i = 0; + if (occupedPoint.length >= 1){ + for (i = 0; i < occupedPoint.length; i++){ + if (pos[1] <= (occupedPoint[i] + 10) && (pos[1] >= (occupedPoint[i] - 10))){ + pos[1] = pos[1] - 20; + rev_pos[1] = rev_pos[1] - 20; + } + } + } occupedPoint.push(pos[1]); + } + return [arc.centroid(d), rev_pos, pos] + } + + + function labelTransform(d) { + // effectively computes the centre of the slice. + // see https://github.com/d3/d3-shape/blob/master/README.md#arc_centroid + var pos = outerArc.centroid(d); + // verify label conflict: if overlaps move up of 10 + if (pos[0] < 0 && pos[1] < 0) { + var i = 0; + if (occupedLabel.length >= 1){ + for (i = 0; i < occupedLabel.length; i++){ + if (pos[1] <= (occupedLabel[i] + 10) && (pos[1] >= (occupedLabel[i] - 10))){ + pos[1] = pos[1] - 20; + } + } + } occupedLabel.push(pos[1]); + } + // changes the point to be on left or right depending on where label is. + pos[0] = radius * 0.95 * (midAngle(d) < Math.PI ? 1 : -1); + return 'translate(' + pos + ')'; + } + + function updateLabelText(d) { + return d.data[category] + ': ' + floatFormat(d.data[variable]) + ''; + } + + // function that calculates transition path for label and also it's text anchoring + function labelStyleTween(d) { + this._current = this._current || d; + var interpolate = d3.interpolate(this._current, d); + this._current = interpolate(0); + return function(t){ + var d2 = interpolate(t); + return midAngle(d2) < Math.PI ? 'start':'end'; + }; + } + + function labelTween(d) { + this._current = this._current || d; + var interpolate = d3.interpolate(this._current, d); + this._current = interpolate(0); + return function(t){ + var d2 = interpolate(t), + pos = outerArc.centroid(d2); // computes the midpoint [x,y] of the centre line that would be + // generated by the given arguments. It is defined as startangle + endangle/2 and innerR + outerR/2 + pos[0] = radius * (midAngle(d2) < Math.PI ? 1 : -1); // aligns the labels on the sides + return 'translate(' + pos + ')'; + }; + } + + function pointTween(d) { + this._current = this._current || d; + var interpolate = d3.interpolate(this._current, d); + this._current = interpolate(0); + return function(t){ + var d2 = interpolate(t), + pos = outerArc.centroid(d2); + pos[0] = radius * 0.95 * (midAngle(d2) < Math.PI ? 1 : -1); + return [arc.centroid(d2), outerArc.centroid(d2), pos]; + }; + } + + // function to calculate the tween for an arc's transition. + // see http://bl.ocks.org/mbostock/5100636 for a thorough explanation. + function arcTween(d) { + var i = d3.interpolate(this._current, d); + this._current = i(0); + return function(t) { return arc(i(t)); }; + } + + function findNeighborArc(i, data0, data1, key) { + var d; + return (d = findPreceding(i, data0, data1, key)) ? {startAngle: d.endAngle, endAngle: d.endAngle} + : (d = findFollowing(i, data0, data1, key)) ? {startAngle: d.startAngle, endAngle: d.startAngle} + : null; + } + // Find the element in data0 that joins the highest preceding element in data1. + function findPreceding(i, data0, data1, key) { + var m = data0.length; + while (--i >= 0) { + var k = key(data1[i]); + for (var j = 0; j < m; ++j) { + if (key(data0[j]) === k) return data0[j]; + } + } + } + + function key(d) { + return d.data[category]; + } + + // Find the element in data0 that joins the lowest following element in data1. + function findFollowing(i, data0, data1, key) { + var n = data1.length, m = data0.length; + while (++i < n) { + var k = key(data1[i]); + for (var j = 0; j < m; ++j) { + if (key(data0[j]) === k) return data0[j]; + } + } + } + + // =========================================================================================== + + }); + } + + // getter and setter functions. See Mike Bostocks post "Towards Reusable Charts" for a tutorial on how this works. + chart.width = function(value) { + if (!arguments.length) return width; + width = value; + return chart; + }; + + chart.height = function(value) { + if (!arguments.length) return height; + height = value; + return chart; + }; + + chart.margin = function(value) { + if (!arguments.length) return margin; + margin = value; + return chart; + }; + + chart.radius = function(value) { + if (!arguments.length) return radius; + radius = value; + return chart; + }; + + chart.padAngle = function(value) { + if (!arguments.length) return padAngle; + padAngle = value; + return chart; + }; + + chart.cornerRadius = function(value) { + if (!arguments.length) return cornerRadius; + cornerRadius = value; + return chart; + }; + + chart.colour = function(value) { + if (!arguments.length) return colour; + colour = value; + return chart; + }; + + chart.variable = function(value) { + if (!arguments.length) return variable; + variable = value; + return chart; + }; + + chart.category = function(value) { + if (!arguments.length) return category; + category = value; + return chart; + }; + + chart.transTime = function(value) { + if (!arguments.length) return transTime; + transTime = value; + return chart; + }; + + chart.data = function(value) { + if (!arguments.length) return data; + data = value; + if (typeof updateData === 'function') updateData(); + return chart; + }; + + return chart; +} \ No newline at end of file diff --git a/haitidata/static/less/haitidata.less b/haitidata/static/less/haitidata.less index bfb7224..f2a51af 100755 --- a/haitidata/static/less/haitidata.less +++ b/haitidata/static/less/haitidata.less @@ -175,7 +175,7 @@ form { .navbar-header { i { - color: white; + color: @brand-primary; font-size: 2em; } @@ -712,6 +712,41 @@ footer { .grid-spacer { margin-top: 30px; } + +#accordion { + .panel { + border-radius: 0; + border-top: 2px solid @gray-light; + line-height: 1em; + } + .panel-heading { + background: none; + border: 0; + } + .panel-body { + img { + margin-bottom: 1em; + } + small { + color: @gray; + font-size: 0.825em; + } + form { + font-size: 0.825em; + .form-control { + background: none; + color: @gray-dark; + font-size: 0.825em; + height: 24px; + line-height: 1; + -webkit-appearance:none; + -webkit-box-shadow: none; + box-shadow: none; + } + } + } +} + /* ------ OSGeo Importer ------------------------------ */ body.importer { diff --git a/haitidata/templates/charts_app/chart_base.html b/haitidata/templates/charts_app/chart_base.html new file mode 100644 index 0000000..031c954 --- /dev/null +++ b/haitidata/templates/charts_app/chart_base.html @@ -0,0 +1,12 @@ +{% extends "site_base.html" %} +{% load i18n %} +{% load url from future %} + +{% block title %} {{ block.super }} {% endblock %} + +{% block body_class %}charts{% endblock %} + +{% block body_outer %} +{% block body %}{% endblock body %} +{% block sidebar %}{% endblock sidebar %} +{% endblock body_outer %} diff --git a/haitidata/templates/charts_app/chart_confirm_delete.html b/haitidata/templates/charts_app/chart_confirm_delete.html new file mode 100644 index 0000000..7695d94 --- /dev/null +++ b/haitidata/templates/charts_app/chart_confirm_delete.html @@ -0,0 +1,5 @@ +

    Do you really want to delete this chart?

    +
    + {% csrf_token %} + +
    \ No newline at end of file diff --git a/haitidata/templates/charts_app/chart_detail.html b/haitidata/templates/charts_app/chart_detail.html new file mode 100644 index 0000000..834d1fc --- /dev/null +++ b/haitidata/templates/charts_app/chart_detail.html @@ -0,0 +1,106 @@ +{% extends "charts_app/chart_base.html" %} +{% load i18n %} +{% load dialogos_tags %} +{% load agon_ratings_tags %} +{% load bootstrap_tags %} +{% load url from future %} +{% load base_tags %} +{% load guardian_tags %} + +{% block page-title %} + {% trans "Explore Graphs" %} + +{% endblock %} + +{% block subheader %} +
    +
    +
    +
    +

    {{ object.title }} Title

    +

    + Chart based on {{ object.layer.title }} layer (Category field: {{ object.category }}, Quantity field: {{ object.quantity }}) + + {% if resource.category %} + {% trans "in" %} {{ resource.category }} | + {% endif %} + {% if resource.date %} + {% if resource.date_type == 'creation' %} {% trans "Created on" %} {{ resource.date }} + {% elif resource.date_type == 'publication' %} {% trans "Published on" %} {{ resource.date }} + {% else %} {% trans "Updated on" %} {{ resource.date }} + {% endif %} + {% endif %} +

    + {% block social_links %} + {% if SOCIAL_BUTTONS %} + {% include "social_links.html" %} + {% endif %} + {% endblock %} +
    +
    +
    +
    +{% endblock %} + + + +{% block body_outer %} + + + + + + + + +
    +
    +
    +

    Abstract

    +

    {{ object.abstract }}

    +
    + + +
    + + + + +{% include "charts_app/chart_main_script.html" %} + + + +{% endblock %} diff --git a/haitidata/templates/charts_app/chart_form.html b/haitidata/templates/charts_app/chart_form.html new file mode 100644 index 0000000..ddda0ca --- /dev/null +++ b/haitidata/templates/charts_app/chart_form.html @@ -0,0 +1,87 @@ + + + + + + + + + + +

    {{ layer.title }}

    + +
    +
    + +
    + {% csrf_token %} + {{ form.non_field_errors }} +
    + {{ form.layer.errors }} + {{ form.layer.as_hidden }} +
    +
    + {{ form.title.errors }} + + {{ form.title }} +
    +
    + {{ form.category.errors }} + + +
    +
    + {{ form.quantity.errors }} + + +
    +
    + {{ form.type.errors }} + + {{ form.type }} +
    +
    + {{ form.aggr_type.errors }} + + {{ form.aggr_type }} +
    +
    + {{ form.abstract.errors }} + + {{ form.abstract }} +
    + + +
    + +Download CSV + + + +{% include "charts_app/chart_main_script.html" %} diff --git a/haitidata/templates/charts_app/chart_main_script.html b/haitidata/templates/charts_app/chart_main_script.html new file mode 100644 index 0000000..01d41a3 --- /dev/null +++ b/haitidata/templates/charts_app/chart_main_script.html @@ -0,0 +1,24 @@ + \ No newline at end of file diff --git a/haitidata/templates/charts_app/chart_update_form.html b/haitidata/templates/charts_app/chart_update_form.html new file mode 100644 index 0000000..0d4f735 --- /dev/null +++ b/haitidata/templates/charts_app/chart_update_form.html @@ -0,0 +1,94 @@ + + + + + + + + + +

    {{ object.layer.title }}

    + +
    +
    + +
    + {% csrf_token %} + {{ form.non_field_errors }} +
    + {{ form.layer.as_hidden }} +
    +
    + {{ form.category.as_hidden }} +
    +
    + {{ form.quantity.as_hidden }} +
    +
    + {{ form.title.errors }} + + {{ form.title }} +
    +
    + {{ form.type.errors }} + + {{ form.type }} +
    +
    + {{ form.aggr_type.errors }} + + {{ form.aggr_type }} +
    +
    + {{ form.abstract.errors }} + + {{ form.abstract }} +
    + +
    + +Download CSV +
    + +
    +Delete this Chart + + + + +{% include "charts_app/chart_main_script.html" %} + + + + \ No newline at end of file diff --git a/haitidata/templates/layers/layer_base.html b/haitidata/templates/layers-paolo/layer_base.html similarity index 100% rename from haitidata/templates/layers/layer_base.html rename to haitidata/templates/layers-paolo/layer_base.html diff --git a/haitidata/templates/layers/layer_change_poc.html b/haitidata/templates/layers-paolo/layer_change_poc.html similarity index 100% rename from haitidata/templates/layers/layer_change_poc.html rename to haitidata/templates/layers-paolo/layer_change_poc.html diff --git a/haitidata/templates/layers-paolo/layer_detail.html b/haitidata/templates/layers-paolo/layer_detail.html new file mode 100644 index 0000000..17d24a8 --- /dev/null +++ b/haitidata/templates/layers-paolo/layer_detail.html @@ -0,0 +1,708 @@ +{% extends "layers/layer_base.html" %} +{% load i18n %} +{% load dialogos_tags %} +{% load agon_ratings_tags %} +{% load bootstrap_tags %} +{% load pagination_tags %} +{% load url from future %} +{% load base_tags %} +{% load guardian_tags %} + +{% block title %}{{ block.super }} {% trans "Layers" %} | {{ resource.title|default:resource.typename }}{% endblock %} +{% block page-title %} + {% trans "Explore Layers" %} + +{% endblock %} + +{% block head %} + + {% if TWITTER_CARD %} + {% include "base/_resourcebase_twittercard.html" %} + {% endif %} + + {% if OPENGRAPH_ENABLED %} + {% include "base/_resourcebase_opengraph.html" %} + {% endif %} + + {% if preview == 'geoext' %} + {% include "layers/layer_geoext_map.html" %} + {% elif preview == 'OL3' %} + {% include "layers/layer_ol3_map.html" %} + {% elif preview == 'react' %} + {% include 'geonode-client/layer_map.html' %} + {% else %} + {% include "layers/layer_leaflet_map.html" %} + {% endif %} +{{ block.super }} +{% endblock %} + + +{% block body_class %}layers{% endblock %} + +{% block subheader %} +
    +
    +
    +
    +

    {{ resource.title|default:resource.typename }}

    +

    + {{ resource.service_type }} + {% if resource.category %} + {% trans "in" %} {{ resource.category }} | + {% endif %} + {% if resource.date %} + {% if resource.date_type == 'creation' %} {% trans "Created on" %} {{ resource.date }} + {% elif resource.date_type == 'publication' %} {% trans "Published on" %} {{ resource.date }} + {% else %} {% trans "Updated on" %} {{ resource.date }} + {% endif %} + {% endif %} +

    + {% block social_links %} + {% if SOCIAL_BUTTONS %} + {% include "social_links.html" %} + {% endif %} + {% endblock %} +
    +
    +
    +
    +{% endblock %} + +{% block body_outer %} +
    + + + +
    +
    +
    +
    + + + + + + + + +
    + {% include "_actions.html" %} +
    + +
    + +
    + {% include "base/resourcebase_info_panel.html" %} +
    + + {% if resource.is_mosaic %} +
    +
    + +
    + {% csrf_token %} +   +
    + {% if filter %} + {% trans "Active Filter:" %} {{ filter }} + {% endif %} +
    + + + + + + + + + + + + {% autopaginate all_granules.features 10 %} + {% for feature in granules.features %} + + + + + + + + {% endfor %} + +
    {% trans "Bounding Box" %} (minX,minY,maxX,maxY){% trans "Time" %}{% trans "Actions" %}
    {% if feature.properties.time %}{{ feature.properties.time }}{% endif %} + Granule Preview + Granule Remove + +
    +
    + {% paginate %} +
    + {% endif %} + +
    + {% if resource.is_mosaic %} + + + + + + + + + + + + + + + + +
    {% trans "Dimension" %}{% trans "Enabled" %}{% trans "Regex" %}
    {% trans "TIME" %}{% if resource.has_time %}{% trans "True" %}{% else %}{% trans "False" %}{% endif %}{% if resource.time_regex %}{{ resource.time_regex }}{% else %} {% endif %}
    + {% endif %} + {% if resource.attribute_set.all %} + + + + + + + {% if wps_enabled %} + + + + + {% endif %} + + + + {% for attribute in resource.attributes %} + + + + + {% if wps_enabled %} + {% if attribute.unique_values == "NA" %} + + {% else %} + + {% endif %} + + + + {% endif %} + + {% endfor %} + +
    {% trans "Attribute Name" %}{% trans "Label" %}{% trans "Description" %}{% trans "Range" %}{% trans "Average" %}{% trans "Median" %}{% trans "Standard Deviation" %}
    {{ attribute }}{{ attribute.attribute_label|default:"" }}{{ attribute.description|default:"" }}{{ attribute.unique_values }} + + {{ attribute.average|floatformat:"2" }}{{ attribute.median|floatformat:"2" }}{{ attribute.stddev|floatformat:"2" }}
    + {% endif %} +
    + +
    + {% with resource as obj %} + {% include "_comments.html" %} + {% endwith %} +
    + + {% if GEOGIG_ENABLED and resource.link_set.geogig %} + {% with "_geogig_layer_detail.html" as geogig_template %} +
    + {% with resource as obj %} + {% include geogig_template %} + {% endwith %} +
    + {% endwith %} + {% endif %} + +
    + + {% if request.user.is_authenticated %} +

    {% trans "Rate this layer" %}

    + {% user_rating request.user resource "layer" as user_layer_rating %} +
    + {% endif %} +

    {% trans 'Average Rating' %}

    + {% overall_rating resource "layer" as layer_rating %} + {% num_ratings resource as num_votes %} +
    ({{num_votes}}) +
    + +
    + +
    + +
    + +
    +
    + +
    +
    + + Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. +
    +
    +
    +
    + +
    +
    + Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    + + +
    +
    +
    +
    + +
      + {% if resource.storeType != "remoteStore" %} +
    • + {% if links or links_download %} + + {% else %} + {% if request.user.is_authenticated %} + + {% endif %} + {% endif %} +
    • + {% endif %} + + + {% if GEOSERVER_BASE_URL %} + {% get_obj_perms request.user for resource.layer as "layer_perms" %} + {% endif %} + +
    • + + + +
    • + + {% if "change_resourcebase_metadata" in perms_list or "change_resourcebase" in perms_list or "delete_resourcebase" in perms_list or "change_layer_style" in layer_perms %} +
    • + +
    • + + {% endif %} + +
    • + +
    • + + + + {% if resource.get_legend %} +
    • +

      {%trans "Legend" %}

      +

      {{ style.sld_title }}

      + {% if resource.get_legend.link_type == 'image' %} + {% if request.user.is_authenticated and 'access_token' in request.session %} +

      + {% else %} +

      + {% endif %} + {% else %} +
      + {% endif %} +
    • + {% endif %} +
    • +

      {% trans "Maps using this layer" %}

      + {% if resource.maps %} +

      {% trans "List of maps using this layer:" %}

      + {% endif %} +
        + {% for maplayer in resource.maps %} +
      • {{ maplayer.map.title }}
      • + {% empty %} +
      • {% trans "This layer is not currently used in any maps." %}
      • + {% endfor %} +
      +
    • +
    • +

      {% trans "Create a map using this layer" %}

      +

      {% trans "Click the button below to generate a new map based on this layer." %}

      + {% trans "Create a Map" %} +
    • + + {% if documents.count > 0 %} +
    • +

      {% trans "Documents related to this layer" %}

      +

      {% trans "List of documents related to this layer:" %}

      + +
    • + {% endif %} + + {% if user.is_authenticated %} +
    • +

      {% trans "Styles" %}

      +

      {% trans "The following styles are associated with this layer. Choose a style to view it in the preview map." %}

      +
        + {% for style in resource.styles.all %} +
      • + {% if resource.default_style == style %} + + (default style) + {% else %} + + {% endif %} + {{ style.sld_title }} +
      • + {% empty %} +
      • {% trans "No styles associated with this layer" %}
      • + {% endfor %} +
      +
    • + {% endif %} + + {% if GEONODE_SECURITY_ENABLED %} + {% if "change_resourcebase_permissions" in perms_list %} +
    • +

      {% trans "Permissions" %}

      +

      {% trans "Click the button below to change the permissions of this layer." %}

      +

      {% trans "Change Layer Permissions" %}

      +
    • + {% endif %} + {% endif %} + + {% if resource.storeType == "remoteStore" %} +
    • +

      {% trans "External service layer" %}

      +
      {% trans "Source" %}: {{ resource.service.title }}
      +
      {% trans "Type" %}: {{ resource.service.type }}
      +
    • + {% endif %} + + {% include "base/_resourcebase_contact_snippet.html" %} +
    + + + {% if GEONODE_SECURITY_ENABLED %} + {% include "_permissions_form.html" %} + {% endif %} + +
    +
    +{% endblock %} + +{% block extra_script %} + + {% if GEOGIG_ENABLED and resource.link_set.geogig %} + {% with "_geogig_scripts.html" as geogig_scripts_template %} + {% include geogig_scripts_template %} + {% endwith %} + {% endif %} + + {% if request.user.is_authenticated %} + {% user_rating_js request.user resource "layer" %} + {% else %} + {% overall_rating resource 'layer' as the_layer_rating %} + {% endif %} + {% include 'rating.html' %} + {% include 'request_download.html' %} + + + {% if GEONODE_SECURITY_ENABLED %} + {% include "_permissions_form_js.html" %} + {% endif %} +{% endblock extra_script %} diff --git a/haitidata/templates/layers-paolo/layer_detail.html.save b/haitidata/templates/layers-paolo/layer_detail.html.save new file mode 100644 index 0000000..9662e80 --- /dev/null +++ b/haitidata/templates/layers-paolo/layer_detail.html.save @@ -0,0 +1,601 @@ +{% extends "layers/layer_base.html" %} +{% load i18n %} +{% load dialogos_tags %} +{% load agon_ratings_tags %} +{% load bootstrap_tags %} +{% load pagination_tags %} +{% load url from future %} +{% load base_tags %} +{% load guardian_tags %} + +{% block title %}{{ block.super }} {% trans "Layers" %} | {{ resource.title|default:resource.typename }}{% endblock %} +{% block page-title %}{% trans "Explore Layers" %}{% endblock %} + +{% block head %} + + {% if TWITTER_CARD %} + {% include "base/_resourcebase_twittercard.html" %} + {% endif %} + + {% if OPENGRAPH_ENABLED %} + {% include "base/_resourcebase_opengraph.html" %} + {% endif %} + + {% if preview == 'geoext' %} + {% include "layers/layer_geoext_map.html" %} + {% elif preview == 'OL3' %} + {% include "layers/layer_ol3_map.html" %} + {% elif preview == 'react' %} + {% include 'geonode-client/layer_map.html' %} + {% else %} + {% include "layers/layer_leaflet_map.html" %} + {% endif %} +{{ block.super }} +{% endblock %} + + +{% block body_class %}layers{% endblock %} + +{% block subheader %} +
    +
    +
    +
    +

    {{ resource.title|default:resource.typename }}

    +

    + {{ resource.service_type }} + {% if resource.category %} + {% trans "in" %} {{ resource.category }} | + {% endif %} + {% if resource.date %} + {% if resource.date_type == 'creation' %} {% trans "Created on" %} {{ resource.date }} + {% elif resource.date_type == 'publication' %} {% trans "Published on" %} {{ resource.date }} + {% else %} {% trans "Updated on" %} {{ resource.date }} + {% endif %} + {% endif %} +

    + {% block social_links %} + {% if SOCIAL_BUTTONS %} + {% include "social_links.html" %} + {% endif %} + {% endblock %} +
    +
    +
    +
    +{% endblock %} + +{% block body_outer %} +
    +
    + +
    +
    +
    + +
    + {% include "_actions.html" %} +
    + +
    + +
    + {% include "base/resourcebase_info_panel.html" %} +
    + + {% if resource.is_mosaic %} +
    +
    + +
    + {% csrf_token %} +   +
    + {% if filter %} + {% trans "Active Filter:" %} {{ filter }} + {% endif %} +
    + + + + + + + + + + + + {% autopaginate all_granules.features 10 %} + {% for feature in granules.features %} + + + + + + + + {% endfor %} + +
    {% trans "Bounding Box" %} (minX,minY,maxX,maxY){% trans "Time" %}{% trans "Actions" %}
    {% if feature.properties.time %}{{ feature.properties.time }}{% endif %} + Granule Preview + Granule Remove + +
    +
    + {% paginate %} +
    + {% endif %} + +
    + {% if resource.is_mosaic %} + + + + + + + + + + + + + + + + +
    {% trans "Dimension" %}{% trans "Enabled" %}{% trans "Regex" %}
    {% trans "TIME" %}{% if resource.has_time %}{% trans "True" %}{% else %}{% trans "False" %}{% endif %}{% if resource.time_regex %}{{ resource.time_regex }}{% else %} {% endif %}
    + {% endif %} + {% if resource.attribute_set.all %} + + + + + + + {% if wps_enabled %} + + + + + {% endif %} + + + + {% for attribute in resource.attributes %} + + + + + {% if wps_enabled %} + {% if attribute.unique_values == "NA" %} + + {% else %} + + {% endif %} + + + + {% endif %} + + {% endfor %} + +
    {% trans "Attribute Name" %}{% trans "Label" %}{% trans "Description" %}{% trans "Range" %}{% trans "Average" %}{% trans "Median" %}{% trans "Standard Deviation" %}
    {{ attribute }}{{ attribute.attribute_label|default:"" }}{{ attribute.description|default:"" }}{{ attribute.unique_values }} + + {{ attribute.average|floatformat:"2" }}{{ attribute.median|floatformat:"2" }}{{ attribute.stddev|floatformat:"2" }}
    + {% endif %} +
    + +
    + {% with resource as obj %} + {% include "_comments.html" %} + {% endwith %} +
    + + {% if GEOGIG_ENABLED and resource.link_set.geogig %} + {% with "_geogig_layer_detail.html" as geogig_template %} +
    + {% with resource as obj %} + {% include geogig_template %} + {% endwith %} +
    + {% endwith %} + {% endif %} + +
    + + {% if request.user.is_authenticated %} +

    {% trans "Rate this layer" %}

    + {% user_rating request.user resource "layer" as user_layer_rating %} +
    + {% endif %} +

    {% trans 'Average Rating' %}

    + {% overall_rating resource "layer" as layer_rating %} + {% num_ratings resource as num_votes %} +
    ({{num_votes}}) +
    + +
    + +
    + +
    + +
      + {% if resource.storeType != "remoteStore" %} +
    • + {% if links or links_download %} + + {% else %} + {% if request.user.is_authenticated %} + + {% endif %} + {% endif %} +
    • + {% endif %} + + + {% if GEOSERVER_BASE_URL %} + {% get_obj_perms request.user for resource.layer as "layer_perms" %} + {% endif %} + +
    • + + + +
    • + + {% if "change_resourcebase_metadata" in perms_list or "change_resourcebase" in perms_list or "delete_resourcebase" in perms_list or "change_layer_style" in layer_perms %} +
    • + +
    • + + {% endif %} + +
    • + +
    • + + + + {% if resource.get_legend %} +
    • +

      {%trans "Legend" %}

      +

      {{ style.sld_title }}

      + {% if resource.get_legend.link_type == 'image' %} + {% if request.user.is_authenticated and 'access_token' in request.session %} +

      + {% else %} +

      + {% endif %} + {% else %} +
      + {% endif %} +
    • + {% endif %} +
    • +

      {% trans "Maps using this layer" %}

      + {% if resource.maps %} +

      {% trans "List of maps using this layer:" %}

      + {% endif %} +
        + {% for maplayer in resource.maps %} +
      • {{ maplayer.map.title }}
      • + {% empty %} +
      • {% trans "This layer is not currently used in any maps." %}
      • + {% endfor %} +
      +
    • +
    • +

      {% trans "Create a map using this layer" %}

      +

      {% trans "Click the button below to generate a new map based on this layer." %}

      + {% trans "Create a Map" %} +
    • + + {% if documents.count > 0 %} +
    • +

      {% trans "Documents related to this layer" %}

      +

      {% trans "List of documents related to this layer:" %}

      + +
    • + {% endif %} + + {% if user.is_authenticated %} +
    • +

      {% trans "Styles" %}

      +

      {% trans "The following styles are associated with this layer. Choose a style to view it in the preview map." %}

      +
        + {% for style in resource.styles.all %} +
      • + {% if resource.default_style == style %} + + (default style) + {% else %} + + {% endif %} + {{ style.sld_title }} +
      • + {% empty %} +
      • {% trans "No styles associated with this layer" %}
      • + {% endfor %} +
      +
    • + {% endif %} + + {% if GEONODE_SECURITY_ENABLED %} + {% if "change_resourcebase_permissions" in perms_list %} +
    • +

      {% trans "Permissions" %}

      +

      {% trans "Click the button below to change the permissions of this layer." %}

      +

      {% trans "Change Layer Permissions" %}

      +
    • + {% endif %} + {% endif %} + + {% if resource.storeType == "remoteStore" %} +
    • +

      {% trans "External service layer" %}

      +
      {% trans "Source" %}: {{ resource.service.title }}
      +
      {% trans "Type" %}: {{ resource.service.type }}
      +
    • + {% endif %} + + {% include "base/_resourcebase_contact_snippet.html" %} +
    + + + {% if GEONODE_SECURITY_ENABLED %} + {% include "_permissions_form.html" %} + {% endif %} + +
    +
    +{% endblock %} + +{% block extra_script %} + + {% if GEOGIG_ENABLED and resource.link_set.geogig %} + {% with "_geogig_scripts.html" as geogig_scripts_template %} + {% include geogig_scripts_template %} + {% endwith %} + {% endif %} + + {% if request.user.is_authenticated %} + {% user_rating_js request.user resource "layer" %} + {% else %} + {% overall_rating resource 'layer' as the_layer_rating %} + {% endif %} + {% include 'rating.html' %} + {% include 'request_download.html' %} + + + {% if GEONODE_SECURITY_ENABLED %} + {% include "_permissions_form_js.html" %} + {% endif %} +{% endblock extra_script %} diff --git a/haitidata/templates/layers/layer_geoext_map.html b/haitidata/templates/layers-paolo/layer_geoext_map.html similarity index 100% rename from haitidata/templates/layers/layer_geoext_map.html rename to haitidata/templates/layers-paolo/layer_geoext_map.html diff --git a/haitidata/templates/layers/layer_granule_remove.html b/haitidata/templates/layers-paolo/layer_granule_remove.html similarity index 100% rename from haitidata/templates/layers/layer_granule_remove.html rename to haitidata/templates/layers-paolo/layer_granule_remove.html diff --git a/haitidata/templates/layers/layer_leaflet_map.html b/haitidata/templates/layers-paolo/layer_leaflet_map.html similarity index 100% rename from haitidata/templates/layers/layer_leaflet_map.html rename to haitidata/templates/layers-paolo/layer_leaflet_map.html diff --git a/haitidata/templates/layers/layer_list.html b/haitidata/templates/layers-paolo/layer_list.html similarity index 100% rename from haitidata/templates/layers/layer_list.html rename to haitidata/templates/layers-paolo/layer_list.html diff --git a/haitidata/templates/layers/layer_map.html b/haitidata/templates/layers-paolo/layer_map.html similarity index 100% rename from haitidata/templates/layers/layer_map.html rename to haitidata/templates/layers-paolo/layer_map.html diff --git a/haitidata/templates/layers/layer_metadata.html b/haitidata/templates/layers-paolo/layer_metadata.html similarity index 100% rename from haitidata/templates/layers/layer_metadata.html rename to haitidata/templates/layers-paolo/layer_metadata.html diff --git a/haitidata/templates/layers/layer_metadata_detail.html b/haitidata/templates/layers-paolo/layer_metadata_detail.html similarity index 100% rename from haitidata/templates/layers/layer_metadata_detail.html rename to haitidata/templates/layers-paolo/layer_metadata_detail.html diff --git a/haitidata/templates/layers/layer_ol3_map.html b/haitidata/templates/layers-paolo/layer_ol3_map.html similarity index 100% rename from haitidata/templates/layers/layer_ol3_map.html rename to haitidata/templates/layers-paolo/layer_ol3_map.html diff --git a/haitidata/templates/layers/layer_remove.html b/haitidata/templates/layers-paolo/layer_remove.html similarity index 100% rename from haitidata/templates/layers/layer_remove.html rename to haitidata/templates/layers-paolo/layer_remove.html diff --git a/haitidata/templates/layers/layer_replace.html b/haitidata/templates/layers-paolo/layer_replace.html similarity index 100% rename from haitidata/templates/layers/layer_replace.html rename to haitidata/templates/layers-paolo/layer_replace.html diff --git a/haitidata/templates/layers/layer_style_manage.html b/haitidata/templates/layers-paolo/layer_style_manage.html similarity index 100% rename from haitidata/templates/layers/layer_style_manage.html rename to haitidata/templates/layers-paolo/layer_style_manage.html diff --git a/haitidata/templates/layers/wps_execute_gs_aggregate.xml b/haitidata/templates/layers-paolo/wps_execute_gs_aggregate.xml similarity index 100% rename from haitidata/templates/layers/wps_execute_gs_aggregate.xml rename to haitidata/templates/layers-paolo/wps_execute_gs_aggregate.xml diff --git a/haitidata/templates/layers/wps_execute_gs_unique.xml b/haitidata/templates/layers-paolo/wps_execute_gs_unique.xml similarity index 100% rename from haitidata/templates/layers/wps_execute_gs_unique.xml rename to haitidata/templates/layers-paolo/wps_execute_gs_unique.xml diff --git a/haitidata/templates/layers/layer_detail.html b/haitidata/templates/layers/layer_detail.html index 2ae8065..6725573 100644 --- a/haitidata/templates/layers/layer_detail.html +++ b/haitidata/templates/layers/layer_detail.html @@ -8,8 +8,7 @@ {% load base_tags %} {% load guardian_tags %} -{% block title %}{{ block.super }} {% trans "Layers" %} | {{ resource.title|default:resource.typename }}{% endblock %} -{% block page-title %}{% trans "Explore Layers" %}{% endblock %} +{% block title %}{{ resource.title|default:resource.typename }} — {{ block.super }}{% endblock %} {% block head %} @@ -36,36 +35,11 @@ {% block body_class %}layers{% endblock %} -{% block subheader %} -
    -
    -
    -
    -

    {{ resource.title|default:resource.typename }}

    -

    - {{ resource.service_type }} - {% if resource.category %} - {% trans "in" %} {{ resource.category }} | - {% endif %} - {% if resource.date %} - {% if resource.date_type == 'creation' %} {% trans "Created on" %} {{ resource.date }} - {% elif resource.date_type == 'publication' %} {% trans "Published on" %} {{ resource.date }} - {% else %} {% trans "Updated on" %} {{ resource.date }} - {% endif %} - {% endif %} -

    - {% block social_links %} - {% if SOCIAL_BUTTONS %} - {% include "social_links.html" %} - {% endif %} - {% endblock %} -
    -
    -
    -
    -{% endblock %} - {% block body_outer %} + +
    @@ -227,6 +201,24 @@ {% endif %} + {% block social_links %} + {% if SOCIAL_BUTTONS %} + {% include "social_links.html" %} + {% endif %} + {% endblock %} + +
    +
      + {% for chart in resource.chart_set.all %} +
    • {{ chart.get_type_display }}, Category field = {{chart.category}}, Quantity field = {{chart.quantity}}
    • + {% empty %} +
    • No charts available at this time

    • + {% endfor %} +
    + + Generate New Chart +
    +
    {% with resource as obj %} {% include "_comments.html" %} @@ -266,8 +258,8 @@ {% if resource.storeType != "remoteStore" %}
  • {% if links or links_download %} - - {% else %} + + {% else %} {% if request.user.is_authenticated %} {% endif %} @@ -279,7 +271,7 @@
  • +
  • +

    {% trans "Charts with this layer" %}

    + {% if resource.maps %} +

    {% trans "List of chart with this layer:" %}

    + {% endif %} +
      + {% for chart in resource.chart_set.all %} +
    • {{ chart.get_type_display }}, Category field = {{chart.category}}, Quantity field = {{chart.quantity}}
    • + {% empty %} +
    • No charts available at this time

    • + {% endfor %} +
    +
  • +
  • +

    {% trans "Create a chart using this layer" %}

    +

    {% trans "Click the button below to generate a new chart based on this layer, choosing a quantity and a category field." %}

    + +
    +
    + {% csrf_token %} +
    + +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +

    Suggested title:

    +

    Text_di provas

    +
    +
    +
    + +
    + + +
    +
    + + +
    +
    +
  • + + + + {% if documents.count > 0 %}
  • {% trans "Documents related to this layer" %}

    @@ -542,6 +731,7 @@ {% endblock %} {% block extra_script %} +{{ block.super }} {% if GEOGIG_ENABLED and resource.link_set.geogig %} {% with "_geogig_scripts.html" as geogig_scripts_template %} diff --git a/haitidata/templates/site_base.html b/haitidata/templates/site_base.html index ace650b..8e8b490 100644 --- a/haitidata/templates/site_base.html +++ b/haitidata/templates/site_base.html @@ -47,79 +47,79 @@
  • -
  • - - -
  • - {% block extra_tab %} - {% endblock %} - {% endblock %} - - -
    -
    - - {% endblock header %} - + +
  • + + +
  • + {% block extra_tab %} + {% endblock %} + {% endblock %} + + +
    + + +{% endblock header %} + - {% block middle %} +{% block middle %}

    {% block page-title %}{% endblock %}

    @@ -132,12 +132,12 @@ {% include "_messages.html" %} {% block body_outer %}
    -
    - {% block body %}{% endblock %} -
    -
    - {% block sidebar %}{% endblock %} -
    +
    + {% block body %}{% endblock %} +
    +
    + {% block sidebar %}{% endblock %} +
    {% endblock %}
    diff --git a/haitidata/urls.py b/haitidata/urls.py index 2d53e1e..6acf437 100644 --- a/haitidata/urls.py +++ b/haitidata/urls.py @@ -8,6 +8,9 @@ urlpatterns = patterns('', url(r'^/?$', TemplateView.as_view(template_name='site_index.html'), name='home'), - ) + urlpatterns + ) + urlpatterns + [ + url(r'^chart/', include('charts_app.urls')), + url(r'^table/', include('wfs_harvest.urls')) + ] urlpatterns += importer_urlpatterns diff --git a/wfs_harvest/__init__.py b/wfs_harvest/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/wfs_harvest/admin.py b/wfs_harvest/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/wfs_harvest/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/wfs_harvest/migrations/__init__.py b/wfs_harvest/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/wfs_harvest/models.py b/wfs_harvest/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/wfs_harvest/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/wfs_harvest/templates/wfs-harvest/field_choice.html b/wfs_harvest/templates/wfs-harvest/field_choice.html new file mode 100644 index 0000000..b9312ef --- /dev/null +++ b/wfs_harvest/templates/wfs-harvest/field_choice.html @@ -0,0 +1,41 @@ +

    Field choice

    +

    Choose category field

    + +
    + +

    Choose quantity field

    + +
    +
    + Build Chart + Add Chart +
    + \ No newline at end of file diff --git a/wfs_harvest/tests.py b/wfs_harvest/tests.py new file mode 100644 index 0000000..fb01967 --- /dev/null +++ b/wfs_harvest/tests.py @@ -0,0 +1,20 @@ +import urllib + +from django.test import SimpleTestCase +from django.core.urlresolvers import reverse + +from . import views + +# Create your tests here. +class GetFieldsView(SimpleTestCase): + def test_non_existing_lyr(self): + # url = reverse(views.get_fields) + enc_lyrname = urllib.urlencode({'lyrname': 'idontexist'}) + # complete_url = url + '?' + enc_lyrname + # self.client.get('/table') + # self.client.get(complete_url) + self.assertTrue(False) + + def test_non_existing_field(self): + # self.client.get(reverse('wfs_harvest:get_fields')) + self.assertTrue(False) \ No newline at end of file diff --git a/wfs_harvest/urls.py b/wfs_harvest/urls.py new file mode 100644 index 0000000..c29d41e --- /dev/null +++ b/wfs_harvest/urls.py @@ -0,0 +1,8 @@ +from django.conf.urls import url + +from . import views + +urlpatterns = [ + url(r'^$', views.get_wfs_csv), + url(r'^fields$', views.get_fields) + ] diff --git a/wfs_harvest/utils.py b/wfs_harvest/utils.py new file mode 100644 index 0000000..c599214 --- /dev/null +++ b/wfs_harvest/utils.py @@ -0,0 +1,56 @@ +import urllib +import xml.etree.ElementTree as ET + +from geonode.layers.models import Layer + + +def get_fields(layer_id): + layer = Layer.objects.get(pk=layer_id) + lyrname = layer.typename + params = urllib.urlencode({ + 'service':'WFS', + 'version':'1.1.0', + 'request':'DescribeFeatureType', + 'typename':lyrname + }) + + wfs_request = urllib.urlopen('http://localhost/geoserver/ows?%s' + % params) + content = wfs_request.read() + + root = ET.fromstring(content) + namespace = root.tag.split('}')[0] + '}' + xpath = ('./{0}complexType/{0}complexContent/' + '{0}extension/{0}sequence/{0}element').format(namespace) + numeric_types = ['byte', 'decimal', 'int', 'integer', 'long', 'short', + 'boolean', 'double', 'float'] + fields = {} + for element in root.findall(xpath): + type = element.attrib['type'] + if not type.startswith('gml:'): + fields[element.attrib['name']] = type[4:] + + fieldnames = fields.keys() + num_fieldnames = [k for k, v in fields.iteritems() if v in numeric_types] + + return fieldnames, num_fieldnames + + +def get_featno(layer_id): + lyr = Layer.objects.get(pk=layer_id) + wfs_baseurl = lyr.link_set.get(link_type='OGC:WFS').url + + params = urllib.urlencode({ + 'service': 'WFS', + 'version': '1.1.0', + 'request': 'GetFeature', + 'typename': lyr.typename, + 'resultType': 'hits' + }) + + wfs_count_request = urllib.urlopen(wfs_baseurl + '?%s' % params) + content = wfs_count_request.read() + + root = ET.fromstring(content) + + return int(root.attrib['numberOfFeatures']) diff --git a/wfs_harvest/views.py b/wfs_harvest/views.py new file mode 100644 index 0000000..b11b404 --- /dev/null +++ b/wfs_harvest/views.py @@ -0,0 +1,69 @@ +import urllib +import xml.etree.ElementTree as ET + +from django.http import HttpResponse +from django.shortcuts import render +from django.conf import settings + +from geonode.layers.models import Layer + + +def get_fields(request): + lyrname = request.GET['lyrname'] + params = urllib.urlencode({ + 'service':'WFS', + 'version':'1.1.0', + 'request':'DescribeFeatureType', + 'typename':lyrname + }) + + wfs_request = urllib.urlopen('http://localhost/geoserver/ows?%s' + % params) + content = wfs_request.read() + + root = ET.fromstring(content) + namespace = root.tag.split('}')[0] + '}' + xpath = ('./{0}complexType/{0}complexContent/' + '{0}extension/{0}sequence/{0}element').format(namespace) + numeric_types = ['byte', 'decimal', 'int', 'integer', 'long', 'short', + 'boolean', 'double', 'float'] + fields = {} + for element in root.findall(xpath): + type = element.attrib['type'] + if not type.startswith('gml:'): + fields[element.attrib['name']] = type[4:] + + fieldnames = fields.keys() + num_fieldnames = [k for k, v in fields.iteritems() if v in numeric_types] + + context = { + 'lyrname': lyrname, + 'fieldnames': fieldnames, + 'num_fieldnames': num_fieldnames + } + return render(request, 'wfs_harvest/field_choice.html', context) + + +def get_wfs_csv(request): + qdict = request.GET + typename = qdict['lyrname'] + category_field = qdict['category'] + quantity_field = qdict['quantity'] + + params = urllib.urlencode({ + 'service':'WFS', + 'version':'1.1.0', + 'request':'GetFeature', + 'typename':typename, + 'propertyName':category_field + ',' + quantity_field, + 'outputFormat':'csv', + 'maxFeatures': str(settings.MAX_CSV_RECORDS) + }) + + lyr = Layer.objects.get(typename=typename) + wfs_baseurl = lyr.link_set.get(link_type='OGC:WFS').url + wfs_request = urllib.urlopen(wfs_baseurl + '?%s' % params) + content = wfs_request.read() + response = HttpResponse(content, content_type='text/csv') + response['Content-Disposition'] = 'attachment; filename="myfile.csv"' + return response From d63421a37e70f9c31a11820ade13d1870b0053a9 Mon Sep 17 00:00:00 2001 From: Emere Date: Mon, 3 Jul 2017 10:53:10 +0200 Subject: [PATCH 02/70] Added Simone's commits --- .gitignore | 3 + .idea/vcs.xml | 6 ++ charts_app/models.py | 28 ++++++- charts_app/urls.py | 8 +- charts_app/views.py | 84 +------------------ haitidata/settings.py | 5 +- .../templates/charts_app/chart_base.html | 2 +- .../templates/charts_app/chart_list.html | 51 +++++++++++ .../templates/geonode-client/layer_map.html | 4 +- wfs_harvest/views.py | 13 ++- 10 files changed, 110 insertions(+), 94 deletions(-) create mode 100644 .idea/vcs.xml create mode 100644 haitidata/templates/charts_app/chart_list.html diff --git a/.gitignore b/.gitignore index b903977..9ce3160 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,6 @@ geoserver/ uploaded/ development.db development.db-journal + +# PyCharm +.idea diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/charts_app/models.py b/charts_app/models.py index 298ff2b..e8200a8 100644 --- a/charts_app/models.py +++ b/charts_app/models.py @@ -3,10 +3,11 @@ from django.core.urlresolvers import reverse from django.core.exceptions import ValidationError from django.utils.translation import ugettext_lazy as _ from django.conf import settings +from django.forms import ModelForm, ValidationError as VE from geonode.layers.models import Layer -from wfs_harvest.utils import get_featno +from wfs_harvest.utils import get_featno, get_fields def validate_wfs(value): @@ -51,3 +52,28 @@ class Chart(models.Model): def get_absolute_url(self): return reverse('chart_detail', kwargs={'pk': self.pk}) + +class ChartForm(ModelForm): + def clean(self): + cleaned_data = super(ChartForm, self).clean() + layer = cleaned_data.get('layer') + category = cleaned_data.get('category') + quantity = cleaned_data.get('quantity') + + categories, quantities = get_fields(layer) + + if category not in categories: + lyr = Layer.objects.get(pk=layer) + raise VE(_('%(lyr_title)s does not contain the field %(category)s'), + code='non_extant_category_field', + params={'lyr_title': lyr.title, 'category': category}) + + if quantity not in quantities: + lyr = Layer.objects.get(pk=layer) + raise VE(_('%(lyr_title)s does not contain the field %(quantity)s'), + code='non_extant_quantity_field', + params={'lyr_title': lyr.title, 'quantity': quantity}) + + class Meta: + model = Chart + fields = '__all__' \ No newline at end of file diff --git a/charts_app/urls.py b/charts_app/urls.py index 9d7ab99..842fce4 100644 --- a/charts_app/urls.py +++ b/charts_app/urls.py @@ -2,13 +2,7 @@ from django.conf.urls import url from . import views -urlpatterns = [url(r'^sample_csv$', views.get_csv, name='get_csv'), - url(r'^sample_csv2$', views.get_csv_aggr, name='get_csv2'), - url(r'^pie_chart_v1$', views.pie_chart_v1), - url(r'^donut_chart_v1$', views.donut_chart_v1), - url(r'^pie_chart_v2$', views.pie_chart_v2), - url(r'^donut_chart_v2$', views.donut_chart_v2), - url(r'^(?P[0-9]+)/$', views.ChartDetailView.as_view(), name='chart_detail'), +urlpatterns = [url(r'^(?P[0-9]+)/$', views.ChartDetailView.as_view(), name='chart_detail'), url(r'^add/(?P[0-9]+)/$', views.ChartCreate.as_view(), name='chart_add'), url(r'^(?P[0-9]+)/update/$', views.ChartUpdate.as_view(), name='chart_update'), url(r'^(?P[0-9]+)/delete/$', views.ChartDelete.as_view(), name='chart_delete') diff --git a/charts_app/views.py b/charts_app/views.py index d646bc6..093f319 100644 --- a/charts_app/views.py +++ b/charts_app/views.py @@ -7,7 +7,7 @@ from django.views.generic.edit import CreateView, UpdateView, DeleteView from geonode.layers.models import Layer -from .models import Chart +from .models import Chart, ChartForm from wfs_harvest.utils import get_fields @@ -16,8 +16,8 @@ class ChartDetailView(DetailView): class ChartCreate(CreateView): - model = Chart - fields = '__all__' + form_class = ChartForm + template_name = 'charts_app/chart_form.html' def get_initial(self): layer_id = self.kwargs['layer_id'] @@ -44,80 +44,4 @@ class ChartUpdate(UpdateView): class ChartDelete(DeleteView): model = Chart - success_url = '/' - - -def get_csv(request): - response = HttpResponse(content_type='text/csv') - response['Content-Disposition'] = 'attachment; filename="table.csv"' - - writer = csv.writer(response) - writer.writerow(['name', 'area']) - writer.writerow(['Af', 3.51]) - writer.writerow(['Ems / ems', 0.00]) - writer.writerow(['Ep / ep', 0.00]) - writer.writerow(['Lmst', 4.88]) - writer.writerow(['Mpb', 18.93]) - writer.writerow(['Pf', 30.53]) - writer.writerow(['Ppf', 6.84]) - writer.writerow(['Qa', 0.49]) - writer.writerow(['Qhac', 5.91]) - writer.writerow(['Qhad', 0.00]) - writer.writerow(['Qham', 11.01]) - writer.writerow(['Qht1', 1.10]) - writer.writerow(['Qht2', 27.60]) - writer.writerow(['Qpf', 34.40]) - writer.writerow(['Qphf', 42.30]) - - return response - -def get_csv_aggr(request): - response = HttpResponse(content_type='text/csv') - response['Content-Disposition'] = 'attachment; filename="table.csv"' - - writer = csv.writer(response) - writer.writerow(['name', 'area']) - writer.writerow(['Af', 3.51]) - writer.writerow(['Ems / ems', 0.00]) - writer.writerow(['Ep / ep', 0.00]) - writer.writerow(['Lmst', 4.88]) - writer.writerow(['Mpb', 18.93]) - writer.writerow(['Pf', 30.53]) - writer.writerow(['Ppf', 6.84]) - writer.writerow(['Qa', 0.49]) - writer.writerow(['Qhac', 5.91]) - writer.writerow(['Qhad', 0.00]) - writer.writerow(['Qham', 11.01]) - writer.writerow(['Qht1', 1.10]) - writer.writerow(['Qht2', 27.60]) - writer.writerow(['Qphf', 42.30]) - writer.writerow(['Af', 6.58]) - writer.writerow(['Qa', 30.78]) - writer.writerow(['Af', 16.58]) - - return response - - -def pie_chart_v1(request): - return render(request, 'pie_chart_v1.html') - - -def donut_chart_v1(request): - return render(request, 'donut_chart_v1.html') - - -def pie_chart_v2(request): - qdict = request.GET - typename = qdict['lyrname'] - category_field = qdict['category'] - quantity_field = qdict['quantity'] - context = { - 'lyrname': typename, - 'category': category_field, - 'quantity': quantity_field - } - return render(request, 'pie_chart_v2.html', context) - - -def donut_chart_v2(request): - return render(request, 'donut_chart_v2.html') + success_url = '/' \ No newline at end of file diff --git a/haitidata/settings.py b/haitidata/settings.py index e1470c1..5361f3b 100644 --- a/haitidata/settings.py +++ b/haitidata/settings.py @@ -53,7 +53,7 @@ LOCALE_PATHS = ( os.path.join(LOCAL_ROOT, 'locale'), ) + LOCALE_PATHS -INSTALLED_APPS = INSTALLED_APPS + ('haitidata', 'osgeo_importer', 'geonode-client', 'charts_app', 'wfs_harvest') +INSTALLED_APPS = INSTALLED_APPS + ('haitidata', 'osgeo_importer','charts_app', 'wfs_harvest') LAYER_PREVIEW_LIBRARY = 'react' @@ -112,7 +112,8 @@ CELERY_ALWAYS_EAGER = True IMPORT_TASK_SOFT_TIME_LIMIT = 90 MAX_CSV_RECORDS = 20000 - +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True SOCIAL_ORIGINS = [{ "label":"paper-plane-o", diff --git a/haitidata/templates/charts_app/chart_base.html b/haitidata/templates/charts_app/chart_base.html index 031c954..63868a1 100644 --- a/haitidata/templates/charts_app/chart_base.html +++ b/haitidata/templates/charts_app/chart_base.html @@ -4,7 +4,7 @@ {% block title %} {{ block.super }} {% endblock %} -{% block body_class %}charts{% endblock %} +{% block body_class %}Charts{% endblock %} {% block body_outer %} {% block body %}{% endblock body %} diff --git a/haitidata/templates/charts_app/chart_list.html b/haitidata/templates/charts_app/chart_list.html new file mode 100644 index 0000000..5c76b3c --- /dev/null +++ b/haitidata/templates/charts_app/chart_list.html @@ -0,0 +1,51 @@ +{% extends "charts_app/chart_base.html" %} +{% load i18n %} +{% load staticfiles %} +{% load url from future %} + +{% block title %}{{ block.super }} {% trans "Charts" %}{% endblock %} +{% block page-title %} + {% trans "Explore Charts" %} + {% if user.is_authenticated %} + + {% endif %} +{% endblock %} + +{% block body_class %}charts{% endblock %} + +{% block body %} + {% with include_type_filter='true' %} + {% with facet_type='documents' %} + {% with header='Document Type' %} + {% with filter='doc_type__in' %} + {% include "search/_search_content.html" %} + {% endwith %} + {% endwith %} + {% endwith %} + {% endwith %} + {% include "_bulk_permissions_form.html" %} +{% endblock %} + +{% block extra_script %} + {% if GEONODE_SECURITY_ENABLED %} + {% include "_permissions_form_js.html" %} + {% endif %} + + {% with include_spatial='true' %} + {% include 'search/search_scripts.html' %} + {% endwith %} +{% endblock extra_script %} diff --git a/haitidata/templates/geonode-client/layer_map.html b/haitidata/templates/geonode-client/layer_map.html index 2ba679b..bb77184 100644 --- a/haitidata/templates/geonode-client/layer_map.html +++ b/haitidata/templates/geonode-client/layer_map.html @@ -1,6 +1,6 @@ -{% load geonode_client_tags %} -{% client_viewer_js %} + + + {% block extra_head %} + {% endblock %} + {% endblock %} + + + + + + + {% block header %} + + {% endblock header %} + + + + +
    + {% block middle %} +
    + {% include "_status_message.html" %} + {% include "_announcements.html" %} + {% include "_messages.html" %} + {% block body_outer %} +
    +
    + {% block body %}{% endblock %} +
    +
    + {% block sidebar %}{% endblock %} +
    +
    + {% endblock %} +
    + {% endblock middle %} +
    + + {% block footer %} + + {% endblock footer %} + + + + {% if not user.is_authenticated %} + + {% endif %} + + + {% if DEBUG_STATIC %} + + + + + + + + + + + + + + {% else %} + + {% endif %} + + + {% include 'autocomplete_light/static.html' %} + + {% block extra_script %}{% endblock extra_script %} + + + + + + diff --git a/django_project/core/urls.py b/django_project/core/urls.py index 89a3480..9c300cb 100644 --- a/django_project/core/urls.py +++ b/django_project/core/urls.py @@ -2,22 +2,90 @@ from django.conf.urls import url, include from django.contrib import admin from django.conf.urls.i18n import i18n_patterns from django.views.generic import TemplateView +from geonode.sitemap import LayerSitemap, MapSitemap +from geonode.api.urls import api +from geonode.api.views import verify_token, roles, users, admin_role -import geonode +import autocomplete_light + +autocomplete_light.autodiscover() admin.autodiscover() +js_info_dict = { + 'domain': 'djangojs', + 'packages': ('geonode',) +} + +sitemaps = { + "layer": LayerSitemap, + "map": MapSitemap +} + urlpatterns = i18n_patterns( - url("^admin/", include(admin.site.urls)), url(r'^home', TemplateView.as_view(template_name="dummy_index.html"), name="layer_browse"), + url(r'^help/$', TemplateView.as_view(template_name='help.html'), name='help'), + url(r'^developer/$', TemplateView.as_view(template_name='developer.html'), name='developer'), + url(r'^about/$', TemplateView.as_view(template_name='about.html'), name='about'), url(r'^api/home/test', TemplateView.as_view(template_name="site_index.html"), name="home"), url(r'^chart/', include('charts_app.urls')), url(r'^table/', include('wfs_harvest.urls')), - url(r'^geonode/document/', include('geonode.documents.urls')), - url(r'^geonode/maps/', include('geonode.maps.urls')), - url(r'^geonode/people/', include('geonode.people.urls')), - url(r'^geonode/groups/', include('geonode.groups.urls')), - url(r'^geonode/', include('geonode.urls')), -) + url(r'^layers/', include('geonode.layers.urls')), -urlpatterns += geonode.proxy.urls.urlpatterns + # Map views + url(r'^maps/', include('geonode.maps.urls')), + + # Catalogue views + url(r'^catalogue/', include('geonode.catalogue.urls')), + + # data.json + url(r'^data.json$', 'geonode.catalogue.views.data_json', name='data_json'), + + # ident + url(r'^ident.json$', 'geonode.views.ident_json', name='ident_json'), + + # h keywords + url(r'^h_keywords_api$', 'geonode.views.h_keywords', name='h_keywords_api'), + + # Search views + url(r'^search/$', TemplateView.as_view(template_name='search/search.html'), name='search'), + + # Social views + url(r"^account/", include("account.urls")), + url(r'^people/', include('geonode.people.urls')), + url(r'^avatar/', include('avatar.urls')), + url(r'^comments/', include('dialogos.urls')), + url(r'^ratings/', include('agon_ratings.urls')), + url(r'^activity/', include('actstream.urls')), + url(r'^announcements/', include('announcements.urls')), + url(r'^messages/', include('user_messages.urls')), + url(r'^social/', include('geonode.social.urls')), + url(r'^security/', include('geonode.security.urls')), + + # Accounts + url(r'^account/ajax_login$', 'geonode.views.ajax_login', name='account_ajax_login'), + url(r'^account/ajax_lookup$', 'geonode.views.ajax_lookup', name='account_ajax_lookup'), + + # Meta + url(r'^lang\.js$', TemplateView.as_view(template_name='lang.js', content_type='text/javascript'), + name='lang'), + + url(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict, name='jscat'), + url(r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}, + name='sitemap'), + + url(r'^autocomplete/', include('autocomplete_light.urls')), + url(r'^admin/', include(admin.site.urls)), + url(r'^groups/', include('geonode.groups.urls')), + url(r'^documents/', include('geonode.documents.urls')), + url(r'^services/', include('geonode.services.urls')), + # OAuth Provider + url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')), + + # Api Views + url(r'^api/o/v4/tokeninfo', verify_token, name='tokeninfo'), + url(r'^api/roles', roles, name='roles'), + url(r'^api/adminRole', admin_role, name='adminRole'), + url(r'^api/users', users, name='users'), + url(r'', include(api.urls)), +) From 9c196de0043166a1b6339c5dffdef66342666bf2 Mon Sep 17 00:00:00 2001 From: meomancer Date: Thu, 3 Aug 2017 11:37:20 +0700 Subject: [PATCH 40/70] fix geonode static is not found in devweb --- .gitignore | 1 + django_project/core/settings/contrib.py | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 8eca957..66ad9e3 100644 --- a/.gitignore +++ b/.gitignore @@ -92,6 +92,7 @@ deployment/pg deployment/static deployment/media deployment/docker/71-apt-cacher-ng +django_project/geonode django_project/celerybeat-schedule # local media django_project/media diff --git a/django_project/core/settings/contrib.py b/django_project/core/settings/contrib.py index 1e6f3cf..7350c43 100644 --- a/django_project/core/settings/contrib.py +++ b/django_project/core/settings/contrib.py @@ -49,6 +49,7 @@ INSTALLED_APPS += ( 'oauth2_provider', # GeoNode internal apps + 'geonode', 'geonode.base', 'geonode.maps', 'geonode.people', From b0ddfb30a92c5709813358327afea9cd142ce97f Mon Sep 17 00:00:00 2001 From: Muhammad Anis Date: Fri, 4 Aug 2017 01:45:56 +0700 Subject: [PATCH 41/70] Add nginx reverse proxy for data --- deployment/docker-compose.yml | 1 + deployment/sites-enabled/default.conf | 9 +++++++++ django_project/core/settings/contrib.py | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/deployment/docker-compose.yml b/deployment/docker-compose.yml index 0658ccb..cf04213 100644 --- a/deployment/docker-compose.yml +++ b/deployment/docker-compose.yml @@ -119,6 +119,7 @@ web: - ./webroot-path:/home/web/webroot-path links: - uwsgi:uwsgi + - geoserver:geoserver ports: - "33300:8080" restart: always diff --git a/deployment/sites-enabled/default.conf b/deployment/sites-enabled/default.conf index a64abcf..1d4fc7b 100644 --- a/deployment/sites-enabled/default.conf +++ b/deployment/sites-enabled/default.conf @@ -3,6 +3,11 @@ upstream uwsgi { server uwsgi:8080; } + +upstream geoserver { + server geoserver:8080; +} + server { # OTF gzip compression gzip on; @@ -34,6 +39,10 @@ server { alias /home/web/static; expires 21d; # cache for 21 days } + + location /api/geoserver/ { + proxy_pass http://geoserver/geoserver/; + } # Finally, send all non-media requests to the Django server. location / { uwsgi_pass uwsgi; diff --git a/django_project/core/settings/contrib.py b/django_project/core/settings/contrib.py index 7350c43..aefb362 100644 --- a/django_project/core/settings/contrib.py +++ b/django_project/core/settings/contrib.py @@ -118,7 +118,7 @@ CACHE_TIME = int(os.getenv('CACHE_TIME', '0')) AUTH_USER_MODEL = os.getenv('AUTH_USER_MODEL', 'people.Profile') GEOSERVER_LOCATION = 'http://geoserver:8080/geoserver/' -GEOSERVER_PUBLIC_LOCATION = 'http://127.0.0.1:33308/geoserver/' +GEOSERVER_PUBLIC_LOCATION = 'http://0.0.0.0:33300/api/geoserver/' OGC_SERVER = { 'default': { From 3898471e8f39efb7e3e3508b93c429eaaf86a54e Mon Sep 17 00:00:00 2001 From: Dimas Date: Thu, 3 Aug 2017 17:28:08 +0700 Subject: [PATCH 42/70] Front end to download clip --- .../geonode/css/images/layers-2x.png | Bin 0 -> 1259 bytes .../geonode/css/images/layers.png | Bin 0 -> 696 bytes .../geonode/css/images/marker-icon-2x.png | Bin 0 -> 2586 bytes .../geonode/css/images/marker-icon.png | Bin 0 -> 1466 bytes .../geonode/css/images/marker-shadow.png | Bin 0 -> 618 bytes .../geonode/css/images/spritesheet-2x.png | Bin 0 -> 2078 bytes .../geonode/css/images/spritesheet.png | Bin 0 -> 1056 bytes .../geonode/css/images/spritesheet.svg | 27 +++++++++++ .../geonode/css/leaflet.draw.css | 9 ++++ .../geonode/js/draw/leaflet.draw.js | 9 ++++ django_project/core/settings/base.py | 2 +- .../core/templates/layers/layer_detail.html | 25 ++++++++++ .../templates/layers/layer_leaflet_map.html | 45 +++++++++++++++++- 13 files changed, 115 insertions(+), 2 deletions(-) create mode 100755 django_project/core/geonode_static/geonode/css/images/layers-2x.png create mode 100755 django_project/core/geonode_static/geonode/css/images/layers.png create mode 100755 django_project/core/geonode_static/geonode/css/images/marker-icon-2x.png create mode 100755 django_project/core/geonode_static/geonode/css/images/marker-icon.png create mode 100755 django_project/core/geonode_static/geonode/css/images/marker-shadow.png create mode 100755 django_project/core/geonode_static/geonode/css/images/spritesheet-2x.png create mode 100755 django_project/core/geonode_static/geonode/css/images/spritesheet.png create mode 100755 django_project/core/geonode_static/geonode/css/images/spritesheet.svg create mode 100755 django_project/core/geonode_static/geonode/css/leaflet.draw.css create mode 100755 django_project/core/geonode_static/geonode/js/draw/leaflet.draw.js diff --git a/django_project/core/geonode_static/geonode/css/images/layers-2x.png b/django_project/core/geonode_static/geonode/css/images/layers-2x.png new file mode 100755 index 0000000000000000000000000000000000000000..200c333dca9652ac4cba004d609e5af4eee168c1 GIT binary patch literal 1259 zcmVFhCYNy;#0irRPomHqW|G1C*;4?@4#E?jH>?v@U%cy?3dQAc-DchXVErpOh~ z-jbon+tNbnl6hoEb;)TVk+%hTDDi_G%i3*RZ&15!$Fjr^f;Ke&A@|?=`2&+{zr+3a z{D*=t(`AXyS%X7N z%a#RZw6vD^t_rnM`L4E>m=U&R!A-&}nZIi$BOPvkhrCuUe@BN~-lRD)f44;J%TwgE zcze8u!PQ_NR7?o(NylLXVTfDO zxs5=@|GsYEsNo4M#nT%N!UE(?dnS)t2+{ELYAFp*3=iF=|EQnTp`#vlSXuGVraYo? z+RCzXo6h3qA8{KG?S4nE(lM+;Eb4nT3XV;7gcAxUi5m)`k5tv}cPy()8ZR3TLW3I- zAS^}cq-IJvL7a4RgR!yk@~RT%$lA7{L5ES*hyx)M4(yxI$Ub(4f)K|^v1>zvwQY!_ zIrWw8q9GS^!Dp~}+?mbnB6jDF8mVlbQ!jFKDY;w=7;XO{9bq7>LXGK24WA`;rL)_Z z)&j}pbV(;6gY;VMhbxgvn`X;6x}VUEE-7 z%)7j-%t8S=ZL3yc)HbXDAqJZvBTPoiW_A-+a8m3_Z?v{DN7Tnr#O_VUMT0UBt$;p` zDh6JbGHN8JJ*JN%y2%msb97@_S>9!%Egwk;?PEkU9ntz&3uR}%Fj5d$JHQbQb3}a{ zSzFT^#n=VInPpcAS}CNxj?_ zVscANk5Cfz(51EI1pz};AWWb|kgbYNb4wCEGUn3+eMUMV?1-{=I4TlmLJMot@rd07 zZuo2hk1ccu{YmGkcYdWAVdk{Z4Nm?^cTD&}jGm+Q1SYIXMwmG*oO*83&#>l%nbR`G zhh=lZ%xIb7kU3#;TBbfECrnC9P=-XpL|TG2BoZdj61*XiFbW8?1Z_wp%#;>${SUIy V$8qr;L*)Pf002ovPDHLkV1hYLS~36t literal 0 HcmV?d00001 diff --git a/django_project/core/geonode_static/geonode/css/images/layers.png b/django_project/core/geonode_static/geonode/css/images/layers.png new file mode 100755 index 0000000000000000000000000000000000000000..1a72e5784b2b456eac5d7670738db80697af3377 GIT binary patch literal 696 zcmV;p0!RIcP)*@&l2<6p=!C&s@#ZL+%BQvF&b?w6S%wp=I>1QHj7AP5C)IWy#b znXXB;g;j=$a-tW89K%FbDceHVq&unY*Wx3L#=EGWH=rjqnp|4c_Ulec!ql3#G-5ZF zVlbBA@XP=)C8U&+Lrc)S4O5%1$&{(;7R^K(CSnvSr$v;+B$8q&7Bf|h$#PARo1^%M zf1H^nG-EiXVXr07OH(*8R)xa|FD;lXUlg_-%)~ZGsL2cX0NXaAzN2q%jqLRR6ruVk8`Jb7n#{`T;o@`F= z#3YcynIR^s83UNF3D!f5m#Mg)NJ24&Qfrqb&_z=yF;=B)#9Iq7u-@^O!(mW{D;qvr zPc)gVb%aowtS8m@ElL4A9G>w#ffQ~q{i&_i)*6f^)Sz|C?C>zb4Uo?H<-&Hz@a?J; z$ml@zGygWofb9$ZBj6aLjpLhsT2AzjOu=-*u_gSCULuqp7Vds@BKcX=lOk~^Pb;%&wG9p3o}FL;Zuhp5D3)R z2yY2yCGfH2=LJmOkQw^9n>daF6?Fz>oOD64$CM+_T`j0x%{zb|G zWolt{H|diO#S`|$6RM$ zYQuE4RW{2yZ`>fAt>jzyYyOB?)~HrQBlbbLT5yF%Xq8FEuzo80dd{%Q!{_)^mTE`^ z2$xe>TH$qiDJ+}(ajTp$Y*4vgGRrt^_?JwUO3+hm&{Mb<8aRtf7%F@*!JJv* zmcB*cag=-t4U&g79u1krRAKHHm?ZXHP8z-#KdAM9?vU7sxldD%A5;r0Rk~kblro}5 z9YhoJP18m~=v^kMBWPltYTV$TD;r4n^eZVWmDs^6;ZN_RG+a#^(N18a+%xd;JvScL zu54_hiMdFR4767cmcp!KOryQBQG{$|3e)h(z_sY-NRM>A$84n-CdxAt6V242bQmV| z86*uGCJtVTXCvLyz=eM@jE-Vz#IeA4DY~VhqL`R_>D;YIh9amQX~+l$Sfbohb*X)d zKiDG!?8t|64T_+_Jzbv6K)P|KG-6qDVGPYUwpPqb#c;-juz~ZW0bFF4JlB>cOB#?3 z9XJ~@0J1u{T_(66oVpmpLOkqOk6}qY=vN7820OS|_L-o5(4!i~Ivv=j{IKzS2m>C_ zhm9Npo09&0s*wy#K%InNpSW)yCZOhAFheUQtcXnn!x)WSjonNUm7@fguKPg0C3ESs~`Bd3Pyd$@XU8m z0JZWv0l=fZ{{jH?{!9Nt!mEGL|9_Oug?i>9H?4E!|Krk+(hy9WRiM;!>w8@J9&fq& z${#rK1z4j2$*KVGO=b{ivL6FFEPprv0No7|9RPB_H>dzW{;{(>P`XWmKn^Y#<8`e9 zc*;k@X>z(^khkvlh3UB1ICnF@RRHbZaQhkI;sl{txVGnBEzaFKZpw96Fm8qu^5@!a z+db!omc48o>}VvJr!j9Mpo^ZMPs2FKikZu-3edWhZ~5&Mp15G60gsVYic)|~eH4Q6 zF8d5^efqo~DD}CwRpRO|j91O-zygw(bv;<>V5MDzeC#nk zosJI@GCU;ylx)tp87H~!5Gl8^4UxdZ-ZLrRy7g=zwjIe|v>O(6W-QBuv-7h4HTLcz&ce9H!^9o^4XLD_t08@f%uD+tdxMAHzHi z6>y1>XBw|wNRu9u6j`13s*X9iz%Z1zep^?+<}$-U*uzd9$?LD0QWc+GSyhyvx<?!6YcvM{vC6CN2-dD>XyCsuOMe zdjA0H)tFMHvR%5Uqd_swkzDP0t5)bhy5xwusp(WsD}~`13N0NuN78MHcc03G_@3v- zZOvStb!W8+G+$o+mNh5)?USue0<9~5nql|l&C!mcb^cmUZGk2gF&p9IOMcs@2-WZX z+M_WESiwx34!IyuOY(`!=Sit;If5uuYqSJm`D>ogL1P7x5=v2W{zicaAxUs>WGzTn zQv?x3HR!VK$IB{-D-)cU&hLE;M2}umynSZBHRVLCW#WkaY>!>~#*V;;^Ck!H4Swwp zDHCGo7gMu}4-?)ga$s&da$6}|l&eSgpl~CnG5lbg z7&|&nHy^@(l0;d(4qw!>Pc+03BPqwvhV@DjJr)KAb74dUY>mzPErgW+cGhAfAE(Hx zg7S551PZuugrt1qVHk*xE*1`NeDO|ZnOO1ye(Ps{N=r+Q=S*|(%4dYb+TIr5*H@Ka z&IFce5q4snQ7O4sQm?Pxu??B#U>#Bu+HC!Ti{Sl150Y#4pk06Ac+lU@`2YRqk-uHH zZoIWi#kr-H+gi|P?w*2JMQ7U)c>*fCAPTksemc#0N4+Zgz+o*bN1@=(#&Q(RLz+r2 zQx|up>q>^w^^^t*`_3bp*JBDwCvP3iT>oMu+dLrW{Yd*GhC1Kx;_L$zF%*j;?iDxZ zrao$m-Bw;}qtlD8Ts>}{*(A|it9iEx_ZRY$yVv3y#q}J<;l}p;3_y0NqKJBW%sac- z#s<-=rSr4%CNFQcuf<8$A3ba|hx+!=-B0jwr*}bFG1p0OLTqz#DYd z16dVY=E5n{UkaA*7{FAF7c$=SE0gV@(AxW_6rfOFvBFyfQpO=ChwyqQo?nZOT`6__ zP3(sCcoy|xktOO{hUoSFKDM)^*yWXvlS$9yTyC~k^q#t~$$O;oU_E7XGiY~S^b+mS zVh=RZHn+0(T-ooM5xx%AW=ZUqv zgKQURIr-z7x5ejdVPYlT>F)dyou|#!MM#5qXK_BVQyz*bJ!*A&^rr((=SaeGlUNwV z01+e{DcnsPPIth+gTfMc34NrqGRM-T5f0=)<0vZ6?K`I0Z1Y3GdqxI|$iyh%qoeNX UQO-*oc+)|Q_08}VdXD6O0C*xx%>V!Z literal 0 HcmV?d00001 diff --git a/django_project/core/geonode_static/geonode/css/images/marker-icon.png b/django_project/core/geonode_static/geonode/css/images/marker-icon.png new file mode 100755 index 0000000000000000000000000000000000000000..950edf24677ded147df13b26f91baa2b0fa70513 GIT binary patch literal 1466 zcmV;r1x5OaP)P001cn1^@s6z>|W`000GnNklGNuHDcIX17Zdjl&3`L?0sTjIws<{((Dh&g-s0<@jYQyl?D*X^?%13;ml^gy> ziMrY_^1WI=(g@LMizu=zCoA>C`6|QEq1eV92k*7m>G65*&@&6)aC&e}G zI)pf-Za|N`DT&Cn1J|o`19mumxW~hiKiKyc-P`S@q)rdTo84@QI@;0yXrG%9uhI>A zG5QHb6s4=<6xy{1 z@NMxEkryp{LS44%z$3lP^cX!9+2-;CTt3wM4(k*#C{aiIiLuB>jJj;KPhPzIC00bL zU3a#;aJld94lCW=`4&aAy8M7PY=HQ>O%$YEP4c4UY#CRxfgbE~(|uiI=YS8q;O9y6 zmIkXzR`}p7ti|PrM3a}WMnR=3NVnWdAAR>b9X@)DKL6=YsvmH%?I24wdq?Gh54_;# z$?_LvgjEdspdQlft#4CQ z`2Zyvy?*)N1Ftw|{_hakhG9WjS?Az@I@+IZ8JbWewR!XUK4&6346+d#~gsE0SY(LX8&JfY>Aj)RxGy96nwhs2rv zzW6pTnMpFkDSkT*a*6Dx|u@ds6ISVn0@^RmIsKZ5Y;bazbc;tTSq(kg(=481ODrPyNB6n z-$+U}(w$m6U6H$w17Bw+wDaFIe~GvNMYvnw31MpY0eQKT9l>SU``8k7w4)z!GZKMI z#_cEKq7k~i%nlK@6c-K?+R;B#5$?T#YpKD`t_4bAs^#E+@5QW$@OX3*`;(#{U^d-vY)&xEE>n5lYl&T?Amke9$Lam@{1K@O ze*LXqlKQHiv=gx+V^Cbb2?z@ISBQ*3amF;9UJ3SBg(N|710TLamQmYZ&Qjn2LuO<* zCZlB4n%@pc&7NNnY1}x+NWpHlq`OJEo|`aYN9<`RBUB+79g;>dgb6YlfN#kGL?lO_ z!6~M^7sOnbsUkKk<@Ysie&`G>ruxH&Mgy&8;i=A zB9OO!xR{AyODw>DS-q5YM{0ExFEAzt zm>RdS+ssW(-8|?xr0(?$vBVB*%(xDLtq3Hf0I5yFm<_g=W2`QWAax{1rWVH=I!VrP zs(rTFX@W#t$hXNvbgX`gK&^w_YD;CQ!B@e0QbLIWaKAXQe2-kkloo;{iF#6}z!4=W zi$giRj1{ zt;2w`VSCF#WE&*ev7jpsC=6175@(~nTE2;7M-L((0bH@yG}-TB$R~WXd?tA$s3|%y zA`9$sA(>F%J3ioz<-LJl*^o1|w84l>HBR`>3l9c8$5Xr@xCiIQ7{x$fMCzOk_-M=% z+{a_Q#;42`#KfUte@$NT77uaTz?b-fBe)1s5XE$yA79fm?KqM^VgLXD07*qoM6N<$ Ef<_J(9smFU literal 0 HcmV?d00001 diff --git a/django_project/core/geonode_static/geonode/css/images/spritesheet-2x.png b/django_project/core/geonode_static/geonode/css/images/spritesheet-2x.png new file mode 100755 index 0000000000000000000000000000000000000000..1525c9f698ed277b39e7bb19a99309cf4f536a46 GIT binary patch literal 2078 zcmb7F`#%$k1D$BfH!~^k=PfCugrO!Mkq|<-^O!XY*ZVOu%siS+uT@?v3AxG0V+f0R z>}$2%Z!3?eEhE!fVa+2n&$`{u_b<5ThjY&7e9q@{emvKFyw52sX)6H$0A+VK7e4@C zhwd*A-39!`M_;2*zeFqbEG+e6Vq_{7nGykTx||puVdx%@jEeA!Kwi#B{$B(X08nJQ zyEyr$kAIyU@fCRNV<#sU$jU(<{lR`tujG4xrpKEBp>jTQH9I_auGvFf{K3>KhxOLd zl4N%dxT+T!zc*`(TK)Mt{U*5yX&)@5mYSRF{*@ z9~C=Baz!GPWJ6z1Z#8%d|56U{0k|NK#R`F+yQ&>SfRDHonqHPLNq!AYo)ki{90zlJDo3HY5-+U2Bs@KK%VhB$Uem6^uO?2h2S%GISVu8+_ z;!PaQbUf{>5T>G&K_(M#naJp20qv64a}143oZdIgLTW1%5C0tll-H^JNP3^OIFr;v z$IL+>Xk$!o68##34C%4Ho~iL}ww%;`UOB3{>HMSk5<_F@7HkCD;CaL7Jl5R8^j)4x z^;nMc)N6XH7mkVPw;d^%WR7>S6LJTY7HCbaxJlF8@2i0b#Fw=EED#4h-dWOYn@@JB zDmKK-hec%=YMV%JD|UkPNOPORVC$EwmCs}q+WJ?AE?;OCXD+dNvty!ZeJC$87Afg= zl(y@TlKcqr627N?0V4H`+rYQrVNr)p@}6lz@^Mf!H#0y49w3!&%q#NOhgPRG%8JHT zA{^qLYeIpKS=(b}U&r?L=AIvG_6^(d=Pp?9mRM)&#%XF^4O zd{{&B>GJ7pThpOjrkk)%t7RD_Ja)wFxhP+MfK)HEY-d)FesU~I7;VLz(7Q^g8cC5- zFqxrr>{R$6mkkM$DaF~hGKOW5@i7-izwpkS6L#pCWP>g$;^#?~PnVvs<3V|2uWmLH zZ{-T4O?`bdZmR+FB|-xNQvPbRzDMT_WTJoa=#0aUyspK4kiGE1voou2FFY!-h27|8 z9sJgV8@l_(lVi8&uubp-PZ-C2>cCS4&BJ7edFvWE`f>mnyGw@>qZ^0+X%wfR1_9Ti zhq&dMf1uwQ6>XAa6ZBB;tCUkDa#ne%RtP=fc$dW!MKHRq?j^w9$B39|-9@h_bI1@JEf}d{F1}SSfs;sB8VG z4H~RBO#aVrjE`Nl&Q8UeKUMWuY^?_G6(m7BWVfzrzOv;)vifhRQWwCJcMEFU)*b=< zryJf&ZcHmR#1F7{%KQG)#I^jqdy3Z4Vq^t2>%GK_P`P1}WT+7RdKtSBT>{}v^V@aJ zyzdW?K0aUC6&u=Jr(yG5=oM)fzFTJ}-9g%$Y`4=We@;wVEJp~0j1N2_*?fRSpwNS6 zd_>G565nm*Kq}9{e8Vx&T@ANUZNZ~T`nR$NfV*@QZXpZEXJ(#xZ5ixv4>Be^ zNgj75TOF9X#c=DadJ!_a*;LN$^hm7QrQ;jiV2ON$=&fL>qWOoVFD5fW^$o5m-+n+# zn$5^iAD}#Fuok3jSH4&z=4TqwZd!nk_1@92=~TBfZ63M1%`hDxoN7nMu2hli=DbI*4X3j-oWPj!`o=PN*bMpKv~p( zlK?>bLve1yjn9!PJt^rS6X2Q7N0bo$yHWMC}3ggipD8vsX|xW!=U#I}LWz z^QnfSrM*$QQ{ryc$jHb5k=UWl;GE*YDBK*|2h61)7W<2wvTJ?p)5iRGT5JEC+@%`% zqS6Z%SFIPtt0zaN=eCZlFYjOW`hszTixox$Zr%@j-VXa>c1Sz2W4PM({(;ce?St=s z;7(-eXX4Dn@faRw%x-a`JGUdS|JLnZ!E%QoTvY;b{k^pS#LL#o%6_}2uB3_$$L!~B0eY#os+2dKcS$ZPmw!~epF literal 0 HcmV?d00001 diff --git a/django_project/core/geonode_static/geonode/css/images/spritesheet.png b/django_project/core/geonode_static/geonode/css/images/spritesheet.png new file mode 100755 index 0000000000000000000000000000000000000000..f7035a1cb0294a91eaedd98d2cbc0de6264eb4f9 GIT binary patch literal 1056 zcmV+*1mF9KP)^cqr000000000000000000000001}0u3|)s5-;puuZqwcDub(csIZEHt~3&VXFw9 z=S}Dq3)Dexi9xvEV5Dhi)kbe9jqQL|8Ub3b#khy(tYgUY?(RiCn z90SpaZPZKS$*92+NJaP-|e z*+P3q)ZU8&?Y+?KZ}|`G;oSX4g2Bs{iwx>FbBYFUO+J?;8V0MJqEL$%hwPHfa}=E` zonPVhPJ3_Y*bT&*e94n9J5II0^Sn`xyiS$t&?+#f8zLZOiAMYt%w+x?$gzi^Bif*&Cl|&@@sNZ*q5>VKmx&adr9P98S#y8by=#s z#)GTmiNry=ug>qSKwm`SNz#GV|Is)RT2MTADN_28bJ>37$o``|vVLOJVC?)oIodlg z*~UutGtV_xUY7VI7_NL2W(Pime9pta^!fq-00000000000000000000000000H`3p a1Q-A)p~XwR_AF)q0000 literal 0 HcmV?d00001 diff --git a/django_project/core/geonode_static/geonode/css/images/spritesheet.svg b/django_project/core/geonode_static/geonode/css/images/spritesheet.svg new file mode 100755 index 0000000..5423793 --- /dev/null +++ b/django_project/core/geonode_static/geonode/css/images/spritesheet.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/django_project/core/geonode_static/geonode/css/leaflet.draw.css b/django_project/core/geonode_static/geonode/css/leaflet.draw.css new file mode 100755 index 0000000..9a6f261 --- /dev/null +++ b/django_project/core/geonode_static/geonode/css/leaflet.draw.css @@ -0,0 +1,9 @@ +.leaflet-draw-section{position:relative}.leaflet-draw-toolbar{margin-top:12px}.leaflet-draw-toolbar-top{margin-top:0}.leaflet-draw-toolbar-notop a:first-child{border-top-right-radius:0}.leaflet-draw-toolbar-nobottom a:last-child{border-bottom-right-radius:0}.leaflet-draw-toolbar a{background-image:url('images/spritesheet.png');background-image:linear-gradient(transparent,transparent),url('images/spritesheet.svg');background-repeat:no-repeat;background-size:270px 30px;background-clip:padding-box}.leaflet-retina .leaflet-draw-toolbar a{background-image:url('images/spritesheet-2x.png');background-image:linear-gradient(transparent,transparent),url('images/spritesheet.svg')} +.leaflet-draw a{display:block;text-align:center;text-decoration:none}.leaflet-draw a .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.leaflet-draw-actions{display:none;list-style:none;margin:0;padding:0;position:absolute;left:26px;top:0;white-space:nowrap}.leaflet-touch .leaflet-draw-actions{left:32px}.leaflet-right .leaflet-draw-actions{right:26px;left:auto}.leaflet-touch .leaflet-right .leaflet-draw-actions{right:32px;left:auto}.leaflet-draw-actions li{display:inline-block} +.leaflet-draw-actions li:first-child a{border-left:0}.leaflet-draw-actions li:last-child a{-webkit-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.leaflet-right .leaflet-draw-actions li:last-child a{-webkit-border-radius:0;border-radius:0}.leaflet-right .leaflet-draw-actions li:first-child a{-webkit-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.leaflet-draw-actions a{background-color:#919187;border-left:1px solid #AAA;color:#FFF;font:11px/19px "Helvetica Neue",Arial,Helvetica,sans-serif;line-height:28px;text-decoration:none;padding-left:10px;padding-right:10px;height:28px} +.leaflet-touch .leaflet-draw-actions a{font-size:12px;line-height:30px;height:30px}.leaflet-draw-actions-bottom{margin-top:0}.leaflet-draw-actions-top{margin-top:1px}.leaflet-draw-actions-top a,.leaflet-draw-actions-bottom a{height:27px;line-height:27px}.leaflet-draw-actions a:hover{background-color:#a0a098}.leaflet-draw-actions-top.leaflet-draw-actions-bottom a{height:26px;line-height:26px}.leaflet-draw-toolbar .leaflet-draw-draw-polyline{background-position:-2px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-polyline{background-position:0 -1px} +.leaflet-draw-toolbar .leaflet-draw-draw-polygon{background-position:-31px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-polygon{background-position:-29px -1px}.leaflet-draw-toolbar .leaflet-draw-draw-rectangle{background-position:-62px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-rectangle{background-position:-60px -1px}.leaflet-draw-toolbar .leaflet-draw-draw-circle{background-position:-92px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-circle{background-position:-90px -1px} +.leaflet-draw-toolbar .leaflet-draw-draw-marker{background-position:-122px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-marker{background-position:-120px -1px}.leaflet-draw-toolbar .leaflet-draw-edit-edit{background-position:-152px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-edit{background-position:-150px -1px}.leaflet-draw-toolbar .leaflet-draw-edit-remove{background-position:-182px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-remove{background-position:-180px -1px} +.leaflet-draw-toolbar .leaflet-draw-edit-edit.leaflet-disabled{background-position:-212px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-edit.leaflet-disabled{background-position:-210px -1px}.leaflet-draw-toolbar .leaflet-draw-edit-remove.leaflet-disabled{background-position:-242px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-remove.leaflet-disabled{background-position:-240px -2px}.leaflet-mouse-marker{background-color:#fff;cursor:crosshair}.leaflet-draw-tooltip{background:#363636;background:rgba(0,0,0,0.5);border:1px solid transparent;-webkit-border-radius:4px;border-radius:4px;color:#fff;font:12px/18px "Helvetica Neue",Arial,Helvetica,sans-serif;margin-left:20px;margin-top:-21px;padding:4px 8px;position:absolute;visibility:hidden;white-space:nowrap;z-index:6} +.leaflet-draw-tooltip:before{border-right:6px solid black;border-right-color:rgba(0,0,0,0.5);border-top:6px solid transparent;border-bottom:6px solid transparent;content:"";position:absolute;top:7px;left:-7px}.leaflet-error-draw-tooltip{background-color:#f2dede;border:1px solid #e6b6bd;color:#b94a48}.leaflet-error-draw-tooltip:before{border-right-color:#e6b6bd}.leaflet-draw-tooltip-single{margin-top:-12px}.leaflet-draw-tooltip-subtext{color:#f8d5e4}.leaflet-draw-guide-dash{font-size:1%;opacity:.6;position:absolute;width:5px;height:5px} +.leaflet-edit-marker-selected{background-color:rgba(254,87,161,0.1);border:4px dashed rgba(254,87,161,0.6);-webkit-border-radius:4px;border-radius:4px;box-sizing:content-box}.leaflet-edit-move{cursor:move}.leaflet-edit-resize{cursor:pointer}.leaflet-oldie .leaflet-draw-toolbar{border:1px solid #999} \ No newline at end of file diff --git a/django_project/core/geonode_static/geonode/js/draw/leaflet.draw.js b/django_project/core/geonode_static/geonode/js/draw/leaflet.draw.js new file mode 100755 index 0000000..070f9b2 --- /dev/null +++ b/django_project/core/geonode_static/geonode/js/draw/leaflet.draw.js @@ -0,0 +1,9 @@ +/* + Leaflet.draw 0.4.10, a plugin that adds drawing and editing tools to Leaflet powered maps. + (c) 2012-2017, Jacob Toye, Jon West, Smartrak, Leaflet + + https://github.com/Leaflet/Leaflet.draw + http://leafletjs.com + */ +!function(t,e,i){L.drawVersion="0.4.10",L.Draw={},L.drawLocal={draw:{toolbar:{actions:{title:"Cancel drawing",text:"Cancel"},finish:{title:"Finish drawing",text:"Finish"},undo:{title:"Delete last point drawn",text:"Delete last point"},buttons:{polyline:"Draw a polyline",polygon:"Draw a polygon",rectangle:"Draw a rectangle",circle:"Draw a circle",marker:"Draw a marker"}},handlers:{circle:{tooltip:{start:"Click and drag to draw circle."},radius:"Radius"},marker:{tooltip:{start:"Click map to place marker."}},polygon:{tooltip:{start:"Click to start drawing shape.",cont:"Click to continue drawing shape.",end:"Click first point to close this shape."}},polyline:{error:"Error: shape edges cannot cross!",tooltip:{start:"Click to start drawing line.",cont:"Click to continue drawing line.",end:"Click last point to finish line."}},rectangle:{tooltip:{start:"Click and drag to draw rectangle."}},simpleshape:{tooltip:{end:"Release mouse to finish drawing."}}}},edit:{toolbar:{actions:{save:{title:"Save changes.",text:"Save"},cancel:{title:"Cancel editing, discards all changes.",text:"Cancel"},clearAll:{title:"clear all layers.",text:"Clear All"}},buttons:{edit:"Edit layers.",editDisabled:"No layers to edit.",remove:"Delete layers.",removeDisabled:"No layers to delete."}},handlers:{edit:{tooltip:{text:"Drag handles, or marker to edit feature.",subtext:"Click cancel to undo changes."}},remove:{tooltip:{text:"Click on a feature to remove"}}}}},L.Draw.Event={},L.Draw.Event.CREATED="draw:created",L.Draw.Event.EDITED="draw:edited",L.Draw.Event.DELETED="draw:deleted",L.Draw.Event.DRAWSTART="draw:drawstart",L.Draw.Event.DRAWSTOP="draw:drawstop",L.Draw.Event.DRAWVERTEX="draw:drawvertex",L.Draw.Event.EDITSTART="draw:editstart",L.Draw.Event.EDITMOVE="draw:editmove",L.Draw.Event.EDITRESIZE="draw:editresize",L.Draw.Event.EDITVERTEX="draw:editvertex",L.Draw.Event.EDITSTOP="draw:editstop",L.Draw.Event.DELETESTART="draw:deletestart",L.Draw.Event.DELETESTOP="draw:deletestop",L.Draw=L.Draw||{},L.Draw.Feature=L.Handler.extend({includes:L.Mixin.Events,initialize:function(t,e){this._map=t,this._container=t._container,this._overlayPane=t._panes.overlayPane,this._popupPane=t._panes.popupPane,e&&e.shapeOptions&&(e.shapeOptions=L.Util.extend({},this.options.shapeOptions,e.shapeOptions)),L.setOptions(this,e)},enable:function(){this._enabled||(L.Handler.prototype.enable.call(this),this.fire("enabled",{handler:this.type}),this._map.fire(L.Draw.Event.DRAWSTART,{layerType:this.type}))},disable:function(){this._enabled&&(L.Handler.prototype.disable.call(this),this._map.fire(L.Draw.Event.DRAWSTOP,{layerType:this.type}),this.fire("disabled",{handler:this.type}))},addHooks:function(){var t=this._map;t&&(L.DomUtil.disableTextSelection(),t.getContainer().focus(),this._tooltip=new L.Draw.Tooltip(this._map),L.DomEvent.on(this._container,"keyup",this._cancelDrawing,this))},removeHooks:function(){this._map&&(L.DomUtil.enableTextSelection(),this._tooltip.dispose(),this._tooltip=null,L.DomEvent.off(this._container,"keyup",this._cancelDrawing,this))},setOptions:function(t){L.setOptions(this,t)},_fireCreatedEvent:function(t){this._map.fire(L.Draw.Event.CREATED,{layer:t,layerType:this.type})},_cancelDrawing:function(t){this._map.fire("draw:canceled",{layerType:this.type}),27===t.keyCode&&this.disable()}}),L.Draw.Polyline=L.Draw.Feature.extend({statics:{TYPE:"polyline"},Poly:L.Polyline,options:{allowIntersection:!0,repeatMode:!1,drawError:{color:"#b00b00",timeout:2500},icon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon"}),touchIcon:new L.DivIcon({iconSize:new L.Point(20,20),className:"leaflet-div-icon leaflet-editing-icon leaflet-touch-icon"}),guidelineDistance:20,maxGuideLineLength:4e3,shapeOptions:{stroke:!0,color:"#3388ff",weight:4,opacity:.5,fill:!1,clickable:!0},metric:!0,feet:!0,nautic:!1,showLength:!0,zIndexOffset:2e3},initialize:function(t,e){L.Browser.touch&&(this.options.icon=this.options.touchIcon),this.options.drawError.message=L.drawLocal.draw.handlers.polyline.error,e&&e.drawError&&(e.drawError=L.Util.extend({},this.options.drawError,e.drawError)),this.type=L.Draw.Polyline.TYPE,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._markers=[],this._markerGroup=new L.LayerGroup,this._map.addLayer(this._markerGroup),this._poly=new L.Polyline([],this.options.shapeOptions),this._tooltip.updateContent(this._getTooltipText()),this._mouseMarker||(this._mouseMarker=L.marker(this._map.getCenter(),{icon:L.divIcon({className:"leaflet-mouse-marker",iconAnchor:[20,20],iconSize:[40,40]}),opacity:0,zIndexOffset:this.options.zIndexOffset})),this._mouseMarker.on("mouseout",this._onMouseOut,this).on("mousemove",this._onMouseMove,this).on("mousedown",this._onMouseDown,this).on("mouseup",this._onMouseUp,this).addTo(this._map),this._map.on("mouseup",this._onMouseUp,this).on("mousemove",this._onMouseMove,this).on("zoomlevelschange",this._onZoomEnd,this).on("touchstart",this._onTouch,this).on("zoomend",this._onZoomEnd,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._clearHideErrorTimeout(),this._cleanUpShape(),this._map.removeLayer(this._markerGroup),delete this._markerGroup,delete this._markers,this._map.removeLayer(this._poly),delete this._poly,this._mouseMarker.off("mousedown",this._onMouseDown,this).off("mouseout",this._onMouseOut,this).off("mouseup",this._onMouseUp,this).off("mousemove",this._onMouseMove,this),this._map.removeLayer(this._mouseMarker),delete this._mouseMarker,this._clearGuides(),this._map.off("mouseup",this._onMouseUp,this).off("mousemove",this._onMouseMove,this).off("zoomlevelschange",this._onZoomEnd,this).off("zoomend",this._onZoomEnd,this).off("touchstart",this._onTouch,this).off("click",this._onTouch,this)},deleteLastVertex:function(){if(!(this._markers.length<=1)){var t=this._markers.pop(),e=this._poly,i=e.getLatLngs(),o=i.splice(-1,1)[0];this._poly.setLatLngs(i),this._markerGroup.removeLayer(t),e.getLatLngs().length<2&&this._map.removeLayer(e),this._vertexChanged(o,!1)}},addVertex:function(t){if(this._markers.length>=2&&!this.options.allowIntersection&&this._poly.newLatLngIntersects(t))return void this._showErrorTooltip();this._errorShown&&this._hideErrorTooltip(),this._markers.push(this._createMarker(t)),this._poly.addLatLng(t),2===this._poly.getLatLngs().length&&this._map.addLayer(this._poly),this._vertexChanged(t,!0)},completeShape:function(){this._markers.length<=1||(this._fireCreatedEvent(),this.disable(),this.options.repeatMode&&this.enable())},_finishShape:function(){var t=this._poly._defaultShape?this._poly._defaultShape():this._poly.getLatLngs(),e=this._poly.newLatLngIntersects(t[t.length-1]);if(!this.options.allowIntersection&&e||!this._shapeIsValid())return void this._showErrorTooltip();this._fireCreatedEvent(),this.disable(),this.options.repeatMode&&this.enable()},_shapeIsValid:function(){return!0},_onZoomEnd:function(){null!==this._markers&&this._updateGuide()},_onMouseMove:function(t){var e=this._map.mouseEventToLayerPoint(t.originalEvent),i=this._map.layerPointToLatLng(e);this._currentLatLng=i,this._updateTooltip(i),this._updateGuide(e),this._mouseMarker.setLatLng(i),L.DomEvent.preventDefault(t.originalEvent)},_vertexChanged:function(t,e){this._map.fire(L.Draw.Event.DRAWVERTEX,{layers:this._markerGroup}),this._updateFinishHandler(),this._updateRunningMeasure(t,e),this._clearGuides(),this._updateTooltip()},_onMouseDown:function(t){if(!this._clickHandled&&!this._touchHandled&&!this._disableMarkers){this._onMouseMove(t),this._clickHandled=!0,this._disableNewMarkers();var e=t.originalEvent,i=e.clientX,o=e.clientY;this._startPoint.call(this,i,o)}},_startPoint:function(t,e){this._mouseDownOrigin=L.point(t,e)},_onMouseUp:function(t){var e=t.originalEvent,i=e.clientX,o=e.clientY;this._endPoint.call(this,i,o,t),this._clickHandled=null},_endPoint:function(e,i,o){if(this._mouseDownOrigin){var n=L.point(e,i).distanceTo(this._mouseDownOrigin);this._calculateFinishDistance(o.latlng)<10&&L.Browser.touch?this._finishShape():Math.abs(n)<9*(t.devicePixelRatio||1)&&this.addVertex(o.latlng),this._enableNewMarkers()}this._mouseDownOrigin=null},_onTouch:function(t){var e,i,o=t.originalEvent;!o.touches||!o.touches[0]||this._clickHandled||this._touchHandled||this._disableMarkers||(e=o.touches[0].clientX,i=o.touches[0].clientY,this._disableNewMarkers(),this._touchHandled=!0,this._startPoint.call(this,e,i),this._endPoint.call(this,e,i,t),this._touchHandled=null),this._clickHandled=null},_onMouseOut:function(){this._tooltip&&this._tooltip._onMouseOut.call(this._tooltip)},_calculateFinishDistance:function(t){var e;if(this._markers.length>0){var i;if(this.type===L.Draw.Polyline.TYPE)i=this._markers[this._markers.length-1];else{if(this.type!==L.Draw.Polygon.TYPE)return 1/0;i=this._markers[0]}var o=this._map.latLngToContainerPoint(i.getLatLng()),n=new L.Marker(t,{icon:this.options.icon,zIndexOffset:2*this.options.zIndexOffset}),s=this._map.latLngToContainerPoint(n.getLatLng());e=o.distanceTo(s)}else e=1/0;return e},_updateFinishHandler:function(){var t=this._markers.length;t>1&&this._markers[t-1].on("click",this._finishShape,this),t>2&&this._markers[t-2].off("click",this._finishShape,this)},_createMarker:function(t){var e=new L.Marker(t,{icon:this.options.icon,zIndexOffset:2*this.options.zIndexOffset});return this._markerGroup.addLayer(e),e},_updateGuide:function(t){var e=this._markers?this._markers.length:0;e>0&&(t=t||this._map.latLngToLayerPoint(this._currentLatLng),this._clearGuides(),this._drawGuide(this._map.latLngToLayerPoint(this._markers[e-1].getLatLng()),t))},_updateTooltip:function(t){var e=this._getTooltipText();t&&this._tooltip.updatePosition(t),this._errorShown||this._tooltip.updateContent(e)},_drawGuide:function(t,e){var i,o,n,s=Math.floor(Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))),a=this.options.guidelineDistance,r=this.options.maxGuideLineLength,l=s>r?s-r:a;for(this._guidesContainer||(this._guidesContainer=L.DomUtil.create("div","leaflet-draw-guides",this._overlayPane));l1&&this._markers[this._markers.length-1].off("click",this._finishShape,this)},_fireCreatedEvent:function(){var t=new this.Poly(this._poly.getLatLngs(),this.options.shapeOptions);L.Draw.Feature.prototype._fireCreatedEvent.call(this,t)}}),L.Draw.Polygon=L.Draw.Polyline.extend({statics:{TYPE:"polygon"},Poly:L.Polygon,options:{showArea:!1,showLength:!1,shapeOptions:{stroke:!0,color:"#3388ff",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0},metric:!0,feet:!0,nautic:!1,precision:{}},initialize:function(t,e){L.Draw.Polyline.prototype.initialize.call(this,t,e),this.type=L.Draw.Polygon.TYPE},_updateFinishHandler:function(){var t=this._markers.length;1===t&&this._markers[0].on("click",this._finishShape,this),t>2&&(this._markers[t-1].on("dblclick",this._finishShape,this),t>3&&this._markers[t-2].off("dblclick",this._finishShape,this))},_getTooltipText:function(){var t,e;return 0===this._markers.length?t=L.drawLocal.draw.handlers.polygon.tooltip.start:this._markers.length<3?(t=L.drawLocal.draw.handlers.polygon.tooltip.cont,e=this._getMeasurementString()):(t=L.drawLocal.draw.handlers.polygon.tooltip.end,e=this._getMeasurementString()),{text:t,subtext:e}},_getMeasurementString:function(){var t=this._area,e="";return t||this.options.showLength?(this.options.showLength&&(e=L.Draw.Polyline.prototype._getMeasurementString.call(this)),t&&(e+="
    "+L.GeometryUtil.readableArea(t,this.options.metric,this.options.precision)),e):null},_shapeIsValid:function(){return this._markers.length>=3},_vertexChanged:function(t,e){var i;!this.options.allowIntersection&&this.options.showArea&&(i=this._poly.getLatLngs(),this._area=L.GeometryUtil.geodesicArea(i)),L.Draw.Polyline.prototype._vertexChanged.call(this,t,e)},_cleanUpShape:function(){var t=this._markers.length;t>0&&(this._markers[0].off("click",this._finishShape,this),t>2&&this._markers[t-1].off("dblclick",this._finishShape,this))}}),L.SimpleShape={},L.Draw.SimpleShape=L.Draw.Feature.extend({options:{repeatMode:!1},initialize:function(t,e){this._endLabelText=L.drawLocal.draw.handlers.simpleshape.tooltip.end,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._mapDraggable=this._map.dragging.enabled(),this._mapDraggable&&this._map.dragging.disable(),this._container.style.cursor="crosshair",this._tooltip.updateContent({text:this._initialLabelText}),this._map.on("mousedown",this._onMouseDown,this).on("mousemove",this._onMouseMove,this).on("touchstart",this._onMouseDown,this).on("touchmove",this._onMouseMove,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._map&&(this._mapDraggable&&this._map.dragging.enable(),this._container.style.cursor="",this._map.off("mousedown",this._onMouseDown,this).off("mousemove",this._onMouseMove,this).off("touchstart",this._onMouseDown,this).off("touchmove",this._onMouseMove,this),L.DomEvent.off(e,"mouseup",this._onMouseUp,this),L.DomEvent.off(e,"touchend",this._onMouseUp,this),this._shape&&(this._map.removeLayer(this._shape),delete this._shape)),this._isDrawing=!1},_getTooltipText:function(){return{text:this._endLabelText}},_onMouseDown:function(t){this._isDrawing=!0,this._startLatLng=t.latlng,L.DomEvent.on(e,"mouseup",this._onMouseUp,this).on(e,"touchend",this._onMouseUp,this).preventDefault(t.originalEvent)},_onMouseMove:function(t){var e=t.latlng;this._tooltip.updatePosition(e),this._isDrawing&&(this._tooltip.updateContent(this._getTooltipText()),this._drawShape(e))},_onMouseUp:function(){this._shape&&this._fireCreatedEvent(),this.disable(),this.options.repeatMode&&this.enable()}}),L.Draw.Rectangle=L.Draw.SimpleShape.extend({statics:{TYPE:"rectangle"},options:{shapeOptions:{stroke:!0,color:"#3388ff",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,showArea:!0,clickable:!0},metric:!0},initialize:function(t,e){this.type=L.Draw.Rectangle.TYPE,this._initialLabelText=L.drawLocal.draw.handlers.rectangle.tooltip.start,L.Draw.SimpleShape.prototype.initialize.call(this,t,e)},_drawShape:function(t){this._shape?this._shape.setBounds(new L.LatLngBounds(this._startLatLng,t)):(this._shape=new L.Rectangle(new L.LatLngBounds(this._startLatLng,t),this.options.shapeOptions),this._map.addLayer(this._shape))},_fireCreatedEvent:function(){var t=new L.Rectangle(this._shape.getBounds(),this.options.shapeOptions);L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this,t)},_getTooltipText:function(){var t,e,i,o=L.Draw.SimpleShape.prototype._getTooltipText.call(this),n=this._shape,s=this.options.showArea;return n&&(t=this._shape._defaultShape?this._shape._defaultShape():this._shape.getLatLngs(),e=L.GeometryUtil.geodesicArea(t),i=s?L.GeometryUtil.readableArea(e,this.options.metric):""),{text:o.text,subtext:i}}}),L.Draw.Circle=L.Draw.SimpleShape.extend({statics:{TYPE:"circle"},options:{shapeOptions:{stroke:!0,color:"#3388ff",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0},showRadius:!0,metric:!0,feet:!0,nautic:!1},initialize:function(t,e){this.type=L.Draw.Circle.TYPE,this._initialLabelText=L.drawLocal.draw.handlers.circle.tooltip.start,L.Draw.SimpleShape.prototype.initialize.call(this,t,e)},_drawShape:function(t){this._shape?this._shape.setRadius(this._startLatLng.distanceTo(t)):(this._shape=new L.Circle(this._startLatLng,this._startLatLng.distanceTo(t),this.options.shapeOptions),this._map.addLayer(this._shape))},_fireCreatedEvent:function(){var t=new L.Circle(this._startLatLng,this._shape.getRadius(),this.options.shapeOptions);L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this,t)},_onMouseMove:function(t){var e,i=t.latlng,o=this.options.showRadius,n=this.options.metric;if(this._tooltip.updatePosition(i),this._isDrawing){this._drawShape(i),e=this._shape.getRadius().toFixed(1);var s="";o&&(s=L.drawLocal.draw.handlers.circle.radius+": "+L.GeometryUtil.readableDistance(e,n,this.options.feet,this.options.nautic)),this._tooltip.updateContent({text:this._endLabelText,subtext:s})}}}),L.Draw.Marker=L.Draw.Feature.extend({statics:{TYPE:"marker"},options:{icon:new L.Icon.Default,repeatMode:!1,zIndexOffset:2e3},initialize:function(t,e){this.type=L.Draw.Marker.TYPE,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._tooltip.updateContent({text:L.drawLocal.draw.handlers.marker.tooltip.start}),this._mouseMarker||(this._mouseMarker=L.marker(this._map.getCenter(),{icon:L.divIcon({className:"leaflet-mouse-marker",iconAnchor:[20,20],iconSize:[40,40]}),opacity:0,zIndexOffset:this.options.zIndexOffset})),this._mouseMarker.on("click",this._onClick,this).addTo(this._map),this._map.on("mousemove",this._onMouseMove,this),this._map.on("click",this._onTouch,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._map&&(this._marker&&(this._marker.off("click",this._onClick,this),this._map.off("click",this._onClick,this).off("click",this._onTouch,this).removeLayer(this._marker),delete this._marker),this._mouseMarker.off("click",this._onClick,this),this._map.removeLayer(this._mouseMarker),delete this._mouseMarker,this._map.off("mousemove",this._onMouseMove,this))},_onMouseMove:function(t){var e=t.latlng;this._tooltip.updatePosition(e),this._mouseMarker.setLatLng(e),this._marker?(e=this._mouseMarker.getLatLng(),this._marker.setLatLng(e)):(this._marker=new L.Marker(e,{icon:this.options.icon,zIndexOffset:this.options.zIndexOffset}),this._marker.on("click",this._onClick,this),this._map.on("click",this._onClick,this).addLayer(this._marker))},_onClick:function(){this._fireCreatedEvent(),this.disable(),this.options.repeatMode&&this.enable()},_onTouch:function(t){this._onMouseMove(t),this._onClick()},_fireCreatedEvent:function(){var t=new L.Marker.Touch(this._marker.getLatLng(),{icon:this.options.icon});L.Draw.Feature.prototype._fireCreatedEvent.call(this,t)}}),L.Edit=L.Edit||{},L.Edit.Marker=L.Handler.extend({initialize:function(t,e){this._marker=t,L.setOptions(this,e)},addHooks:function(){var t=this._marker;t.dragging.enable(),t.on("dragend",this._onDragEnd,t),this._toggleMarkerHighlight()},removeHooks:function(){var t=this._marker;t.dragging.disable(),t.off("dragend",this._onDragEnd,t),this._toggleMarkerHighlight()},_onDragEnd:function(t){var e=t.target;e.edited=!0,this._map.fire(L.Draw.Event.EDITMOVE,{layer:e})},_toggleMarkerHighlight:function(){var t=this._marker._icon;t&&(t.style.display="none",L.DomUtil.hasClass(t,"leaflet-edit-marker-selected")?(L.DomUtil.removeClass(t,"leaflet-edit-marker-selected"),this._offsetMarker(t,-4)):(L.DomUtil.addClass(t,"leaflet-edit-marker-selected"),this._offsetMarker(t,4)),t.style.display="")},_offsetMarker:function(t,e){var i=parseInt(t.style.marginTop,10)-e,o=parseInt(t.style.marginLeft,10)-e;t.style.marginTop=i+"px",t.style.marginLeft=o+"px"}}),L.Marker.addInitHook(function(){L.Edit.Marker&&(this.editing=new L.Edit.Marker(this),this.options.editable&&this.editing.enable())}),L.Edit=L.Edit||{},L.Edit.Poly=L.Handler.extend({options:{},initialize:function(t,e){this.latlngs=[t._latlngs],t._holes&&(this.latlngs=this.latlngs.concat(t._holes)),this._poly=t,L.setOptions(this,e),this._poly.on("revert-edited",this._updateLatLngs,this)},_defaultShape:function(){return L.Polyline._flat?L.Polyline._flat(this._poly._latlngs)?this._poly._latlngs:this._poly._latlngs[0]:this._poly._latlngs},_eachVertexHandler:function(t){for(var e=0;et&&(i._index+=e)})},_createMiddleMarker:function(t,e){var i,o,n,s=this._getMiddleLatLng(t,e),a=this._createMarker(s);a.setOpacity(.6),t._middleRight=e._middleLeft=a,o=function(){a.off("touchmove",o,this);var n=e._index;a._index=n,a.off("click",i,this).on("click",this._onMarkerClick,this),s.lat=a.getLatLng().lat,s.lng=a.getLatLng().lng,this._spliceLatLngs(n,0,s),this._markers.splice(n,0,a),a.setOpacity(1),this._updateIndexes(n,1),e._index++,this._updatePrevNext(t,a),this._updatePrevNext(a,e),this._poly.fire("editstart")},n=function(){a.off("dragstart",o,this),a.off("dragend",n,this),a.off("touchmove",o,this),this._createMiddleMarker(t,a),this._createMiddleMarker(a,e)},i=function(){o.call(this),n.call(this),this._fireEdit()},a.on("click",i,this).on("dragstart",o,this).on("dragend",n,this).on("touchmove",o,this),this._markerGroup.addLayer(a)},_updatePrevNext:function(t,e){t&&(t._next=e),e&&(e._prev=t)},_getMiddleLatLng:function(t,e){var i=this._poly._map,o=i.project(t.getLatLng()),n=i.project(e.getLatLng());return i.unproject(o._add(n)._divideBy(2))}}),L.Polyline.addInitHook(function(){this.editing||(L.Edit.Poly&&(this.editing=new L.Edit.Poly(this,this.options.poly),this.options.editable&&this.editing.enable()),this.on("add",function(){this.editing&&this.editing.enabled()&&this.editing.addHooks()}),this.on("remove",function(){this.editing&&this.editing.enabled()&&this.editing.removeHooks()}))}),L.Edit=L.Edit||{},L.Edit.SimpleShape=L.Handler.extend({options:{moveIcon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon leaflet-edit-move"}),resizeIcon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon leaflet-edit-resize"}),touchMoveIcon:new L.DivIcon({iconSize:new L.Point(20,20),className:"leaflet-div-icon leaflet-editing-icon leaflet-edit-move leaflet-touch-icon"}),touchResizeIcon:new L.DivIcon({iconSize:new L.Point(20,20),className:"leaflet-div-icon leaflet-editing-icon leaflet-edit-resize leaflet-touch-icon"})},initialize:function(t,e){L.Browser.touch&&(this.options.moveIcon=this.options.touchMoveIcon,this.options.resizeIcon=this.options.touchResizeIcon),this._shape=t,L.Util.setOptions(this,e)},addHooks:function(){var t=this._shape;this._shape._map&&(this._map=this._shape._map,t.setStyle(t.options.editing),t._map&&(this._map=t._map,this._markerGroup||this._initMarkers(),this._map.addLayer(this._markerGroup)))},removeHooks:function(){var t=this._shape;if(t.setStyle(t.options.original),t._map){this._unbindMarker(this._moveMarker);for(var e=0,i=this._resizeMarkers.length;e100&&i<500||t.target._simulatedClick&&!t._simulated?(L.DomEvent.stop(t),!1):(L.DomEvent._lastClick=e,!0)},_onTouchStart:function(t){if(this._map._loaded){this._touchEvent(t,"touchstart")}},_onTouchEnd:function(t){if(this._map._loaded){this._touchEvent(t,"touchend")}},_onTouchCancel:function(t){if(this._map._loaded){var e="touchcancel";this._detectIE()&&(e="pointercancel"),this._touchEvent(t,e)}},_onTouchLeave:function(t){if(this._map._loaded){this._touchEvent(t,"touchleave")}},_onTouchMove:function(t){if(this._map._loaded){this._touchEvent(t,"touchmove")}},_detectIE:function(){var e=t.navigator.userAgent,i=e.indexOf("MSIE ");if(i>0)return parseInt(e.substring(i+5,e.indexOf(".",i)),10);if(e.indexOf("Trident/")>0){var o=e.indexOf("rv:");return parseInt(e.substring(o+3,e.indexOf(".",o)),10)}var n=e.indexOf("Edge/");return n>0&&parseInt(e.substring(n+5,e.indexOf(".",n)),10)}}),L.Map.addInitHook("addHandler","touchExtend",L.Map.TouchExtend),L.Marker.Touch=L.Marker.extend({_initInteraction:function(){return this.addInteractiveTarget?L.Marker.prototype._initInteraction.apply(this):this._initInteractionLegacy()},_initInteractionLegacy:function(){if(this.options.clickable){var t=this._icon,e=["dblclick","mousedown","mouseover","mouseout","contextmenu","touchstart","touchend","touchmove"];this._detectIE?e.concat(["MSPointerDown","MSPointerUp","MSPointerMove","MSPointerCancel"]):e.concat(["touchcancel"]),L.DomUtil.addClass(t,"leaflet-clickable"),L.DomEvent.on(t,"click",this._onMouseClick,this),L.DomEvent.on(t,"keypress",this._onKeyPress,this);for(var i=0;i0)return parseInt(e.substring(i+5,e.indexOf(".",i)),10);if(e.indexOf("Trident/")>0){var o=e.indexOf("rv:");return parseInt(e.substring(o+3,e.indexOf(".",o)),10)}var n=e.indexOf("Edge/");return n>0&&parseInt(e.substring(n+5,e.indexOf(".",n)),10)}}),L.LatLngUtil={cloneLatLngs:function(t){for(var e=[],i=0,o=t.length;i2){for(var a=0;a1&&(i=i+a+r[1])}return i},readableArea:function(e,i,o){var n,s,o=L.Util.extend({},t,o);return i?(s=["ha","m"],type=typeof i,"string"===type?s=[i]:"boolean"!==type&&(s=i),n=e>=1e6&&-1!==s.indexOf("km")?L.GeometryUtil.formattedNumber(1e-6*e,o.km)+" km²":e>=1e4&&-1!==s.indexOf("ha")?L.GeometryUtil.formattedNumber(1e-4*e,o.ha)+" ha":L.GeometryUtil.formattedNumber(e,o.m)+" m²"):(e/=.836127,n=e>=3097600?L.GeometryUtil.formattedNumber(e/3097600,o.mi)+" mi²":e>=4840?L.GeometryUtil.formattedNumber(e/4840,o.ac)+" acres":L.GeometryUtil.formattedNumber(e,o.yd)+" yd²"),n},readableDistance:function(e,i,o,n,s){var a,s=L.Util.extend({},t,s);switch(i?"string"==typeof i?i:"metric":o?"feet":n?"nauticalMile":"yards"){case"metric":a=e>1e3?L.GeometryUtil.formattedNumber(e/1e3,s.km)+" km":L.GeometryUtil.formattedNumber(e,s.m)+" m";break;case"feet":e*=3.28083,a=L.GeometryUtil.formattedNumber(e,s.ft)+" ft";break;case"nauticalMile":e*=.53996,a=L.GeometryUtil.formattedNumber(e/1e3,s.nm)+" nm";break;case"yards":default:e*=1.09361,a=e>1760?L.GeometryUtil.formattedNumber(e/1760,s.mi)+" miles":L.GeometryUtil.formattedNumber(e,s.yd)+" yd"}return a}})}(),L.Util.extend(L.LineUtil,{segmentsIntersect:function(t,e,i,o){return this._checkCounterclockwise(t,i,o)!==this._checkCounterclockwise(e,i,o)&&this._checkCounterclockwise(t,e,i)!==this._checkCounterclockwise(t,e,o)},_checkCounterclockwise:function(t,e,i){return(i.y-t.y)*(e.x-t.x)>(e.y-t.y)*(i.x-t.x)}}),L.Polyline.include({intersects:function(){var t,e,i,o=this._getProjectedPoints(),n=o?o.length:0;if(this._tooFewPointsForIntersection())return!1;for(t=n-1;t>=3;t--)if(e=o[t-1],i=o[t],this._lineSegmentsIntersectsRange(e,i,t-2))return!0;return!1},newLatLngIntersects:function(t,e){return!!this._map&&this.newPointIntersects(this._map.latLngToLayerPoint(t),e)},newPointIntersects:function(t,e){var i=this._getProjectedPoints(),o=i?i.length:0,n=i?i[o-1]:null,s=o-2;return!this._tooFewPointsForIntersection(1)&&this._lineSegmentsIntersectsRange(n,t,s,e?1:0)},_tooFewPointsForIntersection:function(t){var e=this._getProjectedPoints(),i=e?e.length:0;return i+=t||0,!e||i<=3},_lineSegmentsIntersectsRange:function(t,e,i,o){var n,s,a=this._getProjectedPoints();o=o||0;for(var r=i;r>o;r--)if(n=a[r-1],s=a[r],L.LineUtil.segmentsIntersect(t,e,n,s))return!0;return!1},_getProjectedPoints:function(){if(!this._defaultShape)return this._originalPoints;for(var t=[],e=this._defaultShape(),i=0;i0&&this._singleLineLabel&&(L.DomUtil.removeClass(this._container,"leaflet-draw-tooltip-single"),this._singleLineLabel=!1):(L.DomUtil.addClass(this._container,"leaflet-draw-tooltip-single"),this._singleLineLabel=!0),this._container.innerHTML=(t.subtext.length>0?''+t.subtext+"
    ":"")+""+t.text+"",t.text||t.subtext?(this._visible=!0,this._container.style.visibility="inherit"):(this._visible=!1,this._container.style.visibility="hidden"),this):this},updatePosition:function(t){var e=this._map.latLngToLayerPoint(t),i=this._container;return this._container&&(this._visible&&(i.style.visibility="inherit"),L.DomUtil.setPosition(i,e)),this},showAsError:function(){return this._container&&L.DomUtil.addClass(this._container,"leaflet-error-draw-tooltip"),this},removeError:function(){return this._container&&L.DomUtil.removeClass(this._container,"leaflet-error-draw-tooltip"),this},_onMouseOut:function(){this._container&&(this._container.style.visibility="hidden")}}),L.DrawToolbar=L.Toolbar.extend({statics:{TYPE:"draw"},options:{polyline:{},polygon:{},rectangle:{},circle:{},marker:{}},initialize:function(t){for(var e in this.options)this.options.hasOwnProperty(e)&&t[e]&&(t[e]=L.extend({},this.options[e],t[e]));this._toolbarClass="leaflet-draw-draw",L.Toolbar.prototype.initialize.call(this,t)},getModeHandlers:function(t){return[{enabled:this.options.polyline,handler:new L.Draw.Polyline(t,this.options.polyline),title:L.drawLocal.draw.toolbar.buttons.polyline},{enabled:this.options.polygon,handler:new L.Draw.Polygon(t,this.options.polygon),title:L.drawLocal.draw.toolbar.buttons.polygon},{enabled:this.options.rectangle,handler:new L.Draw.Rectangle(t,this.options.rectangle),title:L.drawLocal.draw.toolbar.buttons.rectangle},{enabled:this.options.circle,handler:new L.Draw.Circle(t,this.options.circle),title:L.drawLocal.draw.toolbar.buttons.circle},{enabled:this.options.marker,handler:new L.Draw.Marker(t,this.options.marker),title:L.drawLocal.draw.toolbar.buttons.marker}]},getActions:function(t){return[{enabled:t.completeShape,title:L.drawLocal.draw.toolbar.finish.title,text:L.drawLocal.draw.toolbar.finish.text,callback:t.completeShape,context:t},{enabled:t.deleteLastVertex,title:L.drawLocal.draw.toolbar.undo.title,text:L.drawLocal.draw.toolbar.undo.text,callback:t.deleteLastVertex,context:t},{title:L.drawLocal.draw.toolbar.actions.title,text:L.drawLocal.draw.toolbar.actions.text,callback:this.disable,context:this}]},setOptions:function(t){L.setOptions(this,t);for(var e in this._modes)this._modes.hasOwnProperty(e)&&t.hasOwnProperty(e)&&this._modes[e].handler.setOptions(t[e])}}),L.EditToolbar=L.Toolbar.extend({statics:{TYPE:"edit"},options:{edit:{selectedPathOptions:{dashArray:"10, 10",fill:!0,fillColor:"#fe57a1",fillOpacity:.1,maintainColor:!1}},remove:{},poly:null,featureGroup:null},initialize:function(t){t.edit&&(void 0===t.edit.selectedPathOptions&&(t.edit.selectedPathOptions=this.options.edit.selectedPathOptions),t.edit.selectedPathOptions=L.extend({},this.options.edit.selectedPathOptions,t.edit.selectedPathOptions)),t.remove&&(t.remove=L.extend({},this.options.remove,t.remove)),t.poly&&(t.poly=L.extend({},this.options.poly,t.poly)),this._toolbarClass="leaflet-draw-edit",L.Toolbar.prototype.initialize.call(this,t),this._selectedFeatureCount=0},getModeHandlers:function(t){var e=this.options.featureGroup;return[{enabled:this.options.edit,handler:new L.EditToolbar.Edit(t,{featureGroup:e,selectedPathOptions:this.options.edit.selectedPathOptions,poly:this.options.poly}),title:L.drawLocal.edit.toolbar.buttons.edit},{enabled:this.options.remove,handler:new L.EditToolbar.Delete(t,{featureGroup:e}),title:L.drawLocal.edit.toolbar.buttons.remove}]},getActions:function(){return[{title:L.drawLocal.edit.toolbar.actions.save.title,text:L.drawLocal.edit.toolbar.actions.save.text,callback:this._save,context:this},{title:L.drawLocal.edit.toolbar.actions.cancel.title,text:L.drawLocal.edit.toolbar.actions.cancel.text,callback:this.disable,context:this},{title:L.drawLocal.edit.toolbar.actions.clearAll.title,text:L.drawLocal.edit.toolbar.actions.clearAll.text,callback:this._clearAllLayers,context:this}]},addToolbar:function(t){var e=L.Toolbar.prototype.addToolbar.call(this,t);return this._checkDisabled(),this.options.featureGroup.on("layeradd layerremove",this._checkDisabled,this),e},removeToolbar:function(){this.options.featureGroup.off("layeradd layerremove",this._checkDisabled,this),L.Toolbar.prototype.removeToolbar.call(this)},disable:function(){this.enabled()&&(this._activeMode.handler.revertLayers(),L.Toolbar.prototype.disable.call(this))},_save:function(){this._activeMode.handler.save(),this._activeMode&&this._activeMode.handler.disable()},_clearAllLayers:function(){this._activeMode.handler.removeAllLayers(),this._activeMode&&this._activeMode.handler.disable()},_checkDisabled:function(){var t,e=this.options.featureGroup,i=0!==e.getLayers().length;this.options.edit&&(t=this._modes[L.EditToolbar.Edit.TYPE].button,i?L.DomUtil.removeClass(t,"leaflet-disabled"):L.DomUtil.addClass(t,"leaflet-disabled"),t.setAttribute("title",i?L.drawLocal.edit.toolbar.buttons.edit:L.drawLocal.edit.toolbar.buttons.editDisabled)),this.options.remove&&(t=this._modes[L.EditToolbar.Delete.TYPE].button,i?L.DomUtil.removeClass(t,"leaflet-disabled"):L.DomUtil.addClass(t,"leaflet-disabled"),t.setAttribute("title",i?L.drawLocal.edit.toolbar.buttons.remove:L.drawLocal.edit.toolbar.buttons.removeDisabled))}}),L.EditToolbar.Edit=L.Handler.extend({statics:{TYPE:"edit"},includes:L.Mixin.Events,initialize:function(t,e){if(L.Handler.prototype.initialize.call(this,t),L.setOptions(this,e),this._featureGroup=e.featureGroup,!(this._featureGroup instanceof L.FeatureGroup))throw new Error("options.featureGroup must be a L.FeatureGroup");this._uneditedLayerProps={},this.type=L.EditToolbar.Edit.TYPE},enable:function(){!this._enabled&&this._hasAvailableLayers()&&(this.fire("enabled",{handler:this.type}),this._map.fire(L.Draw.Event.EDITSTART,{handler:this.type}),L.Handler.prototype.enable.call(this),this._featureGroup.on("layeradd",this._enableLayerEdit,this).on("layerremove",this._disableLayerEdit,this))},disable:function(){this._enabled&&(this._featureGroup.off("layeradd",this._enableLayerEdit,this).off("layerremove",this._disableLayerEdit,this),L.Handler.prototype.disable.call(this),this._map.fire(L.Draw.Event.EDITSTOP,{handler:this.type}),this.fire("disabled",{handler:this.type}))},addHooks:function(){var t=this._map;t&&(t.getContainer().focus(),this._featureGroup.eachLayer(this._enableLayerEdit,this),this._tooltip=new L.Draw.Tooltip(this._map),this._tooltip.updateContent({text:L.drawLocal.edit.handlers.edit.tooltip.text,subtext:L.drawLocal.edit.handlers.edit.tooltip.subtext}),t._editTooltip=this._tooltip,this._updateTooltip(),this._map.on("mousemove",this._onMouseMove,this).on("touchmove",this._onMouseMove,this).on("MSPointerMove",this._onMouseMove,this).on(L.Draw.Event.EDITVERTEX,this._updateTooltip,this))},removeHooks:function(){this._map&&(this._featureGroup.eachLayer(this._disableLayerEdit,this),this._uneditedLayerProps={},this._tooltip.dispose(),this._tooltip=null,this._map.off("mousemove",this._onMouseMove,this).off("touchmove",this._onMouseMove,this).off("MSPointerMove",this._onMouseMove,this).off(L.Draw.Event.EDITVERTEX,this._updateTooltip,this))},revertLayers:function(){this._featureGroup.eachLayer(function(t){this._revertLayer(t)},this)},save:function(){var t=new L.LayerGroup;this._featureGroup.eachLayer(function(e){e.edited&&(t.addLayer(e),e.edited=!1)}),this._map.fire(L.Draw.Event.EDITED,{layers:t})},_backupLayer:function(t){var e=L.Util.stamp(t);this._uneditedLayerProps[e]||(t instanceof L.Polyline||t instanceof L.Polygon||t instanceof L.Rectangle?this._uneditedLayerProps[e]={latlngs:L.LatLngUtil.cloneLatLngs(t.getLatLngs())}:t instanceof L.Circle?this._uneditedLayerProps[e]={latlng:L.LatLngUtil.cloneLatLng(t.getLatLng()),radius:t.getRadius()}:t instanceof L.Marker&&(this._uneditedLayerProps[e]={latlng:L.LatLngUtil.cloneLatLng(t.getLatLng())}))},_getTooltipText:function(){return{text:L.drawLocal.edit.handlers.edit.tooltip.text,subtext:L.drawLocal.edit.handlers.edit.tooltip.subtext}},_updateTooltip:function(){this._tooltip.updateContent(this._getTooltipText())},_revertLayer:function(t){var e=L.Util.stamp(t);t.edited=!1,this._uneditedLayerProps.hasOwnProperty(e)&&(t instanceof L.Polyline||t instanceof L.Polygon||t instanceof L.Rectangle?t.setLatLngs(this._uneditedLayerProps[e].latlngs):t instanceof L.Circle?(t.setLatLng(this._uneditedLayerProps[e].latlng),t.setRadius(this._uneditedLayerProps[e].radius)):t instanceof L.Marker&&t.setLatLng(this._uneditedLayerProps[e].latlng),t.fire("revert-edited",{layer:t}))},_enableLayerEdit:function(t){var e,i,o=t.layer||t.target||t;this._backupLayer(o),this.options.poly&&(i=L.Util.extend({},this.options.poly),o.options.poly=i),this.options.selectedPathOptions&&(e=L.Util.extend({},this.options.selectedPathOptions),e.maintainColor&&(e.color=o.options.color,e.fillColor=o.options.fillColor),o.options.original=L.extend({},o.options),o.options.editing=e),o instanceof L.Marker?(o.editing&&o.editing.enable(),o.dragging.enable(),o.on("dragend",this._onMarkerDragEnd).on("touchmove",this._onTouchMove,this).on("MSPointerMove",this._onTouchMove,this).on("touchend",this._onMarkerDragEnd,this).on("MSPointerUp",this._onMarkerDragEnd,this)):o.editing.enable()},_disableLayerEdit:function(t){var e=t.layer||t.target||t;e.edited=!1,e.editing&&e.editing.disable(),delete e.options.editing,delete e.options.original,this._selectedPathOptions&&(e instanceof L.Marker?this._toggleMarkerHighlight(e):(e.setStyle(e.options.previousOptions),delete e.options.previousOptions)),e instanceof L.Marker?(e.dragging.disable(),e.off("dragend",this._onMarkerDragEnd,this).off("touchmove",this._onTouchMove,this).off("MSPointerMove",this._onTouchMove,this).off("touchend",this._onMarkerDragEnd,this).off("MSPointerUp",this._onMarkerDragEnd,this)):e.editing.disable()},_onMouseMove:function(t){this._tooltip.updatePosition(t.latlng)},_onMarkerDragEnd:function(t){var e=t.target;e.edited=!0,this._map.fire(L.Draw.Event.EDITMOVE,{layer:e})},_onTouchMove:function(t){var e=t.originalEvent.changedTouches[0],i=this._map.mouseEventToLayerPoint(e),o=this._map.layerPointToLatLng(i);t.target.setLatLng(o)},_hasAvailableLayers:function(){return 0!==this._featureGroup.getLayers().length}}),L.EditToolbar.Delete=L.Handler.extend({statics:{TYPE:"remove"},includes:L.Mixin.Events,initialize:function(t,e){if(L.Handler.prototype.initialize.call(this,t),L.Util.setOptions(this,e),this._deletableLayers=this.options.featureGroup,!(this._deletableLayers instanceof L.FeatureGroup))throw new Error("options.featureGroup must be a L.FeatureGroup");this.type=L.EditToolbar.Delete.TYPE},enable:function(){!this._enabled&&this._hasAvailableLayers()&&(this.fire("enabled",{handler:this.type}),this._map.fire(L.Draw.Event.DELETESTART,{handler:this.type}),L.Handler.prototype.enable.call(this),this._deletableLayers.on("layeradd",this._enableLayerDelete,this).on("layerremove",this._disableLayerDelete,this))},disable:function(){this._enabled&&(this._deletableLayers.off("layeradd",this._enableLayerDelete,this).off("layerremove",this._disableLayerDelete,this),L.Handler.prototype.disable.call(this),this._map.fire(L.Draw.Event.DELETESTOP,{handler:this.type}),this.fire("disabled",{handler:this.type}))},addHooks:function(){var t=this._map;t&&(t.getContainer().focus(),this._deletableLayers.eachLayer(this._enableLayerDelete,this),this._deletedLayers=new L.LayerGroup,this._tooltip=new L.Draw.Tooltip(this._map),this._tooltip.updateContent({text:L.drawLocal.edit.handlers.remove.tooltip.text}),this._map.on("mousemove",this._onMouseMove,this))},removeHooks:function(){this._map&&(this._deletableLayers.eachLayer(this._disableLayerDelete,this),this._deletedLayers=null,this._tooltip.dispose(),this._tooltip=null,this._map.off("mousemove",this._onMouseMove,this))},revertLayers:function(){this._deletedLayers.eachLayer(function(t){this._deletableLayers.addLayer(t),t.fire("revert-deleted",{layer:t})},this)},save:function(){this._map.fire(L.Draw.Event.DELETED,{layers:this._deletedLayers})},removeAllLayers:function(){this._deletableLayers.eachLayer(function(t){this._removeLayer({layer:t})},this),this.save()},_enableLayerDelete:function(t){(t.layer||t.target||t).on("click",this._removeLayer,this)},_disableLayerDelete:function(t){var e=t.layer||t.target||t;e.off("click",this._removeLayer,this),this._deletedLayers.removeLayer(e)},_removeLayer:function(t){var e=t.layer||t.target||t;this._deletableLayers.removeLayer(e),this._deletedLayers.addLayer(e),e.fire("deleted")},_onMouseMove:function(t){this._tooltip.updatePosition(t.latlng)},_hasAvailableLayers:function(){return 0!==this._deletableLayers.getLayers().length}})}(window,document); \ No newline at end of file diff --git a/django_project/core/settings/base.py b/django_project/core/settings/base.py index d7d7fe8..700ec1a 100644 --- a/django_project/core/settings/base.py +++ b/django_project/core/settings/base.py @@ -216,7 +216,7 @@ except ImportError: # INSTALLED_APPS = INSTALLED_APPS + ('osgeo_importer', 'geonode-client', 'wfs_harvest') -LAYER_PREVIEW_LIBRARY = 'react' +LAYER_PREVIEW_LIBRARY = 'leaflet' IMPORT_HANDLERS = [ # If GeoServer handlers are enabled, you must have an instance of geoserver running. diff --git a/django_project/core/templates/layers/layer_detail.html b/django_project/core/templates/layers/layer_detail.html index 88bbe5b..d746209 100644 --- a/django_project/core/templates/layers/layer_detail.html +++ b/django_project/core/templates/layers/layer_detail.html @@ -274,6 +274,9 @@
      +
    • + +
    • {% if resource.storeType != "remoteStore" %}
    • {% if links or links_download %} @@ -749,6 +752,28 @@ function updateLinkAndTitle(){ {% include 'rating.html' %} {% include 'request_download.html' %} + + + + + + + \ No newline at end of file diff --git a/django_project/core/templates/layers/layer_detail.html b/django_project/core/templates/layers/layer_detail.html index 34a4abb..2303f0e 100644 --- a/django_project/core/templates/layers/layer_detail.html +++ b/django_project/core/templates/layers/layer_detail.html @@ -275,7 +275,7 @@
      • - +
      • {% if resource.storeType != "remoteStore" %}
      • @@ -751,40 +751,12 @@ function updateLinkAndTitle(){ {% endif %} {% include 'rating.html' %} {% include 'request_download.html' %} + {% include 'layers/download_clip.html' %}