UNPKG

@nteract/data-explorer

Version:
195 lines (194 loc) 8.36 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.semioticHierarchicalChart = void 0; const d3_collection_1 = require("d3-collection"); const d3_interpolate_1 = require("d3-interpolate"); const React = __importStar(require("react")); const tooltip_content_1 = __importDefault(require("../utilities/tooltip-content")); const overrideFrameHover = (hierarchyType) => (annotation) => { const { d } = annotation; if (d.type === "frame-hover" && hierarchyType !== "treemap") { return; } return null; }; const hierarchicalAnnotation = (hierarchyType, selectedDimensions, metric) => (annotation) => { const { d, networkFrameState, nodes: drawnNodes } = annotation; const { type, parent } = d; const { networkFrameRender } = networkFrameState; if (hierarchyType !== "treemap" && parent && type === "highlight") { const { nodes } = networkFrameRender; const { customMark, styleFn: baseStyle } = nodes; const ancestors = parent.ancestors(); const parentPlusPieces = [parent, ...ancestors]; const drawnPieces = parentPlusPieces.map((d) => drawnNodes.find((p) => (p.depth === 0 && d.depth === 0) || p.hierarchicalID === d.hierarchicalID)); const allPieces = [d, ...drawnPieces]; const baseMarkProps = { forceUpdate: true }; const ancestorHighlight = allPieces.map((node, nodei) => { const transform = `translate(${node.x},${node.y})`; const styleFn = (d) => (Object.assign(Object.assign({}, baseStyle(d)), { fill: "red", opacity: 0.5, stroke: "red", strokeWidth: "4px" })); const customNode = customMark({ d: node, styleFn, transform: transform, baseMarkProps, key: `highlight-${nodei}-parent`, }); const thisLevelName = selectedDimensions[node.depth - 1]; return (React.createElement("g", null, customNode, React.createElement("text", { transform: transform }, thisLevelName && `${thisLevelName}: ${node.key}`, node.depth !== 0 && node[metric] && `${metric}: ${node[metric]}`))); }); return React.createElement("g", null, ancestorHighlight); } return null; }; const parentPath = (datapoint, pathArray) => { if (datapoint.parent) { pathArray = parentPath(datapoint.parent, [datapoint.key, ...pathArray]); } else { pathArray = [...pathArray]; } return pathArray; }; const hierarchicalTooltip = (datapoint, primaryKey, metric, selectedDimensions) => { const pathString = datapoint.parent ? parentPath(datapoint.parent, (datapoint.key && [datapoint.key]) || []).map((d, i) => (React.createElement("p", null, selectedDimensions[i], ": ", d))) : ""; const content = []; if (!datapoint.parent) { content.push(React.createElement("h2", { key: "hierarchy-title" }, "Root")); } else if (datapoint.key) { content.push(React.createElement("h2", { key: "hierarchy-title" }, datapoint.key)); content.push(React.createElement("p", { key: "path-string" }, pathString)); content.push(React.createElement("p", { key: "hierarchy-value" }, "Total Value: ", datapoint.value)); content.push(React.createElement("p", { key: "hierarchy-children" }, "Children: ", datapoint.children.length)); } else { content.push(pathString, React.createElement("p", { key: "leaf-label" }, primaryKey.map((pkey) => datapoint[pkey]).join(", "))); content.push(React.createElement("p", { key: "hierarchy-value" }, metric, ": ", datapoint[metric])); } return content; }; const hierarchicalColor = (colorHash, datapoint) => { if (datapoint.depth === 0) { return "white"; } if (datapoint.depth === 1) { return colorHash[datapoint.key]; } let colorNode = datapoint; for (let x = datapoint.depth; x > 1; x--) { colorNode = colorNode.parent; } const lightenScale = d3_interpolate_1.interpolateLab("white", colorHash[colorNode.key]); return lightenScale(Math.max(0, datapoint.depth / 6)); }; exports.semioticHierarchicalChart = (data, schema, options, colorHashOverride, colorDimOverride) => { const { hierarchyType: baseHierarchyType = "dendrogram", chart, selectedDimensions, primaryKey, colors, } = options; const { metric1 } = chart; // a sunburst is just a radial partition const hierarchyType = baseHierarchyType === "sunburst" ? "partition" : baseHierarchyType; if (selectedDimensions.length === 0) { return {}; } const nestingParams = d3_collection_1.nest(); selectedDimensions.forEach((dim) => { nestingParams.key((param) => param[dim]); }); const colorHash = colorHashOverride || {}; const sanitizedData = []; data.forEach((datapoint) => { if (!colorDimOverride && !colorHash[datapoint[selectedDimensions[0]]]) { colorHash[datapoint[selectedDimensions[0]]] = colors[Object.keys(colorHash).length]; } sanitizedData.push(Object.assign(Object.assign({}, datapoint), { sanitizedR: datapoint.r, r: undefined })); }); const entries = nestingParams.entries(sanitizedData.sort((a, b) => a[metric1] - b[metric1])); const rootNode = { id: "all", values: entries }; const hierarchySettings = { edges: rootNode, edgeStyle: () => ({ fill: "lightgray", stroke: "gray" }), nodeStyle: (node) => { return { fill: hierarchicalColor(colorHash, node), stroke: node.depth === 1 ? "white" : "black", strokeOpacity: node.depth * 0.1 + 0.2, }; }, networkType: { type: hierarchyType, projection: baseHierarchyType === "sunburst" && "radial", hierarchySum: (node) => node[metric1], hierarchyChildren: (node) => node.values, padding: hierarchyType === "treemap" ? 3 : 0, zoom: false, }, edgeRenderKey: (edge, index) => { return index; }, nodeIDAccessor: (d, i) => d.id || d.key || i, baseMarkProps: { forceUpdate: true }, margin: { left: 10, right: 10, top: 10, bottom: 10 }, hoverAnnotation: [ { type: "frame-hover" }, { type: "highlight", style: { stroke: "red", strokeOpacity: 0.5, strokeWidth: 5, fill: "none", }, }, ], svgAnnotationRules: hierarchicalAnnotation(hierarchyType, selectedDimensions, metric1), htmlAnnotationRules: overrideFrameHover(hierarchyType), tooltipContent: (hoveredDatapoint) => { return (React.createElement(tooltip_content_1.default, { x: hoveredDatapoint.x, y: hoveredDatapoint.y }, hierarchicalTooltip(hoveredDatapoint, primaryKey, metric1, selectedDimensions))); }, }; return { frameSettings: hierarchySettings, colorDim: selectedDimensions[0], colorHash, }; };