一般情况下简单的绘制,其实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知识点不多但绝对满满的干货,更是告诉大家遇到问题后不要怕、更不能放弃,永远都能找到解题的方法,条条大路通罗马,一条不行就换一条,总会解决的!!!