[英]JavaScript Canvas on draw vanishes
我有一個canvas函數,如果我單擊canvas字段並移動鼠標,它會繪制一個正方形,目前為止可以使用。
我的問題是,如果我松開鼠標並再次單擊畫布,則舊繪制的矩形將消失。
我如何使舊畫不消失。
我的功能:
function foo() {
var tool = this;
this.started = false;
var canvasx = canvas.offsetLeft;
var canvasy = canvas.offsetTop;
var last_mousex = 0;
var last_mousey = 0;
var mousex = 0;
var mousey = 0;
this.mousedown = function (ev) {
if(checkboxSquare.checked) {
last_mousex = parseInt(ev.clientX-canvasx);
last_mousey = parseInt(ev.clientY-canvasy);
context.strokeStyle = $('#selectColor').val();
context.lineWidth = $('#selectWidth').val();
tool.started = true;
}
};
this.mousemove = function (ev) {
if (tool.started && checkboxSquare.checked) {
mousex = parseInt(ev.clientX-canvasx);
mousey = parseInt(ev.clientY-canvasy);
context.clearRect(0, 0, canvas.width, canvas.height); // clear canvas
context.beginPath();
var width = mousex-last_mousex;
var height = mousey-last_mousey;
context.rect(last_mousex,last_mousey,width,height);
context.stroke();
}
};
this.mouseup = function (ev) {
if (tool.started && checkboxSquare.checked) {
tool.mousemove(ev);
tool.started = false;
}
};
}
看起來像這樣: http : //jsfiddle.net/AbdiasSoftware/kqW4X/
舊的繪制矩形在單擊時消失,因為每次繪制矩形之前您都要清除整個畫布。
最簡單的解決方法是將整個畫布另存為mouseup上的圖像,並在繪制每個矩形之前繪制該圖像。
var canvas; var _foo = new foo(); canvas.onmousedown = _foo.mousedown; canvas.onmousemove= _foo.mousemove; canvas.onmouseup = _foo.mouseup; function foo() { canvas = $('#canvas')[0]; var context = canvas.getContext('2d'); var checkboxSquare = $('#checkboxSquare')[0]; var img = new Image(); var tool = this; this.started = false; var last_mousex = 0; var last_mousey = 0; var mousex = 0; var mousey = 0; this.mousedown = function (ev) { if(checkboxSquare.checked) { last_mousex = ev.offsetX; last_mousey = ev.offsetY; context.strokeStyle = $('#selectColor').val(); context.lineWidth = $('#selectWidth').val(); tool.started = true; } }; this.mousemove = function (ev) { if (tool.started && checkboxSquare.checked) { mousex = ev.offsetX; mousey = ev.offsetY; context.clearRect(0, 0, canvas.width, canvas.height); // clear canvas context.drawImage(img, 0, 0); // draw saved canvas (image) context.beginPath(); var width = mousex-last_mousex; var height = mousey-last_mousey; context.rect(last_mousex,last_mousey,width,height); context.stroke(); } }; this.mouseup = function (ev) { if (tool.started && checkboxSquare.checked) { tool.mousemove(ev); img.src = canvas.toDataURL(); // save canvas as image tool.started = false; } }; }
canvas { border: 1px solid black; cursor: default; margin-top: 5px }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <input type="checkbox" id="checkboxSquare">Square | Color <select id="selectColor"> <option value="red">red</option> <option value="green">green</option> <option value="blue">blue</option> </select> | Width <select id="selectWidth"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <canvas id="canvas" width="400" height="400"></canvas>
只需創建與主畫布相同的背景畫布即可。 拖出新框時,首先在主畫布上繪制背景畫布(包括所有過去的框),然后繪制當前框。 完成拖動框后,只需將其拖到背景畫布上即可。
const canvas = document.createElement("canvas"); const background = document.createElement("canvas"); canvas.style.border="2px solid black"; canvas.style.cursor = "crosshair"; background.width = canvas.width = innerWidth - 24; background.height = canvas.height = innerHeight - 24; const ctx = canvas.getContext("2d"); background.ctx = background.getContext("2d"); document.body.appendChild(canvas); const bounds = canvas.getBoundingClientRect(); var currentBox; const boxStyle = { fillStyle : "#4aF", strokeStyle : "black", lineWidth : 3, lineJoin : "round", } const mouse = { x : 0, y : 0,button : false, changed : false }; ["mousemove","mousedown","mouseup"].forEach(en => document.addEventListener(en, mouseEvent)); function createBox(x,y,w,h,style){ return {x,y,w,h,style,draw : drawBox} } function drawBox(ctx){ setStyle(ctx, this.style); ctx.beginPath(); ctx.rect(this.x,this.y,this.w,this.h); ctx.fill(); ctx.stroke(); } function setStyle(ctx, style){ Object.keys(style).forEach(key => ctx[key] = style[key]) } function mouseEvent(event) { mouse.x = event.pageX - bounds.left - scrollX; mouse.y = event.pageY - bounds.top - scrollY; if(event.type === "mousedown"){ mouse.button = true } else if(event.type === "mouseup"){ mouse.button = false } mouse.changed = true; } function mainLoop(){ var b = currentBox; // alias for readability if(mouse.changed){ if(mouse.button){ if(!b){ b = currentBox = createBox(mouse.x,mouse.y,0,0,boxStyle); }else{ bw = mouse.x - bx; bh = mouse.y - by; } }else if(b){ b.draw(background.ctx); b = currentBox = undefined; } if(b){ ctx.clearRect(0,0,canvas.width,canvas.height); ctx.drawImage(background,0,0); b.draw(ctx); canvas.style.cursor = "none"; }else{ canvas.style.cursor = "crosshair"; } mouse.changed = false; } requestAnimationFrame(mainLoop); } requestAnimationFrame(mainLoop);
創建畫布繪圖應用程序時,您應該偵聽文檔鼠標事件而不是畫布。 按下鼠標按鈕時,即使您已將畫布,文檔或事件移出瀏覽器窗口,也將捕獲鼠標並在按下鼠標時繼續發送鼠標事件。
這意味着您可以拖動畫布的內容,而不必擔心丟失mouseup事件。
我有一些時間要花費,所以將擴展上面的演示以包括選擇和移動現有框。 像往常一樣畫盒子。 將鼠標懸停在框上會突出顯示它們,單擊以選中它們。 選中后可以拖動。 使用相同的方法背景圖片保存舊盒子。 但是增加了一個盒子列表來容納舊盒子一個更廣泛的例子
const canvas = document.createElement("canvas"); const background = document.createElement("canvas"); canvas.style.border="2px solid black"; canvas.style.cursor = "crosshair"; background.width = canvas.width = innerWidth - 24; background.height = canvas.height = innerHeight - 24; const ctx = canvas.getContext("2d"); background.ctx = background.getContext("2d"); document.body.appendChild(canvas); const bounds = canvas.getBoundingClientRect(); var currentBox; var selectedBox; var mouseOverBox; const styles = { box : { fillStyle : "#4aF", strokeStyle : "black", lineWidth : 3, lineJoin : "round", }, highlight : { strokeStyle : "white", lineWidth : 1, lineJoin : "round", setLineDash : [[10,10]], }, selected : { strokeStyle : "red", lineWidth : 2, lineJoin : "round", setLineDash : [[5,5]], }, } const boxes = { items : [], add(box){ // add a box and fix width and height to positive if(box.w < 0){ box.x += box.w; box.w = -box.w; } if(box.h < 0){ box.y += box.h; box.h = -box.h; } boxes.items.push(box) }, apply(name, ...args){ for(var i = 0; i < boxes.items.length; i ++ ){ boxes.items[i][name](...args); } }, }; const mouse = { x : 0, y : 0,button : false, changed : false }; ["mousemove","mousedown","mouseup"].forEach(en => document.addEventListener(en, mouseEvent)); const boxBehaviours = { draw(ctx, style = this.style){ if(!this.hide){ setStyle(ctx, style); ctx.beginPath(); ctx.rect(this.x,this.y,this.w,this.h); if(style.fillStyle) { ctx.fill() } if(style.strokeStyle) {ctx.stroke() } } }, isPointOver(x,y){ var b = this; if(x >= bx && x < bx + bw && y >= by && y < by + bh){ b.mouseOver = true; boxBehaviours.topMouseBox = b; }else { b.mouseOver =false; } }, } function createBox(x,y,w,h,style){ return {x,y,w,h,style, ...boxBehaviours}; } function setStyle(ctx, style){ Object.keys(style).forEach(key => { if(typeof ctx[key] === "function"){ ctx[key](...style[key]); }else{ ctx[key] = style[key]; } }) } function mouseEvent(event) { mouse.x = event.pageX - bounds.left - scrollX; mouse.y = event.pageY - bounds.top - scrollY; if(event.type === "mousedown"){ mouse.button = true } else if(event.type === "mouseup"){ mouse.button = false } } function redrawBackground(){ background.ctx.clearRect(0,0,canvas.width,canvas.height) boxes.apply("draw",background.ctx); } function mainLoop(time){ var b = currentBox; // alias for readability var mob = mouseOverBox; // alias for readability var sb = selectedBox; // alias for readability // first check mouse button. If button down could be // dragging a selected box or creating a new box if(mouse.button){ if(sb){ // is selected box if(!mouse.drag){ // start the drag mouse.drag = {x : mouse.x - sb.x, y : mouse.y - sb.y} }else{ // move the box sb.x = mouse.x- mouse.drag.x; sb.y = mouse.y- mouse.drag.y; } }else{ // else muse be create (or select click) if(!b){ b = currentBox = createBox(mouse.x,mouse.y,0,0,styles.box); }else{ bw = mouse.x - bx; bh = mouse.y - by; } } }else if(b || sb){ // mouse up and there is a box if(sb){ // if selected box if(mouse.drag){ // is dragging then drop it mouse.drag = undefined; sb.hide = false; redrawBackground(); sb = selectedBox = undefined; } // is the mouse is down and has not moved over 2 pixels // and there is a mob (mouseOverBox) under it // then dump the new box and select the mob box }else if(Math.abs(bw) < 2 && Math.abs(bh) < 2 && mob){ sb = selectedBox = mob; mob = mouseOverBox = undefined; b = currentBox = undefined; sb.hide = true; redrawBackground(); }else{ // just a normal box add it to box array // draw it and remove it from currentBox boxes.add(b); b.draw(background.ctx); b = currentBox = undefined; } } // clear andf draw background ctx.clearRect(0,0,canvas.width,canvas.height); ctx.drawImage(background,0,0); if(b){ // is there a current box then draw that b.draw(ctx); canvas.style.cursor = "none"; } else { // no current box so // find any boxes under the mouse boxBehaviours.topMouseBox = null; boxes.apply("isPointOver",mouse.x, mouse.y); // is there a selected box (sb) if(sb){ // yes selected box then draw it ctx.save(); styles.selected.lineDashOffset = time / 25; sb.hide = false; sb.draw(ctx,styles.selected); sb.hide = true; ctx.restore(); canvas.style.cursor = "move"; // no selected box sp then just high light the box under the // mouse and assign it to mouseOverBox (mob); }else if(boxBehaviours.topMouseBox){ mob = mouseOverBox = boxBehaviours.topMouseBox; ctx.save(); styles.highlight.lineDashOffset = time / 20; mob.draw(ctx, styles.highlight); ctx.restore(); canvas.style.cursor = "pointer"; }else{ canvas.style.cursor = "crosshair"; } } requestAnimationFrame(mainLoop); } requestAnimationFrame(mainLoop);
我假設通過setInterval
或requestAnimationFrame
為每個幀調用foo()
函數。 如果我的假設是正確的,那么先前繪制的正方形消失的原因是因為您僅存儲一個矩形的x和y坐標,並且每次再次單擊畫布時,它都會被新矩形的新值覆蓋。
要解決您的問題,應在mouseup上存儲x和y坐標以及正方形的尺寸。 這些坐標可以存儲在數組中。
var squares = [];
this.mouseup = function (ev) {
// other code
var square = {
x: last_mousex,
y: last_mousey,
width: mousex - last_mousex,
height: mousey - last_mousey
};
squares.push(square);
};
現在,每次繪制正方形時,請先繪制squares
數組中存儲的squares
。
this.mousemove = function (ev) {
if (tool.started && checkboxSquare.checked) {
// other code
context.clearRect(0, 0, canvas.width, canvas.height); // clear canvas
// draw each square in the squares array after clearning the canvas
squares.forEach(function(square) {
context.beginPath();
context.rect(square.x, square.y, square.width, square.height);
});
context.beginPath();
var width = mousex - last_mousex;
var height = mousey - last_mousey;
context.rect(last_mousex, last_mousey, width, height);
context.stroke();
}
};
您將在繪制正方形時看到一些代碼重復,這是將其抽象為單獨函數的好機會。
var point = []; var clicks = 0; var sketch = document.querySelector('#sketch'); var sketch_style = getComputedStyle(sketch); // Creating a tmp canvas var tmp_canvas = document.createElement('canvas'); var tmp_ctx = tmp_canvas.getContext('2d'); tmp_canvas.id = 'tmp_canvas'; tmp_canvas.width = parseInt(sketch_style.getPropertyValue('width')); tmp_canvas.height = parseInt(sketch_style.getPropertyValue('height')); sketch.appendChild(tmp_canvas); var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); canvas.id = 'paint'; canvas.width = parseInt(sketch_style.getPropertyValue('width')); canvas.height = parseInt(sketch_style.getPropertyValue('height')); sketch.appendChild(canvas); tmp_canvas.addEventListener('mousedown', mousedown, false); tmp_canvas.addEventListener('mousemove', mousemove, false); tmp_canvas.addEventListener('mouseup', mouseup, false); function mousemove(e) { if (clicks == 1) { x = e.layerX - this.offsetLeft; y = e.layerY - this.offsetTop; showRect(x, y); } } function showRect(x, y) { tmp_ctx.clearRect(0, 0, canvas.width, canvas.height); // clear canvas tmp_ctx.beginPath(); var width = x - point[0].x; var height = y - point[0].y; tmp_ctx.rect(point[0].x, point[0].y, width, height); tmp_ctx.stroke(); } function mousedown(e) { x = e.layerX - this.offsetLeft; y = e.layerY - this.offsetTop; point.push({ x, y }); clicks++; }; function mouseup() { context.drawImage(tmp_canvas, 0, 0); clicks = 0; point.length = 0; }
html, body { width: 100% ; height: 100% ; } #sketch { border: 10px solid gray; height: 100% ; position: relative; } #tmp_canvas { position: absolute; left: 0px; right: 0; bottom: 0; top: 0; cursor: crosshair; }
<html> <head> <meta charset="utf-8"> </head> <body> <div id="sketch"> </div> </body> </html>
嘗試在臨時畫布中進行繪制,然后在主畫布中全部重繪。
的jsfiddle: - https://jsfiddle.net/durga598/v0m06faz/
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.