使用D3创建包含线条的交互式图表(缩放/平移)

时间:2016-06-21 09:38:27

标签: javascript d3.js

我刚刚开始使用d3,而js中的相对新手仍在使用。我尝试用线条代替烛台来应用安迪的example。似乎我的函数redrawChart()无法正常工作。缩放/平移工作但缩放/平移不与我的线路相互作用。

完整代码:

<!DOCTYPE html><meta charset="utf-8">
<style>

#cumul body {
  font: 10px sans-serif;
}

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.x.axis path {
  display: none;
}

.line {
  fill: none;
  stroke: steelblue;
  stroke-width: 1.5px;
}

.grid .tick {
    stroke: lightgrey;
    stroke-opacity: 0.7;
    shape-rendering: crispEdges;
}
.grid path {
    stroke-width: 0;
}
.navigator .data {
    fill: lightgrey;
    stroke-width: 0px;
}

.navigator .line {
    fill: none;
    stroke: darkgrey;
    stroke-width: 1px;
}
.navigator .viewport {
    stroke: grey;
    fill: black;
    fill-opacity: 0.2;
}
.chart .overlay {
    stroke-width: 0px;
    fill-opacity: 0;
}
</style>

<html>
<head>
<!--<script src="d3.min.js" type="text/JavaScript"></script>-->
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body>
    <div id="cumul">
        <script>

            var margin = { top: 30, right: 50, bottom: 50, left: 50 },
                width = 960 - margin.left - margin.right,
                height = 500 - margin.top - margin.bottom;

            var navWidth = width,
                navHeight = 100 - margin.top - margin.bottom;

            var formatDate = d3.time.format("%Y-%m-%d").parse;

            var plotChart = d3.select("body").classed('chart', true).append('svg')
                .attr('width', width + margin.left + margin.right)
                .attr('height', height + margin.top + margin.bottom)
                .append('g')
                .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

            var plotArea = plotChart.append('g')
                .attr('clip-path', 'url(#plotAreaClip)');

            plotArea.append('clipPath')
                .attr('id', 'plotAreaClip')
                .append('rect')
                .attr({ width: width, height: height });

            var navChart = d3.select("body").classed('chart', true).append('svg')
                .classed('navigator', true)
                .attr('width', navWidth + margin.left + margin.right)
                .attr('height', navHeight + margin.top + margin.bottom)
                .append('g')
                .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

            d3.json("json.json", function (error, data) {
                if (error) throw error;
                console.log(data)
                data.forEach(function (d) {
                    d.date  = formatDate(d.date);
                    d.value = +d.value;
                    d.valueBchk = +d.valueBchk;
                    d.valueIdx = +d.valueIdx;
                })


                var minN = d3.min(data, function (d) { return d.date; }).getTime(),
                    maxN = d3.max(data, function (d) { return d.date; }).getTime();
                var minDate = new Date(minN - 8.64e7),
                    maxDate = new Date(maxN + 8.64e7);
                var yMin = d3.min(data, function (d) { return Math.min(d.value, d.valueBchk, d.valueIdx); }),
                    yMax = d3.max(data, function (d) { return Math.max(d.value, d.valueBchk, d.valueIdx); });

                var xScale = d3.time.scale()
                    .domain([minDate, maxDate])
                    .range([0, width]),
                    yScale = d3.scale.linear()
                    .domain([yMin, yMax]).nice()
                    .range([height, 0]);

                var navXScale = d3.time.scale()
                    .domain([minDate, maxDate])
                    .range([0, navWidth]),
                navYScale = d3.scale.linear()
                    .domain([yMin, yMax])
                    .range([navHeight, 0]);

                var xAxis = d3.svg.axis()
                    .scale(xScale)
                    .orient("bottom")
                    .ticks(5);

                var yAxis = d3.svg.axis()
                    .scale(yScale)
                    .orient("left");

                plotChart.append('g')
                    .attr('class', 'x axis')
                    .attr('transform', 'translate(0,' + height + ')')
                    .call(xAxis);

                plotChart.append("text") // text label for the x axis
                   .attr("transform", "translate(" + (width / 2) + " ," + (height + margin.bottom) + ")")
                   .style("text-anchor", "middle")
                   .text("Dates");

                plotChart.append('g')
                    .attr('class', 'y axis')
                    .call(yAxis);

                plotChart.append("text")
                  .attr("transform", "rotate(-90)")
                  .attr("y", 6)
                  .attr("dy", ".71em")
                  .style("text-anchor", "end")
                  .text("Vami");


                plotChart.append("text")
                   .attr("x", (width / 2))
                   .attr("y", 0 - (margin.top / 2))
                   .attr("text-anchor", "middle")
                   .style("font-size", "16px")
                   .style("text-decoration", "underline")
                   .text("Value-Added Monthly Index");

                var navXAxis = d3.svg.axis()
                    .scale(navXScale)
                    .orient('bottom');

                navChart.append('g')
                    .attr('class', 'x axis')
                    .attr('transform', 'translate(0,' + navHeight + ')')
                    .call(navXAxis);

                var line = d3.svg.line()
                    //.interpolate("monotone")
                    .x(function (d) { return xScale(d.date); })
                    .y(function (d) { return yScale(d.value); });

                var line2 = d3.svg.line()
                   //.interpolate("monotone")
                   .x(function (d) { return xScale(d.date); })
                   .y(function (d) { return yScale(d.valueBchk); });

                var line3 = d3.svg.line()
                   //.interpolate("monotone")
                  .x(function (d) { return xScale(d.date); })
                  .y(function (d) { return yScale(d.valueIdx); });



                var dataSeries = plotArea.append('g')
                    .attr('class', 'line')
                    .datum(data)
                    .call(line);

                var dataSeries2 = plotArea.append('g')
                    .attr('class', 'line')
                    .datum(data)
                    .call(line2);

                var dataSeries3 = plotArea.append('g')
                    .attr('class', 'line')
                    .datum(data)
                    .call(line3);

                var navData = d3.svg.area()
                    .x(function (d) { return navXScale(d.date); })
                    .y0(navHeight)
                    .y1(function (d) { return navYScale(d.value); });

                var navLine = d3.svg.line()
                    .x(function (d) { return navXScale(d.date); })
                    .y(function (d) { return navYScale(d.value); });

                plotChart.append("path")
                   .datum(data)
                   .attr("class", "line")
                   .attr("d", line);

                plotChart.append("text")
                    .attr("transform", "translate(" + (width + 3) + "," + yScale(data[data.length - 1].value) + ")")
                    .attr("dy", ".35em")
                    .attr("text-anchor", "start")
                    .text("Fund");

                //plotChart.append("path")
                //    .datum(data)
                //    .attr("class", "line")
                //    .style("stroke", "red")
                //    .attr("d", line2);

               // plotChart.append("text")
               //      .attr("transform", "translate(" + (width + 3) + "," + yScale(data[data.length - 1].valueBchk) + ")")
               //      .attr("dy", ".35em")
               //      .style("fill", "red")
               //      .attr("text-anchor", "start")
               //      .text("Bchk");

               // plotChart.append("path")
               //     .datum(data)
               //     .attr("class", "line")
               //     .style("stroke", "blue")
               //     .attr("d", line3);

               // plotChart.append("text")
               //      .attr("transform", "translate(" + (width + 3) + "," + yScale(data[data.length - 1].valueIdx) + ")")
               //      .attr("dy", ".35em")
               //      .style("fill", "blue")
               //      .attr("text-anchor", "start")
               //      .text("Idx");

                navChart.append('path')
                    .attr('class', 'data')
                    .attr('d', navData(data));

                navChart.append('path')
                    .attr('class', 'line')
                    .attr('d', navLine(data));

                var viewport = d3.svg.brush()
                    .x(navXScale)
                    .on("brush", function () {
                        xScale.domain(viewport.empty() ? navXScale.domain() : viewport.extent());
                        redrawChart();
                    });

                var zoom = d3.behavior.zoom()
                .x(xScale)
                .on('zoom', function () {
                    if (xScale.domain()[0] < minDate) {
                        var x = zoom.translate()[0] - xScale(minDate) + xScale.range()[0];
                        zoom.translate([x, 0]);
                    } else if (xScale.domain()[1] > maxDate) {
                        var x = zoom.translate()[0] - xScale(maxDate) + xScale.range()[1];
                        zoom.translate([x, 0]);
                    }
                    redrawChart();
                    updateViewportFromChart();
                });

                //x.domain(d3.extent(data, function (d) { return d.date; }));
                //y.domain([d3.min(data, function(d) {return Math.min(d.value, d.valueBchk, d.valueIdx); }), d3.max(data, function(d) {return Math.max(d.value, d.valueBchk, d.valueIdx); })]);

                navChart.append("g")
                    .attr("class", "viewport")
                    .call(viewport)
                    .selectAll("rect")
                    .attr("height", navHeight);

                var overlay = d3.svg.area()
                    .x(function (d) { return xScale(d.date); })
                    .y0(0)
                    .y1(height);

                plotArea.append('path')
                    .attr('class', 'overlay')
                    .attr('d', overlay(data))
                    .call(zoom);

                viewport.on("brushend", function () {
                    updateZoomFromChart();
                });

                var daysShown = 30;

                xScale.domain([
                    data[data.length - daysShown - 1].date,
                    data[data.length - 1].date
                ]);



                function redrawChart() {

                    plotChart.select(".line").attr("d", line);
                    //dataSeries2.call(line2);
                    //dataSeries3.call(line3);
                    plotChart.select('.x.axis').call(xAxis);

                }

                function updateViewportFromChart() {

                    if ((xScale.domain()[0] <= minDate) && (xScale.domain()[1] >= maxDate)) {

                        viewport.clear();
                    }
                    else {

                        viewport.extent(xScale.domain());
                    }

                    navChart.select('.viewport').call(viewport);
                }

                function updateZoomFromChart() {

                    zoom.x(xScale);

                    var fullDomain = maxDate - minDate,
                        currentDomain = xScale.domain()[1] - xScale.domain()[0];

                    var minScale = currentDomain / fullDomain,
                        maxScale = minScale * 20;

                    zoom.scaleExtent([minScale, maxScale]);
                }

                redrawChart();
                updateZoomFromChart();
                updateViewportFromChart();
            });

        </script>
    </div>
