在Angular中使用d3.js svg clipPath不剪切

时间:2013-11-26 18:23:36

标签: angularjs svg d3.js

我正在开发一个类似于以下示例的图表: http://bl.ocks.org/mbostock/1667367使用clipPath剪切区域,使区域图不会溢出轴。

在Angular指令中使用相同的示例,它几乎可以正常工作但剪切。使用焦点功能时,图形中的线会溢出剪辑矩形的限制。

但是jsFiddle中的相同代码正常工作http://jsfiddle.net/gserra/TXYGH/。指令中提到的代码如下:

angular.module('casApp.directives', []).
  directive('lineChart', ['d3', '_', 'moment', function (d3, _, moment) {
    var margin = {top: 10, right: 10, bottom: 100, left: 40};
    var margin2 = {top: 430, right: 10, bottom: 20, left: 40};

    return {
      restrict: 'E',
      replace: true,
      scope: {
        data: '=',
        stream: '=',
        start: '=',
        end: '=',
        period: '@',
        unit: '@',
        sensor: '@',
        width: '@',
        height: '@'
      },
      template: '<div class="line-chart"></div>',
      controller:'DataCtrl',
      link: function (scope, element) {
        var height = scope.height - margin.top - margin.bottom,
          height2 = scope.height - margin2.top - margin2.bottom,
          width = scope.width - margin.left - margin.right;

        scope.updateTime();

        var x = d3.time.scale()
          .domain([scope.start, scope.end])
          .range([0, width]);

        var x2 = d3.time.scale()
          .domain(x.domain())
          .range([0, width]);

        var min = d3.min(scope.data, function (d) {return d.value; })
        var max = d3.max(scope.data, function (d) {return d.value; })
        var thres = Math.abs(max-min);

        var y = d3.scale.linear()
          .domain([min - thres, max + thres])
          .range([height, 0]);

        var y2 = d3.scale.linear()
          .domain(y.domain())
          .range([height2, 0]);

        var line = d3.svg.line()
          .x(function (d) {
            return x(moment(d.at));
          })
          .y(function (d) {
            return y(d.value);
          });

        var line2 = d3.svg.line()
          .x(function (d) {
            return x2(moment(d.at));
          })
          .y(function (d) {
            return y2(d.value);
          });

        var graph = d3.select(element[0])
          .append('svg')
          .attr('width', scope.width)
          .attr('height', scope.height);

        var xAxis = d3.svg.axis().scale(x).orient('bottom'),
          xAxis2 = d3.svg.axis().scale(x2).orient('bottom'),
          yAxis = d3.svg.axis().scale(y).orient('left');

        var brush = d3.svg.brush()
          .x(x2)
          .on('brush', brushed);

        var focus = graph.append('g')
          .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

        var context = graph.append('g')
          .attr('transform', 'translate(' + margin2.left + ',' + margin2.top + ')');

        focus.append('defs').append('clipPath')
          .attr('id', 'clip')
          .append('rect')
          .attr('width', width)
          .attr('height', height);

        focus.append('g')
          .data([scope.data])
          .attr('clip-path', 'url(#clip)')
          .append('path')
          .attr('d', line)
          .attr('class', 'line');

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

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

        context.append('path')
          .data([scope.data])
          .attr('d', line2)
          .attr('class', 'line');

        context.append('g')
          .attr('class', 'x axis')
          .attr('transform', 'translate(0,' + height2 + ')')
          .call(xAxis2);

        context.append('g')
          .attr('class', 'x brush')
          .call(brush)
          .selectAll('rect')
          .attr('y', -6)
          .attr('height', height2 + 7);

        function brushed() {
          x.domain(brush.empty() ? x2.domain() : brush.extent());
          focus.select('path.line').attr('d', line);
          focus.select('.x.axis').call(xAxis);
        }

        function updateGraph () {
           // update x axis
          x.domain([scope.start, scope.end]);
          x2.domain([scope.start, scope.end]);
          xAxis.scale(x);
          xAxis2.scale(x2);

          focus.selectAll('g.x.axis').call(xAxis);
          context.selectAll('g.x.axis').call(xAxis2);

          // update y axis
          var min = d3.min(scope.data, function (d) {return d.value; })
          var max = d3.max(scope.data, function (d) {return d.value; })
          var thres = Math.abs(max-min);

          y.domain([min - thres, max + thres]);
          y2.domain([min - thres, max + thres]);

          yAxis.scale(y);

          focus.selectAll('g.y.axis').call(yAxis);

          //update line
          focus.selectAll('path.line')
            .data([scope.data])
            .attr('d', line);

          context.selectAll('path.line')
            .data([scope.data])
            .attr('d', line2);
        }

        scope.$watch('data', function () {
          var last = scope.data.length > 0 ? moment(_.last(scope.data).at) : null;

          if (last && last > scope.end) {
            scope.updateTime(last, moment(last).add(scope.unit, scope.period));
            scope.data = [_.last(scope.data)];
          }
          updateGraph();
        });
      }
    };
  }]).

  directive('paginator', function () {
    return {
      controller: 'DataCtrl',
      restrict: 'E',
      template: '<button class="forward" ng-disabled="stream" ng-click="forward()">Page up</button>' +
                '<button class="back" ng-click="back()">Page down</button>'
    };
  });

使用控制器中的socket.io自动更新图表。我试过没有成功将defs附加到“svg”而不是“g”。有什么想法吗?

我正在使用Angular 1.2.2

1 个答案:

答案 0 :(得分:11)

最后,在将代码隔离到另一个文件并简化它之后,我发现了这种奇怪行为的原因:

<head>我有:

<head>
  <meta charset="utf8">
  <title>Real time context aware graphics display</title>
  <link rel="stylesheet" href="/stylesheets/app.css">
  <link rel="stylesheet" href="/stylesheets/graph.css"><base href="/">
  <base href="/">
  <style type="text/css"></style>
</head>

广告,当我删除<base href="/">时,所有工作都完美无缺。我不确切地知道原因。