Skip to content
Snippets Groups Projects
Commit 61bbb8c6 authored by Loïc Correnson's avatar Loïc Correnson
Browse files

[dome/diagram] color model

parent 3a879730
No related branches found
No related tags found
No related merge requests found
...@@ -26,6 +26,7 @@ import { classes } from 'dome/misc/utils'; ...@@ -26,6 +26,7 @@ import { classes } from 'dome/misc/utils';
import { Size } from 'react-virtualized'; import { Size } from 'react-virtualized';
import * as d3 from 'd3-graphviz'; import * as d3 from 'd3-graphviz';
import AutoSizer from 'react-virtualized-auto-sizer'; import AutoSizer from 'react-virtualized-auto-sizer';
import './style.css';
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* --- Graph Specifications --- */ /* --- Graph Specifications --- */
...@@ -33,13 +34,27 @@ import AutoSizer from 'react-virtualized-auto-sizer'; ...@@ -33,13 +34,27 @@ import AutoSizer from 'react-virtualized-auto-sizer';
export type Direction = 'LR' | 'TD'; export type Direction = 'LR' | 'TD';
export type Cell = string | { label: string, port: string }; export type Color =
| 'white'
| 'grey'
| 'dark'
| 'primary'
| 'selected'
| 'green'
| 'orange'
| 'red'
| 'yellow'
| 'blue'
| 'pink';
export type Shape = export type Shape =
| 'point' | 'box' | 'point' | 'box'
| 'diamond' | 'hexagon' | 'diamond' | 'hexagon'
| 'circle' | 'ellipse' | 'circle' | 'ellipse'
| 'note' | 'tab' | 'folder'; | 'note' | 'tab' | 'folder';
export type Cell = string | { label: string, port: string };
export type Box = Cell | Box[]; export type Box = Cell | Box[];
export interface Node { export interface Node {
...@@ -49,9 +64,12 @@ export interface Node { ...@@ -49,9 +64,12 @@ export interface Node {
label?: string; label?: string;
/** Node tooltip */ /** Node tooltip */
title?: string; title?: string;
/** Node color (filled background) */
color?: Color;
/** /**
* Shape. Box shapes alternate LR and TD directions. * Shape. Nested boxes alternate LR and TD directions. Initial direction is
* Initial direction is orthogonal to the graph direction. */ * orthogonal to the graph direction. Node label is ignored for box layout.
*/
shape?: Shape | Box[]; shape?: Shape | Box[];
} }
...@@ -100,6 +118,38 @@ export interface DiagramProps { ...@@ -100,6 +118,38 @@ export interface DiagramProps {
} }
/* -------------------------------------------------------------------------- */
/* --- Color Model --- */
/* -------------------------------------------------------------------------- */
const BGCOLOR = {
'white': '#fff',
'grey': '#ccc',
'dark': '#666',
'primary': 'dodgerblue',
'selected': 'deepskyblue',
'green': 'lime',
'orange': '#ffa700',
'red': 'red',
'yellow': 'yellow',
'blue': 'cyan',
'pink': 'hotpink',
};
const FGCOLOR = {
'white': 'black',
'grey': 'black',
'dark': 'white',
'primary': 'white',
'selected': 'black',
'green': 'black',
'orange': 'black',
'red': 'white',
'yellow': 'black',
'blue': 'black',
'pink': 'white',
};
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* --- Dot Model --- */ /* --- Dot Model --- */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
...@@ -172,8 +222,11 @@ class DotModel { ...@@ -172,8 +222,11 @@ class DotModel {
.attr('label', n.label) .attr('label', n.label)
.attr('shape', n.shape); .attr('shape', n.shape);
} }
const color = n.color ?? 'white';
this this
.attr('tooltip', n.title) .attr('tooltip', n.title)
.attr('fontcolor', FGCOLOR[color])
.attr('fillcolor', BGCOLOR[color])
.println('];'); .println('];');
} }
...@@ -210,14 +263,16 @@ interface GraphvizProps extends DiagramProps { size: Size } ...@@ -210,14 +263,16 @@ interface GraphvizProps extends DiagramProps { size: Size }
function GraphvizView(props: GraphvizProps): JSX.Element { function GraphvizView(props: GraphvizProps): JSX.Element {
// --- Model Generation // --- Model Generation
const { direction = 'LR', nodes, edges } = props; const {
direction = 'LR', nodes, edges
} = props;
const model = React.useMemo(() => { const model = React.useMemo(() => {
const dot = new DotModel(); const dot = new DotModel();
dot dot
.attr('rankdir', direction) .attr('rankdir', direction)
.attr('bgcolor', 'none') .attr('bgcolor', 'none')
.attr('width', 0.5) .attr('width', 0.5)
.println(); .println('node [ style="filled" ];');
nodes.concat().sort(byNode).forEach(n => dot.node(n)); nodes.concat().sort(byNode).forEach(n => dot.node(n));
edges.concat().sort(byEdge).forEach(e => dot.edge(e)); edges.concat().sort(byEdge).forEach(e => dot.edge(e));
return dot.flush(); return dot.flush();
...@@ -235,7 +290,7 @@ function GraphvizView(props: GraphvizProps): JSX.Element { ...@@ -235,7 +290,7 @@ function GraphvizView(props: GraphvizProps): JSX.Element {
React.useEffect(() => { React.useEffect(() => {
d3.graphviz(`#${id}`, { d3.graphviz(`#${id}`, {
useWorker: false, useWorker: false,
fit: false, zoom: true, width, height, fit: true, zoom: true, width, height,
}).renderDot(model); }).renderDot(model);
}, [id, model, width, height]); }, [id, model, width, height]);
...@@ -258,7 +313,7 @@ export function Diagram(props: DiagramProps): JSX.Element { ...@@ -258,7 +313,7 @@ export function Diagram(props: DiagramProps): JSX.Element {
{display && ( {display && (
<AutoSizer> <AutoSizer>
{(size: Size) => ( {(size: Size) => (
<div className={className}> <div className={className} style={size}>
<GraphvizView size={size} {...props} /> <GraphvizView size={size} {...props} />
</div> </div>
)} )}
......
/* -------------------------------------------------------------------------- */
/* --- Main Dome Styles --- */
/* -------------------------------------------------------------------------- */
* {
user-select: none;
box-sizing: border-box;
margin: 0 ;
padding: 0 ;
}
body {
color: var(--text);
background: var(--background-softer);
overflow: hidden ;
position: fixed ;
font-family: sans-serif ;
font-size: 13px ;
top: 0 ;
bottom: 0 ;
left: 0 ;
right: 0 ;
}
#app {
width: 100% ;
height: 100% ;
}
/* -------------------------------------------------------------------------- */
/* --- Frame Colors --- */
/* -------------------------------------------------------------------------- */
.dome-erased {
display: none !important;
}
.dome-hidden {
visibility: hidden !important;
}
.dome-positionned {
position: relative;
}
.dome-color-frame {
fill: var(--text-discrete) ;
color: var(--text-discrete) ;
border-color: var(--border) ;
background: var(--background-intense) ;
}
.dome-color-dragzone {
opacity: 0.0 ;
background: transparent ;
transition: opacity .1s linear 0.1s , background .1s linear 0.1s ;
}
.dome-color-dragzone:hover {
background: var(--grid-layout-holder) ;
opacity: 0.4 ;
transition: opacity .1s linear 0.1s , background .1s linear 0.1s ;
}
.dome-color-dragging {
background: var(--grid-layout-target) ;
opacity: 0.5 ;
transition: opacity .1s linear 0.1s , background .1s linear 0.1s ;
}
div.dome-dragged {
background: var(--grid-layout-holder) ;
border: none ;
}
.dome-dragging * {
cursor: move ;
}
/* -------------------------------------------------------------------------- */
/* --- Text Properties --- */
/* -------------------------------------------------------------------------- */
.dome-text-label {
font-family: sans-serif ;
user-select: none ;
white-space: nowrap ;
text-overflow: ellipsis ;
}
.dome-text-title {
font-family: sans-serif ;
font-size: larger ;
font-weight: bolder ;
user-select: none ;
white-space: nowrap ;
text-overflow: ellipsis ;
}
.dome-text-descr {
font-weight: lighter ;
font-family: sans-serif ;
font-size: smaller ;
user-select: none ;
white-space: normal ;
text-overflow: ellipsis ;
}
.dome-text-data {
cursor: text ;
user-select: text ;
font-family: sans-serif ;
white-space: nowrap ;
text-overflow: clip ;
}
.dome-text-code {
cursor: text ;
user-select: text ;
font-family: 'Andale mono', monospace ;
font-size: 9pt ;
white-space: nowrap ;
text-overflow: clip ;
}
.dome-text-cell {
cursor: default ;
user-select: text ;
font-family: 'Andale mono', monospace ;
font-size: 9pt ;
white-space: nowrap ;
text-overflow: clip ;
}
.dome-text-item {
cursor: default ;
user-select: none ;
font-family: 'Andale mono', monospace ;
font-size: 9pt ;
white-space: nowrap ;
text-overflow: clip ;
}
/* -------------------------------------------------------------------------- */
/* --- Theme-compliant Scrollbars --- */
/* -------------------------------------------------------------------------- */
::-webkit-scrollbar {
width: 14px;
height: 14px;
}
::-webkit-scrollbar-track {
background: var(--background-intense);
}
::-webkit-scrollbar-thumb {
background-color: var(--info-text-discrete);
border-radius: 20px;
border: 3px solid var(--background-intense);
}
::-webkit-scrollbar-corner {
background-color: var(--background-profound);
background: var(--background-profound);
color: var(--background-profound);
}
/* -------------------------------------------------------------------------- */
/* --- Theme-compliant Input Widgets --- */
/* -------------------------------------------------------------------------- */
input[type="search"]::placeholder {
font-style: italic;
color: var(--text-discrete);
}
input[type="text"]::placeholder {
font-style: italic;
color: var(--text-discrete);
}
input[type="text"] {
vertical-align: middle;
margin: 2px 4px 2px 0px;
background-color: var(--background-interaction);
border: var(--border);
border-radius: 2px;
}
input:focus-visible {
outline: none;
box-shadow: 0px 0px 1px 1px var(--border);
}
input[type="checkbox"] {
appearance: none;
width: 13px;
height: 13px;
border: 1px solid var(--border);
border-radius: 2px;
content: "";
font-size: 12px;
color: var(--text);
background-clip: content-box;
padding: 1px;
}
input[type="checkbox"]:checked {
background-color: var(--checked-element);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* --- Graph Styles --- */
/* -------------------------------------------------------------------------- */
.dome-xDiagram {
background: #eee;
}
...@@ -37,18 +37,37 @@ import { registerSandbox } from 'ivette'; ...@@ -37,18 +37,37 @@ import { registerSandbox } from 'ivette';
const nodes: Node[] = [ const nodes: Node[] = [
{ id: 'A' }, { id: 'A' },
{ id: 'B', shape: 'diamond' }, { id: 'B', shape: 'diamond' },
{ id: 'R', {
id: 'R',
shape: [ shape: [
{ label: 'C', port: 'c' }, { label: 'C', port: 'c' },
[ 'D1', 'D2'], ['D1', 'D2'],
{ label: 'E', port: 'e' }, { label: 'E', port: 'e' },
] ]
} },
{ id: 'white', color: 'white' },
{ id: 'grey', color: 'grey' },
{ id: 'dark', color: 'dark' },
{ id: 'primary', color: 'primary' },
{ id: 'selected', color: 'selected' },
{ id: 'green', color: 'green' },
{ id: 'orange', color: 'orange' },
{ id: 'red', color: 'red' },
{ id: 'yellow', color: 'yellow' },
{ id: 'blue', color: 'blue' },
{ id: 'pink', color: 'pink' },
]; ];
const edges: Edge[] = [ const edges: Edge[] = [
{ source: 'A', target: 'R', targetPort: 'c' }, { source: 'A', target: 'R', targetPort: 'c' },
{ source: 'R', target: 'B', sourcePort: 'e' }, { source: 'R', target: 'B', sourcePort: 'e' },
{ source: 'primary', target: 'selected' },
{ source: 'white', target: 'grey' },
{ source: 'grey', target: 'dark' },
{ source: 'green', target: 'orange' },
{ source: 'orange', target: 'red' },
{ source: 'yellow', target: 'pink' },
{ source: 'pink', target: 'blue' }
]; ];
function DiagramSample(): JSX.Element { function DiagramSample(): JSX.Element {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment