Skip to content

Commit

Permalink
feat: add function based styling for all modes and styles
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesLMilner committed Jul 24, 2023
1 parent 56a6960 commit 11d6c17
Show file tree
Hide file tree
Showing 18 changed files with 952 additions and 306 deletions.
40 changes: 40 additions & 0 deletions guides/GETTING_STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -290,3 +290,43 @@ draw.start();
```

Please note at the moment it is not possible to style against specific modes but only universally against geometry type (Point, LineString, Polygon)

## Styling Specific Features

Terra Draw supports styling overrides of individual features if required. This can be achieved by providing a styling function rather than a string or a number to a feature. As an example here we can style each polygon feature as a random color:

```typescript
// Function to generate a random hex color - can adjust as needed
function getRandomColor() {
const letters = "0123456789ABCDEF";
let color = "#";
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}

// Cache for each feature id mapped to a hex color string
const colorCache: Record<string, HexColor> = {};

const draw = new TerraDraw({
adapter: new TerraDrawMapboxGLAdapter({
map, // Assume this is defined further up
coordinatePrecision: 9,
}),
modes: {
polygon: new TerraDrawPolygonMode({
styles: {
fillColor: ({ id }) => {
// Get the color from the cache or generate a new one
colorCache[id] = colorCache[id] || getRandomColor();
return colorCache[id];
},
},
}),
},
});

// Ensure the color cache is clead up on deletion of features
draw.on("delete", (ids) => ids.forEach((id) => delete cache[id]));
```
8 changes: 8 additions & 0 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ import {

export type HexColor = `#${string}`;

export type HexColorStyling =
| HexColor
| ((feature: GeoJSONStoreFeatures) => HexColor);

export type NumericStyling =
| number
| ((feature: GeoJSONStoreFeatures) => number);

export interface TerraDrawAdapterStyling {
pointColor: HexColor;
pointWidth: number;
Expand Down
39 changes: 38 additions & 1 deletion src/modes/base.mode.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BehaviorConfig, TerraDrawModeBehavior } from "./base.behavior";
import {
HexColor,
TerraDrawAdapterStyling,
TerraDrawKeyboardEvent,
TerraDrawModeRegisterConfig,
Expand All @@ -13,7 +14,13 @@ import {
} from "../store/store";
import { isValidStoreFeature } from "../store/store-feature-validation";

type CustomStyling = Record<string, string | number>;
type CustomStyling = Record<
string,
| string
| number
| ((feature: GeoJSONStoreFeatures) => HexColor)
| ((feature: GeoJSONStoreFeatures) => number)
>;

export enum ModeTypes {
Drawing = "drawing",
Expand Down Expand Up @@ -156,4 +163,34 @@ export abstract class TerraDrawBaseDrawMode<T extends CustomStyling> {
event: TerraDrawMouseEvent,
setMapDraggability: (enabled: boolean) => void
) {}

protected getHexColorStylingValue(
value: HexColor | ((feature: GeoJSONStoreFeatures) => HexColor) | undefined,
defaultValue: HexColor,
feature: GeoJSONStoreFeatures
): HexColor {
return this.getStylingValue(value, defaultValue, feature);
}

protected getNumericStylingValue(
value: number | ((feature: GeoJSONStoreFeatures) => number) | undefined,
defaultValue: number,
feature: GeoJSONStoreFeatures
): number {
return this.getStylingValue(value, defaultValue, feature);
}

private getStylingValue<T extends string | number>(
value: T | ((feature: GeoJSONStoreFeatures) => T) | undefined,
defaultValue: T,
feature: GeoJSONStoreFeatures
) {
if (value === undefined) {
return defaultValue;
} else if (typeof value === "function") {
return value(feature);
} else {
return value;
}
}
}
45 changes: 29 additions & 16 deletions src/modes/circle/circle.mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
TerraDrawAdapterStyling,
TerraDrawKeyboardEvent,
HexColor,
HexColorStyling,
NumericStyling,
} from "../../common";
import { haversineDistanceKilometers } from "../../geometry/measure/haversine-distance";
import { circle } from "../../geometry/shape/create-circle";
Expand All @@ -18,10 +20,10 @@ type TerraDrawCircleModeKeyEvents = {
};

