react-occult
Version:
Layered Information Visualization based on React and D3
227 lines (205 loc) • 5.54 kB
JavaScript
import * as React from 'react';
import Annotation from '../Annotation';
import AnnotationCalloutCircle from 'react-annotation/lib/Types/AnnotationCalloutCircle';
import { packEnclose } from 'd3-hierarchy';
import HullEnclosure from './widgets/HullEnclosure';
import RectangleEnclosure from './widgets/RectangleEnclosure';
import CircleEnclosure from './widgets/CircleEnclosure';
import SpanOrDiv from '../../widgets/SpanOrDiv';
export const htmlFrameHoverRule = ({
d: baseD,
i,
tooltipContent,
useSpans,
nodes,
edges,
nodeIDAccessor
}) => {
const d =
baseD.x && baseD.y
? baseD
: baseD.edge
? {
...(edges.find(
p =>
nodeIDAccessor(p.source) === nodeIDAccessor(baseD.source) &&
nodeIDAccessor(p.target) === nodeIDAccessor(baseD.target)
) || {}),
...baseD
}
: nodes.find(p => nodeIDAccessor(p) === baseD.id);
if (!d) return null;
let content = d.edge ? (
<SpanOrDiv span={useSpans} className="tooltip-content">
<p key="html-annotation-content-1">
{(d.source || d.edge.source).id} to {(d.target || d.edge.target).id}
</p>
</SpanOrDiv>
) : (
<SpanOrDiv span={useSpans} className="tooltip-content">
<p key="html-annotation-content-1">{d.id}</p>
<p key="html-annotation-content-2">Degree: {d.degree}</p>
</SpanOrDiv>
);
if (d.type === 'frame-hover' && tooltipContent) {
content = tooltipContent(d);
}
return (
<SpanOrDiv
span={useSpans}
key={`network-annotation-label-${i}`}
className={`annotation annotation-network-label ${d.className || ''}`}
style={{
position: 'absolute',
top: `${d.y}px`,
left: `${d.x}px`
}}
>
{content}
</SpanOrDiv>
);
};
export const svgNodeRule = ({ d, i, nodeSizeAccessor }) => {
if (!d) {
return null;
}
const noteData = Object.assign(
{
dx: d.dx || -25,
dy: d.dy || -25,
x: d.x,
y: d.y,
note: { label: d.label, orientation: d.orientation, align: d.align },
connector: { end: 'arrow' }
},
d,
{
type: AnnotationCalloutCircle,
subject: {
radius: d.radius || d.radius || nodeSizeAccessor(d)
}
}
);
return <Annotation key={d.key || `annotation-${i}`} noteData={noteData} />;
};
export const svgReactAnnotationRule = ({
d,
i,
projectedNodes,
nodeIDAccessor
}) => {
const selectedNode =
d.x && d.y ? d : projectedNodes.find(p => nodeIDAccessor(p) === d.id);
if (!selectedNode) {
return null;
}
const noteData = Object.assign(
{
dx: 0,
dy: 0,
x: selectedNode.x,
y: selectedNode.y,
note: { label: d.label },
connector: { end: 'arrow' }
},
d,
{ type: typeof d.type === 'function' ? d.type : undefined }
);
return <Annotation key={d.key || `annotation-${i}`} noteData={noteData} />;
};
export const svgEncloseRule = ({
d,
i,
projectedNodes,
nodeIDAccessor,
nodeSizeAccessor
}) => {
const selectedNodes = projectedNodes.filter(
p => d.ids.indexOf(nodeIDAccessor(p)) !== -1
);
if (selectedNodes.length === 0) {
return null;
}
const circle = packEnclose(
selectedNodes.map(p => ({ x: p.x, y: p.y, r: nodeSizeAccessor(p) }))
);
return CircleEnclosure({ circle, d, i });
};
export const svgRectEncloseRule = ({
d,
i,
projectedNodes,
nodeIDAccessor,
nodeSizeAccessor
}) => {
const selectedNodes = projectedNodes.filter(
p => d.ids.indexOf(nodeIDAccessor(p)) !== -1
);
if (selectedNodes.length === 0) {
return null;
}
const bboxNodes = selectedNodes.map(p => {
if (p.shapeNode) {
return {
x0: p.x0,
x1: p.x1,
y0: p.y0,
y1: p.y1
};
}
const nodeSize = nodeSizeAccessor(p);
return {
x0: p.x - nodeSize,
x1: p.x + nodeSize,
y0: p.y - nodeSize,
y1: p.y + nodeSize
};
});
return RectangleEnclosure({ bboxNodes, d, i });
};
export const svgHullEncloseRule = ({
d,
i,
projectedNodes,
nodeIDAccessor,
nodeSizeAccessor
}) => {
const selectedNodes = projectedNodes.filter(
p => d.ids.indexOf(nodeIDAccessor(p)) !== -1
);
if (selectedNodes.length === 0) {
return null;
}
const projectedPoints = [];
selectedNodes.forEach(p => {
if (p.shapeNode) {
projectedPoints.push({ x: p.x0, y: p.y0 });
projectedPoints.push({ x: p.x0, y: p.y1 });
projectedPoints.push({ x: p.x1, y: p.y0 });
projectedPoints.push({ x: p.x1, y: p.y1 });
} else {
const nodeSize = nodeSizeAccessor(p);
projectedPoints.push({ x: p.x - nodeSize, y: p.y - nodeSize });
projectedPoints.push({ x: p.x + nodeSize, y: p.y - nodeSize });
projectedPoints.push({ x: p.x - nodeSize, y: p.y + nodeSize });
projectedPoints.push({ x: p.x + nodeSize, y: p.y + nodeSize });
}
});
return HullEnclosure({ points: projectedPoints.map(d => [d.x, d.y]), d, i });
};
export const svgHighlightRule = ({
d,
customNodeIcon: customMark,
nodeStyle: baseStyle
}) => {
let styleFn = baseStyle;
if (d.style && typeof d.style === 'function') {
styleFn = d => ({ ...baseStyle(d), ...d.style(d) });
} else if (d.style) {
styleFn = d => ({ ...baseStyle(d), ...d.style });
}
const transform = `translate(${d.x},${d.y})`;
const baseMarkProps = { forceUpdate: true };
const HighlightMark = customMark({ d, styleFn, transform, baseMarkProps });
return HighlightMark;
};