如何解决JQuery 在画布图像上画线并在不影响图像的情况下重置线
我遇到了这个问题,我从输入字段上传图像并将其绘制到画布中。我有事件侦听器(mousemove
、click
、keydown
),当用户点击图像的任何部分时,那个点就是 x1
、{{1} } 坐标,当他们移动鼠标时,这就是每次更新 y1
、x2
的地方。
问题是总是需要一行,我用一个名为 y2
的函数来管理它,所以当 resetLine
,x2
改变时,该行被重置,所以我们每次鼠标移动时,不要以一堆连续的线结束。
问题在于我们正在绘制的图像,我重置线条的方式似乎也重置了图像,我认为这是预期的,所以我必须在每次鼠标移动时重新绘制图像,我认为这不是这样做的正确方法,而且每次移动鼠标时,您都可以看到图像闪烁。 任何帮助将不胜感激。
编辑:这是我之前制作的一个示例,但是图像是使用 javascript 制作成 css 背景 url 图像的,但是它有很多问题,我不得不开始使用画布绘制背景图像: https://angle-measurement.herokuapp.com
这是我在 codepen 上做的一个类似的: https://codepen.io/Overflow0x/pen/yLaZxqm,但它们都使用 css 的背景图像,而不是画布。
y2
class APP {
constructor() {
this.$imageFileInput = $("#imageFileInput");
this.$lineWeight = $("#lineWeight");
this.$lineColor = $("#lineColor");
this.$reset = $("#reset");
this.$canvas = $("#canvas");
this.canvas = document.getElementById("canvas");
this.lineColor = "";
this.lineWidth = 3;
this.x1y1 = {
x: 4,y: 8
};
this.x2y2 = {
x: 0,y: 0
};
this.imageDataUrl = null;
this.imageWidth = 0;
this.imageHeight = 0;
this.ctx = this.canvas.getContext("2d");
this.y2X2MoveHandlerState = 0;
// 0 unregistered,1,registered
}
setCanvasDimentions() {
this.ctx.canvas.width = (83 / 100) * window.innerWidth;
this.ctx.canvas.height = (60 / 100) * window.innerHeight;
}
registerX1Y1ClickHandler() {
var self = this;
self.$canvas.on('click',function(event) {
//console.log('registerX1Y2ClickHandler event\t',event);
console.log("click",event)
self.x1y1 = self.getMousePos(event);
self.log();
});
}
registerSaveLineClickHandler() {
var self = this;
$(document).keydown(function(e) {
console.warn(e);
if (e.keyCode == 83) {
// 's' button pressed...
self.toggleY2X2MoveHandler();
}
});
}
registerY2X2MoveHandler(mode = null) {
this.y2X2MoveHandlerState = 1;
var self = this;
self.$canvas.on('mousemove',function(event) {
console.log("mousemove",event);
self.x2y2 = self.getMousePos(event);
self.log();
self.resetLine();
self.draw_line();
self.draw_angle();
});
}
toggleY2X2MoveHandler() {
var self = this;
if (self.y2X2MoveHandlerState == 0) {
self.registerY2X2MoveHandler();
} else {
self.$canvas.off("mousemove");
self.y2X2MoveHandlerState = 0;
}
}
registerOnImageChangeHandler() {
var self = this;
self.$imageFileInput.on('change',function(event) {
console.log("image change",event);
const file = event.target.files[0];
self.getBase64Promise(file).then(function(result) {
self.imageDataUrl = result;
self.drawImage(result);
//self.ctx.canvas.style.backgroundImage = 'url(\'' + result + '\')';
}).catch(function(error) {
console.error("ikh\t",error)
self.error = error;
})
});
}
registerOnLineWeightChangeHandler() {
var self = this;
self.$lineWeight.on('change',function(event) {
self.lineWidth = event.target.value;
});
}
registerOnColorChangeHandler() {
var self = this;
self.$lineColor.on('change',function(event) {
self.lineColor = event.target.value;
});
}
registerOnResetHandler() {
var self = this;
self.$reset.on('click',function() {
var cords = {
x: 0,y: 0
};
self.x1y1 = cords;
self.x2y2 = cords;
self.resetLine();
});
}
angle() {
var x1y1 = this.getObjectValuesAsArray(this.x1y1);
var x2y2 = this.getObjectValuesAsArray(this.x2y2);
var x1 = x1y1[0]
var y1 = x1y1[1]
var x2 = x2y2[0]
var y2 = x2y2[1]
var dy = y2 - y1;
var dx = x2 - x1;
var theta = Math.atan2(dy,dx); // range (-PI,PI]
theta *= 180 / Math.PI; // rads to degs,range (-180,180]
//if (theta < 0) theta = 360 + theta; // range [0,360)
theta = Number(theta).toPrecision(4);
return theta;
}
getBase64Promise(file) {
return new Promise(function(resolve,reject) {
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function() {
return resolve(reader.result);
};
reader.onerror = function(error) {
return reject(error);
};
});
}
getMousePos(event) {
var rect = this.$canvas.get(0).getBoundingClientRect();
return {
x: (event.clientX - rect.left) / (rect.right - rect.left) * this.ctx.canvas.width,y: (event.clientY - rect.top) / (rect.bottom - rect.top) * this.ctx.canvas.height
};
}
/*
This code (getMousePos) takes into account both changing coordinates to canvas space
(evt.clientX - rect.left) and scaling when canvas logical size differs
from its style size
(/ (rect.right - rect.left) * canvas.width see: Canvas width and height in HTML5).
*/
getObjectValuesAsArray(obj) {
return Object.keys(obj).map(function(k) {
return obj[k]
});
}
resetLine() {
this.ctx.save();
this.ctx.globalCompositeOperation = 'copy';
this.ctx.strokeStyle = 'transparent';
this.ctx.beginPath();
this.ctx.lineTo(0,0);
this.ctx.stroke();
this.drawImage(this.imageDataUrl);
this.ctx.restore();
}
drawImage(result) {
var self = this;
console.warn(result);
var img = $('<img>',{
src: result
});
img.on('load',function() {
console.warn("jq image\t",img);
self.imageWidth = img.get(0).naturalWidth;
self.imageHeight = img.get(0).naturalHeight;
self.ctx.canvas.width = img.get(0).naturalWidth;
self.ctx.canvas.height = img.get(0).naturalHeight;
self.ctx.clearRect(0,self.ctx.canvas.width,self.ctx.canvas.height);
self.ctx.drawImage(img.get(0),self.ctx.canvas.height);
});
}
draw_line() {
this.ctx.strokeStyle = this.lineColor;
this.ctx.lineWidth = this.lineWidth;
var x1y1 = this.getObjectValuesAsArray(this.x1y1);
var x2y2 = this.getObjectValuesAsArray(this.x2y2);
//console.log("vectors x1y1\t",x1y1,"\t vectors x2y2",x2y2);
this.ctx.beginPath();
this.ctx.moveTo(x1y1[0],x1y1[1]);
this.ctx.lineTo(x2y2[0],x2y2[1]);
this.ctx.stroke();
//this.ctx.strokeRect(vectors[0],vectors[1],vectors[2],vectors[3]);
}
draw_angle() {
this.ctx.strokeStyle = this.lineColor;
this.ctx.lineWidth = this.lineWidth;
var x2y2 = this.getObjectValuesAsArray(this.x2y2);
//console.log("vectors x1y1\t",x2y2);
this.ctx.font = "18px DejaVuSansMono33-Regular";
this.ctx.fillStyle = this.lineColor;
var x2 = x2y2[0];
var y2 = x2y2[1];
var dx = x2;
var dy = y2;
var width = this.ctx.canvas.width;
var height = this.ctx.canvas.height;
console.warn("canvas width and height",width,height);
this.ctx.fillText(this.angle() + "°",dx,dy);
//this.ctx.strokeRect(vectors[0],vectors[3]);
}
log() {
console.log("x2y2\t",this.x2y2);
//console.log("ctx",this.ctx)
}
init() {
this.setCanvasDimentions();
this.registerX1Y1ClickHandler();
this.registerY2X2MoveHandler();
this.registerOnImageChangeHandler();
this.registerOnColorChangeHandler();
this.registerOnLineWeightChangeHandler();
this.registerSaveLineClickHandler();
this.registerOnResetHandler();
this.log();
}
};
$(document).ready(function() {
var app = new APP();
app.init();
});
@font-face {
font-family: 'DejaVuSansMono33-Regular';
font-style: normal;
font-weight: normal;
src: url("/static/DejaVuSansMono33-Regular.otf") format("truetype");
}
html,body {
font-family: DejaVuSansMono33-Regular,"Helvetica Neue",sans-serif;
font-size: 14px;
background: "red";
height: 100%;
}
canvas#canvas {
height: 100%;
background-size: cover;
background-size: 100% 100%;
display: inline;
}
#measure {
position: absolute;
left: -10000px;
top: -100000px;
}
body {
text-align: center;
background: #f2f6f8;
}
#canvas-container {
height: 100%;
width: 100%;
text-align: center;
padding: 1rem;
background: none;
}
input[type="color"] {
-webkit-appearance: none;
border: none;
width: 32px;
height: 32px;
}
input[type="color"]::-webkit-color-swatch-wrapper {
padding: 0;
}
input[type="color"]::-webkit-color-swatch {
border: none;
}
.container {
height: 100% !important;
}
.section {
padding-bottom: 0px !important;
margin-bottom: 0px !important;
}
解决方法
罪魁祸首显然是这个函数:
drawImage(result) {
var self = this;
console.warn(result);
var img = $('<img>',{
src: result
});
img.on('load',function() {
console.warn("jq image\t",img);
self.imageWidth = img.get(0).naturalWidth;
self.imageHeight = img.get(0).naturalHeight;
self.ctx.canvas.width = img.get(0).naturalWidth;
self.ctx.canvas.height = img.get(0).naturalHeight;
self.ctx.clearRect(0,self.ctx.canvas.width,self.ctx.canvas.height);
self.ctx.drawImage(img.get(0),self.ctx.canvas.height);
});
}
但那里实际发生了什么?
好吧,除了 resetLine()
和 draw_angle()
,它是 mouseMove 回调处理程序的一部分,因此每次鼠标移动时都会执行。
所以:
var img = $('<img>',{
src: result
});
您正在创建一个新图像并使用:
img.on('load',function() {});
您实际上是在等待它被“加载” - 每次鼠标移动。
这意味着您观察到的闪烁是由触发图像的 onload 事件以及您的画布最终获得要绘制的图像所花费的时间造成的。
修复相当简单。我建议设置一个类变量,例如
this.image=null;
并通过以下方式修改 drawImage() 函数:
- 如果
this.image
为 null,则添加 onLoad 侦听器并将局部变量img
分配给this.image
- 如果
this.image
为 not null,则将其用作引用而不是img
类似于:
drawImage(result) {
var self = this;
console.warn(result);
var img = $('<img>',{
src: result
});
if (this.image == null) {
img.on('load',function() {
console.warn("jq image\t",img);
self.imageWidth = img.get(0).naturalWidth;
self.imageHeight = img.get(0).naturalHeight;
self.ctx.canvas.width = img.get(0).naturalWidth;
self.ctx.canvas.height = img.get(0).naturalHeight;
self.ctx.clearRect(0,self.ctx.canvas.height);
self.ctx.drawImage(img.get(0),self.ctx.canvas.height);
});
this.image = img;
} else {
img = this.image;
self.imageWidth = img.get(0).naturalWidth;
self.imageHeight = img.get(0).naturalHeight;
self.ctx.canvas.width = img.get(0).naturalWidth;
self.ctx.canvas.height = img.get(0).naturalHeight;
self.ctx.clearRect(0,self.ctx.canvas.height);
}
}
顺便说一句 - 这绝不是最优雅的方法,它只是为了让您入门。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。