前言

这几天接了个活,须要做一个停车场示意图,首先想到的是应用 Canvas 来绘制。因为后期只是浅显的应用过 Canvas,而没有正式的在我的项目中应用过,这次也是摸着文档过河。

如何绘制

Canvas 是画布,是一个须要脚本来绘制图形的 Html 标签。<canvas> 简略的应用

<canvas id="canvas"></canvas>

间接在页面上增加标签,必须应用脚本来绘制图形

var canvas = document.getElementById('canvas');var ctx = canvas.getContext('2d');// 设置宽高canvas.width = 500;canvas.height = 500;ctx.beginPath(); // 开始门路ctx.rect(10, 10, 100, 100); // 绘制矩形ctx.fillStyle = '#eee'; // 填充色彩ctx.fill(); // 门路填充

能够看到一个简略的矩形会呈现在画布中

其中 getContext 是获取 Canvas 对象;它有两个参数:

  • contextType 上下文类型(2d, webgl, webgl2)
  • contextAttributes 上下文属性;具体可参考MDN

画布存在默认高度 300 × 150,这里的高度设置是有一点须要留神的:如果咱们应用 css 来设置高度时,画布会依照 300 × 150 的比例进行缩放,如果你设置 500 × 500 可能会变形。所以咱们最好还是应用 Javascript 或者在标签上间接设置高宽度。

绘制步骤

从下面的一系列应用状况,咱们能够总结出大略的绘制门路的办法

创立画布

应用 ID 来获取 canvas 对象

var canvas = document.getElementById('canvas');var ctx = canvas.getContext('2d');

开始绘制门路

应用 beginPath 开始绘制

ctx.beginPath();

绘制门路

这里咱们能够应用 Canvas 提供的各种绘制门路的办法;常见的一些绘制办法

办法形容
arc()创立圆弧
rect()创立矩形
fillRect()绘制矩形门路区域
strokeRect()绘制矩形门路描边
arcTo()创立两切线之间的弧/曲线
moveTo()把门路挪动到画布中的指定点,不创立线条
lineTo()增加一个新点,而后在画布中创立从该点到最初指定点的线条
clip()从原始画布剪切任意形态和尺寸的区域
quadraticCurveTo()创立二次方贝塞尔曲线
bezierCurveTo()创立三次方贝塞尔曲线

填充或者描边

绘制完门路后,能够抉择敞开门路 closePath 或者间接填充或描边门路,这些都是一些惯例办法

ctx.fillStyle = '#eee'; // 填充色彩ctx.fill(); // 门路填充ctx.strokeStyle = 'red'; // 门路描边色彩ctx.stroke(); // 门路描边

每个绘制的图形图案能够分成这根本的 4 步。咱们须要理解的其实是每次绘制的坐标点,只有坐标点是确认的,绘制进去的图形还是没有什么误差。

画布操作

当把停车场绘制实现后,须要实现点击车位显示车位应用状况;因为点击 Canvas 只能监听到点击的坐标点,须要判断用户点击地位是否在车位内,而当初晓得车位的起始点坐标与车位宽高,所以判断条件为

// 用户点击坐标 point// 车位绘制信息 polylinePoints  function checkPointInPolyline(point, polylinePoints) {    // 当 x > 车位起始点 && x < 起始点 + 车位宽度 && y > 起始点 && y < 起始点 + 车位高度    if (      point.x >= polylinePoints.x &&      point.x <= polylinePoints.x + polylinePoints.w &&      point.y >= polylinePoints.y &&      point.y <= polylinePoints.y + polylinePoints.h    ) {      return true;    } else {      return false;    }  }

咱们都晓得 canvas 在绘制的过程中,是以页面左上角原点 (0, 0) 开始绘制,然而因为停车场是一个垂直居中布局,当咱们点击画布的原点失去的坐标是:

