【问题标题】:Smooth color transition between multiple color stops多个色标之间的平滑颜色过渡
【发布时间】:2016-04-13 14:42:33
【问题描述】:

我正在尝试使用画布绘制我的网站的滚动范围地图。我有一堆 Y 坐标和到达该点的访客数量。我使用到达该点的访客数量为每个坐标着色。比方说

10 位用户正在访问我的网站。

5 个用户滚动到 = 0, 300px 3 个用户向上滚动 = 300, 700px 2 个用户向上滚动 = 700、800 像素

现在,我分别有 3 个色标(300、700、800)像素。并且着色应该基于用户的数量。我这样做了,但是停靠点之间的过渡很平滑,看起来很稳固。

var Scroll = function(config, data) {
    var container, computed;
    this.data = data;
    this.config = config;
    container = document.querySelector(this.config.container);
    this.canvas = document.createElement('canvas');
    this.ctx = this.canvas.getContext('2d');
    computed = getComputedStyle(container) || {};
    this.canvas.className = 'zarget-scrollmap-canvas';
    this.width = this.canvas.width = this.config.width || +(computed.width.replace(/px/, ''));
    this.height = this.canvas.height = this.config.height || +(computed.height.replace(/px/, ''));
    this.canvas.style.cssText = 'position:absolute; top: 0px; left:0px';
    container.appendChild(this.canvas);

    var map = function(value, istart, istop, ostart, ostop) {
       return ostart + (ostop - ostart) * ((value - istart) / (istop - istart));
    };

    this.mapIntensityToColor = function(intensity, min, max) {
       var cint = map(intensity, min, max, 0, 255);

      /**
       * Based On Rainbow Gradient
       */
       if (cint > 204) {
          return [255, Math.round(map(intensity, min, max, 255, 0)), 0];
       }

       if (cint > 153) {
          max = (203 / 255 * 100) * (max / 100);
          return [Math.round(map(intensity, 0, max, 255, 0)), 255, 0];
       }

       if (cint > 102) {
          max = (153 / 255 * 100) * (max / 100);
          return [0, 255, Math.round(map(intensity, 0, max, 255, 0))];
       }

       if (cint > 0) {
          max = (102 / 255 * 100) * (max / 100);
          return [0, Math.round(map(intensity, 0, max, 255, 0)), 255];
       }
       max = (51 / 255 * 100) * (max / 100);
       return [0, 0, Math.round(map(intensity, 0, max, 0, 255))];
    };

    this.draw = function(data) {
      var min = 0;
      var max = 1300;
      var data = [
        [0, 50, 1300],
        [50, 100, 1100],
        [100, 150, 1100],
        [150, 200, 1000],
        [200, 250, 500],
        [250, 300, 400],
        [300, 350, 300],
        [350, 450, 200],
        [450, 500, 400],
        [500, 900, 0],
        [900, 950, 300],
        [950, 3350, 0]
      ];
      var point, startY, endY, alpha, val, color;
      this.ctx.globalAlpha = 0.75;

      for (var i = 0, l = data.length; i < l; i++) {
        point = data[i];
        startY = point[0];
        endY = point[1];
        val = point[2];
        color = this.mapIntensityToColor(val, min, max);
        this.ctx.fillStyle = "rgb(" + color.join(",") + ")";
        this.ctx.fillRect(0, startY, this.width, endY - startY);
    }

};};
var a = new Scroll({"container": "#overlay"});
a.draw();
#overlay {
  width: 100%;
  height: 2000px;
  position: absolute;
  top: 0px;
  left: 0px;
}
<div id="overlay"></div>

上述函数的输出

预期输出

我尝试使用线性渐变,但颜色混合很差。

线性渐变

https://jsfiddle.net/bdxeca48/2/

【问题讨论】:

  • ...期望的结果/问题是什么?
  • 问题:1.颜色之间的过渡不好。 2.如何停止颜色@正确的y点。输出:我需要像所附图像一样的输出。
  • intensity 代表什么?代码缺少插值器。
  • 它是包含到达Y轴点的人数的值。帮助挑选颜色。
  • 我相信我下面的回答就是你想要的。然而,由于某种原因,我错过了赏金,但无法解释...... :(

标签: javascript canvas gradient


【解决方案1】:

您可以在每一步的“中间”使用带有单一色标的线性渐变:

this.draw = function(data) {
    var min = 0;
    var max = 1300;
    var data = [
        [0, 50, 1300],
        [50, 100, 1100],
        [100, 150, 1100],
        [150, 200, 1000],
        [200, 250, 500],
        [250, 300, 400],
        [300, 350, 300],
        [350, 450, 200],
        [450, 500, 400],
        [500, 900, 0],
        [900, 950, 300],
        [950, 3350, 0]
    ];

    var point, startY, endY, alpha, val, color;
    this.ctx.globalAlpha = 0.75;

    // Calculate the maximum y scrolled
    var maxScrollY = 0;
    for(var i = 0, l = data.length; i < l; i++){
        point = data[i];
        if(maxScrollY < point[1]){
            maxScrollY = point[1];
        }
    }
    // here, maxScrollY will be 3350

    var linearGrad = ctx.createLinearGradient(0, 0, 0, maxScrollY);

    // Build the gradient
    for (var i = 0, l = data.length; i < l; i++) {
        point = data[i];

        // You have to divide the coordinate by maxScrollY to get
        // coordinates between 0.0 and 1.0
        startY = point[0] / maxScrollY;
        endY = point[1] / maxScrollY;

        // Take the y coordinate between startY and endY for the color stop coordinate
        var middleY = startY + (endY-startY)/2;

        val = point[2];
        color = this.mapIntensityToColor(val, min, max);
        linearGrad.addColorStop(middleY, "rgb(" + color.join(",") + ")");
    }

    // Then just render
    ctx.fillStyle = linearGrad;
    ctx.fillRect(0, 0, this.width, maxScrollY);
}

结果:

这是一个演示:https://jsfiddle.net/4n294hb1/

【讨论】:

  • 我已经试过了,但是颜色混合很差。 jsfiddle.net/bdxeca48/2
  • 只需在每一步的“中间”添加一个色标。
  • 需要添加任何插值颜色以使其平滑jsfiddle.net/4n294hb1/1。您可以在小提琴链接中感受到红色和绿色之间的黑暗
【解决方案2】:

在这里提琴:https://jsfiddle.net/Lfhdzw2c/

我用这个替换了你的 IntensityToColor 函数,这是我从https://rainbowcoding.com/how-to-create-rainbow-text-in-html-css-javascript/借来的

function color_from_hue(hue)
{
  var h = hue/60;
  var c = 255;
  var x = (1 - Math.abs(h%2 - 1))*255;
  var color;

  var i = Math.floor(h);
  if (i == 0) color = rgb_to_hex(c, x, 0);
  else if (i == 1) color = rgb_to_hex(x, c, 0);
  else if (i == 2) color = rgb_to_hex(0, c, x);
  else if (i == 3) color = rgb_to_hex(0, x, c);
  else if (i == 4) color = rgb_to_hex(x, 0, c);
  else color = rgb_to_hex(c, 0, x);

  return color;
}

【讨论】:

    猜你喜欢
    • 2014-03-17
    • 1970-01-01
    • 1970-01-01
    • 2013-11-19
    • 2014-02-11
    • 2022-12-25
    • 1970-01-01
    • 2014-03-17
    • 1970-01-01
    相关资源
    最近更新 更多