Unable to identify colours on leaflet - javascript

var non_tfl_lines_JubileetoIlford = L.geoJson(non_tfl_lines_JubileetoIlford, {
pointToLayer: function(feature, latlng) {
switch (feature.geometry.type) {
case 'LineString': return new L.polyline(latlng, {
color: feature.properties.color
});
case 'Point': return new L.Circle(latlng, 400, {
color: getColor(feature.properties.relief_JtI)});
}
onEachFeature: popup
}
}).addTo(map);
For some reason the colour of the polyline is the default colour and not the one specified. In same time it gives me the correct colours of the circles. Any idea what could be wrong?

As you see in the documentation, pointToLayer callback is for GeoJSON points; this is why your code works for points.
If you want to set the color with information from your geojson structure, the best is to have a color property ...
{
"type": "Feature",
"properties": {
"color": "#ff7800"
},
"geometry": {
"type": "LineString",
"coordinates": [
And use it in the style callback
L.geoJson(non_tfl_lines_JubileetoIlford, {
style: function(feature) {
if(feature.geometry.type == "LineString") {
return {
"color": feature.properties.color,
"weight": 5,
"opacity": 0.65
};
}
}
Here is an example http://jsfiddle.net/FranceImage/myxd1ooy/

Related

How do I extrude a geojson polygon in harp Gl using purely Javascript?

we are experimenting with harp gl to replace a custom building tool for geojson. I want to visualize my polygons with the extruded polygon technique. Coming from MapBox GL I was able to have two properties on my geojson feature.properties called height and base height. So I have Some GeoJson that I'm using for testing. I cannot seem to get the extruded polygon to show up. I am writing this in Javascript, using the https://unpkg.com/##here/harp.gl/dist/harp.js source. I am able to render points on my map. Just not these polygons. (ignore the walls for now, I want to see the floors first)
What I would like to achieve (This is how it looks in MapBox):
function for reseting building data:
resetBuildings: function (data) {
const dataProvider = new harp.GeoJsonDataProvider("buildings", data);
var geoJsonBuildingDataSource;
if (this.mapView.getDataSourceByName("buildings") == null) {
geoJsonBuildingDataSource = new harp.VectorTileDataSource({
dataProvider,
name: "buildings",
styleSetName: "geojson",
});
this.mapView.addDataSource(geoJsonBuildingDataSource);
}
else { geoJsonBuildingDataSource = this.mapView.getDataSourceByName("buildings") }
const theme = {
styles: {
geojson: this.getStyleSet()
},
};
geoJsonBuildingDataSource.setTheme(theme);
My StyleSet definition(?):
getStyleSet: function(){
return [
{
when: ["==", ["geometry-type"], "Polygon"],
technique: "extruded",
renderOrder: 1000,
constantHeight: true,
color: "#FF0000",
transparent: false,
opacity: 0.8,
lineWidth: 1,
lineColor: "#003344",
height: ["number", ["get", "base_height"], 10],
floorHeight: ["number", ["get", "base_height"], 0]
}
];
}
My test GeoJson:
{"type":"FeatureCollection","features":[{"id":"6223a3f0-2835-4ad8-8456-3ccbefc0d19c","type":"Feature","properties":{"level":1,"name":"base","height":0.2,"base_height":0,"color":"grey","message":"","coordinates":null},"geometry":{"type":"Polygon","coordinates":[[[174.81047388530345,-36.909499151794726],[174.81050337403076,-36.90965937993286],[174.8107788255581,-36.909634193592254],[174.8107567090126,-36.9094734295196],[174.81047388530345,-36.909499151794726]]]}},{"id":"a0583d91-f038-4d6e-8e32-99db806982bc","type":"Feature","properties":{"level":0,"name":"Wall","height":5,"base_height":0.2,"color":"blue","message":"","coordinates":null},"geometry":{"type":"LineString","coordinates":[[174.8104752256997,-36.909499687675165],[174.81075804940883,-36.90947396540121],[174.81078083615245,-36.90963526535126],[174.81050337403076,-36.909658844053574],[174.81049399125453,-36.909598825525144],[174.81050337403076,-36.909658844053574],[174.81078083615245,-36.90963526535126],[174.81075804940883,-36.90947396540121],[174.8104752256997,-36.909499687675165]]}},{"id":"ec219095-8891-440b-9fea-2db9cf74c7e0","type":"Feature","properties":{"level":0,"name":"Wall","height":5,"base_height":0.2,"color":"blue","message":"","coordinates":null},"geometry":{"type":"LineString","coordinates":[[174.8104752256997,-36.90950022355558],[174.81048594887454,-36.909558634520565],[174.8104752256997,-36.90950022355558]]}},{"id":"628a2754-c1b6-43a4-975b-eb45084d3853","type":"Feature","properties":{"level":1,"name":"base","height":0.2,"base_height":0,"color":"grey","message":"","coordinates":null},"geometry":{"type":"Polygon","coordinates":[[[174.8106367829821,-36.909648805405354],[174.81078191913713,-36.90963279956284],[174.81078129891483,-36.909646601064004],[174.81085540198825,-36.90961396183521],[174.81089173813234,-36.90967024159831],[174.81086324249378,-36.90968392941179],[174.8108926788683,-36.909721493301554],[174.8109264286474,-36.90971335389515],[174.81098518665493,-36.909814312925626],[174.81076392360183,-36.90990054860199],[174.81063578104482,-36.90969921056885],[174.8106354709525,-36.909651008673336],[174.8106367829821,-36.909648805405354]]]}},{"id":"d5a1c90d-295e-463b-9530-7643e411ca38","type":"Feature","properties":{"level":0,"name":"Wall","height":5,"base_height":0.2,"color":"blue","message":"","coordinates":null},"geometry":{"type":"LineString","coordinates":[[174.81063687126533,-36.909700434854784],[174.81076318373476,-36.90989889886059],[174.8109779359279,-36.90981381148965],[174.81076318373476,-36.90989889886059],[174.81063687126533,-36.909700434854784]]}}]}
Thank you in advance!
I figured it out. I was using the wrong kind of data source. I needed to use a FeaturesDataSource. My style set definition was also wrong, and I was not setting it to the map theme.
How I now initialize map:
this.styleSet = this.getStyleSet();
hereMapsHelper.geoJsonObj = JSON.parse(GeoJson);
const canvas = document.getElementById(mapContainerId);
var options = {
canvas,
theme: {
extends: "https://unpkg.com/#here/harp-map-theme#latest/resources/berlin_tilezen_base.json",
styles: {
geojson: this.styleSet,
}
}
}
var map = new harp.MapView(options);
function for buildings:
resetBuildings: function (data) {
var geoJsonBuildingDataSource;
if (this.mapView.getDataSourceByName("buildings") != null) {
var existingBuildingDataSource = this.mapView.getDataSourceByName("buildings")
this.mapView.removeDataSource(existingBuildingDataSource);
}
geoJsonBuildingDataSource = new harp.FeaturesDataSource({
geojson: data,
name: "buildings",
styleSetName: "geojson",
maxGeometryHeight: 30000
});
this.mapView.addDataSource(geoJsonBuildingDataSource);
},
Function to define style set:
getStyleSet: function () {
const color = new THREE.Color("blue");
const colorString = "#" + color.getHexString();
return [
{
description: "geoJson property-based style",
when: ["==", ["geometry-type"], "Polygon"],
technique: "extruded-polygon",
renderOrder: 1000,
height: ["number", ["get", "base_height"], 10],
floorHeight: ["number", ["get", "base_height"], 0],
attr: {
color: colorString,
transparent: true,
opacity: 0.8,
boundaryWalls: false,
constantHeight: true,
lineWidth: 1,
lineColor: "#003344",
emissive: colorString,
emissiveIntensity: 0.45
},
},
{
description: "geoJson property-based style",
when: ["==", ["geometry-type"], "Point"],
technique: "circles",
renderOrder: 2000,
color: "#00FF00",
size: 15,
}
];
},
This only renders floors, as I havent defined the style for the walls yet. But its progress!

TypeError when styling geojson elements in leaflet.js

I'm trying to use leaflet.js to create a choropleth map. I started with a geojson of countries and added additional information from API data. The geojson now looks like:
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "ADMIN": "Aruba", "ISO_A3": "ABW", "HW_COUNT": 0, "ISO_A2": "AW" }, "geometry": { "type": ...
And is loaded into variable combined_jsons.
This code successfully loads the map with the geojson:
var mymap = L.map('mapid').setView([51.505, -0.09], 2);
L.geoJSON(combined_jsons).addTo(mymap)
Unfortunately, I am having trouble with the next step, which is styling the countries based on HW_COUNT.
I used this example to try and structure my styling correctly with this code:
L.geoJSON(combined_jsons, {
style: function(feature){
var fillColor,
hw_count = combined_jsons.features.properties.HW_COUNT;
if (hw_count > 5) fillColor = "#006837";
else if (hw_count > 0) fillColor = "#78c679";
else fillColor = "#f7f7f7";
return { color: "#999", weight: 1, fillColor: fillColor, fillOpacity: .6 };
}
} ).addTo(mymap);
That returns the Uncaught TypeError: combined_jsons.features.properties is undefined error. I can successfully console.log(combined_jsons.features[0].properties.HW_COUNT);, but adding the [0] seems to go against the point of the styling, which I assume iterates through every element?
Is there a better way of structuring this layer?
thanks
You need to get the property of the current feature and not from all features, also check if the property exists:
style: function(feature){
var fillColor,
hw_count = 0;
if(feature && feature.properties && feature.properties.HW_COUNT){
hw_count = feature.properties.HW_COUNT;
}
if (hw_count > 5) fillColor = "#006837";
else if (hw_count > 0) fillColor = "#78c679";
else fillColor = "#f7f7f7";
return { color: "#999", weight: 1, fillColor: fillColor, fillOpacity: .6 };
}
Based on the suggestions of #IvanSanchez and #Falke-Design, I updated the code as follows:
L.geoJSON(combined_jsons, {
style: function(feature){
var fillColor,
hw_count = feature.properties.HW_COUNT;
if (hw_count > 5) fillColor = "#006837";
else if (hw_count > 0) fillColor = "#78c679";
else fillColor = "#f7f7f7";
return { color: "#999", weight: 1, fillColor: fillColor, fillOpacity: .6 };
}
} ).addTo(mymap);
The change to the fourth line from hw_count = combined_jsons.features.properties.HW_COUNT; to hw_count = feature.properties.HW_COUNT; did the trick.
If I had not made sure to add a HW_COUNT entry for every country (even when the value was 0), I would have used the #Falke-Design code in order to first verify that the entry existed.

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.

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});
}
});
}

Highcharts determine if text is outside of data point

I’m wondering if there is a way to distinguish the data point being inside or outside of a bar.
Basically, with the chart below
I want the text 9178 to be in a colour I generate (because it’s inside a bar)
I want the rest of the numbers to be black (because they are outside of bars)
I’m wondering if the API provides something that I can use programmatically to decide what colour to use.
e.g. If a data point has a method isOverflow() that I can call, then I can set the colour to black if it returns true.
created on jsfiddle: https://jsfiddle.net/Mingzilla/pjqhqn4u/6
var generateColor = function(item) {
var lightColor = "#DADADA";
var color = new Highcharts.Color(item.point.color).rgba;
var isLightBg = color[0] + color[1] + color[2] > 384;
return isLightBg ? '#000000' : lightColor;
};
$(function() {
$('#container').highcharts({
title: {
text: 'I want data point inside a bar to be my colour, and outside to be black'
},
chart: {
type: 'column'
},
xAxis: {
categories: ['Car Insurance',
'Life Insurance',
'Pet Insurance'
]
},
plotOptions: {
series: {
dataLabels: {
enabled: true,
overflow: 'justify',
style: {
fontWeight: 'normal',
textShadow: 'none'
},
formatter: function() {
var item = this;
return '<span style="fill:' +
generateColor(item) + '">' +
(item.point.formattedValue || item.point.y) +
'</span>';
}
}
}
},
series: [{
"color": "#666699",
"name": "North",
"data": [{
"color": "#666699",
"name": "Car Insurance",
"y": 9178
}, {
"color": "#666699",
"name": "Life Insurance",
"y": 4518
}, {
"color": "#666699",
"name": "Pet Insurance",
"y": 1450
}]
}, {
"color": "#663366",
"name": "South",
"data": [{
"color": "#663366",
"name": "Car Insurance",
"y": 2129
}, {
"color": "#663366",
"name": "Life Insurance",
"y": 1066
}, {
"color": "#663366",
"name": "Pet Insurance",
"y": 374
}]
}]
});
});
Defaulty the color is based on contrast or declared single color. But you can return a color (i.e black) for all datalabels. Then catch load / redraw events in the chart object to interate on all dataLabels. Inside each of them, there is information about position and verticalAlign, which can be used to check where label is. If this is top, apply your lightColor by css() method.
var lightColor = "#DADADA";
function datalabelColor() {
var chart = this,
series = chart.series,
each = Highcharts.each,
dL;
each(series, function(serie, i) {
each(serie.data, function(p, j) {
dL = p.dataLabel;
if(dL.alignOptions.verticalAlign === 'top') {
dL.css({
color: lightColor
});
}
});
});
}
Example:
- https://jsfiddle.net/mys5k9ty/
Let me know if you have any further questions.

Categories