技术CTO-关注编程入门知识,提供编程入门教程

您的位置: 首页 > 前端开发 > html/html5 > 正文

canvas 图片编辑(拖拽旋转缩放)交流

来源: 技术CTO 阅读:

需要做一个在canvas里对图片进行拖拽、缩放、旋转的一个小应用。

现在可以拖拽,旋转有个问题,不好解决,demo文件在下面,大概80行代码的样子,希望路过的朋友指点下,谢谢!(我觉得问题出在转换坐标系过程了,但是不是很明白,求指点。)



\

好吧,小伙伴儿们,我自己有些进展了,我整理了下,目前需要解决的问题,有两个:

一、计算mousemove旋转时产生的角度;
二、判断旋转之后再拖拽时,mousedown的点是否在图片区域内。

我现在有一些解决思路,但是我数学不好,自己研究可能会花很长一段时间,希望路过的大神能出个demo让小弟参考下! QQ:1140215489
百度知道 100分悬赏
http://zhidao.baidu.com/question/2201564571024171668.html
矩阵~~~

最终显示 =  正常 * 矩阵

旋转操作就是获取一个 旋转矩阵

那么你的鼠标坐标定位判断要 / 旋转矩阵

鼠标坐标/矩阵 == 图片原始区域内 则判断在图片里

好吧 上面是理论 不过根据一致性原则 应该是 ok的
你可以先弄弄看 晚上时间多 可以帮你一起看下
引用 3 楼 KK3K2005 的回复:
矩阵~~~

最终显示 =  正常 * 矩阵
....
你可以先弄弄看 晚上时间多 可以帮你一起看下


就喜欢爽快的大神,非常期待!今天搞了一天没搞出名堂来,燥死我了!
先行谢过了啊!!
引用 3 楼 KK3K2005 的回复:
矩阵~~~
....
你可以先弄弄看 晚上时间多 可以帮你一起看下

大神,我研究出来了,不过我还是很想看看使用矩阵是怎么做的?

这是我的链接
每次在csdn上问问题都是这样,好几天无人光顾,最后还是自己整出来了...
研究过程我写在了我的博客里了,欢迎交流。



<!doctype html>
<html>
<head>
<title> </title>
<meta http-equiv="X-UA-Compatible" content="IE=9"> 
<meta charset="utf-8" />
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<style>
#canvas{border:1px solid #ccc;}
</style>
   
</head>
<body>
<canvas id="canvas" width="500" height="300"></canvas>
<pre>
功能:拖拽+旋转
思路:始终保持图片中心点在canvas坐标系的原点处,图片的每一次重绘都基于canvas坐标系的原点来绘制,即drawImage(img,-imgW/2,-imgH/2)。
移动、旋转的时候绘制方法不变,变换的是canvas坐标系。
关键:理解屏幕坐标系和canvas坐标系的关系。将鼠标事件的屏幕坐标,转换为canvas坐标系中的坐标。
计算旋转时每一次mousemove,在旋转前的canvas坐标系中move的角度。
</pre>
<script>
var cvs =document.getElementById("canvas");   
var ctx =cvs.getContext("2d");
var cvsH=cvs.height;
var cvsW=cvs.width;
var beginX,beginY;
var LT={x:30,y:30};//图片左上角的点
var Selected_Round_R=12;
var isDown=false;
var imgH,imgW;
var moveAble=false,rotateAble=false;
var img = new Image();
var rotate_radian=0;//canvas坐标系x轴与屏幕坐标系X轴夹角弧度
img.src ="img/niuniu.jpg";
img.onload=function (){
imgH=img.height;
imgW=img.width;
PO={x:LT.x+imgW/2,y:LT.y+imgH/2};
ctx.translate(PO.x,PO.y);//载入时将canvas坐标系原点移到图片中心点上
onDraw();

}
function onDraw(){
ctx.clearRect(-cvsW,-cvsH,2*cvsW,2*cvsH);
ctx.drawImage(img,-imgW/2,-imgH/2);
//旋转控制旋钮
ctx.beginPath();
ctx.arc(0,-imgH/2-Selected_Round_R,Selected_Round_R,0,Math.PI*2,false);
ctx.closePath();
ctx.lineWidth=2;
        ctx.strokeStyle="#0000ff";
ctx.stroke();
}
cvs.addEventListener("mousedown", startMove, false); 
cvs.addEventListener("mousemove", moving, false);
cvs.addEventListener("mouseup", endMove, false);  
cvs.addEventListener("mouseout",endMove, false);

