先看效果

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style type="text/css">
* {
padding: 0;
margin: 0;
font-size: 14px;
} #box {
width: 400px;
height: 400px;
border: 1px solid red;
margin: 20px auto;
position: relative;
} #operate {
text-align: center;
;
} #operate p {
margin-bottom: 6px;
} input[type=file] {
display: none;
} label {
display: inline-block;
cursor: pointer;
background: #38f;
color: #fff;
width: 102px;
height: 38px;
line-height: 38px;
border-radius: 4px;
} #clipcanvas {
position: absolute;
top: 0;
left: 0;
z-index: 10;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="box">
<canvas id="canvas" width="400" height="400"></canvas>
<canvas id="clipcanvas"></canvas>
</div>
<div id="operate">
<p><label><input type="file" name="" id="bg" value="" />选择头像</label></p>
<p><label><input type="file" name="" id="flag" value="" />选择上层</label></p>
<p><input type="text" name="" id="posX" value="0" />请输入上层x位置</p>
<p><input type="text" name="" id="posY" value="0" />请输入上层y位置</p>
<p><label id="create">直接生成</label></p>
<p><label id="reset">重新截图</label></p>
</div>
<a href="" download="logo.png" title="点击下载" id="down">
<img src="" id="result">
</a> </body>
<script type="text/javascript">
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const baseW = 400;
const flagW = 100;
let bgConfig;
let flagConfig;
document.getElementById("bg").onchange = async function() {
const file = this.files[0];
try {
const img = await getImageObj(file);
const rate = compress(img, baseW);
bgConfig = [img, 0, 0, img.width, img.height, 0, 0, rate.w, rate.h];
drawn();
} catch (e) {
console.error(e);
}
}; document.getElementById("flag").onchange = async function() {
const file = this.files[0];
try {
const img = await getImageObj(file);
const rate = compress(img, flagW);
flagConfig = [img, 0, 0, img.width, img.height, 0, 0, rate.w, rate.h];
drawn();
} catch (e) {
console.error(e);
}
};
document.getElementById("posX").onchange = function() {
let val = Number(this.value) || 0;
flagConfig[5] = val;
drawn();
}
document.getElementById("posY").onchange = function() {
let val = Number(this.value) || 0;
flagConfig[6] = val;
drawn();
} function drawn() {
ctx.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight);
if (bgConfig) {
ctx.drawImage(...bgConfig);
}
if (flagConfig) {
ctx.drawImage(...flagConfig);
}
} //图片压缩,获取等比缩放后的结果
function compress(img, base) {
let w = img.width;
let h = img.height;
if (img.width > img.height) {
if (img.width > base) {
//要将宽度缩放
w = base;
h = (w / img.width) * img.height; // 新的 宽比 高 = 旧的宽比高 h / w = img.heigth/img.width ;
}
} else {
if (img.height > base) {
h = base;
w = (h / img.height) * img.width;
}
}
return {
w,
h
};
} function getImageObj(file) {
const url = getObjectURL(file);
const img = new Image();
img.src = url;
return new Promise((resolve, reject) => {
img.onload = function() {
resolve(img);
}
img.onerror = function(e) {
reject(e);
}
});
} //取得该文件的url
function getObjectURL(file) {
var url = null;
if (window.createObjectURL != undefined) {
url = window.createObjectURL(file);
} else if (window.URL != undefined) {
url = window.URL.createObjectURL(file);
} else if (window.webkitURL != undefined) {
url = window.webkitURL.createObjectURL(file);
}
return url;
} //截图
var clipcanvas = document.getElementById("clipcanvas");
var clipctx = clipcanvas.getContext("2d"); clipcanvas.width = canvas.clientWidth;
clipcanvas.height = canvas.clientHeight;
var start = null;
var clipArea = {}; //裁剪范围
clipcanvas.onmousedown = function(e) {
start = {
x: e.offsetX,
y: e.offsetY
};
}
clipcanvas.onmousemove = function(e) {
if (start) {
fill(start.x, start.y, e.offsetX - start.x, e.offsetY - start.y)
}
}
document.addEventListener("mouseup", function() {
if (start) {
start = null;
exportImg(clipArea);
}
});
//重新截图
document.getElementById("reset").onclick = function(){
clipctx.clearRect(0, 0, clipcanvas.width, clipcanvas.height);
}
//直接生成
document.getElementById("create").onclick = function(){
exportImg({
x:0,
y:0,
w:canvas.clientWidth,
h:canvas.clientHeight,
})
}
function fill(x, y, w, h) {
clipctx.clearRect(0, 0, clipcanvas.width, clipcanvas.height);
clipctx.beginPath();
clipctx.fillStyle = 'rgba(0,0,0,0.6)';
clipctx.strokeStyle = "green";
//遮罩层
clipctx.globalCompositeOperation = "source-over";
clipctx.fillRect(0, 0, clipcanvas.width, clipcanvas.height);
//画框
clipctx.globalCompositeOperation = 'destination-out';
clipctx.fillRect(x, y, w, h);
//描边
clipctx.globalCompositeOperation = "source-over";
clipctx.moveTo(x, y);
clipctx.lineTo(x + w, y);
clipctx.lineTo(x + w, y + h);
clipctx.lineTo(x, y + h);
clipctx.lineTo(x, y);
clipctx.stroke();
clipctx.closePath();
clipArea = {
x,
y,
w,
h
};
} function startClip(area) {
var canvas = document.createElement("canvas");
canvas.width = area.w;
canvas.height = area.h;
var data = ctx.getImageData(area.x, area.y, area.w, area.h);
var context = canvas.getContext("2d");
context.putImageData(data, 0, 0);
return canvas.toDataURL("image/png");
} function exportImg(clipArea){
var url = startClip(clipArea);
document.getElementById("result").src = url;
document.getElementById("down").href = url;
} </script>
</html>

  

