1

我有一个 div 需要根据 XHR 响应托管图表或表格。在图表的情况下,我需要将 div 内容替换为 chart.js 用来显示图表的画布元素。

如果我将 canvas 元素添加到 HTML 代码中,angular-chart.js 会呈现一个图形。但是,如果我使用 javascript 将画布注入 div,则画布元素将位于 dom 中,但不会显示图表。

我该如何解决这个问题?

HTML

<div ng-controller="ChartCtrl">
  <div>
    {{chart.name}}
    This works (doughnut):
    <canvas id="chart-{{$index}}" class="chart chart-doughnut" chart-data="chart.data" chart-labels="chart.labels"></canvas>
  </div>
  This Doesn't work ({{chart.type}}):
  <div id="chartDiv"> </div>
</div>

Javascript

var myApp = angular.module('myApp', ['chart.js']);

// Create the controller, the 'ToddlerCtrl' parameter 
// must match an ng-controller directive
myApp.controller('ChartCtrl', function ($scope) {
   var chart_div = $('#chartDiv');
   chart_div.empty();
   canvas_html = '<canvas id="chart-2" class="chart chart-doughnut" chart-data="chart.data" chart-labels="chart.labels"></canvas>';
   console.log(canvas_html)
   chart_div.append(canvas_html);
   //console.log(chart_div)
  $scope.chart =    {
     name: 'Chart 1',
     type: 'Doughnut',
     labels: ['EVSC', 'ISB'],
     data: [13, 44]
   };
});

Plunker 示例:http ://plnkr.co/edit/9JkANojIl8EXRj3hJNVH?p=preview

4

2 回答 2

1

您正在更改 DOM 的结构,您不能以“vanilla”或“jQuery”的方式附加新创建的元素。

您需要将您的 HTML 字符串或 DOM 元素编译为模板,以生成将链接到scope. 该过程将遍历 DOM 树并将 DOM 元素与指令匹配。

// Instantiate the app, the 'myApp' parameter must match what is in ng-app
var myApp = angular.module('myApp', ['chart.js']);

// Create the controller, the 'ToddlerCtrl' parameter must match an ng-controller directive
myApp.controller('ChartCtrl', function ($scope, $compile) {
  canvas_html = '<canvas id="chart-2" class="chart chart-doughnut" chart-data="chart.data" chart-labels="chart.labels"></canvas>';

  var element = angular.element(canvas_html);
  $compile(element)($scope);
  angular.element('#chartDiv').append(element);

  $scope.chart =    {
     name: 'Chart 1',
     type: 'Doughnut',
     labels: ['EVSC', 'ISB'],
     data: [13, 44]
   };
});

您可以在这个 Plunker 示例中查看结果。

于 2016-07-25T10:33:47.373 回答
1

@HiDeo 的答案是正确的,但这里有一个简化的指令来做同样的事情(注意$compile静止)。chartData附加到的变量是scopeChartjs 图表的预设,任何都可以使用 - 唯一需要注意的是$watch我添加到update属性中的变量:如果您要更新图表,我建议您这样做只是为了保持双手清洁。

.directive('replaceWithChart',function($compile){
    return {
        restrict: 'A',
        scope: {
            chartData: '=replaceWithChart',
            height: '=',
            width: '='
        },
        compile: function(element){
            var canvasModel = angular.element('<canvas></canvas>');
            return {
                post: function postLink(scope,elem,attr){
                    elem.empty();
                    var canvas = canvasModel.clone();
                    elem.append($compile(canvas)(scope));

                    !scope.height && (scope.height = elem[0].style.height || (elem[0].offsetHeight || elem[0].clientHeight));
                    !scope.width && (scope.width = elem[0].style.width || (elem[0].offsetWidth || elem[0].clientWidth));

                    var chart = new Chart(canvas[0].getContext('2d'),scope.chartData);
                    canvas.attr('height',(canvas[0].style.height = scope.height + 'px'));
                    canvas.attr('width',(canvas[0].style.width = scope.width + 'px'));

                    scope.$watch('chartData.update',function(){
                        scope.chartData.update && !(scope.chartData.update = false) && chart.update();
                    });
                    elem.on('$destroy',chart.destroy.bind(chart));
                    // Fixed some rendering issue, but I can't remember which
                    window.setTimeout(function(){
                        var padding = elem[0].style.padding || (window.getComputedStyle(elem[0],null).getPropertyValue('padding'));
                        elem[0].style.padding = '0';
                        elem[0].style.padding = padding;
                        chart.resize();
                    },300); // Magic number - I found this worked best
                }
            };
        }
    };
})
于 2016-07-29T02:43:39.817 回答