文章的代碼和思路來自https://blog.csdn.net/cysear/article/details/89185239#comments_13156603
在原文基礎上做了部分優化:
- 實作了不拖拽也可縮放的效果
- 雙擊滑鼠,在圖片上生成一個圓圈且該圓圈實作了跟隨縮放比例一起縮放以及縮放后位置不變的效果
效果圖不會上傳,,自己下下來看吧
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>canvas.js</title>
<style>
#mouseTip{
display:none;
position:absolute;
pointer-events: none;
background-color: gray;
}
</style>
</head>
<body>
<canvas id="scaleDragCanvas" width="800" height="600" style="border: thin solid #aaaaaa; margin:0 auto;
display: block;"></canvas>
<span id='mouseTip'>
</span>
<script>
var canvas, context;
var showTips = null, originalPos = null;
var img, imgX = 0, imgY = 0, imgScale = 1, scaleRate = 1;
var MINIMUM_SCALE = 1 ,pos={},posl={},dragging = false;
(function int() {
canvas = document.getElementById('scaleDragCanvas'); //畫布物件
context = canvas.getContext('2d');//畫布顯示二維圖片
loadImg();
canvasEventsInit();
})();
var initWidth = 0, initHeight = 0
function loadImg() {
img = new Image();
img.onload = function () {
scaleRate = img.width/canvas.width;//讓長寬保持相同縮放比例
//MINIMUM_SCALE = canvas.width/img.width;
initWidth = img.width * scaleRate;
initHeight = img.height * scaleRate;
console.log("initWidth=" + initWidth + ",initHeight=" + initHeight + ", scaleRate=" + scaleRate);
drawImage();
//imgScale = scaleRate;
}
img.src = 'F:/image.jpg';
}
function drawImage() {
context.clearRect(0, 0, canvas.width, canvas.height);
// 保證 imgX 在 [img.width*(1-imgScale),0] 區間內
///**
if(imgX<img.width*(1-imgScale) /scaleRate) {
imgX = img.width*(1-imgScale)/scaleRate ;
}else if(imgX>0) {
imgX=0
}
// 保證 imgY 在 [img.height*(1-imgScale),0] 區間內
if(imgY<img.height*(1-imgScale)/scaleRate) {
imgY = img.height*(1-imgScale)/scaleRate;
}else if(imgY>0) {
imgY=0
}
//*/
//console.log(img.width);
context.drawImage(
img, //規定要使用的影像、畫布或視頻,
0, 0, //開始剪切的 xy 坐標位置,
initWidth, initHeight, //被剪切影像的高度,
//img.width,img.height,
imgX, imgY,//在畫布上放置影像的 x 、y坐標位置,
img.width * imgScale, img.height * imgScale //要使用的影像的寬度、高度
//1700,1200
);
//var p = windowToCanvas(150/img.width * imgScale, 400/img.width * imgScale);
//console.log(p.x + "," + p.y);
//console.log("imgX=" + imgX + ",imgY=" + imgY);
//console.log(img.width/canvas.width);
//console.log("========" + img.width + "," + img.height);
//console.log("##" + img.width * (1-imgScale) + "," + img.height * (1-imgScale) + "");
for(var i = 0; i< window.localStorage.length; i++){
var key = window.localStorage.key(i);
var pp = JSON.parse(window.localStorage.getItem(key));
makeCircle(context, pp.x, pp.y, false);
}
}
/*事件注冊*/
function canvasEventsInit() {
canvas.onmousedown = function (event) {
if(showTips == null){
dragging = true;
pos = windowToCanvas(event.clientX, event.clientY); //坐標轉換,將視窗坐標轉換成canvas的坐標
}
//console.log(pos);
};
canvas.onmousemove = function (evt) { //移動
if(showTips != null){
//測距功能
if(showTips){
showPosTips(originalPos.x, originalPos.y, evt);
}
}else{
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));
//document.body.style.cursor = 'Handle';
drawImage(); //重新繪制圖片
}else{
pos3 = windowToCanvas(evt.clientX, evt.clientY);
//console.log("pos=" + pos3.x + "," + pos3.y + "; ");
if(context.isPointInPath(pos3.x, pos3.y)){
console.log("進入區域");
}
}
}
};
canvas.onmouseup = function (evt) {
if(showTips != null){
if(!showTips){
document.getElementById("mouseTip").style.display = 'block';
originalPos = {x: evt.clientX, y: evt.clientY};
showTips = true;
}else{
document.getElementById("mouseTip").style.display = 'none';
showTips = null;
}
}else{
dragging = false;
}
//document.body.style.cursor = 'default';
};
canvas.onmousewheel = canvas.onwheel = function (event) { //滾輪放大縮小
var pos = windowToCanvas (event.clientX, event.clientY);
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)};
//console.log("newPos==========" + newPos.x + "," + newPos.y)
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);
}
//console.log("wheel.imgY = " + imgY);
drawImage(); //重新繪制圖片
};
canvas.ondblclick = function(event){
console.log("雙擊:滑鼠坐標【" + (event.clientX + "," + event.clientY) + "】圖片左上角坐標【" +imgX + "," +imgY + "】" +
"圖片比例尺【" + scaleRate + "】 縮放比例【" +imgScale+"】解析度【" +img.width + "X" + img.height +"】");
var p = windowToCanvas (event.clientX, event.clientY);
makeCircle(context, (Math.abs(imgX) + Math.abs(p.x))/imgScale, (Math.abs(imgY) + Math.abs(p.y))/imgScale, true);
console.log(" 距離畫布邊框【" +p.x + " " + p.y+"】");
//console.log((Math.abs(Math.abs(imgX) - event.clientX)) + "@@@" + (Math.abs(Math.abs(imgY) -event.clientY)));
}
}
function showPosTips(x, y, evt){
drawImage();
console.log(x +",,," + y);
//context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.stokeStyle="#f00";
context.moveTo(x, y);
var temp = windowToCanvas(evt.clientX, evt.clientY);
context.lineTo(temp.x, temp.y);
context.stroke();
document.getElementById("mouseTip").innerHTML = temp.x + "," + temp.y;
document.getElementById("mouseTip").style.left = evt.clientX + 'px';
document.getElementById("mouseTip").style.top = evt.clientY + 'px';
}
/*坐標轉換*/
function windowToCanvas(x,y) {
var box = canvas.getBoundingClientRect();
//console.log( "x=" + (x - box.left - (box.width - canvas.width) / 2) + ",y=" + (y - box.top - (box.height - canvas.height) / 2));
//這個方法回傳一個矩形物件,包含四個屬性:left、top、right和bottom,分別表示元素各邊與頁面上邊和左邊的距離
return {
x: x - box.left - (box.width - canvas.width) / 2,
y: y - box.top - (box.height - canvas.height) / 2
};
}
function makeCircle(context, posX, posY, isCreate){
var resetX = posX/img.width*(img.width*imgScale) + imgX;
var resetY = posY/img.height * (img.height * imgScale) + imgY;
context.beginPath();//這里可以理解為另外起筆,如果忽略這個步驟那么下面的樣式就會繼承上面的,所以最好不要忽略
//context.fillStyle = 'red';//漸變填充樣式
context.fillStyle = 'rgba(100,150,185,0.9)';//漸變填充樣式
context.font = (imgScale>1?0.5:imgScale) * 44 + 'px STheiti, SimHei';
context.fillText('32', resetX-(20*(imgScale>1?0.5:imgScale)), resetY+(15*(imgScale>1?0.5:imgScale)));
context.strokeStyle = 'red';//定義填充樣式
context.lineWidth = 2;//定義線性的線寬,寬是從圓圈向內外兩邊同時加粗的
//context.arc(519/img.width*(img.width*imgScale) + imgX,343/img.height * (img.height * imgScale) + imgY,50 * (imgScale>1?0.5:imgScale),0,2*Math.PI);//定義圓[這五個引數分別是(橫坐標,縱坐標,半徑,起始的點(弧度),結束的點(弧度))]
//context.arc(251.598/img.width*(img.width*imgScale) + imgX,1005.732/img.height * (img.height * imgScale) + imgY,50 * (imgScale>1?0.5:imgScale),0,2*Math.PI);//定義圓[這五個引數分別是(橫坐標,縱坐標,半徑,起始的點(弧度),結束的點(弧度))]
context.arc(resetX, resetY, 50 * (imgScale>1?0.5:imgScale),0,2*Math.PI);//定義圓[這五個引數分別是(橫坐標,縱坐標,半徑,起始的點(弧度),結束的點(弧度))]
//context.closePath();
//context.globalAlpha = 0.1;
//context.fill();//定義圓為面性即藍色圓面
context.stroke();//只有加上這行才有邊框
//context.restore();
if(isCreate){
window.localStorage.setItem(posX+"_" + posY, JSON.stringify({x: posX, y: posY}));
}
}
function jianbian(){
var gradient=context.createLinearGradient(0,0,20,0);
gradient.addColorStop("0","magenta");
gradient.addColorStop("0.5","blue");
gradient.addColorStop("1.0","red");
return gradient;
}
</script>
</body>
</html>
其中“F:/image.jpg”換成自己本地的圖片就行了
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/3321.html
標籤:python
