UNPKG

@macrostrat/column-components

Version:

React rendering primitives for stratigraphic columns

260 lines (249 loc) 10.8 kB
import $f5b828bbb980a05d$export$2e2bcd8739ae039 from "./column-components.de2f942b.js"; import {hasSpan as $4c0de4777a549324$export$edcf47b10d53ec33} from "./column-components.bdaf6e51.js"; import {FlexibleNode as $a0c6e663f4b9fd09$export$bbc681c531bc8538, Force as $a0c6e663f4b9fd09$export$ab7becc5aba9dee4, Node as $a0c6e663f4b9fd09$export$85c928794f8d04d4, Renderer as $a0c6e663f4b9fd09$export$88530751e3977073} from "./column-components.410c3de3.js"; import {ColumnContext as $c7Uig$ColumnContext, ColumnLayoutProvider as $c7Uig$ColumnLayoutProvider} from "./column-components.0ccab336.js"; import {createContext as $c7Uig$createContext, useContext as $c7Uig$useContext} from "react"; import {StatefulComponent as $c7Uig$StatefulComponent} from "@macrostrat/ui-components"; import {compareAgeRanges as $c7Uig$compareAgeRanges, AgeRangeRelationship as $c7Uig$AgeRangeRelationship} from "@macrostrat/stratigraphy-utils"; const $00c4b971e86fe1d8$export$20c7bffdb69233c9 = (0, $c7Uig$createContext)(null); const $00c4b971e86fe1d8$var$buildColumnIndex = function() { /* * Find out where on the X axis arrows, * etc. should plot to aviod overlaps */ const heightTracker = []; return function(note) { let colIx = 0; // Get column that note should render in const nPossibleCols = heightTracker.length + 1; for(let column = 0, end = nPossibleCols, asc = 0 <= end; asc ? column <= end : column >= end; asc ? column++ : column--){ if (heightTracker[column] == null) heightTracker[column] = note.height; if (heightTracker[column] < note.height) { const hy = note.top_height || note.height; heightTracker[column] = hy; colIx = column; break; } } return colIx; }; }; function $00c4b971e86fe1d8$var$withinDomain(scale) { const scaleDomain = scale.domain(); const d1 = [ Math.min(...scaleDomain), Math.max(...scaleDomain) ]; return (d)=>{ const noteRange = [ d.height, d.top_height ?? d.height ]; const rel = (0, $c7Uig$compareAgeRanges)(d1, noteRange); return rel !== (0, $c7Uig$AgeRangeRelationship).Disjoint; }; } class $00c4b971e86fe1d8$export$c48860e5e2301a05 extends (0, $c7Uig$StatefulComponent) { static{ this.contextType = (0, $c7Uig$ColumnContext); } static{ this.defaultProps = { paddingLeft: 60, estimatedTextHeight (note, width) { const txt = note.note || ""; return 12; } }; } constructor(props){ super(props); this.computeContextValue = this.computeContextValue.bind(this); this.savedRendererForWidth = this.savedRendererForWidth.bind(this); this.generatePath = this.generatePath.bind(this); this.createNodeForNote = this.createNodeForNote.bind(this); this.computeForceLayout = this.computeForceLayout.bind(this); this.updateHeight = this.updateHeight.bind(this); this.updateNotes = this.updateNotes.bind(this); this.componentDidMount = this.componentDidMount.bind(this); this.componentDidUpdate = this.componentDidUpdate.bind(this); // State is very minimal to start const { noteComponent: noteComponent } = this.props; this.state = { notes: [], elementHeights: {}, columnIndex: {}, nodes: {}, generatePath: this.generatePath, createNodeForNote: this.createNodeForNote, noteComponent: noteComponent }; } render() { const { children: children, width: width } = this.props; return (0, $f5b828bbb980a05d$export$2e2bcd8739ae039)($00c4b971e86fe1d8$export$20c7bffdb69233c9.Provider, { value: this.state }, (0, $f5b828bbb980a05d$export$2e2bcd8739ae039)((0, $c7Uig$ColumnLayoutProvider), { width: width }, children)); } computeContextValue() { const { width: width, paddingLeft: paddingLeft } = this.props; // Clamp notes to within scale boundaries // (we could turn this off if desired) const { scaleClamped: scale } = this.context; const forwardedValues = { paddingLeft: // Forwarded values from column context // There may be a more elegant way to do this paddingLeft, scale: scale, width: width }; // Compute force layout const renderer = new (0, $a0c6e663f4b9fd09$export$88530751e3977073)({ direction: "right", layerGap: paddingLeft, nodeHeight: 5 }); return this.setState({ renderer: renderer, updateHeight: this.updateHeight, generatePath: this.generatePath, ...forwardedValues }); } savedRendererForWidth(width) { if (this._rendererIndex == null) this._rendererIndex = {}; if (this._rendererIndex[width] == null) this._rendererIndex[width] = new (0, $a0c6e663f4b9fd09$export$88530751e3977073)({ direction: "right", layerGap: width, nodeHeight: 5 }); return this._rendererIndex[width]; } generatePath(node, pixelOffset) { const { paddingLeft: paddingLeft } = this.props; const renderer = this.savedRendererForWidth(paddingLeft - pixelOffset); try { return renderer.generatePath(node); } catch (err) { return null; } } createNodeForNote(note) { const { notes: notes, elementHeights: elementHeights } = this.state; let { scaleClamped: scale } = this.context; const { id: noteID } = note; const pixelHeight = elementHeights[noteID] || 10; const padding = 5; let noteHeight = scale(note.height); if ((0, $4c0de4777a549324$export$edcf47b10d53ec33)(note)) { const upperHeight = scale(note.top_height); const harr = [ noteHeight - padding, upperHeight + padding ]; if (harr[0] - harr[1] > 0) return new (0, $a0c6e663f4b9fd09$export$bbc681c531bc8538)(harr, pixelHeight); noteHeight = (harr[0] + harr[1]) / 2; } return new (0, $a0c6e663f4b9fd09$export$85c928794f8d04d4)(noteHeight, pixelHeight); } computeForceLayout(prevProps, prevState) { let { notes: notes, nodes: nodes, elementHeights: elementHeights } = this.state; const { pixelHeight: pixelHeight } = this.context; const { width: width, paddingLeft: paddingLeft, forceOptions: forceOptions } = this.props; if (notes.length === 0) return; // Something is wrong... //return if elementHeights.length < notes.length // Return if we've already computed nodes const v1 = Object.keys(nodes).length === notes.length; if (prevState == null) prevState = {}; const v2 = elementHeights === prevState.elementHeights || []; if (v1 && v2) return; const force = new (0, $a0c6e663f4b9fd09$export$ab7becc5aba9dee4)({ minPos: 0, maxPos: pixelHeight, nodeSpacing: 0, ...forceOptions }); const dataNodes = notes.map(this.createNodeForNote); force.nodes(dataNodes).compute(); const _nodes = force.nodes() ?? []; const nodesObj = {}; for(let i = 0; i < _nodes.length; i++){ const node = _nodes[i]; const note = notes[i]; nodesObj[note.id] = node; } return this.updateState({ nodes: { $set: nodesObj } }); } updateHeight(id, height) { if (height == null) return; const { elementHeights: elementHeights } = this.state; elementHeights[id] = height; return this.updateState({ elementHeights: { $set: elementHeights } }); } updateNotes() { // We received a new set of notes from props const { scaleClamped: scaleClamped } = this.context; const notes = this.props.notes.filter($00c4b971e86fe1d8$var$withinDomain(scaleClamped)).sort((a, b)=>a.height - b.height); const columnIndex = notes.map($00c4b971e86fe1d8$var$buildColumnIndex()); return this.setState({ notes: notes, columnIndex: columnIndex }); } /* * Lifecycle methods */ componentDidMount() { this._previousContext = null; this.updateNotes(); return this.computeContextValue(); } componentDidUpdate(prevProps, prevState) { if (this.props.notes !== prevProps.notes) this.updateNotes(); // Update note component const { noteComponent: noteComponent } = this.props; if (noteComponent !== prevProps.noteComponent) this.setState({ noteComponent: noteComponent }); this.computeForceLayout.call(prevProps, prevState); if (this.props.notes === prevProps.notes) return; if (this.context === this._previousContext) return; this.computeContextValue(); return this._previousContext = this.context; } } function $00c4b971e86fe1d8$export$b74b5a117fd60a1d(props) { let { padding: padding, width: width, ...rest } = props; if (padding == null) padding = 5; const { pixelHeight: pixelHeight } = (0, $c7Uig$useContext)((0, $c7Uig$ColumnContext)); if (width == null) ({ width: width } = (0, $c7Uig$useContext)($00c4b971e86fe1d8$export$20c7bffdb69233c9)); if (isNaN(width)) return null; return (0, $f5b828bbb980a05d$export$2e2bcd8739ae039)("rect", { width: width + 2 * padding, height: pixelHeight, transform: `translate(${-padding},${-padding})`, ...rest }); } const $00c4b971e86fe1d8$export$53f13bca8c4c45d9 = function({ ...rest }) { return (0, $f5b828bbb980a05d$export$2e2bcd8739ae039)($00c4b971e86fe1d8$export$b74b5a117fd60a1d, { className: "underlay", ...rest }); }; function $00c4b971e86fe1d8$export$77b5a6d4f65baae() { const ctx = (0, $c7Uig$useContext)($00c4b971e86fe1d8$export$20c7bffdb69233c9); if (ctx == null) throw new Error("useNoteLayout must be used within a NoteLayoutProvider"); return ctx; } export {$00c4b971e86fe1d8$export$20c7bffdb69233c9 as NoteLayoutContext, $00c4b971e86fe1d8$export$c48860e5e2301a05 as NoteLayoutProvider, $00c4b971e86fe1d8$export$b74b5a117fd60a1d as NoteRect, $00c4b971e86fe1d8$export$53f13bca8c4c45d9 as NoteUnderlay, $00c4b971e86fe1d8$export$77b5a6d4f65baae as useNoteLayout}; //# sourceMappingURL=column-components.fea107a9.js.map