工欲善其事,必先利其器。要想打造自己的可视化引擎,那就必须要先熟悉Cavas API。Canvas具体教程可以参考Canvas MDN。下面我们将对Cavas API进行简单的说明。
基本用法
<canvas>是HTML 5 新增的元素,在浏览器创建一个固定大小的画布。通过Document.getElementById() 方法获取HTML <canvas> 元素的引用。HTMLCanvasElement.getContext() 方法获取该画布上的上下文context,我们可以称之为画笔。通过画笔,我们就可以在画布上绘制图形了。下面时一个简单的官方绘制绿色矩形的示例:
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'green'; // 设置画笔颜色——绿色
ctx.fillRect(10, 10, 150, 100); // 在坐标(10, 10)处绘制宽为150,高为100的长方形
绘图API
Cavas为我们提供了许多绘图API,我们将简单的介绍本系列文章中常用的API,其他具体API可以参见Canvas MDN。
绘制函数
- 绘制矩形
清除矩形区域 clearRect(x, y, width, height);
填充矩形区域 fillRect(x, y, width, height);
绘制矩形边框 strokeRect(x, y, width, height); - 路径
新建路劲 beginPath();
移动画笔至指定坐标 moveTo(x, y);
从当前位置到指定坐标的直线 lineTo(x, y);
在指定坐标绘制半径的圆弧 arc(x, y, radius, startAngle, endAngle, anticlockwise);
绘制二次贝塞尔曲线 quadraticCurveTo(cp1x, cp1y, x, y);
绘制三次贝塞尔曲线 bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
闭合路径 closePath();
绘制图形轮廓 stroke();
填充图形路径 stroke(); - 文本
指定位置填充文本 fillText(text, x, y [, maxWidth]); 指定位置绘制文本边框 strokeText(text, x, y [, maxWidth]); - 图像
绘制指定图像 drawImage(image, sx, sy, [sWidth, sHeight, dx, dy, dWidth, dHeight]);
样式
- 颜色:fillStyle(填充颜色)/strokeStyle(轮廓颜色);
- 透明度: globalAlpha;
- 线性: lineWidth(线宽)/lineCap(末端样式)/lineJoin(线条接合样式)/miterLimit(交接处最大长度);
- 渐变: createRadialGradient(x1, y1, r1, x2, [y2, r2])/addColorStop(position, color)
- 阴影: shadowOffsetX(X轴阴影)/shadowOffsetY(Y轴阴影)/shadowBlur(模糊程度)/shadowColor(阴影颜色)
其他
- save() 保存画笔状态
- restore() 回复画笔保存时状态快照
- translate(x, y) 画布位置偏移
- rotate(angle) 画布旋转
- scale(x, y) 画布缩放
下面一个例子,我们将对上面API做一个简单的应用
<canvas id="canvas" width="500" height="500"></canvas>
<button onclick="draw('rect')">长方形</button>
<button onclick="draw('rect_str')">长方形框</button>
<button onclick="draw('angle3')">三角形</button>
<button onclick="draw('arc')">圆弧</button>
<button onclick="draw('bezier')">贝塞尔绘制爱心</button>
<script type="text/javascript">
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
function draw(type) {
let posX = Math.round(Math.random() * 500);
let posY = Math.round(Math.random() * 500);
if (type === 'rect') {
ctx.fillRect(posX, posY, 100, 150);
} else if(type === 'rect_str') {
ctx.strokeRect(posX, posY, 100, 100);
} else if(type === 'angle3') {
ctx.beginPath();
ctx.moveTo(posX, posY);
ctx.lineTo(posX + 50, posY - 50);
ctx.lineTo(posX, posY - 100);
ctx.closePath();
ctx.fill();
} else if(type === 'arc') {
ctx.beginPath();
ctx.arc(posX, posY, 50, 0, Math.PI * 2, true);
ctx.closePath();
ctx.stroke();
} else if(type === 'bezier') {
ctx.beginPath();
ctx.moveTo(75,40);
ctx.bezierCurveTo(75,37,70,25,50,25);
ctx.bezierCurveTo(20,25,20,62.5,20,62.5);
ctx.bezierCurveTo(20,80,40,102,75,120);
ctx.bezierCurveTo(110,102,130,80,130,62.5);
ctx.bezierCurveTo(130,62.5,130,25,100,25);
ctx.bezierCurveTo(85,25,75,37,75,40);
ctx.fill();
} else if(type === 'text') {
ctx.font="20px Georgia";
ctx.fillText("Hello World!", posX, posY);
}
}
</script>
封装Canvas
Canvas类
由上一节例子可以看出,对于每次绘制图形时必须创建<canvas>标签,同时保存画笔对象context,并通过context绘制图形,为了后续更好的管理画布,我们这里对Canvas进行了封装。本引擎以面向对象的方式管理图元。
认识CanvasWidth属性和样式Width的区别
在封装Canvas类之前,我们先来了解一下canvas width 属性与canvas 样式width的区别。width属性是Canvas画布的宽度,样式width是canvas文档流中的宽度。样式width是canvas在文档流中实际的像素大小,width属性是Canvas画布的宽度,相对于画笔而言的虚拟宽度,可以理解为画笔所能精确到的细度。假设canvas的样式width为300px, canvas的width属性为600px,这意味着画笔能够绘制相对于文档页面0.5px的宽度。默认情况下Canvas的Canvas Width属性和样式属性为1:1。
代码
class Canvas {
constructor(config) {
if (config.ele === undefined) {
throw new Error('Not found config of canvas element');
}
// canvas 标签的容器标签
this.container = config.ele;
// 设置canvas width属性与样式width 的比率
this.ratio = config.ratio || 2;
// 创建 canvas 标签
this.canvas = document.createElement('canvas');
this.childs = [];
this.init();
}
/**
* 重新定义Canvas的大小
*/
repaint() {
this.container.innerHTML = '';
this.canvas = document.createElement('canvas');
this.init();
}
/**
* 初始化Canvas系数
*/
init() {
// 获取容器的样式
const styles = getComputedStyle(this.container, null);
// 容器的宽
const width = parseInt(styles.width);
// 容器的高
const height = parseInt(styles.height);
// 设置canvas的样式宽
this.canvas.style.width = `${width}px`;
// 设置canvas的样式高
this.canvas.style.height = `${height}px`;
// 根据比率设置相应的属性宽高
this.canvas.width = this.ratio * width; //设置缩放比
this.canvas.height = this.ratio * height;
// 去除点击选中样式
this.canvas.style.outline = 'none';
this.canvas.onclick = (e) => { this.canvas.focus(); };
this.container.appendChild(this.canvas);
// 设置画笔属性
this.painter = this.canvas.getContext('2d');
}
}
由上述代码,我们只需要对新建一个Canvas类,就能获取到画笔工具,使用例子如下:
<style>
.bigger{
width: 200px;
height:200px;
}
</style>
<div class="bigger" id="canvas" />
let dv = document.getElementById('canvas');
let canvas = new Canvas({
ele: dv
});
canvas.painter.fillRect(0, 0, 100, 150);
目录
【实现自己的可视化引擎01】认识Canvas
【实现自己的可视化框架引擎02】抽象图像元素
【实现自己的可视化引擎03】构建基础图元库
【实现自己的可视化引擎04】图像元素动画
【实现自己的可视化引擎05】交互与事件
【实现自己的可视化引擎06】折线图
【实现自己的可视化引擎07】柱状图
【实现自己的可视化引擎08】条形图
【实现自己的可视化引擎09】饼图
【实现自己的可视化引擎10】散点图
【实现自己的可视化引擎11】雷达图
【实现自己的可视化引擎12】K线图
【实现自己的可视化引擎13】仪表盘
【实现自己的可视化引擎14】地图
【实现自己的可视化引擎15】关系图