所以我试图将指令转换为组件。在给定输入数据集时,该指令基本上呈现带有图例的圆环图。此外,当你在圆环上盘旋时,我会显示弹出的动画。该指令绝对正常。问题是当我将指令转换为组件时。请在下面找到组件
的代码(() => {
angular
.module('charts.donut-chart')
.component('donutChart', {
templateUrl: 'charts/donut-chart/donut-chart.html',
controller: DonutChartController,
bindings: {
chartData: '=',
chartColors: '=',
chartHeight: '=',
chartWidth: '=',
legendHeight: '=',
hover: '@',
tooltips: '=',
enableLegend: '=',
id: '=',
},
});
function DonutChartController ($document, donutOptionsFactory, $filter, $scope, $timeout, $window, $element, $attrs, $compile) {
// console.log($element, $attrs);
const d3 = $window.d3;
const vm = this;
const timestamp = new Date().getTime();
vm.chartId = `donut_chart_${timestamp}`;
const donutOptions = {
chartWidth: vm.chartWidth,
chartHeight: vm.chartHeight,
legendHeight: vm.legendHeight,
};
// chart options
let chartWidth;
let chartHeight;
let enableLegend;
let legendHeight;
let outerRadiusOfArc;
let innerRadiusOfArc;
let color;
let arcColors;
let pie;
let arc;
let svgContainer;
let formattedDonutChartOptions;
let svgElement;
const deregistrationFn = $scope.$watch(() => $document[0].querySelector(`#${this.chartId}`), (newValue) => {
if (newValue !== null) {
deregistrationFn();
svgContainer = d3.select(`#${vm.chartId}`);
vm.initChartOptions();
createChart();
// bindMouseEvents();
}
});
vm.initChartOptions = () => {
formattedDonutChartOptions = donutOptionsFactory.getOptionsForDonutChart(donutOptions, svgContainer);
chartWidth = formattedDonutChartOptions.chartWidth;
chartHeight = formattedDonutChartOptions.chartHeight;
enableLegend = formattedDonutChartOptions.enableLegend;
legendHeight = formattedDonutChartOptions.legendHeight;
outerRadiusOfArc = formattedDonutChartOptions.outerRadiusOfArc;
innerRadiusOfArc = formattedDonutChartOptions.innerRadiusOfArc;
color = formattedDonutChartOptions.chartColors;
};
function onArcMouseOver (d, path) {
console.log('mouseover', d, path);
d3.select(path).transition()
.attr('d', d3.svg.arc()
.innerRadius(outerRadiusOfArc * 1.5)
.outerRadius(outerRadiusOfArc));
}
function onArcMouseOut (d, path) {
console.log('mouseout', d, path);
d3.select(path).transition()
.duration(500)
.ease('bounce')
.attr('d', d3.svg.arc()
.innerRadius(innerRadiusOfArc)
.outerRadius(outerRadiusOfArc));
}
function createChart () {
arcColors = d3.scale.ordinal()
.range(color);
pie = d3.layout.pie()
.sort(null)
.value(d => d.value);
arc = d3.svg.arc()
.innerRadius(innerRadiusOfArc)
.outerRadius(outerRadiusOfArc);
svgElement = svgContainer.append('svg')
.attr('width', chartWidth)
.attr('height', chartHeight)
.append('g')
.attr('transform', `translate(${chartWidth / 2}, ${chartHeight / 2})`);
svgElement.selectAll('path')
.data(pie(vm.chartData))
.enter()
.append('path')
.attr('fill', (d, i) => arcColors(i))
.attr('d', arc)
.on('mouseover', (d, i, j) => {
console.log(d, i, j, this);
const ref = this;
const dObject = d;
// (() => {
// onArcMouseOver(dObject, d3.select(this));
// })(dObject, ref);
d3.select(this).transition()
.attr('d', d3.svg.arc()
.innerRadius(outerRadiusOfArc * 1.5)
.outerRadius(outerRadiusOfArc));
})
.on('mouseout', (d, i, j) => {
console.log(d, i, j, this);
// onArcMouseOut(d, d3.select(this));
const ref = this;
const dObject = d;
// (() => {
// onArcMouseOut(dObject, d3.select(this));
// })(dObject, ref);
d3.select(this).transition()
.duration(500)
.ease('bounce')
.attr('d', d3.svg.arc()
.innerRadius(innerRadiusOfArc)
.outerRadius(outerRadiusOfArc));
});
}
function bindMouseEvents () {
/* function pathAnim (path, dir) {
switch (dir) {
case 0: // mouseout
path.transition()
.duration(500)
.ease('bounce')
.attr('d', d3.svg.arc()
.innerRadius(innerRadiusOfArc)
.outerRadius(outerRadiusOfArc));
break;
case 1:// mouseover
path.transition()
.attr('d', d3.svg.arc()
.innerRadius(outerRadiusOfArc * 1.5)
.outerRadius(outerRadiusOfArc));
break;
default: break;
}
}*/
const eventObject = {
mouseover (d) {
console.log('mouseover', this, d);
// pathAnim(d3.select(this), 1);
},
mouseout (d) {
console.log('mouseout', this, d);
// pathAnim(d3.select(this), 0);
},
};
svgElement.on(eventObject);
}
}
})();
上面的模板是
<div layout="row" id={{$ctrl.chartId}} layout-align="center center"></div>
上述组件工作正常,并按预期呈现圆环图。问题是我无法像指令那样做悬停效果。我尝试了两种绑定鼠标事件的方法。第一个是单独的使用函数bindMouseEvents()这个函数工作并返回我的&#39; d&#39;带有弧的所有startangle和endangle值的参数,但这些函数中的this
未定义或指向DonutController。 this
应指向悬而未决的元素。
所以我尝试了第二种方法。我将我追加数据的事件绑定到路径部分.on('mouseover', (d, i, j) => {
。我分配匿名回调,并从内部触发我自己的函数将参数传递给我自己的函数。这里当我使用chrome的调试器调试代码时,它向我显示this
正确指向悬停元素但是当我将它传递给我自己的函数时this
的所有对象值被传递为空或未定义,因此我的动画失败。
所以在第一种方法中我根据需要得到d
对象,但是this
搞砸了,在第二种方法中我得到了this
,但当我调用我的函数时将this
传递给它,它将作为一个空对象传递(具有所有键的对象,但这些键的值为空或未定义)。
有人可以指出我搞砸了什么吗?或者将我的指令转换为组件的更好方法?
提前致谢
答案 0 :(得分:0)
fat-arrow表示法的主要原因之一是保留父作用域中的this
。所以当你把它称为:
.on('mouseover', (d, i, j) => {
this
被保留,d3
不适用于注入悬停元素。简单的解决方法是使用传统功能:
.on('mouseover', function(d, i, j){
以下是您的代码的工作演示:
(() => {
angular
.module('charts.donut-chart')
.component('donutChart', {
template: "<div layout=\"ro\" id={{$ctrl.chartId}} layout-align=\"center center\"></div>",
controller: DonutChartController,
bindings: {
chartData: '=',
chartColors: '=',
chartHeight: '=',
chartWidth: '=',
legendHeight: '=',
hover: '@',
tooltips: '=',
enableLegend: '=',
id: '=',
},
});
function DonutChartController($document, $filter, $scope, $timeout, $window, $element, $attrs, $compile) {
// console.log($element, $attrs);
const d3 = $window.d3;
const vm = this;
const timestamp = new Date().getTime();
vm.chartId = `donut_chart_${timestamp}`;
const donutOptions = {
chartWidth: vm.chartWidth,
chartHeight: vm.chartHeight,
legendHeight: vm.legendHeight,
};
// chart options
let chartWidth;
let chartHeight;
let enableLegend;
let legendHeight;
let outerRadiusOfArc;
let innerRadiusOfArc;
let color;
let arcColors;
let pie;
let arc;
let svgContainer;
let formattedDonutChartOptions;
let svgElement;
const deregistrationFn = $scope.$watch(() => $document[0].querySelector(`#${this.chartId}`), (newValue) => {
if (newValue !== null) {
deregistrationFn();
svgContainer = d3.select(`#${vm.chartId}`);
vm.initChartOptions();
createChart();
}
});
vm.initChartOptions = () => {
//formattedDonutChartOptions = donutOptionsFactory.getOptionsForDonutChart(donutOptions, svgContainer);
chartWidth = 500; //formattedDonutChartOptions.chartWidth;
chartHeight = 500; //formattedDonutChartOptions.chartHeight;
enableLegend = true; //formattedDonutChartOptions.enableLegend;
legendHeight = 50; //formattedDonutChartOptions.legendHeight;
outerRadiusOfArc = 250; //formattedDonutChartOptions.outerRadiusOfArc;
innerRadiusOfArc = 200; //formattedDonutChartOptions.innerRadiusOfArc;
color = ['red', 'green', 'yellow']; //formattedDonutChartOptions.chartColors;
};
function onArcMouseOver(d, path) {
console.log('mouseover', d, path);
d3.select(path).transition()
.attr('d', d3.svg.arc()
.innerRadius(outerRadiusOfArc * 1.5)
.outerRadius(outerRadiusOfArc));
}
function onArcMouseOut(d, path) {
console.log('mouseout', d, path);
d3.select(path).transition()
.duration(500)
.ease('bounce')
.attr('d', d3.svg.arc()
.innerRadius(innerRadiusOfArc)
.outerRadius(outerRadiusOfArc));
}
function createChart() {
arcColors = d3.scale.ordinal()
.range(color);
pie = d3.layout.pie()
.sort(null)
.value(d => d.value);
arc = d3.svg.arc()
.innerRadius(innerRadiusOfArc)
.outerRadius(outerRadiusOfArc);
svgElement = svgContainer.append('svg')
.attr('width', chartWidth)
.attr('height', chartHeight)
.append('g')
.attr('transform', `translate(${chartWidth / 2}, ${chartHeight / 2})`);
svgElement.selectAll('path')
.data(pie([{
value: 10
}, {
value: 20
}, {
value: 30
}]))
.enter()
.append('path')
.attr('fill', (d, i) => arcColors(i))
.attr('d', arc)
.on('mouseover', function(d, i, j) {
d3.select(this).transition()
.attr('d', d3.svg.arc()
.innerRadius(outerRadiusOfArc * 1.5)
.outerRadius(outerRadiusOfArc));
})
.on('mouseout', function(d, i, j) {
d3.select(this).transition()
.duration(500)
.ease('bounce')
.attr('d', d3.svg.arc()
.innerRadius(innerRadiusOfArc)
.outerRadius(outerRadiusOfArc));
});
}
}
})();
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
<script src="index.js"></script>
<script src="donutChart.js"></script>
</head>
<body ng-app="charts.donut-chart">
<!-- components match only elements -->
<div ng-controller="MainCtrl as ctrl">
<donut-chart></donut-detail>
</div>
<script>
(function(angular) {
'use strict';
angular.module('charts.donut-chart', []).controller('MainCtrl', function MainCtrl() {
});
})(window.angular);
</script>
</body>
</html>