绘制上的JavaScript Canvas消失

时间:2017-04-05 11:47:32

标签: javascript 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/

4 个答案:

答案 0 :(得分:1)

旧的绘制矩形在点击时消失,因为每次在绘制矩形之前都会清除整个画布。

最简单的解决方法是将整个画布保存为mouseup上的图像,并在绘制每个矩形之前绘制该图像。

 std::vector& layerStack = Stack::getLayers()
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
}

答案 1 :(得分:1)

只需创建与主画布相同的背景画布。当您拖出一个新框时,首先在主画布上绘制背景画布(包含所有过去的框),然后绘制当前框。完成拖动框后,只需将其转到背景画布。



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{
               b.w = mouse.x - b.x;
               b.h = mouse.y - b.y;
           }
        }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);




额外注意。使用Document

捕获鼠标

创建画布绘制应用程序时,您应该听取文档鼠标事件而不是画布。当鼠标按钮关闭时,鼠标会被捕获并在鼠标停止时继续发送鼠标事件,即使您已从浏览器窗口外的画布,文档或事件移开。

这意味着您可以拖动画布的内容,而不必担心丢失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 >= b.x && x < b.x + b.w && y >= b.y && y < b.y + b.h){
                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{
                 b.w = mouse.x - b.x;
                 b.h = mouse.y - b.y;
             }
           }
        }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(b.w) < 2 && Math.abs(b.h) < 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);
&#13;
&#13;
&#13;

答案 2 :(得分:0)

我假设通过var path = DependencyService.Get<IFilesystemService>().GetAppRootFolder();foo()为每一帧调用setInterval函数。如果我的假设是正确的,你之前绘制的正方形消失的原因是你只存储一个矩形的x和y坐标,每次再次点击画布时,它会被新矩形的新值覆盖

要解决您的问题,您应该在mouseup上存储x和y坐标以及方形的尺寸。这些坐标可以存储在数组中。

requestAnimationFrame

现在每次绘制正方形时,首先绘制存储在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

在绘制正方形时,您会看到一些代码重复,这是将其抽象为单独函数的好机会。

答案 3 :(得分:0)

&#13;
&#13;
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;
}
&#13;
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;
}
&#13;
<html>
<head>
    <meta charset="utf-8">
</head>
<body>
    <div id="sketch">
    </div>
</body>
</html>
&#13;
&#13;
&#13;

尝试在临时画布中执行并在main中重绘所有内容。

的jsfiddle: - https://jsfiddle.net/durga598/v0m06faz/