Skip to content

Commit

Permalink
Support rendering layers of measurable SVG nodes in plexus (jaegertra…
Browse files Browse the repository at this point in the history
…cing#422)

Support rendering layers of measurable SVG nodes in plexus
Signed-off-by: vvvprabhakar <vvvprabhakar@gmail.com>
  • Loading branch information
tiffon committed Jul 26, 2019
2 parents 339d00d + 78631cd commit f3f2482
Show file tree
Hide file tree
Showing 11 changed files with 276 additions and 176 deletions.
4 changes: 2 additions & 2 deletions packages/plexus/demo/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ html {
}

.DemoGraph {
border: 1px solid #666;
border: 1px solid #bbb;
cursor: move;
overflow: hidden;
height: 700px;
Expand All @@ -42,7 +42,7 @@ html {
}

.DemoGraph--dag {
background: #f0f0f0;
background: #fafafa;
stroke-width: 0.85;
}

Expand Down
67 changes: 59 additions & 8 deletions packages/plexus/demo/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { TVertex, TLayoutEdge, TLayoutVertex } from '../../src/types';

import './index.css';
import TNonEmptyArray from '../../src/types/TNonEmptyArray';
import { TLayer } from '../../src/LayeredDigraph/types';
import { TLayer, TRendererUtils, TMeasureNodeUtils } from '../../src/LayeredDigraph/types';

type TState = {
hoveredEdge: TLayoutEdge<any> | null;
Expand Down Expand Up @@ -172,14 +172,14 @@ class Demo extends React.PureComponent<{}, TState> {
layers: [
{
key: 'emph-nodes',
nodeRender: (lv: TLayoutVertex<any>) =>
renderNode: (lv: TLayoutVertex<any>) =>
VOWELS.has(lv.vertex.key[0]) ? <div className="DemoGraph--node--emphasized" /> : null,
},
{
setOnNode,
key: 'main-nodes',
measurable: true,
nodeRender: getLargeNodeLabel,
renderNode: getLargeNodeLabel,
},
],
},
Expand Down Expand Up @@ -213,7 +213,7 @@ class Demo extends React.PureComponent<{}, TState> {
{
key: 'emph-nodes-border',
layerType: 'svg',
nodeRender: (lv: TLayoutVertex<any>) =>
renderNode: (lv: TLayoutVertex<any>) =>
!VOWELS.has(lv.vertex.key[0]) ? null : (
<g>
<rect
Expand All @@ -228,7 +228,7 @@ class Demo extends React.PureComponent<{}, TState> {
{
key: 'emph-nodes-html',
layerType: 'html',
nodeRender: (lv: TLayoutVertex<any>) =>
renderNode: (lv: TLayoutVertex<any>) =>
VOWELS.has(lv.vertex.key[0]) ? <div className="DemoGraph--node--emphasized" /> : null,
},
{
Expand All @@ -237,7 +237,7 @@ class Demo extends React.PureComponent<{}, TState> {
layers: [
{
key: 'emph-nodes',
nodeRender: (lv: TLayoutVertex<any>) =>
renderNode: (lv: TLayoutVertex<any>) =>
!VOWELS.has(lv.vertex.key[0]) ? null : (
<g>
<rect
Expand All @@ -251,7 +251,7 @@ class Demo extends React.PureComponent<{}, TState> {
},
{
key: 'border-nodes',
nodeRender: (lv: TLayoutVertex<any>) => (
renderNode: (lv: TLayoutVertex<any>) => (
<rect
className="DemoGraph--node--vectorBorder"
vectorEffect="non-scaling-stroke"
Expand All @@ -267,7 +267,7 @@ class Demo extends React.PureComponent<{}, TState> {
key: 'nodes',
layerType: 'html',
measurable: true,
nodeRender: getLargeNodeLabel,
renderNode: getLargeNodeLabel,
},
{
key: 'edges-visible-path',
Expand All @@ -291,6 +291,57 @@ class Demo extends React.PureComponent<{}, TState> {
},
hoveredEdge
)}
<h1>LayeredDigraph with measurable SVG nodes</h1>
<div>
<div className="DemoGraph">
<LayeredDigraph
zoom
minimap
className="DemoGraph--dag"
layoutManager={new LayoutManager({ useDotEdges: true })}
minimapClassName="Demo--miniMap"
setOnGraph={layeredClassNameIsSmall}
measurableNodesKey="nodes"
layers={[
{
key: 'edges',
defs: [{ localId: 'arrowHead' }],
edges: true,
layerType: 'svg',
markerEndId: 'arrowHead',
setOnContainer: [{ className: 'DdgGraph--edges' }, scaleProperty.strokeOpacity],
},
{
key: 'nodes',
layerType: 'svg',
measurable: true,
measureNode: (_: any, utils: TMeasureNodeUtils) => {
const { height, width } = utils.getWrapperSize();
return { height: height + 40, width: width + 40 };
},
renderNode: (vertex: TVertex, utils: TRendererUtils, lv: TLayoutVertex | null) => (
<>
{lv && (
<rect
width={lv.width}
height={lv.height}
fill="#ddd"
stroke="#444"
strokeWidth="1"
vectorEffect="non-scaling-stroke"
/>
)}
<text x="20" y="20" dy="1em">
{vertex.key}
</text>
</>
),
},
]}
{...largeDag}
/>
</div>
</div>
<h1>Directed graph with cycles - dot edges</h1>
<div>
<div className="DemoGraph">
Expand Down
10 changes: 5 additions & 5 deletions packages/plexus/src/LayeredDigraph/HtmlLayersGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,30 +34,30 @@ export default class HtmlLayersGroup<T = {}, U = {}> extends React.PureComponent
const { key, setOnContainer } = layer;

if (layer.measurable) {
const { nodeRender, setOnNode } = layer;
const { renderNode, setOnNode } = layer;
return (
<MeasurableNodesLayer<T, U>
key={key}
getClassName={getClassName}
graphState={graphState}
layerType={ELayerType.Html}
nodeRender={nodeRender}
renderNode={renderNode}
senderKey={key}
setOnContainer={setOnContainer}
setOnNode={setOnNode}
setSizeVertices={setSizeVertices}
/>
);
}
if (layer.nodeRender) {
const { nodeRender, setOnNode } = layer;
if (layer.renderNode) {
const { renderNode, setOnNode } = layer;
return (
<NodesLayer<T, U>
key={key}
getClassName={getClassName}
graphState={graphState}
layerType={ELayerType.Html}
nodeRender={nodeRender}
renderNode={renderNode}
setOnContainer={setOnContainer}
setOnNode={setOnNode}
/>
Expand Down
55 changes: 0 additions & 55 deletions packages/plexus/src/LayeredDigraph/MeasurableHtmlNode.tsx

This file was deleted.

111 changes: 111 additions & 0 deletions packages/plexus/src/LayeredDigraph/MeasurableNode.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright (c) 2019 Uber Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import * as React from 'react';

import { TMeasurableNodeRenderer, TLayerType, TRendererUtils, ELayerType } from './types';
import { assignMergeCss, getProps } from './utils';
import { TLayoutVertex, TVertex } from '../types';

type TProps<T = {}> = Omit<TMeasurableNodeRenderer<T>, 'measurable'> & {
getClassName: (name: string) => string;
hidden: boolean;
layerType: TLayerType;
layoutVertex: TLayoutVertex<T> | null;
renderUtils: TRendererUtils;
vertex: TVertex<T>;
};

const SVG_HIDDEN_STYLE = { visibility: 'hidden' };

export default class MeasurableHtmlNode<T = {}> extends React.PureComponent<TProps<T>> {
htmlRef: React.RefObject<HTMLDivElement> = React.createRef();
svgRef: React.RefObject<SVGGElement> = React.createRef();

private measureHtml() {
const { current } = this.htmlRef;
if (!current) {
return { height: 0, width: 0 };
}
return {
height: current.offsetHeight,
width: current.offsetWidth,
};
}

private measureSvg() {
const { current } = this.svgRef;
if (!current) {
return { height: 0, width: 0 };
}
const { height, width } = current.getBBox();
return { height, width };
}

private renderHtml() {
const { getClassName, hidden, renderNode, renderUtils, setOnNode, vertex, layoutVertex } = this.props;
const { height = null, left = null, top = null, width = null } = layoutVertex || {};
const props = assignMergeCss(getProps(setOnNode, vertex, renderUtils, layoutVertex), {
className: getClassName('MeasurableHtmlNode'),
style: {
height,
width,
boxSizing: 'border-box',
position: 'absolute',
transform:
left == null || top == null ? undefined : `translate(${left.toFixed()}px,${top.toFixed()}px)`,
visibility: hidden ? 'hidden' : undefined,
},
});
return (
<div ref={this.htmlRef} {...props}>
{renderNode(vertex, renderUtils, layoutVertex)}
</div>
);
}

private renderSvg() {
const { getClassName, hidden, renderNode, renderUtils, setOnNode, vertex, layoutVertex } = this.props;
const { left = null, top = null } = layoutVertex || {};
const props = assignMergeCss(getProps(setOnNode, vertex, renderUtils, layoutVertex), {
className: getClassName('MeasurableSvgNode'),
transform: left == null || top == null ? undefined : `translate(${left.toFixed()}, ${top.toFixed()})`,
style: hidden ? SVG_HIDDEN_STYLE : null,
});
return (
<g ref={this.svgRef} {...props}>
{renderNode(vertex, renderUtils, layoutVertex)}
</g>
);
}

getRef() {
if (this.props.layerType === ELayerType.Html) {
return { htmlWrapper: this.htmlRef.current, svgWrapper: undefined };
}
return { svgWrapper: this.svgRef.current, htmlWrapper: undefined };
}

measure() {
return this.props.layerType === ELayerType.Html ? this.measureHtml() : this.measureSvg();
}

render() {
const { layerType } = this.props;
if (layerType === ELayerType.Html) {
return this.renderHtml();
}
return this.renderSvg();
}
}
Loading

0 comments on commit f3f2482

Please sign in to comment.