在交互式图表中动态扩展数据,数据在哪里被更改?

时间:2016-03-16 16:43:35

标签: javascript d3.js

我制作了一个交互式条形图,可以上下拖动条形图来调整数据。

当条形拖动超过y轴域的当前最大值/最小值时,y轴相应地缩放。但是,我不能让其余的柱子相应地缩放(即:如果我将一个柱子的值增加到一个新的极限,其他的柱子应该随着新的比例缩小)

我有一个JS Fiddle here,其中包含迄今为止有效的所有内容。

// canvas properties
var margin =
    {
        top: 40,
        bottom: 40,
        right: 30,
        left: 50
    }

var w = 960 - margin.left - margin.right,
    h = 500 - margin.top - margin.bottom;

// initiating axes
var x = d3.scale.ordinal()
        .rangeRoundBands([0, w], 0.1);

var y = d3.scale.linear()
        .range([h, 0]);

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom")
    .tickSize(0)
    .tickPadding(6);

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

var zeroline = d3.svg.axis()
    .scale(x)
    .orient("bottom")
    .tickSize(0)
    .tickFormat('')

var svg = d3.select("body").append("svg")
    .attr("width", w + margin.left + margin.right)
    .attr("height", h + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var newValue;    
var data = [
  {name: "A", value: -15},
  {name: "B", value: -20},
  {name: "C", value: -22},
  {name: "D", value: -18},
  {name: "E", value: 2},
  {name: "F", value: 6},
  {name: "G", value: 26},
  {name: "H", value: 18}
];

function type(d)
{
    d.value = +d.value;
    return d;
}

function generateChart(error, data)
{
    /* ========== Parse Data & Create Axes ========== */
     // create a new property called y (needed for d3.events)
    var data = data.map(function (d, i)
    {
        return {
            name: d.name,
            value: d.value,
            y: d.value
        }
    });

    var max = d3.max(data, function (d) { return d.y; });
    var min = -max;

    y.domain([min, max]).nice();
    x.domain(data.map(function (d) { return d.name; }));

    var zz = svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + (h / 2) + ")")
    .call(zeroline);

    var xx = svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + (h + 20) + ")")
        .call(xAxis);

    var yy = svg.append("g")
        .attr("class", "y axis")
        .call(yAxis);

    /* ========== Drag Behaviour for Rectangles ========== */
    var drag = d3.behavior.drag()
        .on("drag", resize);

    /* ========== Create Rectangles ========== */
    var DataBar = svg.selectAll(".bar")
        .data(data)
        .enter().append("rect")
        .attr("class", function (d) { return "bar bar--" + (d.value < 0 ? "negative" : "positive"); })
        .attr("id", function (d) { return (d.value < 0 ? "negative" : "positive"); })
        .attr("x", function (d) { return x(d.name); })
        .attr("y", function (d) { return y(Math.max(0, d.value)); })
        .attr("width", x.rangeBand())
        .attr("height", function (d) { return Math.abs(y(d.value) - y(0)); })
        .attr("cursor", "ns-resize")
        .call(drag);

    /* ========== Drag Functions ========== */
    function resize(d)
    {
        if (d3.select(this)[0][0].id == 'positive')
        {

            d.y = d3.event.y;
            if (y.invert(d.y) >= 0) // positive -> postive
            {
                var barHeight = -(d.y - y(0));
                var bar = d3.select(this);
                bar.attr("y", function (d) { return d.y; })
                   .attr("height", barHeight)
                   .style("fill", "steelblue");

            }
            else if (y.invert(d.y) < 0) // positive -> negative
            {
                var barHeight = Math.abs((d.y) - y(0))
                var dragy = d3.event.y
                barHeight += dragy - (d.y);
                var bar = d3.select(this)
                bar.attr("height", barHeight)
                   .attr("y", y(0))
                   .style("fill", "darkorange");

            }

            newValue = y.invert(d.y);
        }
        else if (d3.select(this)[0][0].id == 'negative')
        {
            var barHeight = Math.abs(y(d.y) - y(0))
            var dragy = d3.event.y

            if (y.invert(dragy) < 0) // negative -> negative
            {
                barHeight += dragy - y(d.y);
                var bar = d3.select(this)
                bar.attr("height", barHeight)
                   .attr("y", y(0))
                   .style("fill", "darkorange");
            }
            else if (y.invert(dragy) >= 0) // negative -> positive
            {

                var barHeight = -(dragy - y(0));

                var bar = d3.select(this);
                bar.attr("y", function (d) { return dragy; })
                   .attr("height", barHeight)
                   .style("fill", "steelblue");

            }

            //newValue = y.invert(dragy);

        }
        var max = d3.max(data, function (d) { return d.value; });
        var min = -max;
        var update = [];

        if (newValue > max)// || newValue < min)
        {
            y.domain([-newValue, newValue]).nice();
            yy.call(yAxis)
        }

    }    
}

generateChart('error!', data)

(快速注意:y轴重新缩放仅适用于此时的初始蓝条。)

1 个答案:

答案 0 :(得分:1)

if (newValue > max) { ... }块之后添加以下代码块:

var selectedObjectName = d3.select(this).data()[0].name;
svg.selectAll("rect.bar").filter(function (d){
   return (d.name != selectedObjectName);})
   .attr("height", function (d) { return Math.abs(y(d.value) - y(0));})
   .attr("y", function (d) { return y(Math.max(0, d.value)); });

想法是选择所有矩形,过滤掉当前选定的矩形,然后重新调整剩余矩形的高度和y坐标。 Fiddle