SVG Map w/ JS- Changing the states of multiple paths on hover - javascript

I'm working on a clickable SVG map using the Raphael library and referencing details from this tutorial. I've also set up a working jsfiddle here. Basically, for each state in the map, I have paths defined for the map shape itself and for a state abbreviation label—in the case of the fiddle, I'm showing one state, PA, for demonstration purposes. I have separate arrays defined for "regions" and "labels". Currently, I have the hover state working for the state shape (changing its color to a dark blue), but would also like the state abbreviation label to change to white while hovering on the state.
I have the following arrays and loop defined to handle the hover and click events for the regions (shapes), and I would like to add logic that finds the matching label and changes its fill attribute to white on hover (and reverts on mouseout):
// REGION ARRAY
var regions = {};
regions["pennsylvania"] = {href: "#", path: map.path("path here")};
// LABEL ARRAY
var labels = {};
labels["pennsylvania"] = {href: "#", path: map.path("path here")};
// REGION STYLES
var animationSpeed = 500;
var shapeStyle = {
fill: "#cdd6e9",
stroke: "#fff",
"stroke-width": 0.25,
"stroke-linejoin": "round",
cursor: "pointer"
};
var hoverStyle = {
fill: "#0a3a62"
}
// REGION LOOP
for (var regionName in regions) {
(function(region) {
region.path.attr(shapeStyle);
region.path[0].addEventListener("mouseout", function() {
region.path.animate(shapeStyle, animationSpeed);
}, true);
region.path[0].addEventListener("mouseover", function() {
region.path.animate(hoverStyle, animationSpeed);
}, true);
region.path[0].addEventListener("click", function() {
location.href = region.href;
}, true);
})(regions[regionName]);
}
Thus, in looping through the regions array, how would I adjust the script to find the matching label in the labels array and change its fill state? Thanks for any insight here.

Set the label events while you're setting your region events so you can match on the regionName. You can either use the let keyword on your for loop or you can pass the regionName or both (regions[regionName],labels[regionName]) to the immediate function as #Ian suggested.
var labelHoverStyle = { // add
fill: '#FFFFFF'
}
var labelStyle = {
fill: "#0a3a62",
stroke: "#0a3a62",
"stroke-width": 0.25,
"stroke-linejoin": "round",
cursor: "pointer"
}
Using Let
for(let regionName in regions) { // notice the variable declaration
(function (region) {
if (regionName == "district-of-columbia") {
region.path.attr(shapeStyle2);
region.path[0].addEventListener("mouseout", function() {
region.path.animate(shapeStyle2, animationSpeed);
labels[regionName].path.animate(labelStyle, animationSpeed);
}, true);
} else {
region.path.attr(shapeStyle);
region.path[0].addEventListener("mouseout", function() {
region.path.animate(shapeStyle, animationSpeed);
labels[regionName].path.animate(labelStyle, animationSpeed);
}, true);
}
region.path[0].addEventListener("mouseover", function() {
region.path.animate(hoverStyle, animationSpeed);
labels[regionName].path.animate(labelHoverStyle, animationSpeed);
}, true);
region.path[0].addEventListener("click", function() {
location.href = region.href;
}, true);
})(regions[regionName]);
}
Passing regionName or (regions[regionName],labels[regionName])
for(var regionName in regions) {
(function (region, label) { // notice the parameters
if (region.href.indexOf('district-of-columbia') > -1) {
region.path.attr(shapeStyle2);
region.path[0].addEventListener("mouseout", function() {
region.path.animate(shapeStyle2, animationSpeed);
label.path.animate(labelStyle, animationSpeed);
}, true);
} else {
region.path.attr(shapeStyle);
region.path[0].addEventListener("mouseout", function() {
region.path.animate(shapeStyle, animationSpeed);
label.path.animate(labelStyle, animationSpeed);
}, true);
}
region.path[0].addEventListener("mouseover", function() {
region.path.animate(hoverStyle, animationSpeed);
label.path.animate(labelHoverStyle, animationSpeed);
}, true);
....
})(regions[regionName], labels[regionName]); // notice the arguments
}

Related

Change color of Task Name in Google Gantt Chart

I am using Google Gantt chart to show the Project duration.
Now, the requirement is to show the entire Resource Name column in black color. Right now, they are showing in some random colors.
Below is my code related to Gantt chart option and customization functions:
var options = {
height: 600,
width: "100%",
hAxis: {
textStyle: {
fontName: ["Roboto Condensed"]
}
},
gantt: {
criticalPathEnabled: false,
labelStyle: {
fontName: ["Roboto Condensed"],
fontSize: 18,
color: '#757575'
}
}
};
var container = document.getElementById('chart_div');
var chart = new google.visualization.Gantt(container);
// monitor activity, change bar color
var observer = new MutationObserver(function (mutations) {
Array.prototype.forEach.call(container.getElementsByTagName('path'), function(bar, index) {
var barY;
if (data.getValue(index, 4) > data.getValue(index, 3)) {
bar.setAttribute('fill', '#b71c1c');
barY = bar.getAttribute('d').split(' ')[2];
Array.prototype.forEach.call(container.getElementsByTagName('rect'), function(bar) {
if (bar.getAttribute('y') === barY) {
bar.setAttribute('fill', '#f44336');
}
});
}
if (data.getValue(index, 4) < data.getValue(index, 3)) {
bar.setAttribute('fill', '#FFFF00');
barY = bar.getAttribute('d').split(' ')[2];
Array.prototype.forEach.call(container.getElementsByTagName('rect'), function(bar) {
if (bar.getAttribute('y') === barY) {
bar.setAttribute('fill', '#FFFF00');
}
});
}
});
});
observer.observe(container, {
childList: true,
subtree: true
});
Now, I am using some conditional formatting to change the bar colors if the start date is less than the end date and vice-versa. Now, when i change the mutationobserver function to show the text color as black, the conditional formatting applied to bar color is getting removed.
Can anyone please suggest any changes to the above code so that I can get this done?

How to make visible atleast one line inside line chart even though the custom legend clicked to make invisible it

I created a line chart and i have 4 lines inside it.And 4 lines are of different colors.When clicking on the corresponding colored spots(inside custom legend)the corresponding colored lines will get disappear.And if again click the line will visible.If i made all lines invisible by clicking once in all colored spots, the entire chart will get disappear. Now i want at least one line to be visible even legend clicked.That is if only one line left in line chart don't allow it to disappear while clicking the legend In my case legend is not default from highchart.It is customized .Iam attatching code here
Highcharts.chart('myChart', {
chart:{
backgroundColor: 'transparent',
//polar: true,
height: 600,
type: 'line',
//marginTop: 27 ,
margin: [60, 10, 60, 10],
events: {
load: function() {
// legend box
var div = document.createElement('div');
div.setAttribute('class', 'legend-box');
document.getElementsByClassName('chart-indicator-ano')[0].appendChild(div);
// items
var ul = document.createElement('ul');
ul.setAttribute('class', 'item-list');
div.appendChild(ul);
this.series.forEach(function(s,i) {
var li = document.createElement('li');
li.setAttribute('class', 'menu-item-' + (i + 1));
li.style.opacity = 1;
li.style.color = s.color;
ul.appendChild(li);
var sp = document.createElement('span');
sp.setAttribute('class', 'hover-item-' + (i + 1));
li.appendChild(sp);
li.addEventListener('click', function() {
this.setAttribute('data-open',"0");
s.setVisible();
});
});
}
}
},
...................
...................
...................
}
}
This code will disable series hiding when there's only one visible series left:
// on custom legend item click
var visibleSeries = 0,
hidingEnabled = true;
if (s.visible) {
chart.series.forEach(function(s) {
if (s.visible) {
visibleSeries++;
}
});
if (visibleSeries === 1) {
hidingEnabled = false;
}
}
if (hidingEnabled) {
s.setVisible();
}

SVG and mouseover

I'm a JS newbie and have converted an SVG to JS using Raphael. I'm trying to make an interactive map of the USA with mouseover effects over multiple paths and circles.
I have the states as variables with a parent variable and the cities I've visted as variables with a parent variable. Here's a snippet of my JS:
var states = rsr.set();
var connecticut = rsr.path("M877.198,184.1l-0.6-4.2l-0.8-4.4l-1.602-6L870,170.4l-21.802,4.8l0.602,3.3l1.5,7.3v8.102 l-1.102,2.3l1.802,2.101l5-3.399l3.6-3.2l1.9-2.1l0.8,0.6l2.7-1.5l5.198-1.1L877.198,184.1z").attr({fill: '#D3D3D3','stroke-width': '0','stroke-opacity': '1'});
connecticut.node.id = 'Connecticut';
states.push(connecticut);
var cities = rsr.set();
var losAngeles = rsr.circle(87, 349, 5).attr({fill: '#3F3F3F','stroke-width': '0','stroke-opacity': '1'});
cities.push(losAngeles);
I'm having trouble creating mouseover effects on both the states AND cities. I'm thinking it could have something to do with the z-index?
I've written these for loops so far but only one ever works at a time.
for (var i = 0; i <= states.length; i++) {
states[i].mouseover(function() {
this.animate({
fill: '#fff',
transform: 's1.05'
}, 200);
});
states[i].mouseout(function() {
this.animate({
fill: '#D3D3D3',
transform: 's1'
}, 200);
});
}
for (var i = 0; i <= cities.length; i++) {
cities[i].mouseover(function() {
this.animate({
r : 10,
}, 200);
});
cities[i].mouseout(function() {
this.animate({
r : 5,
}, 200);
});
}
I've tried using toFront(); and toBack(); and still can't get it to work. Any suggestions?

