canvas 奇巧淫技(二)绘制箭头路径效果

前几天有很多人问到了如何绘制高德地图那样的导航箭头线效果,当时想了想并不难就先用canvas 做了,然后集成到mapbox 上,迁移到其他map lib 也只需要应用相应的地理转屏幕坐标函数。

线的绘制样式

在canvas 的应用中我们经常会遇到各种线样式的绘制,比如虚线,渐变线,带pattern 线(箭头,铁轨图标等),或者虚线与pattern 的动画效果。如下图所示,总结下实现方法。

虚线样式

  • 利用 CanvasRenderingContext2D.setLineDash 的方法设置虚线样式, 接受一个数组类型的参数([solid: number, empty:number]) ,表示实线虚线的像素比例.

比如 ctx.setLineDash([10, 5]),就可以画出上图的虚线效果。发挥想象可以做出更多奇特效果。比如让虚线动起来,有走马灯的感觉。。

渐变线样式

通过 createLinearGradient 函数创建渐变,然后设定其渐变色段, 赋值给strokeStyle,渐变效果如开头图所示

// 创建一个从左到右的渐变,从绿色渐变到几乎透明,
var gradient = ctx.createLinearGradient(0, 0, 600, 0);
gradient.addColorStop(0, "rgba(0,255,100,0.9)");
gradient.addColorStop(1, "rgba(255,255,255,0.1)");
ctx.strokeStyle = gradient;
复制代码

有个问题就是如果需要渐变方向符合线条走向,这是常见需求,只需要提前算下每条线的范围和方向,创建对应的LinearGradient 即可,其实类似于下面的箭头绘制,需要反算 atan 角度一样的。

icon pattern 的线样式

最后这个算是综合的应用,我写了些canvas functions 放到了之前的canvasOverlay 里面去用,可以方便的集成到各种支持canvas 的lib 里面用。 基本思路就是:(懒得画图了,思路比较简单)

  • 每一个有向线段根据startPnt, endPnt 坐标反算 atan 弧度角

  • 设定一个stepSize,在线段上生成绘制图标的坐标,把ctx.原点平移到这个点,并且旋转弧度角去绘制 图标的偏向(熟悉canvas 的应该都明白,通过操作canvas 坐标轴去绘制旋转要素)

需要注意的是,atan弧度角的计算在第二三象限,会跟第一四象限混淆。比如向左下角的有向线的向量是两个负值,但是tan 值是正的,跟第一象限一样,所以反算的时候也会算出来小于90度的角,实际上是大于180 的角度了,需要 + Math.PI

大概的绘制过程,code as follow:

function generatePoints(startP, endP, stepSize = 30, ctx, aniOffset = 0.5, img) {
    let radA = Math.atan((endP[1] - startP[1]) / (endP[0] - startP[0]));
    if ((endP[0] - startP[0]) < 0) {
        radA += Math.PI;
    }
    const dist = calcDist(startP, endP);
    let points = [];
    const steps = dist / stepSize;

    const drawImg = (pX, pY) => {
        if (img && ctx) {
            ctx.save();
            ctx.translate(pX , pY);  // consider img position and imgWidth/Height.
            ctx.rotate(radA);
            ctx.drawImage(img, -img.width / 2,  -img.width/2);
            ctx.restore();
        }
    }

    // gen points by stepSize.. if enable corner arrow, start s with (0~1) float number.
    for (let s = aniOffset; s <= steps; s += 1) {
        const pX = Math.round(startP[0] + s * stepSize * Math.cos(radA));
        const pY = Math.round(startP[1] + s * stepSize * Math.sin(radA));
        points.push([pX, pY]);
        drawImg(pX, pY);
    }
    // console.warn(`icon Number: ${points.length}`);
    return points;
}

复制代码

就简单写到这里,集成mapbox 的DEMO

最近还有个问题提到比较多,关于canvas 上的图标如何贴合地图的倾斜,这也是个视觉上的问题。大抵上可以通过CSS3d 或者 canvas 的透视去做,前者应该更简单些。有空再实践下

因为之前也写过一些canvas 的文章,比如绘制风向图,希望形成一个系列,所以这次就叫第二篇,下一篇应该是icon与倾斜角的贴合实践

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您提供关于用canvas绘制箭头环形图的相关信息。这是一个很有趣的项目,需要一些基本的HTML5和JavaScript编程知识。在这里我提供一个简单的步骤指南: Step 1: 创建一个Canvas元素 首先,您需要在HTML文件中创建一个Canvas元素。在您的HTML文件中添加以下代码即可: ``` <canvas id="myCanvas" width="400" height="400"></canvas> ``` <br> Step 2: 设置Canvas样式 接下来,您需要设置Canvas的样式。样式可以用CSS来设置,也可以用JavaScript来设置。 ``` // CSS样式设置样例 canvas { background-color: #FFF; } // 使用JavaScript设置样式 var canvas = document.getElementById("myCanvas"); canvas.style.backgroundColor = "#FFF"; ``` <br> Step 3: 画一个环形图 现在,您需要使用JavaScript代码画一个环形图。 ``` var canvas = document.getElementById('myCanvas'); var context = canvas.getContext('2d'); var centerX = canvas.width / 2; var centerY = canvas.height / 2; var radius = 100; context.beginPath(); context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false); context.fillStyle = '#ddd'; context.fill(); context.lineWidth = 10; context.strokeStyle = '#aaa'; context.stroke(); ``` <br> Step 4: 添加箭头 最后,我们需要在环形图上添加一个箭头,这需要一些算法实现。这里我们提供一个简单的算法: ``` // 在一个圆形对象上绘制箭头 function drawArrow(context, start, end, radius) { var angle = Math.atan2(end.y - start.y, end.x - start.x); var x1 = end.x + radius * Math.cos(angle - Math.PI / 8); var y1 = end.y + radius * Math.sin(angle - Math.PI / 8); var x2 = end.x + radius * Math.cos(angle + Math.PI / 8); var y2 = end.y + radius * Math.sin(angle + Math.PI / 8); context.beginPath(); context.moveTo(x1, y1); context.lineTo(end.x, end.y); context.lineTo(x2, y2); context.strokeStyle = '#f00'; context.stroke(); } ``` 然后,我们调用绘制箭头的函数: ``` var start = {x: centerX - radius, y: centerY}; var end = {x: centerX + radius, y: centerY}; drawArrow(context, start, end, 10); ``` 现在,您可以在Canvas中看到一个环形图,并在图形中央看到一个箭头

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值