import React from 'react'; import { CompositeLayer, Layer } from 'deck.gl'; import { IconLayer, LineLayer, TextLayer } from '@deck.gl/layers'; import { CompositeLayerType, LayerProps } from '../../mapvis.types'; import { BrushingExtension, CollisionFilterExtension } from '@deck.gl/extensions'; import { Node } from '@graphpolaris/shared/lib/data-access'; import { createIcon } from './shapeFactory'; export class NodeLinkLayer extends CompositeLayer<CompositeLayerType> { static type = 'nodelink'; private _layers: Record<string, Layer> = {}; constructor(props: LayerProps) { super(props); } updateState({ changeFlags }: { changeFlags: any }) { return changeFlags.propsOrDataChanged || changeFlags.somethingChanged; } renderLayers() { const { data, settings, getNodeLocation, ml, graphMetadata } = this.props; const layerSettings = settings[NodeLinkLayer.type]; const brushingExtension = new BrushingExtension(); const collisionFilter = new CollisionFilterExtension(); graphMetadata.edges.labels.forEach((label: string) => { const layerId = `${label}-edges-line`; const edgeData = data.edges; this._layers[layerId] = new LineLayer({ id: layerId, data: edgeData, visible: !layerSettings.edges[label].hidden, pickable: true, getWidth: layerSettings.edges[label].width, getSourcePosition: (d) => getNodeLocation(d.from), getTargetPosition: (d) => getNodeLocation(d.to), getColor: (d) => layerSettings.edges[d.label].color, extensions: [brushingExtension], brushingEnabled: layerSettings.enableBrushing, }); }); if (ml?.linkPrediction?.enabled) { this._layers['link_prediction'] = new LineLayer({ id: 'link-prediction-layer', data: ml.linkPrediction.result, pickable: false, getWidth: 1, getSourcePosition: (d) => getNodeLocation(d.from), getTargetPosition: (d) => getNodeLocation(d.to), getColor: (d) => [0, 0, 0], }); } graphMetadata.nodes.labels.forEach((label: string) => { const layerId = `${label}-nodes-scatterplot`; this._layers[layerId] = new IconLayer({ id: layerId, visible: !layerSettings.nodes[label].hidden, data: data.nodes.filter((node: Node) => node.label === label), pickable: true, getColor: (d) => [200, 140, 0], getSize: (d) => layerSettings.nodes[label].size, getPosition: (d) => getNodeLocation(d._id), getIcon: (d: any) => { return { url: createIcon(layerSettings.nodes[label].shape, layerSettings.nodes[label].color), width: 24, height: 24, }; }, }); }); const textLayerId = 'label-target'; this._layers[textLayerId] = new TextLayer({ id: textLayerId, data: data.nodes, getPosition: (d: any) => getNodeLocation(d._id), getText: (d: any) => d.id, getSize: 15, visible: true, getAlignmentBaseline: 'top', background: true, getPixelOffset: [10, 10], extensions: [collisionFilter], collisionEnabled: true, getCollisionPriority: (d: any) => d.id, collisionTestProps: { sizeScale: 10 }, getRadius: 10, radiusUnits: 'pixels', collisionGroup: 'text', }); return Object.values(this._layers); } } NodeLinkLayer.layerName = 'NodeLink';