最近在写canvas关于图片的操作,看了网上的代码基本都是不行的,于是就自己写了一个。

html代码

  <canvas id="myCanvas" width="375px" height="500px"></canvas>
<a id="save">
点击保存
</a>

移动端操作: Js代码

    var canvas = document.getElementById('myCanvas'); //画布对象
var context = canvas.getContext('2d'); //画布显示二维图片
var saveBtn = document.getElementById('save');
var img, //图片是否加载完成;
imgX = 0,
imgY = 0,
dragging = false,
posl = {},
scale = 1,
pos = {
x: 0,
y: 0
},
newPos = {
x: 0,
y: 0
}; loadImg(); function drawImage(params) {
context.clearRect(0, 0, canvas.width, canvas.height);
// 保证 imgX 在 [img.width*(1-scale),0] 区间内
if (imgX < img.width * (1 - scale)) {
imgX = img.width * (1 - scale);
} else if (imgX > 0) {
imgX = 0
}
// 保证 imgY 在 [img.height*(1-scale),0] 区间内
if (imgY < img.height * (1 - scale)) {
imgY = img.height * (1 - scale);
} else if (imgY > 0) {
imgY = 0
}
context.drawImage(
img, //规定要使用的图像、画布或视频。
0, 0, //开始剪切的 x 坐标位置。
img.width, img.height, //被剪切图像的高度。
imgX, imgY, //在画布上放置图像的 x 、y坐标位置。
img.width * scale, img.height * scale //要使用的图像的宽度、高度
);
} function loadImg() {
img = new Image();
img.onload = function () {
drawImage();
}
img.src = './test.jpg'
}
var start, end = 0;
canvas.addEventListener('touchstart', function (e) {
e.preventDefault()
if (e.touches.length === 1) {
dragging = true;
pos = windowToCanvas(e.touches[0].clientX, e.touches[0].clientY); //坐标转换,将窗口坐标转换成canvas的坐标
}
if (e.touches.length === 2) {
var t1 = e.touches[0];
var t2 = e.touches[1];
var pos1 = {
x: t1.clientX,
y: t1.clientY
}
var pos2 = {
x: t2.clientX,
y: t2.clientY
}
pos = windowToCanvas((pos1.x + pos2.x) / 2, (pos1.y + pos2.y) / 2);
}
});
canvas.addEventListener('touchmove', function (e) {
e.preventDefault()
if (e.touches.length === 1) {
// 加上dragging区分pos和posl的值,一个为双指,这里为单指的值
if (dragging) {
posl = windowToCanvas(e.touches[0].clientX, e.touches[0].clientY);
var x = posl.x - pos.x;
var y = posl.y - pos.y;
imgX += x;
imgY += y;
pos = JSON.parse(JSON.stringify(posl));
drawImage(); //重新绘制图片
}
}
// 双指中有可能存在移动,所以不加dragging判断,都是用的同一个中心点
if (e.touches.length === 2) {
posl = JSON.parse(JSON.stringify(pos));
var s1 = end;
var t1 = e.touches[0];
var t2 = e.touches[1];
var pos1 = {
x: t1.clientX,
y: t1.clientY
}
var pos2 = {
x: t2.clientX,
y: t2.clientY
}
pos = windowToCanvas((pos1.x + pos2.x) / 2, (pos1.y + pos2.y) / 2);
end = Math.sqrt(Math.pow((pos1.x - pos2.x), 2) + Math.pow((pos1.y - pos2.y), 2));
var pianX = posl.x - pos.x;
var pianY = posl.y - pos.y; newPos = {
x: ((pos.x - imgX + pianX) / scale),
y: ((pos.y - imgY + pianY) / scale)
};
// 缩小
if (s1 > end) {
scale = scale - 0.05;
imgX = (1 - scale) * newPos.x + (pos.x -
newPos.x);
imgY = (1 - scale) * newPos.y + (pos.y - newPos.y);
if (scale < 1) { //最小缩放1
scale = 1;
drawImage(); //重新绘制图片
return
}
// drawImage(); //重新绘制图片
// 放大
} else {
scale = scale + 0.05;
imgX = (1 - scale) * newPos.x + (pos.x -
newPos.x);
imgY = (1 - scale) * newPos.y + (pos.y - newPos.y);
// drawImage();
}
drawImage(); }
});
canvas.addEventListener('touchend', function (e) {
e.preventDefault()
if (e.touches.length === 1) {
dragging = false;
}
})
saveBtn.addEventListener('click', function (e) {
var imgUrl = canvas.toDataURL();
var imgName = prompt('下载的图片名称:');
if (imgName != null) {
saveBtn.download = imgName;
saveBtn.href = imgUrl;
}
}) function windowToCanvas(x, y) {
var box = canvas.getBoundingClientRect();
//这个方法返回一个矩形对象,包含四个属性:left、top、right和bottom。分别表示元素各边与页面上边和左边的距离
return {
x: x - box.left - (box.width - canvas.width) / 2,
y: y - box.top - (box.height - canvas.height) / 2
};
}

 PC端操作: Js代码

    var canvas = document.getElementById('scaleDragCanvas'); //画布对象