</body>
</html>

以及JSON文件:

[
  {
    "date": "1998-01-30",
    "value": 1000,
    "valueBchk": 1000,
    "valueIdx": 1000
  },
  {
    "date": "1998-02-28",
    "value":1007,
    "valueBchk": 1014.9,
    "valueIdx": 1066.4
  },
  {
    "date": "1998-03-31",
    "value": 1019,
    "valueBchk": 1057.5,
    "valueIdx": 1110.1
  },
  {
    "date": "1998-04-30",
    "value": 1060.3,
    "valueBchk": 1037.8,
    "valueIdx": 1119.6
  },
  {
    "date": "1998-05-31",
    "value": 1077.9,
    "valueBchk": 1032.4,
    "valueIdx": 1104.3
  },
  {
    "date": "1998-06-30",
    "value": 1112.6,
    "valueBchk": 1049,
    "valueIdx": 1129.2
  },
  {
    "date": "1998-07-31",
    "value": 1116.5,
    "valueBchk": 1070,
    "valueIdx": 1126.1
  },

  {
    "date": "1998-08-31",
    "value": 1133.3,
    "valueBchk": 1051.1,
    "valueIdx": 974.6
  },
  {
    "date": "1998-09-30",
    "value": 1158,
    "valueBchk": 1045.1,
    "valueIdx": 990.5
  },
  {
    "date": "1998-10-31",
    "value": 1173.2,
    "valueBchk": 1061.2,
    "valueIdx": 1078.8
  },
  {
    "date": "1998-11-30",
    "value": 1207.6,
    "valueBchk": 1092.2,
    "valueIdx": 1141.6
  },
  {
    "date": "1998-12-31",
    "value": 1252.8,
    "valueBchk": 1134.6,
    "valueIdx": 1196
  },
  {
    "date": "1999-01-31",
    "value": 1286.9,
    "valueBchk": 1196.9,
    "valueIdx": 1220.9
  },
  {
    "date": "1999-02-28",
    "value": 1295.7,
    "valueBchk": 1166.1,
    "valueIdx": 1187
  },
  {
    "date": "1999-03-31",
    "value": 1321.5,
    "valueBchk": 1199.8,
    "valueIdx": 1235.1
  },
  {
    "date": "1999-04-30",
    "value": 1339,
    "valueBchk": 1259.7,
    "valueIdx": 1282.4
  },
  {
    "date": "1999-05-31",
    "value": 1318.1,
    "valueBchk": 1243.6,
    "valueIdx": 1234.2
  },
  {
    "date": "1999-06-30",
    "value": 1290.7,
    "valueBchk": 1273.3,
    "valueIdx": 1290.4
  },
  {
    "date": "1999-07-31",
    "value": 1242.1,
    "valueBchk": 1265.6,
    "valueIdx": 1285.2
  },
  {
    "date": "1999-08-31",
    "value": 1251.9,
    "valueBchk": 1267.4,
    "valueIdx": 1281.5
  },
  {
    "date": "1999-09-30",
    "value": 1316.7,
    "valueBchk": 1273.4,
    "valueIdx": 1267.7
  },
  {
    "date": "1999-10-31",
    "value": 1316.7,
    "valueBchk": 1273.4,
    "valueIdx": 1267.7
  },
  {
    "date": "1999-11-30",
    "value": 1371.6,
    "valueBchk": 1288.7,
    "valueIdx": 1332.2
  },
  {
    "date": "1999-12-31",
    "value": 1397.4,
    "valueBchk": 1357.7,
    "valueIdx": 1368.4
  },
  {
    "date": "2000-01-31",
    "value": 1412,
    "valueBchk": 1437,
    "valueIdx": 1477.8
  },
  {
    "date": "2000-02-29",
    "value": 1443.9,
    "valueBchk": 1450.7,
    "valueIdx": 1391.9
  },
  {
    "date": "2000-03-31",
    "value": 1461,
    "valueBchk": 1537,
    "valueIdx": 1394.3
  },
  {
    "date": "2000-04-30",
    "value": 1531.5,
    "valueBchk": 1560.8,
    "valueIdx": 1489.3
  },
  {
    "date": "2000-05-31",
    "value": 1571.1,
    "valueBchk": 1500.7,
    "valueIdx": 1425
  },
  {
    "date": "2000-06-30",
    "value": 1671.3,
    "valueBchk": 1499.7,
    "valueIdx": 1387.6
  },
  {
    "date": "2000-07-31",
    "value": 1660.3,
    "valueBchk": 1507.5,
    "valueIdx": 1432.9
  },
  {
    "date": "2000-08-31",
    "value": 1671.5,
    "valueBchk": 1500.8,
    "valueIdx": 1391.2
  },
  {
    "date": "2000-09-30",
    "value": 1681.3,
    "valueBchk": 1554.6,
    "valueIdx": 1435.1
  },
  {
    "date": "2000-10-31",
    "value": 1717.5,
    "valueBchk": 1551.1,
    "valueIdx": 1357.5
  }
] 

1 个答案:

答案 0 :(得分:2)

redrawChart功能中,您可以:

plotChart.select(".line").attr("d", line);

这将选择plotChart中第一个带有line类的元素。当您打算使用类别行选择路径时,您已经使用行分类了很多内容,而此选择器正在选择g元素。

另外,你应该将你的路径追加到plotArea(而不是plotChart),这样它就在剪辑中。

尝试:

plotArea.append("path")
  .datum(data)
  .attr("class", "myActualLine")
  .attr("d", line);

...

function redrawChart() {
  plotChart.select(".myActualLine").attr("d", line);
  plotChart.select('.x.axis').call(xAxis);
}

完整的工作代码here