function imgIsDown(x,y){
return (-imgW/2<=x && x<=imgW/2 && -imgH/2<y && y<=imgH/2);
}
function RTIsDown(x,y){
var round_center={x:0,y:-imgH/2-Selected_Round_R};
var bool=getPointDistance({x:x,y:y},round_center)<=Selected_Round_R;
return bool;
}
function startMove(){
event.preventDefault();
isDown=true;
var loc=getEvtLoc();//获取鼠标事件在屏幕坐标系的位置(原点在canvas标签左上角)
var x=loc.x,y=loc.y;
beginX=x,beginY=y;
var cLoc=convertCoor(loc);
var Xc=cLoc.x,Yc=cLoc.y;
moveAble=imgIsDown(Xc,Yc);
rotateAble=RTIsDown(Xc,Yc);
if (moveAble) cvs.style.cursor="move";
if (rotateAble) cvs.style.cursor="crosshair";
}
function moving(){
event.preventDefault();
if(isDown==false) return;
var loc=getEvtLoc();
if(moveAble){
var x=loc.x,y=loc.y;
var dx=x-beginX,dy=y-beginY;
var mPO={x:PO.x+dx,y:PO.y+dy};//因为鼠标移动dx dy,所以PO在屏幕坐标系的坐标也 移动dx dy
var cPO=convertCoor(mPO);//屏幕坐标系移动后的PO转换成canvas坐标系的坐标
ctx.translate(cPO.x,cPO.y);//canvas坐标系原点移动到新的图片中心点
onDraw();

PO.x=PO.x+dx;//记录下屏幕坐标系上PO的坐标变化
PO.y=PO.y+dy;
beginX=x,beginY=y;//记录移动后鼠标在屏幕坐标系的新位置
}else if(rotateAble){
var cLoc=convertCoor(loc);
var Xc=cLoc.x,Yc=cLoc.y;
var newR = Math.atan2(Xc,-Yc);//在旋转前的canvas坐标系中 move的角度(因为旋钮在上方,所以跟,应该计算 在旋转前canvas坐标系中,鼠标位置和原点连线 与 y轴反方向的夹角)
ctx.rotate(newR);
rotate_radian+=newR;
onDraw();
}
}
function endMove(){
event.preventDefault();
isDown=false;
moveAble=rotateAble=false;
cvs.style.cursor="auto";
}

function getEvtLoc(){//获取相对canvas标签左上角的鼠标事件坐标
return {x:event.offsetX,y:event.offsetY}
}

function convertCoor(P) {//坐标变换 屏幕坐标系的点 转换为canvas坐标系的点
var x=P.x-PO.x;//在屏幕坐标系中,P点相对canvas坐标系原点PO的偏移
var y=P.y-PO.y; 

if(rotate_radian!=0){
var len = Math.sqrt(x*x + y*y);
var oldR=Math.atan2(y,x);//屏幕坐标系中 PO与P点连线 与屏幕坐标系X轴的夹角弧度
var newR =oldR-rotate_radian;//canvas坐标系中PO与P点连线 与canvas坐标系x轴的夹角弧度
x = len*Math.cos(newR);
y = len*Math.sin(newR);      
}

return {x:x,y:y};
}
//获取两点距离
function getPointDistance(a,b){
var x1=a.x,y1=a.y,x2=b.x,y2=b.y;
var dd= Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
return dd;
}
</script>
</body>
</html>
不好意思最近忙死天天加班到深夜 星期天有时间我来看下矩阵做法
\\
引用 7 楼 KK3K2005 的回复:
不好意思最近忙死天天加班到深夜 星期天有时间我来看下矩阵做法


嗯,老兄你有空了再整就行,注意身体!
借此楼发布一下我的终极成果:

test-2.3
不错 支持一下楼主  谢谢分享
在火狐上不行....

^_^ 如果您热爱技术、热爱编程,想与更多的朋友一起交流学习,欢迎加入本站官方QQ群:345733473 ^_^