0

Is there any way to allow a user to draw on top of a board of divs and allow the drawing to float on top, but for the divs below to still be selectable?

Using html5 canvas (react-sketch), you can of course superimpose a canvas object on top of a page of divs, but then the underlying divs are covered by the (transparent) canvas, and though viewable, cannot be selected.

Is there any simple way around this?

claireablani
  • 6,042
  • 5
  • 12
  • 18
  • 1
    "simple"? Not really... Try to think about it, how would you differentiate between a click that should draw and one that should select div's content? Now, there are ways to do things around that, but you need to be really clear with us about the configuration and the features you'd like to have. E.g, it is feasible to avoid the canvas layer except when no text is selected in underlying divs, or to trigger fake clicks on underlying buttons, but your question is too broad to get an clear answer. – Kaiido Sep 19 '17 at 06:51

1 Answers1

1

It's doable but you will invite several challenges that in my opinion is simply not worth it.

Example of this:

var ctx = c.getContext("2d"), rect = c.getBoundingClientRect(), isDown = false;
c.width = rect.width;
c.height = rect.height;

// canvas interaction when no divs are in the way
window.onmouseup = window.onmousedown = function(e) {isDown = e.type === "mousedown"};

window.onmousemove = function(e) {
  if (isDown) ctx.fillRect(e.clientX, e.clientY, 2, 2);
};
#c {
  position:fixed;
  left:0;
  top:0;
  width:100vw;
  height:100vh;
  pointer-events:none;
  }

div {
  padding:10px;
  border:1px solid #999;
  width:200px;
  margin-bottom:9px;
  }
<div>Hello</div>
<div>There</div>
<canvas id=c></canvas>

As you can see, sure, we can interact and select divs below the canvas, but we are still drawing to the canvas and so forth.

If I may suggest a different approach, it would be to have a modus switch so that when you activate interactive mode using a switch/button in the UI, only interaction with canvas is allowed, and of course, vica versa when mode is switched off.

The mode button could be attached to a hotkey, middle mouse-button and so forth.

var ctx = c.getContext("2d"), rect = c.getBoundingClientRect(), isDown = false;
var drawMode = false;
c.width = rect.width;
c.height = rect.height;

window.onmouseup = c.onmousedown = function(e) {isDown = e.type === "mousedown"};

// only draw if we are in interactive mode
c.onmousemove = function(e) {
  if (drawMode && isDown) ctx.fillRect(e.clientX, e.clientY, 2, 2);
};

// toggle mode
document.querySelector("button").onclick = function() {
  this.classList.toggle("selected");
  c.classList.toggle("active");
  drawMode = !drawMode;
};
#c {
  position:fixed;
  left:0;
  top:0;
  width:100vw;
  height:100vh;
  pointer-events:none;
  }
#c.active {
  pointer-events:auto;
  }
div {
  padding:10px;
  border:1px solid #999;
  width:200px;
  margin-bottom:9px;
  }

button {
  position:fixed;
  right:7px;
  top:7px;
  opacity:0.5;
  transition:opacity 0.2s;
  background:#9f9;
  border:1px solid #000;
  padding:7px;
  }
button:hover {opacity:1}
button.selected {background:#fc0}
<div>Hello</div>
<div>There</div>
<canvas id=c></canvas>
<button>Interactive mode</button>
<p>Click button in upper right corner to activate interactive drawing on canvas</p>
  • Would there be any way in your example to then save the drawing, so that it could be rerendered in this canvas-y state, where objects underneath were still selectable? – claireablani Sep 21 '17 at 05:40
  • @claireablani sure, you can record the points drawn, or store the content as an image (toDataURL, toBlob, getImageData) and redraw when needed. –  Sep 22 '17 at 03:14
  • ah okay, I will look up "redraw from toDataURL" and "redraw from blob" – claireablani Sep 22 '17 at 05:53