使interact.js可调整大小的像素完美 [英] Making interact.js resizable pixel perfect
问题描述
在此 jsFiddle 中,我有一个可以使用interact.js
调整大小的SVG矩形.还有一个10px x 10px的网格,.resizable
函数包含一个10px x 10 px的捕捉.目的是调整矩形大小,并使边缘完全对齐到网格上.
In this jsFiddle I have an SVG rect that is resizable using interact.js
. There's also a 10px by 10px grid and the .resizable
function has included a 10px by 10 px snap. The objective is to resize the rect and have the edges snap exactly on the grid.
在大多数情况下,它可以正常工作,但很多时候却不能,如下图所示.也许需要在resizeend
上手动进行调整?如何解决此问题?
In most cases it works fine, but many times it is not, as you can see in the picture below. Maybe an adjustment needs to be done manually on resizeend
? How to fix this problem?
推荐答案
如Erik所说:
使用此target.setAttribute(attr/a, Math.round(v/10)*10)
似乎有效:
.on('resizemove', function(event) {
// Resize the rect, not the group, it will resize automatically
const target = event.target.querySelector('rect');
for (const attr of ['width', 'height']) {
let v = Number(target.getAttribute(attr));
v += event.deltaRect[attr];
target.setAttribute(attr, Math.round(v/10)*10);
}
for (const attr of ['top', 'left']) {
const a = attr == 'left' ? 'x' : 'y';
let v = Number(target.getAttribute(a));
v += event.deltaRect[attr];
target.setAttribute(a, Math.round(v/10)*10);
}
findLocations(rect, handles);
});
此处提供完整演示- https://jsfiddle.net/alexander_L/1mzs36qL/3/及以下:
Full Demo here - https://jsfiddle.net/alexander_L/1mzs36qL/3/ and below:
const svg = document.getElementById('mysvg');
const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
// draw vertical lines
var gridSize = 10;
for (var i=0;i < 100;i++){
var line = document.createElementNS("http://www.w3.org/2000/svg", "line");
svg.appendChild(line);
line.setAttribute("x1", (i + 1) * gridSize)
line.setAttribute("y1", 0)
line.setAttribute("x2", (i + 1) * gridSize)
line.setAttribute("y2", 500)
line.setAttribute("stroke-width", 1)
line.setAttribute("stroke", 'gray');
}
// draw horizontal lines
for (var i=0;i < 100;i++){
var line = document.createElementNS("http://www.w3.org/2000/svg", "line");
svg.appendChild(line);
line.setAttribute("x1", 0)
line.setAttribute("y1", (i + 1) * gridSize)
line.setAttribute("x2", 2000)
line.setAttribute("y2", (i + 1) * gridSize)
line.setAttribute("stroke-width", 1)
line.setAttribute("stroke", 'gray');
}
svg.appendChild(group);
group.appendChild(rect);
group.setAttribute('class', 'resize-me');
rect.setAttribute('x', 100);
rect.setAttribute('y', 100);
rect.setAttribute('width', 100);
rect.setAttribute('height', 100);
rect.setAttribute('stroke-width', 1);
rect.setAttribute('stroke', 'white');
rect.setAttribute('fill', 'grey');
// Create the handles
const handles = [];
for (let i = 0; i < 8; i++) {
const handle = document.createElementNS("http://www.w3.org/2000/svg", "rect");
handle.setAttribute('width', 8);
handle.setAttribute('height', 8);
handle.setAttribute('stroke-width', 1);
handle.setAttribute('stroke', 'white');
handle.setAttribute('fill', 'black');
handles.push(handle);
group.appendChild(handle);
}
// Manually assign them their resize duties (R->L, T->B)
handles[0].classList.add('resize-top', 'resize-left');
handles[1].classList.add('resize-top');
handles[2].classList.add('resize-top', 'resize-right');
handles[3].classList.add('resize-left');
handles[4].classList.add('resize-right');
handles[5].classList.add('resize-bottom', 'resize-left');
handles[6].classList.add('resize-bottom');
handles[7].classList.add('resize-bottom', 'resize-right');
// This function takes the rect and the list of handles and positions
// the handles accordingly
const findLocations = (r, h) => {
const x = Number(r.getAttribute('x'));
const y = Number(r.getAttribute('y'));
const width = Number(r.getAttribute('width'));
const height = Number(r.getAttribute('height'));
// Important these are in the same order as the classes above
let locations = [
[0, 0],
[width / 2, 0],
[width, 0],
[0, height / 2],
[width, height / 2],
[0, height],
[width / 2, height],
[width, height]
];
// Move each location such that it's relative to the (x,y) of the rect,
// and also subtract half the width of the handles to make up for their
// own size.
locations = locations.map(subarr => [
subarr[0] + x - 4,
subarr[1] + y - 4
]);
for (let i = 0; i < locations.length; i++) {
h[i].setAttribute('x', locations[i][0]);
h[i].setAttribute('y', locations[i][1]);
}
}
interact('.resize-me')
.resizable({
edges: {
left: '.resize-left',
right: '.resize-right',
bottom: '.resize-bottom',
top: '.resize-top'
},
modifiers: [
interact.modifiers.snap({
targets: [
interact.snappers.grid({
x: 10,
y: 10,
})
]
})
]
})
.on('resizemove', function(event) {
// Resize the rect, not the group, it will resize automatically
const target = event.target.querySelector('rect');
for (const attr of ['width', 'height']) {
let v = Number(target.getAttribute(attr));
v += event.deltaRect[attr];
target.setAttribute(attr, Math.round(v/10)*10);
}
for (const attr of ['top', 'left']) {
const a = attr == 'left' ? 'x' : 'y';
let v = Number(target.getAttribute(a));
v += event.deltaRect[attr];
target.setAttribute(a, Math.round(v/10)*10);
}
findLocations(rect, handles);
});
findLocations(rect, handles);
svg {
width: 100%;
height: 240px;
background-color: #2e9;
-ms-touch-action: none;
touch-action: none;
}
body { margin: 0; }
<script src="https://cdn.jsdelivr.net/npm/interactjs@latest/dist/interact.min.js"></script>
<svg id="mysvg"></svg>
这篇关于使interact.js可调整大小的像素完美的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!