├── .gitignore ├── mapboxstyle ├── .thumb.png ├── ffcmap.tm2z ├── project.yml ├── style.mss └── project.xml ├── images ├── contact_icons.png ├── location-icon.png ├── touch-icon-114.png ├── touch-icon-52.png └── touch-icon-72.png ├── external ├── leaflet │ ├── images │ │ ├── layers.png │ │ ├── layers-2x.png │ │ ├── marker-icon.png │ │ ├── marker-icon-2x.png │ │ └── marker-shadow.png │ ├── MarkerCluster.css │ ├── MarkerCluster.Default.ie.css │ ├── MarkerCluster.Default.css │ ├── leaflet-button-control.css │ ├── leaflet.ie.css │ ├── leaflet-button-control.js │ ├── leaflet.css │ └── leaflet.markercluster.js ├── underscore │ ├── underscore-min.js │ └── underscore-min.map └── jquery │ └── jquery.min.js ├── index.html ├── config.json.sample ├── README.md ├── server.js ├── ffGeoJsonp.php ├── map.html ├── community_map.css └── community_map.js /.gitignore: -------------------------------------------------------------------------------- 1 | config.json -------------------------------------------------------------------------------- /mapboxstyle/.thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/cmap.api.fossasia.net/master/mapboxstyle/.thumb.png -------------------------------------------------------------------------------- /images/contact_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/cmap.api.fossasia.net/master/images/contact_icons.png -------------------------------------------------------------------------------- /images/location-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/cmap.api.fossasia.net/master/images/location-icon.png -------------------------------------------------------------------------------- /images/touch-icon-114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/cmap.api.fossasia.net/master/images/touch-icon-114.png -------------------------------------------------------------------------------- /images/touch-icon-52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/cmap.api.fossasia.net/master/images/touch-icon-52.png -------------------------------------------------------------------------------- /images/touch-icon-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/cmap.api.fossasia.net/master/images/touch-icon-72.png -------------------------------------------------------------------------------- /mapboxstyle/ffcmap.tm2z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/cmap.api.fossasia.net/master/mapboxstyle/ffcmap.tm2z -------------------------------------------------------------------------------- /external/leaflet/images/layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/cmap.api.fossasia.net/master/external/leaflet/images/layers.png -------------------------------------------------------------------------------- /external/leaflet/images/layers-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/cmap.api.fossasia.net/master/external/leaflet/images/layers-2x.png -------------------------------------------------------------------------------- /external/leaflet/images/marker-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/cmap.api.fossasia.net/master/external/leaflet/images/marker-icon.png -------------------------------------------------------------------------------- /external/leaflet/images/marker-icon-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/cmap.api.fossasia.net/master/external/leaflet/images/marker-icon-2x.png -------------------------------------------------------------------------------- /external/leaflet/images/marker-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/cmap.api.fossasia.net/master/external/leaflet/images/marker-shadow.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Freifunk Community Map 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /config.json.sample: -------------------------------------------------------------------------------- 1 | { 2 | "feedUrl": "//feed-fossasia-api.herokuapp.com/feed.php", 3 | "embedTimelineUrl": "//timeline-fossasia-api.herokuapp.com/embed.php", 4 | "geoJSONUrl": "http://api.fossasia.net/map/ffGeoJsonp.php", 5 | "postContenLimit": 30 6 | } -------------------------------------------------------------------------------- /external/leaflet/MarkerCluster.css: -------------------------------------------------------------------------------- 1 | .leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow { 2 | -webkit-transition: -webkit-transform 0.2s ease-out, opacity 0.2s ease-in; 3 | -moz-transition: -moz-transform 0.2s ease-out, opacity 0.2s ease-in; 4 | -o-transition: -o-transform 0.2s ease-out, opacity 0.2s ease-in; 5 | transition: transform 0.2s ease-out, opacity 0.2s ease-in; 6 | } -------------------------------------------------------------------------------- /external/leaflet/MarkerCluster.Default.ie.css: -------------------------------------------------------------------------------- 1 | /* IE 6-8 fallback colors */ 2 | .marker-cluster-small { 3 | background-color: rgb(181, 226, 140); 4 | } 5 | .marker-cluster-small div { 6 | background-color: rgb(110, 204, 57); 7 | } 8 | 9 | .marker-cluster-medium { 10 | background-color: rgb(241, 211, 87); 11 | } 12 | .marker-cluster-medium div { 13 | background-color: rgb(240, 194, 12); 14 | } 15 | 16 | .marker-cluster-large { 17 | background-color: rgb(253, 156, 115); 18 | } 19 | .marker-cluster-large div { 20 | background-color: rgb(241, 128, 23); 21 | } 22 | -------------------------------------------------------------------------------- /mapboxstyle/project.yml: -------------------------------------------------------------------------------- 1 | _prefs: 2 | baselayer: '' 3 | saveCenter: true 4 | _properties: {} 5 | attribution: Map data © OpenStreetMap contributors 6 | bounds: 7 | - -180 8 | - -85.0511 9 | - 180 10 | - 85.0511 11 | center: 12 | - 9.140625 13 | - 48.821332549646634 14 | - 6 15 | description: Map to display Freifunk and other free networks 16 | format: "png8:m=h:c=32" 17 | interactivity_layer: admin 18 | layers: null 19 | maxzoom: 22 20 | minzoom: 0 21 | mtime: 1398410448920 22 | name: Freifunk Community Map 23 | scale: 1 24 | source: "mapbox:///mapbox.mapbox-streets-v4" 25 | styles: 26 | - style.mss 27 | template: '' 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Community Map 2 | ============= 3 | 4 | [![Join the chat at https://gitter.im/fossasia/api.fossasia.net](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fossasia/api.fossasia.net?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | 6 | ## Setup 7 | ----- 8 | 9 | ``` 10 | git clone https://github.com/fossasia/cmap.api.fossasia.net.git 11 | cd cmap.api.fossasia.net 12 | node server.js 13 | ``` 14 | 15 | ## Dependencies 16 | (external folder) 17 | 18 | * jQuery v2.0.3 19 | * underscore.js v1.5.2 20 | * leaflet.js 21 | 22 | ## Contribute 23 | 24 | The community map is a fun & visual way to know more about open-source communities across Asia. If you think there are cool features that can be integrated in the map, you can let us know by opening an issue, or sending pull requests. Bug reports are equally welcomed. 25 | 26 | [FOSSASIA API repo](https://github.com/fossasia/api.fossasia.net) 27 | -------------------------------------------------------------------------------- /external/leaflet/MarkerCluster.Default.css: -------------------------------------------------------------------------------- 1 | .marker-cluster-small { 2 | background-color: rgba(181, 226, 140, 0.6); 3 | } 4 | .marker-cluster-small div { 5 | background-color: rgba(110, 204, 57, 0.6); 6 | } 7 | 8 | .marker-cluster-medium { 9 | background-color: rgba(241, 211, 87, 0.6); 10 | } 11 | .marker-cluster-medium div { 12 | background-color: rgba(240, 194, 12, 0.6); 13 | } 14 | 15 | .marker-cluster-large { 16 | background-color: rgba(253, 156, 115, 0.6); 17 | } 18 | .marker-cluster-large div { 19 | background-color: rgba(241, 128, 23, 0.6); 20 | } 21 | 22 | .marker-cluster { 23 | background-clip: padding-box; 24 | border-radius: 20px; 25 | } 26 | .marker-cluster div { 27 | width: 30px; 28 | height: 30px; 29 | margin-left: 5px; 30 | margin-top: 5px; 31 | 32 | text-align: center; 33 | border-radius: 15px; 34 | font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif; 35 | } 36 | .marker-cluster span { 37 | line-height: 30px; 38 | } -------------------------------------------------------------------------------- /external/leaflet/leaflet-button-control.css: -------------------------------------------------------------------------------- 1 | .leaflet-control-button { 2 | z-index: 1000; 3 | width: 26px; 4 | height: 26px; 5 | box-shadow: 0 1px 7px rgba(0,0,0,0.65); 6 | -webkit-border-radius: 4px; 7 | border-radius: 4px; 8 | } 9 | 10 | .leaflet-buttons-control-button { 11 | background: white; 12 | -webkit-border-radius: 4px; 13 | border-radius: 4px; 14 | } 15 | 16 | .leaflet-touch .leaflet-control-button { 17 | border: 4px solid rgba(0, 0, 0, 0.3); 18 | width: 30px; 19 | height: 30px; 20 | font-size: 28px; 21 | line-height: 30px; 22 | box-shadow: none; 23 | -webkit-border-radius: 10px; 24 | border-radius: 10px; 25 | } 26 | 27 | .leaflet-touch .leaflet-buttons-control-button { 28 | width: 100%; 29 | height: 100%; 30 | background: white; 31 | -webkit-border-radius: 7px; 32 | border-radius: 7px; 33 | } 34 | 35 | .leaflet-touch .leaflet-buttons-control-img { 36 | margin: 2px; 37 | } 38 | 39 | .leaflet-buttons-control-button.disabled { 40 | background: lightgray; 41 | opacity: 0.8; 42 | cursor: default; 43 | } -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var http = require("http"); 2 | var url = require("url"); 3 | var fs = require("fs"); 4 | var port = process.argv[2] || 8080; 5 | 6 | http.createServer(function(request, response) { 7 | 8 | var uri = url.parse(request.url).pathname; 9 | var filename = process.cwd() + uri; 10 | 11 | fs.exists(filename, function(exists) { 12 | if(!exists) { 13 | response.writeHead(404, {"Content-Type": "text/plain"}); 14 | response.write("404 Not Found\n"); 15 | response.end(); 16 | return; 17 | } 18 | 19 | if (fs.statSync(filename).isDirectory()) filename += '/index.html'; 20 | 21 | fs.readFile(filename, "binary", function(err, file) { 22 | if(err) { 23 | response.writeHead(500, {"Content-Type": "text/plain"}); 24 | response.write(err + "\n"); 25 | response.end(); 26 | return; 27 | } 28 | 29 | response.writeHead(200); 30 | response.write(file, "binary"); 31 | response.end(); 32 | }); 33 | }); 34 | }).listen(parseInt(port, 10)); 35 | 36 | console.log("Static file server running at => http://localhost:" + port + "/\nCTRL + C to shutdown"); -------------------------------------------------------------------------------- /external/leaflet/leaflet.ie.css: -------------------------------------------------------------------------------- 1 | .leaflet-vml-shape { 2 | width: 1px; 3 | height: 1px; 4 | } 5 | .lvml { 6 | behavior: url(#default#VML); 7 | display: inline-block; 8 | position: absolute; 9 | } 10 | 11 | .leaflet-control { 12 | display: inline; 13 | } 14 | 15 | .leaflet-popup-tip { 16 | width: 21px; 17 | _width: 27px; 18 | margin: 0 auto; 19 | _margin-top: -3px; 20 | 21 | filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); 22 | -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; 23 | } 24 | .leaflet-popup-tip-container { 25 | margin-top: -1px; 26 | } 27 | .leaflet-popup-content-wrapper, .leaflet-popup-tip { 28 | border: 1px solid #999; 29 | } 30 | .leaflet-popup-content-wrapper { 31 | zoom: 1; 32 | } 33 | 34 | .leaflet-control-zoom, 35 | .leaflet-control-layers { 36 | border: 3px solid #999; 37 | } 38 | .leaflet-control-layers-toggle { 39 | } 40 | .leaflet-control-attribution, 41 | .leaflet-control-layers, 42 | .leaflet-control-scale-line { 43 | background: white; 44 | } 45 | .leaflet-zoom-box { 46 | filter: alpha(opacity=50); 47 | } 48 | .leaflet-control-attribution { 49 | border-top: 1px solid #bbb; 50 | border-left: 1px solid #bbb; 51 | } -------------------------------------------------------------------------------- /ffGeoJsonp.php: -------------------------------------------------------------------------------- 1 | =6] { line-width: 2; } 26 | [zoom>=8] { line-width: 4; } 27 | [disputed=1] { line-dasharray: 4,4; } 28 | } 29 | // States / Provices / Subregions 30 | [admin_level>=3] { 31 | line-width: 0.2; 32 | line-dasharray: 10,3,3,3; 33 | [zoom>=8] { line-width: 0.6; } 34 | [zoom>=12] { line-width: 3; } 35 | } 36 | } 37 | 38 | // Places // 39 | 40 | #country_label_line { 41 | line-color: #324; 42 | line-opacity: 0.05; 43 | } 44 | 45 | #place_label{ 46 | [type='city'][zoom<=15] { 47 | text-name: @name; 48 | text-face-name: 'Open Sans Semibold'; 49 | text-fill: #a5a1a1; 50 | text-halo-fill: #ffffff; 51 | text-halo-radius: 1.5; 52 | text-size: 16; 53 | text-wrap-width: 100; 54 | text-wrap-before: true; 55 | [zoom>=10] { text-size: 18; } 56 | [zoom>=12] { text-size: 24; } 57 | } 58 | [type='town'][zoom<=17] { 59 | text-name: @name; 60 | text-face-name: 'Open Sans Regular'; 61 | text-fill: #a5a1a1; 62 | text-halo-fill: #ffffff; 63 | text-halo-radius: 1.5; 64 | text-size: 14; 65 | text-wrap-width: 100; 66 | text-wrap-before: true; 67 | [zoom>=10] { text-size: 16; } 68 | [zoom>=12] { text-size: 20; } 69 | } 70 | [type='village'] { 71 | text-name: @name; 72 | text-face-name: 'Open Sans Regular'; 73 | text-fill: #a5a1a1; 74 | text-halo-fill: #ffffff; 75 | text-halo-radius: 1.5; 76 | text-size: 12; 77 | text-wrap-width: 100; 78 | text-wrap-before: true; 79 | [zoom>=12] { text-size: 14; } 80 | [zoom>=14] { text-size: 18; } 81 | } 82 | [type='hamlet'], 83 | [type='suburb'], 84 | [type='neighbourhood'] { 85 | text-name: @name; 86 | text-face-name: 'Open Sans Regular'; 87 | text-fill: #a5a1a1; 88 | text-halo-fill: #ffffff; 89 | text-halo-radius: 1.5; 90 | text-size: 12; 91 | text-wrap-width: 100; 92 | text-wrap-before: true; 93 | [zoom>=14] { text-size: 14; } 94 | [zoom>=16] { text-size: 16; } 95 | } 96 | } 97 | // Water Features // 98 | 99 | #water { 100 | polygon-fill: @water; 101 | polygon-gamma: 0.6; 102 | } 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /external/leaflet/leaflet-button-control.js: -------------------------------------------------------------------------------- 1 | /** 2 | * https://gist.github.com/ejh/2935327 3 | */ 4 | 5 | L.Control.Button = L.Control.extend({ 6 | options: { 7 | position: 'topleft' 8 | }, 9 | initialize: function (options) { 10 | this._button = {}; 11 | this.setButton(options); 12 | }, 13 | 14 | onAdd: function (map) { 15 | this._map = map; 16 | var container = L.DomUtil.create('div', 'leaflet-control-button'); 17 | 18 | this._container = container; 19 | 20 | this._update(); 21 | return this._container; 22 | }, 23 | 24 | onRemove: function (map) { 25 | }, 26 | 27 | setButton: function (options) { 28 | var button = { 29 | 'text': options.text || "", //string 30 | 'iconUrl': options.iconUrl, //string 31 | 'onClick': options.onClick, //callback function 32 | 'hideText': !!options.hideText, //forced bool 33 | 'maxWidth': options.maxWidth || 70, //number 34 | 'doToggle': options.toggle, //bool 35 | 'toggleStatus': false //bool 36 | }; 37 | 38 | this._button = button; 39 | this._update(); 40 | }, 41 | 42 | getText: function () { 43 | return this._button.text; 44 | }, 45 | 46 | getIconUrl: function () { 47 | return this._button.iconUrl; 48 | }, 49 | 50 | destroy: function () { 51 | this._button = {}; 52 | this._update(); 53 | }, 54 | 55 | toggle: function (e) { 56 | if(typeof e === 'boolean'){ 57 | this._button.toggleStatus = e; 58 | } 59 | else{ 60 | this._button.toggleStatus = !this._button.toggleStatus; 61 | } 62 | this._update(); 63 | }, 64 | 65 | _update: function () { 66 | if (!this._map) { 67 | return; 68 | } 69 | 70 | this._container.innerHTML = ''; 71 | this._makeButton(this._button); 72 | 73 | }, 74 | 75 | _makeButton: function (button) { 76 | var newButton = L.DomUtil.create('div', 'leaflet-buttons-control-button', this._container); 77 | if(button.toggleStatus) 78 | L.DomUtil.addClass(newButton,'leaflet-buttons-control-toggleon'); 79 | 80 | var image = L.DomUtil.create('img', 'leaflet-buttons-control-img', newButton); 81 | image.setAttribute('src',button.iconUrl); 82 | 83 | if(button.text !== ''){ 84 | 85 | L.DomUtil.create('br','',newButton); //there must be a better way 86 | 87 | var span = L.DomUtil.create('span', 'leaflet-buttons-control-text', newButton); 88 | var text = document.createTextNode(button.text); //is there an L.DomUtil for this? 89 | span.appendChild(text); 90 | if(button.hideText) 91 | L.DomUtil.addClass(span,'leaflet-buttons-control-text-hide'); 92 | } 93 | 94 | L.DomEvent 95 | .addListener(newButton, 'click', L.DomEvent.stop) 96 | .addListener(newButton, 'click', button.onClick) 97 | .addListener(newButton, 'click', this._clicked, this); 98 | L.DomEvent.disableClickPropagation(newButton); 99 | return newButton; 100 | 101 | }, 102 | 103 | _clicked: function() { //'this' refers to button 104 | if(this._button.doToggle){ 105 | if(this._button.toggleStatus) { //currently true, remove class 106 | L.DomUtil.removeClass(this._container.childNodes[0],'leaflet-buttons-control-toggleon'); 107 | } 108 | else{ 109 | L.DomUtil.addClass(this._container.childNodes[0],'leaflet-buttons-control-toggleon'); 110 | } 111 | this.toggle(); 112 | } 113 | return; 114 | } 115 | 116 | }); -------------------------------------------------------------------------------- /map.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Fossasia Community Map 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /community_map.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 0; 3 | margin: 0; 4 | } 5 | 6 | html, body, #map { 7 | height: 100%; 8 | } 9 | 10 | /* Leaflet controls */ 11 | .leaflet-bar a, .leaflet-bar a:hover { 12 | color: #DF3A6C; 13 | } 14 | 15 | .leaflet-buttons-control-button { 16 | height: 100%; 17 | width: 100%; 18 | } 19 | /* /Leaflet controls */ 20 | 21 | 22 | /* MarkerCluster */ 23 | .marker-cluster-small, 24 | .marker-cluster-medium { 25 | background-color: rgba(212, 0, 0, 0.3); 26 | } 27 | .marker-cluster-small div, 28 | .marker-cluster-medium div { 29 | background-color: rgba(212, 0, 0, 0.7); 30 | } 31 | /* /MarkerCluster */ 32 | 33 | /* community-popup */ 34 | .community-popup h2, 35 | .community-popup h3 { 36 | font-size: 12px; 37 | margin: 0px; 38 | color: #009ee0 39 | } 40 | .community-popup .leaflet-container a { 41 | color: #009ee0; 42 | } 43 | .community-popup .nodes { 44 | margin: 10px 0px; 45 | } 46 | .community-popup .state, 47 | .community-popup .state.unknown { 48 | display: inline-block; 49 | text-size: 0.5em; 50 | color: lightgray; 51 | } 52 | .community-popup .state.up-to-date { 53 | color: green; 54 | } 55 | .community-popup .state.valid { 56 | color: orange; 57 | } 58 | .community-popup .state.outdated { 59 | color: red; 60 | } 61 | 62 | .community-popup ul.contacts { 63 | list-style: none; 64 | margin: 10px 0px 0px 0px; 65 | padding: 0px; 66 | } 67 | .community-popup ul.contacts li.contact { 68 | float: left; 69 | margin: 5px 5px 0px 0px; 70 | } 71 | .community-popup ul.contacts li.contact a { 72 | display: block; 73 | width: 30px; 74 | height: 30px; 75 | border-radius: 4px; 76 | background: url(images/contact_icons.png); 77 | background-repeat:no-repeat; 78 | background-position:right top; 79 | background-size: 30px 390px; 80 | } 81 | .community-popup ul.contacts li.contact a.button.www { 82 | background-position: 0px 0px; 83 | } 84 | .community-popup ul.contacts li.contact a.button.email { 85 | background-position: 0px -30px; 86 | } 87 | .community-popup ul.contacts li.contact a.button.phone { 88 | background-position: 0px -60px; 89 | } 90 | .community-popup ul.contacts li.contact a.button.twitter { 91 | background-position: 0px -90px; 92 | } 93 | .community-popup ul.contacts li.contact a.button.irc { 94 | background-position: 0px -120px; 95 | } 96 | .community-popup ul.contacts li.contact a.button.jabber { 97 | background-position: 0px -150px; 98 | } 99 | .community-popup ul.contacts li.contact a.button.rss { 100 | background-position: 0px -180px; 101 | } 102 | .community-popup ul.contacts li.contact a.button.facebook { 103 | background-position: 0px -210px; 104 | } 105 | .community-popup ul.contacts li.contact a.button.flickr { 106 | background-position: 0px -240x; 107 | } 108 | .community-popup ul.contacts li.contact a.button.googleplus { 109 | background-position: 0px -270px; 110 | } 111 | .community-popup ul.contacts li.contact a.button.identica { 112 | background-position: 0px -300px; 113 | } 114 | .community-popup ul.contacts li.contact a.button.vimeo { 115 | background-position: 0px -330px; 116 | } 117 | .community-popup ul.contacts li.contact a.button.youtube { 118 | background-position: 0px -360px; 119 | } 120 | 121 | .community-popup img.logo { 122 | height: 64px; 123 | 124 | } 125 | 126 | .leaflet-popup-content { 127 | width: 272px !important; 128 | } 129 | /* /community-popup */ 130 | 131 | 132 | .info { 133 | padding: 6px 8px; 134 | background: white; 135 | background: rgba(255,255,255,0.8); 136 | box-shadow: 0 0 15px rgba(0,0,0,0.2); 137 | border-radius: 5px; 138 | } 139 | .info hr { 140 | margin: 5px 0 5px; 141 | color: #777; 142 | } 143 | @media only screen and (max-width: 768px) { 144 | .info { 145 | bottom: 30px; 146 | } 147 | } 148 | 149 | iframe.embed-timeline { 150 | margin: 0; 151 | padding: 0; 152 | border: none; 153 | width: 272px; 154 | height: 112px; 155 | display: block; 156 | } 157 | .rssfeed { 158 | margin: 8px; 159 | } 160 | .rssfeed .title { 161 | color: #47a3da; 162 | font-size: 16px; 163 | } 164 | .rssfeed .description { 165 | margin-left: 16px; 166 | } 167 | 168 | .rssfeed .bloglink { 169 | display: block; 170 | } 171 | .rssfeed ul { 172 | padding-left: 15px; 173 | } 174 | .hidden { 175 | display: none; 176 | } -------------------------------------------------------------------------------- /community_map.js: -------------------------------------------------------------------------------- 1 | var FFCommunityMapWidget = function(settings, map_options, link) { 2 | 3 | var renderPopup = function (props, configs) { 4 | //console.log(props); 5 | //clean up values before rendering 6 | if (props.url && !props.url.match(/^http([s]?):\/\/.*/)) { 7 | props.url = "http://" + props.url; 8 | } 9 | if (props.email && !props.email.match(/^mailto:.*/)) { 10 | props.email = "mailto:" + props.email; 11 | } 12 | if (props.twitter && !props.twitter.match(/^http([s]?):\/\/.*/)) { 13 | props.twitter = "https://twitter.com/" + props.twitter; 14 | } 15 | if (props.irc && !props.irc.match(/^irc:.*/)) { 16 | props.irc = "irc:" + props.irc; 17 | } 18 | if (props.jabber && !props.jabber.match(/^jabber:.*/)) { 19 | props.jabber = "xmpp:" + props.jabber; 20 | } 21 | if (props.identica && !props.identica.match(/^identica:.*/)) { 22 | props.identica = "identica:" + props.identica; 23 | } 24 | 25 | function getAgeFromProperties(props) { 26 | var ageindays = -1; 27 | if (props.mtime) { 28 | ageindays = Math.round((Math.round(+new Date()/1000) - props.mtime) / (3600*24)); 29 | } 30 | return ageindays; 31 | }; 32 | 33 | function getStateFromProperties(props) { 34 | var state = 'unknown'; 35 | if (props.mtime) { 36 | var ageindays = getAgeFromProperties(props); 37 | if (ageindays < 0 || isNaN(ageindays)) { 38 | state = 'unknown'; 39 | } else if (ageindays < 2) { 40 | state = 'up-to-date'; 41 | } else if (ageindays < 7) { 42 | state = 'valid'; 43 | } else { 44 | state = 'outdated'; 45 | } 46 | } 47 | return state; 48 | }; 49 | props.age = getAgeFromProperties(props); 50 | props.state = getStateFromProperties(props); 51 | 52 | props.contacts = []; 53 | if (props.url) { 54 | props.contacts.push({ 55 | type: 'www', 56 | url : props.url 57 | }); 58 | } 59 | 60 | if (props.email) { 61 | props.contacts.push({ 62 | type: 'email', 63 | url : props.email 64 | }); 65 | } 66 | 67 | if (props.facebook) { 68 | props.contacts.push({ 69 | type: 'facebook', 70 | url : props.facebook 71 | }); 72 | } 73 | 74 | if (props.twitter) { 75 | props.contacts.push({ 76 | type: 'twitter', 77 | url : props.twitter 78 | }); 79 | } 80 | 81 | if (props.irc) { 82 | props.contacts.push({ 83 | type: 'irc', 84 | url : props.irc 85 | }); 86 | } 87 | 88 | if (props.jabber) { 89 | props.contacts.push({ 90 | type: 'jabber', 91 | url : props.jabber 92 | }); 93 | } 94 | 95 | if (props.identica) { 96 | props.contacts.push({ 97 | type: 'identica', 98 | url : props.identicy 99 | }); 100 | } 101 | 102 | if (props.googleplus) { 103 | props.contacts.push({ 104 | type: 'googleplus', 105 | url : props.googleplus 106 | }); 107 | } 108 | 109 | props.embedTimelineUrl = configs.embedTimelineUrl; 110 | //render html and return 111 | return widget.communityTemplate(props); 112 | }; 113 | 114 | var options = L.extend({ 115 | divId: 'map', 116 | geoJSONUrl: settings.geoJson || "/map/ffGeoJson.json", 117 | getPopupHTML: renderPopup, 118 | zoom: 3, 119 | maxZoom: 8, 120 | center: [46.2830,86.6700] 121 | }, options); 122 | 123 | var widget = {}; 124 | widget.map = L.map(options.divId, map_options); 125 | widget.map.setView( 126 | options.center, 127 | options.zoom 128 | ); 129 | 130 | var mapboxLayer = L.tileLayer('https://{s}.tiles.mapbox.com/v3/andibraeu.kd6ccoce/{z}/{x}/{y}.png', { 131 | attribution: '© Mapbox © OpenStreetMap Improve this map' 132 | }); 133 | 134 | var osmlayer = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', { 135 | attribution: '© OpenStreetMap contributors' 136 | }); 137 | 138 | //set default layer 139 | widget.map.addLayer(osmlayer); 140 | 141 | var clusters = L.markerClusterGroup({ 142 | spiderfyOnMaxZoom: true, 143 | showCoverageOnHover: false, 144 | maxClusterRadius: 40 145 | }).addTo(widget.map); 146 | 147 | //disable srolling 148 | if (!settings.scrollByMousewheel) { 149 | widget.map.scrollWheelZoom.disable(); 150 | } 151 | if (!settings.hideLocationButton) { 152 | var locationButton = new L.Control.Button({ 153 | iconUrl: "/map/images/location-icon.png", 154 | hideText: true, 155 | doToggle: false, 156 | onClick: function(e) { 157 | var btn = $(this); 158 | /* disable the location button visually if location permission is not granted */ 159 | widget.map.on('locationerror', function(e) { 160 | if (e.code == 1 /*PERMISSION_DENIED*/) { 161 | btn.addClass('disabled'); 162 | console.log(btn); 163 | } 164 | }); 165 | /* try to read the user location and center map there */ 166 | widget.map.locate({ 167 | setView: true, 168 | maxZoom: 8, 169 | timeout: 30000 170 | }); 171 | } 172 | }); 173 | widget.map.addControl(locationButton); 174 | } 175 | 176 | if (!settings.hideLayerControl) { 177 | var controls = L.control.layers({ 178 | "Gray": mapboxLayer, 179 | "OSM": osmlayer 180 | }).addTo(widget.map); 181 | } 182 | 183 | $.getJSON('config.json', function(configs) { 184 | $.getJSON(options.geoJSONUrl, function(geojson) { 185 | var geoJsonLayer = L.geoJson(geojson, { 186 | onEachFeature: function(feature, layer) { 187 | layer.bindPopup(options.getPopupHTML(feature.properties, configs), { minWidth: 210 }); 188 | }, 189 | filter: function(feature, layer) { 190 | if (feature.geometry.coordinates[0] && feature.geometry.coordinates[1]) { 191 | return true; 192 | } else { 193 | return false; 194 | } 195 | }, 196 | pointToLayer: function(feature, latlng) { 197 | var marker = L.circleMarker(latlng, { 198 | //title: feature.properties.name, 199 | //riseOnHover: true 200 | stroke: true, 201 | weight: 10, 202 | opacity: 0.3, 203 | color: '#d40000', 204 | fill: true, 205 | fillColor: '#d40000', 206 | fillOpacity: 0.7 207 | }); 208 | return marker; 209 | } 210 | }).addTo(clusters); 211 | 212 | //add stats info box 213 | if (!settings.hideInfoBox) { 214 | var legend = L.control({position: 'bottomleft'}); 215 | legend.onAdd = function(data) { 216 | var div = L.DomUtil.create('div', 'info'); 217 | var nodes = 0; 218 | _.each(geojson.features, function(item, key, list) { 219 | if (item.properties.nodes) { nodes += parseInt(item.properties.nodes); } 220 | }); 221 | div.innerHTML = '' + geojson.features.length + ' Orte'; 222 | div.innerHTML += '
'; 223 | div.innerHTML += '' + nodes + ' Zugänge'; 224 | return div; 225 | }; 226 | legend.addTo(widget.map); 227 | } 228 | }); 229 | 230 | //initialize underscore templating 231 | _.templateSettings.variable = "props"; 232 | widget.communityTemplate = _.template( 233 | $( "script.template#community-popup" ).html() 234 | ); 235 | 236 | widget.map.on('popupopen', function(e){ 237 | var url = configs.feedUrl 238 | + '?limit=3&source=' 239 | + e.popup._contentNode.getElementsByClassName('community-popup')[0].getAttribute('data-id'); 240 | console.log(url); 241 | $.ajax({ 242 | url: url, 243 | error: function(err) { 244 | console.log(err); 245 | }, 246 | dataType: "jsonp", 247 | success: function(data) { 248 | $data = $($.parseXML(data)); 249 | items = $data.find('item'); 250 | if (items.length > 0) { 251 | console.log('There are some items'); 252 | var rssfeed = $(e.popup._container).find('.community-popup').append('
').find('.rssfeed'); 253 | rssfeed.append(''); 254 | var rssfeedList = rssfeed.append('