主要介绍三种方式:

首先创建一个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实现画布的缩放的更多相关文章

  1. 通过Canvas及File API缩放并上传图片

    原文地址:Resize an Image Using Canvas, Drag and Drop and the File API 示例地址:Canvas Resize Demo 原文作者:Dr. T ...

  2. 通过Canvas及File API缩放并上传图片完整演示样例

    创建一个只管的用户界面,并同意你控制图片的大小.上传到server端的数据,并不须要处理enctype为 multi-part/form-data 的情况.只一个简单的POST表单处理程序就能够了. ...

  3. 安卓自定义View进阶-Canvas之画布操作 转载

    安卓自定义View进阶-Canvas之画布操作 转载 https://www.gcssloop.com/customview/Canvas_Convert 本来想把画布操作放到后面部分的,但是发现很多 ...

  4. 通过Canvas及File API缩放并上传图片完整示例

    <!DOCTYPE html> <html> <head> <title>通过Canvas及File API缩放并上传图片</title> ...

  5. HTML5 Canvas(画布)实战编程初级篇:基本介绍和基础画布元素

    欢迎大家阅读HTML5 Canvas(画布)实战编程初级篇系列,在这个系列中,我们将介绍最简单的HTML5画布编程.包括: 画布元素 绘制直线 绘制曲线 绘制路径 绘制图形 绘制颜色,渐变和图案 绘制 ...

  6. Canvas对画布及文字控制基础API学习

    这次纯API练习,比较简单,但是是为了之后的结合项目打基础的,所以也不能忽视它,下面开始: Canvas的平移.旋转.缩放 这里还是以上次画那个青春痘的DEMO为例[http://www.cnblog ...

  7. canvas图片编辑操作:缩放、移动、保存(PC端+移动端)

    最近在写canvas关于图片的操作,看了网上的代码基本都是不行的,于是就自己写了一个. html代码 <canvas id="myCanvas" width="37 ...

  8. canvas实例:旋转缩放的方块

    首先在页面中创建一个canvas标签: <body> <canvas id="c1" width="500" height="500 ...

  9. (网页)html5 canvas清空画布方法(转)

    总结以下三种清空canvas画布的方式: 1. 最简单的方法:由于canvas每当高度或宽度被重设时,画布内容就会被清空,因此可以用以下方法清空: function clearCanvas() { v ...

  10. WPF 中Canvas图形移动、缩放代码

    从Flash转C#,很多内容一知半解,边摸索边前进,代码粗糙,权当留个脚印. 只是想得到一个基础的移动和缩放功能的界面,找了很久都是画线.画矩形等基础形状的代码,移动和缩放说的并不清晰,只能自己努力来 ...

随机推荐

  1. Protobuf的使用,结合idea

    安装Protobuf并配置idea Protocol Buffers(又名 protobuf)是 Google 的中立语言, 平台中立.可扩展的结构化数据序列化机制. 官网: https://gith ...

  2. 吉特日化MES & SQL Server中的数据类型

    一. 整数数据类型 1.bit bit数据类型是整型,其值只能是0.1或空值.这种数据类型用于存储只有两种可能值的数据,如Yes 或No.True 或False .On 或Off.注意:很省空间的一种 ...

  3. [USACO2007NOVG] Telephone Wire G

    题目描述 Farmer John's cows are getting restless about their poor telephone service; they want FJ to rep ...

  4. 通过 VS Code 优雅地编辑 Pod 内的代码(非 NodePort)

    目录 1. 概述 2. NodePort 方式 3. Ingress 方式 4. 救命稻草 5. 其他 1. 概述 今天聊点啥呢,话说,你有没有想过怎样用 VS Code 连上 K8s 集群内的某个 ...

  5. SpringBoot整合Liquibase

    1.是什么? Liquibase官网 Liquibase是一个开源的数据库管理工具,可以帮助开发人员管理和跟踪数据库变更.它可以与各种关系型数据库和NoSQL数据库一起使用,并提供多种数据库任务自动化 ...

  6. MybatisPlus高级特性之ActiveRecord模式

    1.是什么? ActiveRecord是一种领域模型模式,特点是一个模型类对应关系型数据库中的一个表:而模型类的一个实例对应表中的一行记录.ActiveRecord 一直广受解释型动态语言 ( PHP ...

  7. NetSuite 开发日记 —— 事务处理行限制

    一.创建行限制 在 NetSuite 中处理事务时,一次可访问的记录.事务处理或数据行数限制为 10,000.除非另有说明,此限制适用于所有交易类型.超过 1,000 行可能会对 Netsuite 的 ...

  8. BUUCTF-Crypto详细Writeup

    每一天都要努力啊    ----2024-01-01 18:11:36 1.一眼就解密 原题:下面的字符串解密后便能获得flag:ZmxhZ3tUSEVfRkxBR19PRl9USElTX1NUUkl ...

  9. 神经网络优化篇:详解梯度的数值逼近(Numerical approximation of gradients)

    在实施backprop时,有一个测试叫做梯度检验,它的作用是确保backprop正确实施.因为有时候,虽然写下了这些方程式,却不能100%确定,执行backprop的所有细节都是正确的.为了逐渐实现梯 ...

  10. Feign源码解析5:loadbalancer

    背景 经过前面几篇的理解,我们大致梳理清楚了FeignClient的创建.Feign调用的大体流程,本篇会深入Feign调用中涉及的另一个重要组件:loadbalancer,了解loadbalance ...