利用canvas阴影功能与双线技巧绘制轨道交通大屏项目效果

简介: 利用canvas阴影功能与双线技巧绘制轨道交通大屏项目效果

利用canvas阴影功能与双线技巧绘制轨道交通大屏项目效果


前言分析设计稿实现效果绘制空心线与发光效果绘制倒影绘制轨道中间的斑马线效果结语


前言


近日公司接到一个轨道系统的需求,需要将地铁线路及列车实时位置展示在大屏上。既然是大屏项目,那视觉效果当然是第一重点,咱们可以先来看看项目完成后的效果图。


微信图片_20220425132516.gifline.gif


可以看到中间线路里轨道的效果是非常炫酷的,那么本文的主要内容就是讲解如何在canvas上绘制出这种效果。


分析设计稿


先看看设计稿中的轨道效果


微信图片_20220425132519.jpg123.jpg


程序员解决问题时经常喜欢用到的方法是把一个大问题拆解为若干个小问题然后逐一处理,也就是分而治之,所以我在思考这个轨道效果的实现时,也是先考虑到将它拆解。


根据设计稿我们可以看到这个线路实际上是由 外层的空心线+发光效果+内层的斑马线+倒影 组成的,所以我们要做的就是如何处理这几个小问题。


实现效果


绘制空心线与发光效果


绘制空心线时我们需要利用到


[CanvasRenderingContext2D.globalCompositeOperation](https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation)


这个属性,详细原理可以查看canvas 绘制双线技巧,本文不再做赘述。


了解实现原理之后动手就很容易了,简述思路就是:

通过ctx.globalCompositeOperation = "destination-out"绘制空心线,再利用canvas的阴影配置来模拟发光的效果。


直接上代码:


1//  获取页面里的画布元素和其上下文对象
 2var canvas = document.getElementById("canvas");
 3var ctx = canvas.getContext("2d");
 4//  由于ctx.globalCompositeOperation = "destination-out"会影响到画布上已有的图像
 5//  所以需要先创建一个离屏canvas,把空心线绘制到离屏canvas上,再将离屏canvas绘制到页面的画布中
 6var tempCanvas = document.createElement("canvas");
 7tempCanvas.width = 800;
 8tempCanvas.height = 800;
 9var tempCtx = tempCanvas.getContext("2d");
10//  创建坐标点用来连线
11var points = [createPoint(50, 50), createPoint(500, 50), createPoint(500, 500)];
12//  配置参数
13var options = {
14  color: "#03a4fe", //  轨道颜色
15  lineWidth: 26,    //  总宽度
16  borderWidth: 8,   //  边框宽度
17  shadowBlur: 20,   //  阴影模糊半径
18};
19paint(ctx, points, options);
20//  绘制
21function paint(ctx, points, options) {
22  paintHollow(tempCtx, points, options);
23  //    将离屏canvas绘制到页面上
24  ctx.drawImage(tempCanvas, 0, 0);
25}
26/**
27 * 绘制空心线
28 * @param {*} ctx 画布上下文
29 * @param {*} points 坐标点的集合
30 * @param {*} options 配置 
31 */
32function paintHollow(
33  ctx,
34  points,
35  { color, lineWidth, borderWidth, shadowBlur }
36) {
37    //  连线
38  paintLine(ctx, points);
39  //    添加配置参数
40  ctx.lineWidth = lineWidth;
41  ctx.strokeStyle = color;
42  ctx.lineCap = "round";
43  ctx.lineJoin = "round";
44  //    利用阴影
45  ctx.shadowColor = color;
46  ctx.shadowOffsetX = 0;
47  ctx.shadowOffsetY = 0;
48  ctx.shadowBlur = shadowBlur;
49  ctx.stroke();
50  ctx.globalCompositeOperation = "destination-out";
51  ctx.lineWidth -= borderWidth;
52  ctx.strokeStyle = color;
53  ctx.stroke();
54  ctx.globalCompositeOperation = "source-over";
55}
56/**
57 * 根据点位绘制连线
58 * @param {*} ctx 画布上下文
59 * @param {Array} points 坐标点的集合
60 */
61function paintLine(ctx, points) {
62  var pointIndex = 0,
63    p0,
64    value,
65    pointCount = points.length;
66  p0 = points[0];
67  ctx.beginPath();
68  ctx.moveTo(p0.x, p0.y);
69  for (pointIndex = 1; pointIndex < pointCount; pointIndex++) {
70    value = points[pointIndex];
71    ctx.lineTo(value.x, value.y);
72  }
73}


