首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >d3图在角度上的共享X轴

d3图在角度上的共享X轴
EN

Stack Overflow用户
提问于 2016-03-14 15:21:58
回答 1查看 572关注 0票数 0

我是添加D3线图表到一个页面使用纳克重复角.在ng-重复中有一个图表指令,它使用来自ng-重复的数据.

我是添加数据到ng-重复的动态基础上的ng-点击。这很好,但是我需要所有的图表来共享同一个X轴。当数据被添加并从ng-重复中删除时,我需要更新X轴。

我的指令的当前代码:基本上,我将需要为ng重复中的所有图表设置X轴,基于stackedChartData中的日期而不是每个单独的图表。

代码语言:javascript
复制
<div ng-repeat="chart in stackedChartData">
    <stacked-chart chart-data="chart.list" x="date" y="value"
                  width="600" height="270"
                  margin="{top: 40, right:20, bottom:50, left:40}"></stacked-chart>
  </div>


    function StackedChartController($scope, $element, $attrs){
        this.x = $scope.x;
        this.y = $scope.y;
        this.xLabel = ($scope.xlabel || capitalize(this.x));
        this.yLabel = ($scope.ylabel || capitalize(this.y));
        this.height = $scope.height;
        this.width = $scope.width;
        this.margin = $scope.margin;
        this.data = $scope.chartData || [];
        this.xScale = null;
        this.yScale = null;
        this.svg = null;

        this.svg = d3.select($element[0])
            .append("svg")
            .attr("width", this.width)
            .attr("height", this.height)
            .append("g")
            .attr("transform",
                "translate(" + this.margin.left + "," + this.margin.top + ")");


        this.innerWidth = this.width - this.margin.left - this.margin.right;
        this.innerHeight = this.height - this.margin.top - this.margin.bottom;

        $scope.$watch("chartData", (function(newVal, oldVal) {
            this.data = newVal;

            this.xDomain = (typeof $scope.xdomain === 'function' ? $scope.xdomain : xDomainCommand);
            this.yDomain = (typeof $scope.ydomain === 'function' ? $scope.ydomain : yDomainCommand);
            // Redraw the graph after new data loads.
            this.drawAxes();
            this.append($scope.lines || [], this.data);
            this.plotData(this.data);
        }).bind(this));

        /* Debugging
         $scope.$watch("ydomain", (function(newVal, oldVal) {
         console.log('ydomain', newVal, oldVal);
         }).bind(this));
         */

        var x = this.x,
            y = this.y;

        var xDomainCommand = function(data, d3){
            data = data || [];
            return [d3.min(data, function(d) {
                return d[x];
            }), d3.max(data, function(d) {
                return d[x];
            })];
        };

        var yDomainCommand = function(data, d3){
            data = data || [];
            return [
                ((d3.min(data, function(d){
                    return d[y];
                }) - 1)),  (d3.max(data, function(d){
                    return d[y];
                }) + 1)
            ];
        }

        // Setting these methods to default functions.
        // But these will often be override by different scopes
        // which need to be able specify different different functions
        // for caclulating the data ranges.
        this.xDomain = xDomainCommand;
        this.yDomain = yDomainCommand;
    }


    /**
     * Plotting the data (an array of objects) passed to the function.
     * @param data
     */
    StackedChartController.prototype.plotData = function(data){
        data = data || [];
        var xScale = this.xScale.bind(this);
        var yScale = this.yScale.bind(this);
        var x = this.x;
        var y = this.y;
        var valueline = d3.svg.line()
            .x(function(d) {
                return xScale(d[x]);
            })
            .y(function(d) {
                return yScale(d[y]);
            });

        // Add the valueline path.
        this.svg.append("path")
            .attr("class", "line")
            .attr("d", valueline(data));

        // Add the points
        this.svg.selectAll("dot")
            .data(data)
            .enter().append("circle")
            .attr("r", 5)
            .attr("cx", function(d) {
                return xScale(d[x])
            })
            .attr("cy", function(d) {
                return yScale(d[y]);
            })
            // Tooltip
            .append("svg:title")
            .text((function(d){
                if (typeof this.tooltip === 'function'){
                    return this.tooltip(d)
                } else {
                    return null;
                }
            }).bind(this));
    };


    /**
     * Sets the size of the graph (range) and max/min values to plot (domain)
     */
    StackedChartController.prototype.setParams = function(){

        // Set the ranges
        this.xScale = d3.time.scale().range([0, this.innerWidth]);
        //xScale = d3.scale.linear().range([0, width]);
        this.yScale= d3.scale.linear().range([this.innerHeight, 0]);
        // Scale the range of the data
        this.xScale.domain(this.xDomain(this.data, d3));
        this.yScale.domain(this.yDomain(this.data, d3));

        // Define the axes
        var axisGenerators = {};
        axisGenerators.x = d3.svg.axis().scale(this.xScale)
            .orient("bottom").ticks(5);
        axisGenerators.y = d3.svg.axis().scale(this.yScale)
            .orient("left").ticks(5);
        return axisGenerators;
    };


    /**
     * Adds extra lines beyond the initial one created by the initial dataset.
     *
     */
    StackedChartController.prototype.append = function(lines, data){
        data = data || [];
        var xScale = this.xScale.bind(this);
        var yScale = this.yScale.bind(this);

        lines.forEach(function(item){
            var valueline = d3.svg.line()
                .x(function(d) {
                    return xScale(d[item.x]);
                })
                .y(function(d) {
                    return yScale(d[item.y]);
                });

            this.svg.append("path")
                .attr("class", "line")
                .style("stroke", item.color || 'black')
                .attr("d", valueline(this.data));

            if (item.showPoints === true) {
                this.svg.selectAll("dot")
                    .data(data)
                    .enter().append("circle")
                    .attr("r", 5)
                    .attr("cx", function (d) {
                        return xScale(d[item.x])
                    })
                    .attr("cy", function (d) {
                        return yScale(d[item.y]);
                    })
            }
        }, this);
    };


    /**
     * Clears the graph before redrawing the axes.
     */
    StackedChartController.prototype.drawAxes = function(){
        var svg = this.svg;

        // Remove original lines drawn on the axes.
        // PF (2016/03/04) This is interfering with multiple datasets.
        svg.selectAll('*').remove();

        var axisGenerators = this.setParams();


        // Add the X Axis
        svg.append("svg:g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + this.innerHeight + ")")
            .call(axisGenerators.x);
        // text label for the x axis

        // Add the Y Axis
        svg.append("svg:g")
            .attr("class", "y axis")
            .call(axisGenerators.y);
    };


    return {
        restrict: 'E',
        replace: true,
        scope: {
            x: '@',
            y: '@',
            height: '=',
            width: '=',
            margin: '=',
            chartData: '=',
            tooltip: '=',
            lines: '=',
            xdomain:'=',
            ydomain: '='
        },
        template: '<svg></svg>',
        controller: StackedChartController
    };
};
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-03-24 21:28:10

我通过创建一个单独的日期数组来解决这个问题,所有的图表都使用这些日期作为x域。

每次将新项添加到图表ng重复时,它们的日期也会被推入另一个按日期排序的数组中。

我在指令中设置了一个$watch,用于查看日期数组,并在此数组更改时重新绘制所有图形。

指令监视

代码语言:javascript
复制
$scope.$watch('at', (function (newVal, oldVal) {
            this.xDomain = $scope.xdomain;
            this.yDomain = (typeof $scope.ydomain === 'function' ? $scope.ydomain : yDomainCommand);
            // Redraw the graph after new data loads.
            drawAxes();
            plotData(this.data);
            append($scope.lines || [], this.data);
            $compile($element)($scope);
        }).bind(this));

我需要访问指令范围之外的数据,所以我在parentData中使用了下面的语法

指令范围

代码语言:javascript
复制
scope: {
            x: '@',
            y: '@',
            height: '=',
            width: '=',
            margin: '=',
            chartData: '=',
            at: '=parentData', // used to access outside scope
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35991449

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档