Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<h1>Preparations</h1> <p>In order to detect line-clicks we need to record all path information.</p> <p>The following example is a modified version of the code provided in original post and includes a stroke recorder which records each stroke (between mouse down and mouse down) to an array which contains all strokes.</p> <p>For simplicity we listen here to mouse clicks when we alter mode. When in click mode we iterate the stroke collection and re-build the paths we previously recorded for then to check if our mouse position is in one of these lines.</p> <p>The code can be optimized by using a hit region before building paths to reduce overhead but for the sake of demo only the essential code is included:</p> <h1>Demo code</h1> <p><strong><a href="http://jsfiddle.net/AbdiasSoftware/zcpvg/" rel="nofollow noreferrer">ONLINE DEMO HERE</a></strong></p> <p>To record we need to have something to store the lines/strokes in:</p> <pre><code>var lines = [], line; </code></pre> <p>We add an event listener for clicks that we'll use when we switch mode. Note that normally you would share mousedown/up events perhaps instead:</p> <pre><code>canvas.addEventListener("click", checkLine, false); </code></pre> <p>To make the lines more "clickable" we use a thicker line width here (fixed for demo):</p> <pre><code>context.lineWidth = 3; </code></pre> <p>In order to record we need to modify the existing callbacks. There is also a bug in it which causes the line to be redrawn of top of each other for each mouse move which eventually will slow down the drawing if the line is long.</p> <p>We also need to adjust mouse positions so it becomes relative to canvas:</p> <pre><code>function startDraw(event) { /// if we are in "click" mode exit from here (for demo) if (mode.checked === true) return; /// adjust mouse position var pos = mouseXY(canvas, event); drawing = true; /// start a new path context.beginPath(); context.moveTo(pos.x, pos.y); /// create a new stroke and push first position to it line = []; line.push([pos.x, pos.y]); } </code></pre> <p>For each part we draw we need to reset path so we don't redraw the whole line (in your final render/redraw you would of course just redraw the line in one go, but not while drawing it):</p> <pre><code>function continueDraw(event) { if (drawing) { /// adjust mouse position var pos = mouseXY(canvas, event); /// complete one line segment started in mouse down context.lineTo(pos.x, pos.y); context.stroke(); /// reset path and start from where we ended this line context.beginPath(); context.moveTo(pos.x, pos.y); /// store current point to stroke/line line.push([pos.x, pos.y]); } } </code></pre> <p>And finally when line is finished we store our stroke:</p> <pre><code>function endDraw(event) { if (drawing) { var pos = mouseXY(canvas, event); context.lineTo(pos.x, pos.y); context.stroke(); drawing = false; /// push stroke/line to line stack lines.push(line); } } </code></pre> <p>We use this to adjust mouse position::</p> <pre><code>function mouseXY(c, e) { var r = c.getBoundingClientRect(); return {x: e.clientX - r.left, y: e.clientY - r.top}; } </code></pre> <h1>Checking line clicks</h1> <p>To check a line we need to iterate through our line collection and rebuild each line as a path. There is no need to draw these paths so the speed is OK. When a path is rebuilt we check the adjusted mouse position against the path by using <code>isPointInStroke</code>:</p> <pre><code>function checkLine(e) { if (mode.checked === false) return; var i = 0, line, l, p, pos = mouseXY(canvas, e); /// make sure stroke has same width as originally recorded context.lineWidth = 3; /// loop through line collection for(; line = lines[i]; i++) { /// reset path context.beginPath(); /// begin stroke context.moveTo(line[0][0], line[0][1]); /// iterate through each point stored for(l = 1; p = line[l]; l++) { /// add a line context.lineTo(p[0], p[1]); } /// then we check the point if (context.isPointInStroke(pos.x, pos.y) === true) { alert('hit line ' + i); /// show "ID" of line clicked return; } } } </code></pre> <p>Even complex overlapping lines can be detected with no problem:</p> <p><img src="https://i.stack.imgur.com/v10gO.png" alt="Demo snapshot"></p> <p>(Yes I know! I could beat Dali and Munch any day! X-p )</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload