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#,很多内容一知半解,边摸索边前进,代码粗糙,权当留个脚印. 只是想得到一个基础的移动和缩放功能的界面,找了很久都是画线.画矩形等基础形状的代码,移动和缩放说的并不清晰,只能自己努力来 ...
随机推荐
- VO、DTO、Entity的区别
只能说从实际用法的一般习惯上进行区分: 1.entity 里的每一个字段,与数据库相对应,注意:entity与对应的实际数据库表的字段 没有强制要求但是一般建议保持一致(包括字段数据类型),当然,从实 ...
- [CF1364E] X-OR
X-OR 题面翻译 题目描述 本题是交互题. 有一个固定的长度为 \(n\) 的排列 \(P\),其值域为 \([0,n-1]\),你可以进行不超过 \(4269\) 次询问,之后你需要输出这个排列 ...
- leetcode:354 俄罗斯套娃信封问题(LIS)
解题思路: 根据题意,不难发现组合的元素,他们的长宽都是单调递增的,因此可以转化为最长上升子序列问题. 首先按照长度从小到大对信封进行排序,长度相同,按照宽度从大到小进行排序.因为当长度相同,因为可能 ...
- nginx下的proxy_pass使用
之前的文章说到了,return,rewrite的使用,以及它们的使用场景,今天再来说一种代理的使用,proxy_pass,它属于nginx下的ngx_http_proxy_module模块,没有显示的 ...
- zabbix-agent报错记录
Too many parameters 由于agent版本差异监控项的参数不一样 , 解决方法升级agent版本 Cannot obtain filesystem information: [2] N ...
- Linux 多路复用(多路转接)
出现原因 如果需要从一个文件描述符中读取数据,然后将数据写入到另一个文件描述符时,可以按照如下的阻塞 IO : while ((n = read(STDIN_FILENO, buf, BUFFER_S ...
- Git commit emoji 对照表
emoji emoji代码 commit说明 (调色板) :art: 改进代码结构/代码格式 ️ (闪电) :zap: 提升性能 (赛马) :racehorse: 提升性能 (火焰) :fire: 移 ...
- UE5: UpdateOverlap - 从源码深入探究UE的重叠触发
前言 出于工作需要和个人好奇,本文对UE重叠事件更新的主要函数UpdateOverlaps从源码的角度进行了详细的分析,通过阅读源码,深入理解重叠事件是如何被触发和更新的. 解决问题 阅读本文,你将得 ...
- MySQL进阶篇:详解存储引擎MyISAM
MySQL进阶篇:第一章_一.三_存储引擎特点_MyISAM 1.1 存储引擎特点 1.1.2 MyISAM 1). 介绍 MyISAM是MySQL早期的默认存储引擎.. 2). 特点 不支持事务,不 ...
- 第四部分_Shell脚本数组和其他变量
数组定义 ㈠ 数组分类 普通数组:只能使用整数作为数组索引(元素的下标) 关联数组:可以使用字符串作为数组索引(元素的下标) ㈡ 普通数组定义 可以切片 一次赋予一个值 #数组名[索引下标]=值 ar ...