I am designing a visualization which begins with the user drawing points on the screen as shown here: https://jsfiddle.net/jtr13/j2yrknf3/25/
The relevant part of the code (inspired by this answer) is:
svg.on("mousedown", mousedown)
.on("mouseup", mouseup);
function mousedown() {
const new_x = xScale.invert(d3.pointer(event)[0]);
const new_y = yScale.invert(d3.pointer(event)[1]);
svg.append("circle")
.data([{x: new_x, y: new_y}])
.attr("cx", d => xScale(d.x))
.attr("cy", d => yScale(d.y))
.attr("r", "3");
svg.on("mousemove", mousemove);
}
function mousemove() {
const new_x = xScale.invert(d3.pointer(event)[0]);
const new_y = yScale.invert(d3.pointer(event)[1]);
svg.append("circle")
.data([{x: new_x, y: new_y}])
.attr("cx", d => xScale(d.x))
.attr("cy", d => yScale(d.y))
.attr("r", "3");
}
function mouseup() {
svg.on("mousemove", null);
}
The problem is that too many points are added during mousemove. I would like points to be added at about 1/5 or 1/10 of the current rate. I tried adding delays of various sorts and nothing worked. How can I slow down the drag behavior?
Throttle Function: Limits how often a function runs by making it wait a set time between calls.
Throttled Mousemove: Slows down how often the mousemove event runs, so it only triggers every 100 milliseconds. You can change the timing if you want it faster or slower.
// Throttle function to limit the rate at which the mousemove function is called
function throttle(func, delay) {
let lastCall = 0;
return function(...args) {
const now = new Date().getTime();
if (now - lastCall >= delay) {
lastCall = now;
return func(...args);
}
};
}
// Width and height
const w = 400;
const h = 350;
// Create scale functions
const xScale = d3.scaleLinear()
.domain([0, 4])
.range([0, w]);
const yScale = d3.scaleLinear()
.domain([0, 4])
.range([h, 0]);
// Define the SVG container
const svg = d3.select("div#plot")
.append("svg")
.attr("width", w)
.attr("height", h);
svg.append("rect")
.attr("x", "0")
.attr("y", "0")
.attr("width", w)
.attr("height", h)
.attr("fill", "lightblue");
// Add event listeners for mouse interactions
svg.on("mousedown", mousedown).on("mouseup", mouseup);
// Function for mousedown event
function mousedown() {
const new_x = xScale.invert(d3.pointer(event)[0]);
const new_y = yScale.invert(d3.pointer(event)[1]);
svg.append("circle")
.data([{ x: new_x, y: new_y }])
.attr("cx", d => xScale(d.x))
.attr("cy", d => yScale(d.y))
.attr("r", "3");
d3.select("h3#num").text("Number of points: " + d3.selectAll("circle").size());
svg.on("mousemove", throttledMousemove);
}
// Function for mousemove event with throttling
const throttledMousemove = throttle(function () {
const new_x = xScale.invert(d3.pointer(event)[0]);
const new_y = yScale.invert(d3.pointer(event)[1]);
svg.append("circle")
.data([{ x: new_x, y: new_y }])
.attr("cx", d => xScale(d.x))
.attr("cy", d => yScale(d.y))
.attr("r", "3");
d3.select("h3#num").text("Number of points: " + d3.selectAll("circle").size());
}, 100); // Adjust the delay to control the rate (e.g., 100 milliseconds)
// Function for mouseup event
function mouseup() {
svg.on("mousemove", null);
}
// Function to restart and clear all points
function restart() {
d3.selectAll("circle").remove();
d3.select("h3#num").text("Number of points: 0");
}
<h3 id="info">Click and drag to add points.</h3>
<h3 id="num">Number of points: 0</h3>
<button onclick="restart()">Restart</button>
<p></p>
<div id="plot"></div>
<script src="https://d3js.org/d3.v7.js"></script>