How to update category of a clicked bar in Highcharts?

I can update the category of x-axis in Highcharts. But I need to update the category or enable the category of clicked Bar.
You need to render all labels, but in callback hide them by setting opacity as 0. As a result we have labels (physically) but not visible.
$.each(chart.xAxis[0].ticks, function (i, tick) {
if(tick.label) {
tick.label.attr({
opacity: 0
});
}
});
Next step is catch click action on point and show/hide label.
plotOptions: {
series: {
point: {
events: {
click:function(){
var x = this.x,
chart = this.series.chart,
ticks = chart.xAxis[0].ticks,
currentLabel = ticks[x].label;
if(currentLabel.opacity === 0) {
currentLabel.attr({
opacity: 1
});
} else {
currentLabel.attr({
opacity: 0
});
}
}
}
}
}
},
Example: http://jsfiddle.net/ojjajck9/2/

highlightSeries plugin for jquery flot charts

I'm looking for help with the highlightSeries plugin made by Brian Peiris (http://brian.peiris.name/highlightSeries/). It doesn't appear to be working; I'm positive that the event is firing, because an alert test I performed earlier worked just fine, printing out $(this).text(). I'm trying to get the series on the chart to be highlighted when the user mouses over the series name in the legend (something which works perfectly fine on Mr. Peiris's website).
$('.server-chart').each(function() {
var serv = $(this).attr('id').substr(6);
var plotData = [];
//alert(serv + ": " + $.toJSON(serverStats[serv]));
for (var k in serverStats[serv].StatsByCollection) {
var outlabel = k;
var outdata = serverStats[serv].StatsByCollection[k];
plotData.push({ label: outlabel, data: outdata});
}
plotOptions = {
legend: {
container: $('#legend-' + serv),
labelFormatter: function(label, series) {
return '' + label + '';
},
noColumns: 2
},
series: {
lines: {
show: true,
fill: false
},
points: {
show: false,
fill: false
}
},
colors: colors,
grid: {
hoverable: false
},
highlightSeries: {
color: "#FF00FF"
}
}
$_plot = $.plot(this, plotData, plotOptions);
$plots.push($_plot);
$('#legend-' + serv + ' .legendLabel, #legend-' + serv + ' .legendColorBox').on('mouseenter', function () {
$_plot.highlightSeries($(this).text());
});
$('#legend-' + serv + ' .legendLabel, #legend-' + serv + ' .legendColorBox').on('mouseleave', function () {
$_plot.unHighlightSeries($(this).text());
});
});
I'm not sure what other code to put on here, so tell me if you need more; the charts are all working fine, this is just the part of the ready function setting up all of the plots and their options inside the placeholders.
Also, there's a couple of classes attached to the labels that are extraneous; I was trying different things to get this stuff to work.
The plugin requires a patched version of flot to work (it introduces a public drawSeries method). The last patched version is for an older version of flot (0.7).
With that said, I wouldn't use this plugin. If you just want to highlight a series on legend mouseover it's pretty simple.
$('#legend .legendLabel, #legend .legendColorBox').on('mouseenter', function() {
var label = $(this).text();
var allSeries = $_plot.getData();
// find your series by label
for (var i = 0; i < allSeries.length; i++){
if (allSeries[i].label == label){
allSeries[i].oldColor = allSeries[i].color;
allSeries[i].color = 'black'; // highlight it in some color
break;
}
}
$_plot.draw(); // draw it
});
$('#legend .legendLabel, #legend .legendColorBox').on('mouseleave', function() {
var label = $(this).text();
var allSeries = $_plot.getData();
for (var i = 0; i < allSeries.length; i++){
if (allSeries[i].label == label){
allSeries[i].color = allSeries[i].oldColor;
break;
}
}
$_plot.draw();
});
See example here.

Categories

Resources