之前写过一篇文章——用 scale 构建可缩放的画布,这次就来介绍下,另外一个很有意思的 canvas api,叫做 translate。
按照惯例,还是先上 mdn 文档:https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/translate,避免因为我个人的拙见,而对大家产生什么误导。
首先 translate 的作用是什么呢?简单点说,就是平移画布用的。
默认情况下,我们把 canvas 左上角看作是我们画布的原点,也就是坐标为 (0, 0) 的点,然后我们调用各种 API 绘制图形的时候,都是根据这个坐标系来进行的。
但是这个局限的地方在于,如果我们希望拥有一张无限大小的 canvas 画布,为了查看我们可是区域范围外面的内容,我们应该采用什么方式呢?
- 坐标系不变,给我们画布上的图形的坐标整体进行平移
- 画布上的图形坐标不发生变化,给坐标系进行平移
通常来说,这两种方式其实是大同小异,可谓是殊途同归吧。
但是因为 canvas 直接提供了 translate 这个 api,所以明显用第二种方式,更加的简洁明了。
下面我就谈一谈,怎么用第二种方式,构建一个无限大小的画布了。
1. 抽象出 render 方法
首先,我么需要沿用我们之前的 demo 里面的思想,抽象出一个 render 方法出来。
每次需要改变 canvas 画布里面的内容的时候,就动态的去调用这个方法,重新渲染 canvas 里面的内容。
const render = () => {
// 清空画布
ctx.clearRect(0, 0, w, h);
// 存储上下文
ctx.save();
// 通过 translate,平移坐标系
ctx.translate(origin.x, origin.y);
// 调用每一个对象 render 方法,绘制每个单独的对象
objects.forEach(node => {
node.render();
});
// 恢复上下文
ctx.restore();
};
可以看到,我们每次平移了一个 origin 坐标,这个坐标就是我们每次动态绘制的时候,需要传入的对象。
2. 按下鼠标拖动画布
我们需要朝 canvas 上添加鼠标按下事件,并且在按下的过程中,添加一个 mousemove 事件。
事件的作用就是当鼠标在拖动的过程中,计算出偏移,然后动态的调用 render 方法,对整个画布进行渲染。
//元素的鼠标落下事件
canvas.onmousedown = function(ev) {
//event的兼容性
var ev = ev || event;
//获取鼠标按下的坐标
var x1 = ev.clientX;
var y1 = ev.clientY;
// 获取 canvas 元素的范围大小
const bcr = canvas.getBoundingClientRect();
// 混存之前的坐标点,也就是第一次
var temp = JSON.parse(JSON.stringify(origin));
//给可视区域添加鼠标的移动事件
document.onmousemove = function(ev) {
//event的兼容性
var ev = ev || event;
//获取鼠标移动时的坐标
var x2 = ev.clientX;
var y2 = ev.clientY;
//计算出鼠标的移动距离
var x = x2 - x1;
var y = y2 - y1;
//更改元素的left,top值
origin.x = temp.x + x;
origin.y = temp.y + y;
render();
};
//清除
document.onmouseup = function(ev) {
document.onmousemove = null;
};
};
3. 效果
以下是构建出来的效果:
![Aug-29-2019 23-01-10.gif](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4ubmxhcmsuY29tL3l1cXVlLzAvMjAxOS9naWYvMjA0OTU0LzE1NjcwOTA5MTg5MjYtOWViMDgyY2YtYmY0MS00ZDk5LWJjYjktZGNhZmM5YTQ5ODc2LmdpZg#align=left&display=inline&height=534&name=Aug-29-2019 23-01-10.gif&originHeight=534&originWidth=562&size=942237&status=done&width=562)
可以看到的是,我再拖动的时候很平滑,就像是我真的有一张无限大小的画布一样。