ReactJS and Konva free drawing with pencil, brush and eraser

1k Views Asked by At

I want to create a simple app where I can choose between pencil, brush and eraser. I have Home.js and addLine.js. But there is a bug which I cant fix. When I change from brush back to pencil I'am drawing with the pencil but there is something like a border surrounding the pencil drawing which takes the color I previously used for the brush. Sample bug pucture If it matters I used react color for color picking.

const Home = () => {
 
  
  const stageEl = React.createRef();
  const layerEl = React.createRef();
  const [color, setColor] = useState('');

  
  return (
    <div className="home-page-div">
      <h1>This is the Home page!</h1>
    
      <button onClick= { () => addLine(stageEl.current.getStage(), layerEl.current, color, "pencil")}>Pencil</button>
     <button onClick={ () => addLine(stageEl.current.getStage(), layerEl.current, color, "brush")}>Brush</button>
      <button onClick={() => addLine(stageEl.current.getStage(), layerEl.current, color, "eraser")}>Erase</button>
      <CompactPicker 
      color={color} 
      onChange={(color)=>{setColor(color.hex)}}
      />       
      <Stage
        width={window.innerWidth * 0.9}
        height={window.innerHeight - 150}
        ref={stageEl}
      
      >
        <Layer ref={layerEl}>
        
        </Layer>
      </Stage>
    </div>
  )
};

export default Home;

and addLine

export const addLine = (stage, layer, color, mode) => {
  let isPaint = false;
  let lastLine;
 
  stage.on("mousedown touchstart", function(e) {
    isPaint = true;
    let pos = stage.getPointerPosition();
    lastLine = new Konva.Line({
      stroke:  `${color}`,
      strokeWidth:  mode === "brush" ? 8 : mode === "pencil" ? 1 : 10,
      globalCompositeOperation:
        mode === "eraser" ? 'destination-out' : 'source-over',
      points: [pos.x, pos.y],
      draggable: false,
    });
    layer.add(lastLine);
  });
  console.log(mode);
  console.log(color);
  stage.on("mouseup touchend", function() {
    isPaint = false;
  });
  stage.on("mousemove touchmove", function() {
    if (!isPaint) {
      return;
    }
    
  const pos = stage.getPointerPosition();
    let newPoints = lastLine.points().concat([pos.x, pos.y]);
    lastLine.points(newPoints);
    layer.batchDraw();
  });
};
   
1

There are 1 best solutions below

0
On

On button click, you are calling addLine() function:

<button onClick= { () => addLine(stageEl.current.getStage(), layerEl.current, color, "pencil")}>Pencil</button>

Inside that function you are adding NEW even listeners:

stage.on("mousedown touchstart", function(e) {
  // .. function
});

That means a new listener is added on every click. So when you click on another tool, the old one will still work.

Two fix the issue you can use two ways:

  1. Listen to the stage event just once, and inside addLine() function just change the current attributes of current line. Similar to how it done in Konva free drawing demo

  2. Or just remove all previous listeners inside addLine() function with node.off() method. But I don't recommend that approach as it may lead to bugs if you remove wrong listeners.