原生js 基于canvas写一个简单的前端 截图工具的更多相关文章

  1. 用node.js从零开始去写一个简单的爬虫

    如果你不会Python语言,正好又是一个node.js小白,看完这篇文章之后,一定会觉得受益匪浅,感受到自己又新get到了一门技能,如何用node.js从零开始去写一个简单的爬虫,十分钟时间就能搞定, ...

  2. 用Canvas写一个简单的游戏--别踩白块儿

    第一次写博客也不知怎么写,反正就按照我自己的想法来吧!怎么说呢?还是不要扯那些多余的话了,直接上正题吧! 第一次用canvas写游戏,所以挑个简单实现点的来干:别踩白块儿,其他那些怎么操作的那些就不用 ...

  3. 使用 js,自己写一个简单的滚动条

    当我们给元素加上 overflow: auto;  的时候,就会出现滚动条,然而浏览的不同,滚动条的样式大不一样,有些甚至非常丑. 于是就想着自己写一个滚动条,大概需要弄清楚一下这几个点: 1.滚动条 ...

  4. 基于Blazor写一个简单的五子棋游戏

    写这个五子棋游戏,其实主要目的是想尝试一下微软新作Blazor.Blazor对于那些搞.NET的程序员,又想做一些前端工作,真的挺友好,不用一句JS就可搞定前端交互,美哉.现在已经有很流行的前端框架, ...

  5. 第一个Three.js程序——动手写一个简单的场景

    三维场景基本要素: 步骤: 代码: 源码: <!DOCTYPE html> <html lang="en"> <head> <meta c ...

  6. js eval函数写一个简单的计算器

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  7. 分享:计算机图形学期末作业!!利用WebGL的第三方库three.js写一个简单的网页版“我的世界小游戏”

    这几天一直在忙着期末考试,所以一直没有更新我的博客,今天刚把我的期末作业完成了,心情澎湃,所以晚上不管怎么样,我也要写一篇博客纪念一下我上课都没有听,还是通过强大的度娘完成了我的作业的经历.(当然作业 ...

  8. Particles.js基于Canvas画布创建粒子原子颗粒效果

    文章目录 使用方法 自定义参数 相关链接 Particles.js是一款基于HTML5 Canvas画布的轻量级粒子动画插件,可以设置粒子的形状.旋转.分布.颜色等属性,还可以动态添加粒子,效果非常炫 ...

  9. 原生js实现canvas气泡冒泡效果

    说明: 本文章主要分为ES5和ES6两个版本 ES5版本是早期版本,后面用ES6重写优化的,建议使用ES6版本. 1, 原生js实现canvas气泡冒泡效果的插件,api丰富,使用简单2, 只需引入J ...

随机推荐

  1. Gerapy框架的使用

    Gerapy 基于Scrapy,Scrapyd,Scrapyd-Client,Scrapyd-API,Django和Vue.js的分布式爬虫管理框架. 支持 Gerapy是在Python 3.x上开发 ...

  2. 如何在element-ui table 取到对应的ID的最后一个对象

    来回切换3个状态值如何得到对应ID的最后一个对象 var is_push = () => { for (var i = 0; i < this.form.FaultDevices.leng ...

  3. 探索Visual Studio生成的.vs文件夹内部结构和作用

    这里直接先将我摸索出的结果贴出来,文章后面会一一详细说明和分析:.vs目录是用来存储当前用户在解决方案中的工作配置,具体包括VS关闭前最后的窗口布局.最后打开的选项卡/操作记录/文件文档.某些自定义配 ...

  4. SSM框架中常用的配置文件

    学习框架,刚开始的时候最烦的就是一些配置文件,有很多需要配置的东西,今天把这些配置文件信息稍微整理一下,以后说不定会用的到. web.xml文件 <?xml version="1.0& ...

  5. 西北地区打不开github的解决办法~

    泱泱我大西北,github打不开,的确痛苦的. http://ipaddress.com/ip_lookup/ 先查github.com 可能存在打不开的情况~ 随便找一个web在线代理,就可以查到了 ...

  6. js中一个对象中遇到一个相同的key所对应的value值相加

    如图: 变成: js原生如下: var abc=[ {typeid:1,ade:1}, {typeid:2,ade:1}, {typeid:1,ade:2}, {typeid:1,ade:2}, {t ...

  7. Prime Distance POJ - 2689 (数学 素数)

    The branch of mathematics called number theory is about properties of numbers. One of the areas that ...

  8. 关于jmeter读取CSV文件的详细设置

    jmeter 读取excel数据使用的方法是使用Jmeter CSV Data Set Config参数化 但是将excel文件保存成csv格式后,jmeter读取后返回的数据总是出现乱码问题, 以下 ...

  9. HDU 4283 You Are the One 【区间DP】

    <题目链接> 题目大意: 有$n$个人排成一排要上台表演,每个人有一个屌丝值$pi$.第i个上台表演的人,他的不满意度为$(i-1)*p_i$.现在有一个类似于栈的黑屋子,你可以让某些人进 ...

  10. 错误解决记录-------------验证启动HDFS时遇到的错误

    主要解决验证启动HDFS时: 1) jps:bash: jps: command not found... 原因:主要是java/bin 环境变量没配置好. 解决办法: 在  ~/.bash_prof ...