0

I have an image send by a camera with a websocket and I display it with a canvas, then, I draw on it. I tried to, when the user click on a different place, to delete the previous lines and draw the new ones but, I've read that was impossible to clear a precise part of a canvas, but, with surprise, it's happend to me.

So I wanted to know why it works even if I read multiple time that was impossible.

When I launch the program for the first time and there is no images yet, there is no refresh but when I display the first picture, I can click many times, only the last click will be show and I don't understand why.

Thanks for your help and here a sample of my code

    updateImage(){
    console.log(this.refs.myCanvas);

    const ctx = this.refs.myCanvas.getContext('2d');
    let src = this.state.imageSrc;

    this.image.onload = () => {
      console.log('done')
      //ctx.clearRect(0,0,this.refs.myCanvas.width,this.refs.myCanvas.height)
      ctx.drawImage(this.image, 0, 0,this.refs.myCanvas.width,this.refs.myCanvas.height); //On dessine l'image
      if(this.props.beam_markX != undefined && this.props.beam_markY != undefined){
        this.draw_Beam_Marker()
      }

    }
    this.image.src = "data:image/jpg;base64,"+src;
    this.componentWillUnmount() //On appel la derniere methode

  }

  draw_Beam_Marker(e){
    const ctx = this.refs.myCanvas.getContext('2d');
    ctx.strokeStyle = "#7FFF00" //chartreuse
    ctx.font = '15px Arial'
    ctx.fillStyle = "#7FFF00"

    if(e != undefined){ //Quand on clique sur l'image

      if(this.props.beam_markX != e.nativeEvent.offsetX && this.props.beam_markY != e.nativeEvent.offsetY && this.props.crosshair === 0){ //On ne dessine que si nouveaux coordonnes et que le crosshair n'est pas lock

        ctx.beginPath();
        ctx.moveTo(0, e.nativeEvent.offsetY);
        ctx.lineTo(this.refs.myCanvas.width, e.nativeEvent.offsetY);
        ctx.stroke();
        ctx.moveTo(e.nativeEvent.offsetX, 0);
        ctx.lineTo(e.nativeEvent.offsetX, this.refs.myCanvas.height);
        ctx.stroke();
        ctx.fillText("X: "+e.nativeEvent.offsetX,e.nativeEvent.offsetX+1,e.nativeEvent.offsetY+12);
        ctx.fillText("Y: "+e.nativeEvent.offsetY,e.nativeEvent.offsetX+1,e.nativeEvent.offsetY+30);
        ctx.fillText("W: "+this.refs.myCanvas.width,e.nativeEvent.offsetX+1,e.nativeEvent.offsetY+48);
        ctx.fillText("H: "+this.refs.myCanvas.height,e.nativeEvent.offsetX+1,e.nativeEvent.offsetY+66);
        ctx.closePath();
        this.props.setBeamMark(e.nativeEvent.offsetX,e.nativeEvent.offsetY);

      }
    }
      else if(this.props.beam_markX != undefined && this.props.beam_markY != undefined ){ //Quand on passe a une nouvelle image
        //ctx.clearRect(0,0,this.refs.myCanvas.width,this.refs.myCanvas.height)
        ctx.beginPath();
        ctx.moveTo(0, this.props.beam_markY);
        ctx.lineTo(this.refs.myCanvas.width, this.props.beam_markY);
        ctx.stroke();
        ctx.moveTo(this.props.beam_markX, 0);
        ctx.lineTo(this.props.beam_markX, this.refs.myCanvas.height);
        ctx.stroke();
        ctx.fillText("X: "+this.props.beam_markX,this.props.beam_markX+1,this.props.beam_markY+12)
        ctx.fillText("Y: "+this.props.beam_markY,this.props.beam_markX+1,this.props.beam_markY+30);
        ctx.fillText("W: "+this.refs.myCanvas.width,this.props.beam_markX+1,this.props.beam_markY+48);
        ctx.fillText("H: "+this.refs.myCanvas.height,this.props.beam_markX+1,this.props.beam_markY+66);
        ctx.closePath();
      }
  }

When no image display (last click is when X=409)

With first image, the olds clicks disappeared

When no image display (last click is when X=502) With first image, only the last is showed

Quentin
  • 486
  • 4
  • 20
  • I don't understand your question. Please be more concise and try to write a ;tldr. Secondly, please link the articles where you read clearing a precise part of a canvas was impossible so that I can understand what was original meant – EyuelDK May 18 '17 at 13:19
  • @EyuelDK Sorry for my bad english, i will try to be more precise. Firstly, here the link where it' s said it's not possible http://stackoverflow.com/questions/24140805/how-to-clear-specific-line-in-canvas-html5 . Secondly, why I tried to know, it's why when I have an image, there only the last lines where I clicked to be visible, why it's not the same render like the first picture, with no refresh – Quentin May 18 '17 at 13:26
  • Are you sure this is the code you used to produce the images below? This statement `this.draw_Beam_Marker()` would never draw anything because the parameter `e` is always undefined. I don't think that this is the code originally used. – EyuelDK May 18 '17 at 13:57
  • However, this is actually the code used and running, e is only defined when I click on the canvas. – Quentin May 18 '17 at 14:01
  • I still don't think that this code tells the full story, but if it works it works - even though I don't agree with that mentality. But take a look at your definition of the method `draw_Beam_Marker(e)`, it accepts a parameter `e` but is called here without any appropriate arguments `this.draw_Beam_Marker()` In the body of `draw_Beam_Marker` it clearly states `if(e != undefined){ //Quand on clique sur l'image` This should always be false when this is execute`this.draw_Beam_Marker()` IMO, there is some other part of your code that is making it work other than what you showed here. – EyuelDK May 18 '17 at 14:08

2 Answers2

0

Only the last click is being shown because you are drawing the image and that is going to overlay the entire canvas and then you are drawing your lines this.props.beam_markX and this.props.beam_markY which is only going to then draw one line. A way you could do this is each time you click store inside an array your x and y values then: clear the canvas, draw the image, and redraw the lines! Here is an example:

var canvas = document.querySelectorAll('canvas')[0]
var ctx = canvas.getContext('2d')
var clicks = []
canvas.addEventListener('click', function(event){
    var x = event.clientX
    var y = event.clientY

    clicks.push({
      x:event.clientX,
      y:event.clientY
    })
    
    drawLines()
})

function drawLines(){
 //Make the canvas blank
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  
  //Draw your image here
  //ctx.drawImage
  
  //Draw the lings
  for(var click of clicks){
    //Y Axis Line
    drawLine(click.x, 0, click.x, canvas.height)
      //X Axis Line
      drawLine(0, click.y, canvas.width, click.y)
      //Text
      ctx.fillText(click.x + ', ' + click.y,click.x,click.y)
      
  }
}

function drawLine(x1, y1, x2, y2){
   ctx.beginPath();
      ctx.moveTo(x1,y1);
      ctx.lineTo(x2,y2);
      ctx.stroke();
}
html, body{
  margin:0px;
  padding:0px;
}
canvas{
  background:#cdcdcd;
}
<canvas width="200" height="200"></canvas>
<p>Click in the canvas!</p>

Hope it helps!! :]

Sean_Codes
  • 131
  • 8
  • Thanks to take time for help but I have only one question, "Only the last click is being shown because you are drawing the image and that is going to overlay the entire canvas". Ok I understand, but when the canvas was overlay with the image, why the refreshing style happening ? I mean, did each time I click somewhere the image was drawing again so overlay the previous 'instance' of herself ? – Quentin May 18 '17 at 14:02
  • Yes the canvas doesn't work the same way as normal html elements technically you don't even need to clear the canvas here because the image will take the full width and height and draw over everything! :] So yes each time you draw the image it overlays the last image – Sean_Codes May 18 '17 at 14:11
  • Yes I understand that part, but if I don't change the image, I stay on the same everytime and I cliked somewhere, the old marker disapeared and the new apperead and I don't know why because I don't call method to draw new image ... Sorry, i'm maybe retarded ... – Quentin May 18 '17 at 14:16
  • Ok I understand, I tried to maniupalete width and height of my drawing image, and you're write, each time I click on my image, even if it was the same was re-drawing, thanks for help :) – Quentin May 18 '17 at 14:31
0

Your entire problem lies with this code:

this.image.onload = () => {
  console.log('done')
  //ctx.clearRect(0,0,this.refs.myCanvas.width,this.refs.myCanvas.height)
  ctx.drawImage(this.image, 0, 0,this.refs.myCanvas.width,this.refs.myCanvas.height); //On dessine l'image
  if(this.props.beam_markX != undefined && this.props.beam_markY != undefined){
    this.draw_Beam_Marker() 
  }
}

Simply put, this statement ctx.drawImage(this.image, 0, 0, this.refs.myCanvas.width, this.refs.myCanvas.height); will draw over your previous drawings. The only markers that will remain are the ones drawn after the image has loaded.

EyuelDK
  • 3,029
  • 2
  • 19
  • 27
  • I tried to deleted this part : if(this.props.beam_markX != undefined && this.props.beam_markY != undefined){ this.draw_Beam_Marker() } and the results is, if I tried to click somewhere, the mark apparead and disappeared instantly, just like the canvas is always refreshing – Quentin May 18 '17 at 14:13
  • Ok I understand, I tried to manipulete width and height of my drawing image, and you're write, each time I click on my image, even if it was the same was re-drawing, thanks for help :) – Quentin May 18 '17 at 14:31