UNPKG

@macrostrat/column-components

Version:

React rendering primitives for stratigraphic columns

165 lines (139 loc) 3.55 kB
import labella from "labella"; const { Node, Renderer, Force } = labella; export class FlexibleNode { allowedRange: [number, number]; centerPos: number; currentPos: number; width: number; data: any | null; layerIndex: number; parent: FlexibleNode | null; child: FlexibleNode | null; constructor( allowedRange: [number, number], width: number, data: any | null = null, ) { this.allowedRange = allowedRange; this.centerPos = (this.allowedRange[0] + this.allowedRange[1]) / 2; this.currentPos = this.centerPos; this.width = width; this.data = data; this.layerIndex = 0; } get idealPos() { const [end, start] = this.allowedRange; if (this.currentPos < start) { return start; } if (this.currentPos > end) { return end; } return this.currentPos; } // return negative if overlap distanceFrom(node) { const halfWidth = this.width / 2; const nodeHalfWidth = node.width / 2; // max(a[0], b[0]) - min(a[1], b[1]) return ( Math.max(this.currentPos - halfWidth, node.currentPos - nodeHalfWidth) - Math.min(this.currentPos + halfWidth, node.currentPos + nodeHalfWidth) ); } moveToIdealPosition() { this.currentPos = this.idealPos; return this; } displacement() { return this.idealPos - this.currentPos; } overlapWithNode(node, buffer = 0) { return this.distanceFrom(node) - buffer < 0; } overlapWithPoint(pos) { const halfWidth = this.width / 2; return ( pos >= this.currentPos - halfWidth && pos <= this.currentPos + halfWidth ); } positionBefore(node, buffer = 0) { return node.currentLeft() - this.width / 2 - buffer; } positionAfter(node, buffer = 0) { return node.currentRight() + this.width / 2 + buffer; } currentRight() { return this.currentPos + this.width / 2; } currentLeft() { return this.currentPos - this.width / 2; } idealRight() { return this.idealPos + this.width / 2; } idealLeft() { return this.idealPos - this.width / 2; } createStub(width) { const stub = new Node(this.idealPos, width, this.data); stub.currentPos = this.currentPos; stub.child = this; this.parent = stub; return stub; } removeStub() { if (this.parent) { this.parent.child = null; this.parent = null; } return this; } isStub() { return !!this.child; } getPathToRoot() { const path = []; let current: FlexibleNode = this; while (current) { path.push(current); current = current.parent; } return path; } getPathFromRoot() { return this.getPathToRoot().reverse(); } getPathToRootLength() { let length = 0; let current: FlexibleNode = this; while (current) { const targetPos = current.parent ? current.parent.currentPos : current.idealPos; length += Math.abs(current.currentPos - targetPos); current = current.parent; } return length; } // Trace back to the node without parent getRoot() { let previous: FlexibleNode = this; let current: FlexibleNode = this; while (current) { previous = current; current = current.parent; } return previous; } getLayerIndex() { return this.layerIndex; } clone() { const node = new FlexibleNode(this.allowedRange, this.width, this.data); node.currentPos = this.currentPos; node.layerIndex = this.layerIndex; return node; } } export { Node, Renderer, Force };