Skip to content

Instantly share code, notes, and snippets.

@tomgp
Last active October 7, 2022 01:37
Show Gist options
  • Save tomgp/18a6adf32aeafd1f6cc706ec4478e2a8 to your computer and use it in GitHub Desktop.
Save tomgp/18a6adf32aeafd1f6cc706ec4478e2a8 to your computer and use it in GitHub Desktop.
2d Slider
<html>
<head>
<style>
body{
font-family: sans-serif;
}
svg{
border: 1px solid black;
cursor: move;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js">
</script>
</head>
<body>
<h1>2D slider</h1>
<svg width="300" height="300">
</svg>
<p>
values: [<span id="valueX">0</span>, <span id="valueY">0</span>]
</p>
</body>
<script>
function main(){
const xScale = d3.scaleLinear()
.domain([-5 , 5])
.range([0, 300]);
const yScale = d3.scaleLinear()
.domain([-5 , 5])
.range([0, 300]);
const mySlider = makeSlider(xScale, yScale, {snapToInteger: true});
mySlider.event.on('change', function(a){
const join = d3.select('svg')
.selectAll('.handle')
.data([this]);
join.enter()
.append('circle')
.style('pointer-events', 'none')
.attr('class', d=>'handle')
.attr('r', 20)
.attr('cx', d=>d.x)
.attr('cy', d=>d.y);
join
.attr('cx', d=>d.x)
.attr('cy', d=>d.y);
d3.select('#valueX')
.text(this.valueX);
d3.select('#valueY')
.text(this.valueY);
})
d3.select('svg')
.call(mySlider);
}
const makeSlider = (xScale, yScale, options) => {
let dragging = false;
const slider = (parent)=>{
parent.append('rect')
.attr('x', xScale.range()[0])
.attr('y', yScale.range()[0])
.attr('width', xScale.range()[1] - xScale.range()[0])
.attr('height', yScale.range()[1] - yScale.range()[0])
.attr('fill-opacity', 0.1);
parent.on('mousedown', function(){
dragging = true;
dispatchLocation(d3.mouse(this));
})
parent.on('mousemove', function(){
if(dragging){
dispatchLocation(d3.mouse(this));
}
});
parent.on('mouseout',function(){
dragging = false;
});
parent.on('mouseup', function(){
dragging = false;
dispatchLocation(d3.mouse(this), true);
})
};
slider.event = d3.dispatch("change");
function dispatchLocation(position, snap = false) {
let valueX = xScale.invert(position[0]);
let valueY = yScale.invert(position[1]);
if (options.snapToInteger){
valueY = Math.round(valueY);
valueX = Math.round(valueX);
};
if(snap){
position[0] = xScale(valueX);
position[1] = yScale(valueY);
}
slider.event.call('change', {
x: position[0],
y: position[1],
valueX,
valueY,
});
}
return slider;
}
window.onload = main;
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment