我怎样才能(在 D3 中)让一个矩形改变它的大小,同时保持固定在一个点上?
How can I (in D3) make a rectangle change its size while staying fix in one point?
单击 canvas 我正在尝试创建一个矩形。按住单击时,其大小应根据指针的坐标发生变化。左上角保持不变,宽度和高度发生变化。
矩形从左到右改变它的形式,但我也希望它在当前 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
并用它来设置属性。请注意,您仍然需要在 mousedown
函数中捕获 mousestart
坐标,如上所示。:
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>
单击 canvas 我正在尝试创建一个矩形。按住单击时,其大小应根据指针的坐标发生变化。左上角保持不变,宽度和高度发生变化。
矩形从左到右改变它的形式,但我也希望它在当前 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
并用它来设置属性。请注意,您仍然需要在 mousedown
函数中捕获 mousestart
坐标,如上所示。:
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>