var context = canvas.getContext('2d'); //画布显示二维图片
var saveBtn = document.getElementById('save');
var img, imgX = 0,
imgY = 0,
imgScale = 1;
var MINIMUM_SCALE = 1.0,
pos = {},
posl = {},
dragging = false; loadImg();
canvasEventsInit(); function loadImg() {
img = new Image();
img.onload = function () {
drawImage();
}
img.src =
'./test.jpg';
} function drawImage() {
context.clearRect(0, 0, canvas.width, canvas.height);
// 保证 imgX 在 [img.width*(1-imgScale),0] 区间内
if (imgX < img.width * (1 - imgScale)) {
imgX = img.width * (1 - imgScale);
} else if (imgX > 0) {
imgX = 0
}
// 保证 imgY 在 [img.height*(1-imgScale),0] 区间内
if (imgY < img.height * (1 - imgScale)) {
imgY = img.height * (1 - imgScale);
} else if (imgY > 0) {
imgY = 0
}
context.drawImage(
img, //规定要使用的图像、画布或视频。
0, 0, //开始剪切的 x 坐标位置。
img.width, img.height, //被剪切图像的高度。
imgX, imgY, //在画布上放置图像的 x 、y坐标位置。
img.width * imgScale, img.height * imgScale //要使用的图像的宽度、高度
);
} /*事件注册*/
function canvasEventsInit() {
canvas.onmousedown = function (event) {
dragging = true;
pos = windowToCanvas(event.clientX, event.clientY); //坐标转换,将窗口坐标转换成canvas的坐标
};
saveBtn.addEventListener('click', function (e) {
var imgUrl = canvas.toDataURL();
var imgName = prompt('下载的图片名称:');
if (imgName != null) {
saveBtn.download = imgName;
saveBtn.href = imgUrl;
}
})
canvas.onmousemove = function (evt) { //移动
if (dragging) {
posl = windowToCanvas(evt.clientX, evt.clientY);
var x = posl.x - pos.x,
y = posl.y - pos.y;
imgX += x;
imgY += y;
pos = JSON.parse(JSON.stringify(posl));
drawImage(); //重新绘制图片
}
};
canvas.onmouseup = function () {
dragging = false;
};
canvas.onmousewheel = canvas.onwheel = function (event) { //滚轮放大缩小
var pos = windowToCanvas(event.clientX, event.clientY);
console.log(pos)
event.wheelDelta = event.wheelDelta ? event.wheelDelta : (event.deltalY * (-40)); //获取当前鼠标的滚动情况
var newPos = {
x: ((pos.x - imgX) / imgScale).toFixed(2),
y: ((pos.y - imgY) / imgScale).toFixed(2)
};
if (event.wheelDelta > 0) { // 放大
imgScale += 0.1;
imgX = (1 - imgScale) * newPos.x + (pos.x - newPos.x);
imgY = (1 - imgScale) * newPos.y + (pos.y - newPos.y);
} else { // 缩小
imgScale -= 0.1;
if (imgScale < MINIMUM_SCALE) { //最小缩放1
imgScale = MINIMUM_SCALE;
}
imgX = (1 - imgScale) * newPos.x + (pos.x - newPos.x);
imgY = (1 - imgScale) * newPos.y + (pos.y - newPos.y);
console.log(imgX, imgY);
}
drawImage(); //重新绘制图片 }; } /*坐标转换*/
}
} function windowToCanvas(x, y) {
var box = canvas.getBoundingClientRect();
//这个方法返回一个矩形对象,包含四个属性:left、top、right和bottom。分别表示元素各边与页面上边和左边的距离
return {
x: x - box.left - (box.width - canvas.width) / 2,
y: y - box.top - (box.height - canvas.height) / 2
};
}

  

