2016-12-30 22 views
0

所以我試圖將一個指令轉換爲組件。該指令基本上呈現給出輸入數據集時帶有圖例的圓環圖。當你在圓環上懸停時,我會彈出動畫。該指令工作非常好。問題是當我將指令轉換爲組件時。請找到下面的代碼爲組件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給它,它被作爲一個傳遞空對象(具有所有鍵的對象,但這些鍵的值爲空或未定義)。

有人能指出我在搞什麼嗎?或者有更好的方法將我的指令轉換爲組件?

預先感謝

回答

0

其中一個主要的原因脂肪箭頭符號是從父範圍保持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>

+0

感謝@馬克的答覆。我發現使用箭頭符號不會保留'this'。 Mozilla的文檔幫助我在這裏。 – digitalis