在画布上单击一下,我试图创建一个矩形。按住点击时,其大小应根据指针的坐标进行更改。当左上角保持静止时,宽度和高度会改变。
矩形从左到右改变其形状,但是我也希望它在当前x值变得小于固定点的x值时从右向左移动。有人可以帮我解决这个问题吗?我该如何实现?非常感谢!
const margin = {top: 10, right: 30, bottom: 100, left: 60},
chartWidth = width - margin.left - margin.right,
chartHeight = height - margin.top - margin.bottom;
let shouldAppear = false;
const svg = d3.select('svg')
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform","translate(" + left + "," + top + ")");
svg.append('rect')
.attr('class', 'canvas')
.attr('width', chartWidth)
.attr('height', chartHeight)
svg.on('mousedown', function(){
shouldAppear = true;
const mouse = d3.mouse(this);
rectangle.attr('y', mouse[1])
.attr('x', mouse[0])
})
svg.on('mousemove', function(){
const mouse = d3.mouse(this);
if (shouldAppear){
rectangle
.attr('width', Math.abs(mouse[0] - rectangle.attr('x')))
.attr('height', Math.abs(mouse[1] - rectangle.attr('y')))
}
})
svg.on('mouseup', function(){
shouldAppear = false;
rectangle
.attr('width', 0)
.attr('height', 0)
});
let rectangle = svg
.append('rect')
.attr('class', 'rectangle')
.attr('width', 0)
.attr('height', 0)
.style('fill','red')
}
问题是,当指针移到起点的左侧或顶部时,宽度和高度的计算将变为负数,而svg不允许width
元素的height
或rect
元素的值为负。] >
一种解决方案是将鼠标在mousedown
功能中的起始位置保存为mousestart
:
let mousestart; svg.on("mousedown", function () { shouldAppear = true; const mouse = d3.mouse(this); mousestart = mouse; rectangle.attr("y", mouse[1]).attr("x", mouse[0]); });
然后使用
mousestart
位置评估光标是在起始位置的左侧,右侧,顶部还是底部,并分别在mousemove
函数中根据需要为矩形创建特定的调整。
svg.on("mousemove", function () { const mouse = d3.mouse(this); if (shouldAppear) { let x = mouse[0] - mousestart[0]; //negative values indicate cursor moved left let y = mouse[1] - mousestart[1]; //negative values indicate cursor moved up if (x >= 0 && y >= 0) { // if the cursor moved right and down from starting position rectangle .attr("width", Math.abs(mouse[0] - rectangle.attr("x"))) .attr("height", Math.abs(mouse[1] - rectangle.attr("y"))); } if (x <= 0){ // if the cursor moved left rectangle .attr('x', mouse[0]) // move the rectangle to the new cursor x position .attr('width', mousestart[0] - mouse[0] ) // the width of the rectangle is now the difference between the starting point and current x point .attr("height", Math.abs(mouse[1] - rectangle.attr("y"))); // the height is calculated based on the difference between the current position and the rectangle y } if (y <= 0) { // if the cursor moved up similar calculations as above but in the y direction rectangle .attr('y', mouse[1]) .attr('height', mousestart[1] - mouse[1] ) .attr("width", Math.abs(mouse[0] - rectangle.attr("x"))); } if (x <= 0 && y <= 0 ) { // if the cursor moved left and up similar calculations as above but in both x and y direction rectangle .attr('x', mouse[0]) .attr('y', mouse[1]) .attr('width', mousestart[0] - mouse[0] ) .attr('height', mousestart[1] - mouse[1] ) } } });
检查完整的代码段:
let width = 400, height = 400; const margin = { top: 10, right: 30, bottom: 100, left: 60 }, chartWidth = width - margin.left - margin.right, chartHeight = height - margin.top - margin.bottom; let shouldAppear = false; const svg = d3 .select("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); svg .append("rect") .attr("class", "canvas") .attr("width", chartWidth) .attr("height", chartHeight - 10); let mousestart; svg.on("mousedown", function () { shouldAppear = true; const mouse = d3.mouse(this); mousestart = mouse; rectangle.attr("y", mouse[1]).attr("x", mouse[0]); }); svg.on("mousemove", function () { const mouse = d3.mouse(this); if (shouldAppear) { let x = mouse[0] - mousestart[0]; //negative values indicate cursor moved left let y = mouse[1] - mousestart[1]; //negative values indicate cursor moved up if (x >= 0 && y >= 0) { // if the cursor moved right and down from starting position rectangle .attr("width", Math.abs(mouse[0] - rectangle.attr("x"))) .attr("height", Math.abs(mouse[1] - rectangle.attr("y"))); } if (x <= 0){ // if the cursor moved left rectangle .attr('x', mouse[0]) // move the rectangle to the new cursor x position .attr('width', mousestart[0] - mouse[0] ) // the width of the rectangle is now the difference between the starting point and current x point .attr("height", Math.abs(mouse[1] - rectangle.attr("y"))); // the height is calculated based on the difference between the current position and the rectangle y } if (y <= 0) { // if the cursor moved up similar calculations as above but in the y direction rectangle .attr('y', mouse[1]) .attr('height', mousestart[1] - mouse[1] ) .attr("width", Math.abs(mouse[0] - rectangle.attr("x"))); } if (x <= 0 && y <= 0 ) { // if the cursor moved left and up similar calculations as above but in both x and y direction rectangle .attr('x', mouse[0]) .attr('y', mouse[1]) .attr('width', mousestart[0] - mouse[0] ) .attr('height', mousestart[1] - mouse[1] ) } } }); svg.on("mouseup", function () { shouldAppear = false; rectangle.attr("width", 0).attr("height", 0); }); let rectangle = svg .append("rect") .attr("class", "rectangle") .attr("width", 0) .attr("height", 0) .style("fill", "red");
<script src="https://d3js.org/d3.v5.min.js"></script> <svg></svg>
更新
mousemove
功能的改进,易于阅读,它计算了rect
元素的属性rectx
,recty
,rectwidth
,rectheight
,并使用它来设置属性。注意,您仍然需要在mousestart
功能中捕获mousedown
坐标,如上所示。:
svg.on("mousemove", function () { const mouse = d3.mouse(this); if (shouldAppear) { let rectx, recty, rectwidth, rectheight; if (mouse[0] < mousestart[0]) { // if cursor moved left rectx = mouse[0]; rectwidth = mousestart[0] - mouse[0]; } else { // if cursor moved right rectx = mousestart[0]; rectwidth = mouse[0] - mousestart[0]; } if (mouse[1] < mousestart[1]) { // if cursor moved up recty = mouse[1]; rectheight = mousestart[1] - mouse[1]; } else { // if cursor moved down recty = mousestart[1]; rectheight = mouse[1] - mousestart[1]; } rectangle .attr('x', rectx) .attr('y', recty) .attr('width', rectwidth) .attr('height', rectheight) } });
查看完整摘要:
let width = 400, height = 400; const margin = { top: 10, right: 30, bottom: 100, left: 60 }, chartWidth = width - margin.left - margin.right, chartHeight = height - margin.top - margin.bottom; let shouldAppear = false; const svg = d3 .select("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); svg .append("rect") .attr("class", "canvas") .attr("width", chartWidth) .attr("height", chartHeight - 10); let mousestart; svg.on("mousedown", function () { shouldAppear = true; const mouse = d3.mouse(this); mousestart = mouse; rectangle.attr("y", mouse[1]).attr("x", mouse[0]); }); svg.on("mousemove", function () { const mouse = d3.mouse(this); if (shouldAppear) { let rectx, recty, rectwidth, rectheight; if (mouse[0] < mousestart[0]) { // if cursor moved left rectx = mouse[0]; rectwidth = mousestart[0] - mouse[0]; } else { // if cursor moved right rectx = mousestart[0]; rectwidth = mouse[0] - mousestart[0]; } if (mouse[1] < mousestart[1]) { // if cursor moved up recty = mouse[1]; rectheight = mousestart[1] - mouse[1]; } else { // if cursor moved down recty = mousestart[1]; rectheight = mouse[1] - mousestart[1]; } rectangle .attr('x', rectx) .attr('y', recty) .attr('width', rectwidth) .attr('height', rectheight) } }); svg.on("mouseup", function () { shouldAppear = false; rectangle.attr("width", 0).attr("height", 0); }); let rectangle = svg .append("rect") .attr("class", "rectangle") .attr("width", 0) .attr("height", 0) .style("fill", "red");
<script src="https://d3js.org/d3.v5.min.js"></script> <svg></svg>