canvas图片编辑操作:缩放、移动、保存(PC端+移动端)的更多相关文章

  1. Canvas动画(PC端 移动端)

    Canvas动画(PC端 移动端) 一,介绍与需求 1.1,介绍 canvas是HTML5中新增一个HTML5标签与操作canvas的javascript API,它可以实现在网页中完成动态的2D与3 ...

  2. 兼顾pc和移动端的textarea字数监控的实现方法

    概述 pc端移动端中文本框监控字数的功能的一种较为简单的实现,考虑到安卓和IOS输入法输入过程中是否触发keyup的差异.利用监听compositionstart判断是否开启了输入法.从而实现体验较为 ...

  3. 把图片画到画布上,适应PC和移动端

    画一张图片到画布上 <canvas id="myCanvas" width="1000px" height="200px" >您 ...

  4. 用react开发一个新闻列表网站(PC和移动端)

    最近在学习react,试着做了一个新闻类的网站,结合ant design框架, 并且可以同时在PC和移动端运行: 主要包含登录和注册组件.头部和脚部组件.新闻块类组件.详情页组件.评论和收藏组件等: ...

  5. JS判断PC和移动端设备

    1.方法一 function IsPC() { var userAgentInfo = navigator.userAgent; var Agents = ["Android", ...

  6. 前端分辨pc和移动端导入不同css

    通过navigator获取浏览器,根据浏览器的不同判断出pc和移动端然后设置不同的css 分辨不同屏幕导入不同的css文件: function loadCSS() { if((navigator.us ...

  7. 判断PC机大小端

    判断PC机大小端 #include<stdio.h> #include<stdlib.h> int main() { short a = 0x0102; char *p = ( ...

  8. js判断是pc还是移动端

    //判断pc还是移动端 var isM = function () { var ua = navigator.userAgent; /* navigator.userAgent 浏览器发送的用户代理标 ...

  9. 一个 VUE 组件:实现子元素 scroll 父元素容器不跟随滚动(兼容PC、移动端)

    介绍 我们经常遇到一种情况.当滑动滚动条区域时,子元素滚动条到底部或顶部时就会触发父级滚动条,父级滚动条同理会继续向上触发,直至body容器.这是浏览器默认的滚动行为. 但是很多情况,我们想要子元素滚 ...

随机推荐

  1. Go的100天之旅-02基本语法

    基本语法 Go关键字 下面是Go的25个关键字: break default func interface select case defer go map struct chan else goto ...

  2. Apache Kylin v3.1.0 重点功能推介

    Apache Kylin v3.1.0 已于上周正式发布,其中包含了许多值得一试的新功能,本文选择了 Presto 查询下压引擎.Flink 构建引擎.Kylin on Kubernetes 解决方案 ...

  3. linux管理防火墙

    操作系统环境:CentOS Linux release 7.0.1406(Core) 64位CentOS 7.0默认使用的是firewall作为防火墙,这里改为iptables防火墙步骤. 1.关闭f ...

  4. Burp Suite Extender Module - 扩展模块

    模块功能: 在扩展模块可以通过使用自定义代码,进行Burp 的自定义操作. 1. Burp Extensions页面 2. BApp Store中可以购买和安装别人写好的扩展功能 3. 在APIs界面 ...

  5. 搞定 CompletableFuture,并发异步编程和编写串行程序还有什么区别?你们要的多图长文

    你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it well enough ...

  6. 想进大厂?字节跳动等独角兽公司都在招募Python工程师!(Python就是第一语言)

    在本文章中,作者通过自身经历,力求客观的谈谈个人选择学习Python的动机,以及独角兽公司对Python工程师的要求及薪资. 从目前各种迹象(企业招聘,语言排名等)看来Python相对Java应该是暂 ...

  7. 题解 SP2713 【GSS4 - Can you answer these queries IV】

    用计算器算一算,就可以发现\(10^{18}\)的数,被开方\(6\)次后就变为了\(1\). 所以我们可以直接暴力的进行区间修改,若这个数已经到达\(1\),则以后就不再修改(因为\(1\)开方后还 ...

  8. javac不是内部或外部命令,也不是可运行的程序或批处理文件的错误解决方法(Windows10/Windows7)

    前言:在配置JDK环境变量后,java显示正常,javac则显示javac不是内部或外部命令,也不是可运行的程序或批处理文件.造成javac不是内部或外部命令,也不是可运行的程序或批处理文件的问题一般 ...

  9. django表单使用

    一.表单常用字段类型及参数 表单可以自动生成html代码,每一个字段默认有一个html显示样式,大多数默认为输入框. 字段相当于正则表达式的集合,能够对表单传入的数据进行校验,并且某一部分校验失败时会 ...

  10. Android中的ANR问题

    ANR:(Application Not Responding) 1.为什么会产生ANR 在Android中App的相应能力是由Activity Manager和Window Manager系统服务来 ...