Skip to content

Commit

Permalink
selection boxes are now reverse scaled as the canvas zooms
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanvorster committed Jul 2, 2023
1 parent 931347c commit 4f71a48
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { ImageLayerFactory } from './image-layer/ImageLayerFactory';
import { DefaultCanvasState } from './DefaultCanvasState';
import { CanvasEngineListener } from '@projectstorm/react-canvas-core';
import { ConceptCanvasModel } from './ConceptCanvasModel';
import { ControlsLayerFactory } from './controls-layer/ControlsLayerFactory';

export class ConceptCanvasEngine extends CanvasEngine<CanvasEngineListener, ConceptCanvasModel> {
elementBank: FactoryBank<ImageElementFactory>;
Expand All @@ -26,6 +27,8 @@ export class ConceptCanvasEngine extends CanvasEngine<CanvasEngineListener, Conc

this.getLayerFactories().registerFactory(new SelectionBoxLayerFactory());
this.getLayerFactories().registerFactory(new ImageLayerFactory());
this.getLayerFactories().registerFactory(new ControlsLayerFactory());

this.getStateMachine().pushState(new DefaultCanvasState());

// @ts-ignore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import * as _ from 'lodash';
import { ImageElement } from './image-element/ImageElementFactory';
import { action } from 'mobx';
import { FileData } from '@projectstorm/tornado-common';
import { ControlsLayerModel } from './controls-layer/ControlsLayerFactory';

export class ConceptCanvasModel extends CanvasModel {
constructor(public model: ConceptBoardModel) {
super();

const layer = new ImageLayerModel();
this.addLayer(layer);
this.addLayer(new ImageLayerModel());
this.addLayer(new ControlsLayerModel());
}

load(engine: CanvasEngine) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as React from 'react';
import { ImageElement } from '../image-element/ImageElementFactory';
import { styled } from '../../../../../theme/theme';
import { useForceUpdate } from '../../../../../hooks/useForceUpdate';
import { useEffect } from 'react';
import { ImageLayerModel } from '../image-layer/ImageLayerFactory';

export interface ControlsElementWidgetProps {
model: ImageElement;
}

export const ControlsElementWidget: React.FC<ControlsElementWidgetProps> = (props) => {
const forceUpdate = useForceUpdate();
useEffect(() => {
const l = props.model.registerListener({
selectionChanged: () => {
forceUpdate();
}
});
return l.deregister;
}, []);
if (!props.model.isSelected()) {
return null;
}

const canvas = (props.model.getParent() as ImageLayerModel).getParent();
const zoom = canvas.getZoomLevel() / 100;

return (
<S.Container
style={{
left: props.model.getX() * zoom + canvas.getOffsetX(),
top: props.model.getY() * zoom + canvas.getOffsetY(),
width: props.model.width * zoom,
height: props.model.height * zoom
}}
/>
);
};
namespace S {
export const Container = styled.div`
position: absolute;
border: solid 2px ${(p) => p.theme.editor.selected};
box-shadow: 0 0 20px ${(p) => p.theme.editor.selectedShadow};
box-sizing: border-box;
pointer-events: none;
`;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import * as React from 'react';
import {
AbstractReactFactory,
FactoryBank,
GenerateModelEvent,
GenerateWidgetEvent,
LayerModel,
LayerModelGenerics
} from '@projectstorm/react-canvas-core';
import { ImageElement, ImageElementFactory } from '../image-element/ImageElementFactory';
import * as _ from 'lodash';
import { ConceptCanvasEngine } from '../ConceptCanvasEngine';
import { ConceptCanvasModel } from '../ConceptCanvasModel';
import { ControlsElementWidget } from './ControlsElementWidget';

export class ControlsLayerFactory extends AbstractReactFactory<ControlsLayerModel, ConceptCanvasEngine> {
static TYPE = 'concept/controls/layer';

constructor() {
super(ControlsLayerFactory.TYPE);
}

generateModel(event: GenerateModelEvent): ControlsLayerModel {
return new ControlsLayerModel();
}

generateReactWidget(event: GenerateWidgetEvent<ControlsLayerModel>): JSX.Element {
return (
<>
{_.map(event.model.getParent().getLayers()[0].getModels(), (m: ImageElement) => {
return <ControlsElementWidget model={m} key={m.getID()} />;
})}
</>
);
}
}

export type ControlsLayerGenerics = LayerModelGenerics & {
ENGINE: ConceptCanvasEngine;
PARENT: ConceptCanvasModel;
};

export class ControlsLayerModel extends LayerModel<ControlsLayerGenerics> {
constructor() {
super({
type: ControlsLayerFactory.TYPE,
transformed: false
});
}

getChildModelFactoryBank(engine: ControlsLayerGenerics['ENGINE']): FactoryBank<ImageElementFactory> {
return engine.elementBank;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,9 @@ export interface ImageElementWidgetProps {
}

export const ImageElementWidget: React.FC<ImageElementWidgetProps> = (props) => {
const forceUpdate = useForceUpdate();
useEffect(() => {
const l = props.model.registerListener({
selectionChanged: () => {
forceUpdate();
}
});
return l.deregister;
}, []);

return (
<S.Container
data-imageid={props.model.getID()}
selected={props.model.isSelected()}
style={{
left: props.model.getX(),
top: props.model.getY(),
Expand All @@ -36,10 +25,8 @@ export const ImageElementWidget: React.FC<ImageElementWidgetProps> = (props) =>
);
};
namespace S {
export const Container = styled.div<{ selected: boolean }>`
export const Container = styled.div`
position: absolute;
border: solid 2px ${(p) => (p.selected ? p.theme.editor.selected : 'transparent')};
${(p) => (p.selected ? `box-shadow: 0 0 20px ${p.theme.editor.selectedShadow}` : '')};
box-sizing: border-box;
pointer-events: all;
`;
Expand Down

0 comments on commit 4f71a48

Please sign in to comment.