Access subkeys in multi-dimensional javascript object

冷暖自知 提交于 2020-01-15 04:19:26

问题


This is really a javascript question, as it involves iterating through the elements of a multidimensional js object and interpreting how to use the firefox console's representation of that object.

Using d3.js/dc.js, I have two line charts. When the user clicks on a dot point in one chart, I need to identify the same point on its companion chart. Both charts use a similar X axis, a date series. The dates will correspond exactly, so the nth datapoint on chart 1 will correspond to the nth datapoint on chart2 - so when the user clicks on chart 1, I have the data from the data point they just clicked on and I want to grab the "y" data from the same datapoint on chart 2 (identifiable by having the identical "x" datapoint on the x-axis).

I am attempting to iterate through the multidimensional javascript object (representing the datapoints on the d3.js line chart #2) and I am unsure how to access the value I need.

This loop:

lineChart.on('renderlet', function(lineChart) {
    var allDots = lineChart.selectAll('circle.dot');
    allDots.on('click', function(d) {
        var dot2find = d.x;
        for (var key in allDots) { //<=== THIS LOOP
            //at the moment, I am just cycling through chart 1 to find its own date
            if (allDots.hasOwnProperty(key)) {
                console.log(allDots[key]);
                //if (this_x_val == dot2find) alert('Found It');
        }
    }
}

results in:

[circle.dot, circle.dot, circle.dot, (etc, all the 600+ data elements)]

When I look inside one of those circle objects, I see this (in Firefox console):

When I open that first __data__ object in Firefox console, I see the elements I need to access: the x (date) value:

So, in my for loop above, how do I access the x (date) value and the y (numeric) value in each of those circle.dot objects?

Code Example:

var startDate = new Date("2011-11-14T16:17:54Z");
var currDate = moment(startDate);
var cf = crossfilter([{date: startDate, quantity: 1}]);
AddData();

var timeDimension = cf.dimension(function(d){ return d.date; });
var totalGroup = timeDimension.group().reduceSum(function(d){ return d.quantity; });

var lineChart1 = dc.lineChart("#line-chart1")
    .brushOn(false)
    .width(800)
    .height(200)
    .elasticY(true)
    .x(d3.time.scale().domain([startDate, currDate]))
    .dimension(timeDimension)
    .group(totalGroup);
var lineChart2 = dc.lineChart("#line-chart2")
    .brushOn(false)
    .width(800)
    .height(200)
    .elasticY(true)
    .x(d3.time.scale().domain([startDate, currDate]))
    .dimension(timeDimension)
    .group(totalGroup);
var lineChart3 = dc.lineChart("#line-chart3")
    .brushOn(false)
    .width(800)
    .height(200)
    .elasticY(true)
    .x(d3.time.scale().domain([startDate, currDate]))
    .dimension(timeDimension)
    .group(totalGroup);

dc.renderAll();

lineChart1.on('renderlet', function(lineChart1) {
    lineChart1.selectAll('circle.dot').on('click', function(d) {
         alert('Chart One: X-axis (Date): ' +d.x+"\n\n"+ "Y-axis (Value): "+d.y);
         //How would I add the corresponding y-axis datapoint values for charts 2 and 3?
    });
});

d3.selectAll("circle.dot").on("mouseover", function(){
var thisDatum = d3.select(this).datum();
  d3.selectAll("circle.dot").filter(d=>d.x == thisDatum.x && d.y == thisDatum.y).attr("fill", "firebrick");
}).on("mouseout", function(){
	d3.selectAll("circle.dot").attr("fill", "teal")
})

for (var nn=1;nn<6;nn++){
	setTimeout(function(){
    AddData();
    lineChart1.x(d3.time.scale().domain([startDate, currDate]));
    lineChart2.x(d3.time.scale().domain([startDate, currDate]));
    lineChart3.x(d3.time.scale().domain([startDate, currDate]));
    dc.renderAll();
  },1000);
}

function AddData(){
    var q = Math.floor(Math.random() * 6) + 1;
    currDate = currDate.add('month', 1);
    cf.add( [{date: currDate.clone().toDate(), quantity: q}]);  
}
#line-chart3{margin-bottom:10px;}
.msg{font-family:Arial,Helvetica;font-size:1.2rem;color:brown;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.3/d3.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.1/crossfilter.min.js"></script>
<script src="http://dc-js.github.io/dc.js/js/dc.js"></script>
<link href="http://dc-js.github.io/dc.js/css/dc.css" rel="stylesheet"/>
<script src="http://cdnjs.cloudflare.com/ajax/libs/moment.js/2.7.0/moment.min.js"></script>

<div class="msg">Click a data point in chart 1:</div>
<div id="line-chart1"></div>
<div id="line-chart2"></div>
<div id="line-chart3"></div>
<div class="msg">Click on a data point in chart 1 -- an alert messagebox should pop-up with the corresp. datapoint values from all 3 line charts.</div>

回答1:


You don't need any kind of loop.

To get the properties associated with the clicked element, just use:

d3.select(this).datum()

In your case, if you want the x property:

d3.select(this).datum().x

Here is a demo to show you how to do it. In this demo, I'm drawing two SVGs with the same data. When you hover over one circle, it paints the circle at the other SVG which has the same x and y properties:

var data = [{x:20, y:30},
{x:40, y:60},
{x:20, y:40},
{x:10, y:90},
{x:70, y:20},
{x:60, y:90},
{x:30, y:90},
{x:90, y:10}];

draw("#svg1");
draw("#svg2");

function draw(selector){

var width = 250,
    height = 250;

var svg = d3.select(selector)
    .append("svg")
    .attr("width", width)
    .attr("height", height);

var xScale = d3.scaleLinear()
    .domain([0, 100])
    .range([30, width - 10]);

var yScale = d3.scaleLinear()
    .domain([0,100])
    .range([height - 30, 10]);
	
var circles = svg.selectAll("foo")
	.data(data)
	.enter()
	.append("circle");
	
circles.attr("r", 10)
	.attr("fill", "teal")
	.attr("cx", d=>xScale(d.x))
	.attr("cy", d=>yScale(d.y));

var xAxis = d3.axisBottom(xScale);
var yAxis = d3.axisLeft(yScale);

svg.append("g").attr("transform", "translate(0,220)")
    .attr("class", "xAxis")
    .call(xAxis);

svg.append("g")
    .attr("transform", "translate(30,0)")
    .attr("class", "yAxis")
    .call(yAxis);

}

d3.selectAll("circle").on("mouseover", function(){
var thisDatum = d3.select(this).datum();
  d3.selectAll("circle").filter(d=>d.x == thisDatum.x && d.y == thisDatum.y).attr("fill", "firebrick");
}).on("mouseout", function(){
	d3.selectAll("circle").attr("fill", "teal")
})
#svg1 {
  float: left;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="svg1"></div>
<div id="svg2"></div>



回答2:


To access a nested property, such as the 'x' property of the '__data__' property of the allDots[key] object, you would simply chain property dereferences:

allDots[key].__data__.x

OR

allDots[key]['__data__']['x']

(or any mixture thereof)



来源:https://stackoverflow.com/questions/42150936/access-subkeys-in-multi-dimensional-javascript-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!