Nidhin Joseph
Nidhin Joseph

Reputation: 10237

Making interactive canvas with SVG image borders

I am having an issue accessing elements inside a div with a 'irregular' border design.

The requirement that I have is to have a border which has 2 clickable elements on the top side of a div. The div itself has a canvas to draw anything.

The problem is, if I need to make the border visible, then I have to make the z-index for div lower, which would no longer allow drawing in the canvas. If I make the z-index for the div higher, then, the border elements gets cut off.

I have tried border-image, but it (1) it makes the corners square and (2) it does not make the 2 items clickable. So, I have an SVG which contains the border, and 2 clickable Elements.

(function() {
  const canvas = document.getElementById('signature-pad');

  function resizeCanvas() {
    const ratio = Math.max(window.devicePixelRatio || 1, 1);
    canvas.width = canvas.offsetWidth * ratio;
    canvas.height = canvas.offsetHeight * ratio;
    canvas.getContext('2d').scale(ratio, ratio);
  }

  window.onresize = resizeCanvas;
  resizeCanvas();

  const signaturePad = new SignaturePad(canvas, {
    backgroundColor: 'red' // necessary for saving image as JPEG; can be removed is only saving as PNG or SVG
  });

})();
.container {
  height: 500px;
  width: 409px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}

img {
  position: absolute;
  top: 0;
  height: 100%;
  z-index: 1;
}

.container::before {
  display: block;
  content: " ";
  position: absolute;
  width: calc(100% - 3rem);
  height: calc(100% - 2rem);
  background-color: red;
  z-index: -1;
}

canvas {
  width: calc(100% - 3rem);
  height: calc(100% - 2rem);
  z-index: 1;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/signature_pad.min.js"></script>

<div class="container">
  <img src="https://i.imgur.com/yWMwxJQ.png">
  <canvas id="signature-pad" class="signature-pad" height="500px;" width="409px;"></canvas>
</div>

JSFiddle

Upvotes: 0

Views: 459

Answers (2)

Kaiido
Kaiido

Reputation: 136708

Just set your <img> first (higher z-index) and its pointer-events CSS rule to none, this way, pointer events will go through it and reach your canvas:

(function() {
  const canvas = document.getElementById('signature-pad');

  function resizeCanvas() {
    const ratio = Math.max(window.devicePixelRatio || 1, 1);
    canvas.width = canvas.offsetWidth * ratio;
    canvas.height = canvas.offsetHeight * ratio;
    canvas.getContext('2d').scale(ratio, ratio);
  }

  window.onresize = resizeCanvas;
  resizeCanvas();

  const signaturePad = new SignaturePad(canvas, {
    backgroundColor: 'red' // necessary for saving image as JPEG; can be removed is only saving as PNG or SVG
  });

})();
.container {
  height: 500px;
  width: 409px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}

img {
  position: absolute;
  top: 0;
  height: 100%;
  z-index: 1;
  /* disable all pointer-events so we can reach underneath layer */
  pointer-events: none;
}

.container::before {
  display: block;
  content: " ";
  position: absolute;
  width: calc(100% - 3rem);
  height: calc(100% - 2rem);
  background-color: red;
  z-index: -1;
}

canvas {
  width: calc(100% - 3rem);
  height: calc(100% - 2rem);
  z-index: 1;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/signature_pad.min.js"></script>

<div class="container">
  <canvas id="signature-pad" class="signature-pad" height="500px;" width="409px;"></canvas>
  <!-- make <img> on top -->
  <img src="https://i.imgur.com/yWMwxJQ.png">
</div>

Upvotes: 1

Cue
Cue

Reputation: 2759

Using a ::before pseudo element you can create a block inside .container with z-index: -1

Apply background-image (or foreground using <img>, I've opted for background) to .item.

.container {
  height: 500px;
  width: 409px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}

.container::before {
  display: block;
  content: " ";
  position: absolute;
  width: calc(100% - 3rem);
  height: calc(100% - 2rem);
  background-color: red;
  z-index: -1;
  
}

.item {
  background-size: contain;
  background-repeat: no-repeat;
  height: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
<div class="container">
  <div class="item" style="background-image:url('https://i.imgur.com/yWMwxJQ.png')">
    <div><button onclick="alert(1)">Hello</button></div>
  </div>
</div>

Upvotes: 1

Related Questions