Dynamic highlight on geojson data between two maps in Leaflet - javascript

I'm trying to link two sets of geojson data.
The two data sets are integrated in different "div" and therefore different maps. As can be seen on running the code below, the dynamic highlight works on both maps on hover the IDS.
However, what I want is to highlight the geojson object on the first map when hovering the corresponding geojson object from the second one. (Objects are linked by a same ID attibut).
var dat1 =({
"type" : "FeatureCollection",
"name" : "NewFeatureType",
"features" : [
{
"type" : "Feature",
"geometry" : {
"type" : "Polygon",
"coordinates" : [
[
[ 7.2518485112, 47.1390738345 ],
[ 7.2540323762, 47.1390773819 ],
[ 7.2540289251, 47.1400723508 ],
[ 7.2518450195, 47.1400688032 ],
[ 7.2518485112, 47.1390738345 ]
]
]
},
"properties" : {
"start_fid" : "504748"
}
},
{
"type" : "Feature",
"geometry" : {
"type" : "Polygon",
"coordinates" : [
[
[ 7.2565390484, 47.130837227 ],
[ 7.2633719322, 47.1308479108 ],
[ 7.2633626773, 47.1336579369 ],
[ 7.2565294346, 47.1336472526 ],
[ 7.2565390484, 47.130837227 ]
]
]
},
"properties" : {
"start_fid" : "862126"
}
}
]
});
var dat2 =({
"type" : "FeatureCollection",
"name" : "NewFeatureType",
"features" : [
{
"type" : "Feature",
"geometry" : {
"type" : "Point",
"coordinates" : [ -19.9169596449, 32.1396903724 ]
},
"properties" : {
"start_fid" : "504748"
}
},
{
"type" : "Feature",
"geometry" : {
"type" : "Point",
"coordinates" : [ -19.924214327, 32.1530002773 ]
},
"properties" : {
"start_fid" : "862126"
}
}
]
});
var mymap = L.map('mapid').setView([47.132,7.260], 15);
L.tileLayer('https://api.mapbox.com/styles/v1/mtheisen/citei76iz005f2jpac8g7ilcl/tiles/256/{z}/{x}/{y}?access_token=pk.eyJ1IjoibXRoZWlzZW4iLCJhIjoiY2l0ZWk0NTBoMDVmMDJ0bXlyNmxzZ3RnMyJ9.fErHtcHVcTsHCLMPN1ZcQg', {
attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © Mapbox',
maxZoom: 18,
id: 'mtheisen',
accessToken: 'pk.eyJ1IjoibXRoZWlzZW4iLCJhIjoiY2l0ZWk0NTBoMDVmMDJ0bXlyNmxzZ3RnMyJ9.fErHtcHVcTsHCLMPN1ZcQg'
}).addTo(mymap);
geojson1=L.geoJson(dat1, {style: style,
onEachFeature: onEachFeature
}).addTo(mymap);
var mymapid2 = L.map('mapid2',{ zoomControl:false }).setView([32.1378527851,-19.9229088608], 14);
geojson2=L.geoJson(dat2, {
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng)
},
style: style,
onEachFeature: onEachFeature
}).addTo(mymapid2);
function style(feature) {
return {
fillColor: "red",
weight: 1,
opacity: 1,
color: 'red',
dashArray: '3',
fillOpacity: 0.7
};
}
var highlightStyle = {
fillColor: "yellow",
weight: 2,
opacity: 1,
color: 'yellow',
dashArray: '3',
fillOpacity: 0.7
};
function highlightFeature(e) {
var layer = e.target;
layer.setStyle(highlightStyle);
}
function resetHighlight(e) {
geojson1.resetStyle(e.target);
}
function zoomTo(e) {
var layer = e.target;
mymap.fitBounds(layer.getBounds());
}
function onEachFeature(feature, layer) {
name = feature.properties.start_fid;
$('#mapid2').append('<li data-value="' + name + '">'+name+'</li>');
layer._leaflet_id = name;
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
click: zoomTo
});
}
var hovered_id, layer;
$('#mapid2 li').on('mouseenter', function(e){
hovered_id = $(e.target).data('value');
//console.log(hovered_id);
layer = geojson1.getLayer(hovered_id);
layer2 = geojson2.getLayer(hovered_id);
layer.setStyle(highlightStyle);
layer2.setStyle(highlightStyle);
}).on('mouseout', function(e){
geojson1.resetStyle(layer);
geojson2.resetStyle(layer2);
});
#mapid {
height: 100%;
width: 50%;
left: 0;
position: fixed;
z-index: 0;
/*top: 0;*/
}
#mapid2 {
height: 100%;
width: 50%;
right: 0;
position: fixed;
z-index: 0;
/*top: 0;*/
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.5.1/leaflet.css" rel="stylesheet"/>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.5.1/leaflet.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<div id="mapid"></div>
<div id="mapid2"></div>
<script src="script.js"></script>
</body>

Thanks to my brother for the solution!
var dat1 =({
"type" : "FeatureCollection",
"name" : "NewFeatureType",
"features" : [
{
"type" : "Feature",
"geometry" : {
"type" : "Polygon",
"coordinates" : [
[
[ 7.2518485112, 47.1390738345 ],
[ 7.2540323762, 47.1390773819 ],
[ 7.2540289251, 47.1400723508 ],
[ 7.2518450195, 47.1400688032 ],
[ 7.2518485112, 47.1390738345 ]
]
]
},
"properties" : {
"start_fid" : "504748",
"group_fid" : "1"
}
},
{
"type" : "Feature",
"geometry" : {
"type" : "Polygon",
"coordinates" : [
[
[ 7.2565390484, 47.130837227 ],
[ 7.2633719322, 47.1308479108 ],
[ 7.2633626773, 47.1336579369 ],
[ 7.2565294346, 47.1336472526 ],
[ 7.2565390484, 47.130837227 ]
]
]
},
"properties" : {
"start_fid" : "862126",
"group_fid" : "2"
}
},
{
"type" : "Feature",
"geometry" : {
"type" : "Polygon",
"coordinates" : [
[
[ 7.2585, 47.1345 ],
[ 7.2633, 47.1345 ],
[ 7.2633, 47.1366 ],
[ 7.2585, 47.1366 ],
[ 7.2585, 47.1345 ]
]
]
},
"properties" : {
"start_fid" : "99999",
"group_fid" : "2"
}
}
]
});
var dat2 =({
"type" : "FeatureCollection",
"name" : "NewFeatureType",
"features" : [
{
"type" : "Feature",
"geometry" : {
"type" : "Point",
"coordinates" : [ -19.9169596449, 32.1396903724 ]
},
"properties" : {
"start_fid" : "504748",
"group_fid" : "1"
}
},
{
"type" : "Feature",
"geometry" : {
"type" : "Point",
"coordinates" : [ -19.924214327, 32.1530002773 ]
},
"properties" : {
"start_fid" : "862126",
"group_fid" : "2"
}
}
]
});
var defaultStyle = {
fillColor: "red",
weight: 1,
opacity: 1,
color: 'red',
dashArray: '3',
fillOpacity: 0.7
};
var highlightStyle = {
fillColor: "yellow",
weight: 2,
opacity: 1,
color: 'yellow',
dashArray: '3',
fillOpacity: 0.7
};
var mymap = L.map('mapid').setView([47.132,7.260], 15);
L.tileLayer('https://api.mapbox.com/styles/v1/mtheisen/citei76iz005f2jpac8g7ilcl/tiles/256/{z}/{x}/{y}?access_token=pk.eyJ1IjoibXRoZWlzZW4iLCJhIjoiY2l0ZWk0NTBoMDVmMDJ0bXlyNmxzZ3RnMyJ9.fErHtcHVcTsHCLMPN1ZcQg', {
attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © Mapbox',
maxZoom: 18,
id: 'mtheisen',
accessToken: 'pk.eyJ1IjoibXRoZWlzZW4iLCJhIjoiY2l0ZWk0NTBoMDVmMDJ0bXlyNmxzZ3RnMyJ9.fErHtcHVcTsHCLMPN1ZcQg'
}).addTo(mymap);
geojson1=L.geoJson(dat1, {style: defaultStyle,
onEachFeature: onEachFeature
}).addTo(mymap);
var mymap2 = L.map('mapid2').setView([32.1378527851,-19.9229088608], 14);
geojson2=L.geoJson(dat2, {
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng)
},
style: defaultStyle,
onEachFeature: onEachFeature
}).addTo(mymap2);
function highlightFeature(e) {
manageHighlight(e, dat1, geojson1, highlightStyle);
manageHighlight(e, dat2, geojson2, highlightStyle);
}
function resetHighlight(e) {
manageHighlight(e, dat1, geojson1, defaultStyle);
manageHighlight(e, dat2, geojson2, defaultStyle);
}
function manageHighlight(e, dataBloc, geojson, style){
for (var i = 0; i < dataBloc.features.length; i++) {
if(dataBloc.features[i].properties.group_fid == e.target.feature.properties.group_fid){
var layer = geojson.getLayer(dataBloc.features[i].properties.start_fid);
layer.setStyle(style);
}
}
}
function onEachFeature(feature, layer) {
name = feature.properties.start_fid;
layer._leaflet_id = name;
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
});
}
#mapid {
height: 100%;
width: 50%;
left: 0;
position: fixed;
z-index: 0;
/*top: 0;*/
}
#mapid2 {
height: 100%;
width: 50%;
right: 0;
position: fixed;
z-index: 0;
/*top: 0;*/
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.5.1/leaflet.css" rel="stylesheet"/>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.5.1/leaflet.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<div id="mapid"></div>
<div id="mapid2"></div>
<script src="script.js"></script>
</body>

Related

Attribute circle-color always draws black circles

I am trying to display multiple circles on a mapbox-gl map. The color of the circles depends on the value of the aqi property. I have set interpolation of the color depending on that value. The problem is I am always getting black circles.
The circle color property:
'circle-color': [
'interpolate',
['linear'],
['get', 'aqi'],
0,
'#eee695',
50,
'#a5fc03',
100,
'#dbfc03',
200,
'#fc1c03'
],
The full function:
map.on('load', () => {
Axios.get('https://api.waqi.info/map/bounds/?latlng=41.03143,20.52421,42.20194,22.89056&token='+AQI_KEY).then(res=>{
const data = [];
res.data.data.map(station=>{
if(station.aqi!=='-'){
data.push(JSON.stringify({ "type": "Feature", "properties": {"aqi": station.aqi},
"geometry":
{
"type": "Point", "coordinates": [ station.lon, station.lat ]
}
}))
}
})
map.addSource('AQI', {
'type': 'geojson',
'data':
{
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "aqi": "aqi" } },
"features": data.map(JSON.parse)
}
});
map.addLayer(
{
'id': 'AQI-heat',
'type': 'circle',
'source': 'AQI',
'paint': {
'circle-radius': {
'type': 'exponential',
'stops': [[0, 70], [500, 70]]
},
'circle-opacity': {
'type': 'exponential',
'stops': [[-99, 0.0], [-50, 1.0]]
},
'circle-color': [
'interpolate',
['linear'],
['get', 'aqi'],
0,
'#eee695',
50,
'#a5fc03',
100,
'#dbfc03',
200,
'#fc1c03'
],
'circle-blur': 1
}
}
);
})
})
}
Even tho I have set different colors for different values, I always just get black circles.

MapBox GL Javascript - clusters - count not displaying

I'm using MapBox GL JS v1.4.1
Based on the example here: https://docs.mapbox.com/mapbox-gl-js/example/cluster/
I cannot get my cluster count to display.
I have tried replicating the MapBox example directly and also using my own data but whatever I try results in the count not displaying.
This is what I have:
<div id="map"></div>
mapboxgl.accessToken = 'ACCESS_TOKEN';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/dark-v10',
zoom: 1
});
My geoJson data:
var geoData = {
"type": 'FeatureCollection',
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [151.12100, -33.78420]
},
"properties": {
"title" : "title",
"description": "description"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [151.12100, -33.78420]
},
"properties": {
"title" : "title",
"description": "description"
}
}
]
};
Loading the map, adding geoJSON, clusters etc:
map.on('load', function() {
map.addSource("testMapData", {
type: "geojson",
data: geoData,
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50
});
map.addLayer({
id: "cluster-count",
type: "symbol",
source: "testMapData",
filter: ["has", "point_count"],
layout: {
"text-field": "{point_count_abbreviated}",
"text-font": ["Arial Unicode MS Bold"],
"text-size": 12,
"text-allow-overlap" : true
}
});
map.addLayer({
id: "clusters",
type: "circle",
source: "testMapData",
filter: ["has", "point_count"],
paint: {
"circle-color": "#f1f075",
"circle-radius": 40
}
});
map.addLayer({
id: "unclustered-point",
type: "circle",
source: "testMapData",
filter: ["!", ["has", "point_count"]],
paint: {
"circle-color": "#51bbd6",
"circle-radius": 8,
"circle-stroke-width": 1,
"circle-stroke-color": "#fff"
}
});
});
Based on the above I should get the cluster count on each of my clusters, but I only see the cluster with no count.
The console also shows no errors.
I can't determine if there's an issue with my geoJSON (it validates via the linter here: http://geojsonlint.com/)... or if the issue lies in how I have added the cluster-count layer... or somewhere else entirely.
Currently you are adding the cluster-count layer before the clusters layer so the latter is covering up the former. If you switch the order you will see both: https:///codepen.io/pj_leonard/pen/bGGgYwv?editors=1000
Update your code to the following:
map.on('load', function() {
map.addSource("testMapData", {
type: "geojson",
data: geoData,
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50
});
map.addLayer({
id: "clusters",
type: "circle",
source: "testMapData",
filter: ["has", "point_count"],
paint: {
"circle-color": "#f1f075",
"circle-radius": 40
}
});
map.addLayer({
id: "cluster-count",
type: "symbol",
source: "testMapData",
filter: ["has", "point_count"],
layout: {
"text-field": "{point_count_abbreviated}",
"text-font": ["Arial Unicode MS Bold"],
"text-size": 12,
"text-allow-overlap" : true
}
});
map.addLayer({
id: "unclustered-point",
type: "circle",
source: "testMapData",
filter: ["!", ["has", "point_count"]],
paint: {
"circle-color": "#51bbd6",
"circle-radius": 8,
"circle-stroke-width": 1,
"circle-stroke-color": "#fff"
}
});
});
Disclaimer: I work at Mapbox
If the order of the layers is correct, pay attention to text font, eg: "text-font": ["MicrosoftYaHeiRegular"]

Make a graph with cytoscape without overlaps

I use cytoscape to display a graph whose nodes can overlap.
I would like to avoid this but without changing the position y of each node.
I use the position y of a node to manage levels but the position x can vary without problem.
$.getJSON("/stratifiant/cytoscape", function(data) {
var cy = cytoscape({
container: document.getElementById('container'),
elements: data,
style: [{
selector: 'node',
style: {
shape: 'rectangle',
'background-color': 'red',
label: 'data(label)'
}
}]
});
});
JSON :
{
"nodes" : [ {
"data" : {
"x" : 0,
"y" : 0,
"id" : "120510",
"label" : "SOG.1006"
}
}, {
"data" : {
"x" : 100,
"y" : 0,
"id" : "120487",
"label" : "SOG.1005"
}
}, {
"data" : {
"x" : 200,
"y" : 0,
"id" : "120188",
"label" : "SOG.1002"
}
}, {
"data" : {
"x" : 300,
"y" : 0,
"id" : "120189",
"label" : "SOG.1003"
}
}, {
"data" : {
"x" : 400,
"y" : 0,
"id" : "120537",
"label" : "SOG.1008"
}
}, {
"data" : {
"x" : 0,
"y" : 100,
"id" : "120179",
"label" : "SOG.1000"
}
}, {
"data" : {
"x" : 100,
"y" : 100,
"id" : "120187",
"label" : "SOG.1001"
}
}, {
"data" : {
"x" : 0,
"y" : 200,
"id" : "120536",
"label" : "SOG.1007"
}
}, {
"data" : {
"x" : 100,
"y" : 200,
"id" : "120190",
"label" : "SOG.1004"
}
} ],
"edges" : [ {
"data" : {
"id" : "s120510-120487",
"source" : "120510",
"target" : "120487"
}
}, {
"data" : {
"id" : "a120179-120188",
"source" : "120179",
"target" : "120188"
}
}, {
"data" : {
"id" : "s120179-120187",
"source" : "120179",
"target" : "120187"
}
}, {
"data" : {
"id" : "a120536-120187",
"source" : "120190",
"target" : "120187"
}
}, {
"data" : {
"id" : "s120536-120190",
"source" : "120536",
"target" : "120190"
}
} ]
}
Which layout should I use with cytoscape with which options?
You could use a Layout, so you dont need set the specyfic place for each node. My recommendation for you is the dagre or breadthfirst layout.
$.getJSON("/stratifiant/cytoscape", function(data) {
var cy = cytoscape({
container: document.getElementById('container'),
elements: data,
layout:{
name:'dagre',
},
style: [{
selector: 'node',
style: {
shape: 'rectangle',
'background-color': 'red',
label: 'data(label)'
}
}]
});
});

Manipulate CZML fill property of polygon dynamically

Can properties of entities drawn in CZML be manipulated? I am trying to toggle fill property of a group of polygons at a time. I have added parent property. But it doesn't seem to work. Anyone has faced this issue before? Any help is much appreciated :)
Here is my sample code:
[
{
"id":"document",
"name":"CZML Geometries: Polygon",
"version":"1.0"
},
{
"id":"testParent",
"description":"test parent entity"
},
{
"id":"id_1",
"polygon":{
"positions":{
"cartographicDegrees":[
-95,29,0,
-95,29,0,
-95,29,0,
-95,29,0,
-95,29,0
]
},
"extrudedHeight":{
"number":4
},
"height":{
"number":0
},
"fill":false,
"parent":"testParent",
"outline":true
}
}
]
Once a CZML document has been loaded into a DataSource, you can manipulate it at runtime as a collection of Entities. Here's an example showing how to toggle the fill flags on a set of polygons. Click "Run code snippet" at the bottom of this:
var viewer = new Cesium.Viewer('cesiumContainer', {
navigationInstructionsInitiallyVisible: false, animation: false, timeline: false,
// These next 5 lines are just to avoid the Bing Key error message.
imageryProvider : Cesium.createTileMapServiceImageryProvider({
url : Cesium.buildModuleUrl('Assets/Textures/NaturalEarthII')
}),
baseLayerPicker : false,
geocoder : false,
// This next line fixes another Stack Snippet error, you may omit
// this setting from production code as well.
infoBox : false
});
var czml = [{
"id" : "document",
"name" : "CZML Geometries: Polygon",
"version" : "1.0"
}, {
"id" : "redPolygon",
"name" : "Red polygon on surface",
"polygon" : {
"positions" : {
"cartographicDegrees" : [
-115.0, 37.0, 0,
-115.0, 32.0, 0,
-107.0, 33.0, 0,
-102.0, 31.0, 0,
-102.0, 35.0, 0
]
},
"material" : {
"solidColor" : {
"color" : {
"rgba" : [255, 0, 0, 100]
}
}
},
"fill" : true,
"extrudedHeight" : 0,
"outline" : true,
"outlineColor" : {
"rgba" : [255, 0, 0, 255]
}
}
}, {
"id" : "greenPolygon",
"name" : "Green polygon",
"polygon" : {
"positions" : {
"cartographicDegrees" : [
-108.0, 42.0, 0,
-100.0, 42.0, 0,
-104.0, 40.0, 0
]
},
"material" : {
"solidColor" : {
"color" : {
"rgba" : [0, 255, 0, 100]
}
}
},
"fill" : true,
"extrudedHeight" : 0,
"outline" : true,
"outlineColor" : {
"rgba" : [0, 255, 0, 255]
}
}
}, {
"id" : "orangePolygon",
"name" : "Orange polygon",
"polygon" : {
"positions" : {
"cartographicDegrees" : [
-108.0, 25.0, 0,
-100.0, 25.0, 0,
-100.0, 30.0, 0,
-108.0, 30.0, 0
]
},
"material" : {
"solidColor" : {
"color" : {
"rgba" : [255, 100, 0, 100]
}
}
},
"fill" : true,
"extrudedHeight" : 0,
"outline" : true,
"outlineColor" : {
"rgba" : [255, 100, 0, 255]
}
}
}];
Cesium.CzmlDataSource.load(czml).then(function(dataSource) {
viewer.dataSources.add(dataSource);
viewer.zoomTo(dataSource);
document.getElementById('toggleFill').addEventListener('click', function() {
// Iterate the list of entities, looking for polygons.
var numEntities = dataSource.entities.values.length;
for (var i = 0; i < numEntities; ++i) {
var entity = dataSource.entities.values[i];
if (entity.polygon) {
// Toggle the fill flag on each polygon.
entity.polygon.fill = !entity.polygon.fill.getValue();
}
}
});
});
html, body, #cesiumContainer {
width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden;
font-family: sans-serif;
}
#toolbar { position: absolute; top: 5px; left: 8px; }
<link href="http://cesiumjs.org/releases/1.28/Build/Cesium/Widgets/widgets.css"
rel="stylesheet"/>
<script src="http://cesiumjs.org/releases/1.28/Build/Cesium/Cesium.js">
</script>
<div id="cesiumContainer"></div>
<div id="toolbar">
<button id="toggleFill" class="cesium-button" type="button">Toggle fill</button>
</div>

Leaflet Zoom Map Layer

I am looking function which enable me to loss of parts of Layer when zooming the map.
map.on('zoomend', onZoomend)
function onZoomend(feature){
if(map.getZoom()<11)
{map.addLayer("road_2"==feature.properties.density)};
if(map.getZoom()>11)
{map.removeLayer("road_2"==feature.properties.density)};
}
My GeoJson file is in panel layers:
var overLayers = [
{
group: "Layer",
collapsed: true,
layers: [
{
name: "Road",
icon: iconByName('fuel_road'),
layer: L.geoJson(road,{style: style_road})
},
File GeoJson bulid that:
var road = {
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "density" : "road_1"....
{ "type": "Feature", "properties": { "density" : "road_2"....
{ "type": "Feature", "properties": ....
Update:
Is this way have a future? What must it be improved?
function style_road(feature) {
if ("road_1" == feature.properties.density) {
return {
weight: 3,
opacity:function()
{if (zoom > 13) {opacity:0},
else (zoom < 13) {opacity:1},
},
color: 'red',
};
}
else if ("road_2" == feature.properties.density){
return {
weight: 1.5,
opacity: 1,
color: 'red',
};
}
else {
return {
weight: 0.5,
opacity: 1,
color: 'red',
};
}
}
I am not sure if I understand you right, but you want to remove a layer when zooming in and adding it when zooming out?
You just can use:
if(map.getZoom()<11){
mylayer.removeFrom(map);
}else{
mylayer.addTo(map);
}
Did I understand you right?
UPDATE:
You can iterate through the GeoJson Layer and set the fillOpacity to 0 for hiding some geoms:
var geoJsonLayer = L.geoJson(myGeoJson).addTo(map);
if(map.getZoom()<11){
geoJsonLayer.eachLayer(function(layer) {
if(layer.feature.properties.density == "road_"){
layer.setStyle({fillOpacity:0});
}
});
}

Categories