{
const width = 200;
const height = 200;
const radius = 10;
let tooltip = d3.select('body').select('.tooltip');
if (tooltip.empty()) {
tooltip = d3.select('body')
.append('div')
.attr('class', 'tooltip')
.style('position', 'absolute')
.style('background', 'rgba(0, 0, 0, 0.7)')
.style('color', 'white')
.style('padding', '5px')
.style('border-radius', '3px')
.style('pointer-events', 'none')
.style('opacity', 0);
}
const svg = d3.create('svg')
.attr('width', width)
.attr('height', height)
.style('overflow', 'hidden')
.style('display', 'block')
.style('touch-action', 'none');
svg.append('rect')
.attr('width', 200)
.attr('height', 200)
.attr('fill', '#F2ECF3');
const circles = svg.selectAll('circle')
.data(circlesData)
.join('circle')
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.attr('fill', d => d.color)
.attr('r', radius);
function circleDrag(width, height, radius) {
let startX, startY, startDX, startDY;
function onDragStart(event, d) {
startX = d.x;
startY = d.y;
startDX = event.x - d.x;
startDY = event.y - d.y;
d3.select(this)
.raise()
.attr('fill', 'yellow')
.attr('stroke', 'black');
tooltip
.style('opacity', 1)
.html(`x: ${Math.round(d.x)}, y: ${Math.round(d.y)}`)
.style('left', (event.sourceEvent.pageX + 10) + 'px')
.style('top', (event.sourceEvent.pageY - 30) + 'px');
}
function onDrag(event, d) {
const newX = Math.max(radius, Math.min(width - radius, event.x));
const newY = Math.max(radius, Math.min(height - radius, event.y));
const atBoundaryX = newX !== event.x - startDX + startX;
const atBoundaryY = newY !== event.y - startDY + startY;
d3.select(this)
.attr('cx', d.x = newX)
.attr('cy', d.y = newY);
tooltip
.html(`x: ${Math.round(newX)}, y: ${Math.round(newY)}`)
.style('left', (event.sourceEvent.pageX + 10) + 'px')
.style('top', (event.sourceEvent.pageY - 30) + 'px');
if (atBoundaryX || atBoundaryY){
startDX = event.x - newX;
startDY = event.y - newY;
}
}
function onDragEnd(event, d) {
d3.select(this)
.attr('fill', d.color)
.attr('stroke', 'none');
tooltip.style('opacity', 0);
}
const drag = d3.drag()
.on('start', onDragStart)
.on('drag', onDrag)
.on('end', onDragEnd);
return drag;
}
circles.call(circleDrag(width, height, radius));
return svg.node();
}