I have tried replacing many pieces of the strings in the legend javascript to make the first color field the same color as the no value for the data. I am assuming I need to add an exception to the first rule but I can't figure it out. I started with the leaflet tuturial for choropleth maps and have gotten this far. This is the last real piece I need to get the map fully functional. Basically wanting the no data value, countries that are not colored or highlighted, and first field in legend to be grey like the map shows, not the green second value as is shown.
var legend = L.control({position: 'bottomright'});
legend.onAdd = function (map) {
var div = L.DomUtil.create('div', 'info legend'),
grades = [0, 0.00001, 0.7300001, 2.9900001, 6.700001],
labels = [],
from, to;
for (var i = 0; i < grades.length; i++) {
from = grades[i];
to = grades[i + 1];
labels.push(
'<i style="background:' + getColor(from + '1' ) + '"></i> ' +
from + (to ? '–' + to : '–43.89303638'));
} //changed '1' to get right colors on the legend but first field is still second green, not sure why??
div.innerHTML = labels.join('<br>');
return div;
};
legend.addTo(map);
This is the piece that fills the colors of the countries by value as is set up now which is functioning correctly.
function getColor(d) {
return d > 6.700001 ? '#D7191C' :
d > 2.9900001 ? '#FDAE61' :
d > 0.7300001 ? '#A6D96A' :
d > 0.00001 ? '#1A9641' :
'#E9E9E9';
}
function style(feature) {
return {
weight: 2,
opacity: 1,
color: 'white',
dashArray: '3',
fillOpacity: 0.7,
fillColor: getColor(feature.properties.UNdata_CO2_20151106_191526521_Value)//changed value from value above in blue
};
}
Here is a link to my webpage!
I added a note regarding my last change, before that it was showing two grey fields then dark green, light green, and orange without showing red for highest values...
The for loop in the legend.onAdd function is generating the colors and labels automatically from the grades array, but you can simply add another label of your own before or after the loop. Assuming that #E9E9E9 is your undefined color, it would go like this:
labels.push('<i style="background: #E9E9E9"></i> ' + 'undefined');
Put this just before the loop if you want to add the undefined field at the top of the legend, or just after the loop if you want to add it to the end. Here is an example fiddle showing this method at work with some random circle markers:
http://fiddle.jshell.net/4aqfdz1d/
Related
I have a requirement to show data labels of two graphs on the same axes.
Only when they intersect, one of the two labels won't show. This can be demonstrated below:
As you can see on the 2nd, 5th and 6th columns from the left with values 0%, 7% and 8% respectively
only the orange line values are shown but the blue column values are missing.
This is the final html of the graph after rendering:
So data-datapoint-id 142, 145 and 146 are missing from the html.
I tried using the plotArea.dataLabel.renderer function as a manipulation of what was proposed here but nothing changed, still not rendering.
Anyone encountered a similar problem? Is that a sapui5 issue or can it be fixed by manually inserting the labels into the HTML if so how?
Thanks,
Ori
Using SVG text and jQuery I managed to manually insert the labels into the top middle of the blue rectangle columns.
This is the result, not perfect but works:
and this is the code:
chart.setVizProperties({
plotArea: {
dataLabel: {
formatString: {'פחת כללי': FIORI_PERCENTAGE_FORMAT_2},
renderer: function (oLabel) {
// Create empty text node to be returned by the function such that the label won't be rendered automatically
var node = document.createElement("text");
if (oLabel.ctx.measureNames === "כמות פחת כללי") {
var kamutLabelIdx = oLabel.ctx._context_row_number;
// Use jQuery and SVG to manipulate the HTML
var kamutLabelQuery = '[data-id=\"' + kamutLabelIdx + '\"]';
var kamutColumn = $(kamutLabelQuery)[0];
// Create text element as child of the column
kamutColumn.innerHTML += "<text>" + oLabel.text + "</text>";
var labelNode = $(kamutLabelQuery += ' text');
// Set the label position to be at the middle of the column
const labelLength = 60;
const xPos = (labelLength + oLabel.dataPointWidth) / 2;
const yPos = oLabel.styles['font-size'];
labelNode.attr({
"textLength" : labelLength,
"x" : xPos,
"y" : yPos,
"font-size" : yPos
});
return node;
}
}
}
}
});
The oLabel parameter of the renderer function provides useful info about the data label to be created:
I still wonder if that's a bug with sapui5 vizframe and if there is a simpler way to do this.
Please let me know of your thoughts
I have a map with circles with different colors based on different data values. The map comes with legend boxes each of which has a range of values. I am trying to figure out how to connect these two - when a map circle is clicked, I'd like to highlight the corresponding legend box. Right now, my click function highlightLegend() looks like this and it highlights all boxes when I click a circle:
circleColorMap.forEach(function(d, i){
legend.classed("legend-highlight", function(d) {
var colorVal = circleColorMap[i].value;
return colorVal >= id.roll_pm25;
});
});`
Here is the code. I know it has something to do with line 172, but I am not sure how to approach this.
You could do this entirely by matching colors:
//highlight a legend box that corresponds to a clicked map circle
function highlightLegend(id) {
var self = d3.select(this),
rects = d3.selectAll('.symbols>svg>rect');
// clear previous selection
rects.style({'stroke': 'none', 'stroke-width': '1px'});
// loop and hightlight matches
rects.each(function(){
var r = d3.select(this);
if (r.style('fill') === self.style('fill')){
r.style({'stroke': 'red', 'stroke-width': '2px'});
}
});
};
Updated code.
With the aid of a tutorial, I've built a map of five regions of England in SVG. I've used Raphael to work with it a little. Most of it seems to be turning out alright so far:
http://codepen.io/msummers40/pen/EjExeO
I'm trying to add two more features and am just not sure how to do it. Are you able to help, please?
I'd like to: Set up the effect of the regions turning red upon clicking so that only the most recently clicked region is coloured. Can you help explain what I'm supposed to do to make this shift from region to region? At the moment, a region gets clicked and stays highlighted.
I'd like to figure out how to add more text to the bottom of the canvas. It may mean adding more information to my JSON but I'm hoping that I can add the text - about two paragraphs with a hyperlink - as a string.
Can you please let me know if you have thoughts about ways that I can do the two things outlined above?
Thank you,
Matt
The full code is on Codepen. What I've added below is a representative sample of the code.
var regions = [
{'title':"northeast_england", 'path' : "M219.02,6.876l-0.079,0.05l-0.482,0.371L218.23,7.47l-0.858,0.346h-0.008l-0.307,0.26l-0.779,0.666 l-0.104,0.278l-0.005,0.019l0.056,0.481l0.116,0.846l0.048,0.395l-0.344,1.05l-0.052-0.007v0.007l-0.635-0.081l-0.375,0.167 l-0.148,0.061v0.006l-0.1,0.328l0.178,0.338l-0.104,0.353h-0.006l-0.32,0.179l-0.056,0.031l-0.161,0.729h-0.006v0.012l-0.271,0.117 l-0.08,0.031l-0.031-0.019l-0.043,0.019l-0.327-0.167l-0.147-0.079l-0.117-0.007h-0.021l-0.216-0.006l-0.419,0.252l-0.009,0.007 l-0.004,0.302v0.605l-0.117,0.292l-0.037,0.11h-0.006v0.006h-0.025l-0.37,0.056l-0.536,0.079l-0.562,0.372l0.017,0.165l0.033,0.187 l0.481,0.788l0.023,0.038l0.008,0.013l-0.988,0.425l-0.594,0.637l-0.011,0.03l-0.187,0.637l-0.068,0.062l-0.801,0.747l-0.409,0.617 l0.062,0.414l0.068,0.414l-0.012,0.012l-0.203,0.228h-0.008l-0.123,0.05l-0.006,0.005l-0.377,0.136l-0.073,0.074l-0.13,0.143 l-0.401,0.426l-0.081,0.08l-0.055,0.055l-0.116,0.136l-0.05,0.364l0.646,0.191l0.025,0.119l0.05,0.153l-0.265,0.148l-0.26,0.155 l-0.155-0.006l-0.005,0.006l-0.309-0.006l-0.648-0.365l-0.624,0.142l-0.363,0.087l-......LOTS MORE COORDINATES...."},
THERE ARE SEVERAL OTHER SVG REGIONS/SHAPES IN THE CODEPEN LINK
var MAP_WIDTH = 600;
var MAP_HEIGHT = 600;
var mapContainer = document.getElementById("map");
var map = new Raphael(mapContainer, MAP_WIDTH, MAP_HEIGHT);
var group = map.set();
var style = {
fill: "#ddd",
stroke: "#aaa",
"stroke-width": 1,
"stroke-linejoin": "round",
cursor: "pointer"
};
regions.forEach(function(region){
group.push(
map.path(region.path).attr('title', region.title)
);
});
group.attr(style);
group.click(function(){
var slug = this.attr('title');
var title;
var fill = this.attr('fill') == 'red' ? '#1f1f1f' : 'red';
// format the title
title = slug.split('-')
.map(function(subString){
return subString[0].toUpperCase() + subString.substr(1);
})
.join(' ')
.trim();
// add some color
this.attr('fill', fill);
// do something useful
document.getElementById('title').textContent = title;
});
For the highlight thing, what I would do is have your click function as follows (pseudocode)::
on-region-clicked {
remove class "highlight" from all regions
add class "highlight" to clicked region
}
Where class "highlight" is:
.highlight {
fill: red;
}
I'll leave the actual Raphael code up to you.
http://www.highcharts.com/docs/chart-concepts/tooltip says
The tooltip appears when hovering over a point in a series.
But what if I need a custom tooltip to show at the last point even though not hover on the point to demonstrate some loading information like this:
You can set a flag on serie, which should have a label. Then in load event get last point from serie and print label by renderer.
load: function () {
var chart = this,
series = this.series,
len, lastPoint;
$.each(series, function (i, s) {
if (s.options.showLabel) {
len = s.data.length - 1;
lastPoint = s.data[len];
chart.renderer.text('Label', lastPoint.plotX + chart.plotLeft, lastPoint.plotY + chart.plotTop)
.css({
color: '#4572A7'
})
.add();
}
});
}
Example: http://jsfiddle.net/nf7ne/55/
I have a map that changes tiles based on four radio buttons. I need the popup window that appears when you roll over a tile to change as the different map layers change. I've gotten it to appear but when I switch layers the map just adds another popup window. I tried using control.removeFrom(map) but it doesn't seem to work. I think my logic may be screwed up somewhere. Here is one of the if statements:
if (two == true && black == true) {
function blkNineStyle(feature) {
return {
fillColor: getColor(feature.properties.pctBlack9000),
weight: 2,
opacity: 1,
color: '#666',
dashArray: '2',
fillOpacity: 0.9
};
}
//Tried to us this to take off the control.
info.removeFrom(map);
map.removeLayer(geojson);
geojson = L.geoJson(tracts, {style: blkNineStyle, onEachFeature: onEachFeature}).addTo(map);
var info = L.control();
info.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'info');
this.update();
return this._div;
};
info.update = function (props) {
this._div.innerHTML = '<h4>Percent White population change</h4>' + (props ? '<b>' + props.name + '</b><br />' + props.pctBlack9000 + '%' : 'Hover over a tract');
};
info.addTo(map);
}
You can see the (broken) map here.
I had this same problem myself and I just solved it.
I had to define an empty variable in the global environment (outside any functions you're using). This isn't a full script or anything, but the general idea I'm describing is below:
var info; // CREATING INFO VARIABLE IN GLOBAL ENVIRONMENT
function makeMap() {
..... geojsons, styles, other stuff ....
// REMOVING PREVIOUS INFO BOX
if (info != undefined) {
info.removeFrom(map)
}
// making current layer's info box
info = L.control();
info.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'info');
this.update();
return this._div;
};
info.update = function (props) {
this._div.innerHTML = '<h4>Data by Zip Code</h4>' + (props ?
'<b>Zip Code: ' + props.id + '</b><br />Value: ' + matchKey(props.id, meanById)
: 'Hover over a zip code');
};
info.addTo(map);
..... other stuff again ......
} // end function
I am very new to both Leaflet and javascript, so I have to say that I'm not exactly sure where to place the info.removeFrom(map) line in the code you have posted at the map link you provided, but you are on the right track with 'info.removeFrom(map)' .
I was able to problem-solve my issue with dynamic legends and info boxes by fiddling around here: http://jsfiddle.net/opensas/TnX96/
I believe you want to remove the control similarly how you added it.
In this case leaflet provides direct remove() method similar to addTo(map) method.
Example-
Whenever you want to remove the legend control use following code-
Create Control-
var legendControl = L.control({position: 'bottomleft'});
legendControl.addTo(mymap);
Remove Control-
legendControl.remove();
For more details refer/click here...
Despite the fact that this question was asked a year ago, I recently had to come up with a solution to a similar problem myself so feel as if I should share in case anybody else ends up here like I did.
The L.control() object in Leaflet isn't technically a layer, and this is why trying to add and remove it some times doesn't work in the same way as for layers.
http://leafletjs.com/reference.html#icontrol
As the L.control constructor requires you only to "create all the neccessary DOM elements for the control", the HTML content of the div itself can be updated and deleted as and when required. Thus, to make a control feature appear and disappear from the map, and instead of adding and removing the L.control object, just adjust the HTML contents of the div contained by it. An empty div would result in no control feature being shown by the map.
Thus the above snippet would become:
//construct control, initialize div
info = L.control();
info.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'info');
this.update();
return this._div;
};
if (two == true && black == true) {
function blkNineStyle(feature) {
return {
fillColor: getColor(feature.properties.pctBlack9000),
weight: 2,
opacity: 1,
color: '#666',
dashArray: '2',
fillOpacity: 0.9
};
}
//set div content to empty string; makes control disappear from map
info.getContainer().innerHTML='';
map.removeLayer(geojson);
geojson = L.geoJson(tracts, {style: blkNineStyle, onEachFeature: onEachFeature}).addTo(map);
//update content of control to make the control reappear
info.update = function (props) {
this._div.innerHTML = '<h4>Percent White population change</h4>' + (props ? '<b>' + props.name + '</b><br />' + props.pctBlack9000 + '%' : 'Hover over a tract');
};
}
//other cases...
if (two == false && black == true) {
//delete and update control where necessary
info.getContainer().innerHTML='';