diff --git a/app/contrib/frontend/maps/__init__.py b/app/contrib/frontend/maps/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/contrib/frontend/maps/apps.py b/app/contrib/frontend/maps/apps.py new file mode 100644 index 00000000..d3c10fe1 --- /dev/null +++ b/app/contrib/frontend/maps/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class MapsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'contrib.frontend.maps' diff --git a/app/contrib/frontend/maps/cms_plugins.py b/app/contrib/frontend/maps/cms_plugins.py new file mode 100644 index 00000000..49c4f352 --- /dev/null +++ b/app/contrib/frontend/maps/cms_plugins.py @@ -0,0 +1,16 @@ +from django import forms +from django.conf import settings +from django.contrib.sites.models import Site + +from cms.plugin_base import CMSPluginBase +from cms.plugin_pool import plugin_pool + +from .models import Maps + +@plugin_pool.register_plugin +class LeafletMapPlugin(CMSPluginBase): + name = "Mapa" + module = "Frontend" + model = Maps + render_template = "maps/plugins/map.html" + diff --git a/app/contrib/frontend/maps/migrations/0001_initial.py b/app/contrib/frontend/maps/migrations/0001_initial.py new file mode 100644 index 00000000..29c3f6ab --- /dev/null +++ b/app/contrib/frontend/maps/migrations/0001_initial.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2 on 2023-09-29 20:11 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('cms', '0022_auto_20180620_1551'), + ] + + operations = [ + migrations.CreateModel( + name='Maps', + fields=[ + ('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, related_name='maps_maps', serialize=False, to='cms.cmsplugin')), + ('geojson', models.FileField(upload_to='maps/geojson/')), + ], + options={ + 'abstract': False, + }, + bases=('cms.cmsplugin',), + ), + ] diff --git a/app/contrib/frontend/maps/migrations/__init__.py b/app/contrib/frontend/maps/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/contrib/frontend/maps/models.py b/app/contrib/frontend/maps/models.py new file mode 100644 index 00000000..dc41fc1c --- /dev/null +++ b/app/contrib/frontend/maps/models.py @@ -0,0 +1,6 @@ +from django.db import models + +from cms.plugin_base import CMSPlugin + +class Maps(CMSPlugin): + geojson = models.FileField(upload_to="maps/geojson/") \ No newline at end of file diff --git a/app/contrib/frontend/maps/static/maps/css/styles.css b/app/contrib/frontend/maps/static/maps/css/styles.css new file mode 100644 index 00000000..95b189af --- /dev/null +++ b/app/contrib/frontend/maps/static/maps/css/styles.css @@ -0,0 +1,3 @@ +#map { + height: 800px; +} diff --git a/app/contrib/frontend/maps/static/maps/js/maps.js b/app/contrib/frontend/maps/static/maps/js/maps.js new file mode 100644 index 00000000..1933f0a1 --- /dev/null +++ b/app/contrib/frontend/maps/static/maps/js/maps.js @@ -0,0 +1,145 @@ +let config = { + minZoom: 7, + maxZoom: 18, + zoomControl: false, +}; + +const zoom = 18; +const lat = -23.55016; +const lng = -46.63366; + +const mapWrapper = document.querySelector("#map"); + +const map = L.map("map", config).setView([lat, lng], zoom); + +// Used to load and display tile layers on the map +// Most tile servers require attribution, which you can set under `Layer` +L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", { + attribution: + '© OpenStreetMap contributors', +}).addTo(map); + +// ------------------------------------------------------------ +L.control.zoom({ position: "topright" }).addTo(map); + +// -------------------------------------------------------------- +L.Control.Search = L.Control.extend({ + options: { + position: "topleft", + }, + onAdd: function () { + const container = L.DomUtil.create("div", "autocomplete-container"); + + L.DomEvent.disableClickPropagation(container); + + container.insertAdjacentHTML( + "beforeend", + `
+ +
` + ); + + return container; + }, +}); + +new L.Control.Search().addTo(map); + +// -------------------------------------------------------------- +let geojsonarray = []; + +new Autocomplete("local", { + onSearch: ({ currentValue }) => { + + const api = mapWrapper.dataset.mapsGeojson; + return new Promise((resolve) => { + fetch(api) + .then((response) => response.json()) + .then((data) => { + const result = data.features + .sort((a, b) => + a.properties.title.localeCompare(b.properties.title) + ) + .filter((element) => { + return element.properties.title.match( + new RegExp(currentValue, "gi") + ); + }); + resolve(result); + }) + .catch((error) => { + console.error(error); + }); + }); + }, + + onResults: ({ matches, template }) => { + return matches === 0 + ? template + : matches + .map((el) => { + const icon = + el.properties.type === "rectangle" + ? "polygon" + : el.properties.type.toLowerCase(); + return ` +
  • +
    ${el.properties.title}
    +
  • `; + }) + .join(""); + }, + + onSubmit: ({ object }) => { + const geojsonlayer = L.geoJSON(object, { + style: function (feature) { + return { + color: feature.properties.color || "red", + weight: 7, + opacity: 1, + fillOpacity: 0.7, + }; + }, + pointToLayer: (feature, latlng) => { + if (feature.properties.type === "circle") { + return new L.circle(latlng, { + radius: feature.properties.radius, + }); + } else if (feature.properties.type === "circlemarker") { + return new L.circleMarker(latlng, { + radius: 20, + }); + } else { + return new L.Marker(latlng); + } + }, + onEachFeature: function (feature, layer) { + // const infos = feature.properties.layer.toString(); + + layer.bindPopup( + "Informações:
    " + "oiee
    " + "
    " + ); + }, + }); + + map.fitBounds(geojsonlayer.getBounds(), { padding: [150, 150] }); + + if (geojsonarray.includes(object.properties.id)) return; + geojsonarray.push(object.properties.id); + + geojsonlayer.addTo(map); + }, + + noResults: ({ currentValue, template }) => + template(`
  • No results found: "${currentValue}"
  • `), + + onReset: () => { + // remove all layers + map.eachLayer(function (layer) { + if (!!layer.toGeoJSON) { + map.removeLayer(layer); + } + }); + geojsonarray = []; + }, +}); diff --git a/app/contrib/frontend/maps/templates/maps/plugins/map.html b/app/contrib/frontend/maps/templates/maps/plugins/map.html new file mode 100644 index 00000000..dd21a8a7 --- /dev/null +++ b/app/contrib/frontend/maps/templates/maps/plugins/map.html @@ -0,0 +1,17 @@ +{% load static sekizai_tags %} + +{% addtoblock "css" %} + + + +{% endaddtoblock %} + +
    + +{% addtoblock "js" %} + + + +{% endaddtoblock %} diff --git a/app/project/settings/base.py b/app/project/settings/base.py index c1fa9b34..0e189e1d 100644 --- a/app/project/settings/base.py +++ b/app/project/settings/base.py @@ -79,6 +79,7 @@ "contrib.frontend", "contrib.frontend.landpage", "contrib.frontend.grid", + "contrib.frontend.maps", "contrib.ga", # Experimentação "eleicao", diff --git a/app/project/settings/cms.py b/app/project/settings/cms.py index ab3ad2ec..32adc01f 100644 --- a/app/project/settings/cms.py +++ b/app/project/settings/cms.py @@ -12,7 +12,7 @@ CMS_PLACEHOLDER_CONF = { "content": { "name": "Blocos", - "plugins": ["BlockPlugin", "BlockPressurePlugin", "EleicaoCandidateListPlugin", "EleicaoCarouselPlugin", "EleicaoVoterFormPlugin"], + "plugins": ["BlockPlugin", "BlockPressurePlugin", "EleicaoCandidateListPlugin", "EleicaoCarouselPlugin", "EleicaoVoterFormPlugin", "LeafletMapPlugin"], }, "navigation": { "name": "Navegação",