canvas中放入一张图片,但是其中的图片可以旋转移动,这是怎么确定的?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了canvas中放入一张图片,但是其中的图片可以旋转移动,这是怎么确定的?相关的知识,希望对你有一定的参考价值。

参考技术A 使用canvas来实现旋转效果。

function rotate(obj,arr)
...
// 对现代浏览器写入html5的元素进行旋转: canvas
else
var c = document.getElementById('canvas_'+obj);
if(c== null)
img.style.visibility = 'hidden';
img.style.position = 'absolute';
c = document.createElement('canvas');
c.setAttribute("id",'canvas_'+obj);
img.parentNode.appendChild(c);

var canvasContext = c.getContext('2d');
switch(n)
default :
case 0 :
c.setAttribute('width', img.width);
c.setAttribute('height', img.height);
canvasContext.rotate(0 * Math.PI / 180);
canvasContext.drawImage(img, 0, 0);
break;
case 1 :
c.setAttribute('width', img.height);
c.setAttribute('height', img.width);
canvasContext.rotate(90 * Math.PI / 180);
canvasContext.drawImage(img, 0, -img.height);
break;
case 2 :
c.setAttribute('width', img.width);
c.setAttribute('height', img.height);
canvasContext.rotate(180 * Math.PI / 180);
canvasContext.drawImage(img, -img.width, -img.height);
break;
case 3 :
c.setAttribute('width', img.height);
c.setAttribute('height', img.width);
canvasContext.rotate(270 * Math.PI / 180);
canvasContext.drawImage(img, -img.width, 0);
break;
;



代码中,创建canvas元素对象,并将图片赋予canvas对象,当变量n处于不同的状态(上下左右四个方向)时,使用canvas重新对图像进行绘制。
参考技术B 通常旋转都是相对于原点来的,可以通过旋转整个画布来达到旋转图片的目的。这样图片的坐标是不变的,正常移动即可了。

electron学习笔记如何通过electron实现图片查看器

前言

对于图片查看器,在实践中做了两种方案的对比。

第一种是借助 canvas 的方案,如果使用 canvas 会生成一张静态图片, 并且操作 canvas 旋转时,旋转后的坐标比较难计算,对于计算图片的放大缩小有一定的难度。

第二种是 “img+css+js” 的组合方案,可以支持 gif 的动态图片。

相比之下,img 只需要操作 css,其旋转后的坐标也比较容易计算,并且旋转使用了transform 来提高渲染的性能。


下面来介绍一下 “img+css+js” 组合方案的实现方式。


实现效果

【electron学习笔记】如何通过electron实现图片查看器_css

可参考如下html:

<main class="imageView-container">
<div class="image-view" id="image-view" @contextmenu="showRightMenuFunc">
...
<img
:src="link"
v-show="link && !imageLoad"
:
:
@load="onload"
class="imageSrc"
:style="position"
id="imgSrc"
/>
<img src="/img/loading.gif" class="img-loading" v-show="imageLoad" />
<div class="pre" @click.stop="optHandle(pre)" :title="preTip" :style="show">
<i class="iconfont icon icon-prev"></i>
</div>
<div class="next" @click.stop="optHandle(next)" :title="nextTip" :style="show">
<i class="iconfont icon icon-next"></i>
</div>
</div>
<div class="image-opt">
...
</div>
</main>


核心功能

放大缩小的难点在于,需要随鼠标放大、缩小、旋转后的坐标变换。

1、先记录鼠标的位置​

// 滚轮放大缩小
imageView.onmousewheel = imageView.onwheel = (event: any) =>
// 记录当前鼠标的位置
const imageView: any = document.getElementById("image-view");
const box = imageView.getBoundingClientRect();
const tempPos =
x: event.x - box.left,
y: event.y - box.top,
;
const x = position.left.substring(0, position.left.indexOf("px"));
const y = position.top.substring(0, position.left.indexOf("px"));
startPointX.value = Number(((pos.x - Number(x)) / imgScale.value).toFixed(2));
startPointY.value = Number(((pos.y - Number(y)) / imgScale.value).toFixed(2));
pos.x = tempPos.x;
pos.y = tempPos.y;
if (event.wheelDelta > 0)
increase();
else
decrease();

;


2、放大​

/**
* @description: 放大
* @param *
* @return *
*/
const increase = () =>
const image = imageArr[index.value];
if (imgScale.value == 15)
return;

let rR = imgScale.value + 0.1;
if (rR > 15)
rR = 15;

const width = image.width * rR;
const height = image.height * rR;
const [wrapW, wrapH] = getRect();
let x = (1 - rR) * startPointX.value + (pos.x - startPointX.value);
let y = (1 - rR) * startPointY.value + (pos.y - startPointY.value);
if (rotateIndex.value % 2 == 0)
// console.log(height, wrapW, wrapH, width, x, y);
if (width <= wrapW)
x = (wrapW - width) / 2;
else if (width >= wrapW && x > 0)
x = 0;
else if (width + x < wrapW)
x = wrapW - width;

if (height <= wrapH)
y = (wrapH - height) / 2;
else if (height >= wrapH && y > 0)
y = 0;
else if (height + y < wrapH)
y = wrapH - height;

else
const abs = Math.abs(width / 2 - height / 2);
let X = 0;
let Y = 0;
if (imgWidth.value < imgHeight.value)
X = x - abs;
Y = y + abs;
else
X = x + abs;
Y = y - abs;

if (height <= wrapW)
x = (wrapW - width) / 2;
else if (height >= wrapW && X > 0)
if (imgWidth.value < imgHeight.value)
x = +abs;
else
x = -abs;

else if (height + X <= wrapW)
const mx = wrapW - height;
if (imgWidth.value < imgHeight.value)
x = mx + abs;
else
x = mx - abs;


if (width <= wrapH)
y = (wrapH - height) / 2;
else if (width >= wrapH && Y > 0)
if (imgWidth.value < imgHeight.value)
y = -abs;
else
y = abs;

else if (width + Y <= wrapH)
const my = wrapH - width;
if (imgWidth.value < imgHeight.value)
y = my - abs;
else
y = my + abs;



imgScale.value = rR;
position.left = x + "px";
position.top = y + "px";
imgWidth.value = width;
imgHeight.value = height;
;


3、缩小​

/**
* @description: 缩小
* @param *
* @return *
*/
const decrease = () =>
const image = imageArr[index.value];
if (imgScale.value == 0.01)
return;

let rR = imgScale.value - 0.1;
if (rR < 0.01)
rR = 0.01;

const width = image.width * rR;
const height = image.height * rR;
const [wrapW, wrapH] = getRect();
// 判断鼠标是否在图片上
let x = (1 - rR) * startPointX.value + (pos.x - startPointX.value);
let y = (1 - rR) * startPointY.value + (pos.y - startPointY.value);
if (rotateIndex.value % 2 == 0)
// console.log(height, wrapW, wrapH, width, x, y);
if (width <= wrapW)
x = (wrapW - width) / 2;
else if (width >= wrapW && x > 0)
x = 0;
else if (width + x < wrapW)
x = wrapW - width;

if (height <= wrapH)
y = (wrapH - height) / 2;
else if (height >= wrapH && y > 0)
y = 0;
else if (height + y < wrapH)
y = wrapH - height;

else
const abs = Math.abs(width / 2 - height / 2);
let X = 0;
let Y = 0;
if (imgWidth.value < imgHeight.value)
X = x - abs;
Y = y + abs;
else
X = x + abs;
Y = y - abs;

if (height <= wrapW)
x = (wrapW - width) / 2;
else if (height >= wrapW && X > 0)
if (imgWidth.value < imgHeight.value)
x = +abs;
else
x = -abs;

else if (height + X <= wrapW)
const mx = wrapW - height;
if (imgWidth.value < imgHeight.value)
x = mx + abs;
else
x = mx - abs;


if (width <= wrapH)
y = (wrapH - height) / 2;
else if (width >= wrapH && Y > 0)
if (imgWidth.value < imgHeight.value)
y = -abs;
else
y = abs;

else if (width + Y <= wrapH)
const my = wrapH - width;
if (imgWidth.value < imgHeight.value)
y = my - abs;
else
y = my + abs;



imgScale.value = rR;
position.left = x + "px";
position.top = y + "px";
imgWidth.value = width;
imgHeight.value = height;
;


4、移动

const imageV: any = document.getElementById("imgSrc");
imageV.onmousedown = (e: any) =>
e.preventDefault();
e.target.setAttribute("draggable", true);
e.target.style.cursor = "pointer";
const startX = e.clientX;
const startY = e.clientY;
const left = position.left;
const leftX = Number(left.substring(0, left.indexOf("px")));
const top = position.top;
const topX = Number(top.substring(0, top.indexOf("px")));
imageV.onmouseup = () =>
e.target.setAttribute("draggable", false);
e.target.style.cursor = "default";
imageV.onmouseup = null;
imageV.mouseleave = null;
imageV.onmousemove = null;
;
imageV.onmouseleave = () =>
e.target.setAttribute("draggable", false);
e.target.style.cursor = "default";
imageV.onmouseup = null;
imageV.mouseleave = null;
imageV.onmousemove = null;
;
imageV.onmousemove = (event: any) =>
const [w, h] = getRect();
const moveX = event.clientX;
const moveY = event.clientY;
let moveLeft = leftX + (moveX - startX);
let moveTop = topX + (moveY - startY);
const abs = Math.abs(imgWidth.value / 2 - imgHeight.value / 2);
let leftT = 0;
let topT = 0;
if (rotateIndex.value % 2 !== 0)
if (imgHeight.value <= w && imgWidth.value <= h)
return;

