Files
igny8/frontend/node_modules/@svgdotjs/svg.select.js/src/SelectHandler.js
2025-11-09 10:27:02 +00:00

167 lines
4.6 KiB
JavaScript

import { G, getWindow } from '@svgdotjs/svg.js'
import { getMoseDownFunc, transformPoint } from './utils'
export class SelectHandler {
constructor(el) {
this.el = el
el.remember('_selectHandler', this)
this.selection = new G()
this.order = ['lt', 't', 'rt', 'r', 'rb', 'b', 'lb', 'l', 'rot']
this.mutationHandler = this.mutationHandler.bind(this)
const win = getWindow()
this.observer = new win.MutationObserver(this.mutationHandler)
}
init(options) {
this.createHandle = options.createHandle || this.createHandleFn
this.createRot = options.createRot || this.createRotFn
this.updateHandle = options.updateHandle || this.updateHandleFn
this.updateRot = options.updateRot || this.updateRotFn
// mount group
this.el.root().put(this.selection)
this.updatePoints()
this.createSelection()
this.createResizeHandles()
this.updateResizeHandles()
this.createRotationHandle()
this.updateRotationHandle()
this.observer.observe(this.el.node, { attributes: true })
}
active(val, options) {
// Disable selection
if (!val) {
this.selection.clear().remove()
this.observer.disconnect()
return
}
// Enable selection
this.init(options)
}
createSelection() {
this.selection.polygon(this.handlePoints).addClass('svg_select_shape')
}
updateSelection() {
this.selection.get(0).plot(this.handlePoints)
}
createResizeHandles() {
this.handlePoints.forEach((p, index, arr) => {
const name = this.order[index]
this.createHandle.call(this, this.selection, p, index, arr, name)
this.selection
.get(index + 1)
.addClass('svg_select_handle svg_select_handle_' + name)
.on('mousedown.selection touchstart.selection', getMoseDownFunc(name, this.el, this.handlePoints, index))
})
}
createHandleFn(group) {
group.polyline()
}
updateHandleFn(shape, point, index, arr) {
const before = arr.at(index - 1)
const next = arr[(index + 1) % arr.length]
const p = point
const diff1 = [p[0] - before[0], p[1] - before[1]]
const diff2 = [p[0] - next[0], p[1] - next[1]]
const len1 = Math.sqrt(diff1[0] * diff1[0] + diff1[1] * diff1[1])
const len2 = Math.sqrt(diff2[0] * diff2[0] + diff2[1] * diff2[1])
const normalized1 = [diff1[0] / len1, diff1[1] / len1]
const normalized2 = [diff2[0] / len2, diff2[1] / len2]
const beforeNew = [p[0] - normalized1[0] * 10, p[1] - normalized1[1] * 10]
const nextNew = [p[0] - normalized2[0] * 10, p[1] - normalized2[1] * 10]
shape.plot([beforeNew, p, nextNew])
}
updateResizeHandles() {
this.handlePoints.forEach((p, index, arr) => {
const name = this.order[index]
this.updateHandle.call(this, this.selection.get(index + 1), p, index, arr, name)
})
}
createRotFn(group) {
group.line()
group.circle(5)
}
getPoint(name) {
return this.handlePoints[this.order.indexOf(name)]
}
getPointHandle(name) {
return this.selection.get(this.order.indexOf(name) + 1)
}
updateRotFn(group, rotPoint) {
const topPoint = this.getPoint('t')
group.get(0).plot(topPoint[0], topPoint[1], rotPoint[0], rotPoint[1])
group.get(1).center(rotPoint[0], rotPoint[1])
}
createRotationHandle() {
const handle = this.selection
.group()
.addClass('svg_select_handle_rot')
.on('mousedown.selection touchstart.selection', getMoseDownFunc('rot', this.el, this.handlePoints))
this.createRot.call(this, handle)
}
updateRotationHandle() {
const group = this.selection.findOne('g.svg_select_handle_rot')
this.updateRot(group, this.rotationPoint, this.handlePoints)
}
// gets new bounding box points and transform them into the elements space
updatePoints() {
const bbox = this.el.bbox()
const fromShapeToUiMatrix = this.el.root().screenCTM().inverseO().multiplyO(this.el.screenCTM())
this.handlePoints = this.getHandlePoints(bbox).map((p) => transformPoint(p, fromShapeToUiMatrix))
this.rotationPoint = transformPoint(this.getRotationPoint(bbox), fromShapeToUiMatrix)
}
// A collection of all the points we need to draw our ui
getHandlePoints({ x, x2, y, y2, cx, cy } = this.el.bbox()) {
return [
[x, y],
[cx, y],
[x2, y],
[x2, cy],
[x2, y2],
[cx, y2],
[x, y2],
[x, cy],
]
}
// A collection of all the points we need to draw our ui
getRotationPoint({ y, cx } = this.el.bbox()) {
return [cx, y - 20]
}
mutationHandler() {
this.updatePoints()
this.updateSelection()
this.updateResizeHandles()
this.updateRotationHandle()
}
}