效果图


微信图片_20220425132526.pngimage.png


绘制倒影


可以看到设计稿里的倒影效果就是在轨道下方再次绘制了一条透明度较低的空心线,所以这里实现起来就比较简单了,稍微改造一下paintHollow方法就可以。


1/**
 2 * 绘制空心线
 3 * @param {*} ctx 画布上下文
 4 * @param {*} points 坐标点的集合
 5 * @param {*} options 配置
 6 * @param {*} isReflect 当前绘制的是否是倒影效果
 7 */
 8function paintHollow(
 9  ctx,
10  points,
11  { color, lineWidth, borderWidth, shadowBlur, reflectOffset },
12  isReflect = false
13) {
14  if (!isReflect) {
15      //    绘制倒影的时候透明度降低
16    ctx.globalAlpha = 0.5;
17    //  通过自调绘制一个倒影效果出来
18    paintHollow(
19      ctx,
20      points.map(({ x, y }) => {
21        return { x, y: y + reflectOffset };
22      }),
23      { color, lineWidth, borderWidth, shadowBlur: 0 },
24      true
25    );
26    ctx.globalAlpha = 1;
27  }
28  //  连线
29  paintLine(ctx, points);
30  //    添加配置参数
31  ctx.lineWidth = lineWidth;
32  ctx.strokeStyle = color;
33  ctx.lineCap = "round";
34  ctx.lineJoin = "round";
35  //    利用阴影
36  ctx.shadowColor = color;
37  ctx.shadowOffsetX = 0;
38  ctx.shadowOffsetY = 0;
39  ctx.shadowBlur = shadowBlur;
40  ctx.stroke();
41  ctx.globalCompositeOperation = "destination-out";
42  ctx.lineWidth -= borderWidth;
43  ctx.strokeStyle = color;
44  ctx.stroke();
45  ctx.globalCompositeOperation = "source-over";
46}


效果图


微信图片_20220425132529.pngimage.png


绘制轨道中间的斑马线效果


中间的斑马线效果我们又可以再拆分为两个部分,先绘制一条底色的连线,然后再通过lineDash属性绘制一条虚线,就可以达到设计稿上的效果了。


1/**
 2 * 绘制轨道中间部分
 3 * @param {*} ctx 
 4 * @param {*} points 
 5 * @param {*} param2 
 6 */
 7function paintInner(
 8  ctx,
 9  points,
10  { color, innerWidth, borderWidth, innerColor, shadowBlur }
11) {
12  ctx.lineCap = "round";
13  ctx.lineJoin = "round";
14  paintLine(ctx, points);
15  ctx.lineWidth = innerWidth;
16  ctx.shadowOffsetX = 0;
17  ctx.shadowOffsetY = 0;
18  ctx.shadowBlur = shadowBlur;
19  ctx.strokeStyle = innerColor;
20  ctx.shadowColor = color;
21  //  先根据中间部分的颜色绘制一条线出来
22  ctx.stroke();
23  ctx.lineCap = "butt";
24  ctx.setLineDash([5, 15]);
25  ctx.lineDashOffset = 0;
26  const { r, g: green, b } = getRgba(color);
27  //  再根据轨道的主色调绘制一条透明度较低的虚线
28  ctx.strokeStyle = `rgba(${r},${green},${b},0.4)`;
29  ctx.stroke();
30}
31/**
32 * 获取一个颜色值的r,g,b,a
33 * @param {*} color 
34 */
35function getRgba(color) {
36  if (!canvas1 || !ctx1) {
37    canvas1 = document.createElement("canvas");
38    canvas1.width = 1;
39    canvas1.height = 1;
40    ctx1 = canvas1.getContext("2d");
41  }
42  canvas1.width = 1;
43  ctx1.fillStyle = color;
44  ctx1.fillRect(0, 0, 1, 1);
45  const colorData = ctx1.getImageData(0, 0, 1, 1).data;
46  return {
47    r: colorData[0],
48    g: colorData[1],
49    b: colorData[2],
50    a: colorData[3],
51  };
52}


