├── .env ├── .gitignore ├── .static ├── CNAME ├── Howto_update_fallback_taxonomy ├── LICENCE ├── Q5-fallback.json ├── README.md ├── TM-Viewer-dataflow.graphml ├── TM-Viewer-dataflow.png ├── assets ├── envelope64.png ├── food_agriculture_bubble_blue_invers.png ├── food_agriculture_darkblue_invert_bubble.png ├── food_agriculture_darkblue_plain.png ├── food_agriculture_orange_invert_bubble.png ├── food_agriculture_orange_plain.png ├── food_agriculture_plain_blue.png ├── food_agriculture_turquoise_invers_bubble.png ├── food_agriculture_turquoise_plain.png ├── food_agriculture_yellow_invers_bubble.png ├── food_agriculture_yellow_plain.png ├── forkme-on-github.png ├── globe64.png ├── icon-filter-24.png ├── icon-filter-64.png ├── icon-filter-big.png ├── phone64.png ├── susylogo.png ├── turquoise_active_citizenship.png ├── turquoise_education_training.png ├── turquoise_fairtrade.png ├── turquoise_finance.png ├── turquoise_food_agriculture.png ├── turquoise_housing_habitat.png ├── turquoise_infrastructure_ressources.png ├── turquoise_other.png ├── turquoise_reuse_reduce_recycle.png ├── turquoise_self-organization_mutuality.png ├── turquoise_social_inclusion.png ├── turquoise_susy-partners.png ├── wikipedia-48.png ├── world_turquoise_invert_bubble.png ├── world_turquoise_plain.png ├── world_yellow_invert_bubble.png ├── world_yellow_plain.png ├── yellow_active_citizenship.png ├── yellow_education_training.png ├── yellow_fairtrade.png ├── yellow_finance.png ├── yellow_food_agriculture.png ├── yellow_housing_habitat.png ├── yellow_infrastructure_ressources.png ├── yellow_other.png ├── yellow_reuse_reduce_recycle.png ├── yellow_self-organization_mutuality.png ├── yellow_social_inclusion.png └── yellow_susy-partners.png ├── bower.json ├── bower_components ├── PruneCluster │ └── dist │ │ ├── LeafletStyleSheet.css │ │ └── PruneCluster.min.js ├── fetch │ └── fetch.js └── leaflet │ └── dist │ ├── images │ ├── layers-2x.png │ ├── layers.png │ └── marker-green.png │ ├── leaflet.css │ └── leaflet.js ├── dist ├── index.html ├── site.css └── site.js ├── editable.html ├── iframe.html ├── index.html ├── localisation-notes.md ├── package.json ├── scripts ├── leaflet-hash.js ├── map.js └── red_fetch.js ├── styles ├── css │ └── style.css └── less │ └── style.less ├── susydata-fallback.json └── taxonomy.json /.env: -------------------------------------------------------------------------------- 1 | BUILDPACK_URL=https://github.com/florianheinemann/buildpack-nginx.git 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bower_components/* 2 | node_modules/* 3 | *.swp 4 | 5 | !bower_components/leaflet 6 | bower_components/leaflet/* 7 | !bower_components/leaflet/dist 8 | bower_components/leaflet/dist/* 9 | !bower_components/leaflet/dist/leaflet.css 10 | !bower_components/leaflet/dist/leaflet.js 11 | !bower_components/leaflet/dist/images 12 | bower_components/leaflet/dist/images/* 13 | !bower_components/leaflet/dist/images/layers.png 14 | !bower_components/leaflet/dist/images/layers-2x.png 15 | !bower_components/leaflet/dist/images/marker-green.png 16 | 17 | !bower_components/fetch/ 18 | bower_components/fetch/* 19 | !bower_components/fetch/fetch.js 20 | 21 | !bower_components/PruneCluster 22 | bower_components/PruneCluster/* 23 | !bower_components/PruneCluster/dist 24 | bower_components/PruneCluster/dist/* 25 | !bower_components/PruneCluster/dist/PruneCluster.min.js 26 | !bower_components/PruneCluster/dist/LeafletStyleSheet.css 27 | -------------------------------------------------------------------------------- /.static: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/.static -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | viewer.transformap.co -------------------------------------------------------------------------------- /Howto_update_fallback_taxonomy: -------------------------------------------------------------------------------- 1 | The taxonomy is created and translated at https://base.transformap.co/wiki/Special:AllPages?from=&to=&namespace=120 2 | 3 | It is then exported (currently manually) to a blazgraph RDF database, which serves the taxonomy as RDF. 4 | The RDF interface is here: https://query.base.transformap.co/bigdata/#namespaces 5 | 6 | How to update the taxonomy in the RDF DB: 7 | ssh root@rancher (server at ecobytes) - ask Ecobytes people to execute this if you don't have access 8 | cd /srv/wikibase/ 9 | docker run -it --rm --env-file /srv/wikibase/mediawiki.env -v /srv/docker-state/wikibase/mediawiki/rootfs/data:/data -v /srv/docker-state/wikibase/mediawiki/rootfs/conf:/conf -v /srv/wikibase/LocalSettings.php:/data/LocalSettings.php --link="wikibase_database_1:database" --net="wikibase_backend" wikibase_mediawiki /usr/bin/php /var/www/html/extensions/Wikibase/repo/maintenance/dumpRdf.php | gzip -c > $date_wikibase_dump.ttl.gz 10 | 11 | # copy dump to your local PC 12 | scp root@rancher:/srv/wikibase/ $date_wikibase_dump.ttl.gz localhost: 13 | 14 | # next steps to be done in the WebIf 15 | We first need to delete the old DB (there would be duplicate values if we just dump in the new extract) 16 | go to https://query.base.transformap.co/bigdata/#namespaces 17 | 18 | clone the transformap namespace to a copy "tm2" or something like that 19 | 20 | click "clone" 21 | 22 | enter the name in the box on the bottom 23 | 24 | click "create namespace" 25 | 26 | delete the "transformap" namespace 27 | 28 | clone the copy to "transformap" 29 | 30 | for the "transformap" namespace, click "Use" 31 | 32 | go to https://query.base.transformap.co/bigdata/#update 33 | 34 | Choose File 35 | 36 | Type RDF Data , Turtle 37 | 38 | click 'update' 39 | 40 | the taxonomy is (currently) served from this repository: https://github.com/TransforMap/transformap-viewer-translations 41 | there is a folder named 'taxonomy-backup/'. In there is a folder 'susy', where the taxonomy (for each language) is stored in JSON form. 42 | 43 | clone this repository 44 | cd taxonomy-backup/ 45 | # in this folder is a README.md: at the bottom is a chain of commands to download the taxonomy for each language 46 | cd susy/ 47 | # in the susy/ - folder, execute the 'for' loop found in the README-file in taxonomy-backup/ 48 | git status # to see what has been updated 49 | git add * 50 | git commit -m "taxonomy fallback update" 51 | git push 52 | 53 | the updated taxonomy is now live on the transformap-viewer 54 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | -------------------------------------------------------------------------------- /Q5-fallback.json: -------------------------------------------------------------------------------- 1 | {"entities":{"Q5":{"pageid":62,"ns":120,"title":"Item:Q5","lastrevid":3393,"modified":"2016-09-26T08:48:05Z","type":"item","id":"Q5","labels":{"en":{"language":"en","value":"Taxonomy category"},"de":{"language":"de","value":"Taxonomie-Kategorie"},"fa":{"language":"fa","value":"\u0637\u0628\u0642\u0647 \u0628\u0646\u062f\u06cc"},"ro":{"language":"ro","value":"Categorie taxonometric\u0103"},"ga":{"language":"ga","value":"Tacsan\u00f3im\u00edocht Catag\u00f3ir"},"hr":{"language":"hr","value":"Kategorija taksonomije"},"pl":{"language":"pl","value":"Kategoria taksonomii"},"el":{"language":"el","value":"\u039a\u03b1\u03c4\u03b7\u03b3\u03bf\u03c1\u03af\u03b1 \u03a4\u03b1\u03be\u03b9\u03bd\u03bf\u03bc\u03af\u03b1\u03c2"},"es":{"language":"es","value":"Categor\u00eda taxon\u00f3mica"},"lv":{"language":"lv","value":"Taksonomijas kategorija"},"cs":{"language":"cs","value":"Kategorie taxonomie"},"bg":{"language":"bg","value":"\u0422\u0430\u043a\u0441\u043e\u043d\u043e\u043c\u0438\u0447\u043d\u0430 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f"},"et":{"language":"et","value":"Taksonoomia kategooria"},"pt":{"language":"pt","value":"Categoria de sistematiza\u00e7\u00e3o"},"fi":{"language":"fi","value":"Luokittelukategoria"}},"descriptions":{"de":{"language":"de","value":"Taxonomie-Kategorie"}},"aliases":[],"claims":{"P9":[{"mainsnak":{"snaktype":"value","property":"P9","datavalue":{"value":{"entity-type":"item","numeric-id":3},"type":"wikibase-entityid"},"datatype":"wikibase-item"},"type":"statement","id":"Q5$98e7621c-44a8-dd92-3072-7622f3fdc72d","rank":"normal"}]},"sitelinks":[]}}} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TransforMap-Viewer 2 | 3 | This is a Web-Map plugin that aims at displaying data from the [TransforMap API](https://github.com/TransforMap/data.transformap.co). It offers dynamic filters, which are built from a Wikibase graph hosted on [base.transformap.co](https://base.transformap.co). 4 | 5 | ## Features 6 | 7 | * Displays geoJSON Points 8 | * Clustering via [PruneCluster](https://github.com/SINTEF-9012/PruneCluster) 9 | * Popup with image display, special support for Mediawiki storage 10 | * Filtering system, builds filter menu out of RDF graph provided by Wikibase 11 | 12 | ## Embedding 13 | 14 | To embed the TransforMap-Viewer into your own website, the simplest way is via an iframe: 15 | 16 | 17 | 18 | You can change the background layer via the param "background" (e.g. src="http://viewer.transformap.co/?background=mapnik#5/51.166/10.451"). Currently 4 layers are supported: 19 | 20 | * background=stamen_terrain_bg : Default, only terrain without any labels, roads or buildings. 21 | * background=stamen_terrain : terrain with (a few) labels, roads and buildings later 22 | * background=mapnik : Default OpenStreetMap 'Mapnik'/'OSM-Carto' style 23 | * background=hot : Humanitarian OSM style. Temperate colors, very detailed. 24 | 25 | If you want to change anything else, e.g. color scheme or the displayed data, fork it and embed it from your fork's gh-pages. 26 | 27 | ## Translations 28 | 29 | Translation for the filter-menu are directly fetched from Wikibase. All other strings are are handled via [weblate.transformap.co](https://weblate.transformap.co/projects/transformap-viewer/transformap-viewer-textsnipplets/). You can help translating, just sign up! It stores its translations here: https://github.com/TransforMap/transformap-viewer-translations. 30 | 31 | Note: The English translations are handled in the source repository directly. 32 | 33 | To add new strings, you have to add them currently manually to scripts/map.js and in the translation repository, to each of the language files in json/*.json. 34 | 35 | # Development 36 | 37 | ## Data flows 38 | 39 | This service relies heavily on different linked data backends, see flowchart: 40 | 41 | ![Flowchart showing the services involved](TM-Viewer-dataflow.png) 42 | 43 | ## CSS 44 | 45 | Is created via [less](http://lesscss.org/). 46 | 47 | Do not edit the CSS file in styles/css/style.css, edit styles/less/style.less and compile to css. 48 | 49 | Install node *less* compiler to convert the stylesheet to less css: 50 | 51 | * Debian: `aptitude install node-less` 52 | * Windows: `npm install less -g` 53 | 54 | Compile it via : 55 | 56 | lessc styles/less/style.less styles/css/style.css 57 | 58 | ## Dependencies 59 | 60 | Install *bower* from npm: 61 | 62 | [sudo] npm install -g bower 63 | 64 | Debian: install npm: 65 | 66 | [sudo] aptitude install npm nodejs-legacy 67 | 68 | Fetch external dependencies: 69 | 70 | bower install 71 | 72 | ## Deployment 73 | 74 | The site http://viewer.transformap.co/ is actually hosted at github.io. Just push the branch gh-pages to update the site. 75 | 76 | Notes: for libraries used with bower, add a static copy of the files to the gh-pages branch to its location in bower_components/ (and add an exception to the .gitignore-file). 77 | 78 | ### build concatenated and minified js/css 79 | 80 | Run `npm install` once to install needed development dependencies. 81 | 82 | Then, run `npm run build` each time js and/or css has been changed to update the content in the `/dist` folder. 83 | 84 | ## Coding Style guide 85 | 86 | We use spaces (2) instead of tabs, please also use this convention. 87 | 88 | ## Forks 89 | 90 | Currently, there are 3 "branches" of development: 91 | 92 | * http://viewer.transformap.co/ - "master" branch, [this](https://github.com/TransforMap/transformap-viewer) repo. 93 | * https://susy-mapviewer.github.io/transformap-viewer/ for embedding into the [solidarityeconomy.eu](http://solidarityeconomy.eu) site. Repo see [here](https://github.com/susy-mapviewer/transformap-viewer). 94 | * https://susy-partners.github.io/transformap-viewer/ for embedding into the websites of SUSY-partners. Repo see [here](https://github.com/susy-partners/transformap-viewer). 95 | -------------------------------------------------------------------------------- /TM-Viewer-dataflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/TM-Viewer-dataflow.png -------------------------------------------------------------------------------- /assets/envelope64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/envelope64.png -------------------------------------------------------------------------------- /assets/food_agriculture_bubble_blue_invers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/food_agriculture_bubble_blue_invers.png -------------------------------------------------------------------------------- /assets/food_agriculture_darkblue_invert_bubble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/food_agriculture_darkblue_invert_bubble.png -------------------------------------------------------------------------------- /assets/food_agriculture_darkblue_plain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/food_agriculture_darkblue_plain.png -------------------------------------------------------------------------------- /assets/food_agriculture_orange_invert_bubble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/food_agriculture_orange_invert_bubble.png -------------------------------------------------------------------------------- /assets/food_agriculture_orange_plain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/food_agriculture_orange_plain.png -------------------------------------------------------------------------------- /assets/food_agriculture_plain_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/food_agriculture_plain_blue.png -------------------------------------------------------------------------------- /assets/food_agriculture_turquoise_invers_bubble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/food_agriculture_turquoise_invers_bubble.png -------------------------------------------------------------------------------- /assets/food_agriculture_turquoise_plain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/food_agriculture_turquoise_plain.png -------------------------------------------------------------------------------- /assets/food_agriculture_yellow_invers_bubble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/food_agriculture_yellow_invers_bubble.png -------------------------------------------------------------------------------- /assets/food_agriculture_yellow_plain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/food_agriculture_yellow_plain.png -------------------------------------------------------------------------------- /assets/forkme-on-github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/forkme-on-github.png -------------------------------------------------------------------------------- /assets/globe64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/globe64.png -------------------------------------------------------------------------------- /assets/icon-filter-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/icon-filter-24.png -------------------------------------------------------------------------------- /assets/icon-filter-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/icon-filter-64.png -------------------------------------------------------------------------------- /assets/icon-filter-big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/icon-filter-big.png -------------------------------------------------------------------------------- /assets/phone64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/phone64.png -------------------------------------------------------------------------------- /assets/susylogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/susylogo.png -------------------------------------------------------------------------------- /assets/turquoise_active_citizenship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/turquoise_active_citizenship.png -------------------------------------------------------------------------------- /assets/turquoise_education_training.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/turquoise_education_training.png -------------------------------------------------------------------------------- /assets/turquoise_fairtrade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/turquoise_fairtrade.png -------------------------------------------------------------------------------- /assets/turquoise_finance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/turquoise_finance.png -------------------------------------------------------------------------------- /assets/turquoise_food_agriculture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/turquoise_food_agriculture.png -------------------------------------------------------------------------------- /assets/turquoise_housing_habitat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/turquoise_housing_habitat.png -------------------------------------------------------------------------------- /assets/turquoise_infrastructure_ressources.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/turquoise_infrastructure_ressources.png -------------------------------------------------------------------------------- /assets/turquoise_other.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/turquoise_other.png -------------------------------------------------------------------------------- /assets/turquoise_reuse_reduce_recycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/turquoise_reuse_reduce_recycle.png -------------------------------------------------------------------------------- /assets/turquoise_self-organization_mutuality.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/turquoise_self-organization_mutuality.png -------------------------------------------------------------------------------- /assets/turquoise_social_inclusion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/turquoise_social_inclusion.png -------------------------------------------------------------------------------- /assets/turquoise_susy-partners.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/turquoise_susy-partners.png -------------------------------------------------------------------------------- /assets/wikipedia-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/wikipedia-48.png -------------------------------------------------------------------------------- /assets/world_turquoise_invert_bubble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/world_turquoise_invert_bubble.png -------------------------------------------------------------------------------- /assets/world_turquoise_plain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/world_turquoise_plain.png -------------------------------------------------------------------------------- /assets/world_yellow_invert_bubble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/world_yellow_invert_bubble.png -------------------------------------------------------------------------------- /assets/world_yellow_plain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/world_yellow_plain.png -------------------------------------------------------------------------------- /assets/yellow_active_citizenship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/yellow_active_citizenship.png -------------------------------------------------------------------------------- /assets/yellow_education_training.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/yellow_education_training.png -------------------------------------------------------------------------------- /assets/yellow_fairtrade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/yellow_fairtrade.png -------------------------------------------------------------------------------- /assets/yellow_finance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/yellow_finance.png -------------------------------------------------------------------------------- /assets/yellow_food_agriculture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/yellow_food_agriculture.png -------------------------------------------------------------------------------- /assets/yellow_housing_habitat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/yellow_housing_habitat.png -------------------------------------------------------------------------------- /assets/yellow_infrastructure_ressources.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/yellow_infrastructure_ressources.png -------------------------------------------------------------------------------- /assets/yellow_other.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/yellow_other.png -------------------------------------------------------------------------------- /assets/yellow_reuse_reduce_recycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/yellow_reuse_reduce_recycle.png -------------------------------------------------------------------------------- /assets/yellow_self-organization_mutuality.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/yellow_self-organization_mutuality.png -------------------------------------------------------------------------------- /assets/yellow_social_inclusion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/yellow_social_inclusion.png -------------------------------------------------------------------------------- /assets/yellow_susy-partners.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/assets/yellow_susy-partners.png -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "transformap-viewer", 3 | "homepage": "https://transformap.co/transformap-viewer", 4 | "authors": [], 5 | "description": "", 6 | "main": "index.html", 7 | "moduleType": [], 8 | "license": "", 9 | "private": true, 10 | "ignore": [ 11 | "**/.*", 12 | "node_modules", 13 | "bower_components", 14 | "test", 15 | "tests" 16 | ], 17 | "dependencies": { 18 | "PruneCluster": "^1.1.0", 19 | "leaflet": "^0.7.7", 20 | "fetch": "^1.0.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /bower_components/PruneCluster/dist/LeafletStyleSheet.css: -------------------------------------------------------------------------------- 1 | .prunecluster { 2 | font-size: 12px; 3 | border-radius: 20px; 4 | transition: all 0.3s linear; 5 | } 6 | .leaflet-marker-icon.prunecluster-anim, 7 | .leaflet-marker-shadow.prunecluster-anim, 8 | .leaflet-markercluster-icon.prunecluster-anim { 9 | transition: all 0.3s linear; 10 | } 11 | 12 | .leaflet-zoom-anim .leaflet-zoom-animated.leaflet-marker-icon, 13 | .leaflet-zoom-anim .leaflet-zoom-animated.leaflet-marker-shadow, 14 | .leaflet-zoom-anim .leaflet-zoom-animated.leaflet-markercluster-icon { 15 | transition: transform 0.25s cubic-bezier(0,0,0.25,1); 16 | } 17 | .prunecluster div { 18 | width: 30px; 19 | height: 30px; 20 | text-align: center; 21 | margin-left: 5px; 22 | margin-top: 5px; 23 | border-radius: 50%; 24 | } 25 | .prunecluster div span { 26 | line-height: 30px; 27 | } 28 | 29 | .prunecluster-small { 30 | background-color: #b5e28c; 31 | background-color: rgba(181, 226, 140, 0.6); 32 | background-color: rgba(255, 255, 51, 0.6); 33 | } 34 | 35 | .prunecluster-small div { 36 | width: 28px; 37 | height: 28px; 38 | background-color: #6ecc39; 39 | background-color: rgba(110, 204, 57, 0.6); 40 | background-color: rgba(255, 255, 51, 0.6); 41 | } 42 | 43 | .prunecluster-small div span { 44 | line-height: 28px; 45 | } 46 | 47 | .prunecluster-medium { 48 | background-color: #f1d357; 49 | background-color: rgba(241, 211, 87, 0.6); 50 | background-color: rgba(255, 204, 51, 0.6); 51 | } 52 | 53 | .prunecluster-medium div { 54 | background-color: #f0c20c; 55 | background-color: rgba(240, 194, 12, 0.6); 56 | background-color: rgba(255, 204, 51, 0.6); 57 | } 58 | 59 | .prunecluster-large { 60 | background-color: #fd9c73; 61 | background-color: rgba(253, 156, 115, 0.6); 62 | background-color: rgba(255, 153, 51, 0.6); 63 | } 64 | 65 | .prunecluster-large div { 66 | width: 34px; 67 | height: 34px; 68 | background-color: #f18017; 69 | background-color: rgba(241, 128, 23, 0.6); 70 | background-color: rgba(255, 153, 51, 0.6); 71 | } 72 | 73 | .prunecluster-large div span { 74 | line-height: 34px; 75 | } 76 | -------------------------------------------------------------------------------- /bower_components/PruneCluster/dist/PruneCluster.min.js: -------------------------------------------------------------------------------- 1 | var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},PruneCluster;!function(a){function b(a,b){return a.lat>=b.minLat&&a.lat<=b.maxLat&&a.lng>=b.minLng&&a.lng<=b.maxLng}function c(a){for(var b,c,d,e=1,f=a.length;f>e;++e){for(c=a[e],d=c.position.lng,b=e-1;b>=0&&a[b].position.lng>d;--b)a[b+1]=a[b];a[b+1]=c}}var d=.2,e=function(){function a(){}return a}();a.Point=e;var f=function(){function a(){}return a}();a.ClusterObject=f;var g=1,h=Math.pow(2,53)-1,i=function(a){function b(b,c,d,e,f,h){void 0===d&&(d={}),void 0===f&&(f=1),void 0===h&&(h=!1),a.call(this),this.data=d,this.position={lat:b,lng:c},this.weight=f,this.category=e,this.filtered=h,this.hashCode=g++}return __extends(b,a),b.prototype.Move=function(a,b){this.position.lat=a,this.position.lng=b},b.prototype.SetData=function(a){for(var b in a)this.data[b]=a[b]},b}(f);a.Marker=i;var j=function(a){function b(c){return a.call(this),this.stats=[0,0,0,0,0,0,0,0],this.data={},c?(b.ENABLE_MARKERS_LIST&&(this._clusterMarkers=[c]),this.lastMarker=c,this.hashCode=31+c.hashCode,this.population=1,void 0!==c.category&&(this.stats[c.category]=1),this.totalWeight=c.weight,this.position={lat:c.position.lat,lng:c.position.lng},void(this.averagePosition={lat:c.position.lat,lng:c.position.lng})):(this.hashCode=1,void(b.ENABLE_MARKERS_LIST&&(this._clusterMarkers=[])))}return __extends(b,a),b.prototype.AddMarker=function(a){b.ENABLE_MARKERS_LIST&&this._clusterMarkers.push(a);var c=this.hashCode;c=(c<<5)-c+a.hashCode,this.hashCode=c>=h?c%h:c,this.lastMarker=a;var d=a.weight,e=this.totalWeight,f=d+e;this.averagePosition.lat=(this.averagePosition.lat*e+a.position.lat*d)/f,this.averagePosition.lng=(this.averagePosition.lng*e+a.position.lng*d)/f,++this.population,this.totalWeight=f,void 0!==a.category&&(this.stats[a.category]=this.stats[a.category]+1||1)},b.prototype.Reset=function(){this.hashCode=1,this.lastMarker=void 0,this.population=0,this.totalWeight=0,this.stats=[0,0,0,0,0,0,0,0],b.ENABLE_MARKERS_LIST&&(this._clusterMarkers=[])},b.prototype.ComputeBounds=function(a){var b=a.Project(this.position.lat,this.position.lng),c=a.Size,d=Math.floor(b.x/c),e=Math.floor(b.y/c),f=d*c,g=e*c,h=a.UnProject(f,g),i=a.UnProject(f+c,g+c);this.bounds={minLat:i.lat,maxLat:h.lat,minLng:h.lng,maxLng:i.lng}},b.prototype.GetClusterMarkers=function(){return this._clusterMarkers},b.prototype.ApplyCluster=function(a){this.hashCode=41*this.hashCode+43*a.hashCode,this.hashCode>h&&(this.hashCode=this.hashCode=h);var c=a.totalWeight,d=this.totalWeight,e=c+d;this.averagePosition.lat=(this.averagePosition.lat*d+a.averagePosition.lat*c)/e,this.averagePosition.lng=(this.averagePosition.lng*d+a.averagePosition.lng*c)/e,this.population+=a.population,this.totalWeight=e,this.bounds.minLat=Math.min(this.bounds.minLat,a.bounds.minLat),this.bounds.minLng=Math.min(this.bounds.minLng,a.bounds.minLng),this.bounds.maxLat=Math.max(this.bounds.maxLat,a.bounds.maxLat),this.bounds.maxLng=Math.max(this.bounds.maxLng,a.bounds.maxLng);for(var f in a.stats)a.stats.hasOwnProperty(f)&&(this.stats.hasOwnProperty(f)?this.stats[f]+=a.stats[f]:this.stats[f]=a.stats[f]);b.ENABLE_MARKERS_LIST&&(this._clusterMarkers=this._clusterMarkers.concat(a.GetClusterMarkers()))},b.ENABLE_MARKERS_LIST=!1,b}(f);a.Cluster=j;var k=function(){function a(){this._markers=[],this._nbChanges=0,this._clusters=[],this.Size=166,this.ViewPadding=.2}return a.prototype.RegisterMarker=function(a){a._removeFlag&&delete a._removeFlag,this._markers.push(a),this._nbChanges+=1},a.prototype._sortMarkers=function(){var a=this._markers,b=a.length;this._nbChanges&&(!b||this._nbChanges/b>d)?this._markers.sort(function(a,b){return a.position.lng-b.position.lng}):c(a),this._nbChanges=0},a.prototype._sortClusters=function(){c(this._clusters)},a.prototype._indexLowerBoundLng=function(a){for(var b,c,d=this._markers,e=0,f=d.length;f>0;)c=Math.floor(f/2),b=e+c,d[b].position.lnga;++a){var c=this._clusters[a];c.Reset(),c.ComputeBounds(this)}},a.prototype.ProcessView=function(a){var c=Math.abs(a.maxLat-a.minLat)*this.ViewPadding,d=Math.abs(a.maxLng-a.minLng)*this.ViewPadding,e={minLat:a.minLat-c-c,maxLat:a.maxLat+c+c,minLng:a.minLng-d-d,maxLng:a.maxLng+d+d};this._sortMarkers(),this._resetClusterViews();for(var f=this._indexLowerBoundLng(e.minLng),g=this._markers,h=this._clusters,i=h.slice(0),k=f,l=g.length;l>k;++k){var m=g[k],n=m.position;if(n.lng>e.maxLng)break;if(n.lat>e.minLat&&n.latq;++q)if(o=i[q],o.bounds.maxLngk;++k)o=h[k],o.population>0&&s.push(o);return this._clusters=s,this._sortClusters(),this._clusters},a.prototype.RemoveMarkers=function(a){if(!a)return void(this._markers=[]);for(var b=0,c=a.length;c>b;++b)a[b]._removeFlag=!0;var d=[];for(b=0,c=this._markers.length;c>b;++b)this._markers[b]._removeFlag||d.push(this._markers[b]);this._markers=d},a.prototype.FindMarkersInArea=function(a){for(var b=a.minLat,c=a.maxLat,d=a.minLng,e=a.maxLng,f=this._markers,g=[],h=this._indexLowerBoundLng(d),i=h,j=f.length;j>i;++i){var k=f[i].position;if(k.lng>e)break;k.lat>=b&&k.lat<=c&&k.lng>=d&&g.push(f[i])}return g},a.prototype.ComputeBounds=function(a){if(!a||!a.length)return null;for(var b=Number.MAX_VALUE,c=-Number.MAX_VALUE,d=Number.MAX_VALUE,e=-Number.MAX_VALUE,f=0,g=a.length;g>f;++f){var h=a[f].position;h.latc&&(c=h.lat),h.lnge&&(e=h.lng)}return{minLat:b,maxLat:c,minLng:d,maxLng:e}},a.prototype.FindMarkersBoundsInArea=function(a){return this.ComputeBounds(this.FindMarkersInArea(a))},a.prototype.ComputeGlobalBounds=function(){return this.ComputeBounds(this._markers)},a.prototype.GetMarkers=function(){return this._markers},a.prototype.GetPopulation=function(){return this._markers.length},a.prototype.ResetClusters=function(){this._clusters=[]},a}();a.PruneCluster=k}(PruneCluster||(PruneCluster={}));var PruneCluster;!function(){}(PruneCluster||(PruneCluster={}));var PruneClusterForLeaflet=(L.Layer?L.Layer:L.Class).extend({initialize:function(a,b){var c=this;void 0===a&&(a=120),void 0===b&&(b=20),this.Cluster=new PruneCluster.PruneCluster,this.Cluster.Size=a,this.clusterMargin=Math.min(b,a/4),this.Cluster.Project=function(a,b){return c._map.project(new L.LatLng(a,b))},this.Cluster.UnProject=function(a,b){return c._map.unproject(new L.Point(a,b))},this._objectsOnMap=[],this.spiderfier=new PruneClusterLeafletSpiderfier(this),this._hardMove=!1,this._resetIcons=!1,this._removeTimeoutId=0,this._markersRemoveListTimeout=[]},RegisterMarker:function(a){this.Cluster.RegisterMarker(a)},RemoveMarkers:function(a){this.Cluster.RemoveMarkers(a)},BuildLeafletCluster:function(a,b){var c=this,d=new L.Marker(b,{icon:this.BuildLeafletClusterIcon(a)});return d.on("click",function(){var e=c.Cluster.FindMarkersInArea(a.bounds),f=c.Cluster.ComputeBounds(e);if(f){var g=new L.LatLngBounds(new L.LatLng(f.minLat,f.maxLng),new L.LatLng(f.maxLat,f.minLng)),h=c._map.getZoom(),i=c._map.getBoundsZoom(g,!1,new L.Point(20,20));i===h?(c._map.fire("overlappingmarkers",{cluster:c,markers:e,center:d.getLatLng(),marker:d}),c._map.setView(b,i)):c._map.fitBounds(g)}}),d},BuildLeafletClusterIcon:function(a){var b="prunecluster prunecluster-",c=38,d=this.Cluster.GetPopulation();return a.population"+a.population+"",className:b,iconSize:L.point(c,c)})},BuildLeafletMarker:function(a,b){var c=new L.Marker(b);return this.PrepareLeafletMarker(c,a.data,a.category),c},PrepareLeafletMarker:function(a,b,c){if(b.icon&&a.setIcon("function"==typeof b.icon?b.icon(b,c):b.icon),b.popup){var d="function"==typeof b.popup?b.popup(b,c):b.popup;a.getPopup()?a.setPopupContent(d,b.popupOptions):a.bindPopup(d,b.popupOptions)}},onAdd:function(a){this._map=a,a.on("movestart",this._moveStart,this),a.on("moveend",this._moveEnd,this),a.on("zoomend",this._zoomStart,this),a.on("zoomend",this._zoomEnd,this),this.ProcessView(),a.addLayer(this.spiderfier)},onRemove:function(a){a.off("movestart",this._moveStart,this),a.off("moveend",this._moveEnd,this),a.off("zoomend",this._zoomStart,this),a.off("zoomend",this._zoomEnd,this);for(var b=0,c=this._objectsOnMap.length;c>b;++b)a.removeLayer(this._objectsOnMap[b].data._leafletMarker);this._objectsOnMap=[],this.Cluster.ResetClusters(),a.removeLayer(this.spiderfier),this._map=null},_moveStart:function(){this._moveInProgress=!0},_moveEnd:function(a){this._moveInProgress=!1,this._hardMove=a.hard,this.ProcessView()},_zoomStart:function(){this._zoomInProgress=!0},_zoomEnd:function(){this._zoomInProgress=!1,this.ProcessView()},ProcessView:function(){var a=this;if(this._map&&!this._zoomInProgress&&!this._moveInProgress){for(var b=this._map,c=b.getBounds(),d=b.getZoom(),e=this.clusterMargin/this.Cluster.Size,f=this._resetIcons,g=c.getSouthWest(),h=c.getNorthEast(),i=this.Cluster.ProcessView({minLat:g.lat,minLng:g.lng,maxLat:h.lat,maxLng:h.lng}),j=this._objectsOnMap,k=[],l=new Array(j.length),m=0,n=j.length;n>m;++m){var o=j[m].data._leafletMarker;l[m]=o,o._removeFromMap=!0}var p=[],q=[],r=[];for(m=0,n=i.length;n>m;++m){for(var s=i[m],t=s.data,u=(s.bounds.maxLat-s.bounds.minLat)*e,v=(s.bounds.maxLng-s.bounds.minLng)*e,w=0,x=r.length;x>w;++w){var y=r[w];if(y.bounds.maxLngC&&B>D&&E>A){t._leafletCollision=!0,y.ApplyCluster(s);break}}}t._leafletCollision||r.push(s)}for(i.forEach(function(b){var c=void 0,e=b.data;if(e._leafletCollision)return e._leafletCollision=!1,e._leafletOldPopulation=0,void(e._leafletOldHashCode=0);var g=new L.LatLng(b.averagePosition.lat,b.averagePosition.lng),h=e._leafletMarker;h&&(1===b.population&&1===e._leafletOldPopulation&&b.hashCode===h._hashCode?((f||h._zoomLevel!==d||b.lastMarker.data.forceIconRedraw)&&(a.PrepareLeafletMarker(h,b.lastMarker.data,b.lastMarker.category),b.lastMarker.data.forceIconRedraw&&(b.lastMarker.data.forceIconRedraw=!1)),h.setLatLng(g),c=h):b.population>1&&e._leafletOldPopulation>1&&(h._zoomLevel===d||e._leafletPosition.equals(g))&&(h.setLatLng(g),(f||b.population!=e._leafletOldPopulation||b.hashCode!==e._leafletOldHashCode)&&h.setIcon(a.BuildLeafletClusterIcon(b)),e._leafletOldPopulation=b.population,e._leafletOldHashCode=b.hashCode,c=h)),c?(c._removeFromMap=!1,k.push(b),c._zoomLevel=d,c._hashCode=b.hashCode,c._population=b.population,e._leafletMarker=c,e._leafletPosition=g):(p.push(b),e._leafletPosition=g,e._leafletOldPopulation=b.population,e._leafletOldHashCode=b.hashCode)}),m=0,n=j.length;n>m;++m){s=j[m];var F=s.data;if(o=F._leafletMarker,F._leafletMarker._removeFromMap){var G=!0;if(o._zoomLevel===d){var H=s.averagePosition;for(u=(s.bounds.maxLat-s.bounds.minLat)*e,v=(s.bounds.maxLng-s.bounds.minLng)*e,w=0,x=p.length;x>w;++w){var I=p[w],J=I.data,K=I.averagePosition,M=H.lng-v,N=K.lng+v;if(z=H.lng+v,A=H.lat-u,B=H.lat+u,C=K.lng-v,D=K.lat-u,E=K.lat+u,z>C&&N>M&&B>D&&E>A&&(1===o._population&&1===I.population&&o._hashCode===I.hashCode?((f||I.lastMarker.data.forceIconRedraw)&&(this.PrepareLeafletMarker(o,I.lastMarker.data,I.lastMarker.category),I.lastMarker.data.forceIconRedraw&&(I.lastMarker.data.forceIconRedraw=!1)),o.setLatLng(J._leafletPosition),G=!1):o._population>1&&I.population>1&&(o.setLatLng(J._leafletPosition),o.setIcon(this.BuildLeafletClusterIcon(I)),J._leafletOldPopulation=I.population,J._leafletOldHashCode=I.hashCode,o._population=I.population,G=!1),!G)){J._leafletMarker=o,o._removeFromMap=!1,k.push(I),p.splice(w,1),--w,--x;break}}}G&&(o._removeFromMap||console.error("wtf"))}}for(m=0,n=p.length;n>m;++m){s=p[m],F=s.data;var O,P=F._leafletPosition;O=1===s.population?this.BuildLeafletMarker(s.lastMarker,P):this.BuildLeafletCluster(s,P),O.addTo(b),O.setOpacity(0),q.push(O),F._leafletMarker=O,O._zoomLevel=d,O._hashCode=s.hashCode,O._population=s.population,k.push(s)}if(window.setTimeout(function(){for(m=0,n=q.length;n>m;++m){var a=q[m];a._icon&&L.DomUtil.addClass(a._icon,"prunecluster-anim"),a._shadow&&L.DomUtil.addClass(a._shadow,"prunecluster-anim"),a.setOpacity(1)}},1),this._hardMove)for(m=0,n=l.length;n>m;++m)o=l[m],o._removeFromMap&&b.removeLayer(o);else{if(0!==this._removeTimeoutId)for(window.clearTimeout(this._removeTimeoutId),m=0,n=this._markersRemoveListTimeout.length;n>m;++m)b.removeLayer(this._markersRemoveListTimeout[m]);var Q=[];for(m=0,n=l.length;n>m;++m)o=l[m],o._removeFromMap&&(o.setOpacity(0),Q.push(o));Q.length>0&&(this._removeTimeoutId=window.setTimeout(function(){for(m=0,n=Q.length;n>m;++m)b.removeLayer(Q[m]);a._removeTimeoutId=0},300)),this._markersRemoveListTimeout=Q}this._objectsOnMap=k,this._hardMove=!1,this._resetIcons=!1}},FitBounds:function(){var a=this.Cluster.ComputeGlobalBounds();a&&this._map.fitBounds(new L.LatLngBounds(new L.LatLng(a.minLat,a.maxLng),new L.LatLng(a.maxLat,a.minLng)))},GetMarkers:function(){return this.Cluster.GetMarkers()},RedrawIcons:function(a){void 0===a&&(a=!0),this._resetIcons=!0,a&&this.ProcessView()}}),PruneClusterLeafletSpiderfier=(L.Layer?L.Layer:L.Class).extend({_2PI:2*Math.PI,_circleFootSeparation:25,_circleStartAngle:Math.PI/6,_spiralFootSeparation:28,_spiralLengthStart:11,_spiralLengthFactor:5,_spiralCountTrigger:8,spiderfyDistanceMultiplier:1,initialize:function(a){this._cluster=a,this._currentMarkers=[],this._multiLines=!!L.multiPolyline,this._lines=this._multiLines?L.multiPolyline([],{weight:1.5,color:"#222"}):L.polyline([],{weight:1.5,color:"#222"})},onAdd:function(a){this._map=a,this._map.on("overlappingmarkers",this.Spiderfy,this),this._map.on("click",this.Unspiderfy,this),this._map.on("zoomend",this.Unspiderfy,this)},Spiderfy:function(a){var b=this;if(a.cluster===this._cluster){this.Unspiderfy();var c=a.markers.filter(function(a){return!a.filtered});this._currentCenter=a.center;var d,e=this._map.latLngToLayerPoint(a.center);c.length>=this._spiralCountTrigger?d=this._generatePointsSpiral(c.length,e):(this._multiLines&&(e.y+=10),d=this._generatePointsCircle(c.length,e));for(var f=[],g=[],h=[],i=0,j=d.length;j>i;++i){var k=this._map.layerPointToLatLng(d[i]),l=this._cluster.BuildLeafletMarker(c[i],a.center);l.setZIndexOffset(5e3),l.setOpacity(0),this._currentMarkers.push(l),this._map.addLayer(l),g.push(l),h.push(k)}window.setTimeout(function(){for(i=0,j=d.length;j>i;++i)g[i].setLatLng(h[i]).setOpacity(1);var c=+new Date,e=42,k=290,l=window.setInterval(function(){f=[];var e=+new Date,g=e-c;if(g>=k)window.clearInterval(l),m=1;else var m=g/k;var n=a.center;for(i=0,j=d.length;j>i;++i){var o=h[i],p=o.lat-n.lat,q=o.lng-n.lng;f.push([n,new L.LatLng(n.lat+p*m,n.lng+q*m)])}b._lines.setLatLngs(f)},e)},1),this._lines.setLatLngs(f),this._map.addLayer(this._lines),this._clusterMarker=a.marker.setOpacity(.3)}},_generatePointsCircle:function(a,b){var c,d,e=this.spiderfyDistanceMultiplier*this._circleFootSeparation*(2+a),f=e/this._2PI,g=this._2PI/a,h=[];for(h.length=a,c=a-1;c>=0;c--)d=this._circleStartAngle+c*g,h[c]=new L.Point(Math.round(b.x+f*Math.cos(d)),Math.round(b.y+f*Math.sin(d)));return h},_generatePointsSpiral:function(a,b){var c,d=this.spiderfyDistanceMultiplier*this._spiralLengthStart,e=this.spiderfyDistanceMultiplier*this._spiralFootSeparation,f=this.spiderfyDistanceMultiplier*this._spiralLengthFactor,g=0,h=[];for(h.length=a,c=a-1;c>=0;c--)g+=e/d+5e-4*c,h[c]=new L.Point(Math.round(b.x+d*Math.cos(g)),Math.round(b.y+d*Math.sin(g))),d+=this._2PI*f/g;return h},Unspiderfy:function(){for(var a=this,b=0,c=this._currentMarkers.length;c>b;++b)this._currentMarkers[b].setLatLng(this._currentCenter).setOpacity(0);var d=this._currentMarkers;window.setTimeout(function(){for(b=0,c=d.length;c>b;++b)a._map.removeLayer(d[b])},300),this._currentMarkers=[],this._map.removeLayer(this._lines),this._clusterMarker&&this._clusterMarker.setOpacity(1)},onRemove:function(a){this.Unspiderfy(),a.off("overlappingmarkers",this.Spiderfy,this),a.off("click",this.Unspiderfy,this),a.off("zoomend",this.Unspiderfy,this)}}); 2 | //# sourceMappingURL=PruneCluster.min.js.map -------------------------------------------------------------------------------- /bower_components/fetch/fetch.js: -------------------------------------------------------------------------------- 1 | (function(self) { 2 | 'use strict'; 3 | 4 | if (self.fetch) { 5 | return 6 | } 7 | 8 | var support = { 9 | searchParams: 'URLSearchParams' in self, 10 | iterable: 'Symbol' in self && 'iterator' in Symbol, 11 | blob: 'FileReader' in self && 'Blob' in self && (function() { 12 | try { 13 | new Blob() 14 | return true 15 | } catch(e) { 16 | return false 17 | } 18 | })(), 19 | formData: 'FormData' in self, 20 | arrayBuffer: 'ArrayBuffer' in self 21 | } 22 | 23 | function normalizeName(name) { 24 | if (typeof name !== 'string') { 25 | name = String(name) 26 | } 27 | if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) { 28 | throw new TypeError('Invalid character in header field name') 29 | } 30 | return name.toLowerCase() 31 | } 32 | 33 | function normalizeValue(value) { 34 | if (typeof value !== 'string') { 35 | value = String(value) 36 | } 37 | return value 38 | } 39 | 40 | // Build a destructive iterator for the value list 41 | function iteratorFor(items) { 42 | var iterator = { 43 | next: function() { 44 | var value = items.shift() 45 | return {done: value === undefined, value: value} 46 | } 47 | } 48 | 49 | if (support.iterable) { 50 | iterator[Symbol.iterator] = function() { 51 | return iterator 52 | } 53 | } 54 | 55 | return iterator 56 | } 57 | 58 | function Headers(headers) { 59 | this.map = {} 60 | 61 | if (headers instanceof Headers) { 62 | headers.forEach(function(value, name) { 63 | this.append(name, value) 64 | }, this) 65 | 66 | } else if (headers) { 67 | Object.getOwnPropertyNames(headers).forEach(function(name) { 68 | this.append(name, headers[name]) 69 | }, this) 70 | } 71 | } 72 | 73 | Headers.prototype.append = function(name, value) { 74 | name = normalizeName(name) 75 | value = normalizeValue(value) 76 | var list = this.map[name] 77 | if (!list) { 78 | list = [] 79 | this.map[name] = list 80 | } 81 | list.push(value) 82 | } 83 | 84 | Headers.prototype['delete'] = function(name) { 85 | delete this.map[normalizeName(name)] 86 | } 87 | 88 | Headers.prototype.get = function(name) { 89 | var values = this.map[normalizeName(name)] 90 | return values ? values[0] : null 91 | } 92 | 93 | Headers.prototype.getAll = function(name) { 94 | return this.map[normalizeName(name)] || [] 95 | } 96 | 97 | Headers.prototype.has = function(name) { 98 | return this.map.hasOwnProperty(normalizeName(name)) 99 | } 100 | 101 | Headers.prototype.set = function(name, value) { 102 | this.map[normalizeName(name)] = [normalizeValue(value)] 103 | } 104 | 105 | Headers.prototype.forEach = function(callback, thisArg) { 106 | Object.getOwnPropertyNames(this.map).forEach(function(name) { 107 | this.map[name].forEach(function(value) { 108 | callback.call(thisArg, value, name, this) 109 | }, this) 110 | }, this) 111 | } 112 | 113 | Headers.prototype.keys = function() { 114 | var items = [] 115 | this.forEach(function(value, name) { items.push(name) }) 116 | return iteratorFor(items) 117 | } 118 | 119 | Headers.prototype.values = function() { 120 | var items = [] 121 | this.forEach(function(value) { items.push(value) }) 122 | return iteratorFor(items) 123 | } 124 | 125 | Headers.prototype.entries = function() { 126 | var items = [] 127 | this.forEach(function(value, name) { items.push([name, value]) }) 128 | return iteratorFor(items) 129 | } 130 | 131 | if (support.iterable) { 132 | Headers.prototype[Symbol.iterator] = Headers.prototype.entries 133 | } 134 | 135 | function consumed(body) { 136 | if (body.bodyUsed) { 137 | return Promise.reject(new TypeError('Already read')) 138 | } 139 | body.bodyUsed = true 140 | } 141 | 142 | function fileReaderReady(reader) { 143 | return new Promise(function(resolve, reject) { 144 | reader.onload = function() { 145 | resolve(reader.result) 146 | } 147 | reader.onerror = function() { 148 | reject(reader.error) 149 | } 150 | }) 151 | } 152 | 153 | function readBlobAsArrayBuffer(blob) { 154 | var reader = new FileReader() 155 | reader.readAsArrayBuffer(blob) 156 | return fileReaderReady(reader) 157 | } 158 | 159 | function readBlobAsText(blob) { 160 | var reader = new FileReader() 161 | reader.readAsText(blob) 162 | return fileReaderReady(reader) 163 | } 164 | 165 | function Body() { 166 | this.bodyUsed = false 167 | 168 | this._initBody = function(body) { 169 | this._bodyInit = body 170 | if (typeof body === 'string') { 171 | this._bodyText = body 172 | } else if (support.blob && Blob.prototype.isPrototypeOf(body)) { 173 | this._bodyBlob = body 174 | } else if (support.formData && FormData.prototype.isPrototypeOf(body)) { 175 | this._bodyFormData = body 176 | } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) { 177 | this._bodyText = body.toString() 178 | } else if (!body) { 179 | this._bodyText = '' 180 | } else if (support.arrayBuffer && ArrayBuffer.prototype.isPrototypeOf(body)) { 181 | // Only support ArrayBuffers for POST method. 182 | // Receiving ArrayBuffers happens via Blobs, instead. 183 | } else { 184 | throw new Error('unsupported BodyInit type') 185 | } 186 | 187 | if (!this.headers.get('content-type')) { 188 | if (typeof body === 'string') { 189 | this.headers.set('content-type', 'text/plain;charset=UTF-8') 190 | } else if (this._bodyBlob && this._bodyBlob.type) { 191 | this.headers.set('content-type', this._bodyBlob.type) 192 | } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) { 193 | this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8') 194 | } 195 | } 196 | } 197 | 198 | if (support.blob) { 199 | this.blob = function() { 200 | var rejected = consumed(this) 201 | if (rejected) { 202 | return rejected 203 | } 204 | 205 | if (this._bodyBlob) { 206 | return Promise.resolve(this._bodyBlob) 207 | } else if (this._bodyFormData) { 208 | throw new Error('could not read FormData body as blob') 209 | } else { 210 | return Promise.resolve(new Blob([this._bodyText])) 211 | } 212 | } 213 | 214 | this.arrayBuffer = function() { 215 | return this.blob().then(readBlobAsArrayBuffer) 216 | } 217 | 218 | this.text = function() { 219 | var rejected = consumed(this) 220 | if (rejected) { 221 | return rejected 222 | } 223 | 224 | if (this._bodyBlob) { 225 | return readBlobAsText(this._bodyBlob) 226 | } else if (this._bodyFormData) { 227 | throw new Error('could not read FormData body as text') 228 | } else { 229 | return Promise.resolve(this._bodyText) 230 | } 231 | } 232 | } else { 233 | this.text = function() { 234 | var rejected = consumed(this) 235 | return rejected ? rejected : Promise.resolve(this._bodyText) 236 | } 237 | } 238 | 239 | if (support.formData) { 240 | this.formData = function() { 241 | return this.text().then(decode) 242 | } 243 | } 244 | 245 | this.json = function() { 246 | return this.text().then(JSON.parse) 247 | } 248 | 249 | return this 250 | } 251 | 252 | // HTTP methods whose capitalization should be normalized 253 | var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'] 254 | 255 | function normalizeMethod(method) { 256 | var upcased = method.toUpperCase() 257 | return (methods.indexOf(upcased) > -1) ? upcased : method 258 | } 259 | 260 | function Request(input, options) { 261 | options = options || {} 262 | var body = options.body 263 | if (Request.prototype.isPrototypeOf(input)) { 264 | if (input.bodyUsed) { 265 | throw new TypeError('Already read') 266 | } 267 | this.url = input.url 268 | this.credentials = input.credentials 269 | if (!options.headers) { 270 | this.headers = new Headers(input.headers) 271 | } 272 | this.method = input.method 273 | this.mode = input.mode 274 | if (!body) { 275 | body = input._bodyInit 276 | input.bodyUsed = true 277 | } 278 | } else { 279 | this.url = input 280 | } 281 | 282 | this.credentials = options.credentials || this.credentials || 'omit' 283 | if (options.headers || !this.headers) { 284 | this.headers = new Headers(options.headers) 285 | } 286 | this.method = normalizeMethod(options.method || this.method || 'GET') 287 | this.mode = options.mode || this.mode || null 288 | this.referrer = null 289 | 290 | if ((this.method === 'GET' || this.method === 'HEAD') && body) { 291 | throw new TypeError('Body not allowed for GET or HEAD requests') 292 | } 293 | this._initBody(body) 294 | } 295 | 296 | Request.prototype.clone = function() { 297 | return new Request(this) 298 | } 299 | 300 | function decode(body) { 301 | var form = new FormData() 302 | body.trim().split('&').forEach(function(bytes) { 303 | if (bytes) { 304 | var split = bytes.split('=') 305 | var name = split.shift().replace(/\+/g, ' ') 306 | var value = split.join('=').replace(/\+/g, ' ') 307 | form.append(decodeURIComponent(name), decodeURIComponent(value)) 308 | } 309 | }) 310 | return form 311 | } 312 | 313 | function headers(xhr) { 314 | var head = new Headers() 315 | var pairs = (xhr.getAllResponseHeaders() || '').trim().split('\n') 316 | pairs.forEach(function(header) { 317 | var split = header.trim().split(':') 318 | var key = split.shift().trim() 319 | var value = split.join(':').trim() 320 | head.append(key, value) 321 | }) 322 | return head 323 | } 324 | 325 | Body.call(Request.prototype) 326 | 327 | function Response(bodyInit, options) { 328 | if (!options) { 329 | options = {} 330 | } 331 | 332 | this.type = 'default' 333 | this.status = options.status 334 | this.ok = this.status >= 200 && this.status < 300 335 | this.statusText = options.statusText 336 | this.headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers) 337 | this.url = options.url || '' 338 | this._initBody(bodyInit) 339 | } 340 | 341 | Body.call(Response.prototype) 342 | 343 | Response.prototype.clone = function() { 344 | return new Response(this._bodyInit, { 345 | status: this.status, 346 | statusText: this.statusText, 347 | headers: new Headers(this.headers), 348 | url: this.url 349 | }) 350 | } 351 | 352 | Response.error = function() { 353 | var response = new Response(null, {status: 0, statusText: ''}) 354 | response.type = 'error' 355 | return response 356 | } 357 | 358 | var redirectStatuses = [301, 302, 303, 307, 308] 359 | 360 | Response.redirect = function(url, status) { 361 | if (redirectStatuses.indexOf(status) === -1) { 362 | throw new RangeError('Invalid status code') 363 | } 364 | 365 | return new Response(null, {status: status, headers: {location: url}}) 366 | } 367 | 368 | self.Headers = Headers 369 | self.Request = Request 370 | self.Response = Response 371 | 372 | self.fetch = function(input, init) { 373 | return new Promise(function(resolve, reject) { 374 | var request 375 | if (Request.prototype.isPrototypeOf(input) && !init) { 376 | request = input 377 | } else { 378 | request = new Request(input, init) 379 | } 380 | 381 | var xhr = new XMLHttpRequest() 382 | 383 | function responseURL() { 384 | if ('responseURL' in xhr) { 385 | return xhr.responseURL 386 | } 387 | 388 | // Avoid security warnings on getResponseHeader when not allowed by CORS 389 | if (/^X-Request-URL:/m.test(xhr.getAllResponseHeaders())) { 390 | return xhr.getResponseHeader('X-Request-URL') 391 | } 392 | 393 | return 394 | } 395 | 396 | xhr.onload = function() { 397 | var options = { 398 | status: xhr.status, 399 | statusText: xhr.statusText, 400 | headers: headers(xhr), 401 | url: responseURL() 402 | } 403 | var body = 'response' in xhr ? xhr.response : xhr.responseText 404 | resolve(new Response(body, options)) 405 | } 406 | 407 | xhr.onerror = function() { 408 | reject(new TypeError('Network request failed')) 409 | } 410 | 411 | xhr.ontimeout = function() { 412 | reject(new TypeError('Network request failed')) 413 | } 414 | 415 | xhr.open(request.method, request.url, true) 416 | 417 | if (request.credentials === 'include') { 418 | xhr.withCredentials = true 419 | } 420 | 421 | if ('responseType' in xhr && support.blob) { 422 | xhr.responseType = 'blob' 423 | } 424 | 425 | request.headers.forEach(function(value, name) { 426 | xhr.setRequestHeader(name, value) 427 | }) 428 | 429 | xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit) 430 | }) 431 | } 432 | self.fetch.polyfill = true 433 | })(typeof self !== 'undefined' ? self : this); 434 | -------------------------------------------------------------------------------- /bower_components/leaflet/dist/images/layers-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/bower_components/leaflet/dist/images/layers-2x.png -------------------------------------------------------------------------------- /bower_components/leaflet/dist/images/layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/bower_components/leaflet/dist/images/layers.png -------------------------------------------------------------------------------- /bower_components/leaflet/dist/images/marker-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TransforMap/transformap-viewer/5d738a3a494b8ddff17f28689614050ef40ab899/bower_components/leaflet/dist/images/marker-green.png -------------------------------------------------------------------------------- /bower_components/leaflet/dist/leaflet.css: -------------------------------------------------------------------------------- 1 | /* required styles */ 2 | 3 | .leaflet-map-pane, 4 | .leaflet-tile, 5 | .leaflet-marker-icon, 6 | .leaflet-marker-shadow, 7 | .leaflet-tile-pane, 8 | .leaflet-tile-container, 9 | .leaflet-overlay-pane, 10 | .leaflet-shadow-pane, 11 | .leaflet-marker-pane, 12 | .leaflet-popup-pane, 13 | .leaflet-overlay-pane svg, 14 | .leaflet-zoom-box, 15 | .leaflet-image-layer, 16 | .leaflet-layer { 17 | position: absolute; 18 | left: 0; 19 | top: 0; 20 | } 21 | .leaflet-container { 22 | overflow: hidden; 23 | -ms-touch-action: none; 24 | touch-action: none; 25 | } 26 | .leaflet-tile, 27 | .leaflet-marker-icon, 28 | .leaflet-marker-shadow { 29 | -webkit-user-select: none; 30 | -moz-user-select: none; 31 | user-select: none; 32 | -webkit-user-drag: none; 33 | } 34 | .leaflet-marker-icon, 35 | .leaflet-marker-shadow { 36 | display: block; 37 | } 38 | /* map is broken in FF if you have max-width: 100% on tiles */ 39 | .leaflet-container img { 40 | max-width: none !important; 41 | } 42 | /* stupid Android 2 doesn't understand "max-width: none" properly */ 43 | .leaflet-container img.leaflet-image-layer { 44 | max-width: 15000px !important; 45 | } 46 | .leaflet-tile { 47 | filter: inherit; 48 | visibility: hidden; 49 | } 50 | .leaflet-tile-loaded { 51 | visibility: inherit; 52 | } 53 | .leaflet-zoom-box { 54 | width: 0; 55 | height: 0; 56 | } 57 | /* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */ 58 | .leaflet-overlay-pane svg { 59 | -moz-user-select: none; 60 | } 61 | 62 | .leaflet-tile-pane { z-index: 2; } 63 | .leaflet-objects-pane { z-index: 3; } 64 | .leaflet-overlay-pane { z-index: 4; } 65 | .leaflet-shadow-pane { z-index: 5; } 66 | .leaflet-marker-pane { z-index: 6; } 67 | .leaflet-popup-pane { z-index: 7; } 68 | 69 | .leaflet-vml-shape { 70 | width: 1px; 71 | height: 1px; 72 | } 73 | .lvml { 74 | behavior: url(#default#VML); 75 | display: inline-block; 76 | position: absolute; 77 | } 78 | 79 | 80 | /* control positioning */ 81 | 82 | .leaflet-control { 83 | position: relative; 84 | z-index: 7; 85 | pointer-events: auto; 86 | } 87 | .leaflet-top, 88 | .leaflet-bottom { 89 | position: absolute; 90 | z-index: 1000; 91 | pointer-events: none; 92 | } 93 | .leaflet-top { 94 | top: 0; 95 | } 96 | .leaflet-right { 97 | right: 0; 98 | } 99 | .leaflet-bottom { 100 | bottom: 0; 101 | } 102 | .leaflet-left { 103 | left: 0; 104 | } 105 | .leaflet-control { 106 | float: left; 107 | clear: both; 108 | } 109 | .leaflet-right .leaflet-control { 110 | float: right; 111 | } 112 | .leaflet-top .leaflet-control { 113 | margin-top: 10px; 114 | } 115 | .leaflet-bottom .leaflet-control { 116 | margin-bottom: 10px; 117 | } 118 | .leaflet-left .leaflet-control { 119 | margin-left: 10px; 120 | } 121 | .leaflet-right .leaflet-control { 122 | margin-right: 10px; 123 | } 124 | 125 | 126 | /* zoom and fade animations */ 127 | 128 | .leaflet-fade-anim .leaflet-tile, 129 | .leaflet-fade-anim .leaflet-popup { 130 | opacity: 0; 131 | -webkit-transition: opacity 0.2s linear; 132 | -moz-transition: opacity 0.2s linear; 133 | -o-transition: opacity 0.2s linear; 134 | transition: opacity 0.2s linear; 135 | } 136 | .leaflet-fade-anim .leaflet-tile-loaded, 137 | .leaflet-fade-anim .leaflet-map-pane .leaflet-popup { 138 | opacity: 1; 139 | } 140 | 141 | .leaflet-zoom-anim .leaflet-zoom-animated { 142 | -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); 143 | -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); 144 | -o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1); 145 | transition: transform 0.25s cubic-bezier(0,0,0.25,1); 146 | } 147 | .leaflet-zoom-anim .leaflet-tile, 148 | .leaflet-pan-anim .leaflet-tile, 149 | .leaflet-touching .leaflet-zoom-animated { 150 | -webkit-transition: none; 151 | -moz-transition: none; 152 | -o-transition: none; 153 | transition: none; 154 | } 155 | 156 | .leaflet-zoom-anim .leaflet-zoom-hide { 157 | visibility: hidden; 158 | } 159 | 160 | 161 | /* cursors */ 162 | 163 | .leaflet-clickable { 164 | cursor: pointer; 165 | } 166 | .leaflet-container { 167 | cursor: -webkit-grab; 168 | cursor: -moz-grab; 169 | } 170 | .leaflet-popup-pane, 171 | .leaflet-control { 172 | cursor: auto; 173 | } 174 | .leaflet-dragging .leaflet-container, 175 | .leaflet-dragging .leaflet-clickable { 176 | cursor: move; 177 | cursor: -webkit-grabbing; 178 | cursor: -moz-grabbing; 179 | } 180 | 181 | 182 | /* visual tweaks */ 183 | 184 | .leaflet-container { 185 | background: #ddd; 186 | outline: 0; 187 | } 188 | .leaflet-container a { 189 | color: #0078A8; 190 | } 191 | .leaflet-container a.leaflet-active { 192 | outline: 2px solid orange; 193 | } 194 | .leaflet-zoom-box { 195 | border: 2px dotted #38f; 196 | background: rgba(255,255,255,0.5); 197 | } 198 | 199 | 200 | /* general typography */ 201 | .leaflet-container { 202 | font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; 203 | } 204 | 205 | 206 | /* general toolbar styles */ 207 | 208 | .leaflet-bar { 209 | box-shadow: 0 1px 5px rgba(0,0,0,0.65); 210 | border-radius: 4px; 211 | } 212 | .leaflet-bar a, 213 | .leaflet-bar a:hover { 214 | background-color: #fff; 215 | border-bottom: 1px solid #ccc; 216 | width: 26px; 217 | height: 26px; 218 | line-height: 26px; 219 | display: block; 220 | text-align: center; 221 | text-decoration: none; 222 | color: black; 223 | } 224 | .leaflet-bar a, 225 | .leaflet-control-layers-toggle { 226 | background-position: 50% 50%; 227 | background-repeat: no-repeat; 228 | display: block; 229 | } 230 | .leaflet-bar a:hover { 231 | background-color: #f4f4f4; 232 | } 233 | .leaflet-bar a:first-child { 234 | border-top-left-radius: 4px; 235 | border-top-right-radius: 4px; 236 | } 237 | .leaflet-bar a:last-child { 238 | border-bottom-left-radius: 4px; 239 | border-bottom-right-radius: 4px; 240 | border-bottom: none; 241 | } 242 | .leaflet-bar a.leaflet-disabled { 243 | cursor: default; 244 | background-color: #f4f4f4; 245 | color: #bbb; 246 | } 247 | 248 | .leaflet-touch .leaflet-bar a { 249 | width: 30px; 250 | height: 30px; 251 | line-height: 30px; 252 | } 253 | 254 | 255 | /* zoom control */ 256 | 257 | .leaflet-control-zoom-in, 258 | .leaflet-control-zoom-out { 259 | font: bold 18px 'Lucida Console', Monaco, monospace; 260 | text-indent: 1px; 261 | } 262 | .leaflet-control-zoom-out { 263 | font-size: 20px; 264 | } 265 | 266 | .leaflet-touch .leaflet-control-zoom-in { 267 | font-size: 22px; 268 | } 269 | .leaflet-touch .leaflet-control-zoom-out { 270 | font-size: 24px; 271 | } 272 | 273 | 274 | /* layers control */ 275 | 276 | .leaflet-control-layers { 277 | box-shadow: 0 1px 5px rgba(0,0,0,0.4); 278 | background: #fff; 279 | border-radius: 5px; 280 | } 281 | .leaflet-control-layers-toggle { 282 | background-image: url(images/layers.png); 283 | width: 36px; 284 | height: 36px; 285 | } 286 | .leaflet-retina .leaflet-control-layers-toggle { 287 | background-image: url(images/layers-2x.png); 288 | background-size: 26px 26px; 289 | } 290 | .leaflet-touch .leaflet-control-layers-toggle { 291 | width: 44px; 292 | height: 44px; 293 | } 294 | .leaflet-control-layers .leaflet-control-layers-list, 295 | .leaflet-control-layers-expanded .leaflet-control-layers-toggle { 296 | display: none; 297 | } 298 | .leaflet-control-layers-expanded .leaflet-control-layers-list { 299 | display: block; 300 | position: relative; 301 | } 302 | .leaflet-control-layers-expanded { 303 | padding: 6px 10px 6px 6px; 304 | color: #333; 305 | background: #fff; 306 | } 307 | .leaflet-control-layers-selector { 308 | margin-top: 2px; 309 | position: relative; 310 | top: 1px; 311 | } 312 | .leaflet-control-layers label { 313 | display: block; 314 | } 315 | .leaflet-control-layers-separator { 316 | height: 0; 317 | border-top: 1px solid #ddd; 318 | margin: 5px -10px 5px -6px; 319 | } 320 | 321 | 322 | /* attribution and scale controls */ 323 | 324 | .leaflet-container .leaflet-control-attribution { 325 | background: #fff; 326 | background: rgba(255, 255, 255, 0.7); 327 | margin: 0; 328 | } 329 | .leaflet-control-attribution, 330 | .leaflet-control-scale-line { 331 | padding: 0 5px; 332 | color: #333; 333 | } 334 | .leaflet-control-attribution a { 335 | text-decoration: none; 336 | } 337 | .leaflet-control-attribution a:hover { 338 | text-decoration: underline; 339 | } 340 | .leaflet-container .leaflet-control-attribution, 341 | .leaflet-container .leaflet-control-scale { 342 | font-size: 11px; 343 | } 344 | .leaflet-left .leaflet-control-scale { 345 | margin-left: 5px; 346 | } 347 | .leaflet-bottom .leaflet-control-scale { 348 | margin-bottom: 5px; 349 | } 350 | .leaflet-control-scale-line { 351 | border: 2px solid #777; 352 | border-top: none; 353 | line-height: 1.1; 354 | padding: 2px 5px 1px; 355 | font-size: 11px; 356 | white-space: nowrap; 357 | overflow: hidden; 358 | -moz-box-sizing: content-box; 359 | box-sizing: content-box; 360 | 361 | background: #fff; 362 | background: rgba(255, 255, 255, 0.5); 363 | } 364 | .leaflet-control-scale-line:not(:first-child) { 365 | border-top: 2px solid #777; 366 | border-bottom: none; 367 | margin-top: -2px; 368 | } 369 | .leaflet-control-scale-line:not(:first-child):not(:last-child) { 370 | border-bottom: 2px solid #777; 371 | } 372 | 373 | .leaflet-touch .leaflet-control-attribution, 374 | .leaflet-touch .leaflet-control-layers, 375 | .leaflet-touch .leaflet-bar { 376 | box-shadow: none; 377 | } 378 | .leaflet-touch .leaflet-control-layers, 379 | .leaflet-touch .leaflet-bar { 380 | border: 2px solid rgba(0,0,0,0.2); 381 | background-clip: padding-box; 382 | } 383 | 384 | 385 | /* popup */ 386 | 387 | .leaflet-popup { 388 | position: absolute; 389 | text-align: center; 390 | } 391 | .leaflet-popup-content-wrapper { 392 | padding: 1px; 393 | text-align: left; 394 | border-radius: 12px; 395 | } 396 | .leaflet-popup-content { 397 | margin: 13px 19px; 398 | line-height: 1.4; 399 | } 400 | .leaflet-popup-content p { 401 | margin: 18px 0; 402 | } 403 | .leaflet-popup-tip-container { 404 | margin: 0 auto; 405 | width: 40px; 406 | height: 20px; 407 | position: relative; 408 | overflow: hidden; 409 | } 410 | .leaflet-popup-tip { 411 | width: 17px; 412 | height: 17px; 413 | padding: 1px; 414 | 415 | margin: -10px auto 0; 416 | 417 | -webkit-transform: rotate(45deg); 418 | -moz-transform: rotate(45deg); 419 | -ms-transform: rotate(45deg); 420 | -o-transform: rotate(45deg); 421 | transform: rotate(45deg); 422 | } 423 | .leaflet-popup-content-wrapper, 424 | .leaflet-popup-tip { 425 | background: white; 426 | 427 | box-shadow: 0 3px 14px rgba(0,0,0,0.4); 428 | } 429 | .leaflet-container a.leaflet-popup-close-button { 430 | position: absolute; 431 | top: 0; 432 | right: 0; 433 | padding: 4px 4px 0 0; 434 | text-align: center; 435 | width: 18px; 436 | height: 14px; 437 | font: 16px/14px Tahoma, Verdana, sans-serif; 438 | color: #c3c3c3; 439 | text-decoration: none; 440 | font-weight: bold; 441 | background: transparent; 442 | } 443 | .leaflet-container a.leaflet-popup-close-button:hover { 444 | color: #999; 445 | } 446 | .leaflet-popup-scrolled { 447 | overflow: auto; 448 | border-bottom: 1px solid #ddd; 449 | border-top: 1px solid #ddd; 450 | } 451 | 452 | .leaflet-oldie .leaflet-popup-content-wrapper { 453 | zoom: 1; 454 | } 455 | .leaflet-oldie .leaflet-popup-tip { 456 | width: 24px; 457 | margin: 0 auto; 458 | 459 | -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; 460 | filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); 461 | } 462 | .leaflet-oldie .leaflet-popup-tip-container { 463 | margin-top: -1px; 464 | } 465 | 466 | .leaflet-oldie .leaflet-control-zoom, 467 | .leaflet-oldie .leaflet-control-layers, 468 | .leaflet-oldie .leaflet-popup-content-wrapper, 469 | .leaflet-oldie .leaflet-popup-tip { 470 | border: 1px solid #999; 471 | } 472 | 473 | 474 | /* div icon */ 475 | 476 | .leaflet-div-icon { 477 | background: #fff; 478 | border: 1px solid #666; 479 | } 480 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | TransforMap-Viewer 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 51 | 52 | 60 | 61 | 122 | 123 |
124 |
125 |
    126 |
