所以我試圖將一個指令轉換爲組件。該指令基本上呈現給出輸入數據集時帶有圖例的圓環圖。當你在圓環上懸停時,我會彈出動畫。該指令工作非常好。問題是當我將指令轉換爲組件時。請找到下面的代碼爲組件angularJS將d3js自定義的甜甜圈指令轉換爲組件
(() => {
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()的單獨函數,該函數可以工作,並返回包含弧的所有startangle和endangle值的'd'參數,但這些函數中的this
未定義或指向DonutController。 this
應指向它沒有的懸停元素。
所以我嘗試了第二種方法。我將我將數據追加到路徑部分的事件綁定到.on('mouseover', (d, i, j) => {
。我分配匿名回調,並從內部觸發我自己的函數將參數傳遞給我自己的函數。在這裏,當我使用chrome的調試器調試代碼時,它向我顯示this
正確指向了懸停元素,但是當我將它傳遞給我自己的函數時,所有對象值this
都被傳遞爲空或未定義,因此我的動畫失敗。
所以在第一種方法中,我得到了d
對象必要的,但在this
被搞砸了,並在第二個方法我得到的this
正常,但是當我把我的功能,並通過this
給它,它被作爲一個傳遞空對象(具有所有鍵的對象,但這些鍵的值爲空或未定義)。
有人能指出我在搞什麼嗎?或者有更好的方法將我的指令轉換爲組件?
預先感謝
感謝@馬克的答覆。我發現使用箭頭符號不會保留'this'。 Mozilla的文檔幫助我在這裏。 – digitalis