【问题标题】:How to get color of svg linearGradient at specific position如何在特定位置获取svg linearGradient的颜色
【发布时间】:2014-06-10 05:05:30
【问题描述】:

我有一个线性渐变,用作百分比条,带有一个小椭圆,沿着条移动以显示当前的完成百分比。完成百分比通过调用函数的 AngularJS 绑定更新。

我需要根据当前位置渐变条的颜色来改变椭圆的颜色。假设百分比为 80%,我需要获取 80% 位置的渐变颜色。

这可能吗?

<svg height="20px" width="100%">
<defs>
    <linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
        <stop offset="0%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
        <stop offset="50%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
        <stop offset="100%" style="stop-color:rgb(79,189,0);stop-opacity:1" />
    </linearGradient>
</defs>
<rect width="100%" height="3px" y="50%" fill="url(#gradient)" style="stroke-width:0" />
<rect width="30px" height="20px" x="{{calculateProfilePercentage()}}%" rx="8" ry="8" fill="rgb(249,166,31)" style="stroke-width:0" />
</svg>

【问题讨论】:

    标签: javascript html angularjs svg linear-gradients


    【解决方案1】:

    AFAIK 您无法从渐变中读取值,因为渐变对象不公开这样做的方法。

    但是,您可以创建一个离屏画布,绘制渐变并从那里读取像素值。

    例如,让我们创建一个对象 GradientReader。这允许我们实例化它并嵌入方法等等:

    function GradientReader(colorStops) {
    
        const canvas = document.createElement('canvas');   // create canvas element
        const ctx = canvas.getContext('2d');               // get context
        const gr = ctx.createLinearGradient(0, 0, 101, 0); // create a gradient
        
        canvas.width = 101;                                // 101 pixels incl.
        canvas.height = 1;                                 // as the gradient
    
        for (const { stop, color } of colorStops) {               // add color stops
            gr.addColorStop(stop, color);
        }
        
        ctx.fillStyle = gr;                                // set as fill style
        ctx.fillRect(0, 0, 101, 1);                        // draw a single line
        
        // method to get color of gradient at % position [0, 100]
        return {
            getColor: (pst) => ctx.getImageData(pst|0, 0, 1, 1).data
        };
    }
    

    现在我们可以设置带有色标的对象了。

    const gr = new GradientReader([{stop: 0.0, color: '#f00'},
                                   {stop: 0.5, color: '#ff0'},
                                   {stop: 1.0, color: 'rgb(79,189,0)'}]);
    

    我们现在有一个模拟渐变的对象,我们现在需要做的就是用百分比值调用它的方法getColor()

    const col = gr.getColor(pst);
    el.style.backgroundColor = `rgb(${col[0]}, ${col[1]}, ${col[2]})`;
    

    FIDDLE

    根据您的喜好/需要进行修改。

    希望这会有所帮助!

    【讨论】:

    • 正是我需要的,谢谢。顺便说一句,您似乎对 Javascript 有深入的了解,您是如何做到的?
    • @Pankas 练习练习 :)
    • 很遗憾,我们不得不为如此简单的事情求助于这样的黑客。我需要在 SVG 文档的上下文中从 linearGradient 获取颜色,而且我不希望为此制作屏幕外画布。似乎编写手动插值程序是唯一(合理的,非基于画布的)选项?
    • 像魅力一样工作!非常感谢这种“开箱即用”的解决方案。
    【解决方案2】:

    这是我在 Angular 8 和一些 ES6 技术中使用上述答案的答案。新的百分比来自可观察者。

    HTML 文件包含一个 SVG,该 SVG 具有两个链接到该类的属性。像这样的:

    <svg>
     <circle [attr.stroke]='strokeColor' [attr.fill]='fillColor'>
    </svg>
    

    应用的 Typescript 文件:

    import {Component, Input, OnInit} from '@angular/core';
    import {Observable} from 'rxjs';
    
    @Component({
      selector: 'app-real-time-indicator',
      templateUrl: './real-time-indicator.component.html',
      styleUrls: ['./real-time-indicator.component.css']
    })
    export class RealTimeIndicatorComponent implements OnInit {
    
      @Input() percentagePassed$: Observable<number>;
      @Input() minutesRemaining$: Observable<number>;
    
      public currentPercentage: number;
      public minutesRemaining: number;
      private canvas2dContext: any;
      private canvas: any;
    
      public fillColor: string;
      public strokeColor: string;
    
      constructor() {
    
      }
    
      ngOnInit(): void {
        this.percentagePassed$.subscribe((newValue) => {
          this.currentPercentage = 100 - newValue;
          let [r, g, b]   = this.getColor( newValue);
          this.fillColor = `rgb(${r},${g},${b})`;
    
          [r, g, b]   = this.getColor( 100 - newValue);
          this.strokeColor = `rgb(${r},${g},${b})`;
        });
        this.canvas = document.createElement('canvas');     // create canvas element
        this.canvas2dContext = this.canvas.getContext('2d');                 // get context
        const gr = this.canvas2dContext.createLinearGradient(0, 0, 101, 0);   // create a gradient
    
        this.canvas.width = 101;                                // 101 pixels incl.
        this.canvas.height = 1;                                 // as the gradient
    
        const colorStops = [
          {stop: 0.0, color: 'lightgreen'},
          {stop: 0.9, color: 'orange'},
          {stop: 1.0, color: 'red'},
        ];
    
        for (const cs of colorStops)                       // add color stops
        {
          gr.addColorStop(cs.stop, cs.color);
        }
    
        this.canvas2dContext.fillStyle = gr;                                // set as fill style
        this.canvas2dContext.fillRect(0, 0, 101, 1);                        // draw a single line
    
      }
    
      // method to get color of gradient at % position [0, 100]
      getColor(percentage: number) {
        return this.canvas2dContext.getImageData(percentage , 0, 1, 1).data;
      }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2019-02-05
      • 1970-01-01
      • 1970-01-01
      • 2013-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-06
      • 1970-01-01
      相关资源
      最近更新 更多