0

I have an array of elements which has some coordinates. On the basis of that coordinates, I am drawing the element in a single canvas. Now I want when the user clicks on any of the element it should trigger a function.

can anyone has an idea of how we can do it

       //js part
      drawLayout() {
        const canvas = this.refs.canvas;
        const ctx = canvas.getContext("2d");

        data.forEach(item => {
            ctx.beginPath();
            ctx.lineWidth = "1";
            ctx.strokeStyle = "red";
            let X = (maxValueOfX - item.row) * width;
            let Y = item.column * height;

            ctx.fillText(item.name, X + 5, Y + 10);

            ctx.rect(X, Y ,width, height)
            ctx.stroke();
       });
       componentDidMount() { 
          this.drawLayout()
       }

    //html part
          <div className="layoutContainer">
                        <canvas
                            ref="canvas"
                            width={width}
                            height={height}
                            style={{ backgroundColor: "#e1d4d4" }}
                        />
             </div>

Thanks

Shyam Kumar
  • 586
  • 3
  • 17

2 Answers2

2

I see there is already an answer. Mine is using plain Javascript but I hope you'll find it useful. First you need a function to detect the mouse position on the canvas.

Immediately after drawing the rect I add an event listener to detect if the rect was clicked.

 function drawLayout() {
        //const canvas = this.refs.canvas;
        const ctx = canvas.getContext("2d");
        canvas.width = 400;
        canvas.height = 400;
       
            ctx.beginPath();
            ctx.lineWidth = "1";
            ctx.strokeStyle = "red";
            let X = 130;
            let Y = 45;
            let text = "test qwerty"

            ctx.fillText(text, X + 5, Y + 12);

            ctx.rect(X, Y , ctx.measureText(text).width + 10 , 16);
            // immediately after drawing the rect add an event listener
            canvas.addEventListener("click",(evt)=>{
              let m = oMousePos(canvas, evt);// the mouse
              // check if the mouse is in path
              if (ctx.isPointInPath(m.x, m.y)) {
              // do something
              console.log(text);
              }
            })
            // stroke the rect
            ctx.stroke();
 }
       
  this.drawLayout();

// a function to get the position of the mouse
function oMousePos(canvas, evt) {
  var ClientRect = canvas.getBoundingClientRect();
 return { //objeto
 x: Math.round(evt.clientX - ClientRect.left),
 y: Math.round(evt.clientY - ClientRect.top)
}
}
      
 <div className="seatLayoutContainer">
                        <canvas
                            id="canvas"
                            width="400"
                            height="400"
                            style="background-color: #e1d4d4"
                        />
             </div>
enxaneta
  • 31,608
  • 5
  • 29
  • 42
1

This seems closely related to this answer about adding an onClick to a canvas element except that you will need to calculate position for multiple elements based on the clicked coordinates.

I slightly modified the jsfiddle from that answer to show one way to tell which element was clicked. This should give you some ideas, but can definitely be cleaned up.

    var elem = document.getElementById('myCanvas'),
    elemLeft = elem.offsetLeft,
    elemTop = elem.offsetTop,
    context = elem.getContext('2d'),
    elements = [];

// Add event listener for `click` events.
elem.addEventListener('click', function(event) {
    var x = event.pageX - elemLeft,
        y = event.pageY - elemTop;
    console.log(x, y);
    elements.forEach(function(element) {
        if (y > element.top && y < element.top + element.height && x > element.left && x < element.left + element.width) {
            switch (element.left) {
                case 20:
                    alert('clicked the first element');
                    break;
                case 40:
                    alert('clicked the second element');
                    break;
                case 60:
                    alert('clicked the third element');
                    break;
                default:
                    alert('No idea what you clicked')
            }
        }
    });

}, false);

// Add element.
elements.push({
    colour: '#05EFFF',
    width: 20,
    height: 20,
    top: 20,
    left: 20
});

// Add element.
elements.push({
    colour: 'red',
    width: 20,
    height: 20,
    top: 20,
    left: 40
});

// Add element.
elements.push({
    colour: 'blue',
    width: 20,
    height: 20,
    top: 20,
    left: 60
});
// Render elements.
elements.forEach(function(element) {
    context.fillStyle = element.colour;
    context.fillRect(element.left, element.top, element.width, element.height);
});

The only difference here is that we are using the coordinates that were clicked to decide which individual canvas element was clicked.

  • you have used fixed number of switch case for all the elements, but In our case it will vary each time. We haven't fixed number of elements. Let me check if I can make switch case dynamically. – Shyam Kumar Mar 18 '19 at 13:16