Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react-component(feat): Add crop box, slicing and tool, generalize box concept #4594

Merged
merged 43 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
0dcbb9f
First commit
nilscognite Jun 11, 2024
9ace9a2
Generalized box and lines
nilscognite Jun 11, 2024
cab5732
More generalize
nilscognite Jun 12, 2024
f4bd56f
Further work
nilscognite Jun 12, 2024
84b40b5
Fix crop box
nilscognite Jun 12, 2024
1ceb3d7
Some fixes
nilscognite Jun 12, 2024
ec8d84e
Move files again
nilscognite Jun 12, 2024
7456ed7
Move files
nilscognite Jun 12, 2024
a132adf
Reuse code
nilscognite Jun 12, 2024
a44efe9
Merge branch 'master' into np/crop-box
nilscognite Jun 12, 2024
47f6d9c
adjustments
nilscognite Jun 12, 2024
eaa3668
After add constrains
nilscognite Jun 14, 2024
dd39291
Fixing cropping
nilscognite Jun 15, 2024
8d88f15
Merge branch 'master' into np/crop-box
nilscognite Jun 15, 2024
fee5202
Fix typename
nilscognite Jun 15, 2024
bc5bfda
Working good now
nilscognite Jun 15, 2024
66296f8
Update PlaneDomainObject.ts
nilscognite Jun 15, 2024
2866ef2
Fix updating
nilscognite Jun 15, 2024
4ab4361
Fix updating
nilscognite Jun 15, 2024
cc2c6fe
Make a general bounding box
nilscognite Jun 15, 2024
1b8ed23
Fixes
nilscognite Jun 15, 2024
2c4f657
make flipping consistent
nilscognite Jun 15, 2024
25342e4
Change name
nilscognite Jun 16, 2024
614aeef
Reorganization
nilscognite Jun 16, 2024
1e623c4
Fixing
nilscognite Jun 16, 2024
17b1e9f
more fixes
nilscognite Jun 16, 2024
526b3f3
Fix icon
nilscognite Jun 16, 2024
f7a4478
Fixing bounding box
nilscognite Jun 16, 2024
d8f056f
Smaller fixing
nilscognite Jun 16, 2024
7fd6e1d
Fix flaes
nilscognite Jun 17, 2024
835d7e9
Merge branch 'master' into np/crop-box
nilscognite Jun 17, 2024
787e13a
Merge branch 'master' into np/crop-box
nilscognite Jun 17, 2024
b81e158
Merge branch 'np/crop-box' of https://github.com/cognitedata/reveal i…
nilscognite Jun 17, 2024
f0268b7
Merge branch 'master' into np/crop-box
nilscognite Jun 17, 2024
efc4bf3
Update RevealButtons.tsx
nilscognite Jun 17, 2024
e52d87e
Fix updating of pending
nilscognite Jun 17, 2024
83a0eec
Update CropBoxDomainObject.ts
nilscognite Jun 17, 2024
c67ef75
Update comments
nilscognite Jun 17, 2024
769684c
Example uses ClipPlane, differentiate Left/Right button, contrained r…
nilscognite Jun 17, 2024
23e6c64
Update BoxDragger.ts
nilscognite Jun 17, 2024
28cf5c8
Fixes according to review
nilscognite Jun 17, 2024
292a825
Fix unit in box dragging
nilscognite Jun 17, 2024
7d7c1c5
Update PanelInfo.ts
nilscognite Jun 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions react-components/src/architecture/base/commands/BaseCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,27 @@ export abstract class BaseCommand {

private readonly _listeners: UpdateDelegate[] = [];

// Unique index for the command, used by in React to force rerender
// Unique id for the command, used by in React to force rerender
// when the command changes for a button.
public readonly _uniqueIndex: number;
private readonly _uniqueId: number;

public get uniqueIndex(): number {
return this._uniqueIndex;
public get uniqueId(): number {
return this._uniqueId;
}

// ==================================================
// VIRTUAL METHODS (To be override)
// =================================================
// CONSTRUCTOR
// ==================================================

constructor() {
BaseCommand._counter++;
this._uniqueIndex = BaseCommand._counter;
this._uniqueId = BaseCommand._counter;
}

// ==================================================
// VIRTUAL METHODS (To be override)
// =================================================

public get name(): string {
return this.tooltip.fallback ?? this.tooltip.key;
}
Expand All @@ -48,7 +52,7 @@ export abstract class BaseCommand {
}

public get tooltip(): TranslateKey {
return { key: '' };
return { key: '', fallback: '' };
nilscognite marked this conversation as resolved.
Show resolved Hide resolved
}

public get icon(): string {
Expand Down
81 changes: 48 additions & 33 deletions react-components/src/architecture/base/commands/BaseEditTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
* Copyright 2024 Cognite AS
*/

import { NavigationTool } from './NavigationTool';
import { NavigationTool } from '../concreteCommands/NavigationTool';
import { isDomainObjectIntersection } from '../domainObjectsHelpers/DomainObjectIntersection';
import { type BaseDragger } from '../domainObjectsHelpers/BaseDragger';
import { VisualDomainObject } from '../domainObjects/VisualDomainObject';
import { type AnyIntersection, CDF_TO_VIEWER_TRANSFORMATION } from '@cognite/reveal';
import { DomainObjectPanelUpdater } from '../reactUpdaters/DomainObjectPanelUpdater';

/**
* The `BaseEditTool` class is an abstract class that extends the `NavigationTool` class.
Expand Down Expand Up @@ -35,38 +36,44 @@ export abstract class BaseEditTool extends NavigationTool {
this._dragger = undefined;
}

public override async onPointerDown(event: PointerEvent, leftButton: boolean): Promise<void> {
public override async onLeftPointerDown(event: PointerEvent): Promise<void> {
this._dragger = await this.createDragger(event);
if (this._dragger === undefined) {
await super.onPointerDown(event, leftButton);
await super.onLeftPointerDown(event);
return;
}
this._dragger.onPointerDown(event);
this.deselectAll(this._dragger.domainObject);
this._dragger.domainObject.setSelectedInteractive(true);
}

public override async onPointerDrag(event: PointerEvent, leftButton: boolean): Promise<void> {
public override async onLeftPointerDrag(event: PointerEvent): Promise<void> {
if (this._dragger === undefined) {
await super.onPointerDrag(event, leftButton);
await super.onLeftPointerDrag(event);
return;
}
const ray = this.getRay(event, true);
this._dragger.onPointerDrag(event, ray);
}

public override async onPointerUp(event: PointerEvent, leftButton: boolean): Promise<void> {
public override async onLeftPointerUp(event: PointerEvent): Promise<void> {
if (this._dragger === undefined) {
await super.onPointerUp(event, leftButton);
await super.onLeftPointerUp(event);
} else {
this._dragger.onPointerUp(event);
this._dragger = undefined;
}
}

public override onActivate(): void {
super.onActivate();
const selected = this.getSelected();
DomainObjectPanelUpdater.show(selected);
}

public override onDeactivate(): void {
super.onDeactivate();
this.deselectAll();
DomainObjectPanelUpdater.hide();
}

// ==================================================
Expand Down Expand Up @@ -111,22 +118,29 @@ export abstract class BaseEditTool extends NavigationTool {
// INSTANCE METHODS
// ==================================================

/**
* Deselects all visual domain objects except for the specified object.
* If no object is specified, all visual domain objects will be deselected.
* @param except - The visual domain object to exclude from deselection.
*/
protected deselectAll(except?: VisualDomainObject | undefined): void {
protected *getSelectable(): Generator<VisualDomainObject> {
const { rootDomainObject } = this;
for (const domainObject of rootDomainObject.getDescendantsByType(VisualDomainObject)) {
if (!this.canBeSelected(domainObject)) {
continue;
}
if (except !== undefined && domainObject === except) {
yield domainObject;
}
}

/**
* Retrieves the selected VisualDomainObject.
* Use only if single selection is expected.
* @returns The selected DomainObject, or undefined if no object is selected.
*/
protected getSelected(): VisualDomainObject | undefined {
for (const domainObject of this.getSelectable()) {
if (!domainObject.isSelected) {
continue;
}
domainObject.setSelectedInteractive(false);
return domainObject;
}
return undefined;
}

/**
Expand All @@ -135,35 +149,36 @@ export abstract class BaseEditTool extends NavigationTool {
* @returns A generator that yields each selected domain object.
*/
protected *getAllSelected(): Generator<VisualDomainObject> {
const { rootDomainObject } = this;
for (const domainObject of rootDomainObject.getDescendantsByType(VisualDomainObject)) {
for (const domainObject of this.getSelectable()) {
if (!domainObject.isSelected) {
continue;
}
if (!this.canBeSelected(domainObject)) {
continue;
}
yield domainObject;
}
}

/**
* Retrieves the selected VisualDomainObject.
* Use only if single selection is expected.
* @returns The selected DomainObject, or undefined if no object is selected.
* Deselects all selectable objects except for the specified object.
* If no object is specified, all visual domain objects will be deselected.
* @param except - The visual domain object to exclude from deselection.
*/
protected getSelected(): VisualDomainObject | undefined {
const { rootDomainObject } = this;
for (const domainObject of rootDomainObject.getDescendantsByType(VisualDomainObject)) {
if (!domainObject.isSelected) {
continue;
}
if (!this.canBeSelected(domainObject)) {
protected deselectAll(except?: VisualDomainObject | undefined): void {
for (const domainObject of this.getSelectable()) {
if (except !== undefined && domainObject === except) {
continue;
}
return domainObject;
domainObject.setSelectedInteractive(false);
}
}

/**
* Sets the visibility of all selectable objects.
* @param visible - A boolean indicating whether the objects should be visible or not.
*/
protected setAllVisible(visible: boolean): void {
for (const domainObject of this.getSelectable()) {
domainObject.setVisibleInteractive(visible, this.renderTarget);
}
return undefined;
}

/**
Expand Down
20 changes: 16 additions & 4 deletions react-components/src/architecture/base/commands/BaseTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export abstract class BaseTool extends RenderTargetCommand {
}

public getToolbarStyle(): PopupStyle {
// Override this to place the the toolbar
// Override this to place the toolbar
// Default lower left corner
return new PopupStyle({ bottom: 0, left: 0 });
}
Expand Down Expand Up @@ -89,15 +89,27 @@ export abstract class BaseTool extends RenderTargetCommand {
await Promise.resolve();
}

public async onPointerDown(_event: PointerEvent, _leftButton: boolean): Promise<void> {
public async onLeftPointerDown(_event: PointerEvent): Promise<void> {
await Promise.resolve();
}

public async onPointerDrag(_event: PointerEvent, _leftButton: boolean): Promise<void> {
public async onLeftPointerDrag(_event: PointerEvent): Promise<void> {
await Promise.resolve();
}

public async onPointerUp(_event: PointerEvent, _leftButton: boolean): Promise<void> {
public async onLeftPointerUp(_event: PointerEvent): Promise<void> {
await Promise.resolve();
}

public async onRightPointerDown(_event: PointerEvent): Promise<void> {
await Promise.resolve();
}

public async onRightPointerDrag(_event: PointerEvent): Promise<void> {
await Promise.resolve();
}

public async onRightPointerUp(_event: PointerEvent): Promise<void> {
await Promise.resolve();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*!
* Copyright 2024 Cognite AS
*/

import { type DomainObject } from '../domainObjects/DomainObject';
import { BaseCommand } from './BaseCommand';

export abstract class DomainObjectCommand<Type extends DomainObject> extends BaseCommand {
// ==================================================
// INSTANCE FIELDS
// ==================================================

protected readonly _domainObject: Type;

// ==================================================
// CONSTRUCTOR
// ==================================================

public constructor(domainObject: Type) {
super();
this._domainObject = domainObject;
}

// ==================================================
// OVERRIDES
// ==================================================

public override get hasData(): boolean {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*!
* Copyright 2024 Cognite AS
*/

import { RenderTargetCommand } from './RenderTargetCommand';
import { type DomainObject } from '../domainObjects/DomainObject';

export abstract class InstanceCommand extends RenderTargetCommand {
// ==================================================
// OVERRIDES
// ==================================================

public override get isEnabled(): boolean {
return this.anyInstances;
}

// ==================================================
// VIRTUAL METHODS
// ==================================================

protected abstract isInstance(domainObject: DomainObject): boolean;

// ==================================================
// INSTANCE METHODS
// ==================================================

protected get anyInstances(): boolean {
return this.getFirstInstance() !== undefined;
}

protected getFirstInstance(): DomainObject | undefined {
// eslint-disable-next-line no-unreachable-loop
for (const domainObject of this.getInstances()) {
nilscognite marked this conversation as resolved.
Show resolved Hide resolved
return domainObject;
}
return undefined;
}

protected *getInstances(): Generator<DomainObject> {
for (const domainObject of this.rootDomainObject.getDescendants()) {
if (this.isInstance(domainObject)) {
yield domainObject;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*!
* Copyright 2024 Cognite AS
*/

import { type TranslateKey } from '../utilities/TranslateKey';
import { InstanceCommand } from './InstanceCommand';

export abstract class ShowAllDomainObjectsCommand extends InstanceCommand {
// ==================================================
// OVERRIDES
// ==================================================

public override get tooltip(): TranslateKey {
return { key: 'EXAMPLES_SHOW', fallback: 'Show or hide' };
}

public override get icon(): string {
return 'EyeShow';
}

public override get isChecked(): boolean {
return this.isAnyVisible();
}

protected override invokeCore(): boolean {
const isVisible = this.isAnyVisible();
for (const domainObject of this.getInstances()) {
domainObject.setVisibleInteractive(!isVisible, this.renderTarget);
}
return true;
}

// ==================================================
// INSTANCE METHODS
// ==================================================

private isAnyVisible(): boolean {
for (const domainObject of this.getInstances()) {
if (domainObject.isVisible(this.renderTarget)) {
return true;
}
}
return false;
}
}
Loading
Loading