Implement anchor and fix bugs with rigid body (#27)
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Co-authored-by: Eric NGUYEN <enguyen@techform.fr> Reviewed-on: https://git.siklos-chaneru.duckdns.org/Siklos/svg-layout-designer-react/pulls/27
This commit is contained in:
parent
c81a6fe44b
commit
704dab7307
12 changed files with 202 additions and 97 deletions
|
@ -2,7 +2,7 @@ import { Dispatch, SetStateAction } from 'react';
|
||||||
import { IConfiguration } from '../../Interfaces/IConfiguration';
|
import { IConfiguration } from '../../Interfaces/IConfiguration';
|
||||||
import { ContainerModel } from '../../Interfaces/IContainerModel';
|
import { ContainerModel } from '../../Interfaces/IContainerModel';
|
||||||
import { fetchConfiguration } from '../API/api';
|
import { fetchConfiguration } from '../API/api';
|
||||||
import { IEditorState } from "../../Interfaces/IEditorState";
|
import { IEditorState } from '../../Interfaces/IEditorState';
|
||||||
import { LoadState } from './Load';
|
import { LoadState } from './Load';
|
||||||
|
|
||||||
export function NewEditor(
|
export function NewEditor(
|
||||||
|
@ -23,6 +23,7 @@ export function NewEditor(
|
||||||
width: configuration.MainContainer.Width,
|
width: configuration.MainContainer.Width,
|
||||||
height: configuration.MainContainer.Height,
|
height: configuration.MainContainer.Height,
|
||||||
isRigidBody: false,
|
isRigidBody: false,
|
||||||
|
isAnchor: false,
|
||||||
fillOpacity: 0,
|
fillOpacity: 0,
|
||||||
stroke: 'black'
|
stroke: 'black'
|
||||||
}
|
}
|
||||||
|
|
70
src/Components/Editor/Behaviors/AnchorBehaviors.ts
Normal file
70
src/Components/Editor/Behaviors/AnchorBehaviors.ts
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/**
|
||||||
|
* @module AnchorBehavior
|
||||||
|
*
|
||||||
|
* An anchor is a container that takes physical priority in the representation :
|
||||||
|
* - It cannot be moved by other rigid siblings container
|
||||||
|
* - It cannot be resized by any other siblings container
|
||||||
|
* - It cannot overlap any other siblings rigid container :
|
||||||
|
* - overlapping container are shifted to the nearest available space/width
|
||||||
|
* - or resized when there is no available space left other than theirs
|
||||||
|
* - or lose their rigid body properties when there is no available space left)
|
||||||
|
* Meaning that:
|
||||||
|
* - Moving an anchor container will resize the width of an overlapping container
|
||||||
|
* or make them lose their property as a rigid body
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { IContainerModel } from '../../../Interfaces/IContainerModel';
|
||||||
|
import { constraintBodyInsideUnallocatedWidth } from './RigidBodyBehaviors';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Impose the container position to its siblings
|
||||||
|
* Apply the following modification to the overlapping rigid body container :
|
||||||
|
* @param container Container to impose its position
|
||||||
|
*/
|
||||||
|
export function ImposePosition(container: IContainerModel): IContainerModel {
|
||||||
|
if (container.parent === undefined ||
|
||||||
|
container.parent === null) {
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rigidBodies = container.parent.children.filter(
|
||||||
|
child => child.properties.isRigidBody && !child.properties.isAnchor
|
||||||
|
);
|
||||||
|
|
||||||
|
const overlappingContainers = getOverlappingContainers(container, rigidBodies);
|
||||||
|
for (const overlappingContainer of overlappingContainers) {
|
||||||
|
constraintBodyInsideUnallocatedWidth(overlappingContainer);
|
||||||
|
}
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the overlapping containers with container
|
||||||
|
* @param container A container
|
||||||
|
* @param containers A list of containers
|
||||||
|
* @returns A list of overlapping containers
|
||||||
|
*/
|
||||||
|
function getOverlappingContainers(
|
||||||
|
container: IContainerModel,
|
||||||
|
containers: IContainerModel[]
|
||||||
|
): IContainerModel[] {
|
||||||
|
const min1 = container.properties.x;
|
||||||
|
const max1 = container.properties.x + Number(container.properties.width);
|
||||||
|
const overlappingContainers: IContainerModel[] = [];
|
||||||
|
for (const other of containers) {
|
||||||
|
if (other === container) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const min2 = other.properties.x;
|
||||||
|
const max2 = other.properties.x + Number(other.properties.width);
|
||||||
|
const isOverlapping = Math.min(max1, max2) - Math.max(min1, min2) > 0;
|
||||||
|
|
||||||
|
if (!isOverlapping) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
overlappingContainers.push(other);
|
||||||
|
}
|
||||||
|
return overlappingContainers;
|
||||||
|
}
|
|
@ -1,5 +1,13 @@
|
||||||
import { IContainerModel } from '../../Interfaces/IContainerModel';
|
/**
|
||||||
import { ISizePointer } from '../../Interfaces/ISizePointer';
|
* @module RigidBodyBehaviors
|
||||||
|
* Apply the following contraints to the `container` :
|
||||||
|
* - The container must be kept inside its parent
|
||||||
|
* - The container must find an unallocated space within the parent
|
||||||
|
* If the contraints fails, an error message will be returned
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { IContainerModel } from '../../../Interfaces/IContainerModel';
|
||||||
|
import { ISizePointer } from '../../../Interfaces/ISizePointer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Transform the container into a rigid body"
|
* "Transform the container into a rigid body"
|
||||||
|
@ -82,7 +90,7 @@ function constraintBodyInsideSpace(
|
||||||
if (containerX < x) {
|
if (containerX < x) {
|
||||||
containerProperties.x = x;
|
containerProperties.x = x;
|
||||||
}
|
}
|
||||||
if (containerX + containerWidth > width) {
|
if (containerX + containerWidth > x + width) {
|
||||||
containerProperties.x = x + width - containerWidth;
|
containerProperties.x = x + width - containerWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +98,7 @@ function constraintBodyInsideSpace(
|
||||||
if (containerY < y) {
|
if (containerY < y) {
|
||||||
containerProperties.y = y;
|
containerProperties.y = y;
|
||||||
}
|
}
|
||||||
if (containerY + containerHeight > height) {
|
if (containerY + containerHeight > y + height) {
|
||||||
containerProperties.y = y + height - containerHeight;
|
containerProperties.y = y + height - containerHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +112,7 @@ function constraintBodyInsideSpace(
|
||||||
* @param container
|
* @param container
|
||||||
* @returns Updated container
|
* @returns Updated container
|
||||||
*/
|
*/
|
||||||
function constraintBodyInsideUnallocatedWidth(
|
export function constraintBodyInsideUnallocatedWidth(
|
||||||
container: IContainerModel
|
container: IContainerModel
|
||||||
): IContainerModel {
|
): IContainerModel {
|
||||||
if (container.parent === null) {
|
if (container.parent === null) {
|
||||||
|
@ -114,12 +122,7 @@ function constraintBodyInsideUnallocatedWidth(
|
||||||
// Get the available spaces of the parent
|
// Get the available spaces of the parent
|
||||||
const availableWidths = getAvailableWidths(container.parent, container);
|
const availableWidths = getAvailableWidths(container.parent, container);
|
||||||
const containerX = Number(container.properties.x);
|
const containerX = Number(container.properties.x);
|
||||||
|
const containerWidth = Number(container.properties.width);
|
||||||
// Sort the available width to find the closest one
|
|
||||||
availableWidths.sort(
|
|
||||||
(width1, width2) =>
|
|
||||||
Math.abs(width1.x - containerX) - Math.abs(width2.x - containerX)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check if there is still some space
|
// Check if there is still some space
|
||||||
if (availableWidths.length === 0) {
|
if (availableWidths.length === 0) {
|
||||||
|
@ -128,6 +131,24 @@ function constraintBodyInsideUnallocatedWidth(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const middle = containerX + containerWidth / 2;
|
||||||
|
// Sort the available width to find the space with the closest position
|
||||||
|
availableWidths.sort(
|
||||||
|
(width1, width2) => {
|
||||||
|
let compared1X = width1.x;
|
||||||
|
if (width1.x < containerX) {
|
||||||
|
compared1X = width1.x + width1.width - containerWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
let compared2X = width2.x;
|
||||||
|
if (width2.x < containerX) {
|
||||||
|
compared2X = width2.x + width2.width - containerWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.abs(compared1X - middle) - Math.abs(compared2X - middle);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// Check if the container actually fit inside
|
// Check if the container actually fit inside
|
||||||
// It will usually fit if it was alrady fitting
|
// It will usually fit if it was alrady fitting
|
||||||
const availableWidthFound = availableWidths.find((width) =>
|
const availableWidthFound = availableWidths.find((width) =>
|
||||||
|
@ -179,17 +200,18 @@ function getAvailableWidths(
|
||||||
const width = Number(container.properties.width);
|
const width = Number(container.properties.width);
|
||||||
let unallocatedSpaces: ISizePointer[] = [{ x, width }];
|
let unallocatedSpaces: ISizePointer[] = [{ x, width }];
|
||||||
|
|
||||||
// We will only uses containers that also have the rigid bodies
|
// We will only uses containers that also are rigid or are anchors
|
||||||
// as out-of-bound or enormouse containers should be ignored
|
const solidBodies = container.children.filter(
|
||||||
const rigidBodies = container.children.filter(
|
(child) => child.properties.isRigidBody || child.properties.isAnchor
|
||||||
(child) => child.properties.isRigidBody
|
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const child of rigidBodies) {
|
for (const child of solidBodies) {
|
||||||
// Ignore the exception
|
// Ignore the exception
|
||||||
if (child === exception) {
|
if (child === exception) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
const childX = child.properties.x;
|
||||||
|
const childWidth = Number(child.properties.width);
|
||||||
|
|
||||||
// get the space of the child that is inside the parent
|
// get the space of the child that is inside the parent
|
||||||
let newUnallocatedSpace: ISizePointer[] = [];
|
let newUnallocatedSpace: ISizePointer[] = [];
|
||||||
|
@ -202,8 +224,8 @@ function getAvailableWidths(
|
||||||
const newUnallocatedWidths = getAvailableWidthsTwoLines(
|
const newUnallocatedWidths = getAvailableWidthsTwoLines(
|
||||||
unallocatedSpace.x,
|
unallocatedSpace.x,
|
||||||
unallocatedSpace.x + unallocatedSpace.width,
|
unallocatedSpace.x + unallocatedSpace.width,
|
||||||
child.properties.x,
|
childX,
|
||||||
child.properties.x + Number(child.properties.width)
|
childX + childWidth
|
||||||
);
|
);
|
||||||
|
|
||||||
// Concat the new list of SizePointer pointing to availables spaces
|
// Concat the new list of SizePointer pointing to availables spaces
|
||||||
|
@ -218,39 +240,49 @@ function getAvailableWidths(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the unallocated widths between two lines in 1D
|
* Returns the unallocated widths between two lines in 1D
|
||||||
* @param min1 left of the first line
|
* @param unalloctedSpaceLeft left of the first line
|
||||||
* @param max1 rigth of the first line
|
* @param unallocatedSpaceRight rigth of the first line
|
||||||
* @param min2 left of the second line
|
* @param rectLeft left of the second line
|
||||||
* @param max2 right of the second line
|
* @param rectRight right of the second line
|
||||||
* @returns Available widths
|
* @returns Available widths
|
||||||
*/
|
*/
|
||||||
function getAvailableWidthsTwoLines(
|
function getAvailableWidthsTwoLines(
|
||||||
min1: number,
|
unalloctedSpaceLeft: number,
|
||||||
max1: number,
|
unallocatedSpaceRight: number,
|
||||||
min2: number,
|
rectLeft: number,
|
||||||
max2: number
|
rectRight: number
|
||||||
): ISizePointer[] {
|
): ISizePointer[] {
|
||||||
if (min2 < min1 && max2 > max1) {
|
if (unallocatedSpaceRight < rectLeft ||
|
||||||
|
unalloctedSpaceLeft > rectRight
|
||||||
|
) {
|
||||||
|
// object 1 and 2 are not overlapping
|
||||||
|
return [{
|
||||||
|
x: unalloctedSpaceLeft,
|
||||||
|
width: unallocatedSpaceRight - unalloctedSpaceLeft
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rectLeft < unalloctedSpaceLeft && rectRight > unallocatedSpaceRight) {
|
||||||
// object 2 is overlapping full width
|
// object 2 is overlapping full width
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (min1 >= min2) {
|
if (unalloctedSpaceLeft >= rectLeft) {
|
||||||
// object 2 is partially overlapping on the left
|
// object 2 is partially overlapping on the left
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
x: max2,
|
x: rectRight,
|
||||||
width: max1 - max2
|
width: unallocatedSpaceRight - rectRight
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max2 >= max1) {
|
if (rectRight >= unallocatedSpaceRight) {
|
||||||
// object 2 is partially overlapping on the right
|
// object 2 is partially overlapping on the right
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
x: min2,
|
x: unalloctedSpaceLeft,
|
||||||
width: max2 - min1
|
width: rectRight - unalloctedSpaceLeft
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -258,12 +290,12 @@ function getAvailableWidthsTwoLines(
|
||||||
// object 2 is overlapping in the middle
|
// object 2 is overlapping in the middle
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
x: min1,
|
x: unalloctedSpaceLeft,
|
||||||
width: min2 - min1
|
width: rectLeft - unalloctedSpaceLeft
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x: min2,
|
x: rectRight,
|
||||||
width: max1 - max2
|
width: unallocatedSpaceRight - rectRight
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
|
@ -4,6 +4,7 @@ import { IConfiguration } from '../../Interfaces/IConfiguration';
|
||||||
import { ContainerModel, IContainerModel } from '../../Interfaces/IContainerModel';
|
import { ContainerModel, IContainerModel } from '../../Interfaces/IContainerModel';
|
||||||
import { findContainerById } from '../../utils/itertools';
|
import { findContainerById } from '../../utils/itertools';
|
||||||
import { getCurrentHistory } from './Editor';
|
import { getCurrentHistory } from './Editor';
|
||||||
|
import IProperties from '../../Interfaces/IProperties';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select a container
|
* Select a container
|
||||||
|
@ -203,20 +204,23 @@ export function AddContainer(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the container
|
const defaultProperties: IProperties = {
|
||||||
const newContainer = new ContainerModel(
|
|
||||||
parentClone,
|
|
||||||
{
|
|
||||||
id: `${type}-${count}`,
|
id: `${type}-${count}`,
|
||||||
parentId: parentClone.properties.id,
|
parentId: parentClone.properties.id,
|
||||||
x,
|
x,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: properties?.Width,
|
width: properties.Width,
|
||||||
height: parentClone.properties.height,
|
height: parentClone.properties.height,
|
||||||
isRigidBody: false,
|
isRigidBody: false,
|
||||||
|
isAnchor: false,
|
||||||
XPositionReference: properties.XPositionReference,
|
XPositionReference: properties.XPositionReference,
|
||||||
...properties.Style
|
...properties.Style
|
||||||
},
|
};
|
||||||
|
|
||||||
|
// Create the container
|
||||||
|
const newContainer = new ContainerModel(
|
||||||
|
parentClone,
|
||||||
|
defaultProperties,
|
||||||
[],
|
[],
|
||||||
{
|
{
|
||||||
type
|
type
|
||||||
|
|
|
@ -4,7 +4,9 @@ import { IHistoryState } from '../../Interfaces/IHistoryState';
|
||||||
import IProperties from '../../Interfaces/IProperties';
|
import IProperties from '../../Interfaces/IProperties';
|
||||||
import { findContainerById } from '../../utils/itertools';
|
import { findContainerById } from '../../utils/itertools';
|
||||||
import { getCurrentHistory } from './Editor';
|
import { getCurrentHistory } from './Editor';
|
||||||
import { RecalculatePhysics } from './RigidBodyBehaviors';
|
import { RecalculatePhysics } from './Behaviors/RigidBodyBehaviors';
|
||||||
|
import { INPUT_TYPES } from '../Properties/PropertiesInputTypes';
|
||||||
|
import { ImposePosition } from './Behaviors/AnchorBehaviors';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handled the property change event in the properties form
|
* Handled the property change event in the properties form
|
||||||
|
@ -28,20 +30,6 @@ export function OnPropertyChange(
|
||||||
throw new Error('[OnPropertyChange] Property was changed before selecting a Container');
|
throw new Error('[OnPropertyChange] Property was changed before selecting a Container');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent === null) {
|
|
||||||
const selectedContainerClone: IContainerModel = structuredClone(current.SelectedContainer);
|
|
||||||
(selectedContainerClone.properties as any)[key] = value;
|
|
||||||
setHistory(history.concat([{
|
|
||||||
LastAction: 'Change property of main',
|
|
||||||
MainContainer: selectedContainerClone,
|
|
||||||
SelectedContainer: selectedContainerClone,
|
|
||||||
SelectedContainerId: selectedContainerClone.properties.id,
|
|
||||||
TypeCounters: Object.assign({}, current.TypeCounters)
|
|
||||||
}]));
|
|
||||||
setHistoryCurrentStep(history.length);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mainContainerClone: IContainerModel = structuredClone(current.MainContainer);
|
const mainContainerClone: IContainerModel = structuredClone(current.MainContainer);
|
||||||
const container: ContainerModel | undefined = findContainerById(mainContainerClone, current.SelectedContainer.properties.id);
|
const container: ContainerModel | undefined = findContainerById(mainContainerClone, current.SelectedContainer.properties.id);
|
||||||
|
|
||||||
|
@ -49,7 +37,15 @@ export function OnPropertyChange(
|
||||||
throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
|
throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (INPUT_TYPES[key] === 'number') {
|
||||||
|
(container.properties as any)[key] = Number(value);
|
||||||
|
} else {
|
||||||
(container.properties as any)[key] = value;
|
(container.properties as any)[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (container.properties.isAnchor) {
|
||||||
|
ImposePosition(container);
|
||||||
|
}
|
||||||
|
|
||||||
if (container.properties.isRigidBody) {
|
if (container.properties.isRigidBody) {
|
||||||
RecalculatePhysics(container);
|
RecalculatePhysics(container);
|
||||||
|
@ -88,25 +84,6 @@ export function OnPropertiesSubmit(
|
||||||
throw new Error('[OnPropertyChange] Property was changed before selecting a Container');
|
throw new Error('[OnPropertyChange] Property was changed before selecting a Container');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent === null) {
|
|
||||||
const selectedContainerClone: IContainerModel = structuredClone(current.SelectedContainer);
|
|
||||||
for (const property in properties) {
|
|
||||||
const input = (event.target as HTMLFormElement).querySelector(`#${property}`);
|
|
||||||
if (input instanceof HTMLInputElement) {
|
|
||||||
(selectedContainerClone.properties as any)[property] = input.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setHistory(history.concat([{
|
|
||||||
LastAction: 'Change property of main',
|
|
||||||
MainContainer: selectedContainerClone,
|
|
||||||
SelectedContainer: selectedContainerClone,
|
|
||||||
SelectedContainerId: selectedContainerClone.properties.id,
|
|
||||||
TypeCounters: Object.assign({}, current.TypeCounters)
|
|
||||||
}]));
|
|
||||||
setHistoryCurrentStep(history.length);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mainContainerClone: IContainerModel = structuredClone(current.MainContainer);
|
const mainContainerClone: IContainerModel = structuredClone(current.MainContainer);
|
||||||
const container: ContainerModel | undefined = findContainerById(mainContainerClone, current.SelectedContainer.properties.id);
|
const container: ContainerModel | undefined = findContainerById(mainContainerClone, current.SelectedContainer.properties.id);
|
||||||
|
|
||||||
|
@ -118,6 +95,11 @@ export function OnPropertiesSubmit(
|
||||||
const input = (event.target as HTMLFormElement).querySelector(`#${property}`);
|
const input = (event.target as HTMLFormElement).querySelector(`#${property}`);
|
||||||
if (input instanceof HTMLInputElement) {
|
if (input instanceof HTMLInputElement) {
|
||||||
(container.properties as any)[property] = input.value;
|
(container.properties as any)[property] = input.value;
|
||||||
|
if (INPUT_TYPES[property] === 'number') {
|
||||||
|
(container.properties as any)[property] = Number(input.value);
|
||||||
|
} else {
|
||||||
|
(container.properties as any)[property] = input.value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,8 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 2000,
|
width: 2000,
|
||||||
height: 100,
|
height: 100,
|
||||||
isRigidBody: false
|
isRigidBody: false,
|
||||||
|
isAnchor: false
|
||||||
},
|
},
|
||||||
userData: {}
|
userData: {}
|
||||||
}}
|
}}
|
||||||
|
@ -47,7 +48,8 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 2000,
|
width: 2000,
|
||||||
height: 100,
|
height: 100,
|
||||||
isRigidBody: false
|
isRigidBody: false,
|
||||||
|
isAnchor: false
|
||||||
},
|
},
|
||||||
userData: {}
|
userData: {}
|
||||||
};
|
};
|
||||||
|
@ -103,7 +105,8 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 2000,
|
width: 2000,
|
||||||
height: 100,
|
height: 100,
|
||||||
isRigidBody: false
|
isRigidBody: false,
|
||||||
|
isAnchor: false
|
||||||
},
|
},
|
||||||
userData: {}
|
userData: {}
|
||||||
};
|
};
|
||||||
|
@ -119,7 +122,8 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
isRigidBody: false
|
isRigidBody: false,
|
||||||
|
isAnchor: false
|
||||||
},
|
},
|
||||||
userData: {}
|
userData: {}
|
||||||
}
|
}
|
||||||
|
@ -136,7 +140,8 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
isRigidBody: false
|
isRigidBody: false,
|
||||||
|
isAnchor: false
|
||||||
},
|
},
|
||||||
userData: {}
|
userData: {}
|
||||||
}
|
}
|
||||||
|
@ -173,7 +178,8 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 2000,
|
width: 2000,
|
||||||
height: 100,
|
height: 100,
|
||||||
isRigidBody: false
|
isRigidBody: false,
|
||||||
|
isAnchor: false
|
||||||
},
|
},
|
||||||
userData: {}
|
userData: {}
|
||||||
};
|
};
|
||||||
|
@ -188,7 +194,8 @@ describe.concurrent('Elements sidebar', () => {
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
isRigidBody: false
|
isRigidBody: false,
|
||||||
|
isAnchor: false
|
||||||
},
|
},
|
||||||
userData: {}
|
userData: {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,7 +23,8 @@ describe.concurrent('Properties', () => {
|
||||||
parentId: 'parentId',
|
parentId: 'parentId',
|
||||||
x: 1,
|
x: 1,
|
||||||
y: 1,
|
y: 1,
|
||||||
isRigidBody: false
|
isRigidBody: false,
|
||||||
|
isAnchor: false
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChange = vi.fn((key, value) => {
|
const handleChange = vi.fn((key, value) => {
|
||||||
|
|
|
@ -3,5 +3,6 @@ export const INPUT_TYPES: Record<string, string> = {
|
||||||
y: 'number',
|
y: 'number',
|
||||||
width: 'number',
|
width: 'number',
|
||||||
height: 'number',
|
height: 'number',
|
||||||
isRigidBody: 'checkbox'
|
isRigidBody: 'checkbox',
|
||||||
|
isAnchor: 'checkbox'
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
export enum AddingBehavior {
|
|
||||||
InsertInto,
|
|
||||||
Replace
|
|
||||||
}
|
|
|
@ -1,11 +1,21 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { XPositionReference } from '../Enums/XPositionReference';
|
import { XPositionReference } from '../Enums/XPositionReference';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properties of a container
|
||||||
|
* @property id id of the container
|
||||||
|
* @property parentId id of the parent container
|
||||||
|
* @property x horizontal offset of the container
|
||||||
|
* @property y vertical offset of the container
|
||||||
|
* @property isRigidBody if true apply rigid body behaviors
|
||||||
|
* @property isAnchor if true apply anchor behaviors
|
||||||
|
*/
|
||||||
export default interface IProperties extends React.CSSProperties {
|
export default interface IProperties extends React.CSSProperties {
|
||||||
id: string
|
id: string
|
||||||
parentId: string | null
|
parentId: string | null
|
||||||
x: number
|
x: number
|
||||||
y: number
|
y: number
|
||||||
isRigidBody: boolean
|
isRigidBody: boolean
|
||||||
|
isAnchor: boolean
|
||||||
XPositionReference?: XPositionReference
|
XPositionReference?: XPositionReference
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ export const DEFAULT_MAINCONTAINER_PROPS: IProperties = {
|
||||||
width: DEFAULT_CONFIG.MainContainer.Width,
|
width: DEFAULT_CONFIG.MainContainer.Width,
|
||||||
height: DEFAULT_CONFIG.MainContainer.Height,
|
height: DEFAULT_CONFIG.MainContainer.Height,
|
||||||
isRigidBody: false,
|
isRigidBody: false,
|
||||||
|
isAnchor: false,
|
||||||
fillOpacity: 0,
|
fillOpacity: 0,
|
||||||
stroke: 'black'
|
stroke: 'black'
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue