how to use array within array in data function of d3 - javascript

I want to create rectangles on the screen using the x1,y1,x2,y2 coordinates in d3. the structure of my data is as below,
[
{
"tname":abc,
"thours":200,
"x1":10,
"y1":10,
"x2":10,
"y2":10,
"ttask":[
{
"pname":one,
"phours":200,
"pteam":abc,
"px1":10,
"py1":10,
"px2":10,
"py2":10
},
{
"pname":two,
"phours":200,
"pteam":abc,
"px1":10,
"py1":10,
"px2":10,
"py2":10
}
]
},
{
"tname":xyz,
"thours":200,
"x1":10,
"y1":10,
"x2":10,
"y2":10,
"ttask":[
{
"pname":one,
"phours":200,
"pteam":xyz,
"px1":10,
"py1":10,
"px2":10,
"py2":10
},
{
"pname":two,
"phours":200,
"pteam":xyz,
"px1":10,
"py1":10,
"px2":10,
"py2":10
}
]
}
]
in above data I want to create rectangle using px1, px2, py1,py2.
I tried multiple combinations of using data function but i could not achieve it
var group = svg.selectAll('g')
.data(teams);
var rect = group.selectAll("rect")
.data(function(d,i){
return d.ttask;
});
this is my last try. I am not sure how the data function treats the my input.
Please help me to understand how can I draw rect for each ttask array element using the data function.

Related

How to highlight a line when mouse over it in observable plot using JavaScript?

My chart looks like so::
and here is my code:
linePlot = Plot.plot({
marginLeft: 60, // space to the left of the chart
y: {
type: "log", // set the type
},
marks: [
Plot.line(data, {x: "timestamp", y: "views", z:"artist", title: d=>`${d.artist}`,})
]
})
I want to highlight or change color of each line when the mouse is over it.
The easiest thing to do would be to attach a pointerenter event to the lines. Since you're using Observable, to use D3 to handle that process. Here's what it looks like on Observable:
https://observablehq.com/d/2e1daf099a7aaaea
To be clear, you are using two libraries: D3 and Plot, both of which are automatically available on Observable. You can use them both in vanilla Javascript pretty easily, though:
// Manufacture some data
let pt_lists = d3.range(10).map(() => {
let cur = 0;
return d3.range(1000).map(function(x) {
let step = 2 * d3.randomInt(0, 2)() - 1;
cur = cur + step;
return [x, cur];
});
});
// Plot the data
let plot = Plot.plot({
marks: pt_lists.map((pts) => Plot.line(pts, {
strokeWidth: 2
}))
});
// Here's where the action is.
// We use d3 to select all the paths in the plot
d3.select(plot)
.selectAll("path")
// React when the pointer hovers over the path.
.on("pointerenter", function() {
d3.select(plot).selectAll("path").attr("opacity", 0.2);
d3.select(this).attr("opacity", 1);
});
// Reset the appearance when the pointer leaves the SVG
d3.select(plot).on("pointerleave", function() {
d3.select(plot).selectAll("path").attr("opacity", 1);
});
// Attach the plot to the container DIV
d3.select('#chart').append(() => plot)
<script src="https://cdn.jsdelivr.net/npm/d3#7"></script>
<script src="https://cdn.jsdelivr.net/npm/#observablehq/plot#0.6"></script>
<div id="chart" style="width: 600px; height: 400px"></div>
It might also be possible to do the interaction in css:
d3.select(chart)
.append("svg:style")
.text(`
path:hover {stroke-width: 2px;}
`)

Add custom parameter to info.contentsFunction

