在 Angular-chart.js 中动态创建的 canvas 上创建图表
Create a chart on a dynamically created canvas in Angular-chart.js
我有一个 div 需要托管图表或 table 取决于 XHR 响应。在图表案例中,我需要将 div 内容替换为 chart.js 用于显示图表的 canvas 元素。
如果我将 canvas 元素添加到 HTML 代码,angular-chart.js 会呈现一个图形。但是,如果我使用 javascript 将 canvas 注入到 div 中,canvas 元素将位于 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
您正在改变 DOM 的结构,您不能像 "vanilla" 或 "jQuery" 那样附加新创建的元素。
你需要compile your HTML string or DOM element into a template to produce a template function that will be linked to the scope
. The process will walk the DOM tree and match DOM elements to directives。
// 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]
};
});
您可以在 this Plunker example 中查看结果。
@HiDeo 的回答是正确的,但这里有一个简化的指令来做同样的事情(仍然注意 $compile
)。附加到 scope
的 chartData
变量是 Chartjs 图表的预设,任何都可以使用 - 唯一需要注意的是我添加到 update
的 $watch
属性:如果您要更新图表,我建议您这样做只是为了保持双手清洁。
.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
}
};
}
};
})
我有一个 div 需要托管图表或 table 取决于 XHR 响应。在图表案例中,我需要将 div 内容替换为 chart.js 用于显示图表的 canvas 元素。
如果我将 canvas 元素添加到 HTML 代码,angular-chart.js 会呈现一个图形。但是,如果我使用 javascript 将 canvas 注入到 div 中,canvas 元素将位于 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
您正在改变 DOM 的结构,您不能像 "vanilla" 或 "jQuery" 那样附加新创建的元素。
你需要compile your HTML string or DOM element into a template to produce a template function that will be linked to the scope
. The process will walk the DOM tree and match DOM elements to directives。
// 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]
};
});
您可以在 this Plunker example 中查看结果。
@HiDeo 的回答是正确的,但这里有一个简化的指令来做同样的事情(仍然注意 $compile
)。附加到 scope
的 chartData
变量是 Chartjs 图表的预设,任何都可以使用 - 唯一需要注意的是我添加到 update
的 $watch
属性:如果您要更新图表,我建议您这样做只是为了保持双手清洁。
.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
}
};
}
};
})