canvas-绘图库fabric.js简介

一般情况下简单的绘制,其实canvas原生方法也可以满足,比如画个线,绘制个圆形、正方形、加个文案。

  let canvas = document.getElementById('canvas');
  canvas.width = 1200;
  canvas.height = 600;
  canvas.style.width = '1200px';
  canvas.style.height = '600px';
  let ctx = canvas.getContext('2d');

  ctx.moveTo(400, 100);
  ctx.lineTo(400, 200);
  ctx.lineTo(500, 200);
  ctx.strokeStyle = "#00F";
  ctx.stroke();
  ctx.beginPath();

  ctx.arc(150, 150, 100, 0, 2 * Math.PI, true);
  ctx.fillStyle = '#ccc';
  ctx.fill();
  ctx.beginPath();

  let str1 = '苟利国家生死以,';
  let str2 = '岂因祸福避趋之!';
  ctx.font = '50px Microsoft Yahei';
  ctx.strokeStyle = 'red';
  ctx.textAlign = 'center';
  ctx.strokeText(str1, 800, 50);

  ctx.font = '50px SimHei';
  ctx.fillStyle = 'blue';
  ctx.textAlign = 'center';
  ctx.fillText(str2, 800, 100);
  //获取文本的宽度,以便以后能动态的使文本居中。
  let strWidth = ctx.measureText(str2).width;
  console.log(strWidth);

看效果图
在这里插入图片描述
如果真的只是这点需求,原生方法也很好,省的加载一个js库。不过现实往往还是很残酷的,怎么可能这么简单,这里都没有交互,比如在现有的图形上做位移、拖拽等等,复杂度就上来了,这时一个好的canvas js库就很有必要了。
fabric.js 算是我用到过的比较全面且好用的一个canvas js库;
先上代码:

const data = {
	line: [
		'1648.607594936709', '654.1772151898734', '2100.253164556962', '1290.126582278481'
	],
	area: [
		"1604.0506329113923", "607.5949367088607", "1648.607594936709", "654.1772151898734", "2100.253164556962", "1290.126582278481"
, "2211.645569620253", "1429.873417721519", "285.56962025316454" , "1429.873417721519" , "617.7215189873417" , "662.2784810126582"
	]
};
// 可以看出上面数据一个是画线,一个是画不规则区域,这是实际项目中用到的数据,拿到这里自有妙处,后面会说

fabric.js使用

import { fabric } from ‘fabric’;

// canvasDraw是canvas的 id
const canvasBox = new fabric.StaticCanvas('canvasDraw', {
  backgroundColor: "transparent"
 });
 // 这个是设置
 // canvas.style.width 和 canvas.width
 // canvas.style.height 和 canvas.height
canvasBox.setDimensions({
 width: 600,
 height: 300
});
// 下面方法等同于 setDimensions
// canvasBox.setWidth(width);
// canvasBox.setHeight(height);

// 这个是设置的 canvas.style.width 和 canvas.style.height
canvasBox._setCssDimension('width', 2400);
canvasBox._setCssDimension('height', 1500);

到此fabric初始化就算完成了,这里有个很重要的点,官方文档和几乎所有写fabric教学的博客都没有讲,那就是如何将canvas.style.width 和 canvas.width 赋予不同的数值,这是个很实用的点,因为坐标点是按canvas.width来的,但是我们的canvas.style.width必须和设计保持一致
比如说:我们需要在一张图片上做绘制,那坐标点是从图片原图上标注的,而设计不可能按原图大小展示,这时就会出现坐标点和canvas.style.width不一致,有两个方法解决这个问题:
1、坐标点根据 canvas.style.width / img.width 的比率做调整
2、canvas.width 和 img.width保持一致,canvas.style.width 和 设计稿 width一致
很显然第二个方案更简单且实用
既然官网没提供方法那我们就看源码都做了什么,因为canvas.width是必然要设置的
我们发现setDimensions时调用了 _setBackstoreDimension 和 _setCssDimension
在这里插入图片描述
很明显这里是canvas.width
在这里插入图片描述
而这里是canvas.style.width
在这里插入图片描述
今天先简单点,只看画线和画不规则图形

function drawLine(arr, color, opacity) {
 // [x1, y1, x2, y2]
  const line =  new fabric.Line(arr, {
    strokeWidth: 10, //线宽
    stroke: color, //线的颜色
    selectable: false,
    opacity: opacity
  });
  this.canvasBox.add(line);
}
function drawPolygon(arr, color, opacity) {
  const newArr = formatData(arr);
  const polygon = new fabric.Polygon(
    newArr,
    {
      fill: color,
      strokeWidth: 1,
      stroke: "#000",
      opacity: opacity
    }
  );
  this.canvasBox.add(polygon);
}
function formatData(arr) {
  // 将 [100,50,200,40] 坐标点转为 {x: 100, y: 50}
  let newArr = [];
  arr.forEach((val, i) => {
    i = i + 1;
    // 偶数不操作
    if ((i % 2) !== 0) {
      newArr.push({
        x: parseInt(val),
        y: parseInt(arr[i])
      });
    }
  });
  return newArr;
}

这时大家就会看到 我有个 parseInt的操作,因为当我使用原数据绘制时,线可以出来但Polygon却没有,搞得很郁闷,查了很长时间,最后当我盯着数据发呆时,看着长长的小数位 突发奇想,于是parseInt诞生了,页面也能看到区域了,真的是坑,这个点不做项目是绝无可能发现的。
也是我今天冒着延期项目也要搞这么一篇文章的原因,虽然fabric知识点不多但绝对满满的干货,更是告诉大家遇到问题后不要怕、更不能放弃,永远都能找到解题的方法,条条大路通罗马,一条不行就换一条,总会解决的!!!
之前时间太紧,没来得及说明下为什么用了parseInt就可以了,其实这个跟Number类型的特性有关,即:javascript以64位双精度浮点数存储所有Number类型值,计算机存储的为二进制,而能存储的二进制为62位,超出就会有舍入操作,因此 JS 中能精准表示的最大整数是Math.pow(2, 53) - 1,十进制即9007199254740992大于 9007199254740992 的可能会丢失精度,而我们的数据中有超出16位的,问题就出来了。
详细的解释大家可以看我这篇文章–JS-数据类型之数字(Number)

猜你喜欢

转载自blog.csdn.net/weixin_44384273/article/details/133085053