效果图


微信图片_20220425132533.pngimage.png


至此我们就还原了设计稿上的轨道效果了!


结语


至此文章已经到达尾声,我们可以总结一下绘制这条轨道线路效果所用到的技术点

  1. CanvasRenderingContext2D.globalCompositeOperation
  2. CanvasRenderingContext2D.shadowBlur
  3. CanvasRenderingContext2D.setLineDash()
  4. 离屏canvas技巧


可以看到想要达到好的效果还是不容易的,需要我们灵活配合使用多种绘制技巧,希望这篇文章能对大家有所帮助!

相关文章
|
10月前
|
搜索推荐 定位技术
百度地图开发mapStyle个性化地图styleJson的配色解决方案
百度地图开发mapStyle个性化地图styleJson的配色解决方案
486 0
|
小程序 前端开发
微信小程序中使用画布canvas实现动态心电图绘制
微信小程序中使用画布canvas实现动态心电图绘制
453 0
微信小程序中使用画布canvas实现动态心电图绘制
|
定位技术 API 网络架构
地图图层接入:从mapbox转向cesium
由于地图坐标系的不统一,地图图商提供的图层服务也各有特色,在图层对接的开发过程中常会遇到许多坑,从二维图层到三维图层,地图引擎mapbox再到cesium,本文将分享笔者在近期地图图层接入过程中总结的一些经验。
3217 10
|
3天前
|
存储 缓存 Java
Android开发之利用GL10描绘点、线、面
本文介绍了如何使用GL10进行三维图形绘制。首先,每个点由三个浮点数(x, y, z)表示,数组大小为顶点数的三倍来构建平面。接着,通过`FloatBuffer`将浮点数组转换为OpenGL可识别的格式。绘制图形时,需启用和禁用顶点开关,并调用`glVertexPointer`指定顶点坐标和`glDrawArrays`绘制点、线、面。文中展示了绘制立方体线框的代码,包括顶点数组转换、立方体各面的定义以及绘制方法。最后,提到了球体的绘制概念。
10 1
Android开发之利用GL10描绘点、线、面
|
7月前
|
搜索推荐 图形学
透明度和透明贴图制作玻璃水杯
模型透明度是控制整个模型的透明度属性,而透明贴图是一种贴图技术,用于控制模型表面每个像素的透明度级别。透明贴图可以与模型的透明度属性结合使用,以实现更复杂和精细的透明效果。通过调整透明贴图的透明度通道,可以实现模型表面不同部分的个性化透明度设置。
111 0
|
10月前
|
定位技术
Echarts实战案例代码(39):地理坐标整体地图背景色渐变效果和字体随地图缩放的解决方案
Echarts实战案例代码(39):地理坐标整体地图背景色渐变效果和字体随地图缩放的解决方案
192 0
|
10月前
|
JSON 前端开发 数据可视化
Echarts实战案例代码(4):地图散点气泡图飞线(迁徙线)API接口前端处理数据的解决方案
Echarts实战案例代码(4):地图散点气泡图飞线(迁徙线)API接口前端处理数据的解决方案
242 0
|
10月前
Photoshop绘制立体效果的拟物化时钟图标
Photoshop绘制立体效果的拟物化时钟图标
51 0
|
11月前
|
前端开发 JavaScript 容器
前端|利用<canvas>画布制作地球轨道
前端|利用<canvas>画布制作地球轨道
179 0
|
数据可视化 定位技术 开发者
地图的路网、边界等线条底图素材的获取方法
本文介绍获取定制地图中路网、水体等线条素材底图的免费方法~
362 1