I need to be able to add some custom info to the pie.info.contentsFunction in Zoomcharts. I have multiple charts on the page, each one created like so...
var pc = new PieChart({
pie: {
innerRadius: 0.5,
},
container: chartContainer1,
area: { height: 500 },
data:chartData,
toolbar: {
"fullscreen": true,
"enabled": true
},
info: {
contentsFunction: boomChartTT
}
});
In the "boomChartTT" function I need to know what chart is being hovered upon. I'd like to be able to do something like this...
info: {
contentsFunction: boomChartTT(i)
}
...where 'i' is the index of the chart.
The reason I need to know the chart index is because I have some other data saved in an indexed array for each chart. The index of the chart matches the index of the data.
EXAMPLE: if user hovers on a slice in chart2 I'd want to pass '2' to the boomChartTT function so I can access the totals data for that chart (say, totalsData[2]).
I've done this in the past with other chart libraries by simply adding a data attribute to the chart container to give me the index like so...
<div id="chartContainer1" data-index="1"></div>
...and then I'm able to access the chartContainer from the hover function (contentsFunction) and then get that index.
I don't want to add the totals data to the actual chart data because I'd have to add it to each slice which is redundant.
Is there a way to do this?
Please let me know if my post is unclear.
EDITED TO ADD:
I don't think it matters but here is the boomChartTT function:
function boomChartTT(data,slice){
var tt="<div class=\"charttooltip\">";
if(data.name==="Others" || data.name==="Previous"){return tt+=data.name+"</div>";}
//var thisData=dataSearch(totalsData[i],"REFERRINGSITE",data.id);
tt+="<h5 class=\"strong\">"+data.id+"</h5>"+oHoverTable.render(thisData)+"</div>";
return tt;
}
The commented line is where I would need the index (i) to to get the correct totalsData.
SOLVED. I simply added "chartIndex" to the data like so...
for(var i=0;i<r.length;i++){
var thisDataObj ={
id:r[i].REFERRINGSITE,
value:r[i].PCTOFSALES,
name:r[i].REFERRINGSITE,
chartIndex: arguments[1],//<----- arguments[1] is the chart index
style: { expandable: false, fillColor: dataSearch(dataRSList,"REFERRINGSITE",r[i].REFERRINGSITE)[0].COLOR }
};
chartData.preloaded.subvalues.push(thisDataObj);
}
Then in the boomChartTT function...
function boomChartTT(data,slice){
var tt="<div class=\"charttooltip\">";
if(data.name==="Others" || data.name==="Previous"){return tt+=data.name+"</div>";}
var thisData=dataSearch(totalsData[data.chartIndex-1],"REFERRINGSITE",data.id);
tt+="<h5 class=\"strong\">"+data.id+"</h5>"+oHoverTable.render(thisData)+"</div>";
return tt;
}
I feared that adding custom fields to the chart data would break the chart (which I believe I've experienced with other libraries). So, there you go.

Display data from JSON on hover of SVG path?

I am working on a SVG map of the US and I would like to display a small info window pointing to each state when you hover over it that shows the population, similar to the info windows on Google Maps. Unfortunately I'm not very good with JSON so I'm stuck at this point.
Currently I have the SVG map of the US up and the fill color changes on hover via CSS. I have a sample group of JSON data and wondering how I can incorporate it into my map so that it displays the population on hover.
Here's an example of the JSON data:
[
{
"id":"AL",
"population":"253045"
},
{
"id":"AR",
"population":"1529923"
},
{
"id":"AZ",
"population":"352416t"
}
]
There's quite a bit of HTML due to the SVG paths, so I won't paste that here, but you can see what I have so far on this JSFiddle
To get info about the hovered state, first put your info in an array, so it can be accessed:
var info = [
{
"id":"AL",
"population":"253045"
},
{
"id":"AR",
"population":"1529923"
},
{
"id":"AZ",
"population":"352416t"
}
]
Then you can get info from your array by filtering it by the id key using filter:
info.filter(function(state) {return state.id === currState});
Here is an example where you get the population of the hovered state:
$('path').hover(function() {
var currState = $(this).attr('id');
var currStateInfo = info.filter(function(x) {return x.id == currState});
if (currInfo[0])
console.log(currInfo[0].population);
});
Here is a working example: https://jsfiddle.net/4tasLo6k/

How to color Google Column Chart's every bar differently and keep them as it is

Though I have successfully colored the bars of google chart individually but not able to keep them when we hover mouse over it. It is getting reset back to blue(which is default).
Here is the jsfiddle of what I have done jsfiddle.
I tried to control the hover behaviour with multiple ways like below.
This I am keeping outside (document.ready) but inside script tag.
1)
$('#chart_div').hover(
function() {
$('#chart_client').hide(); // chart_client is another google chart div.
}, function() { // just for testing I was doing hide/show of that.
$('#chart_client').show();
}
);
2)
$("#chart_div").on({
mouseenter: function () {
$('#chart_client').hide();
},
mouseleave:function () {
$('#chart_client').show();
}
},'rect');
3)
google.visualization.events.addListener('#chart_div', 'ready', function () {
$('#chart_div rect').mouseover(function (e) {
alert('hello');
});
});
I must be doing something wrong, could you please tell me what and where.
I solved it using below code. Earlier I was trying to create charts using dynamically adding rows into chart(please visit my jsfiddle) but with this below approach I am first preparing data(converting dynamic to static) and adding that static data in to chart's 'arrayToDataTable' method.
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawUserKeywordChart);
function drawUserKeywordChart() {
var val = 'Tax:47;Finance:95;Awards:126;Bank:137;Debt:145;';
var length = val.length;
var array = [];
//preparing data
while(length>0){
var sepAt = val.indexOf(";");
var value = parseInt(val.substring(val.indexOf(":")+1, sepAt));
array.push(val.substring(0, val.indexOf(":")));
array.push(value);
val = val.substring(val.indexOf(";")+1, length);
length = val.length;
}
var data = google.visualization.arrayToDataTable([
['Keyword', 'Occurences', { role: 'style' }],
[array[0], array[1], '#8AA3B3'],
[array[2], array[3], '#A9B089'],
[array[4], array[5], '#848C49'],
[array[6], array[7], '#44464A'],
[array[8], array[9], '#704610'],
]);
var options = {
title: 'Keyword Matches',
width: 660,
height: 450,
titleTextStyle:{bold:true,fontSize:20},
legend:{position:'none'}
};
var chart = new google.visualization.ColumnChart(document.getElementById('chart_keyword1'));
chart.draw(data, options);
}
Please advice if you find anything wrong here or you have better approach than this.

How can we create an onclick event for a d3 data map?

I am building a d3 data map:
http://datamaps.github.io/
When I click on a country, I want the border to change color. How do I assign an onclick event to a d3 path using datamaps? The svg paths seem to lack a CSS ID as well as any identifying hook.
You can use JQuery "done:function" and specify on("click") as below :
done: function(datamap) {
datamap.svg.selectAll('.datamaps-subunit').on('click', function(geography) {
alert(geography.properties.name);
});
}
Refer to https://github.com/markmarkoh/datamaps for further detail.
You'll need both the done call back as well as the updateChoropleth function. For example, to turn each country black you would do:
done: function(datamap) {
datamap.svg.selectAll('.datamaps-subunit').on('click', function(geography) {
var m = {};
m[geography.id] = '#000000';
datamap.updateChoropleth(m);
});
}

Categories