@macrostrat/column-components
Version:
React rendering primitives for stratigraphic columns
139 lines (121 loc) • 3.31 kB
text/typescript
import { Component, useContext } from "react";
import h from "@macrostrat/hyper";
import classNames from "classnames";
import {
ColumnContext,
AssetPathContext,
ColumnCtx,
ColumnDivision,
AssetPathCtx,
} from "./context";
import { UUIDComponent } from "./frame";
const symbolIndex = {
"Hummocky cross-stratified": "hcs.svg",
"Trough cross-stratified": "tcs.svg",
"Dessication cracks": "dessication-cracks.svg",
Ooids: "ooids.svg",
"Domal stromatolites": "domal-stromatolites.svg",
"Digitate stromatolites": "digitate-stromatolites.svg",
};
const Symbol = function (props) {
const { symbol, width, height, UUID } = props;
const { resolveSymbol } = useContext(AssetPathContext);
const id = `${UUID}-${symbol}`;
const symbolSize = { width };
const href = resolveSymbol(symbolIndex[symbol]);
return h(
"symbol",
{
id,
key: id,
...symbolSize,
},
[
h("image", {
href,
x: 0,
y: 0,
...symbolSize,
}),
],
);
};
const SymbolDefs = function (props) {
const { patterns, ...rest } = props;
const ids = [];
return h(
"defs",
patterns.map(function (sym) {
const { symbol } = sym;
if (ids.includes(symbol)) {
return null;
}
ids.push(symbol);
return h(Symbol, { symbol, ...rest });
}),
);
};
interface SymbolColumnProps {
width: number;
left: number;
symbols: any[];
}
export class SymbolColumn extends UUIDComponent<SymbolColumnProps> {
constructor(props) {
super(props);
this.renderSymbol = this.renderSymbol.bind(this);
}
static contextType = ColumnContext;
context: ColumnCtx<ColumnDivision>;
static defaultProps = {
width: 30,
left: 0,
};
render() {
const { scale, pixelHeight, zoom } = this.context;
const { left, width } = this.props;
let { symbols } = this.props;
const patterns = symbols.filter((x, i, arr) => arr.indexOf(x) === i);
let transform = null;
if (left != null) {
transform = `translate(${left})`;
}
symbols = symbols
.filter((d) => d.symbol_min_zoom < zoom)
.map(this.renderSymbol);
const x = 0;
const y = 0;
return h("g.symbol-column", { transform }, [
h(SymbolDefs, { width, patterns, UUID: this.UUID }),
h("rect.symbol-column-area", { width, height: pixelHeight }),
h("g.symbols", symbols),
]);
}
renderSymbol(d) {
const { scale, pixelHeight } = this.context;
const { symbol, id, height } = d;
const className = classNames({ symbol }, "symbol");
const { width } = this.props;
const y = scale(height) - width / 2;
if (y < 0 || y > pixelHeight) return null;
const href = `#${this.UUID}-${symbol}`;
return h("use", { className, y, x: 0, width, xlinkHref: href, key: id });
}
}
export class SymbolLegend extends Component {
static contextType = AssetPathContext;
context: AssetPathCtx;
render() {
const { resolveSymbol } = this.context;
const arr = [];
for (let name in symbolIndex) {
const symbol = symbolIndex[name];
const sym = h("div", { key: name }, [
h("img", { src: resolveSymbol(symbol) }),
h("span.label", name),
]);
arr.push(sym);
}
return h("div.symbol-legend", arr);
}
}