1

I am writing a Meteor application that will receive new data every 5 minutes or so, and add the new data to a group of charts. I am using dc.js to make the charts because I want users to be able to explore the data. I want to simplify the line using simplify.js before plotting it.

I am having a hard time figuring out where the path gets calculated in the dc.js library. The code can be found here In dc, a lineChart inheirits from coordinateGridChart. coordinateGridChart has a doRender() method (starting on line 1408):

_chart.doRender = function () {
    if (_x == null)
        throw new dc.errors.InvalidStateException("Mandatory attribute chart.x is missing on chart["
            + _chart.anchor() + "]");

    _chart.resetSvg();

    if (_chart.dataSet()) {
        _chart.generateG();

        generateClipPath();
        prepareXAxis(_chart.g());
        prepareYAxis(_chart.g());

        _chart.plotData();

        _chart.renderXAxis(_chart.g());
        _chart.renderYAxis(_chart.g());

        _chart.renderBrush(_chart.g());

        enableMouseZoom();
    }

So the plotData method seems to do the job. plotData is defined for lineChart on line 2548:

_chart.plotData = function() {
    var groups = _chart.allGroups();

    _chart.calculateDataPointMatrixForAll(groups);

    for (var groupIndex = 0; groupIndex < groups.length; ++ groupIndex) {
        var group = groups[groupIndex];
        plotDataByGroup(groupIndex, group);
    }
};

function plotDataByGroup(groupIndex, group) {
    var stackedCssClass = getStackedCssClass(groupIndex);

    var g = createGrouping(stackedCssClass, group);

    var line = drawLine(g, stackedCssClass, groupIndex);

    if (_renderArea)
        drawArea(g, stackedCssClass, groupIndex, line);

    if (_chart.renderTitle())
        drawDots(g, groupIndex);
}

function getStackedCssClass(groupIndex) {
    return dc.constants.STACK_CLASS + groupIndex;
}

function createGrouping(stackedCssClass, group) {
    var g = _chart.chartBodyG().select("g." + stackedCssClass);

    if (g.empty())
        g = _chart.chartBodyG().append("g").attr("class", stackedCssClass);

    g.datum(group.all());

    return g;
}

function drawLine(g, stackedCssClass, groupIndex) {
    var linePath = g.select("path.line");

    if (linePath.empty())
        linePath = g.append("path")
            .attr("class", "line " + stackedCssClass);

    linePath[0][0][dc.constants.GROUP_INDEX_NAME] = groupIndex;

    var line = d3.svg.line()
        .x(lineX)
        .y(function(d, dataIndex) {
            var groupIndex = this[dc.constants.GROUP_INDEX_NAME];
            return lineY(d, dataIndex, groupIndex);
        });

    dc.transition(linePath, _chart.transitionDuration(),
        function(t) {
            t.ease("linear");
        }).attr("d", line);

    return line;
}

var lineX = function(d) {
    return _chart.margins().left + _chart.x()(_chart.keyAccessor()(d));
};

var lineY = function(d, dataIndex, groupIndex) {
    var y = _chart.getChartStack().getDataPoint(groupIndex, dataIndex);
    if(y >= _chart.dataPointBaseline())
        y += _chart.dataPointHeight(d, groupIndex);
    return y;
};

So, is the path getting added where .attr("d", line) appears? When I console.log the line, it is a group of functions. The "d" attribute of the path is the svg line information, so it is a string that looks like "M100,50L100,55,L101,75" and so on. I can't find where this string is being constructed in the source code. I want to intervene at this step to simplify the line before adding the path element to the svg element.

Anyone familiar enough with dc.js to help me out? Thanks in advance.

4

1 回答 1

2
var line = d3.svg.line()
        .x(lineX)
        .y(function(d, dataIndex) {
            var groupIndex = this[dc.constants.GROUP_INDEX_NAME];
            return lineY(d, dataIndex, groupIndex);
        });

线路径是由这个标准的 d3 线生成器函数生成的。尽管使用 simple.js 的困难在于 d3 行生成器直接生成 svg:path d 属性而不是点向量,因此在这种情况下,您可能必须实现自定义行生成器才能使用 simple.js。但是 d3.svg.line 确实会生成点向量作为中间体

于 2013-06-11T22:03:31.230 回答