能够看到咱们失去并不是靠近 (0, 0) 的坐标点,这是因为鼠标是以 documnet 的左上角为原点获取坐标;因而如果点击车位中某一点时,须要对点击的某点 (x, y) 进行转换。
这里须要用到 getBoundingclientRect 这个函数,它是用于取得页面中某个元素的左,上,右和下别离绝对浏览器视窗的地位;利用失去的 lefttop 值进行转换

canvas.addEventListener('click', function(e) {  console.log(convertPoint(e.x, e.y))})function convertPoint(x, y) {  var _info = canvas.getBoundingClientRect()  return {    x: x - _info.left,    y: y - _info.top  }}

接下来能够看到,坐标点靠近 (0, 0) 画布原点。

字体

在 Canvas 绘制字体,要害是应用 fillText(text, x, y [, maxWidth]) 函数:

  • text 是文本
  • x, y 是绘制的起始点
  • maxWidth 填充文本占据的最大宽度

一个残缺的字体绘制也很简略

ctx.fillStyle = '#333';ctx.font = '18px SimSun, Songti SC';ctx.textAlign = 'center';ctx.textBaseline = 'middle';ctx.fillText('imondo.cn', 200, 200);


然而咱们想应用自定义字体时,应用惯例的 @font-face 设置发现是没有用的,因为浏览器加载字体个别都是懒加载,在绘制的过程中,字体还未加载胜利;这里举荐一个新的 API new FontFace,能够监听到字体加载,而且是个 Pormise

  const myFont = new FontFace('myFont', 'url(./webfont.ttf)');  var _this = this;  myFont    .load()    .then((font) => {      document.fonts.add(font);    })    .then(function () {      ctx.fillStyle = color;      ctx.font = fontSize + ' myFont';      ctx.textAlign = 'center';      ctx.textBaseline = 'middle';      ctx.fillText(text, x, y);    });

兼容性还算能够,当然 IE 就不要思考了(IE:感觉有被触犯到 )

画布旋转缩放

Canvas 的旋转与缩放别离应用 rotatescale ,最须要留神的是它们都是基于默认中心点 (0, 0) 来旋转或缩放,所以在进行操作前,咱们须要应用 translate 来扭转中心点。
当咱们须要旋转文字 90° 时,须要先扭转中心点,再进行旋转,旋转后须要从新还原中心点,不然下次beginPath
绘制时,会基于 translate 后的中心点绘制

ctx.beginPath()ctx.translate(200, 200);ctx.rotate( 90 * Math.PI / 180)ctx.translate(-200, -200);ctx.fillStyle = '#333';ctx.font = '18px SimSun, Songti SC';ctx.textAlign = 'center';ctx.textBaseline = 'middle';ctx.fillText('imondo.cn', 200, 200);


同理缩放操作也是一样

ctx.translate(200, 200);ctx.scale(1.5, 1.5);ctx.translate(-200, -200);


其实就是,绘制开始的坐标就是须要 translate 的坐标。

挪动端含糊解决

当把整个停车场绘制实现后,看着还不错;不过当在手机上关上时,含糊的使人有几百度远视;查遍全网,还是挪动端设施像素比的问题。解决办法就是检测设施像素比,绘制对应倍数比例的 canvas 元素

function createHDCanvas(w = 300, h = 150) {  var ratio = window.devicePixelRatio || 1;  var canvas = document.getElementById('canvas');  canvas.width = w * ratio; // 理论渲染像素  canvas.height = h * ratio; // 理论渲染像素  canvas.style.width = `${w}px`; // 管制显示大小  canvas.style.height = `${h}px`; // 管制显示大小  canvas.getContext('2d').setTransform(ratio, 0, 0, ratio, 0, 0);  return canvas;}

成果

  • 源码:地址

  • 参考:

    • 监听Canvas外部元素点击事件的三种办法
    • 聊聊canvas的元素选中
    • canvas 显示含糊问题

    欢送关注【前端学啥】一起交换