Skip to content

Commit

Permalink
Add transform edit mode (uber#340)
Browse files Browse the repository at this point in the history
This new `TransformMode` effectively merges translate, rotate, and scale modes into one, with the help of edit guides. This new mode also supports editing multiple selected features.
![transform](https://user-images.githubusercontent.com/42187119/75191881-0e549300-5708-11ea-952c-1afd4d6d57a5.gif)
  • Loading branch information
austintang authored Mar 16, 2020
1 parent a6c603d commit 7f426db
Show file tree
Hide file tree
Showing 23 changed files with 1,051 additions and 122 deletions.
4 changes: 4 additions & 0 deletions docs/api-reference/modes/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ User can rotate a feature about its centroid by clicking and dragging the select
The user can move a feature by selecting one or more features and dragging anywhere within the screen.
_Additionally, the user can initiate snapping by clicking and dragging the selected feature's vertex handles. If the vertex handle is close enough to another feature's vertex, the two features will snap together._

## [TransformMode](https://github.com/uber/nebula.gl/blob/master/modules/edit-modes/src/lib/transform-mode.js)

A single mode that provides translating, rotating, and scaling capabilities. Translation can be performed by clicking and dragging the selected feature itself. Rotating can be performed by clicking and dragging the top-most edit handle around a centroid pivot. Scaling can be performed by clicking and dragging one of the corner edit handles. Just like the individual modes, this mode supports multiple selections and feature snapping.

## [DuplicateMode](https://github.com/uber/nebula.gl/blob/master/modules/edit-modes/src/lib/duplicate-mode.js)

User can duplicate and translate a feature by clicking selected feature and dragging anywhere on the screen.
Expand Down
4 changes: 3 additions & 1 deletion examples/advanced/example.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
type EditMode,
ModifyMode,
TranslateMode,
TransformMode,
ScaleMode,
RotateMode,
DuplicateMode,
Expand Down Expand Up @@ -113,7 +114,8 @@ const ALL_MODES = [
{ label: 'Scale', mode: ScaleMode },
{ label: 'Duplicate', mode: DuplicateMode },
{ label: 'Extrude', mode: ExtrudeMode },
{ label: 'Split', mode: SplitPolygonMode }
{ label: 'Split', mode: SplitPolygonMode },
{ label: 'Transform', mode: new SnappableMode(new TransformMode()) }
]
},
{
Expand Down
1 change: 1 addition & 0 deletions modules/edit-modes/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export { DuplicateMode } from './lib/duplicate-mode.js';
export { SplitPolygonMode } from './lib/split-polygon-mode.js';
export { ExtrudeMode } from './lib/extrude-mode.js';
export { ElevationMode } from './lib/elevation-mode.js';
export { TransformMode } from './lib/transform-mode';

// Draw modes
export { DrawPointMode } from './lib/draw-point-mode.js';
Expand Down
1 change: 1 addition & 0 deletions modules/edit-modes/src/lib/draw-90degree-polygon-mode.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export class Draw90DegreePolygonMode extends BaseGeoJsonEditMode {

if (
clickedEditHandle &&
Array.isArray(clickedEditHandle.properties.positionIndexes) &&
(clickedEditHandle.properties.positionIndexes[1] === 0 ||
clickedEditHandle.properties.positionIndexes[1] === polygon.coordinates[0].length - 3)
) {
Expand Down
1 change: 1 addition & 0 deletions modules/edit-modes/src/lib/draw-polygon-mode.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export class DrawPolygonMode extends BaseGeoJsonEditMode {
if (
clickSequence.length > 2 &&
clickedEditHandle &&
Array.isArray(clickedEditHandle.properties.positionIndexes) &&
(clickedEditHandle.properties.positionIndexes[0] === 0 ||
clickedEditHandle.properties.positionIndexes[0] === clickSequence.length - 1)
) {
Expand Down
71 changes: 42 additions & 29 deletions modules/edit-modes/src/lib/extrude-mode.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,23 +147,25 @@ export class ExtrudeMode extends ModifyMode {
}

coordinatesSize(
positionIndexes: number[],
positionIndexes: ?(number[]),
featureIndex: number,
{ features }: FeatureCollection
) {
let size = 0;
const feature = features[featureIndex];
const coordinates: any = feature.geometry.coordinates;
// for Multi polygons, length will be 3
if (positionIndexes.length === 3) {
const [a, b] = positionIndexes;
if (coordinates.length && coordinates[a].length) {
size = coordinates[a][b].length;
}
} else {
const [b] = positionIndexes;
if (coordinates.length && coordinates[b].length) {
size = coordinates[b].length;
if (Array.isArray(positionIndexes)) {
const feature = features[featureIndex];
const coordinates: any = feature.geometry.coordinates;
// for Multi polygons, length will be 3
if (positionIndexes.length === 3) {
const [a, b] = positionIndexes;
if (coordinates.length && coordinates[a].length) {
size = coordinates[a][b].length;
}
} else {
const [b] = positionIndexes;
if (coordinates.length && coordinates[b].length) {
size = coordinates[b].length;
}
}
}
return size;
Expand All @@ -178,11 +180,14 @@ export class ExtrudeMode extends ModifyMode {
}

isOrthogonal(
positionIndexes: number[],
positionIndexes: ?(number[]),
featureIndex: number,
size: number,
features: FeatureCollection
) {
if (!Array.isArray(positionIndexes)) {
return false;
}
if (positionIndexes[positionIndexes.length - 1] === size - 1) {
positionIndexes[positionIndexes.length - 1] = 0;
}
Expand All @@ -202,15 +207,21 @@ export class ExtrudeMode extends ModifyMode {
return [89, 90, 91, 269, 270, 271].includes(Math.abs(prevAngle - nextAngle));
}

nextPositionIndexes(positionIndexes: number[], size: number): number[] {
nextPositionIndexes(positionIndexes: ?(number[]), size: number): number[] {
if (!Array.isArray(positionIndexes)) {
return [];
}
const next = [...positionIndexes];
if (next.length) {
next[next.length - 1] = next[next.length - 1] === size - 1 ? 0 : next[next.length - 1] + 1;
}
return next;
}

prevPositionIndexes(positionIndexes: number[], size: number): number[] {
prevPositionIndexes(positionIndexes: ?(number[]), size: number): number[] {
if (!Array.isArray(positionIndexes)) {
return [];
}
const prev = [...positionIndexes];
if (prev.length) {
prev[prev.length - 1] = prev[prev.length - 1] === 0 ? size - 2 : prev[prev.length - 1] - 1;
Expand All @@ -219,23 +230,25 @@ export class ExtrudeMode extends ModifyMode {
}

getPointForPositionIndexes(
positionIndexes: number[],
positionIndexes: ?(number[]),
featureIndex: number,
{ features }: FeatureCollection
) {
let p1;
const feature = features[featureIndex];
const coordinates: any = feature.geometry.coordinates;
// for Multi polygons, length will be 3
if (positionIndexes.length === 3) {
const [a, b, c] = positionIndexes;
if (coordinates.length && coordinates[a].length) {
p1 = coordinates[a][b][c];
}
} else {
const [b, c] = positionIndexes;
if (coordinates.length && coordinates[b].length) {
p1 = coordinates[b][c];
if (Array.isArray(positionIndexes)) {
const feature = features[featureIndex];
const coordinates: any = feature.geometry.coordinates;
// for Multi polygons, length will be 3
if (positionIndexes.length === 3) {
const [a, b, c] = positionIndexes;
if (coordinates.length && coordinates[a].length) {
p1 = coordinates[a][b][c];
}
} else {
const [b, c] = positionIndexes;
if (coordinates.length && coordinates[b].length) {
p1 = coordinates[b][c];
}
}
}
return p1;
Expand Down
14 changes: 8 additions & 6 deletions modules/edit-modes/src/lib/immutable-feature-collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export class ImmutableFeatureCollection {
*/
replacePosition(
featureIndex: number,
positionIndexes: number[],
positionIndexes: ?(number[]),
updatedPosition: Position
): ImmutableFeatureCollection {
const geometry = this.featureCollection.features[featureIndex].geometry;
Expand Down Expand Up @@ -62,7 +62,7 @@ export class ImmutableFeatureCollection {
*
* @returns A new `ImmutableFeatureCollection` with the given coordinate removed. Does not modify this `ImmutableFeatureCollection`.
*/
removePosition(featureIndex: number, positionIndexes: number[]): ImmutableFeatureCollection {
removePosition(featureIndex: number, positionIndexes: ?(number[])): ImmutableFeatureCollection {
const geometry = this.featureCollection.features[featureIndex].geometry;

if (geometry.type === 'Point') {
Expand All @@ -86,6 +86,7 @@ export class ImmutableFeatureCollection {
geometry.type === 'Polygon' &&
// outer ring is a triangle
geometry.coordinates[0].length < 5 &&
Array.isArray(positionIndexes) &&
// trying to remove from outer ring
positionIndexes[0] === 0
) {
Expand All @@ -106,6 +107,7 @@ export class ImmutableFeatureCollection {
geometry.coordinates.length === 1 &&
// outer ring is a triangle
geometry.coordinates[0][0].length < 5 &&
Array.isArray(positionIndexes) &&
// trying to remove from first polygon
positionIndexes[0] === 0 &&
// trying to remove from outer ring
Expand Down Expand Up @@ -140,7 +142,7 @@ export class ImmutableFeatureCollection {
*/
addPosition(
featureIndex: number,
positionIndexes: number[],
positionIndexes: ?(number[]),
positionToAdd: Position
): ImmutableFeatureCollection {
const geometry = this.featureCollection.features[featureIndex].geometry;
Expand Down Expand Up @@ -230,7 +232,7 @@ function getUpdatedPosition(updatedPosition: Position, previousPosition: Positio

function immutablyReplacePosition(
coordinates: any,
positionIndexes: number[],
positionIndexes: ?(number[]),
updatedPosition: Position,
isPolygonal: boolean
): any {
Expand Down Expand Up @@ -274,7 +276,7 @@ function immutablyReplacePosition(

function immutablyRemovePosition(
coordinates: any,
positionIndexes: number[],
positionIndexes: ?(number[]),
isPolygonal: boolean
): any {
if (!positionIndexes) {
Expand Down Expand Up @@ -320,7 +322,7 @@ function immutablyRemovePosition(

function immutablyAddPosition(
coordinates: any,
positionIndexes: number[],
positionIndexes: ?(number[]),
positionToAdd: Position,
isPolygonal: boolean
): any {
Expand Down
Loading

0 comments on commit 7f426db

Please sign in to comment.