canvas 从ondraw中获取_canvas渐变线

本文介绍了如何使用canvas在JavaScript中绘制颜色渐变的线,以表达数据变化趋势。首先展示了基本的渐变线绘制,然后讨论了如何映射数据值到颜色,定义值的最大值和最小值以确定颜色范围。最后,通过getImageData方法获取颜色数组,并根据数据绘制渐变线。
摘要由CSDN通过智能技术生成

在做可视化的时候,我们经常需要使用颜色渐变的线来表达某个方向或者某条路径上的温度、降雨量等指标的变化趋势,通常这个指标并不是均匀分布的,因此线颜色的渐变也并不是均匀的,我们需要使用颜色表达出值的波动。canvas为我们提供了强大的绘图能力,接下来我们学习一下利用canvas提供的图形接口来显示这种颜色渐变线的效果。

540326e362135930d51fbd75d92b9c57.png

使用canvas绘制颜色渐变的线

首先我们先使用canvas绘制一条渐变的线,代码如下:

<canvas id="canvas" width="800" height="600" style="background: #cccccc;"></canvas>
<script type="text/javascript">
    var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');

    // 创建一个渐变,参数为:开始x坐标、开始y坐标、结束x坐标、结束y坐标、
    var grd=ctx.createLinearGradient(0, 0, 800, 0);
    // 为渐变添加颜色,参数1表示渐变开始和结束之间的位置(用0至1的占比表示),参数2位颜色
    grd.addColorStop(0,'yellow');
    grd.addColorStop(0.5,'red');
    grd.addColorStop(1,'blue');
    // 将渐变赋值给线的样式
    ctx.strokeStyle=grd;
    // 设置线的宽度
    ctx.lineWidth = 10;
    // 绘制线
    ctx.beginPath();
    ctx.moveTo(100, 100);
    ctx.lineTo(700, 500);
    ctx.stroke();
</script>

c30dcd02f67f852c9f9144de2096370b.png
渐变线

通过下面绘制的这条渐变的线可以看出,线的渐变的颜色只是将配置的渐变区域的颜色根据线的坐标直接映射到了线上。但是我们需要的渐变的线并不是这样简单的映射,因为我们绘制的线上的每一个点都是有值的,并且每一个值对应不同的颜色。

ctx.beginPath();
ctx.moveTo(100, 100);
ctx.lineTo(100, 500);
ctx.lineTo(700, 500);
ctx.stroke();

72e7bd1a87722a9928534c00c574eb33.png
配置的渐变区域

a6f473304345cae6000be9daa5b84c0a.png
根据渐变区域映射的渐变的线

映射值和颜色

前面我们学会了使用canvas去绘制一条渐变的线,但是这个渐变并不能完全的满足我们的需求。在实际的应用中我们拿到的每一点的数据通常是由坐标和该位置点的值组成的,x、y分别对应画布上的坐标,value表示该点的值。

const data = [{
    x: 10,
    y: 10,
    value: 34
}, {
    x: 50,
    y: 15,
    value: 134
}, {
    x: 100,
    y: 30,
    value: 298
}, {
    x: 150,
    y: 60,
    value: 404
}, {
    x: 200,
    y: 100,
    value: 734
}, …………]

定义值的最大值和最小值

const MAX_VALUE = 1000;
const MIN_VALUE = 0;

映射值的颜色,当值为1000时使用'#ff0000'红色,值为最小值0时颜色为 '#00ff00',顾名思义当值为500时颜色为'#ffff00'黄色

const colors = {
    0: '#00ff00',
    0.5: '#ffff00',
    1: '#ff0000'
}

那么如何将数据的value值和颜色映射到一起呐?当然你可以使用一些第三方插件来完成这个工作,这里我们介绍一种使用canvas来实现value—color映射对方法。首先我们创建一个宽度为256px高度为1px的canvas画布和一个线性渐变,将配置的colors添加到渐变中,并使用该渐变填充一个宽度256px高度1px的矩形,最后利用canvas的getImageData方法获取canvas内256*1范围的数据,得到的数组中存储的就是根据配置的颜色内插出来的颜色数组(具体结果参考getImageData方法)。

const palette = (function (palette) {
    let canvas = document.createElement('canvas'),
        ctx = canvas.getContext('2d'),
        gradient = ctx.createLinearGradient(0, 0, 256, 0);
    canvas.width = 256;
    canvas.height = 1;
    for (let i in palette) {
        gradient.addColorStop(i, palette[i]);
    }
    ctx.fillStyle = gradient;
    ctx.fillRect(0, 0, 256, 1);

    return ctx.getImageData(0, 0, 256, 1).data;
})(colors);

95cc72309c365282070a648589aa4f08.png
canvase(256*1)的渐变颜色

78ff72de01b231190ede946390d56559.png
内查后的颜色数组

根据值获得获得每个值对应的颜色。

function getRGBForValue(value) {
    let valueRelative = Math.min(Math.max((value - MIN_VALUE) / (MAX_VALUE - MIN_VALUE), 0), 1);
    // 计算value的颜色索引
    let paletteIndex = Math.floor(valueRelative * 256) * 4;
    return [palette[paletteIndex], palette[paletteIndex + 1], palette[paletteIndex + 2]];
}

绘制渐变的线

至此,我们已经会绘制渐变线和根据值获取其对应的颜色了,接下来我们就可以根据data来绘制一条根据数据来渐变的线了。

ctx.lineCap = 'round'; // 配置圆形的结束线帽,保证线在转折处能够紧密结合
for (let index = 0; index < data.length - 1; index++) {
    const startPoint = data[index];
    const endPoint = data[index + 1];
    let gradient = ctx.createLinearGradient(startPoint.x, startPoint.y, endPoint.x, endPoint.y);
    // 获取开始位置的颜色和结束位置的颜色
    let gradientStartRGB = getRGBForValue(startPoint.value);
    let gradientEndRGB = getRGBForValue(endPoint.value);
    // 根据颜色配置渐变 
    gradient.addColorStop(0, 'rgb(' + gradientStartRGB.join(',') + ')');
    gradient.addColorStop(1, 'rgb(' + gradientEndRGB.join(',') + ')');
    // 绘制线
    ctx.strokeStyle = gradient;
    ctx.lineWidth = 10;
    ctx.beginPath();
    ctx.moveTo(startPoint.x, startPoint.y);
    ctx.lineTo(endPoint.x, endPoint.y);
    ctx.stroke();
}

0e1b7e2d1fb0814d6e980a6d49cfadcd.png
最后结果

参考:

https://iosphere.github.io/Leaflet.hotline/demo/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值