Canvas实现画布的缩放
主要介绍三种方式:
首先创建一个index.html文件

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>iot</title>
</head>
<body>
<canvas id="canvas" width="800" height="800" style="width: 800px;height: 800px;border: 1px solid gray;margin: auto;display: flex;"></canvas>
</body>
</html>
<script type="module">
import index from './index.js';
window.onload = (() => {
index.init();
})
</script>
index.html
一、使用canvas style属性和 width以及height属性实现缩放效果
优点:代码简单、易开发
缺点:当放大活缩小到一定倍数时容易失真,且只能围绕画布左上角缩放,效果不好,且不能实现编辑等功能
原理:canvas中style样式的height和width属性修饰的是DOM元素的样式,而canvas自有的height和width属性描述的是画布的大小,当这两种样式等比例关系时,就可以实现放大和缩小
/**
* 通过改变canvas的样式来实现缩放,原理是通过canvas的style中height和width 以及自带的width和height属性不同的比例实现缩放
* flag true:放大 false: 缩小
*/
function zoom1(flag = true) {
const curH = Number(canvas.getAttribute('height'));
const curW = Number(canvas.getAttribute('width'));
canvas.setAttribute('width', flag ? curW * scale : curW / scale);
canvas.setAttribute('height', flag ? curH * scale : curH / scale);
}

二、使用canvas API scale方法实现图形的缩放
优点:代码简洁,可以按照鼠标所在位置进行缩放
缺点:图形边框等会随着缩放,且有一定的失真;缩放后,图形原始坐标点会随着缩放等比例变化,不方便实现编辑功能
/**
* 通过改变canvas的样式来实现缩放,原理是通过canvas的scale属性缩放横纵轴
* flag true:放大 false: 缩小
*/
function zoom2(flag = true) {
const beta = flag ? 1 / scale : scale;
ctx.scale(beta, beta);
}

三、根据缩放比例重新计算点坐标,首推这种方式
优点:图形边框等不会随着缩放而变化,图形不会失真,可以根据缩放后的坐标点实现一些编辑功能(比如选中高亮)
缺点:需要针对不同的图形元素动态计算坐标点,逻辑较为繁琐
已缩小为例,原理图如下:
缩小时需要同时考虑图形距离鼠标位置更近以及图形大小也同比例缩小,所以最好办法是:
1. 计算缩小后图形中心点距离鼠标的位置B,可以根据缩小前图形中心点A的横纵坐标乘以一个比例得到。
2. 再根据位置B计算各个顶点的坐标,计算时要注意各个顶点之间的距离也要等比例缩小

/**
* 通过改变坐标点信息实现缩放,可以设置缩放的中心点
* flag true:放大 false: 缩小
*/
function zoom3(flag = true, event) {
// 记录当前鼠标的相对位置
initX = event.offsetX;
initY = event.offsetY;
// 计算放大缩小的比例
multi = 1 * (flag ? 1 / scale : scale); // 获取图形中心点
const center = getCenter();
// 获取图形最大最小的顶点坐标
const maxMin = getMaxMin();
// 计算缩放后的中心点坐标
const newC = [center[0] - (initX - center[0]) * (multi - 1), center[0] - (initY - center[1]) * (multi - 1)]; // 根据缩放后的中心点计算各个顶点信息
coordinates = coordinates.map(e => {
const operateX = center[0] - e[0] > 0 ? 1 : -1;
const operateY = center[1] - e[1] > 0 ? 1 : -1;
return [newC[0] - (maxMin.maxX - maxMin.minX) * multi / 2 * operateX, newC[1] - (maxMin.maxY - maxMin.minY) * multi / 2 * operateY];
})
}

下面附上完整的JS代码