if (imgWidth.value < imgHeight.value)
leftT = leftX - abs + (moveX - startX);
topT = topX + abs + (moveY - startY);
else
leftT = leftX + abs + (moveX - startX);
topT = topX - abs + (moveY - startY);

if (leftT > 0)
if (imgHeight.value <= w)
moveLeft = leftX;
else
moveLeft = abs;

else
if (imgHeight.value <= w)
moveLeft = leftX;
else if (leftT + imgHeight.value < w)
const ml = w - imgHeight.value;
if (imgWidth.value < imgHeight.value)
moveLeft = ml + abs;
else
moveLeft = ml - abs;



if (topT > 0)
if (imgWidth.value <= h)
moveTop = topX;
else
moveTop = abs;

else
if (imgWidth.value <= h)
moveTop = topX;
else if (topT + imgWidth.value < h)
// console.log(h - imgWidth.value);
const mT = h - imgWidth.value;
if (imgWidth.value < imgHeight.value)
moveTop = mT - abs;
else
moveTop = mT + abs;



else
if (imgWidth.value <= w && imgHeight.value <= h)
return;

if (moveLeft > 0)
if (imgWidth.value <= w)
moveLeft = leftX;
else
moveLeft = 0;

else
if (imgWidth.value <= w)
moveLeft = leftX;
else if (moveLeft + imgWidth.value < w)
moveLeft = w - imgWidth.value;


if (moveTop > 0)
if (imgHeight.value <= h)
moveTop = topX;
else
moveTop = 0;

else
if (imgHeight.value <= h)
moveTop = topX;
else if (moveTop + imgHeight.value < h)
moveTop = h - imgHeight.value;



position.left = moveLeft + "px";
position.top = moveTop + "px";
;
;


5、旋转

/**
* @description: 旋转
* @param *
* @return *
*/
const rotate = () =>
rotateIndex.value = (rotateIndex.value + 1) % 4;
const deg = rotateIndex.value * 90;
const [w, h] = getRect();
const oW = imageArr[index.value].width;
const oH = imageArr[index.value].height;
let nowW = oW;
let nowH = oH;
let scale = 1;
// console.log(deg);
switch (deg)
case 180:
case 0:
if (oH > h)
scale = h / oH;
nowH = h;
nowW = oW * scale;

if (nowW > w)
scale = w / oW;
nowW = w;
nowH = oH * scale;

imgHeight.value = nowH;
imgWidth.value = nowW;
imgScale.value = scale;
// 位置
position.top = h / 2 - nowH / 2 + "px";
position.left = w / 2 - nowW / 2 + "px";
position.transform = `rotate($-degdeg)`;
break;

case 90:
case 270:
if (oW > h)
scale = h / oW;
nowW = h;
nowH = oH * scale;

if (nowH > w)
scale = w / oH;
nowH = w;
nowW = oW * scale;

imgHeight.value = nowH;
imgWidth.value = nowW;
imgScale.value = scale;
// 位置
position.top = h / 2 - nowH / 2 + "px";
position.left = w / 2 - nowW / 2 + "px";
position.transform = `rotate($-degdeg)`;
break;


;


总结

总的来说,通过 electron 实现图片查看器还是比较方便快捷的,主要难点在于坐标计算上,同时还需要注意边界值的情况,大家有兴趣也可以动手尝试一下!


给大家分享更多 electron 实战中的点滴,如果大家对此感兴趣,欢迎各位关注、留言,大家的支持就是我的动力!

以上是关于canvas中放入一张图片,但是其中的图片可以旋转移动,这是怎么确定的?的主要内容,如果未能解决你的问题,请参考以下文章

Android源码 在framework中加入一张图片资源,获取不到资源文件

如何用javascript中的canvas让图片自己旋转

OpenCV两张图片叠加,一张旋转一定的角度,另一张不变,如何叠加?

electron学习笔记如何通过electron实现图片查看器

Canvas-图片旋转

圆形物体旋转角度检测