效果展示:
代码展示:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>头像上传预览加剪裁效果</title>
<script src="http://libs.baidu.com/jquery/1.7.2/jquery.min.js"></script>
<style>
div.uploadButton {
border:1px solid #555;
width:50px;
height:20px;
cursor:pointer;
background:#fff;
border-radius:4px;
overflow:hidden;
}
div.rangeInputBox {
margin:30px auto;
}
input[type=file] {
display:none;
}
input[type=file]:focus {
outline:none;
}
input[type=range].RangeInput {
width:220px;
height:12px;
padding:0;
margin:0 10px;
vertical-align:middle;
background:transparent;
-webkit-appearance:none;
-moz-appearance:none;
appearance:none;
}
input[type=range].RangeInput:focus {
outline:none
}
input[type=range].RangeInput::-webkit-slider-runnable-track {
height:5px;
cursor:pointer;
background:#f2f5fb;
border-radius:2px
}
input[type=range].RangeInput::-webkit-slider-thumb {
width:12px;
height:12px;
margin-top:-4px;
cursor:pointer;
background:#d2dbe8;
border-radius:50%;
-webkit-appearance:none;
appearance:none
}
input[type=range].RangeInput::-moz-range-track {
height:5px;
cursor:pointer;
background:#f2f5fb;
border-radius:2px
}
input[type=range].RangeInput::-moz-range-thumb {
width:12px;
height:12px;
cursor:pointer;
background:#d2dbe8;
border:none;
border-radius:50%
}
input[type=range].RangeInput::-ms-track {
width:100%;
height:5px;
color:transparent;
cursor:pointer;
background:transparent;
border-color:transparent
}
input[type=range].RangeInput::-ms-fill-lower,input[type=range].RangeInput::-ms-fill-upper {
background:#f2f5fb;
border-radius:2px
}
input[type=range].RangeInput::-ms-thumb {
width:12px;
height:12px;
cursor:pointer;
background:#d2dbe8;
border:none;
border-radius:50%
}
input[type=range].RangeInput::-ms-tooltip {
display:none
}
</style>
</head>
<body>
<div>
<div class="uploadButton">
上传文件
<input class="fileInput" accept="image/png,image/jpeg" type="file">
</div>
<div>
<canvas class="canvas" width="240" height="240" style="cursor: move">
Your browser not support HTML5.
</canvas>
</div>
<div class="rangeInputBox">
<input class="rangeInput" type="range" step="0.01" min="1" max="2" value="1">
</div>
</div>
<script>
! function() {
var canvas = document.getElementsByClassName("canvas")[0];
var ctx = canvas.getContext("2d");
var border = {
width: 40 //头像边框厚度
,
color: "rgba(247, 248, 250, .9)" //头像边框颜色
}
var minImgRect = {
width: null,
height: null
}; //图像的最小高度与宽度
var currLoc = {
x: null,
y: null
}; //保存当前图片在canvas里的位置
var imgRect = {
width: null,
height: null
}; //保存当前图像的宽度与高度(缩放后)
var midpoint = null; //保存当前图片的居中比例,拖动时清空,缩放时重新计算
// 居中比例:以canvas中轴线为基准将图片切成两部分,左侧部分占总宽度的比例,y方向同理。
var rangeInput = document.getElementsByClassName("rangeInput")[0]; //滑块对象
var uploadButton = document.getElementsByClassName("uploadButton")[0]; //图像上传按钮对象
var fileInput = uploadButton.getElementsByClassName("fileInput")[0]; //图像上传控件
var image = new Image(); //图像文件
//<div>元素模拟图片上传按钮
uploadButton.onclick = function(event) {
return fileInput.click();
}
//图片上传处理代码
fileInput.addEventListener('change', function(event) {
var file = fileInput.files[0];
image.src = URL.createObjectURL(file);
image.onload = function(event) {
//缩放图片到刚好填满中框
if (image.width < image.height) {
minImgRect.width = canvas.width - border.width * 2;
minImgRect.height = parseInt(minImgRect.width / image.width * image.height);
} else {
minImgRect.height = canvas.height - border.width * 2;
minImgRect.width = parseInt(minImgRect.height / image.height * image.width);
}
//绘制初始图片
imgRect.width = minImgRect.width;
imgRect.height = minImgRect.height;
drawing(centerImg({
x: 0.5,
y: 0.5
}));
};
}, false);
//根据居中比例及图像大小,计算放置图片的坐标
// 参数: {x: <0-1>, y: <0-1>}
// 结果: {x: <coordinate_X>, y: <coordinate_Y>}
function centerImg(ratio) {
return { // 居中时应满足如下条件,借此计算出偏移量 x 和 y
x: canvas.width / 2 - imgRect.width * ratio.x, // 横坐标偏移(x) + 图像宽度*横向居中比例 应等于 canvas 宽度的一半(中点横坐标)
y: canvas.height / 2 - imgRect.height * ratio.y // 纵坐标偏移(y) + 图像高度*纵向居中比例 应等于 canvas 高度的一半(中点纵坐标)
};
}
//绘制图片到canvas
function drawing(loc) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(image, loc.x, loc.y, imgRect.width, imgRect.height); //指定坐标输出图像
ctx.strokeStyle = border.color; // \
ctx.lineWidth = border.width; // | 绘制半透明边框
ctx.strokeRect(border.width / 2, border.width / 2, canvas.width - border.width, canvas.height - border.width); // /
currLoc = {
x: loc.x,
y: loc.y
};
}
//缩放相关代码
rangeInput.oninput = function(event) {
//检查缩放前是否发生过拖动(midpoint是否被清除),如果是则重新计算居中比例
if (midpoint == null) {
midpoint = {
x: (canvas.width * 0.5 - currLoc.x) / imgRect.width,
y: (canvas.height * 0.5 - currLoc.y) / imgRect.height
}
}
imgRect.width = minImgRect.width * parseFloat(this.value);
imgRect.height = minImgRect.height * parseFloat(this.value);
loc = centerImg(midpoint);
//检查计算出的位置是否存在脱离中框的情况
if (loc.x > 40) {
midpoint = null; //由于发生位移,需要情况居中比例,重新计算
loc.x = 40;
}
if (loc.x + imgRect.width < canvas.width - 40) {
midpoint = null;
loc.x = canvas.width - 40 - imgRect.width;
}
if (loc.y > 40) {
midpoint = null;
loc.y = 40;
}
if (loc.y + imgRect.height < canvas.height - 40) {
midpoint = null;
loc.y = canvas.height - 40 - imgRect.height;
}
drawing(loc);
}
//拖动相关代码
canvas.onmousedown = function(event) {
var lastMouseLoc = {
x: event.clientX,
y: event.clientY
};
document.onmousemove = function dragging(event) {
midpoint = null; //由于位置改变,居中比例需要清空,以便在缩放时重新计算。
var mouseMove = {
x: event.clientX - lastMouseLoc.x,
y: event.clientY - lastMouseLoc.y
};
lastMouseLoc = {
x: lastMouseLoc.x + mouseMove.x,
y: lastMouseLoc.y + mouseMove.y
};
if (currLoc.x + mouseMove.x > 40) { //禁止图像向左拖出中框
mouseMove.x = 40 - currLoc.x;
}
if (currLoc.x + mouseMove.x + imgRect.width < canvas.width - 40) { //禁止图像向右拖出中框
mouseMove.x = canvas.width - 40 - currLoc.x - imgRect.width;
}
if (currLoc.y + mouseMove.y > 40) { //禁止图像向下拖出中框
mouseMove.y = 40 - currLoc.y;
}
if (currLoc.y + mouseMove.y + imgRect.height < canvas.height - 40) { //禁止图像向上拖出中框
mouseMove.y = canvas.height - 40 - currLoc.y - imgRect.height;
}
drawing({
x: currLoc.x + mouseMove.x,
y: currLoc.y + mouseMove.y
});
}
document.onmouseup = function(event) {
document.onmousemove = null;
}
};
}()
</script>
</body>
</html>
与御风痕博客园,程序员博客园地的首选!
御风痕博客园 »
纯js实现头像上传预览加剪裁效果