let canvas;
let ctx;
let coordinates = [[50, 50], [250, 50], [250, 250], [50, 250]];
const scale = 0.8;
let [initX, initY] = [0, 0]; let multi = 1;
function init() {
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
draw();
drawText();
addEvent();
} function draw () {
ctx.lineWidth = 4;
ctx.strokeStyle = 'rgba(153, 153, 153, 1)';
ctx.moveTo(...coordinates[0]);
ctx.beginPath();
for (let i = 0; i < coordinates.length; i++) {
ctx.lineTo(...coordinates[i]);
}
ctx.closePath();
ctx.stroke();
} function getMaxMin() {
const x = coordinates.map(e => e[0]);
const y = coordinates.map(e => e[1]); return {
maxX: Math.max(...x),
minX: Math.min(...x),
maxY: Math.max(...y),
minY: Math.min(...y),
}
} function getCenter() {
const maxMin = getMaxMin();
return [(maxMin.maxX + maxMin.minX) / 2, (maxMin.minY + maxMin.maxY) / 2];
} /**
* 绘制文本内容
*/
function drawText() {
const maxMin = getMaxMin();
ctx.save();
ctx.translate((maxMin.maxX + maxMin.minX) / 2, (maxMin.maxY + maxMin.minY) / 2);
ctx.font = '20px serif';
ctx.fillStyle = '#333';
ctx.textAlign = 'center';
ctx.fillText('测试Canvas缩放功能', 0, 0, maxMin.maxX - maxMin.minX);
ctx.restore();
} /**
* 通过改变canvas的样式来实现缩放,原理是通过canvas的style中height和width 以及自带的width和height属性不同的比例实现缩放
* flag true:放大 false: 缩小
*/
function zoom1(flag = true) {
const curH = Number(canvas.getAttribute('height'));
const curW = Number(canvas.getAttribute('width'));
canvas.setAttribute('width', flag ? curW * scale : curW / scale);
canvas.setAttribute('height', flag ? curH * scale : curH / scale);
} /**
* 通过改变canvas的样式来实现缩放,原理是通过canvas的scale属性缩放横纵轴
* 优点:代码量少
* 缺点:会改变数据的原始属性
* flag true:放大 false: 缩小
*/
function zoom2(flag = true) {
const beta = flag ? 1 / scale : scale;
ctx.scale(beta, beta);
} /**
* 通过改变坐标点信息实现缩放,可以设置缩放的中心点
* 优点:代码量较大,需要修改每个要素的坐标点
* 缺点:会改变数据的原始属性
* flag true:放大 false: 缩小
*/
function zoom3(flag = true, event) {
// 记录当前鼠标的相对位置
initX = event.offsetX;
initY = event.offsetY;
// 计算放大缩小的比例
multi = 1 * (flag ? 1 / scale : scale); // 获取图形中心点
const center = getCenter();
// 获取图形最大最小的顶点坐标
const maxMin = getMaxMin();
// 计算缩放后的中心点坐标
const newC = [center[0] - (initX - center[0]) * (multi - 1), center[0] - (initY - center[1]) * (multi - 1)]; // 根据缩放后的中心点计算各个顶点信息
coordinates = coordinates.map(e => {
const operateX = center[0] - e[0] > 0 ? 1 : -1;
const operateY = center[1] - e[1] > 0 ? 1 : -1;
return [newC[0] - (maxMin.maxX - maxMin.minX) * multi / 2 * operateX, newC[1] - (maxMin.maxY - maxMin.minY) * multi / 2 * operateY];
})
} function addEvent() {
ctx.beginPath();
ctx.arc(0, 0, 5, 0, Math.PI * 2);
ctx.stroke();
const minMax = getMaxMin(coordinates);
canvas.addEventListener('mousewheel', event => {
ctx.clearRect(0, 0, 1600, 1600);
// zoom1(event.wheelDelta > 0); // zoom2(event.wheelDelta > 0); zoom3(event.wheelDelta > 0, event);
draw();
drawText(); ctx.restore();
});
} export default { init, addEvent };
Canvas实现画布的缩放的更多相关文章
- 通过Canvas及File API缩放并上传图片
原文地址:Resize an Image Using Canvas, Drag and Drop and the File API 示例地址:Canvas Resize Demo 原文作者:Dr. T ...
- 通过Canvas及File API缩放并上传图片完整演示样例
创建一个只管的用户界面,并同意你控制图片的大小.上传到server端的数据,并不须要处理enctype为 multi-part/form-data 的情况.只一个简单的POST表单处理程序就能够了. ...
- 安卓自定义View进阶-Canvas之画布操作 转载
安卓自定义View进阶-Canvas之画布操作 转载 https://www.gcssloop.com/customview/Canvas_Convert 本来想把画布操作放到后面部分的,但是发现很多 ...
- 通过Canvas及File API缩放并上传图片完整示例
<!DOCTYPE html> <html> <head> <title>通过Canvas及File API缩放并上传图片</title> ...
- HTML5 Canvas(画布)实战编程初级篇:基本介绍和基础画布元素
欢迎大家阅读HTML5 Canvas(画布)实战编程初级篇系列,在这个系列中,我们将介绍最简单的HTML5画布编程.包括: 画布元素 绘制直线 绘制曲线 绘制路径 绘制图形 绘制颜色,渐变和图案 绘制 ...
- Canvas对画布及文字控制基础API学习
这次纯API练习,比较简单,但是是为了之后的结合项目打基础的,所以也不能忽视它,下面开始: Canvas的平移.旋转.缩放 这里还是以上次画那个青春痘的DEMO为例[http://www.cnblog ...
- canvas图片编辑操作:缩放、移动、保存(PC端+移动端)
最近在写canvas关于图片的操作,看了网上的代码基本都是不行的,于是就自己写了一个. html代码 <canvas id="myCanvas" width="37 ...
- canvas实例:旋转缩放的方块
首先在页面中创建一个canvas标签: <body> <canvas id="c1" width="500" height="500 ...
- (网页)html5 canvas清空画布方法(转)
总结以下三种清空canvas画布的方式: 1. 最简单的方法:由于canvas每当高度或宽度被重设时,画布内容就会被清空,因此可以用以下方法清空: function clearCanvas() { v ...
- WPF 中Canvas图形移动、缩放代码
从Flash转C#,很多内容一知半解,边摸索边前进,代码粗糙,权当留个脚印. 只是想得到一个基础的移动和缩放功能的界面,找了很久都是画线.画矩形等基础形状的代码,移动和缩放说的并不清晰,只能自己努力来 ...
随机推荐
- [ABC309G] Ban Permutation
Problem Statement Find the number, modulo $998244353$, of permutations $P=(P_1,P_2,\dots,P_N)$ of $( ...
- [ABC263C] Monotonically Increasing
Notes For two integer sequences of the same length $A_1,A_2,\dots,A_N$ and $B_1,B_2,\dots,B_N$, $A$ ...
- [ABC280G] Do Use Hexagon Grid 2
Problem Statement A hexagonal cell is represented as $(i,j)$ with two integers $i$ and $j$. Cell $(i ...
- [.NET开发者的福音]一个方便易用的在线.NET代码编辑工具.NET Fiddle
前言 今天给大家分享一个方便易用的.NET在线代码编辑工具,能够帮助.NET开发人员快速完成代码编写.测试和分享的需求(.NET开发者的福音):.NET Fiddle. .NET Fiddle介绍 我 ...
- MySQL运维10-Mycat分库分表之一致性哈希分片
一.一致性哈希分片 一致性哈希分片的实现思路和我们之前介绍的水平分表中的取模分片是类似的.只不过取模分片,采用的是利用主键和分片数进行取模运算,然后根据取模后的结果,将数据写入到不同的分片数据中.但是 ...
- 创建定义store并使用组合式api、选项式api
在项目根目录创建store文件夹(此步骤和vuex相同) 在步骤一的store文件夹下根据不同的用途场景创建单独的store文件(等同于vuex中分模块). 定义store基本步骤 步骤 导入defi ...
- Scrapy-settings.py常规配置
# Scrapy settings for scrapy_demo project # # For simplicity, this file contains only settings consi ...
- Java多线程学习(Day01)
目录 线程简介 线程实现(重点) 线程状态 线程同步(重点) 线程通信问题 进程与线程概念 --来自百度百科的解释: 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资 ...
- DES加密算法优缺点大揭秘:为何它逐渐被取代?
一.引言 DES(Data Encryption Standard)加密算法作为一种历史悠久的对称加密算法,自1972年由美国国家标准局(NBS)发布以来,广泛应用于各种数据安全场景.本文将从算法原理 ...
- python在容器内克隆拉取git私有仓库
前言 目前有个python应用需要在容器镜像内拉取git私有仓库的代码,一开始的想法是用GitPython,折腾一番ssh私钥和known_hosts问题后,发现还是在镜像中封装个git最省事,然后用 ...