2016-01-28 40 views
4

我正在使用angular和d3創建一個圓環(在指令中)。使用顏色漸變的角度svg或畫布

我可以很簡單地給填充的區域一個顏色(在這個蹲坑裏它是藍色的)。但我想做的事就是有SVG從平滑地改變它的顏色:

0% - 33.3% - red 
33.4% - 66.66% - orange 
66.7% - 100% green 

指令:

app.directive('donutDirective', function() { 
    return { 
     restrict: 'E', 
     scope: { 
      radius: '=', 
      percent: '=', 
      text: '=', 
     }, 
     link: function(scope, element, attrs) { 
      var radius = scope.radius, 
       percent = scope.percent, 
       percentLabel = scope.text, 
       format = d3.format(".0%"), 
       progress = 0; 

      var svg = d3.select(element[0]) 
       .append('svg') 
       .style('width', radius/2+'px') 
       .style('height', radius/2+'px'); 

      var donutScale = d3.scale.linear() 
       .domain([0, 100]) 
       .range([0, 2 * Math.PI]); 

      //var color = "#5599aa"; 
      var color = "#018BBB"; 

      var data = [ 
       [0,100,"#b8b5b8"], 
       [0,0,color] 
      ]; 

      var arc = d3.svg.arc() 
       .innerRadius(radius/6) 
       .outerRadius(radius/4) 
       .startAngle(function(d){return donutScale(d[0]);}) 
       .endAngle(function(d){return donutScale(d[1]);}); 

      var text = svg.append("text") 
       .attr("x",radius/4) 
       .attr("y",radius/4) 
       .attr("dy", ".35em") 
       .attr("text-anchor", "middle") 
       .attr("font-size","14px") 
       .style("fill","black") 
       .attr("text-anchor", "middle") 
       .text(percentLabel); 

      var path = svg.selectAll("path") 
       .data(data) 
       .enter() 
       .append("path") 
       .style("fill", function(d){return d[2];}) 
       .attr("d", arc) 
       .each(function(d) { 
        this._current = d; 
        // console.log(this._current) 
       ;}); 

      // update the data! 
      data = [ 
       [0,100,"#b8b5b8"], 
       [0,percent,color] 
      ]; 

      path 
       .data(data) 
       .attr("transform", "translate("+radius/4+","+radius/4+")") 
       .transition(200).duration(2150).ease('linear') 
       .attrTween("d", function (a) { 
        var i = d3.interpolate(this._current, a); 
        var i2 = d3.interpolate(progress, percent) 
        this._current = i(0); 
        // console.log(this._current); 
        return function(t) { 
         text.text(format(i2(t)/100)); 
         return arc(i(t)); 
        }; 
       }); 
     } 
    }; 
}); 

Plunker:http://plnkr.co/edit/8qGMeQkmM08CZxZIVRei?p=preview

回答

2

我想要做的是有SVG從平滑地改變它的顏色:

0% - 33.3% - red 
33.4% - 66.66% - orange 
66.7% - 100% green 

假設你想要的顏色過渡/規模像這樣的:

enter image description here

請參閱此工作代碼:http://codepen.io/anon/pen/vLVmyV

可以使用這樣的D3線性刻度smothly使色彩過渡:

//Create a color Scale to smothly change the color of the donut 
var colorScale = d3.scale.linear().domain([0,33.3,66.66,100]).range(['#cc0000','#ffa500','#ffa500','#00cc00']); 

然後,當你更新路徑(與attrTween),使填充動畫,只需要在路徑的代表填充甜甜圈的一部分,讓我們把它叫做colorPath,改變它的填充添加以下像吐溫:

//Set the color to the path depending on its percentage 
//using the colorScale we just created before 
colorPath.style('fill',colorScale(i2(t))) 

你attrTween看起來就像這樣:

colorPath.data([[0,percent,color]]) 
.transition(200).duration(2150).ease('linear') 
.attrTween("d", function (a) { 
    var i = d3.interpolate(this._current, a); 
    var i2 = d3.interpolate(progress, percent) 
    this._current = i(0); 
    // console.log(this._current); 
    return function(t) { 
     text.text(format(i2(t)/100)); 
     colorPath.style('fill',colorScale(i2(t))) 
     return arc(i(t)); 
    }; 
}); 

請注意,我們只對colorPath更新數據:colorPath.data([[0,percent,color]])

整個工作的例子是在這裏:http://plnkr.co/edit/ox82vGxhcaoXJpVpUel1?p=preview

+0

太神奇了,謝謝! –

+0

@OamPsy你非常歡迎,請接受作爲正確答案,謝謝。 – kevinkl3

3

先給ID要這樣的路徑:

var path = svg.selectAll("path") 
       .data(data) 
       .enter() 
       .append("path") 
       .style("fill", function(d){return d[2];}) 
       .attr("d", arc) 
       .attr("id", function(d,i){return "id"+i;})//give id 

然後在補間內通過條件並更改第Ë路徑

.attrTween("d", function (a) { 
        var i = d3.interpolate(this._current, a); 
        var i2 = d3.interpolate(progress, percent) 
        this._current = i(0); 

        return function(t) { 
         if(i2(t) < 33.3) 
          d3.selectAll("#id1").style("fill", "red") 
         else if(i2(t) < 66.6) 
          d3.selectAll("#id1").style("fill", "orange") 
         else if(i2(t) > 66.6) 
          d3.selectAll("#id1").style("fill", "green") 

         text.text(format(i2(t)/100)); 
         return arc(i(t)); 
        }; 
       }); 

工作代碼here

編輯

內,您的指令,你可以讓gradientdefs裏面是這樣的:

 var defs = svg.append("defs"); 
     var gradient1 = defs.append("linearGradient").attr("id", "gradient1"); 
     gradient1.append("stop").attr("offset", "0%").attr("stop-color", "red"); 
     gradient1.append("stop").attr("offset", "25%").attr("stop-color", "orange"); 
     gradient1.append("stop").attr("offset", "75%").attr("stop-color", "green"); 

然後在路徑可以定義像這樣的梯度:

var path = svg.selectAll("path") 
     .data(data) 
     .enter() 
     .append("path") 
     .style("fill", function(d, i) { 
      if (i == 0) { 
      return d[2]; 
      } else { 
      return "url(#gradient1)"; 
      } 
     }) 

工作代碼here

希望這有助於!

+0

這真是太好了!高度讚賞你已經投入的努力。可能我沒有做足夠清晰的IM之後,而不是弧改變整個顏色爲紅色/綠色/橙色,我想要一個漸變效果,如下所示:https:// www .google.co.uk/imgres imgUrl的= HTTPS:?//pixabay.com/static/uploads/photo/2015/02/26/17/13/red-650676_960_720.png&imgrefurl=https://pixabay.com/en /紅 - 黃 - 綠 - 橙 - 石灰 - 650676 /&H = 644&W = 960&tbnid = 0L-m59MbMKaU5M:文檔ID = NN4MXwkocHBA2M&EI = m2GrVrXYHMvzUqu_ucgH與TBM = isch&VED = 0ahUKEwj1kfqQic_KAhXLuRQKHatfDnkQMwhLKCQwJA –

+1

@OamPsy SVG不這樣做,雖然。您可以使用線性漸變或徑向漸變,這兩者都不允許沿着形狀設置漸變。爲了得到你想要的東西,你可能需要在畫布上編碼。 –

+0

@RobertLongson - 我明白了,謝謝你的解釋。好吧,我想我需要一個畫布。我會更新標題。 –