127 |
128 |
129 |
130 | 131 |
132 | 133 |
134 |
135 |
136 |
137 |
138 |
139 | 140 | 141 | 142 | V 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /dist/site.css: -------------------------------------------------------------------------------- 1 | /* required styles */ 2 | 3 | .leaflet-map-pane, 4 | .leaflet-tile, 5 | .leaflet-marker-icon, 6 | .leaflet-marker-shadow, 7 | .leaflet-tile-pane, 8 | .leaflet-tile-container, 9 | .leaflet-overlay-pane, 10 | .leaflet-shadow-pane, 11 | .leaflet-marker-pane, 12 | .leaflet-popup-pane, 13 | .leaflet-overlay-pane svg, 14 | .leaflet-zoom-box, 15 | .leaflet-image-layer, 16 | .leaflet-layer { 17 | position: absolute; 18 | left: 0; 19 | top: 0; 20 | } 21 | .leaflet-container { 22 | overflow: hidden; 23 | -ms-touch-action: none; 24 | touch-action: none; 25 | } 26 | .leaflet-tile, 27 | .leaflet-marker-icon, 28 | .leaflet-marker-shadow { 29 | -webkit-user-select: none; 30 | -moz-user-select: none; 31 | user-select: none; 32 | -webkit-user-drag: none; 33 | } 34 | .leaflet-marker-icon, 35 | .leaflet-marker-shadow { 36 | display: block; 37 | } 38 | /* map is broken in FF if you have max-width: 100% on tiles */ 39 | .leaflet-container img { 40 | max-width: none !important; 41 | } 42 | /* stupid Android 2 doesn't understand "max-width: none" properly */ 43 | .leaflet-container img.leaflet-image-layer { 44 | max-width: 15000px !important; 45 | } 46 | .leaflet-tile { 47 | filter: inherit; 48 | visibility: hidden; 49 | } 50 | .leaflet-tile-loaded { 51 | visibility: inherit; 52 | } 53 | .leaflet-zoom-box { 54 | width: 0; 55 | height: 0; 56 | } 57 | /* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */ 58 | .leaflet-overlay-pane svg { 59 | -moz-user-select: none; 60 | } 61 | 62 | .leaflet-tile-pane { z-index: 2; } 63 | .leaflet-objects-pane { z-index: 3; } 64 | .leaflet-overlay-pane { z-index: 4; } 65 | .leaflet-shadow-pane { z-index: 5; } 66 | .leaflet-marker-pane { z-index: 6; } 67 | .leaflet-popup-pane { z-index: 7; } 68 | 69 | .leaflet-vml-shape { 70 | width: 1px; 71 | height: 1px; 72 | } 73 | .lvml { 74 | behavior: url(#default#VML); 75 | display: inline-block; 76 | position: absolute; 77 | } 78 | 79 | 80 | /* control positioning */ 81 | 82 | .leaflet-control { 83 | position: relative; 84 | z-index: 7; 85 | pointer-events: auto; 86 | } 87 | .leaflet-top, 88 | .leaflet-bottom { 89 | position: absolute; 90 | z-index: 1000; 91 | pointer-events: none; 92 | } 93 | .leaflet-top { 94 | top: 0; 95 | } 96 | .leaflet-right { 97 | right: 0; 98 | } 99 | .leaflet-bottom { 100 | bottom: 0; 101 | } 102 | .leaflet-left { 103 | left: 0; 104 | } 105 | .leaflet-control { 106 | float: left; 107 | clear: both; 108 | } 109 | .leaflet-right .leaflet-control { 110 | float: right; 111 | } 112 | .leaflet-top .leaflet-control { 113 | margin-top: 10px; 114 | } 115 | .leaflet-bottom .leaflet-control { 116 | margin-bottom: 10px; 117 | } 118 | .leaflet-left .leaflet-control { 119 | margin-left: 10px; 120 | } 121 | .leaflet-right .leaflet-control { 122 | margin-right: 10px; 123 | } 124 | 125 | 126 | /* zoom and fade animations */ 127 | 128 | .leaflet-fade-anim .leaflet-tile, 129 | .leaflet-fade-anim .leaflet-popup { 130 | opacity: 0; 131 | -webkit-transition: opacity 0.2s linear; 132 | -moz-transition: opacity 0.2s linear; 133 | -o-transition: opacity 0.2s linear; 134 | transition: opacity 0.2s linear; 135 | } 136 | .leaflet-fade-anim .leaflet-tile-loaded, 137 | .leaflet-fade-anim .leaflet-map-pane .leaflet-popup { 138 | opacity: 1; 139 | } 140 | 141 | .leaflet-zoom-anim .leaflet-zoom-animated { 142 | -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); 143 | -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); 144 | -o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1); 145 | transition: transform 0.25s cubic-bezier(0,0,0.25,1); 146 | } 147 | .leaflet-zoom-anim .leaflet-tile, 148 | .leaflet-pan-anim .leaflet-tile, 149 | .leaflet-touching .leaflet-zoom-animated { 150 | -webkit-transition: none; 151 | -moz-transition: none; 152 | -o-transition: none; 153 | transition: none; 154 | } 155 | 156 | .leaflet-zoom-anim .leaflet-zoom-hide { 157 | visibility: hidden; 158 | } 159 | 160 | 161 | /* cursors */ 162 | 163 | .leaflet-clickable { 164 | cursor: pointer; 165 | } 166 | .leaflet-container { 167 | cursor: -webkit-grab; 168 | cursor: -moz-grab; 169 | } 170 | .leaflet-popup-pane, 171 | .leaflet-control { 172 | cursor: auto; 173 | } 174 | .leaflet-dragging .leaflet-container, 175 | .leaflet-dragging .leaflet-clickable { 176 | cursor: move; 177 | cursor: -webkit-grabbing; 178 | cursor: -moz-grabbing; 179 | } 180 | 181 | 182 | /* visual tweaks */ 183 | 184 | .leaflet-container { 185 | background: #ddd; 186 | outline: 0; 187 | } 188 | .leaflet-container a { 189 | color: #0078A8; 190 | } 191 | .leaflet-container a.leaflet-active { 192 | outline: 2px solid orange; 193 | } 194 | .leaflet-zoom-box { 195 | border: 2px dotted #38f; 196 | background: rgba(255,255,255,0.5); 197 | } 198 | 199 | 200 | /* general typography */ 201 | .leaflet-container { 202 | font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; 203 | } 204 | 205 | 206 | /* general toolbar styles */ 207 | 208 | .leaflet-bar { 209 | box-shadow: 0 1px 5px rgba(0,0,0,0.65); 210 | border-radius: 4px; 211 | } 212 | .leaflet-bar a, 213 | .leaflet-bar a:hover { 214 | background-color: #fff; 215 | border-bottom: 1px solid #ccc; 216 | width: 26px; 217 | height: 26px; 218 | line-height: 26px; 219 | display: block; 220 | text-align: center; 221 | text-decoration: none; 222 | color: black; 223 | } 224 | .leaflet-bar a, 225 | .leaflet-control-layers-toggle { 226 | background-position: 50% 50%; 227 | background-repeat: no-repeat; 228 | display: block; 229 | } 230 | .leaflet-bar a:hover { 231 | background-color: #f4f4f4; 232 | } 233 | .leaflet-bar a:first-child { 234 | border-top-left-radius: 4px; 235 | border-top-right-radius: 4px; 236 | } 237 | .leaflet-bar a:last-child { 238 | border-bottom-left-radius: 4px; 239 | border-bottom-right-radius: 4px; 240 | border-bottom: none; 241 | } 242 | .leaflet-bar a.leaflet-disabled { 243 | cursor: default; 244 | background-color: #f4f4f4; 245 | color: #bbb; 246 | } 247 | 248 | .leaflet-touch .leaflet-bar a { 249 | width: 30px; 250 | height: 30px; 251 | line-height: 30px; 252 | } 253 | 254 | 255 | /* zoom control */ 256 | 257 | .leaflet-control-zoom-in, 258 | .leaflet-control-zoom-out { 259 | font: bold 18px 'Lucida Console', Monaco, monospace; 260 | text-indent: 1px; 261 | } 262 | .leaflet-control-zoom-out { 263 | font-size: 20px; 264 | } 265 | 266 | .leaflet-touch .leaflet-control-zoom-in { 267 | font-size: 22px; 268 | } 269 | .leaflet-touch .leaflet-control-zoom-out { 270 | font-size: 24px; 271 | } 272 | 273 | 274 | /* layers control */ 275 | 276 | .leaflet-control-layers { 277 | box-shadow: 0 1px 5px rgba(0,0,0,0.4); 278 | background: #fff; 279 | border-radius: 5px; 280 | } 281 | .leaflet-control-layers-toggle { 282 | background-image: url(images/layers.png); 283 | width: 36px; 284 | height: 36px; 285 | } 286 | .leaflet-retina .leaflet-control-layers-toggle { 287 | background-image: url(images/layers-2x.png); 288 | background-size: 26px 26px; 289 | } 290 | .leaflet-touch .leaflet-control-layers-toggle { 291 | width: 44px; 292 | height: 44px; 293 | } 294 | .leaflet-control-layers .leaflet-control-layers-list, 295 | .leaflet-control-layers-expanded .leaflet-control-layers-toggle { 296 | display: none; 297 | } 298 | .leaflet-control-layers-expanded .leaflet-control-layers-list { 299 | display: block; 300 | position: relative; 301 | } 302 | .leaflet-control-layers-expanded { 303 | padding: 6px 10px 6px 6px; 304 | color: #333; 305 | background: #fff; 306 | } 307 | .leaflet-control-layers-selector { 308 | margin-top: 2px; 309 | position: relative; 310 | top: 1px; 311 | } 312 | .leaflet-control-layers label { 313 | display: block; 314 | } 315 | .leaflet-control-layers-separator { 316 | height: 0; 317 | border-top: 1px solid #ddd; 318 | margin: 5px -10px 5px -6px; 319 | } 320 | 321 | 322 | /* attribution and scale controls */ 323 | 324 | .leaflet-container .leaflet-control-attribution { 325 | background: #fff; 326 | background: rgba(255, 255, 255, 0.7); 327 | margin: 0; 328 | } 329 | .leaflet-control-attribution, 330 | .leaflet-control-scale-line { 331 | padding: 0 5px; 332 | color: #333; 333 | } 334 | .leaflet-control-attribution a { 335 | text-decoration: none; 336 | } 337 | .leaflet-control-attribution a:hover { 338 | text-decoration: underline; 339 | } 340 | .leaflet-container .leaflet-control-attribution, 341 | .leaflet-container .leaflet-control-scale { 342 | font-size: 11px; 343 | } 344 | .leaflet-left .leaflet-control-scale { 345 | margin-left: 5px; 346 | } 347 | .leaflet-bottom .leaflet-control-scale { 348 | margin-bottom: 5px; 349 | } 350 | .leaflet-control-scale-line { 351 | border: 2px solid #777; 352 | border-top: none; 353 | line-height: 1.1; 354 | padding: 2px 5px 1px; 355 | font-size: 11px; 356 | white-space: nowrap; 357 | overflow: hidden; 358 | -moz-box-sizing: content-box; 359 | box-sizing: content-box; 360 | 361 | background: #fff; 362 | background: rgba(255, 255, 255, 0.5); 363 | } 364 | .leaflet-control-scale-line:not(:first-child) { 365 | border-top: 2px solid #777; 366 | border-bottom: none; 367 | margin-top: -2px; 368 | } 369 | .leaflet-control-scale-line:not(:first-child):not(:last-child) { 370 | border-bottom: 2px solid #777; 371 | } 372 | 373 | .leaflet-touch .leaflet-control-attribution, 374 | .leaflet-touch .leaflet-control-layers, 375 | .leaflet-touch .leaflet-bar { 376 | box-shadow: none; 377 | } 378 | .leaflet-touch .leaflet-control-layers, 379 | .leaflet-touch .leaflet-bar { 380 | border: 2px solid rgba(0,0,0,0.2); 381 | background-clip: padding-box; 382 | } 383 | 384 | 385 | /* popup */ 386 | 387 | .leaflet-popup { 388 | position: absolute; 389 | text-align: center; 390 | } 391 | .leaflet-popup-content-wrapper { 392 | padding: 1px; 393 | text-align: left; 394 | border-radius: 12px; 395 | } 396 | .leaflet-popup-content { 397 | margin: 13px 19px; 398 | line-height: 1.4; 399 | } 400 | .leaflet-popup-content p { 401 | margin: 18px 0; 402 | } 403 | .leaflet-popup-tip-container { 404 | margin: 0 auto; 405 | width: 40px; 406 | height: 20px; 407 | position: relative; 408 | overflow: hidden; 409 | } 410 | .leaflet-popup-tip { 411 | width: 17px; 412 | height: 17px; 413 | padding: 1px; 414 | 415 | margin: -10px auto 0; 416 | 417 | -webkit-transform: rotate(45deg); 418 | -moz-transform: rotate(45deg); 419 | -ms-transform: rotate(45deg); 420 | -o-transform: rotate(45deg); 421 | transform: rotate(45deg); 422 | } 423 | .leaflet-popup-content-wrapper, 424 | .leaflet-popup-tip { 425 | background: white; 426 | 427 | box-shadow: 0 3px 14px rgba(0,0,0,0.4); 428 | } 429 | .leaflet-container a.leaflet-popup-close-button { 430 | position: absolute; 431 | top: 0; 432 | right: 0; 433 | padding: 4px 4px 0 0; 434 | text-align: center; 435 | width: 18px; 436 | height: 14px; 437 | font: 16px/14px Tahoma, Verdana, sans-serif; 438 | color: #c3c3c3; 439 | text-decoration: none; 440 | font-weight: bold; 441 | background: transparent; 442 | } 443 | .leaflet-container a.leaflet-popup-close-button:hover { 444 | color: #999; 445 | } 446 | .leaflet-popup-scrolled { 447 | overflow: auto; 448 | border-bottom: 1px solid #ddd; 449 | border-top: 1px solid #ddd; 450 | } 451 | 452 | .leaflet-oldie .leaflet-popup-content-wrapper { 453 | zoom: 1; 454 | } 455 | .leaflet-oldie .leaflet-popup-tip { 456 | width: 24px; 457 | margin: 0 auto; 458 | 459 | -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; 460 | filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); 461 | } 462 | .leaflet-oldie .leaflet-popup-tip-container { 463 | margin-top: -1px; 464 | } 465 | 466 | .leaflet-oldie .leaflet-control-zoom, 467 | .leaflet-oldie .leaflet-control-layers, 468 | .leaflet-oldie .leaflet-popup-content-wrapper, 469 | .leaflet-oldie .leaflet-popup-tip { 470 | border: 1px solid #999; 471 | } 472 | 473 | 474 | /* div icon */ 475 | 476 | .leaflet-div-icon { 477 | background: #fff; 478 | border: 1px solid #666; 479 | } 480 | .prunecluster { 481 | font-size: 12px; 482 | border-radius: 20px; 483 | transition: all 0.3s linear; 484 | } 485 | .leaflet-marker-icon.prunecluster-anim, 486 | .leaflet-marker-shadow.prunecluster-anim, 487 | .leaflet-markercluster-icon.prunecluster-anim { 488 | transition: all 0.3s linear; 489 | } 490 | 491 | .leaflet-zoom-anim .leaflet-zoom-animated.leaflet-marker-icon, 492 | .leaflet-zoom-anim .leaflet-zoom-animated.leaflet-marker-shadow, 493 | .leaflet-zoom-anim .leaflet-zoom-animated.leaflet-markercluster-icon { 494 | transition: transform 0.25s cubic-bezier(0,0,0.25,1); 495 | } 496 | .prunecluster div { 497 | width: 30px; 498 | height: 30px; 499 | text-align: center; 500 | margin-left: 5px; 501 | margin-top: 5px; 502 | border-radius: 50%; 503 | } 504 | .prunecluster div span { 505 | line-height: 30px; 506 | } 507 | 508 | .prunecluster-small { 509 | background-color: #b5e28c; 510 | background-color: rgba(181, 226, 140, 0.6); 511 | background-color: rgba(255, 255, 51, 0.6); 512 | } 513 | 514 | .prunecluster-small div { 515 | width: 28px; 516 | height: 28px; 517 | background-color: #6ecc39; 518 | background-color: rgba(110, 204, 57, 0.6); 519 | background-color: rgba(255, 255, 51, 0.6); 520 | } 521 | 522 | .prunecluster-small div span { 523 | line-height: 28px; 524 | } 525 | 526 | .prunecluster-medium { 527 | background-color: #f1d357; 528 | background-color: rgba(241, 211, 87, 0.6); 529 | background-color: rgba(255, 204, 51, 0.6); 530 | } 531 | 532 | .prunecluster-medium div { 533 | background-color: #f0c20c; 534 | background-color: rgba(240, 194, 12, 0.6); 535 | background-color: rgba(255, 204, 51, 0.6); 536 | } 537 | 538 | .prunecluster-large { 539 | background-color: #fd9c73; 540 | background-color: rgba(253, 156, 115, 0.6); 541 | background-color: rgba(255, 153, 51, 0.6); 542 | } 543 | 544 | .prunecluster-large div { 545 | width: 34px; 546 | height: 34px; 547 | background-color: #f18017; 548 | background-color: rgba(241, 128, 23, 0.6); 549 | background-color: rgba(255, 153, 51, 0.6); 550 | } 551 | 552 | .prunecluster-large div span { 553 | line-height: 34px; 554 | } 555 | a,a:link{color:#455473;cursor:pointer}body{margin:0;font-family:'PT Sans',sans-serif;background:#1F3050}#map-tiles .leaflet-popup,p{font-family:'Open Sans',sans-serif}p{font-size:16px}li{list-style-type:none}h1,h2,h3,h4,h5,h6{text-align:center}#map-tiles{height:100vh;position:absolute;top:0;bottom:0;right:0;left:260px}#map-tiles .leaflet-popup{text-align:left!important}#map-tiles .leaflet-popup .leaflet-popup-close-button{font-size:23px;width:35px;height:35px;padding:8px 0 0;vertical-align:center}#map-tiles .leaflet-popup .leaflet-popup-close-button:hover{background:#c3c3c3}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper{border-radius:0;padding:0 2px 0 0;margin:0;max-width:300px;max-height:90vh;overflow-x:hidden;overflow-y:auto}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content{padding-bottom:15px;margin:0}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content h1{text-align:left;padding:15px 30px 15px 15px;border-bottom:1px solid #eee;margin-bottom:15px;margin-top:0;color:#1f3050;font-weight:700;font-size:16px}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content p{font-size:12px;text-align:left;padding:5px 15px;margin:0}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content p img{display:block;margin:auto;width:100%;max-width:270px}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content p a{text-align:left!important;color:#1F3050}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content p span.wp{display:block}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content p span.osm{font-style:italic}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content p img.wp{height:1.5em;width:1.5em;display:inline;margin-bottom:-.35em}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content table{font-size:12px;text-align:left;padding:5px 15px;margin:0;width:100%}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content table td+td{text-align:right}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content p.contact{line-height:2em}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content p.contact img{width:16px;margin-bottom:-4px;margin-right:6px;display:inline}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content h3{margin:0;padding:5px 15px 0;text-align:left;font-size:12px;font-weight:700}#map-tiles .my-div-icon{width:25px!important;height:40px;background-image:url(../../bower_components/leaflet/dist/images/marker-green.png);margin-top:-40px}#map-tiles .my-div-icon div{display:none}#map-tiles .my-div-icon:hover>div{display:block;width:200px;z-index:15000;margin-left:-85px;position:absolute;bottom:35px}#map-tiles .my-div-icon:hover>div div{display:block;margin:0 auto;background:rgba(255,255,255,.8);text-align:center;width:fit-content;border:1px solid #1F3050;border-radius:5px;padding:5px 8px}#map-tiles .leaflet-control-layers-toggle{width:26px;height:26px;background-size:22px 22px}#map-tiles #forkme{position:absolute;bottom:14px;left:-70px;display:block;width:300px;height:33px;transform:rotate(45deg);overflow:hidden}#map-menu-container ul#map-menu .list-group-item form.expert_mode.off,#showfilters{display:none}#map-tiles #forkme:hover{opacity:.8}#map-tiles #forkme img{margin-top:-85px;margin-left:40px;transform:rotate(-45deg)}#map-tiles.leaflet-touch .leaflet-control-layers-toggle{width:30px;height:30px;background-size:26px 26px}#showfilters{position:absolute;top:50px;left:10px;border-radius:4px;width:26px;height:26px;background:url(../../assets/icon-filter-24.png) 50% 50% no-repeat #fff;box-shadow:0 1px 5px rgba(0,0,0,.65);cursor:pointer}#map-menu-container{height:100vh;overflow:auto;width:260px;background:#95D5D2;font-size:.8em;font-weight:700;letter-spacing:.075em}#map-menu-container ul#map-menu{padding:0;margin:0;border:none}#map-menu-container ul#map-menu .list-group-item{padding:0;background:#95D5D2;color:#fff;border:none;border-radius:none}#map-menu-container ul#map-menu .list-group-item form.expert_mode.on{display:block;float:right;margin-right:3px;margin-left:6px;font-style:normal;color:#000}#map-menu-container ul#map-menu li.list-group-item.category{border-left:0;border-right:0;border-radius:0;border-bottom:1px solid #aaa}#map-menu-container ul#map-menu li.list-group-item.category ul.subcategories{background:#1F3050}#map-menu-container ul#map-menu li.list-group-item.category:first-child{border-top:1px solid #aaa}#map-menu-container ul#map-menu span.toggle{padding:5px 0 5px 10px;display:block;height:100%;cursor:pointer}#map-menu-container #activefilters .expert_mode.off,#map-menu-container ul#map-menu .category ul{display:none}#map-menu-container ul#map-menu span.toggle.selected{background:#1F3050;font-style:italic}#map-menu-container ul#map-menu .toggle-subcategories{padding-left:20px}#map-menu-container ul#map-menu ul.subcategories{padding-left:10px}#map-menu-container ul#map-menu ul.subcategories li.list-group-item:last-child{border-bottom:0}#map-menu-container ul#map-menu ul.type-of-initiative{font-weight:400;letter-spacing:normal;text-align:left;display:none;background:#fcec74;position:fixed;left:260px;top:0;z-index:10;-webkit-padding-start:0;padding:0 15px;border-top-right-radius:5px;border-bottom-right-radius:5px}#map-menu-container ul#map-menu ul.type-of-initiative .list-group-item{background:#fcec74;padding:5px 0 5px 10px;color:#000;border-top:1px solid #fff}#map-menu-container ul#map-menu ul.type-of-initiative .list-group-item:hover{cursor:pointer}#map-menu-container ul#map-menu ul.type-of-initiative .list-group-item:first-child{border-top:0}#map-menu-container ul#map-menu ul.type-of-initiative .list-group-item.selected{background:#F2BD0B;font-style:italic}#map-menu-container ul#map-menu ul.type-of-initiative .list-group-item.empty{color:gray}#map-menu-container #activefilters{clear:both;padding:0 0 0 10px;color:#fff}#map-menu-container #activefilters h2{text-align:left}#map-menu-container #activefilters ul{font-weight:400;padding:0;margin:0}#map-menu-container #activefilters ul li{border-radius:5px;padding:3px 22px 3px 5px;margin:5px 5px 5px 0;background:#F2BD0B;color:#000}#map-menu-container #activefilters ul li .close{font-weight:700;background:#fcec74;text-align:center;display:block;padding:3px;margin-top:-3px;margin-right:-22px;border-top-right-radius:5px;border-bottom-right-radius:5px;height:100%;width:12px;float:right;border-left:1px solid #fcec74}#map-menu-container #activefilters ul li .close:hover{background:#F2BD0B;cursor:pointer}#map-menu-container div#languageSelector,#map-menu-container div#mobileShowMap>div,#map-menu-container div#resetfilters,#map-menu-container div#searchFilterWrapper,#map-menu-container div#toggleAdvancedFilters{width:fit-content;color:#fff;padding:5px;margin:5px 10px;border:1px solid #fff;cursor:pointer}#map-menu-container div#mobileShowMap,#map-menu-container div#resetfilters{display:none}#map-menu-container div#searchFilterWrapper{float:left}#map-menu-container div#searchFilterWrapper input{padding:3px;float:left;width:116px;margin-right:5px}#map-menu-container div#searchFilterWrapper button{padding:3px;float:right}#map-menu-container div#languageSelector ul{float:right;margin:0 0 0 5px;padding:0}#map-menu-container div#languageSelector ul li{display:none;background:#95D5D2}#map-menu-container div#languageSelector ul li.default{display:block}#map-menu-container div#languageSelector ul.open{margin-top:-5px;margin-right:-6px}#map-menu-container div#languageSelector ul.open li{display:block;border:1px solid #fff;border-top:0;padding:5px}#map-menu-container div#languageSelector ul.open li:hover{color:#000}#map-menu-container div#languageSelector ul.open li.default{background:#1F3050;font-style:italic}#map-menu-container div#susyci{color:#fff;padding:.5em}#map-menu-container div#susyci .logo{text-align:center;margin:1em 0}#map-menu-container div#susyci .logo img{width:80%}#map-menu-container div#susyci .logo a{color:#fff}@media screen and (max-width:640px){#map-menu-container{position:absolute;top:0;left:0;width:100%}#map-menu-container ul#map-menu ul.type-of-initiative{margin-left:10px;padding:0;position:static;border-radius:0}#map-menu-container div#mobileShowMap{display:block;width:100%;height:1em;padding:6px 0 21px}#map-menu-container div#mobileShowMap div{float:right;margin:0 10px}#map-tiles .leaflet-popup-pane{bottom:0;right:0}#map-tiles{left:0}#showfilters{display:block}.leaflet-top{top:40px}} -------------------------------------------------------------------------------- /editable.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | TransforMap-Viewer (Edit) 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 33 | 34 | 35 | 36 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 75 | 76 | 182 | 183 |
184 |
185 |
    186 |
187 |
188 |
189 |
190 | 191 |
192 | 193 |
194 |
195 |
196 |
197 |
198 |
199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | -------------------------------------------------------------------------------- /iframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Transformap viewer included via iframe:

4 | 5 |

foo bar

6 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | TransforMap-Viewer 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 33 | 34 | 35 | 36 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 75 | 76 | 186 | 187 |
188 |
189 |
    190 |
191 |
192 |
193 |
194 | 195 |
196 | 197 |
198 |
199 |
200 |
201 |
202 |
203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /localisation-notes.md: -------------------------------------------------------------------------------- 1 | What needs to be translated: 2 | Filter Menu 3 | (later): Informational Texts about each Category/Type of Initiative 4 | Random Strings (headings, like e.g. "Address" in the popups) 5 | If it is a common thing, use Wikidata? 6 | fall back to Weblate? 7 | 8 | In the Popup: -OK 9 | description of initiative in different language 10 | 11 | Weblate 12 | can be used with Github directly 13 | its ssh-key must be added (to repo?) 14 | (and user configured? 15 | github host key in Weblate -OK and checked 16 | create project -OK 17 | creating component 18 | Failed to fetch repository: Could not create directory '/home/weblate/.ssh 19 | 20 | difference bilingual/monolingual? 21 | only monolingual supported with JSON 22 | 23 | format 24 | 25 | filename called json/$LANGCODE.json, e.g. de.json 26 | content: 27 | { 28 | "English Text %d" : "Deutscher Text", 29 | "stuff" : "" 30 | } 31 | 32 | 33 | We need a language switcher -OK 34 | that is set first on 35 | the user's preferred language 36 | can be set manually to any lang 37 | which langs do we support? 38 | should be generated out of 39 | https://base.transformap.co/wiki/Special:EntityData/Q5.json .entities.P5.labels.$keys 40 | 41 | design: flag symbol, 42 | on hover open sidewards to display language string 43 | on click open downwards to choose lang from ... how many? 44 | mobile: open full-screen 45 | 46 | Flag symbol: 47 | get "en" -> Wikidata -> get country -> get flag? 48 | is P31 of Q34770 (Einzelsprache) 49 | P218 is "de" 50 | gib mir P495 (ursprungsland) 51 | -> P41 (Flagge) 52 | 53 | wir wollen: Text und Link zur Flatte 54 | intermediate vars: 55 | Ursprungsland 56 | Sprachobjekt 57 | 58 | 1. query: 59 | return Ursprungsland of lang object with Lang Label 60 | 2. query 61 | return P41 of Ursprungsland 62 | ==> http://tinyurl.com/zvnb3tw 63 | -> funktionierte GENAU bei deutsch, da nur bei 3 Ursprungsland gesetzt ist und nur DE die Flagge gesetzt hat 64 | Wir können zumindest die Namen der Anderen Sprachen in Landessprache Anzeigen? 65 | bringt das was, wenn sich wer verklickt hat sieht er die anderen auch in Farsi? -> blöd 66 | Alle Labels in En? 67 | Besser: Alle Labels in ihrer eigenen Sprache! 68 | -> sind dann N queries? oder lassen sich die in eine tun... 69 | oder alle Labels in Englisch? 70 | 71 | Hm ... es wär blöd flaggen für Sprachen zu verwenden, die in mehreren Ländern gesprochen werden ... die sich Ev. nicht mögen. 72 | Und es gibt wohl keine offiziellen Flaggen pro Sprache 73 | -> garkeine Flaggen verwenden, nur die Namen! 74 | 75 | https://query.wikidata.org/bigdata/namespace/wdq/sparql?query=%23language%20and%20flags%0ASELECT%20%3Flang%20%3FlangLabel%20%3Fkuerzel%0AWHERE%0A%7B%0A%20%20%3Flang%20wdt%3AP218%20%3Fkuerzel%3B%0A%20%20FILTER%20regex%20(%3Fkuerzel%2C%20%22%5E(de%7Cfr%7Cen)%24%22).%0A%20%20%20%20%20%0A%20%20SERVICE%20wikibase%3Alabel%20%7B%20bd%3AserviceParam%20wikibase%3Alanguage%20%22en%22.%20%7D%0A%7D%0AORDER%20BY%20%3Flang 76 | 77 | 78 | We have fallback languages -OK 79 | e.g. de_AT -> de -> en (en is always last) 80 | 81 | Put such option in a menu for mobile (=) ? 82 | or disable althogether? 83 | 84 | 85 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "transformap-viewer", 3 | "version": "0.0.0", 4 | "description": "This is a Web-Map plugin that aims at displaying data from the [TransforMap API](https://github.com/TransforMap/data.transformap.co). It offers dynamic filters, which are built from a Wikibase graph hosted on [base.transformap.co](https://base.transformap.co).", 5 | "dependencies": {}, 6 | "devDependencies": { 7 | "uglifyjs": "^2.4.10" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "build": "npm run build-js && npm run build-css", 12 | "build-css": "cat bower_components/leaflet/dist/leaflet.css bower_components/PruneCluster/dist/LeafletStyleSheet.css styles/css/style.css > dist/site.css", 13 | "build-js": "uglifyjs bower_components/leaflet/dist/leaflet.js scripts/leaflet-hash.js scripts/red_fetch.js bower_components/PruneCluster/dist/PruneCluster.min.js scripts/map.js > dist/site.js" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/TransforMap/transformap-viewer.git" 18 | }, 19 | "author": "", 20 | "bugs": { 21 | "url": "https://github.com/TransforMap/transformap-viewer/issues" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /scripts/leaflet-hash.js: -------------------------------------------------------------------------------- 1 | /* taken from https://github.com/mlevans/leaflet-hash, MIT License, see link */ 2 | 3 | (function(window) { 4 | var HAS_HASHCHANGE = (function() { 5 | var doc_mode = window.documentMode; 6 | return ('onhashchange' in window) && 7 | (doc_mode === undefined || doc_mode > 7); 8 | })(); 9 | 10 | L.Hash = function(map) { 11 | this.onHashChange = L.Util.bind(this.onHashChange, this); 12 | 13 | if (map) { 14 | this.init(map); 15 | } 16 | }; 17 | 18 | L.Hash.parseHash = function(hash) { 19 | if(hash.indexOf('#') === 0) { 20 | hash = hash.substr(1); 21 | } 22 | var args = hash.split("/"); 23 | if (args.length == 3) { 24 | var zoom = parseInt(args[0], 10), 25 | lat = parseFloat(args[1]), 26 | lon = parseFloat(args[2]); 27 | if (isNaN(zoom) || isNaN(lat) || isNaN(lon)) { 28 | return false; 29 | } else { 30 | return { 31 | center: new L.LatLng(lat, lon), 32 | zoom: zoom 33 | }; 34 | } 35 | } else { 36 | return false; 37 | } 38 | }; 39 | 40 | L.Hash.formatHash = function(map) { 41 | var center = map.getCenter(), 42 | zoom = map.getZoom(), 43 | precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2)); 44 | 45 | return "#" + [zoom, 46 | center.lat.toFixed(precision), 47 | center.lng.toFixed(precision) 48 | ].join("/"); 49 | }, 50 | 51 | L.Hash.prototype = { 52 | map: null, 53 | lastHash: null, 54 | 55 | parseHash: L.Hash.parseHash, 56 | formatHash: L.Hash.formatHash, 57 | 58 | init: function(map) { 59 | this.map = map; 60 | 61 | // reset the hash 62 | this.lastHash = null; 63 | this.onHashChange(); 64 | 65 | if (!this.isListening) { 66 | this.startListening(); 67 | } 68 | }, 69 | 70 | removeFrom: function(map) { 71 | if (this.changeTimeout) { 72 | clearTimeout(this.changeTimeout); 73 | } 74 | 75 | if (this.isListening) { 76 | this.stopListening(); 77 | } 78 | 79 | this.map = null; 80 | }, 81 | 82 | onMapMove: function() { 83 | // bail if we're moving the map (updating from a hash), 84 | // or if the map is not yet loaded 85 | 86 | if (this.movingMap || !this.map._loaded) { 87 | return false; 88 | } 89 | 90 | var hash = this.formatHash(this.map); 91 | if (this.lastHash != hash) { 92 | location.replace(hash); 93 | this.lastHash = hash; 94 | } 95 | }, 96 | 97 | movingMap: false, 98 | update: function() { 99 | var hash = location.hash; 100 | if (hash === this.lastHash) { 101 | return; 102 | } 103 | var parsed = this.parseHash(hash); 104 | if (parsed) { 105 | this.movingMap = true; 106 | 107 | this.map.setView(parsed.center, parsed.zoom); 108 | 109 | this.movingMap = false; 110 | } else { 111 | this.onMapMove(this.map); 112 | } 113 | }, 114 | 115 | // defer hash change updates every 100ms 116 | changeDefer: 100, 117 | changeTimeout: null, 118 | onHashChange: function() { 119 | // throttle calls to update() so that they only happen every 120 | // `changeDefer` ms 121 | if (!this.changeTimeout) { 122 | var that = this; 123 | this.changeTimeout = setTimeout(function() { 124 | that.update(); 125 | that.changeTimeout = null; 126 | }, this.changeDefer); 127 | } 128 | }, 129 | 130 | isListening: false, 131 | hashChangeInterval: null, 132 | startListening: function() { 133 | this.map.on("moveend", this.onMapMove, this); 134 | 135 | if (HAS_HASHCHANGE) { 136 | L.DomEvent.addListener(window, "hashchange", this.onHashChange); 137 | } else { 138 | clearInterval(this.hashChangeInterval); 139 | this.hashChangeInterval = setInterval(this.onHashChange, 50); 140 | } 141 | this.isListening = true; 142 | }, 143 | 144 | stopListening: function() { 145 | this.map.off("moveend", this.onMapMove, this); 146 | 147 | if (HAS_HASHCHANGE) { 148 | L.DomEvent.removeListener(window, "hashchange", this.onHashChange); 149 | } else { 150 | clearInterval(this.hashChangeInterval); 151 | } 152 | this.isListening = false; 153 | } 154 | }; 155 | L.hash = function(map) { 156 | return new L.Hash(map); 157 | }; 158 | L.Map.prototype.addHash = function() { 159 | this._hash = L.hash(this); 160 | }; 161 | L.Map.prototype.removeHash = function() { 162 | this._hash.removeFrom(); 163 | }; 164 | })(window); 165 | -------------------------------------------------------------------------------- /scripts/map.js: -------------------------------------------------------------------------------- 1 | /* This program is free software. It comes without any warranty, to 2 | * the extent permitted by applicable law. You can redistribute it 3 | * and/or modify it under the terms of the Do What The Fuck You Want 4 | * To Public License, Version 2, as published by Sam Hocevar. See 5 | * http://www.wtfpl.net/ for more details. */ 6 | 7 | const endpoint = "https://data.transformap.co/place/"; 8 | var redundant_data_urls = [ endpoint + "name", "https://data.transformap.co/raw/5d6b9d3d32097fd6832200874402cfc3", "https://github.com/TransforMap/transformap-viewer/raw/gh-pages/susydata-fallback.json", "susydata-fallback.json" ]; 9 | 10 | /* fix for leaflet scroll on devices that fire scroll too fast, e.g. Macs 11 | see https://github.com/Leaflet/Leaflet/issues/4410#issuecomment-234133427 12 | 13 | */ 14 | 15 | var lastScroll = new Date().getTime(); 16 | L.Map.ScrollWheelZoom.prototype._onWheelScroll = function (e) { 17 | if (new Date().getTime() - lastScroll < 400) { 18 | e.preventDefault(); 19 | return; 20 | } 21 | var delta = L.DomEvent.getWheelDelta(e); 22 | var debounce = this._map.options.wheelDebounceTime; 23 | 24 | if (delta >= -0.15 && delta <= 0.15) { 25 | e.preventDefault(); 26 | return; 27 | } 28 | if (delta <= -0.25) delta = -0.25; 29 | if (delta >= 0.25) delta = 0.25; 30 | this._delta += delta; 31 | this._lastMousePos = this._map.mouseEventToContainerPoint(e); 32 | 33 | if (!this._startTime) { 34 | this._startTime = +new Date(); 35 | } 36 | 37 | var left = Math.max(debounce - (+new Date() - this._startTime), 0); 38 | 39 | clearTimeout(this._timer); 40 | lastScroll = new Date().getTime(); 41 | this._timer = setTimeout(L.bind(this._performZoom, this), left); 42 | 43 | L.DomEvent.stop(e); 44 | } 45 | 46 | function getUrlVars() { 47 | var vars = {}; 48 | var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) { 49 | vars[key] = value.replace(/#.*$/,''); 50 | }); 51 | return vars; 52 | } 53 | 54 | var map, 55 | center, 56 | zoom, 57 | defaultlayer, 58 | base_maps = {}, 59 | leaflet_bg_maps, 60 | pruneClusterLayer; 61 | function initMap() { 62 | var attr_osm = 'Map data by OpenStreetMap contributors, under ODbL. ', 63 | attr_pois = 'POIs by SUSY, CC-0. '; 64 | 65 | base_maps['mapnik'] = new L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { 66 | attribution: attr_osm + attr_pois, 67 | maxZoom : 19, 68 | noWrap: true 69 | }); 70 | base_maps['stamen_terrain'] = new L.tileLayer('https://stamen-tiles-{s}.a.ssl.fastly.net/terrain/{z}/{x}/{y}.png', { 71 | attribution: 'Map tiles by Stamen Design, '+ 72 | 'under CC BY 3.0. '+ 73 | attr_osm + attr_pois, 74 | maxZoom : 18, 75 | noWrap: true 76 | }); 77 | base_maps['stamen_terrain_bg'] = new L.tileLayer('https://stamen-tiles-{s}.a.ssl.fastly.net/terrain-background/{z}/{x}/{y}.png', { 78 | attribution: 'Map tiles by Stamen Design, '+ 79 | 'under CC BY 3.0. '+ 80 | attr_osm + attr_pois, 81 | maxZoom : 18, 82 | noWrap: true 83 | }); 84 | base_maps['hot'] = new L.tileLayer('http://tile-{s}.openstreetmap.fr/hot/{z}/{x}/{y}.png', { 85 | attribution: 'Tiles courtesy of Humanitarian OpenStreetMap Team. '+ 86 | attr_osm + attr_pois, 87 | maxZoom : 20, 88 | noWrap: true 89 | }); 90 | 91 | if(!leaflet_bg_maps) 92 | leaflet_bg_maps = { 93 | 'Stamen - Terrain': base_maps['stamen_terrain'], 94 | 'Stamen - Terrain Background': base_maps['stamen_terrain_bg'], 95 | 'OpenStreetMap - Mapnik': base_maps['mapnik'], 96 | 'Humanitarian OpenStreetMap ': base_maps['hot'] 97 | }; 98 | if(!defaultlayer) 99 | defaultlayer = base_maps['stamen_terrain_bg']; 100 | 101 | var urlparams = getUrlVars(); 102 | var user_bg = urlparams['background']; 103 | if(user_bg && base_maps[user_bg]) 104 | defaultlayer = base_maps[user_bg]; 105 | 106 | if(!center) 107 | center = new L.LatLng(51.1657, 10.4515); 108 | 109 | map = L.map('map-tiles', { 110 | zoomControl: false, 111 | center: center, 112 | zoom: zoom ? zoom : 5, 113 | layers: defaultlayer, 114 | }); 115 | 116 | new L.Control.Zoom({ position: 'topright' }).addTo(map); 117 | 118 | pruneClusterLayer = new PruneClusterForLeaflet(60,20); 119 | 120 | /* overwrite function to create popup on the fly */ 121 | pruneClusterLayer.PrepareLeafletMarker = function(leafletMarker, data) { 122 | leafletMarker.setIcon(data.icon); 123 | //listeners can be applied to markers in this function 124 | leafletMarker.on('click', function(e){ 125 | // bind popup and open immediately 126 | if (!leafletMarker.getPopup()) { 127 | leafletMarker.bindPopup(data.popup(data)); 128 | leafletMarker.openPopup(); 129 | } 130 | }); 131 | }; 132 | 133 | map.addLayer(pruneClusterLayer); 134 | 135 | var ctrl = new L.Control.Layers(leaflet_bg_maps); 136 | map.addControl(ctrl); 137 | 138 | var hash = new L.Hash(map); // Leaflet persistent Url Hash function 139 | 140 | $('#map-tiles').append('Fork me on GitHub'); 141 | 142 | var topContainer = $("#map-menu-container .top"); 143 | 144 | topContainer.prepend( 145 | "
"+T("show_map")+"
" 146 | ); 147 | 148 | topContainer.append( 149 | "
"+T("reset_filters")+"
" 150 | ); 151 | 152 | topContainer.append( 153 | "
"+T("en_adv_filters")+"
" 154 | ); 155 | 156 | var searchElements = []; 157 | searchElements.push("
"); 158 | searchElements.push(""); 159 | searchElements.push(""); 160 | searchElements.push("
"); 161 | topContainer.append(searchElements.join('')); 162 | 163 | topContainer.append( 164 | "
" + 165 | "

" + T("active_filters") + "

" + 166 | "
    " + 167 | "
    " 168 | ); 169 | 170 | console.log("START mapjs"); 171 | } 172 | 173 | var osm_enabled_pois = []; 174 | function addPOIsToMap(geoJSONfeatureCollection) { 175 | if(geoJSONfeatureCollection.type != "FeatureCollection") { 176 | console.error("not a featureCollection"); 177 | return false; 178 | } 179 | 180 | var op_servers = [ 'https://overpass-api.de/api/', 'http://api.openstreetmap.fr/oapi/', 'http://overpass.osm.rambler.ru/cgi/' ]; 181 | var osm_query_string = "interpreter?data=[out:json][timeout:180];"; 182 | 183 | var POIcollection = geoJSONfeatureCollection.features; 184 | for(var i=0; i < POIcollection.length; i++) { 185 | var feature = POIcollection[i]; 186 | 187 | var livePopup = function(data) { // gets popup content for a marker 188 | var templatePopUpFunction = _.template($('#popUpTemplate').html()); 189 | return templatePopUpFunction(data); 190 | } 191 | 192 | var createdDate = new Date(feature.properties._created) 193 | var created = createdDate.toLocaleDateString() 194 | 195 | var timestampDate = new Date(feature.properties._timestamp) 196 | var timestamp = timestampDate.toLocaleDateString() 197 | 198 | var pdata = { 199 | icon: new L.divIcon({ 200 | className: 'my-div-icon', 201 | iconSize:30, 202 | html:"
    " + feature.properties.name + "
    " 203 | }), 204 | popup: livePopup, 205 | created: created, 206 | modified: timestamp, 207 | tags: feature.properties, 208 | properties: feature.properties // is used by _ template 209 | } 210 | if(feature.properties['osm']) { 211 | var match = feature.properties['osm'].match(/(node|way|relation)\/?([0-9]+)$/); 212 | if(match) { 213 | console.log("found osm on " + feature.properties.name + ": " + feature.properties['osm']); 214 | osm_query_string += match[1] + "(" + match[2] + ");out;"; 215 | } 216 | osm_enabled_pois.push(feature); 217 | } 218 | 219 | var pmarker = new PruneCluster.Marker(feature.geometry.coordinates[1], feature.geometry.coordinates[0], pdata); 220 | pruneClusterLayer.RegisterMarker(pmarker); 221 | } 222 | 223 | if(osm_query_string.length > 42) { 224 | osm_query_string += "out;" 225 | console.log(osm_query_string); 226 | redundantFetch([ op_servers[0] + osm_query_string, op_servers[1] + osm_query_string, op_servers[2] + osm_query_string ], parseOverpassData, function(error) { console.error("no overpass server responded"); }, { cacheBusting : false } ); 227 | } 228 | 229 | pruneClusterLayer.ProcessView(); 230 | return true; 231 | } 232 | 233 | redundantFetch( redundant_data_urls ,addPOIsToMap, function(error) { console.error("none of the POI data urls available"); } ); 234 | 235 | /* OSM workflow: 236 | fetch data from Overpass API 237 | parse returned data 238 | add osm-properties to POIcollection 239 | as all data is by reference, pdata.properties should get updated? 240 | */ 241 | 242 | function parseOverpassData(overpassJSON) { 243 | console.log("parseOverpassData called"); 244 | if(!overpassJSON.elements) { 245 | console.error("parseOverpassData: data invalid"); 246 | return 247 | } 248 | for(var i = 0; i < overpassJSON.elements.length; i++) { 249 | var p = overpassJSON.elements[i]; 250 | 251 | var type = p.type; 252 | var id = p.id; 253 | 254 | for(var osm_count = 0; osm_count < osm_enabled_pois.length; osm_count++) { 255 | var tm_poi = osm_enabled_pois[osm_count]; 256 | var osmlink = tm_poi.properties['osm']; 257 | var match = osmlink.match(/(node|way|relation)\/?([0-9]+)/); 258 | if(match && match[1] == p.type && match[2] == p.id) { 259 | console.log("found match between " + match[1] + match[2] + " and tm:" + tm_poi.properties['name'] ); 260 | for(key in p.tags) { 261 | if(!tm_poi.properties[key]) { 262 | tm_poi.properties[key] = p.tags[key]; 263 | tm_poi.properties[key + "_source"] = "osm"; 264 | } 265 | } 266 | } 267 | } 268 | } 269 | } 270 | 271 | /* get taxonomy stuff */ 272 | var taxonomy_url = "http://viewer.transformap.co/taxonomy.json"; 273 | var taxonomy_url = "taxonomy.de.json"; 274 | 275 | var multilang_taxonomies = {}; 276 | 277 | //current ones 278 | var flat_taxonomy_array, 279 | tree_menu_json; 280 | 281 | function setTaxonomy(rdf_data) { 282 | console.log("setTaxonomy called, data:") 283 | console.log(rdf_data); 284 | 285 | flat_taxonomy_array = rdf_data.results.bindings; 286 | 287 | fill_tax_hashtable(); 288 | tree_menu_json = convertFlattaxToTree(); 289 | 290 | buildTreeMenu(tree_menu_json); 291 | } 292 | 293 | function getLangTaxURL(lang) { 294 | if(!lang) { 295 | console.error("getLangTaxURL: no lang given"); 296 | return false; 297 | } 298 | 299 | var tax_query = 300 | 'prefix bd: ' + 301 | 'prefix wikibase: ' + 302 | 'prefix wdt: ' + 303 | 'prefix wd: ' + 304 | 'SELECT ?item ?itemLabel ?instance_of ?subclass_of ?type_of_initiative_tag ?wikipedia ?description ' + 305 | 'WHERE {' + 306 | '?item wdt:P8* wd:Q8 .' + 307 | '?item wdt:P8 ?subclass_of .' + 308 | 'OPTIONAL { ?item wdt:P4 ?instance_of . }' + 309 | 'OPTIONAL { ?item wdt:P15 ?type_of_initiative_tag }' + 310 | 'OPTIONAL { ?item schema:description ?description FILTER(LANG(?description) = "'+lang+'") }' + 311 | 'OPTIONAL { ?wikipedia schema:about ?item . ?wikipedia schema:inLanguage "en"}' + 312 | 'SERVICE wikibase:label {bd:serviceParam wikibase:language "'+lang+'" }' + 313 | '}'; 314 | 315 | return 'https://query.base.transformap.co/bigdata/namespace/transformap/sparql?query=' +encodeURIComponent(tax_query) + "&format=json"; // server not CORS ready yet 316 | } 317 | 318 | function setFilterLang(lang) { 319 | if(!lang) { 320 | console.error("setFilterLang: no lang given"); 321 | return false; 322 | } 323 | console.log('setFilterLang: ' + lang); 324 | 325 | if(multilang_taxonomies[lang]) { 326 | setTaxonomy(multilang_taxonomies[lang]); 327 | } else { 328 | redundantFetch( [ getLangTaxURL(lang), "https://raw.githubusercontent.com/TransforMap/transformap-viewer-translations/master/taxonomy-backup/susy/taxonomy."+lang+".json" ], 329 | applyOrAddTaxonomyLang, 330 | function(error) { console.error("none of the taxonomy data urls available") }, 331 | { cacheBusting: false } 332 | ); 333 | } 334 | } 335 | 336 | function applyOrAddTaxonomyLang(returned_data) { 337 | console.log("callback for tax called"); 338 | console.log(returned_data); 339 | var lang = returned_data.results.bindings[0].itemLabel["xml:lang"]; 340 | console.log("found lang: " + lang); 341 | multilang_taxonomies[lang] = returned_data; 342 | 343 | if(multilang_taxonomies[current_lang]) 344 | setTaxonomy(multilang_taxonomies[current_lang]); 345 | else { 346 | for(var i=0; i < fallback_langs.length; i++) { 347 | var fb_tax = multilang_taxonomies[fallback_langs[i]]; 348 | if(fb_tax) { 349 | setTaxonomy(fb_tax); 350 | return; 351 | } 352 | } 353 | console.error("applyOrAddTaxonomyLang: no taxonomy in any of the user's langs available"); 354 | } 355 | } 356 | 357 | // note: can only handle 3 tiers (cats, subcats, toi) at the moment. 358 | function convertFlattaxToTree() { 359 | console.log("convertFlattaxToTree called"); 360 | var treejson = { 361 | "xml:lang": "en", 362 | "elements": [] 363 | }; 364 | 365 | var cats_that_hold_type_of_initiatives = []; 366 | 367 | // get all 'childs' for this root (main categories) 368 | for( i in tax_hashtable.cat_qindex) { 369 | var entry = tax_hashtable.cat_qindex[i]; 370 | if(entry["subclass_of"]) { 371 | if(getQNR(entry["subclass_of"].value) == tax_hashtable.root_qnr) { 372 | treejson.elements.push( 373 | { 374 | "type": "category", 375 | "UUID": entry.item.value, 376 | "itemLabel": entry.itemLabel.value, 377 | "description": entry.description ? entry.description.value : "", 378 | "wikipedia": entry.wikipedia ? entry.wikipedia.value : "", 379 | "elements" : [] 380 | } 381 | ); 382 | } 383 | } 384 | } 385 | 386 | // get all child categories for the main categories 387 | treejson.elements.forEach(function(category_item){ //iterate over categories to attach subcats 388 | 389 | var uuid_of_category = category_item.UUID; 390 | //console.log(uuid_of_category); 391 | 392 | for( i in tax_hashtable.cat_qindex) { 393 | var entry = tax_hashtable.cat_qindex[i]; 394 | 395 | if(entry["subclass_of"]) { 396 | if(-1 < $.inArray( uuid_of_category, entry["subclass_of"].value.split(";") ) ) { 397 | //console.log("add subcat " + entry.itemLabel.value + " to category " + category_item.itemLabel ); 398 | var new_subcat = 399 | { 400 | "type": "subcategory", 401 | "UUID": entry.item.value, 402 | "itemLabel": entry.itemLabel.value, 403 | "description": entry.description ? entry.description.value : "", 404 | "wikipedia": entry.wikipedia ? entry.wikipedia.value : "", 405 | "elements" : [] 406 | } 407 | category_item.elements.push(new_subcat); 408 | cats_that_hold_type_of_initiatives.push(new_subcat); 409 | } 410 | } 411 | } 412 | 413 | if(category_item.elements.length == 0) { 414 | cats_that_hold_type_of_initiatives.push(category_item); 415 | } 416 | }); 417 | 418 | // get all type of initiatives and hang them to their parent category 419 | // remember: objects are called by reference, so this updates the whole treejson structure! 420 | for( i in tax_hashtable.toi_qindex) { 421 | var flat_type_of_initiative = tax_hashtable.toi_qindex[i]; 422 | 423 | var parent_uuids = flat_type_of_initiative.subclass_of.value.split(";"); 424 | 425 | parent_uuids.forEach(function(single_toi_uuid) { //they may be subclass of more than one cat 426 | cats_that_hold_type_of_initiatives.forEach(function(cat){ 427 | if(cat.UUID == single_toi_uuid) { 428 | var type_of_initiative = 429 | { 430 | "type": "type_of_initiative", 431 | "UUID": flat_type_of_initiative.item.value, 432 | "itemLabel": flat_type_of_initiative.itemLabel.value, 433 | "description": flat_type_of_initiative.description ? flat_type_of_initiative.description.value : "", 434 | "wikipedia": flat_type_of_initiative.wikipedia ? flat_type_of_initiative.wikipedia.value : "", 435 | "type_of_initiative_tag": flat_type_of_initiative.type_of_initiative_tag.value 436 | } 437 | cat.elements.push(type_of_initiative); 438 | } 439 | }); 440 | }); 441 | }; 442 | 443 | function itemLabelCompare(a,b){ 444 | // 'Others' cat should get sorted last 445 | if(getQNR(a.UUID) == "Q20") return 1; 446 | if(getQNR(b.UUID) == "Q20") return -1; 447 | 448 | //in toi list, 'other*' should be last 449 | if(a.type_of_initiative_tag && a.type_of_initiative_tag.match(/^other_/)) return 1; 450 | if(b.type_of_initiative_tag && b.type_of_initiative_tag.match(/^other_/)) return -1; 451 | 452 | if(a.itemLabel < b.itemLabel) 453 | return -1 454 | else 455 | return 1 456 | } 457 | 458 | //category sort 459 | treejson.elements.sort(itemLabelCompare); 460 | 461 | //subcat sort 462 | treejson.elements.forEach(function(category) { 463 | if(category.elements && category.elements.length) { 464 | category.elements.sort(itemLabelCompare); 465 | category.elements.forEach(function(subcategory) { 466 | if(subcategory.elements && subcategory.elements.length) { 467 | subcategory.elements.sort(itemLabelCompare); 468 | } 469 | }); 470 | } 471 | }); 472 | 473 | console.log("treejson: "); 474 | console.log(treejson); 475 | return treejson; 476 | } 477 | 478 | function buildTreeMenu(tree_json) { 479 | 480 | function appendTypeOfInitiative(toi,parent_element) { 481 | var toi_data = 482 | { 483 | id: getQNR(toi.UUID), 484 | itemLabel: toi.itemLabel, 485 | description: toi.description, 486 | wikipedia: toi.wikipedia 487 | } 488 | parent_element.append( toiTemplate( toi_data ) ); 489 | } 490 | 491 | function appendCategory(cat, parent_element) { 492 | 493 | var cat_data = 494 | { 495 | id: getQNR(cat.UUID), 496 | itemLabel: cat.itemLabel, 497 | description: cat.description, 498 | wikipedia: cat.wikipedia 499 | } 500 | parent_element.append( catTemplate( cat_data ) ); 501 | 502 | if(cat.elements.length != 0) { 503 | cat.elements.forEach(function(entry) { 504 | if(entry.type == "subcategory") { 505 | appendCategory(entry, $('#map-menu .' + cat_data.id + ' > ul.subcategories')); 506 | } 507 | if(entry.type == "type_of_initiative") { 508 | appendTypeOfInitiative(entry, $('#map-menu .' + cat_data.id + ' > ul.type-of-initiative')); 509 | } 510 | }); 511 | } 512 | } 513 | 514 | var menu_root = $('#map-menu'); 515 | menu_root.empty(); 516 | 517 | var catTemplate = _.template($('#menuCategoryTemplate').html()); 518 | var toiTemplate = _.template($('#menuTypeOfInitiativeTemplate').html()); 519 | 520 | tree_json.elements.forEach(function(cat){ 521 | appendCategory(cat,menu_root); 522 | }); 523 | } 524 | 525 | var toi_count_out_of_date = 1; 526 | function updateToiEmptyStatusInFilterMenu () { 527 | if(! toi_count_out_of_date) 528 | return; 529 | 530 | var marker_array = pruneClusterLayer.GetMarkers(); 531 | for(var i = 0; i < marker_array.length; i++) { 532 | var marker = marker_array[i]; 533 | 534 | var toi_array = createToiArray(marker.data.tags.type_of_initiative); 535 | toi_array.forEach(function(e) { 536 | if(! tax_hashtable.toi_count[e]) { 537 | tax_hashtable.toi_count[e]=1; 538 | var qnr = tax_hashtable.toistr_to_qnr[e]; 539 | if(qnr) // only works lateron when menu is loaded 540 | $('#map-menu .' + qnr).removeClass('empty'); 541 | } else { 542 | tax_hashtable.toi_count[e]++ 543 | } 544 | }); 545 | } 546 | toi_count_out_of_date = 0; 547 | } 548 | 549 | function clickOnCat(id) { 550 | console.log("clickOnCat: "+ id); 551 | 552 | //if is already selected AND no sub-catd/tois are selected 553 | if($("#map-menu ." + id + " > span").hasClass("selected") 554 | && $("#map-menu ." + id + " ul .selected").length == 0) { 555 | if(onMobile()) 556 | switchToMap() 557 | return; 558 | } 559 | 560 | //close all other cats on the same level 561 | $("#map-menu ." + id).parent("ul").children("li").children("ul").hide(); 562 | $("#map-menu ul.type-of-initiative li.selected").removeClass("selected"); 563 | $("ul.type-of-initiative").hide(); 564 | 565 | //toggle "selected" on the current level 566 | $("#map-menu ." + id).parent("ul").children("li").children("span").removeClass("selected"); 567 | 568 | //remove all "selected" on all child levels 569 | $("#map-menu ." + id + " .selected").removeClass("selected"); 570 | 571 | $("#map-menu ." + id + " > span").addClass("selected"); 572 | 573 | $("#map-menu ." + id + " > ul").show(); 574 | 575 | if(getFilterMode() == "simple") { 576 | removeFromFilter("*"); 577 | addToFilter(id); 578 | trigger_Filter(); 579 | } 580 | 581 | updateToiEmptyStatusInFilterMenu(); // has internal check to only execute when needed 582 | } 583 | 584 | function clickOnInitiative(id) { 585 | console.log("clickOnInitiative: "+ id); 586 | if($("#map-menu ." + id).hasClass("selected")) { 587 | if(onMobile()) 588 | switchToMap() 589 | return; 590 | } 591 | 592 | if(getFilterMode() == "simple") { 593 | $("#map-menu ul.type-of-initiative li.selected").removeClass("selected"); 594 | $("#map-menu ." + id).addClass("selected"); 595 | removeFromFilter("*"); 596 | addToFilter(id); 597 | trigger_Filter(); 598 | } else { 599 | if( $("#activefilters ul ."+id).length == 0 ) { 600 | addToFilter(id) 601 | } else { 602 | removeFromFilter(id) 603 | } 604 | trigger_Filter(); 605 | } 606 | 607 | 608 | } 609 | 610 | /* 611 | * helper functions 612 | */ 613 | 614 | /* delete an object from an array. 615 | * Returns true if object found and deleted 616 | * only the first object is deleted 617 | */ 618 | Array.prototype.deleteInArray = function (deletion_canditate) { 619 | var position = this.indexOf(deletion_canditate); 620 | if(position > -1) { 621 | this.splice(position,1); 622 | return true; 623 | } else { 624 | return false; 625 | } 626 | } 627 | 628 | // returns "Q12" of https://base.transformap.co/entity/Q12#taxonomy 629 | function getQNR(uri_string) { 630 | if(typeof(uri_string) !== 'string') 631 | return false; 632 | var slashsplit_array = uri_string.split('/'); 633 | var after_last_slash = slashsplit_array[slashsplit_array.length -1]; 634 | var before_hash = after_last_slash.split('#')[0]; 635 | return before_hash; 636 | } 637 | 638 | /* 639 | * returns array of all tois (Q-Nrs) a cat or subcat has 640 | */ 641 | var tois_of_cat_cache = {}; 642 | function getTOIsOfCat(id) { 643 | if(tois_of_cat_cache[id]) 644 | return tois_of_cat_cache[id]; 645 | 646 | var array = []; 647 | 648 | //recursive function 649 | function dig_deeper_into_taxtree(array_position_object,do_output,id) { 650 | if(tois_of_cat_cache[id]) { 651 | array.push(tois_of_cat_cache[id]); 652 | return; 653 | } 654 | 655 | if(array_position_object.elements && array_position_object.elements.length) { //cat or root 656 | for(var i=0; i < array_position_object.elements.length; i++) { 657 | if(getQNR(array_position_object.elements[i].UUID) == id || do_output) { 658 | dig_deeper_into_taxtree(array_position_object.elements[i],true,id); 659 | } 660 | else { 661 | dig_deeper_into_taxtree(array_position_object.elements[i],false,id); 662 | } 663 | } 664 | } 665 | else if (array_position_object.type == "type_of_initiative") //toi 666 | if(do_output) { 667 | array.push(getQNR(array_position_object.UUID)); 668 | } 669 | } 670 | dig_deeper_into_taxtree(tree_menu_json,false,id); 671 | 672 | tois_of_cat_cache[id] = array; 673 | return array; 674 | } 675 | 676 | function createToiArray(toi_string) { 677 | if(typeof(toi_string) !== 'string') 678 | return []; 679 | var toi_array = toi_string.split(';'); 680 | for(var i=0;i span").removeClass("selected"); 799 | $("ul.type-of-initiative").hide(); 800 | $("ul.subcategories").hide(); 801 | $('#searchFilter').val(''); 802 | applySearchFilter(new MouseEvent('click') , ''); 803 | removeFromFilter("*"); 804 | trigger_Filter(); 805 | $("#activefilters ul").append("
  • "+T("clickanyfilterhint")+"
    ×
  • "); 806 | $('#resetfilters').hide(); 807 | } 808 | 809 | function getFilterMode() { 810 | return $("#toggleAdvancedFilters").attr('mode'); 811 | } 812 | 813 | function applySearchFilter(event, keyword) { 814 | event = event || window.event; 815 | current_filter_search = keyword; 816 | if (event.keyCode == 13 || event.type == 'click') { 817 | trigger_Filter(); 818 | } 819 | } 820 | 821 | function toggleAdvancedFilterMode() { 822 | resetFilter(); 823 | if(getFilterMode() == "simple") { 824 | $("#toggleAdvancedFilters").attr('mode',"advanced"); 825 | $("#toggleAdvancedFilters").text(T('dis_adv_filters')); 826 | $("#toggleAdvancedFilters").attr('trn',"dis_adv_filters"); 827 | 828 | $('.expert_mode').removeClass('off') 829 | .addClass('on'); 830 | } else { 831 | $("#toggleAdvancedFilters").attr('mode',"simple"); 832 | $("#toggleAdvancedFilters").text(T('en_adv_filters')); 833 | $("#toggleAdvancedFilters").attr('trn',"en_adv_filters"); 834 | 835 | $('.expert_mode').removeClass('on') 836 | .addClass('off'); 837 | } 838 | } 839 | 840 | function addToFilter(id) { 841 | $("#activefilters ul .hint").remove(); 842 | 843 | if(tax_hashtable.toi_qindex[id]) { // is a toi 844 | if($("#activefilters ul ."+id).length == 0) { // not already there 845 | current_filter_tois.push(id); 846 | var item = tax_hashtable.toi_qindex[id]; 847 | var name = item.itemLabel.value; 848 | $("#activefilters ul").append("
  • "+name+"
    ×
  • "); 849 | 850 | $("#map-menu li."+id+" form.expert_mode input").each(function(){ this.checked = true; }); 851 | 852 | //for parent cats, checked state 853 | //recursive! 854 | function checkStateOfParents(parents_string) { 855 | var parent_cats = parents_string.split(";"); 856 | parent_cats.forEach(function (parent_cat) { 857 | var parent_qnr = getQNR(parent_cat); 858 | 859 | //[-] has to be active, as we just added an item... 860 | $("#map-menu li."+parent_qnr+" > span.toggle > span.expert_mode .remove").removeClass("inactive"); 861 | 862 | //if all sub-items are in filter list, we can set the 'full' checked state 863 | var siblings = getTOIsOfCat(parent_qnr); 864 | var a_toi_missing = false; 865 | for(var i=0; i < siblings.length; i++) { 866 | if(current_filter_tois.indexOf(siblings[i]) == -1) { 867 | a_toi_missing = true; 868 | break; 869 | } 870 | } 871 | if(a_toi_missing == false) { 872 | $("#map-menu li."+parent_qnr+" > span.toggle > form.expert_mode input")[0].checked = true; 873 | $("#map-menu li."+parent_qnr+" > span.toggle > form.expert_mode input")[0].indeterminate = false; 874 | } 875 | else 876 | $("#map-menu li."+parent_qnr+" > span.toggle > form.expert_mode input")[0].indeterminate = true; 877 | 878 | 879 | var new_parent = tax_hashtable.cat_qindex[parent_qnr]; 880 | //we hope categories have only 1 parent 881 | if(new_parent //it could be that this is the highest cat, which's parent is not in cat_qindex 882 | && new_parent.subclass_of.value 883 | && tax_hashtable.cat_qindex[getQNR(new_parent.subclass_of.value)]){ 884 | checkStateOfParents(new_parent.subclass_of.value); 885 | } 886 | }); 887 | } 888 | checkStateOfParents(item.subclass_of.value); 889 | return; 890 | } 891 | } 892 | //if is a cat, add all TOIs 893 | if(tax_hashtable.cat_qindex[id]) { 894 | var array = getTOIsOfCat(id); 895 | array.forEach(function(toi) { 896 | addToFilter(toi); 897 | }); 898 | } 899 | } 900 | 901 | function clickPlus(item) { 902 | addToFilter(item); 903 | trigger_Filter(); 904 | } 905 | function clickMinus(item) { 906 | removeFromFilter(item); 907 | trigger_Filter(); 908 | } 909 | function toggleFilterItem(item,e) { 910 | console.log(e); 911 | if(e.indeterminate === true) { 912 | console.log("indet"); 913 | removeFromFilter(item); 914 | } 915 | else if(e.checked === false) { // changed state after click! 916 | console.log("was checked"); 917 | removeFromFilter(item); 918 | } 919 | else if(e.checked) { 920 | console.log("was unchecked"); 921 | addToFilter(item); 922 | } 923 | trigger_Filter(); 924 | } 925 | 926 | function removeFromFilter(id) { 927 | if(id == "hint") { 928 | $("#activefilters ul .hint").remove(); 929 | return; 930 | } 931 | 932 | if(tax_hashtable.toi_qindex[id]) { // is a toi 933 | $("#activefilters ul ."+id).remove(); 934 | $("#map-menu li."+id+" form.expert_mode input").removeAttr("checked"); 935 | current_filter_tois.deleteInArray(id); 936 | 937 | //for parent cats, set -/+ button color: 938 | var item = tax_hashtable.toi_qindex[id]; 939 | 940 | //recursive! 941 | function checkStateOfParents(parents_string) { 942 | var parent_cats = parents_string.split(";"); 943 | parent_cats.forEach(function (parent_cat) { 944 | var parent_qnr = getQNR(parent_cat); 945 | 946 | // //[+] has to be active, as we just removed an item... 947 | // $("#map-menu li."+parent_qnr+" > span.toggle > span.expert_mode .add").removeClass("inactive"); 948 | 949 | //muss mindestens 'indefinite' sein 950 | 951 | //if none of the sub-items are in filter list, we can uncheck the box 952 | var siblings = getTOIsOfCat(parent_qnr); 953 | var tois_active = false; 954 | for(var i=0; i < siblings.length; i++) { 955 | if(current_filter_tois.indexOf(siblings[i]) > -1) { 956 | var tois_active = true; 957 | break; 958 | } 959 | } 960 | if(tois_active == false) { 961 | $("#map-menu li."+parent_qnr+" > span.toggle > form.expert_mode input")[0].checked = false; 962 | $("#map-menu li."+parent_qnr+" > span.toggle > form.expert_mode input")[0].indeterminate = false; 963 | } 964 | else // has to be at least "indeterminate", because we removed one and it cannot be fully checked 965 | $("#map-menu li."+parent_qnr+" > span.toggle > form.expert_mode input")[0].indeterminate = true; 966 | 967 | var new_parent = tax_hashtable.cat_qindex[parent_qnr]; 968 | //we hope categories have only 1 parent 969 | if(new_parent //it could be that this is the highest cat, which's parent is not in cat_qindex 970 | && new_parent.subclass_of.value 971 | && tax_hashtable.cat_qindex[getQNR(new_parent.subclass_of.value)]){ 972 | console.log("new parent: " + getQNR(new_parent.subclass_of.value) + "for " + id); 973 | checkStateOfParents(new_parent.subclass_of.value); 974 | } 975 | }); 976 | } 977 | checkStateOfParents(item.subclass_of.value); 978 | return; 979 | } 980 | //if is a cat, remove all TOIs 981 | if(tax_hashtable.cat_qindex[id]) { 982 | var array = getTOIsOfCat(id); 983 | array.forEach(function(toi) { 984 | removeFromFilter(toi); 985 | }); 986 | } 987 | if(id == "*") { 988 | $("#activefilters ul li").remove(); 989 | $("#map-menu li form.expert_mode input").removeAttr("checked"); 990 | current_filter_tois = []; 991 | } 992 | } 993 | 994 | /** 995 | * attributes: ;-separated toi-attributes of POI 996 | * filter_UUID: Q-Nr of filter that should be matched against 997 | * 998 | * checks if any attribute in attributes (=TOI) is either the filter_UUID or the TOI is any subclass of the filter_UUID 999 | */ 1000 | function filterMatches(attributes, filter_UUID) { 1001 | 1002 | if(!attributes) { 1003 | console.log("error in filter, no attributes"); 1004 | return false; 1005 | } 1006 | 1007 | var poiFound = false; 1008 | 1009 | if(current_filter_tois.length == 0) { 1010 | poiFound = true; 1011 | } 1012 | 1013 | //console.log("filter called with filter: " + filter_UUID + " and toi: " + attributes.type_of_initiative); 1014 | 1015 | //attributes.type_of_initiative can be ;-separated... 1016 | var toi_array = createToiArray(attributes.type_of_initiative); 1017 | 1018 | for(var i=0;i -1) { 1022 | poiFound = true; 1023 | break; 1024 | } 1025 | } 1026 | 1027 | var searchRelevantPoiProperties = [ 1028 | 'name', 1029 | 'addr:city', 1030 | 'addr:street', 1031 | 'addr:country', 1032 | 'addr.postcode', 1033 | 'website', 1034 | 'contact:website', 1035 | 'contact:email', 1036 | 'description' 1037 | ]; 1038 | 1039 | if (poiFound && current_filter_search != '') { 1040 | var searchFilterRegExp = new RegExp(current_filter_search, 'i'); 1041 | for(searchProperty in searchRelevantPoiProperties) { 1042 | if (attributes[searchRelevantPoiProperties[searchProperty]]) { 1043 | if (attributes[searchRelevantPoiProperties[searchProperty]].match(searchFilterRegExp)) { 1044 | // console.log(searchRelevantPoiProperties[searchProperty] + ': ' + attributes[searchRelevantPoiProperties[searchProperty]]); 1045 | poiFound = true; 1046 | break; 1047 | } else { 1048 | poiFound = false; 1049 | } 1050 | } 1051 | } 1052 | } 1053 | 1054 | return poiFound; 1055 | } 1056 | 1057 | var popup_image_width = "270px"; 1058 | /* 1059 | * checks if a image link points to a Mediawiki and if, returns link to thumbnail version of image 1060 | */ 1061 | function checkForMWimages(image_uri) { 1062 | var retval = image_uri; 1063 | if(image_uri.match(/\/wiki\/File:/)) { // guess it is any Mediawiki instance 1064 | retval = image_uri.replace(/ /,"_") 1065 | .replace(/\/File:/,'/Special:Redirect/file/') 1066 | + "?width=" + popup_image_width; 1067 | } else if (image_uri.match(/^File:/)) { // take File: for hosted at Wikimedia Commons 1068 | retval = image_uri.replace(/ /,"_") 1069 | .replace(/^File:/,'https://commons.wikimedia.org/wiki/Special:Redirect/file/') 1070 | + "?width=" + popup_image_width; 1071 | } 1072 | 1073 | return retval; 1074 | } 1075 | /* 1076 | * returns the description text (attributes[description:*]) in the users lang or a fallback 1077 | * description:$lang -> description:$fallbacks -> description -> description:$? 1078 | */ 1079 | function getDescriptionText(attributes) { 1080 | var best_hit = attributes["description:" + current_lang]; 1081 | if(best_hit) 1082 | return best_hit; 1083 | 1084 | for(var i=0; i < fallback_langs.length; i++) { 1085 | var fallback_desc = attributes["description:" + fallback_langs[i]]; 1086 | if(fallback_desc) 1087 | return fallback_desc; 1088 | } 1089 | 1090 | var standard_descr = attributes["description"]; 1091 | if(standard_descr) 1092 | return standard_descr; 1093 | 1094 | for (attr_key in attributes) { 1095 | if(attr_key.match(/^description:/)) 1096 | return attributes[attr_key]; 1097 | } 1098 | 1099 | return ""; 1100 | } 1101 | 1102 | /* for nicer display of website links, shorten long uris */ 1103 | function trimWebsiteUri(uri,maxlength) { 1104 | var length = (maxlength) ? maxlength : 30; 1105 | var retval = uri.replace(/^http[s]?:\/\//,""); 1106 | 1107 | if(retval.length < length) 1108 | return retval 1109 | else 1110 | return retval.substr(0,length) + "..."; 1111 | } 1112 | 1113 | /* intended for mobile view */ 1114 | function onMobile() { 1115 | return (window.innerWidth <= 640); 1116 | } 1117 | function switchToMap() { 1118 | $('#map-menu-container').hide(); 1119 | $('#map-template').show(); 1120 | } 1121 | function switchToMenu() { 1122 | $('#map-menu-container').show(); 1123 | $('#map-template').hide(); 1124 | } 1125 | 1126 | /* 1127 | * translation stuff 1128 | * 1129 | * On load, everything is in English. When dictionaries are fetched, everything is translated into user's language. 1130 | */ 1131 | 1132 | function getLangs () { 1133 | var language = window.navigator.languages ? window.navigator.languages[0] : (window.navigator.language || window.navigator.userLanguage); 1134 | 1135 | if(typeof language === 'string') 1136 | language = [ language ]; 1137 | 1138 | // we need to have the following languages: 1139 | // browserlang 1140 | // a short one (de instead of de-AT) if not present 1141 | // en as fallback if not present 1142 | 1143 | for(var i = 0; i < language.length; i++) { 1144 | if(language[i].match(/-/)) { 1145 | var short_lang = language[i].match(/^([a-zA-Z]*)-/)[1]; 1146 | if(language.indexOf(short_lang) == -1) { 1147 | language.push(short_lang); 1148 | continue; 1149 | } 1150 | } 1151 | } 1152 | 1153 | if(language.indexOf("en") == -1) 1154 | language.push("en"); 1155 | 1156 | //console.log(language); 1157 | return language; 1158 | } 1159 | 1160 | var browser_languages = getLangs(), 1161 | current_lang = browser_languages[0], 1162 | fallback_langs = []; 1163 | 1164 | var supported_languages = [], 1165 | langnames = [], 1166 | abbr_langnames = {}, 1167 | langnames_abbr = {}; 1168 | 1169 | function resetLang() { 1170 | current_lang = "en"; 1171 | for(var i=0; i < browser_languages.length; i++) { 1172 | var abbr = browser_languages[i]; 1173 | if(abbr_langnames[abbr]) { 1174 | current_lang = abbr; 1175 | break; 1176 | } 1177 | } 1178 | switchToLang(current_lang); 1179 | } 1180 | 1181 | function setFallbackLangs() { 1182 | fallback_langs = []; 1183 | if(current_lang != "en") { 1184 | for(var i=0; i < browser_languages.length; i++) { 1185 | var abbr = browser_languages[i]; 1186 | if(current_lang != abbr) 1187 | fallback_langs.push(abbr); 1188 | } 1189 | } 1190 | console.log("new fallback langs: " + fallback_langs.join(",") + "."); 1191 | } 1192 | setFallbackLangs(); 1193 | 1194 | 1195 | /* get languages for UI from our Wikibase, and pick languages that are translated there */ 1196 | 1197 | function initializeLanguageSwitcher(returned_data){ 1198 | for(lang in returned_data.entities.Q5.labels) { //Q5 is arbitrary. Choose one that gets translated for sure. 1199 | supported_languages.push(lang); 1200 | } 1201 | var langstr = supported_languages.join("|"); 1202 | 1203 | var langstr_query = 1204 | 'SELECT ?lang ?langLabel ?abbr ' + 1205 | 'WHERE' + 1206 | '{' + 1207 | '?lang wdt:P218 ?abbr;' + 1208 | 'FILTER regex (?abbr, "^('+langstr+')$").' + 1209 | 'SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }' + 1210 | '}'; 1211 | 1212 | langstr_query = 'https://query.wikidata.org/bigdata/namespace/wdq/sparql?query=' +encodeURIComponent(langstr_query) + "&format=json"; 1213 | $.getJSON(langstr_query, function (langstrings){ 1214 | 1215 | langstrings.results.bindings.forEach(function (item) { 1216 | abbr_langnames[item.abbr.value] = item.langLabel.value; 1217 | langnames_abbr[item.langLabel.value] = item.abbr.value; 1218 | langnames.push(item.langLabel.value); 1219 | }); 1220 | langnames.sort(); 1221 | 1222 | resetLang(); 1223 | setFallbackLangs(); 1224 | 1225 | $("#map-menu-container .top").append( 1226 | "
    " + 1227 | "Choose Language:" + 1228 | "
      " + 1229 | "
      "); 1230 | 1231 | langnames.forEach(function (item) { 1232 | var langcode = langnames_abbr[item]; 1233 | var is_default = (langcode == current_lang) ? " class=default" : ""; 1234 | console.log("adding lang '" + langcode + "' (" + item + ")"); 1235 | $("#languageSelector ul").append("
    • "+item+"
    • "); 1236 | }); 1237 | }); 1238 | } 1239 | redundantFetch( [ "https://base.transformap.co/wiki/Special:EntityData/Q5.json", "https://raw.githubusercontent.com/TransforMap/transformap-viewer/Q5-fallback.json", "Q5-fallback.json" ], 1240 | initializeLanguageSwitcher, 1241 | function(error) { console.error("none of the lang init data urls available") } ); 1242 | 1243 | 1244 | function switchToLang(lang) { 1245 | $("#languageSelector li.default").removeClass("default"); 1246 | $("#languageSelector li[targetlang="+lang+"]").addClass("default"); 1247 | current_lang = lang; 1248 | setFallbackLangs(); 1249 | 1250 | updateTranslatedTexts(); 1251 | 1252 | if(! dictionary[lang]) { 1253 | var dict_uri = "https://raw.githubusercontent.com/TransforMap/transformap-viewer-translations/master/json/"+lang+".json"; 1254 | 1255 | $.ajax({ 1256 | url: dict_uri, 1257 | context: { lang: current_lang }, 1258 | success: function(returned_data) { 1259 | var trans_jsonobj = JSON.parse(returned_data); 1260 | 1261 | if(! dictionary[this.lang]) 1262 | dictionary[this.lang] = {}; 1263 | for (item in trans_jsonobj) { 1264 | var index = reverse_dic[item]; 1265 | dictionary[this.lang][index] = trans_jsonobj[item]; 1266 | } 1267 | 1268 | console.log("successfully fetched " + this.lang); 1269 | updateTranslatedTexts(); 1270 | 1271 | } 1272 | }); 1273 | 1274 | } 1275 | 1276 | // As rebuilding the filters does not yet support advanced mode by default, 1277 | // we switch to simple mode, as language switching is a very rare case. 1278 | if(getFilterMode() == "advanced") 1279 | toggleAdvancedFilterMode(); 1280 | 1281 | resetFilter(); 1282 | setFilterLang(lang); 1283 | 1284 | console.log("new lang:" +lang); 1285 | } 1286 | 1287 | function updateTranslatedTexts() { 1288 | $("#map-menu-container [trn]").each(function(){ 1289 | var trans_id = $(this).attr("trn"); 1290 | $(this).text(T(trans_id)); 1291 | }); 1292 | } 1293 | 1294 | /* 1295 | * The English translations are held here for ease of use and faster loading times 1296 | * all other Translations are managed via Weblate in this repo: 1297 | * https://github.com/TransforMap/transformap-viewer-translations 1298 | */ 1299 | var dictionary = { 1300 | en: { 1301 | "en_adv_filters" : "Enable Advanced Filter Mode", 1302 | "dis_adv_filters" : "Disable Advanced Filter Mode", 1303 | "search_filter_placeholder" : "Keyword", 1304 | "search_filter_button" : "Search", 1305 | "address" : "Address", 1306 | "contact" : "Contact", 1307 | "opening_hours" : "Opening hours", 1308 | "type_of_initiative" : "Type of Initiative", 1309 | "reset_filters" : "Reset filters", 1310 | "active_filters" : "Active Filters:", 1311 | "show_map" : "Show map", 1312 | "clickanyfilterhint" : "Check a box [ ] to add a filter", 1313 | "filters" : "Filters", 1314 | "set_filters" : "set Filters", 1315 | "imprint" : "Imprint", 1316 | "linked_data" : "Linked Data", 1317 | "creation_date" : "Date of Entry", 1318 | "modification_date" : "Date of Update", 1319 | "susy_disclaimer" : "This website has been produced with the financial assistance of the European Union. The contents of this website are the sole responsibility of the SUSY initiative and can under no circumstances be regarded as reflecting the position of the European Union.", 1320 | "" : "", 1321 | "LAST:":"" 1322 | } 1323 | } 1324 | 1325 | var reverse_dic = {}; //needed for faster lookups 1326 | for (i in dictionary.en) 1327 | reverse_dic[dictionary.en[i]] = i; 1328 | 1329 | /* returns the string according to id in the following preferred order: 1330 | * 1. current_lang 1331 | * 2-n fallback languages 1332 | */ 1333 | function T(id) { 1334 | var native_dict = dictionary[current_lang]; 1335 | if(native_dict) { 1336 | var retval = native_dict[id]; 1337 | if(retval) 1338 | return retval; 1339 | } 1340 | for(var i=0; i < fallback_langs.length; i++) { 1341 | var fb_dict = dictionary[fallback_langs[i]]; 1342 | if(fb_dict) { 1343 | var retval = fb_dict[id]; 1344 | if(retval) 1345 | return retval; 1346 | } 1347 | } 1348 | return "Translation Missing for: '" + id + "'"; 1349 | } 1350 | 1351 | initMap(); 1352 | -------------------------------------------------------------------------------- /scripts/red_fetch.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This library provides a 'fetch', where you can use fallback URIs, to build on redundant servers. 3 | * 4 | * Mon 3 Oct 15:07:12 CEST 2016 5 | * Michael Maier (species@github), WTFPL 6 | * 7 | * Give it an array of resources, that can be fetched from different urls. 8 | * Will try to fetch them in the provided order. 9 | * Execute successFunction on the first successful fetch, and errorFunction only if all resources fail to fetch. 10 | */ 11 | 12 | /* This program is free software. It comes without any warranty, to 13 | * the extent permitted by applicable law. You can redistribute it 14 | * and/or modify it under the terms of the Do What The Fuck You Want 15 | * To Public License, Version 2, as published by Sam Hocevar. See 16 | * http://www.wtfpl.net/ for more details. */ 17 | 18 | /* new version of getting map data with promises 19 | 20 | taken from https://blog.hospodarets.com/fetch_in_action 21 | */ 22 | 23 | var processStatus = function (response) { 24 | // status '0' to handle local files fetching (e.g. Cordova/Phonegap etc.) 25 | if (response.status === 200 || response.status === 0) { 26 | return Promise.resolve(response) 27 | } else { 28 | return Promise.reject(new Error(response.statusText)) 29 | } 30 | }; 31 | 32 | var parseJson = function (response) { 33 | return response.json(); 34 | } 35 | 36 | /* @returns {wrapped Promise} with .resolve/.reject/.catch methods */ 37 | // It goes against Promise concept to not have external access to .resolve/.reject methods, but provides more flexibility 38 | var getWrappedPromise = function () { 39 | var wrappedPromise = {} 40 | var promise = new Promise(function (resolve, reject) { 41 | wrappedPromise.resolve = resolve; 42 | wrappedPromise.reject = reject; 43 | }); 44 | wrappedPromise.then = promise.then.bind(promise); 45 | wrappedPromise.catch = promise.catch.bind(promise); 46 | wrappedPromise.promise = promise;// e.g. if you want to provide somewhere only promise, without .resolve/.reject/.catch methods 47 | return wrappedPromise; 48 | }; 49 | 50 | /* @returns {wrapped Promise} with .resolve/.reject/.catch methods */ 51 | var getWrappedFetch = function () { 52 | var wrappedPromise = getWrappedPromise(); 53 | var args = Array.prototype.slice.call(arguments);// arguments to Array 54 | 55 | fetch.apply(null, args)// calling original fetch() method 56 | .then(function (response) { 57 | wrappedPromise.resolve(response); 58 | }, function (error) { 59 | wrappedPromise.reject(error); 60 | }) 61 | .catch(function (error) { 62 | wrappedPromise.catch(error); 63 | }); 64 | return wrappedPromise; 65 | }; 66 | 67 | /** 68 | * Fetch JSON by url 69 | * @param { { 70 | * url: {String}, 71 | * [cacheBusting]: {Boolean} 72 | * } } params 73 | * @returns {Promise} 74 | */var MAX_WAITING_TIME = 5000;// in ms 75 | 76 | var getJSON = function (params) { 77 | var wrappedFetch = getWrappedFetch( 78 | params.cacheBusting ? params.url + '?' + new Date().getTime() : params.url, 79 | { 80 | method: 'get', // optional, 'GET' is default value 81 | headers: { 82 | 'Accept': 'application/json' 83 | } 84 | }); 85 | 86 | var timeoutId = setTimeout(function () { 87 | wrappedFetch.reject(new Error('Load timeout for resource: ' + params.url));// reject on timeout 88 | }, MAX_WAITING_TIME); 89 | 90 | return wrappedFetch.promise// getting clear promise from wrapped 91 | .then(function (response) { 92 | clearTimeout(timeoutId); 93 | return response; 94 | }) 95 | .then(processStatus) 96 | .then(parseJson); 97 | }; 98 | 99 | function myGetJSON(url, successFunction, errorFunction) { 100 | var getJSONparams = { url: url, cacheBusting: true }; 101 | 102 | getJSON(getJSONparams).then( 103 | function (data) { successFunction(data) }, 104 | function (error) { errorFunction(error) } 105 | ); 106 | } 107 | 108 | function redundantFetch (data_url_array, successFunction, errorFunction, params) { 109 | if( ! (!!data_url_array && Array === data_url_array.constructor ) ) { 110 | console.error('redundantFetch: argument is no array'); 111 | console.error(data_url_array); 112 | return false; 113 | } 114 | var current_url = data_url_array[0]; 115 | if(typeof(current_url) !== 'string') { 116 | console.error('redundantFetch: url is no string'); 117 | return false; 118 | } 119 | 120 | console.log('redundantFetch called, urls:'); 121 | console.log(data_url_array); 122 | 123 | data_url_array.shift(); 124 | 125 | var localErrorFunction; 126 | var localSuccessFunction; 127 | if(data_url_array.length == 0) { //last iteration 128 | localSuccessFunction = successFunction; 129 | localErrorFunction = errorFunction; 130 | } else { 131 | localSuccessFunction = successFunction; 132 | localErrorFunction = function (error) { 133 | redundantFetch(data_url_array, successFunction, errorFunction, params); 134 | } 135 | } 136 | 137 | var getJSONparams = { url: current_url, cacheBusting: ((params && params.cacheBusting === false) ? false : true) }; 138 | getJSON(getJSONparams).then( 139 | function (data) { localSuccessFunction(data); console.log('rfetch: success on '); console.log(data) }, 140 | function (error) { localErrorFunction(error); console.log('rfetch: fail on '); console.log(error) } 141 | ) 142 | } 143 | -------------------------------------------------------------------------------- /styles/css/style.css: -------------------------------------------------------------------------------- 1 | a,a:link{color:#455473;cursor:pointer}body{margin:0;font-family:'PT Sans',sans-serif;background:#1F3050}#map-tiles .leaflet-popup,p{font-family:'Open Sans',sans-serif}p{font-size:16px}li{list-style-type:none}h1,h2,h3,h4,h5,h6{text-align:center}#map-tiles{height:100vh;position:absolute;top:0;bottom:0;right:0;left:260px}#map-tiles .leaflet-popup{text-align:left!important}#map-tiles .leaflet-popup .leaflet-popup-close-button{font-size:23px;width:35px;height:35px;padding:8px 0 0;vertical-align:center}#map-tiles .leaflet-popup .leaflet-popup-close-button:hover{background:#c3c3c3}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper{border-radius:0;padding:0 2px 0 0;margin:0;max-width:300px;max-height:90vh;overflow-x:hidden;overflow-y:auto}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content{padding-bottom:15px;margin:0}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content h1{text-align:left;padding:15px 30px 15px 15px;border-bottom:1px solid #eee;margin-bottom:15px;margin-top:0;color:#1f3050;font-weight:700;font-size:16px}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content p{font-size:12px;text-align:left;padding:5px 15px;margin:0}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content p img{display:block;margin:auto;width:100%;max-width:270px}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content p a{text-align:left!important;color:#1F3050}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content p span.wp{display:block}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content p span.osm{font-style:italic}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content p img.wp{height:1.5em;width:1.5em;display:inline;margin-bottom:-.35em}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content table{font-size:12px;text-align:left;padding:5px 15px;margin:0;width:100%}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content table td+td{text-align:right}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content p.contact{line-height:2em}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content p.contact img{width:16px;margin-bottom:-4px;margin-right:6px;display:inline}#map-tiles .leaflet-popup .leaflet-popup-content-wrapper .leaflet-popup-content h3{margin:0;padding:5px 15px 0;text-align:left;font-size:12px;font-weight:700}#map-tiles .my-div-icon{width:25px!important;height:40px;background-image:url(../../bower_components/leaflet/dist/images/marker-green.png);margin-top:-40px}#map-tiles .my-div-icon div{display:none}#map-tiles .my-div-icon:hover>div{display:block;width:200px;z-index:15000;margin-left:-85px;position:absolute;bottom:35px}#map-tiles .my-div-icon:hover>div div{display:block;margin:0 auto;background:rgba(255,255,255,.8);text-align:center;width:fit-content;border:1px solid #1F3050;border-radius:5px;padding:5px 8px}#map-tiles .leaflet-control-layers-toggle{width:26px;height:26px;background-size:22px 22px}#map-tiles #forkme{position:absolute;bottom:14px;left:-70px;display:block;width:300px;height:33px;transform:rotate(45deg);overflow:hidden}#map-menu-container ul#map-menu .list-group-item form.expert_mode.off,#showfilters{display:none}#map-tiles #forkme:hover{opacity:.8}#map-tiles #forkme img{margin-top:-85px;margin-left:40px;transform:rotate(-45deg)}#map-tiles.leaflet-touch .leaflet-control-layers-toggle{width:30px;height:30px;background-size:26px 26px}#showfilters{position:absolute;top:50px;left:10px;border-radius:4px;width:26px;height:26px;background:url(../../assets/icon-filter-24.png) 50% 50% no-repeat #fff;box-shadow:0 1px 5px rgba(0,0,0,.65);cursor:pointer}#map-menu-container{height:100vh;overflow:auto;width:260px;background:#95D5D2;font-size:.8em;font-weight:700;letter-spacing:.075em}#map-menu-container ul#map-menu{padding:0;margin:0;border:none}#map-menu-container ul#map-menu .list-group-item{padding:0;background:#95D5D2;color:#fff;border:none;border-radius:none}#map-menu-container ul#map-menu .list-group-item form.expert_mode.on{display:block;float:right;margin-right:3px;margin-left:6px;font-style:normal;color:#000}#map-menu-container ul#map-menu li.list-group-item.category{border-left:0;border-right:0;border-radius:0;border-bottom:1px solid #aaa}#map-menu-container ul#map-menu li.list-group-item.category ul.subcategories{background:#1F3050}#map-menu-container ul#map-menu li.list-group-item.category:first-child{border-top:1px solid #aaa}#map-menu-container ul#map-menu span.toggle{padding:5px 0 5px 10px;display:block;height:100%;cursor:pointer}#map-menu-container #activefilters .expert_mode.off,#map-menu-container ul#map-menu .category ul{display:none}#map-menu-container ul#map-menu span.toggle.selected{background:#1F3050;font-style:italic}#map-menu-container ul#map-menu .toggle-subcategories{padding-left:20px}#map-menu-container ul#map-menu ul.subcategories{padding-left:10px}#map-menu-container ul#map-menu ul.subcategories li.list-group-item:last-child{border-bottom:0}#map-menu-container ul#map-menu ul.type-of-initiative{font-weight:400;letter-spacing:normal;text-align:left;display:none;background:#fcec74;position:fixed;left:260px;top:0;z-index:10;-webkit-padding-start:0;padding:0 15px;border-top-right-radius:5px;border-bottom-right-radius:5px}#map-menu-container ul#map-menu ul.type-of-initiative .list-group-item{background:#fcec74;padding:5px 0 5px 10px;color:#000;border-top:1px solid #fff}#map-menu-container ul#map-menu ul.type-of-initiative .list-group-item:hover{cursor:pointer}#map-menu-container ul#map-menu ul.type-of-initiative .list-group-item:first-child{border-top:0}#map-menu-container ul#map-menu ul.type-of-initiative .list-group-item.selected{background:#F2BD0B;font-style:italic}#map-menu-container ul#map-menu ul.type-of-initiative .list-group-item.empty{color:gray}#map-menu-container #activefilters{clear:both;padding:0 0 0 10px;color:#fff}#map-menu-container #activefilters h2{text-align:left}#map-menu-container #activefilters ul{font-weight:400;padding:0;margin:0}#map-menu-container #activefilters ul li{border-radius:5px;padding:3px 22px 3px 5px;margin:5px 5px 5px 0;background:#F2BD0B;color:#000}#map-menu-container #activefilters ul li .close{font-weight:700;background:#fcec74;text-align:center;display:block;padding:3px;margin-top:-3px;margin-right:-22px;border-top-right-radius:5px;border-bottom-right-radius:5px;height:100%;width:12px;float:right;border-left:1px solid #fcec74}#map-menu-container #activefilters ul li .close:hover{background:#F2BD0B;cursor:pointer}#map-menu-container div#languageSelector,#map-menu-container div#mobileShowMap>div,#map-menu-container div#resetfilters,#map-menu-container div#searchFilterWrapper,#map-menu-container div#toggleAdvancedFilters{width:fit-content;color:#fff;padding:5px;margin:5px 10px;border:1px solid #fff;cursor:pointer}#map-menu-container div#mobileShowMap,#map-menu-container div#resetfilters{display:none}#map-menu-container div#searchFilterWrapper{float:left}#map-menu-container div#searchFilterWrapper input{padding:3px;float:left;width:116px;margin-right:5px}#map-menu-container div#searchFilterWrapper button{padding:3px;float:right}#map-menu-container div#languageSelector ul{float:right;margin:0 0 0 5px;padding:0}#map-menu-container div#languageSelector ul li{display:none;background:#95D5D2}#map-menu-container div#languageSelector ul li.default{display:block}#map-menu-container div#languageSelector ul.open{margin-top:-5px;margin-right:-6px}#map-menu-container div#languageSelector ul.open li{display:block;border:1px solid #fff;border-top:0;padding:5px}#map-menu-container div#languageSelector ul.open li:hover{color:#000}#map-menu-container div#languageSelector ul.open li.default{background:#1F3050;font-style:italic}#map-menu-container div#susyci{color:#fff;padding:.5em}#map-menu-container div#susyci .logo{text-align:center;margin:1em 0}#map-menu-container div#susyci .logo img{width:80%}#map-menu-container div#susyci .logo a{color:#fff}@media screen and (max-width:640px){#map-menu-container{position:absolute;top:0;left:0;width:100%}#map-menu-container ul#map-menu ul.type-of-initiative{margin-left:10px;padding:0;position:static;border-radius:0}#map-menu-container div#mobileShowMap{display:block;width:100%;height:1em;padding:6px 0 21px}#map-menu-container div#mobileShowMap div{float:right;margin:0 10px}#map-tiles .leaflet-popup-pane{bottom:0;right:0}#map-tiles{left:0}#showfilters{display:block}.leaflet-top{top:40px}} -------------------------------------------------------------------------------- /styles/less/style.less: -------------------------------------------------------------------------------- 1 | /* next 4 are currently used */ 2 | @yellow-bright: #fcec74; /* 1 #F6DF05 2 */ 3 | @yellow-dark: #F2BD0B; /* #F0BB0C */ 4 | @blue-bright: #95D5D2; /* 5 dec: 149,213,210 */ 5 | @blue-dark: #1F3050; /* 6 */ 6 | 7 | /* the original ones from the CD document */ 8 | @cd-darkblue: #1F3050; 9 | @cd-brightblue: #95D5D2; 10 | @cd-yellow: #FFDD00; 11 | 12 | /* from map.js - here just for comparison */ 13 | @start1: #FCEC74; /* yellow-bright */ 14 | @start2: #F7DF05; /* yellow-dark */ 15 | @start3: #F2BD0B; /* yellow-darker (orange) */ 16 | @start4: #FFF030; /* yellow */ 17 | @start5: #95D5D2; /* bright blue */ 18 | @start6: #1F3050; /* dark blue */ 19 | 20 | @menuwidth: 260px; 21 | 22 | a, 23 | a:link { 24 | color: #455473; 25 | cursor: pointer 26 | } 27 | 28 | body { 29 | margin:0; 30 | font-family: 'PT Sans', sans-serif; 31 | background: @blue-dark; 32 | } 33 | 34 | p { 35 | font-family: 'Open Sans', sans-serif; 36 | font-size: 16px; 37 | } 38 | 39 | li { 40 | list-style-type: none; 41 | } 42 | 43 | h1, 44 | h2, 45 | h3, 46 | h4, 47 | h5, 48 | h6 { 49 | text-align: center 50 | } 51 | 52 | 53 | /************************** 54 | Basic map and pop up styles 55 | **************************/ 56 | 57 | #map-tiles { 58 | height: 100vh; 59 | position:absolute; 60 | top:0; 61 | bottom:0; 62 | right:0; 63 | left:@menuwidth; 64 | 65 | .leaflet-popup { 66 | font-family: 'Open Sans', sans-serif; 67 | text-align: left !important; 68 | 69 | .leaflet-popup-close-button { 70 | font-size:23px; 71 | width:35px; 72 | height:35px; 73 | padding:8px 0 0 0; 74 | vertical-align:center; 75 | } 76 | .leaflet-popup-close-button:hover { 77 | background:#c3c3c3; 78 | } 79 | 80 | .leaflet-popup-content-wrapper { 81 | border-radius: 0; 82 | padding: 0px 2px 0 0; /*20px for scrollbar*/ 83 | margin: 0; 84 | max-width: 300px; 85 | max-height: 90vh; 86 | overflow-x: hidden; 87 | overflow-y: auto; 88 | 89 | .leaflet-popup-content { 90 | padding-bottom: 15px; 91 | margin: 0; 92 | 93 | h1 { 94 | text-align: left; 95 | padding: 15px; 96 | padding-right:30px; /*don't overlap with ×-button*/ 97 | border-bottom: 1px solid #eee; 98 | margin-bottom: 15px; 99 | margin-top:0px; 100 | color: #1f3050; 101 | font-weight: 700; 102 | font-size: 16px; 103 | } 104 | 105 | p { 106 | font-size: 12px; 107 | text-align: left; 108 | padding: 5px 15px; 109 | margin: 0; 110 | 111 | img { 112 | display: block; 113 | margin: auto; 114 | width: 100%; 115 | max-width: 270px; 116 | } 117 | 118 | a { 119 | text-align: left !important; 120 | color: @blue-dark; 121 | } 122 | span.wp { display:block ; } 123 | span.osm { font-style:italic;} 124 | img.wp { 125 | height:1.5em; 126 | width:1.5em; 127 | display:inline; 128 | margin-bottom:-0.35em; 129 | } 130 | } 131 | table { 132 | font-size: 12px; 133 | text-align: left; 134 | padding: 5px 15px; 135 | margin: 0; 136 | width:100%; 137 | td + td { 138 | text-align: right; 139 | } 140 | } 141 | p.contact { 142 | line-height:2em; 143 | img { 144 | width:16px; 145 | margin-bottom:-4px; 146 | margin-right:6px; 147 | display:inline; 148 | } 149 | } 150 | h3 { 151 | margin:0; 152 | padding:5px 15px 0; 153 | text-align:left; 154 | font-size:12px; 155 | font-weight:bold; 156 | } 157 | 158 | } 159 | } 160 | } 161 | .my-div-icon { 162 | width:25px !important; 163 | height:40px; 164 | background-image:url("../../bower_components/leaflet/dist/images/marker-green.png"); 165 | margin-top:-40px; 166 | div { 167 | display:none; 168 | } 169 | } 170 | /* .my-div-icon:before { 171 | width:20px; 172 | height:20px; 173 | content:""; 174 | display:block; 175 | background:#6ecc39 176 | position:relative; 177 | border-radius:10px; 178 | top:5px; 179 | left:5px; 180 | } */ 181 | .my-div-icon:hover > div { 182 | display:block; 183 | width:200px; 184 | z-index:15000; 185 | margin-left:-85px; 186 | position:absolute; 187 | bottom:35px; 188 | div { 189 | display:block; 190 | margin: 0 auto; 191 | background:rgba(255,255,255,0.8); 192 | text-align:center; 193 | width:fit-content; 194 | border:1px solid @blue-dark; 195 | border-radius:5px; 196 | padding:5px 8px; 197 | } 198 | } 199 | .leaflet-control-layers-toggle { 200 | width:26px; 201 | height:26px; 202 | background-size: 22px 22px; 203 | } 204 | #forkme { 205 | position:absolute; 206 | bottom:14px; 207 | left:-70px; 208 | display:block; 209 | width:300px; 210 | height:33px; 211 | transform: rotate(45deg); 212 | overflow:hidden; 213 | } 214 | #forkme:hover { 215 | opacity:0.8; 216 | } 217 | #forkme img { 218 | margin-top:-85px; 219 | margin-left:40px; 220 | transform: rotate(-45deg); 221 | } 222 | 223 | } 224 | #map-tiles.leaflet-touch .leaflet-control-layers-toggle { 225 | width:30px; 226 | height:30px; 227 | background-size: 26px 26px; 228 | } 229 | 230 | #showfilters { 231 | display:none; 232 | position:absolute; 233 | top:50px; 234 | left:10px; 235 | border-radius:4px; 236 | width:26px; 237 | height:26px; 238 | background:white url(../../assets/icon-filter-24.png) 50% 50% no-repeat; 239 | box-shadow: 0 1px 5px rgba(0,0,0,0.65); 240 | cursor:pointer; 241 | } 242 | 243 | /************** 244 | Map menu styling 245 | **************/ 246 | 247 | /* Menu styles */ 248 | #map-menu-container { 249 | height: 100vh; 250 | overflow:auto; 251 | width: @menuwidth; 252 | 253 | background: @blue-bright; 254 | font-size: 0.8em; 255 | font-weight:bold; 256 | letter-spacing:0.075em; 257 | 258 | .top { 259 | } 260 | .bottom { 261 | } 262 | 263 | /* Main categories */ 264 | ul#map-menu { 265 | border-top: 1px solid #aaa; 266 | border-bottom: 1px solid #aaa; 267 | padding:0; 268 | margin:0; 269 | border: none; 270 | .list-group-item { 271 | padding:0; 272 | background: @blue-bright; 273 | color: #fff; 274 | border: none; 275 | border-radius: none; 276 | form.expert_mode.off { 277 | display:none; 278 | } 279 | form.expert_mode.on { 280 | display:block; 281 | float:right; 282 | margin-right:3px; 283 | margin-left:6px; 284 | font-style:normal; 285 | color:black; 286 | } 287 | } 288 | li.list-group-item.category { 289 | border-left: 0px; 290 | border-right: 0px; 291 | border-radius: 0; 292 | border-bottom: 1px solid #aaa; 293 | ul.subcategories { 294 | background:@blue-dark; 295 | } 296 | 297 | } 298 | li.list-group-item.category:first-child { 299 | border-top: 1px solid #aaa; 300 | } 301 | /* These elements are spans inside list group items, to toggle subcategories */ 302 | span.toggle { 303 | padding: 5px 0 5px 10px; 304 | display:block; 305 | height:100%; 306 | cursor: pointer; 307 | } 308 | span.toggle.selected { 309 | background:@blue-dark; 310 | font-style:italic; 311 | } 312 | .toggle-subcategories { 313 | padding-left: 20px; 314 | } 315 | .category ul { 316 | display: none; 317 | } 318 | ul.subcategories { 319 | padding-left: 10px; 320 | li.list-group-item:last-child { 321 | border-bottom: 0; 322 | } 323 | } 324 | ul.type-of-initiative { 325 | font-weight:normal; 326 | letter-spacing:normal; 327 | text-align: left; 328 | display: none; 329 | background: @yellow-bright; 330 | position: fixed; 331 | left: @menuwidth; 332 | top: 0; 333 | z-index: 10; 334 | -webkit-padding-start: 0px; 335 | padding: 0px 15px; 336 | border-top-right-radius: 5px; 337 | border-bottom-right-radius: 5px; 338 | .list-group-item { 339 | background: @yellow-bright; 340 | padding: 5px 0 5px 10px; 341 | color: #000; 342 | border-top:1px solid white; 343 | } 344 | .list-group-item:hover { 345 | cursor: pointer; 346 | } 347 | .list-group-item:first-child { 348 | border-top:0; 349 | } 350 | .list-group-item.selected { 351 | background:@yellow-dark; 352 | font-style:italic; 353 | } 354 | .list-group-item.empty { 355 | color:gray; 356 | } 357 | 358 | } 359 | } 360 | #activefilters { 361 | clear: both; 362 | padding:0 0 0 10px; 363 | color:white; 364 | h2 { 365 | text-align:left; 366 | } 367 | .expert_mode.off { 368 | display:none; 369 | } 370 | ul { 371 | font-weight:normal; 372 | padding:0; 373 | margin:0; 374 | li { 375 | border-radius:5px; 376 | padding:3px 22px 3px 5px; 377 | margin:5px 5px 5px 0; 378 | background:@yellow-dark; 379 | color:black; 380 | .close { 381 | font-weight:bold; 382 | background: @yellow-bright; 383 | text-align:center; 384 | display:block; 385 | padding:3px; 386 | margin-top:-3px; 387 | margin-right:-22px; 388 | border-top-right-radius:5px; 389 | border-bottom-right-radius:5px; 390 | height:100%; 391 | width:12px; 392 | float:right; 393 | border-left:1px solid @yellow-bright; 394 | } 395 | .close:hover { 396 | background:@yellow-dark; 397 | cursor:pointer; 398 | } 399 | } 400 | } 401 | } 402 | 403 | div#resetfilters, 404 | div#toggleAdvancedFilters, 405 | div#searchFilterWrapper, 406 | div#languageSelector, 407 | div#mobileShowMap > div{ 408 | width:fit-content; 409 | color:white; 410 | padding:5px; 411 | margin:5px 10px; 412 | border:1px solid white; 413 | cursor:pointer; 414 | } 415 | div#resetfilters, 416 | div#mobileShowMap { 417 | display:none; 418 | } 419 | div#searchFilterWrapper { 420 | float: left; 421 | input { 422 | padding:3px; 423 | float:left; 424 | width:116px; 425 | margin-right:5px; 426 | } 427 | button { 428 | padding:3px; 429 | float:right; 430 | } 431 | } 432 | div#languageSelector{ 433 | ul { 434 | float:right; 435 | margin:0 0 0 5px; 436 | padding:0; 437 | li { 438 | display:none; 439 | background:@blue-bright; 440 | } 441 | li:hover { 442 | } 443 | li.default { 444 | display:block; 445 | } 446 | } 447 | ul.open { 448 | margin-top:-5px; 449 | margin-right:-6px;/*5 padding + 1 border*/ 450 | li { 451 | display:block; 452 | border:1px solid white; 453 | border-top:0; 454 | padding:5px; 455 | } 456 | li:hover { 457 | color:black; 458 | } 459 | li.default { 460 | background:@blue-dark; 461 | font-style:italic; 462 | } 463 | } 464 | 465 | } 466 | div#susyci { 467 | color:white; 468 | padding:0.5em; 469 | .logo { 470 | text-align:center; 471 | margin:1em 0; 472 | img { 473 | width:80%; 474 | } 475 | a { 476 | color:white; 477 | } 478 | } 479 | 480 | } 481 | } 482 | 483 | 484 | 485 | /******************* 486 | MEDIA 487 | *******************/ 488 | @media screen and (max-width:640px) { 489 | #map-menu-container { 490 | position:absolute; 491 | top:0; 492 | left:0; 493 | width:100%; 494 | ul#map-menu { 495 | ul.type-of-initiative { 496 | margin-left: 10px; 497 | padding:0; 498 | position:static; 499 | border-radius:0; 500 | } 501 | } 502 | div#mobileShowMap { 503 | display:block; 504 | width:100%; 505 | height:1em; 506 | padding:6px 0 21px 0; 507 | div { 508 | float:right; 509 | margin:0 10px; 510 | } 511 | } 512 | } 513 | #map-tiles .leaflet-popup-pane { 514 | bottom:0; 515 | right:0; 516 | } 517 | #map-tiles { 518 | left:0; 519 | /* .leaflet-popup { 520 | position:fixed !important; 521 | transform:none !important; 522 | margin:0px; 523 | width:100vw; 524 | height:100vh; 525 | top:0px !important; 526 | left:0px !important; 527 | bottom:0px !important; 528 | right:0px !important; 529 | } */ 530 | } 531 | #showfilters { 532 | display:block; 533 | } 534 | .leaflet-top { /* to prevent overlapping with popup-close button */ 535 | top:40px; 536 | } 537 | } 538 | 539 | --------------------------------------------------------------------------------