mirror of
https://github.com/barsdeveloper/ueblueprint.git
synced 2026-02-16 10:54:42 +08:00
Selection fixed, SimpleSelectionModel added
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import OrderedIndexArray from "./OrderedIndexArray.js"
|
import OrderedIndexArray from "./OrderedIndexArray.js"
|
||||||
|
|
||||||
export default class SelectionModel {
|
export default class FastSelectionModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
@@ -31,6 +31,8 @@ export default class SelectionModel {
|
|||||||
this.secondaryOrder = new OrderedIndexArray((element) => this.metadata[element].secondaryBoundary)
|
this.secondaryOrder = new OrderedIndexArray((element) => this.metadata[element].secondaryBoundary)
|
||||||
this.selectToggleFunction = selectToggleFunction
|
this.selectToggleFunction = selectToggleFunction
|
||||||
this.rectangles = rectangles
|
this.rectangles = rectangles
|
||||||
|
this.primaryOrder.reserve(this.rectangles.length)
|
||||||
|
this.secondaryOrder.reserve(this.rectangles.length)
|
||||||
rectangles.forEach((rect, index) => {
|
rectangles.forEach((rect, index) => {
|
||||||
/** @type Metadata */
|
/** @type Metadata */
|
||||||
let rectangleMetadata = {
|
let rectangleMetadata = {
|
||||||
@@ -42,6 +44,16 @@ export default class SelectionModel {
|
|||||||
this.metadata[index] = rectangleMetadata
|
this.metadata[index] = rectangleMetadata
|
||||||
selectToggleFunction(rect, false) // Initially deselected (Eventually)
|
selectToggleFunction(rect, false) // Initially deselected (Eventually)
|
||||||
const rectangleBoundaries = boundariesFunc(rect)
|
const rectangleBoundaries = boundariesFunc(rect)
|
||||||
|
|
||||||
|
// Secondary axis first because it may be inserted in this.secondaryOrder during the primary axis check
|
||||||
|
if (this.initialPosition[1] < rectangleBoundaries.secondaryInf) { // Initial position is before the rectangle
|
||||||
|
rectangleMetadata.secondaryBoundary = rectangleBoundaries.secondaryInf
|
||||||
|
} else if (rectangleBoundaries.secondarySup < this.initialPosition[1]) { // Initial position is after the rectangle
|
||||||
|
rectangleMetadata.secondaryBoundary = rectangleBoundaries.secondarySup
|
||||||
|
} else {
|
||||||
|
rectangleMetadata.onSecondaryAxis = true
|
||||||
|
}
|
||||||
|
|
||||||
if (this.initialPosition[0] < rectangleBoundaries.primaryInf) { // Initial position is before the rectangle
|
if (this.initialPosition[0] < rectangleBoundaries.primaryInf) { // Initial position is before the rectangle
|
||||||
rectangleMetadata.primaryBoundary = rectangleBoundaries.primaryInf
|
rectangleMetadata.primaryBoundary = rectangleBoundaries.primaryInf
|
||||||
this.primaryOrder.insert(index)
|
this.primaryOrder.insert(index)
|
||||||
@@ -56,13 +68,6 @@ export default class SelectionModel {
|
|||||||
selectToggleFunction(rect, true)
|
selectToggleFunction(rect, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.initialPosition[1] < rectangleBoundaries.secondaryInf) { // Initial position is before the rectangle
|
|
||||||
rectangleMetadata.secondaryBoundary = rectangleBoundaries.secondaryInf
|
|
||||||
} else if (rectangleBoundaries.secondarySup < this.initialPosition[1]) { // Initial position is after the rectangle
|
|
||||||
rectangleMetadata.secondaryBoundary = rectangleBoundaries.secondarySup
|
|
||||||
} else {
|
|
||||||
rectangleMetadata.onSecondaryAxis = true
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
this.primaryOrder.currentPosition = this.primaryOrder.getPosition(this.initialPosition[0])
|
this.primaryOrder.currentPosition = this.primaryOrder.getPosition(this.initialPosition[0])
|
||||||
this.secondaryOrder.currentPosition = this.secondaryOrder.getPosition(this.initialPosition[1])
|
this.secondaryOrder.currentPosition = this.secondaryOrder.getPosition(this.initialPosition[1])
|
||||||
@@ -98,12 +103,11 @@ export default class SelectionModel {
|
|||||||
Math.sign(finalPosition[0] - this.initialPosition[0]),
|
Math.sign(finalPosition[0] - this.initialPosition[0]),
|
||||||
Math.sign(finalPosition[1] - this.initialPosition[1])
|
Math.sign(finalPosition[1] - this.initialPosition[1])
|
||||||
]
|
]
|
||||||
const primaryBoundaryCrossed = (index, expanding) => {
|
const primaryBoundaryCrossed = (index, added) => {
|
||||||
this.primaryOrder.currentPosition += direction[0] * (expanding ? 1 : -1)
|
|
||||||
if (this.metadata[index].onSecondaryAxis) {
|
if (this.metadata[index].onSecondaryAxis) {
|
||||||
this.selectToggleFunction(this.rectangles[index], expanding)
|
this.selectToggleFunction(this.rectangles[index], added)
|
||||||
} else {
|
} else {
|
||||||
if (expanding) {
|
if (added) {
|
||||||
this.secondaryOrder.insert(index, finalPosition[1])
|
this.secondaryOrder.insert(index, finalPosition[1])
|
||||||
const secondaryBoundary = this.metadata[index].secondaryBoundary
|
const secondaryBoundary = this.metadata[index].secondaryBoundary
|
||||||
if (
|
if (
|
||||||
@@ -125,23 +129,34 @@ export default class SelectionModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (finalPosition[0] < this.boundaries.primaryN.value) {
|
if (finalPosition[0] < this.boundaries.primaryN.value) {
|
||||||
primaryBoundaryCrossed(this.boundaries.primaryN.index, finalPosition[0] < this.initialPosition[0])
|
--this.primaryOrder.currentPosition
|
||||||
|
primaryBoundaryCrossed(
|
||||||
|
this.boundaries.primaryN.index,
|
||||||
|
this.initialPosition[0] > this.boundaries.primaryN.value && finalPosition[0] < this.initialPosition[0])
|
||||||
} else if (finalPosition[0] > this.boundaries.primaryP.value) {
|
} else if (finalPosition[0] > this.boundaries.primaryP.value) {
|
||||||
primaryBoundaryCrossed(this.boundaries.primaryP.index, this.initialPosition[0] < finalPosition[0])
|
++this.primaryOrder.currentPosition
|
||||||
|
primaryBoundaryCrossed(
|
||||||
|
this.boundaries.primaryP.index,
|
||||||
|
this.initialPosition[0] < this.boundaries.primaryP.value && this.initialPosition[0] < finalPosition[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const secondaryBoundaryCrossed = (index, expanding) => {
|
const secondaryBoundaryCrossed = (index, added) => {
|
||||||
this.secondaryOrder.currentPosition += direction[1] * (expanding ? 1 : -1)
|
this.selectToggleFunction(this.rectangles[index], added)
|
||||||
this.selectToggleFunction(this.rectangles[index], expanding)
|
|
||||||
this.computeBoundaries(finalPosition)
|
this.computeBoundaries(finalPosition)
|
||||||
this.selectTo(finalPosition)
|
this.selectTo(finalPosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (finalPosition[1] < this.boundaries.secondaryN.value) {
|
if (finalPosition[1] < this.boundaries.secondaryN.value) {
|
||||||
secondaryBoundaryCrossed(this.boundaries.secondaryN.index, finalPosition[1] < this.initialPosition[1]);
|
--this.secondaryOrder.currentPosition
|
||||||
|
secondaryBoundaryCrossed(
|
||||||
|
this.boundaries.secondaryN.index,
|
||||||
|
this.initialPosition[1] > this.boundaries.secondaryN.value && finalPosition[1] < this.initialPosition[1]);
|
||||||
} else if (finalPosition[1] > this.boundaries.secondaryP.value) {
|
} else if (finalPosition[1] > this.boundaries.secondaryP.value) {
|
||||||
secondaryBoundaryCrossed(this.boundaries.secondaryP.index, this.initialPosition[1] < finalPosition[1]);
|
++this.secondaryOrder.currentPosition
|
||||||
|
secondaryBoundaryCrossed(
|
||||||
|
this.boundaries.secondaryP.index,
|
||||||
|
this.initialPosition[1] < this.boundaries.secondaryP.value && this.initialPosition[1] < finalPosition[1]);
|
||||||
}
|
}
|
||||||
this.finalPosition = finalPosition
|
this.finalPosition = finalPosition
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,10 @@ export default class OrderedIndexArray {
|
|||||||
* @returns The element of the array
|
* @returns The element of the array
|
||||||
*/
|
*/
|
||||||
get(index) {
|
get(index) {
|
||||||
return this.array[index]
|
if (index >= 0 && index < this.length) {
|
||||||
|
return this.array[index]
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,7 +38,7 @@ export default class OrderedIndexArray {
|
|||||||
*/
|
*/
|
||||||
getPosition(value) {
|
getPosition(value) {
|
||||||
let l = 0
|
let l = 0
|
||||||
let r = this.array.length
|
let r = this.length
|
||||||
while (l < r) {
|
while (l < r) {
|
||||||
let m = Math.floor((l + r) / 2)
|
let m = Math.floor((l + r) / 2)
|
||||||
if (this.comparisonValueSupplier(this.array[m]) < value) {
|
if (this.comparisonValueSupplier(this.array[m]) < value) {
|
||||||
@@ -47,24 +50,46 @@ export default class OrderedIndexArray {
|
|||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reserve(length) {
|
||||||
|
if (this.array.length < length) {
|
||||||
|
let newArray = new Uint32Array(length)
|
||||||
|
newArray.set(this.array)
|
||||||
|
this.array = newArray
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts the element in the array.
|
* Inserts the element in the array.
|
||||||
* @param element {number} The value to insert into the array.
|
* @param element {number} The value to insert into the array.
|
||||||
* @returns {number} The position into occupied by value into the array.
|
* @returns {number} The position into occupied by value into the array.
|
||||||
*/
|
*/
|
||||||
insert(element, comparisonValue = null) {
|
insert(element, comparisonValue = null) {
|
||||||
|
let i = 0;
|
||||||
|
for (i = 0; i < this.length; ++i) {
|
||||||
|
if (element == this.array[i]) {
|
||||||
|
console.log("error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
let position = this.getPosition(this.comparisonValueSupplier(element))
|
let position = this.getPosition(this.comparisonValueSupplier(element))
|
||||||
if (
|
if (
|
||||||
position < this.currentPosition
|
position < this.currentPosition
|
||||||
|| comparisonValue != null && position == this.currentPosition && this.comparisonValueSupplier(element) < comparisonValue) {
|
|| comparisonValue != null && position == this.currentPosition && this.comparisonValueSupplier(element) < comparisonValue) {
|
||||||
++this.currentPosition
|
++this.currentPosition
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
let newArray = new Uint32Array(this.array.length + 1)
|
let newArray = new Uint32Array(this.array.length + 1)
|
||||||
newArray.set(this.array.subarray(0, position), 0)
|
newArray.set(this.array.subarray(0, position), 0)
|
||||||
newArray[position] = element
|
newArray[position] = element
|
||||||
newArray.set(this.array.subarray(position), position + 1)
|
newArray.set(this.array.subarray(position), position + 1)
|
||||||
this.array = newArray
|
this.array = newArray
|
||||||
this.length = this.array.length
|
*/
|
||||||
|
this.shiftRight(position)
|
||||||
|
this.array[position] = element
|
||||||
|
++this.length
|
||||||
|
if (this.length > this.array.length) {
|
||||||
|
console.log("error2")
|
||||||
|
}
|
||||||
return position
|
return position
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,23 +112,26 @@ export default class OrderedIndexArray {
|
|||||||
if (position < this.currentPosition) {
|
if (position < this.currentPosition) {
|
||||||
--this.currentPosition
|
--this.currentPosition
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
let newArray = new Uint32Array(this.array.length - 1)
|
let newArray = new Uint32Array(this.array.length - 1)
|
||||||
newArray.set(this.array.subarray(0, position), 0)
|
newArray.set(this.array.subarray(0, position), 0)
|
||||||
newArray.set(this.array.subarray(position + 1), position)
|
newArray.set(this.array.subarray(position + 1), position)
|
||||||
this.array = newArray
|
this.array = newArray
|
||||||
this.length = this.array.length
|
*/
|
||||||
|
this.shiftLeft(position)
|
||||||
|
--this.length
|
||||||
return position
|
return position
|
||||||
}
|
}
|
||||||
|
|
||||||
getNext() {
|
getNext() {
|
||||||
if (this.currentPosition >= 0 && this.currentPosition < this.array.length) {
|
if (this.currentPosition >= 0 && this.currentPosition < this.length) {
|
||||||
return this.get(this.currentPosition)
|
return this.get(this.currentPosition)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
getNextValue() {
|
getNextValue() {
|
||||||
if (this.currentPosition >= 0 && this.currentPosition < this.array.length) {
|
if (this.currentPosition >= 0 && this.currentPosition < this.length) {
|
||||||
return this.comparisonValueSupplier(this.get(this.currentPosition))
|
return this.comparisonValueSupplier(this.get(this.currentPosition))
|
||||||
} else {
|
} else {
|
||||||
return Number.MAX_SAFE_INTEGER
|
return Number.MAX_SAFE_INTEGER
|
||||||
@@ -124,4 +152,12 @@ export default class OrderedIndexArray {
|
|||||||
return Number.MIN_SAFE_INTEGER
|
return Number.MIN_SAFE_INTEGER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shiftLeft(leftLimit, steps = 1) {
|
||||||
|
this.array.set(this.array.subarray(leftLimit + steps), leftLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
shiftRight(leftLimit, steps = 1) {
|
||||||
|
this.array.set(this.array.subarray(leftLimit, -steps), leftLimit + steps)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
44
js/SimpleSelectionModel.js
Normal file
44
js/SimpleSelectionModel.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
export default class SimpleSelectionModel {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{
|
||||||
|
* primaryInf: number,
|
||||||
|
* primarySup: number,
|
||||||
|
* secondaryInf: number,
|
||||||
|
* secondarySup: number
|
||||||
|
* }} BoundariesInfo
|
||||||
|
* @typedef {numeric} Rectangle
|
||||||
|
* @param {number[]} initialPosition Coordinates of the starting point of selection [primaryAxisValue, secondaryAxisValue].
|
||||||
|
* @param {Rectangle[]} rectangles Rectangles that can be selected by this object.
|
||||||
|
* @param {(rect: Rectangle) => BoundariesInfo} boundariesFunc A function that, given a rectangle, it provides the boundaries of such rectangle.
|
||||||
|
* @param {(rect: Rectangle, selected: bool) => void} selectToggleFunction A function that selects or deselects individual rectangles.
|
||||||
|
*/
|
||||||
|
constructor(initialPosition, rectangles, boundariesFunc, selectToggleFunction) {
|
||||||
|
this.initialPosition = initialPosition
|
||||||
|
this.finalPosition = initialPosition
|
||||||
|
this.boundariesFunc = boundariesFunc
|
||||||
|
this.selectToggleFunction = selectToggleFunction
|
||||||
|
this.rectangles = rectangles
|
||||||
|
}
|
||||||
|
|
||||||
|
selectTo(finalPosition) {
|
||||||
|
let primaryInf = Math.min(finalPosition[0], this.initialPosition[0])
|
||||||
|
let primarySup = Math.max(finalPosition[0], this.initialPosition[0])
|
||||||
|
let secondaryInf = Math.min(finalPosition[1], this.initialPosition[1])
|
||||||
|
let secondarySup = Math.max(finalPosition[1], this.initialPosition[1])
|
||||||
|
this.finalPosition = finalPosition
|
||||||
|
this.rectangles.forEach(rect => {
|
||||||
|
let boundaries = this.boundariesFunc(rect)
|
||||||
|
if (
|
||||||
|
Math.max(boundaries.primaryInf, primaryInf) < Math.min(boundaries.primarySup, primarySup)
|
||||||
|
&& Math.max(boundaries.secondaryInf, secondaryInf) < Math.min(boundaries.secondarySup, secondarySup)
|
||||||
|
) {
|
||||||
|
this.selectToggleFunction(rect, true)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
this.selectToggleFunction(rect, false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
import Utility from "./Utility.js"
|
import Utility from "./Utility.js"
|
||||||
import UEBlueprintDragScroll from "./UEBlueprintDragScroll.js"
|
import UEBlueprintDragScroll from "./UEBlueprintDragScroll.js"
|
||||||
import UEBlueprintSelect from "./UEBlueprintSelect.js"
|
import UEBlueprintSelect from "./UEBlueprintSelect.js"
|
||||||
import SelectionModel from "./SelectionModel.js"
|
import FastSelectionModel from "./FastSelectionModel.js"
|
||||||
|
import SimpleSelectionModel from "./SimpleSelectionModel.js"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import("./UEBlueprintObject.js").default} UEBlueprintObject
|
* @typedef {import("./UEBlueprintObject.js").default} UEBlueprintObject
|
||||||
@@ -72,7 +73,7 @@ export default class UEBlueprint extends HTMLElement {
|
|||||||
this.zoom = 0
|
this.zoom = 0
|
||||||
/** @type {HTMLElement} */
|
/** @type {HTMLElement} */
|
||||||
this.headerElement = null
|
this.headerElement = null
|
||||||
/** @type {SelectionModel} */
|
/** @type {FastSelectionModel} */
|
||||||
this.selectionModel = null
|
this.selectionModel = null
|
||||||
/** @type {(node: UEBlueprintObject) => BoundariesInfo} */
|
/** @type {(node: UEBlueprintObject) => BoundariesInfo} */
|
||||||
this.nodeBoundariesSupplier = (node) => {
|
this.nodeBoundariesSupplier = (node) => {
|
||||||
@@ -336,7 +337,7 @@ export default class UEBlueprint extends HTMLElement {
|
|||||||
this.selectorElement.style.setProperty('--ueb-select-to-x', initialPosition[0])
|
this.selectorElement.style.setProperty('--ueb-select-to-x', initialPosition[0])
|
||||||
this.selectorElement.style.setProperty('--ueb-select-to-y', initialPosition[1])
|
this.selectorElement.style.setProperty('--ueb-select-to-y', initialPosition[1])
|
||||||
this.selectorElement.dataset.selecting = "true"
|
this.selectorElement.dataset.selecting = "true"
|
||||||
this.selectionModel = new SelectionModel(initialPosition, this.nodes, this.nodeBoundariesSupplier, this.nodeSelectToggleFunction)
|
this.selectionModel = new FastSelectionModel(initialPosition, this.nodes, this.nodeBoundariesSupplier, this.nodeSelectToggleFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
finishSelecting() {
|
finishSelecting() {
|
||||||
|
|||||||
@@ -96,6 +96,9 @@ export default class UEBlueprintObject extends UEBlueprintDraggableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setSelected(value = true) {
|
setSelected(value = true) {
|
||||||
|
if (this.selected == value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.selected = value
|
this.selected = value
|
||||||
if (value) {
|
if (value) {
|
||||||
this.classList.add('ueb-selected')
|
this.classList.add('ueb-selected')
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
126
ueblueprint.js
126
ueblueprint.js
@@ -190,7 +190,10 @@ class OrderedIndexArray {
|
|||||||
* @returns The element of the array
|
* @returns The element of the array
|
||||||
*/
|
*/
|
||||||
get(index) {
|
get(index) {
|
||||||
return this.array[index]
|
if (index >= 0 && index < this.length) {
|
||||||
|
return this.array[index]
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -208,7 +211,7 @@ class OrderedIndexArray {
|
|||||||
*/
|
*/
|
||||||
getPosition(value) {
|
getPosition(value) {
|
||||||
let l = 0;
|
let l = 0;
|
||||||
let r = this.array.length;
|
let r = this.length;
|
||||||
while (l < r) {
|
while (l < r) {
|
||||||
let m = Math.floor((l + r) / 2);
|
let m = Math.floor((l + r) / 2);
|
||||||
if (this.comparisonValueSupplier(this.array[m]) < value) {
|
if (this.comparisonValueSupplier(this.array[m]) < value) {
|
||||||
@@ -220,24 +223,46 @@ class OrderedIndexArray {
|
|||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reserve(length) {
|
||||||
|
if (this.array.length < length) {
|
||||||
|
let newArray = new Uint32Array(length);
|
||||||
|
newArray.set(this.array);
|
||||||
|
this.array = newArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts the element in the array.
|
* Inserts the element in the array.
|
||||||
* @param element {number} The value to insert into the array.
|
* @param element {number} The value to insert into the array.
|
||||||
* @returns {number} The position into occupied by value into the array.
|
* @returns {number} The position into occupied by value into the array.
|
||||||
*/
|
*/
|
||||||
insert(element, comparisonValue = null) {
|
insert(element, comparisonValue = null) {
|
||||||
|
let i = 0;
|
||||||
|
for (i = 0; i < this.length; ++i) {
|
||||||
|
if (element == this.array[i]) {
|
||||||
|
console.log("error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
let position = this.getPosition(this.comparisonValueSupplier(element));
|
let position = this.getPosition(this.comparisonValueSupplier(element));
|
||||||
if (
|
if (
|
||||||
position < this.currentPosition
|
position < this.currentPosition
|
||||||
|| comparisonValue != null && position == this.currentPosition && this.comparisonValueSupplier(element) < comparisonValue) {
|
|| comparisonValue != null && position == this.currentPosition && this.comparisonValueSupplier(element) < comparisonValue) {
|
||||||
++this.currentPosition;
|
++this.currentPosition;
|
||||||
}
|
}
|
||||||
let newArray = new Uint32Array(this.array.length + 1);
|
/*
|
||||||
newArray.set(this.array.subarray(0, position), 0);
|
let newArray = new Uint32Array(this.array.length + 1)
|
||||||
newArray[position] = element;
|
newArray.set(this.array.subarray(0, position), 0)
|
||||||
newArray.set(this.array.subarray(position), position + 1);
|
newArray[position] = element
|
||||||
this.array = newArray;
|
newArray.set(this.array.subarray(position), position + 1)
|
||||||
this.length = this.array.length;
|
this.array = newArray
|
||||||
|
*/
|
||||||
|
this.shiftRight(position);
|
||||||
|
this.array[position] = element;
|
||||||
|
++this.length;
|
||||||
|
if (this.length > this.array.length) {
|
||||||
|
console.log("error2");
|
||||||
|
}
|
||||||
return position
|
return position
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,23 +285,26 @@ class OrderedIndexArray {
|
|||||||
if (position < this.currentPosition) {
|
if (position < this.currentPosition) {
|
||||||
--this.currentPosition;
|
--this.currentPosition;
|
||||||
}
|
}
|
||||||
let newArray = new Uint32Array(this.array.length - 1);
|
/*
|
||||||
newArray.set(this.array.subarray(0, position), 0);
|
let newArray = new Uint32Array(this.array.length - 1)
|
||||||
newArray.set(this.array.subarray(position + 1), position);
|
newArray.set(this.array.subarray(0, position), 0)
|
||||||
this.array = newArray;
|
newArray.set(this.array.subarray(position + 1), position)
|
||||||
this.length = this.array.length;
|
this.array = newArray
|
||||||
|
*/
|
||||||
|
this.shiftLeft(position);
|
||||||
|
--this.length;
|
||||||
return position
|
return position
|
||||||
}
|
}
|
||||||
|
|
||||||
getNext() {
|
getNext() {
|
||||||
if (this.currentPosition >= 0 && this.currentPosition < this.array.length) {
|
if (this.currentPosition >= 0 && this.currentPosition < this.length) {
|
||||||
return this.get(this.currentPosition)
|
return this.get(this.currentPosition)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
getNextValue() {
|
getNextValue() {
|
||||||
if (this.currentPosition >= 0 && this.currentPosition < this.array.length) {
|
if (this.currentPosition >= 0 && this.currentPosition < this.length) {
|
||||||
return this.comparisonValueSupplier(this.get(this.currentPosition))
|
return this.comparisonValueSupplier(this.get(this.currentPosition))
|
||||||
} else {
|
} else {
|
||||||
return Number.MAX_SAFE_INTEGER
|
return Number.MAX_SAFE_INTEGER
|
||||||
@@ -297,9 +325,17 @@ class OrderedIndexArray {
|
|||||||
return Number.MIN_SAFE_INTEGER
|
return Number.MIN_SAFE_INTEGER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shiftLeft(leftLimit, steps = 1) {
|
||||||
|
this.array.set(this.array.subarray(leftLimit + steps), leftLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
shiftRight(leftLimit, steps = 1) {
|
||||||
|
this.array.set(this.array.subarray(leftLimit, -steps), leftLimit + steps);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SelectionModel {
|
class FastSelectionModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
@@ -330,6 +366,8 @@ class SelectionModel {
|
|||||||
this.secondaryOrder = new OrderedIndexArray((element) => this.metadata[element].secondaryBoundary);
|
this.secondaryOrder = new OrderedIndexArray((element) => this.metadata[element].secondaryBoundary);
|
||||||
this.selectToggleFunction = selectToggleFunction;
|
this.selectToggleFunction = selectToggleFunction;
|
||||||
this.rectangles = rectangles;
|
this.rectangles = rectangles;
|
||||||
|
this.primaryOrder.reserve(this.rectangles.length);
|
||||||
|
this.secondaryOrder.reserve(this.rectangles.length);
|
||||||
rectangles.forEach((rect, index) => {
|
rectangles.forEach((rect, index) => {
|
||||||
/** @type Metadata */
|
/** @type Metadata */
|
||||||
let rectangleMetadata = {
|
let rectangleMetadata = {
|
||||||
@@ -341,6 +379,16 @@ class SelectionModel {
|
|||||||
this.metadata[index] = rectangleMetadata;
|
this.metadata[index] = rectangleMetadata;
|
||||||
selectToggleFunction(rect, false); // Initially deselected (Eventually)
|
selectToggleFunction(rect, false); // Initially deselected (Eventually)
|
||||||
const rectangleBoundaries = boundariesFunc(rect);
|
const rectangleBoundaries = boundariesFunc(rect);
|
||||||
|
|
||||||
|
// Secondary axis first because it may be inserted in this.secondaryOrder during the primary axis check
|
||||||
|
if (this.initialPosition[1] < rectangleBoundaries.secondaryInf) { // Initial position is before the rectangle
|
||||||
|
rectangleMetadata.secondaryBoundary = rectangleBoundaries.secondaryInf;
|
||||||
|
} else if (rectangleBoundaries.secondarySup < this.initialPosition[1]) { // Initial position is after the rectangle
|
||||||
|
rectangleMetadata.secondaryBoundary = rectangleBoundaries.secondarySup;
|
||||||
|
} else {
|
||||||
|
rectangleMetadata.onSecondaryAxis = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.initialPosition[0] < rectangleBoundaries.primaryInf) { // Initial position is before the rectangle
|
if (this.initialPosition[0] < rectangleBoundaries.primaryInf) { // Initial position is before the rectangle
|
||||||
rectangleMetadata.primaryBoundary = rectangleBoundaries.primaryInf;
|
rectangleMetadata.primaryBoundary = rectangleBoundaries.primaryInf;
|
||||||
this.primaryOrder.insert(index);
|
this.primaryOrder.insert(index);
|
||||||
@@ -355,13 +403,6 @@ class SelectionModel {
|
|||||||
selectToggleFunction(rect, true);
|
selectToggleFunction(rect, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.initialPosition[1] < rectangleBoundaries.secondaryInf) { // Initial position is before the rectangle
|
|
||||||
rectangleMetadata.secondaryBoundary = rectangleBoundaries.secondaryInf;
|
|
||||||
} else if (rectangleBoundaries.secondarySup < this.initialPosition[1]) { // Initial position is after the rectangle
|
|
||||||
rectangleMetadata.secondaryBoundary = rectangleBoundaries.secondarySup;
|
|
||||||
} else {
|
|
||||||
rectangleMetadata.onSecondaryAxis = true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
this.primaryOrder.currentPosition = this.primaryOrder.getPosition(this.initialPosition[0]);
|
this.primaryOrder.currentPosition = this.primaryOrder.getPosition(this.initialPosition[0]);
|
||||||
this.secondaryOrder.currentPosition = this.secondaryOrder.getPosition(this.initialPosition[1]);
|
this.secondaryOrder.currentPosition = this.secondaryOrder.getPosition(this.initialPosition[1]);
|
||||||
@@ -397,12 +438,11 @@ class SelectionModel {
|
|||||||
Math.sign(finalPosition[0] - this.initialPosition[0]),
|
Math.sign(finalPosition[0] - this.initialPosition[0]),
|
||||||
Math.sign(finalPosition[1] - this.initialPosition[1])
|
Math.sign(finalPosition[1] - this.initialPosition[1])
|
||||||
];
|
];
|
||||||
const primaryBoundaryCrossed = (index, expanding) => {
|
const primaryBoundaryCrossed = (index, added) => {
|
||||||
this.primaryOrder.currentPosition += direction[0] * (expanding ? 1 : -1);
|
|
||||||
if (this.metadata[index].onSecondaryAxis) {
|
if (this.metadata[index].onSecondaryAxis) {
|
||||||
this.selectToggleFunction(this.rectangles[index], expanding);
|
this.selectToggleFunction(this.rectangles[index], added);
|
||||||
} else {
|
} else {
|
||||||
if (expanding) {
|
if (added) {
|
||||||
this.secondaryOrder.insert(index, finalPosition[1]);
|
this.secondaryOrder.insert(index, finalPosition[1]);
|
||||||
const secondaryBoundary = this.metadata[index].secondaryBoundary;
|
const secondaryBoundary = this.metadata[index].secondaryBoundary;
|
||||||
if (
|
if (
|
||||||
@@ -424,23 +464,34 @@ class SelectionModel {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (finalPosition[0] < this.boundaries.primaryN.value) {
|
if (finalPosition[0] < this.boundaries.primaryN.value) {
|
||||||
primaryBoundaryCrossed(this.boundaries.primaryN.index, finalPosition[0] < this.initialPosition[0]);
|
--this.primaryOrder.currentPosition;
|
||||||
|
primaryBoundaryCrossed(
|
||||||
|
this.boundaries.primaryN.index,
|
||||||
|
this.initialPosition[0] > this.boundaries.primaryN.value && finalPosition[0] < this.initialPosition[0]);
|
||||||
} else if (finalPosition[0] > this.boundaries.primaryP.value) {
|
} else if (finalPosition[0] > this.boundaries.primaryP.value) {
|
||||||
primaryBoundaryCrossed(this.boundaries.primaryP.index, this.initialPosition[0] < finalPosition[0]);
|
++this.primaryOrder.currentPosition;
|
||||||
|
primaryBoundaryCrossed(
|
||||||
|
this.boundaries.primaryP.index,
|
||||||
|
this.initialPosition[0] < this.boundaries.primaryP.value && this.initialPosition[0] < finalPosition[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const secondaryBoundaryCrossed = (index, expanding) => {
|
const secondaryBoundaryCrossed = (index, added) => {
|
||||||
this.secondaryOrder.currentPosition += direction[1] * (expanding ? 1 : -1);
|
this.selectToggleFunction(this.rectangles[index], added);
|
||||||
this.selectToggleFunction(this.rectangles[index], expanding);
|
|
||||||
this.computeBoundaries(finalPosition);
|
this.computeBoundaries(finalPosition);
|
||||||
this.selectTo(finalPosition);
|
this.selectTo(finalPosition);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (finalPosition[1] < this.boundaries.secondaryN.value) {
|
if (finalPosition[1] < this.boundaries.secondaryN.value) {
|
||||||
secondaryBoundaryCrossed(this.boundaries.secondaryN.index, finalPosition[1] < this.initialPosition[1]);
|
--this.secondaryOrder.currentPosition;
|
||||||
|
secondaryBoundaryCrossed(
|
||||||
|
this.boundaries.secondaryN.index,
|
||||||
|
this.initialPosition[1] > this.boundaries.secondaryN.value && finalPosition[1] < this.initialPosition[1]);
|
||||||
} else if (finalPosition[1] > this.boundaries.secondaryP.value) {
|
} else if (finalPosition[1] > this.boundaries.secondaryP.value) {
|
||||||
secondaryBoundaryCrossed(this.boundaries.secondaryP.index, this.initialPosition[1] < finalPosition[1]);
|
++this.secondaryOrder.currentPosition;
|
||||||
|
secondaryBoundaryCrossed(
|
||||||
|
this.boundaries.secondaryP.index,
|
||||||
|
this.initialPosition[1] < this.boundaries.secondaryP.value && this.initialPosition[1] < finalPosition[1]);
|
||||||
}
|
}
|
||||||
this.finalPosition = finalPosition;
|
this.finalPosition = finalPosition;
|
||||||
}
|
}
|
||||||
@@ -516,7 +567,7 @@ class UEBlueprint extends HTMLElement {
|
|||||||
this.zoom = 0;
|
this.zoom = 0;
|
||||||
/** @type {HTMLElement} */
|
/** @type {HTMLElement} */
|
||||||
this.headerElement = null;
|
this.headerElement = null;
|
||||||
/** @type {SelectionModel} */
|
/** @type {FastSelectionModel} */
|
||||||
this.selectionModel = null;
|
this.selectionModel = null;
|
||||||
/** @type {(node: UEBlueprintObject) => BoundariesInfo} */
|
/** @type {(node: UEBlueprintObject) => BoundariesInfo} */
|
||||||
this.nodeBoundariesSupplier = (node) => {
|
this.nodeBoundariesSupplier = (node) => {
|
||||||
@@ -780,7 +831,7 @@ class UEBlueprint extends HTMLElement {
|
|||||||
this.selectorElement.style.setProperty('--ueb-select-to-x', initialPosition[0]);
|
this.selectorElement.style.setProperty('--ueb-select-to-x', initialPosition[0]);
|
||||||
this.selectorElement.style.setProperty('--ueb-select-to-y', initialPosition[1]);
|
this.selectorElement.style.setProperty('--ueb-select-to-y', initialPosition[1]);
|
||||||
this.selectorElement.dataset.selecting = "true";
|
this.selectorElement.dataset.selecting = "true";
|
||||||
this.selectionModel = new SelectionModel(initialPosition, this.nodes, this.nodeBoundariesSupplier, this.nodeSelectToggleFunction);
|
this.selectionModel = new FastSelectionModel(initialPosition, this.nodes, this.nodeBoundariesSupplier, this.nodeSelectToggleFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
finishSelecting() {
|
finishSelecting() {
|
||||||
@@ -946,6 +997,9 @@ class UEBlueprintObject extends UEBlueprintDraggableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setSelected(value = true) {
|
setSelected(value = true) {
|
||||||
|
if (this.selected == value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.selected = value;
|
this.selected = value;
|
||||||
if (value) {
|
if (value) {
|
||||||
this.classList.add('ueb-selected');
|
this.classList.add('ueb-selected');
|
||||||
|
|||||||
Reference in New Issue
Block a user