type FreehandPolygonStyling = {
fillColor: HexColor;
outlineColor: HexColor;
outlineWidth: number;
fillOpacity: number;
fillColor: HexColorStyling;
outlineColor: HexColorStyling;
outlineWidth: NumericStyling;
fillOpacity: NumericStyling;
};

export class TerraDrawCircleMode extends TerraDrawBaseDrawMode<FreehandPolygonStyling> {
Expand Down Expand Up @@ -174,18 +176,29 @@ export class TerraDrawCircleMode extends TerraDrawBaseDrawMode<FreehandPolygonSt
feature.geometry.type === "Polygon" &&
feature.properties.mode === this.mode
) {
if (this.styles.fillColor) {
styles.polygonFillColor = this.styles.fillColor;
}
if (this.styles.outlineColor) {
styles.polygonOutlineColor = this.styles.outlineColor;
}
if (this.styles.outlineWidth) {
styles.polygonOutlineWidth = this.styles.outlineWidth;
}
if (this.styles.fillOpacity) {
styles.polygonFillOpacity = this.styles.fillOpacity;
}
styles.polygonFillColor = this.getHexColorStylingValue(
this.styles.fillColor,
styles.polygonFillColor,
feature
);

styles.polygonOutlineColor = this.getHexColorStylingValue(
this.styles.outlineColor,
styles.polygonOutlineColor,
feature
);

styles.polygonOutlineWidth = this.getNumericStylingValue(
this.styles.outlineWidth,
styles.polygonOutlineWidth,
feature
);

styles.polygonFillOpacity = this.getNumericStylingValue(
this.styles.fillOpacity,
styles.polygonFillOpacity,
feature
);

return styles;
}
Expand Down
89 changes: 55 additions & 34 deletions src/modes/freehand/freehand.mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {
TerraDrawAdapterStyling,
TerraDrawKeyboardEvent,
HexColor,
HexColorStyling,
NumericStyling,
} from "../../common";
import { Polygon } from "geojson";

Expand All @@ -18,14 +20,14 @@ type TerraDrawFreehandModeKeyEvents = {
};

type FreehandPolygonStyling = {
fillColor: HexColor;
outlineColor: HexColor;
outlineWidth: number;
fillOpacity: number;
closingPointColor: HexColor;
closingPointWidth: number;
closingPointOutlineColor: HexColor;
closingPointOutlineWidth: number;
fillColor: HexColorStyling;
outlineColor: HexColorStyling;
outlineWidth: NumericStyling;
fillOpacity: NumericStyling;
closingPointColor: HexColorStyling;
closingPointWidth: NumericStyling;
closingPointOutlineColor: HexColorStyling;
closingPointOutlineWidth: NumericStyling;
};

export class TerraDrawFreehandMode extends TerraDrawBaseDrawMode<FreehandPolygonStyling> {
Expand Down Expand Up @@ -236,40 +238,59 @@ export class TerraDrawFreehandMode extends TerraDrawBaseDrawMode<FreehandPolygon
feature.geometry.type === "Polygon" &&
feature.properties.mode === this.mode
) {
if (this.styles.fillColor) {
styles.polygonFillColor = this.styles.fillColor;
}
if (this.styles.outlineColor) {
styles.polygonOutlineColor = this.styles.outlineColor;
}
if (this.styles.outlineWidth) {
styles.polygonOutlineWidth = this.styles.outlineWidth;
}
if (this.styles.fillOpacity) {
styles.polygonFillOpacity = this.styles.fillOpacity;
}
styles.polygonFillColor = this.getHexColorStylingValue(
this.styles.fillColor,
styles.polygonFillColor,
feature
);

styles.polygonOutlineColor = this.getHexColorStylingValue(
this.styles.outlineColor,
styles.polygonOutlineColor,
feature
);

styles.polygonOutlineWidth = this.getNumericStylingValue(
this.styles.outlineWidth,
styles.polygonOutlineWidth,
feature
);

styles.polygonFillOpacity = this.getNumericStylingValue(
this.styles.fillOpacity,
styles.polygonFillOpacity,
feature
);

return styles;
} else if (
feature.type === "Feature" &&
feature.geometry.type === "Point" &&
feature.properties.mode === this.mode
) {
if (this.styles.closingPointColor) {
styles.pointColor = this.styles.closingPointColor;
}
if (this.styles.closingPointWidth) {
styles.pointWidth = this.styles.closingPointWidth;
}
styles.pointWidth = this.getNumericStylingValue(
this.styles.closingPointWidth,
styles.pointWidth,
feature
);

styles.pointOutlineColor =
this.styles.closingPointOutlineColor !== undefined
? this.styles.closingPointOutlineColor
: "#ffffff";
styles.pointOutlineWidth =
this.styles.closingPointOutlineWidth !== undefined
? this.styles.closingPointOutlineWidth
: 2;
styles.pointColor = this.getHexColorStylingValue(
this.styles.closingPointColor,
styles.pointColor,
feature
);

styles.pointOutlineColor = this.getHexColorStylingValue(
this.styles.closingPointOutlineColor,
styles.pointOutlineColor,
feature
);

styles.pointOutlineWidth = this.getNumericStylingValue(
this.styles.closingPointOutlineWidth,
2,
feature
);

return styles;
}
Expand Down
67 changes: 41 additions & 26 deletions src/modes/greatcircle/great-circle.mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {
TerraDrawAdapterStyling,
TerraDrawKeyboardEvent,
HexColor,
HexColorStyling,
NumericStyling,
} from "../../common";
import { LineString } from "geojson";
import { TerraDrawBaseDrawMode } from "../base.mode";
Expand All @@ -20,12 +22,12 @@ type TerraDrawGreateCircleModeKeyEvents = {
};

type GreateCircleStyling = {
lineStringWidth: number;
lineStringColor: HexColor;
closingPointColor: HexColor;
closingPointWidth: number;
closingPointOutlineColor: HexColor;
closingPointOutlineWidth: number;
lineStringWidth: NumericStyling;
lineStringColor: HexColorStyling;
closingPointColor: HexColorStyling;
closingPointWidth: NumericStyling;
closingPointOutlineColor: HexColorStyling;
closingPointOutlineWidth: NumericStyling;
};

export class TerraDrawGreatCircleMode extends TerraDrawBaseDrawMode<GreateCircleStyling> {
Expand Down Expand Up @@ -251,34 +253,47 @@ export class TerraDrawGreatCircleMode extends TerraDrawBaseDrawMode<GreateCircle
feature.geometry.type === "LineString" &&
feature.properties.mode === this.mode
) {
if (this.styles.lineStringColor) {
styles.lineStringColor = this.styles.lineStringColor;
}
if (this.styles.lineStringWidth) {
styles.lineStringWidth = this.styles.lineStringWidth;
}
styles.lineStringColor = this.getHexColorStylingValue(
this.styles.lineStringColor,
styles.lineStringColor,
feature
);

styles.lineStringWidth = this.getNumericStylingValue(
this.styles.lineStringWidth,
styles.lineStringWidth,
feature
);

return styles;
} else if (
feature.type === "Feature" &&
feature.geometry.type === "Point" &&
feature.properties.mode === this.mode
) {
if (this.styles.closingPointColor) {
styles.pointColor = this.styles.closingPointColor;
}
if (this.styles.closingPointWidth) {
styles.pointWidth = this.styles.closingPointWidth;
}
styles.pointColor = this.getHexColorStylingValue(
this.styles.closingPointColor,
styles.pointColor,
feature
);

styles.pointWidth = this.getNumericStylingValue(
this.styles.closingPointWidth,
styles.pointWidth,
feature
);

styles.pointOutlineColor =
this.styles.closingPointOutlineColor !== undefined
? this.styles.closingPointOutlineColor
: "#ffffff";
styles.pointOutlineWidth =
this.styles.closingPointOutlineWidth !== undefined
? this.styles.closingPointOutlineWidth
: 2;
styles.pointOutlineColor = this.getHexColorStylingValue(
this.styles.closingPointOutlineColor,
"#ffffff",
feature
);

styles.pointOutlineWidth = this.getNumericStylingValue(
this.styles.closingPointOutlineWidth,
2,
feature
);

return styles;
}
Expand Down
Loading

0 comments on commit 11d6c17

Please sign in to comment.