Это решение работает с использованием преобразования матрицы для учета угла формы при изменении размера по высоте и ширине, в то время как функции cos и sin учитывают изменение координат, вызванное изменением ширины и высоты.
resizeRectangle = (e) => {
const {x, y, angle, width, height} = this.state
const point = this.svg.createSVGPoint()
point.x = e.clientX
point.y = e.clientY
const rotatedPoint = point.matrixTransform(
this.rect.getScreenCTM().inverse()
)
const widthDifference = rotatedPoint.x - width
const heightDifference = rotatedPoint.y - height
const widthOriginMovementRight = widthDifference * Math.cos(angle * Math.PI / 180)
const widthOriginMovementDown = widthDifference * Math.sin(angle * Math.PI / 180)
const heightOriginMovementRight = heightDifference * Math.cos((angle+90) * Math.PI / 180)
const heightOriginMovementDown = heightDifference * Math.sin((angle+90) * Math.PI / 180)
const sumMovementX = widthOriginMovementRight + heightOriginMovementRight - widthDifference
const sumMovementY = widthOriginMovementDown + heightOriginMovementDown - heightDifference
this.setState({
width: rotatedPoint.x,
height: rotatedPoint.y,
x: x + (sumMovementX /2) ,
y: y + (sumMovementY /2)
})
та же техника, используемая для нахождения повернутой точки, должна быть введена и в логику рендеринга
render() {
const {width, height, x, y, angle, focusedElement, start} = this.state
if (this.svg) {
const point = this.svg.createSVGPoint()
point.x = x
point.y = y
var rotatedPoint = point.matrixTransform(
this.rect.getScreenCTM().inverse()
)
}
и в операторе возврата
return (
<div>
<svg
ref={node => this.svg = node}
viewPort="0 0 300 300"
style={{width: 300, height: 300, backgroundColor: '#999'}}
onMouseUp={this.handleMouseUp}
onMouseMove={this.handleMouseMove}
onMouseDown={this.handleMouseDown}
>
<g
transform={
((!focusedElement && !!rotatedPoint) || focusedElement === 'resize') ?
`
translate(${x}, ${y})
rotate(${angle})
translate(${-rotatedPoint.x}, ${-rotatedPoint.y})
`
:
`
translate(${x}, ${y})
rotate(${angle}, ${(width / 2)}, ${(height / 2)})
`
}
ref={node => this.rect = node}
>