Changing Region Colors in JVectorMap with a Button - jvectormap

I'm new to jvectormap, but have found it to be awesome.
I have created a map with the following characteristics. When the map loads, about 30 countries have colors applied, either Red, Yellow or Green, based on some score associated with that country (like the percentage of the population that are Duran Duran fans). The rest of the countries are just grey. (There is some interactivity on the colored regions, like tooltips and clicks.) When the map is first created, there is a line at the end:
map.series.regions[0].setValues(getColors(currentColor);
and currentColor had previously been defined:
var currentColor = "[ALL]";
so that all of the colors (red, yellow and green) are shown on the map, and that works.
Beneath the map I want to provide buttons to show just the countries of a given color, like just the red ones. When the Red button is clicked, just the red countries will be shown in red and the others shown in grey. Each color would get its own button.
This seems like it would be easy to do. I have seen the technique used here: http://jvectormap.com/examples/random-colors/, where you could click to randomly change the colors and everything else about the map (panning, zooming, etc.) remains intact. The key part is:
map.series.regions[0].setValues(generateColors());
when you have a map constructor like:
map = new jvm.Map({
(If your map constructor is like this:
$('#map').vectorMap({
then you would need to do something like this:
var mapObject = $('#map').vectorMap('get', 'mapObject');
mapObject.series.regions[0].setValues(generateColors());
)
I have tried to do exactly that, but with my own getColors(color) method:
map.series.regions[0].setValues(getColors(currentColor));
where I regenerate the array of map colors that is passed to setValues(), but there is no change to the map. I know that the array of map colors is correct, because my workaround has been to do the following when the button is pressed:
(1) change the currentColor variable
(2) empty out the map div container: $("#map").empty()
(3) redraw the map from scratch using the constructor and the call to map.series.regions[0].setValues(getColors(currentColor));
The downside of this approach is that any panning or zooming is lost when the map is redrawn from scratch. Is there any step I am missing to get the map to update when I call: map.series.regions[0].setValues()
Here is a jsfiddle showing how it does not work, unless you redraw the map from scratch: http://jsfiddle.net/msalamon/euqyfs7v/10/
In the jsfiddle, if you call "High Redraw" it shows just the Red countries, but only by redrawing.

I figured it out. See: http://jsfiddle.net/msalamon/euqyfs7v/11/.
I assumed that setValues() fully replaced the prior values, so any missing values were set to a default value. But instead setValues() only replaces the values that were included there. So when a particular color/level is selected with the button, I have changed it so that the returned array includes a default value for any region that is not included:
else
{
colors[code] = "#999999";
}

this code work for me, you just have to change values, :)
<button id="update-colors-button2">change </button>
<button id="update-colors-button">change </button>
<div id="world-map" style="width: 600px; height: 400px"></div>
<script type="text/javascript">
map = new jvm.WorldMap({
map: 'chile',
container: $('#world-map'),
series: {
regions: [{
attribute: 'fill'
}]
}
});
$(function(){
$('#update-colors-button').click(function(e){
e.preventDefault();
map.series.regions[0].clear();
map.series.regions[0].setValues({'ari' : '#328942'});
});
$('#update-colors-button2').click(function(e){
e.preventDefault();
map.series.regions[0].clear();
map.series.regions[0].setValues({'ata' : '#328942'});
});
})
</script>

Related

gsap Flip.fit svg element not moving to expected coordinates because of { duration: x }

I am confused with gsap's Flip.fit moving to coordinates.
I have a game board with 182 tiles and 182 playing tiles.
The goal
When the user clicks the bag, a random playing tile is selected and is "supposed" to move over the tile on the board.
If you change
Flip.fit(PTILE[tileArray], TILE[tileArray], {duration: 1 , scale: true});
when changing { duration: 0, ... } the move works as expected, however no animation. When duration is above zero, the final location is very random.
codepen
I'm not sure how the duration affects the final position, however, I found a way to get the positions right. That is reset the transform of your PTILE before telling GSAP to do the Flip animation.
// reset transform value
gsap.set(PTILE[tileArray], { transform: "" });
// animate with new transform value
Flip.fit(PTILE[tileArray], TILE[tileArray], {
duration: 1,
scale: true
});
My reason is that PTITLE and TITLE are placed in different <g> tags which means their transform systems are inconsistent. Plus, Flip.fit() will act like gsap.to() with new TITLE position is the to object, GSAP will try to calculate the from object from your original transforms which are already set in the SVG as transform:matrix(). This process, somehow, is messing up. So what I did is give GSAP an exact transform value for the from object, which is empty.
Ok, I found out that Inkscape stores the SVG with inline transforms that threw the animation off. I tried saving in plain or optimised, but still had no luck.
So there are two solutions.
Use SVGOMG an online SVG cleaner.
Use Affinity Designer application which can export and flatten transforms.
The key to rule out other factors is to use relative coordinates and flatten transforms.
I have included a screenshot of Affinity exporting options.
Affinity Export screenshot

Plotly.js, show tooltips outside of chart container

I need to implement a plotly.js chart on a page with a very restricted width. As a result, a tooltip is partially cut. Is it possible to cause tooltip not to be limited by plotly.js container size?
My code example at codepen: https://codepen.io/anatoly314/pen/gOavXzZ?editors=1111
//my single trace defined as following but it's better to see example at codepen
const yValue1 = [1000];
const trace1 = {
x: [1],
y: yValue1,
name: `Model 1`,
text: yValue1.map(value => Math.abs(value)),
type: 'bar',
textposition: 'outside'
};
It is, by design, not possible for any part of the chart to overflow its container.
I would say it is wrong to say that by design this is not possible! It is a bit hacky, but when you add the following lines, it shows the label outside of svg:
svg.main-svg,svg.main-svg *
{
overflow:visible !important;
}
The answer given by rokdd works. However the css selector should be more specific, otherwise it's natural that you will introduce subtle bugs (particularly if you need to scroll the content where the plotly chart is contained).
If we look at the DOM tree constructed by Plotly, we find that the tooltips are created inside the <g class="hoverlayer"></g> element (which is a direct child of one of the three <svg class="main-svg"></svg>). So that parent (that svg.main-svg element) is only one that needs to affected.
The ideal css selector in this case would be the :has selector. However it's still not supported (as of 2022): https://css-tricks.com/the-css-has-selector/
So the next simplest thing is to use a little bit of javascript right after we call Plotly.newPlot:
// get the correct svg element
var mainSvgEl = document.querySelector('#positive g.hoverlayer').parentElement;
mainSvgEl.style['overflow'] = 'visible';
Or in a more generic way (works for any chart):
Array.from(document.querySelectorAll('g.hoverlayer')).forEach(hoverEl => {
let mainSvgEl = hoverEl.parentElement;
mainSvgEl.style['overflow'] = 'visible';
});

Change "fill" of d3 bar graph

I'm learning D3 in Laravel and trying to use this color picking button:
<input type="color">
...to update the fill of the d3 bar chart at this link:
(https://bl.ocks.org/mbostock/3885304)
I have tried numerous solutions, including working with css objects and the answer here:
(Input type color styling)
I get the whole chart loaded on a page but the color picking button, which can change colors like in the answer on the other linked question, doesn't update the graph's fill. To clarify, I was sure to update "fill" and not "color". I'm new to D3 and js but not html and css. Color can be set by adding a line of the following, for example:
.attr("fill", "green");
... to the end of the code, but I want to see how to change the graph's bar fill by picking a color from the "input type" button.
Add a listener to the input for a change event. On a change, select all the bars, then set the fill to the new color.
d3.select("input")
.on("change", function() {
g.selectAll(".bar")
.style("fill", d3.select(this).property("value"))
});

Positioning multiple fixed sticky elements with Waypoints

I'm using Waypoints and their Sticky shortcut to 'stick' an element with the id stick-this to the top of the viewport once it gets scrolled past. I am having some difficulty positioning the element past another fixed element on the screen, however.
There is a <div> with a class .header which always remains fixed. I am trying to position the top of the new element to the height() of the .header element so they are 'stacked' on top of one another and both visible. This is the code I am using to accomplish this:
var sticky = new Waypoint.Sticky({
element: $('#stick-this')[0],
handler: function() {
$(".stuck").css({ "top" : $(".header").height() });
}
})
So, essentially, once the #stick-this is scrolled past, it becomes sticky with a position:fixed class and the top is dynamically determined by the height() of .header.
This works great until I scroll back up, and the top style is still applied to this element, in spite of the stuck class not being applied anymore.
So when I scroll past, the element ends up like this
<div id="stick-this" class="stuck" style="top:70px /*or whatever the height() ends up being */">
and when I scroll back up the element ends up like this with the top property still in place
<div id="stick-this" class="" style="top:70px /*I need this back to 0px */">
Is it possible to have a function called when the "sticky" is removed, so that the inline style property can be set to top:0px or something like that?
For anyone else struggling with this, I ended up dynamically writing the CSS when the sticky element's class is initiated and inserting it into the head:
var sticky = new Waypoint.Sticky({
element: $('#stick-this')[0],
offset: $('.header').outerHeight(true),
handler: function(direction) {
$("<style>")
.prop("type", "text/css")
.html("\
.stuck {\
position: fixed;\
top:" + $(".header").height() + "px;\
}")
.appendTo("head");
}
})
so, the class will be added with the correct top positioning, and once the class is removed, the top property is inherently returned back to 0px.
It's important to have the \ after each line break in the .html() portion of this code in order for it to work.

DC.js Choropleth filtering Issue

I am trying to filter data on my choropleth chart from a bargraph. Strange thing is that it is not showing correct value on selecting a bar from the accompanying bar chart.
Here is the jsfiddle: https://jsfiddle.net/anmolkoul/jk8LammL/
The script code begins from line 4794
If i select WIN004 from the bar chart, it should highlight only five states and the tooltip should reflect the values for the data. Some states are highlighted for whom WIN004 does not exist.
I changed the properties of the choropleth from
.colors(d3.scale.quantize().range(["#F90D00", "#F63F00", "#F36F01", "#F09E01", "#EDCB02", "#DDEA03", "#ADE703", "#7EE404", "#50E104", "#24DE05", "#05DB11"]))
.colorDomain([-1, 1])
To
.colors(d3.scale.linear().range(["green", "white", "red"]))
.colorDomain([-2, 0, 2])
But i get a lot of white states where its hard to discern what has been highlighted. The tool tip for some white-ed-out states show -0.00 :/
Here is the fiddle http://jsfiddle.net/anmolkoul/jk8LammL/1/
So i guess either its a problem with my color range or how my data is getting parsed.
I would ideally like to specify the data ranges in the .colorDomain based on the top and bottom values of the riskIndicator dimension. My functions are not working though. Should i use d3.max or riskIndicator.top here?
EDIT:
I got the color domain dynamic by using the min and max values but still the graph is not performing as expected? Could this be an issue with the geochoropleth chart? I further took a working geochoropleth example and ported my data to it and even that gave me the same issue of representing data incorrectly. I thoughit could be a data problem but i validated using a couple of good BI tools and their map charts displayed data correctly.
Could this be an issue with the dc choropleth?
Thank you.
Anmol
This has the same root cause as the issue in this question:
Crossfilter showing negative numbers on dc.js with no negative numbers in the dataset
In short, floating point numbers don't always cancel out to zero when added and subtracted. This "fake group" will ensure they snap to zero when they get close:
function snap_to_zero(source_group) {
return {
all:function () {
return source_group.all().map(function(d) {
return {key: d.key,
value: (Math.abs(d.value)<1e-6) ? 0 : d.value};
});
}
};
}
Added it to the FAQ!

Resources