Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion modules/editable-layers/src/lib/layers/segments-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {ArrowStyles, DEFAULT_STYLE, MAX_ARROWS} from '../style';
import {NebulaLayer} from '../nebula-layer';
import {toDeckColor} from '../../utils/utils';
import {DeckCache} from '../deck-renderer/deck-cache';
import {PathMarkerLayer} from '@deck.gl-community/layers';
import {PathMarkerLayer} from '../../../../layers/src/path-marker-layer/path-marker-layer';

const NEBULA_TO_DECK_DIRECTIONS = {
[ArrowStyles.NONE]: {forward: false, backward: false},
Expand Down
6 changes: 5 additions & 1 deletion modules/graph-layers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@
"raf": "^3.4.1"
},
"devDependencies": {
"ngraph.generators": "^20.1.0"
"ngraph.generators": "^20.1.0",
"zod": "^4.0.0"
},
"peerDependencies": {
"zod": "^3.23.8 || ^4.0.0"
}
}
3 changes: 3 additions & 0 deletions modules/graph-layers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@ export {StyleEngine} from './style/style-engine';
export {GraphStyleEngine} from './style/graph-style-engine';
export type {
GraphStylesheet,
GraphStylesheetInput,
GraphStylesheetParsed,
GraphStyleAttributeReference,
GraphStyleScale,
GraphStyleScaleType,
GraphStyleValue
} from './style/graph-style-engine';
export {GraphStylesheetSchema} from './style/graph-style-engine';
export {
DEFAULT_GRAPH_LAYER_STYLESHEET,
type GraphLayerStylesheet,
Expand Down
10 changes: 8 additions & 2 deletions modules/graph-layers/src/layers/graph-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,11 +270,17 @@ export class GraphLayer extends CompositeLayer<GraphLayerProps> {
const engine = this.state.graphEngine;
const {edges: edgeStyles} = this._getResolvedStylesheet();

if (!engine || !edgeStyles || edgeStyles.length === 0) {
if (!engine || !edgeStyles) {
return [];
}

return edgeStyles
const edgeStyleArray = Array.isArray(edgeStyles) ? edgeStyles : [edgeStyles];

if (edgeStyleArray.length === 0) {
return [];
}

return edgeStyleArray
.filter(Boolean)
.flatMap((style, idx) => {
const {decorators, data = (edges) => edges, visible = true, ...restEdgeStyle} = style;
Expand Down
20 changes: 8 additions & 12 deletions modules/graph-layers/src/style/graph-layer-stylesheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors

import type {GraphStylesheet, GraphStyleValue, GraphStyleType} from './graph-style-engine';
import type {GraphStylesheet, GraphStyleType} from './graph-style-engine';

export type GraphNodeStyleType = Exclude<
GraphStyleType,
Expand Down Expand Up @@ -35,13 +35,13 @@ export type GraphLayerStylesheet = {
edges?: GraphLayerEdgeStyle | GraphLayerEdgeStyle[];
};

export type GraphLayerStylesheetInput = GraphLayerStylesheet | null | undefined;

export type NormalizedGraphLayerStylesheet = {
nodes: GraphLayerNodeStyle[];
edges: GraphLayerEdgeStyle[];
};

export type GraphLayerStylesheetInput = GraphLayerStylesheet | null | undefined;

const DEFAULT_EDGE_STYLE: GraphLayerEdgeStyle = {
type: 'edge',
stroke: 'black',
Expand Down Expand Up @@ -76,18 +76,18 @@ export function normalizeGraphLayerStylesheet({
? resolvedNodeStyles.filter(Boolean)
: [...DEFAULT_GRAPH_LAYER_STYLESHEET.nodes];

const edgesArray = Array.isArray(resolvedEdgeStyles)
const edgeEntries = Array.isArray(resolvedEdgeStyles)
? resolvedEdgeStyles
: resolvedEdgeStyles
? [resolvedEdgeStyles]
: DEFAULT_GRAPH_LAYER_STYLESHEET.edges;

const edges = edgesArray
const edges: GraphLayerEdgeStyle[] = (edgeEntries)
.filter(Boolean)
.map((edgeStyleEntry) => ({
...edgeStyleEntry,
type: ((edgeStyleEntry as GraphLayerEdgeStyle).type ?? 'edge') as EdgeStyleType,
decorators: (edgeStyleEntry as GraphLayerEdgeStyle).decorators ?? []
type: ((edgeStyleEntry).type ?? 'edge'),
decorators: (edgeStyleEntry).decorators ?? []
})) as GraphLayerEdgeStyle[];

return {
Expand All @@ -96,8 +96,4 @@ export function normalizeGraphLayerStylesheet({
};
}

export type {
GraphStyleValue,
GraphStylesheet,
GraphStyleType
} from './graph-style-engine';
export type {GraphStyleValue, GraphStylesheet, GraphStyleType} from './graph-style-engine';
87 changes: 67 additions & 20 deletions modules/graph-layers/src/style/graph-style-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,50 @@
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors

import {StyleEngine, type DeckGLAccessorMap, type DeckGLUpdateTriggers} from './style-engine';
import {ZodError} from 'zod';

/** Supported scale families for attribute references. *
export type GraphStyleScaleType

/** Supported scale families for attribute references. */
export type GraphStyleScaleType =
| 'linear'
| 'log'
| 'pow'
| 'sqrt'
| 'quantize'
| 'quantile'
| 'ordinal';
/** Configuration for attribute scale mapping. *
export type GraphStyleScale =

/** Configuration for attribute scale mapping. */
export type GraphStyleScale = {
type?: GraphStyleScaleType;
domain?: (number | string)[];
range?: any[];
clamp?: boolean;
nice?: boolean | number;
base?: number;
exponent?: number;
unknown?: unknown;
};

/** Declares that a style property should derive its value from a graph attribute. */
export type GraphStyleAttributeReference<TValue = unknown> =
| `@${string}`
/** Declares that a style property should derive its value from a graph attribute. *
export type GraphStyleAttributeReference<TValue = unknown>

| {
attribute: string;
fallback?: TValue;
scale?: GraphStyleScale | ((value: unknown) => unknown);
};

/** Acceptable value for a single style state or accessor. */
export type GraphStyleLeafValue<TValue = unknown> =
| TValue
export type GraphStyleLeafValue<TValue = unknown>

| GraphStyleAttributeReference<TValue>
| ((datum: unknown) => TValue);

/** Acceptable value for a style property, including optional interaction states. */
export type GraphStyleValue<TValue = unknown> =
| GraphStyleLeafValue<TValue>
| {[state: string]: GraphStyleLeafValue<TValue>};
/** Acceptable value for a style property, including optional interaction states. *
export type GraphStyleValue<TValue = unknown>


const COMMON_DECKGL_PROPS = {
getOffset: 'offset',
opacity: 'opacity'
} as const;

const GRAPH_DECKGL_ACCESSOR_MAP = {
circle: {
...COMMON_DECKGL_PROPS,
Expand Down Expand Up @@ -164,6 +159,15 @@ export type GraphStylesheet<
> = {type: TType} &
GraphStylePropertyMap<TType, TValue> &
Partial<Record<GraphStyleSelector, GraphStylePropertyMap<TType, TValue>>>;
*/

import {StyleEngine, type DeckGLUpdateTriggers} from './style-engine';
import {
GraphStylesheetSchema,
GRAPH_DECKGL_ACCESSOR_MAP,
type GraphStylesheet,
type GraphStylesheetParsed
} from './graph-stylesheet.schema';

const GRAPH_DECKGL_UPDATE_TRIGGERS: DeckGLUpdateTriggers = {
circle: ['getFillColor', 'getRadius', 'getLineColor', 'getLineWidth'],
Expand All @@ -179,12 +183,55 @@ const GRAPH_DECKGL_UPDATE_TRIGGERS: DeckGLUpdateTriggers = {
arrow: ['getColor', 'getSize', 'getOffset']
};

function formatStylesheetError(error: ZodError) {
const details = error.issues
.map((issue) => {
const path = issue.path.length ? issue.path.join('.') : 'root';
return ` • ${path}: ${issue.message}`;
})
.join('\n');
return `Invalid graph stylesheet:\n${details}`;
}

export class GraphStyleEngine extends StyleEngine {
constructor(style: GraphStylesheet, {stateUpdateTrigger}: {stateUpdateTrigger?: unknown} = {}) {
super(style, {
let parsedStyle: GraphStylesheetParsed;
try {
parsedStyle = GraphStylesheetSchema.parse(style);
} catch (error) {
if (error instanceof ZodError) {
throw new Error(formatStylesheetError(error));
}
throw error;
}

super(parsedStyle as GraphStylesheet, {
deckglAccessorMap: GRAPH_DECKGL_ACCESSOR_MAP,
deckglUpdateTriggers: GRAPH_DECKGL_UPDATE_TRIGGERS,
stateUpdateTrigger
});
}
}

export {
GraphStyleScaleTypeEnum,
GraphStyleScaleSchema,
GraphStyleAttributeReferenceSchema,
GraphStyleLeafValueSchema,
GraphStyleStateMapSchema,
GraphStyleValueSchema,
GraphStylesheetSchema
} from './graph-stylesheet.schema';

export type {
GraphStyleAttributeReference,
GraphStyleLeafValue,
GraphStyleScale,
GraphStyleScaleType,
GraphStyleSelector,
GraphStyleType,
GraphStyleValue,
GraphStylesheet,
GraphStylesheetInput,
GraphStylesheetParsed
} from './graph-stylesheet.schema';
Loading