Scanning to find the closest point on canvas.
<!DOCTYPE html>
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="style.css">
<div id='graph'></div>
<script src='d3_.js'></script>
<script type="text/javascript">
var ttSel = d3.select('body').selectAppend('div.tooltip.tooltip-hidden')
var sel = d3.select('#graph').html('')
var c = d3.conventions({
sel,
margin: {left: 30},
layers: 'cs',
})
var [ctx, svg] = c.layers
d3.drawAxis(c)
var colorScale = d3.scaleLinear().range(['#f0f', '#0f0'])
var data = d3.range(500000).map(() => {
var r = Math.random()
var px = c.x(r)
var py = c.y(Math.random())
var color = colorScale(r + Math.random()/5)
ctx.fillStyle = color
ctx.fillRect(px, py, 1, 1)
return {px, py, color}
})
var highlightCircle = svg.append('circle')
.at({r: 10, fill: 'none'})
.st({pointerEvents: 'none'})
svg.append('rect')
.at({width: c.width, height: c.height, fillOpacity: 0})
.call(d3.attachTooltip)
.on('mousemove', function(){
var [px, py] = d3.mouse(this)
var startT = new Date()
var m = _.minBy(data, d => {
var dx = d.px - px
var dy = d.py - py
return dx*dx + dy*dy
})
ttSel.text(m.color + ' found in ' + (new Date() - startT) + 'ms')
highlightCircle
.translate([m.px, m.py])
.at({stroke: m.color, strokeWidth: 4})
})
.on('mouseout', function(){
highlightCircle.at({strokeWidth: 0})
})
</script>
body{
font-family: menlo, Consolas, 'Lucida Console', monospace;
margin: 0px;
}
.tooltip {
top: -1000px;
position: fixed;
padding: 10px;
background: rgba(255, 255, 255, .90);
border: 1px solid lightgray;
pointer-events: none;
}
.tooltip-hidden{
opacity: 0;
transition: all .3s;
transition-delay: .1s;
}
@media (max-width: 590px){
div.tooltip{
bottom: -1px;
width: calc(100%);
left: -1px !important;
right: -1px !important;
top: auto !important;
width: auto !important;
}
}
svg{
overflow: visible;
}
.domain{
display: none;
}
text{
pointer-events: none;
text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
}