aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2024-02-23 00:23:35 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2024-02-23 19:13:07 +0100
commitc0e3f3774cd471f51d096d4980cf5f8565d13bef (patch)
tree0f0a2209674f2383d676e2fa9adbb443fcfb0241
parentfeat(web): SVG export (diff)
downloadrefinery-c0e3f3774cd471f51d096d4980cf5f8565d13bef.tar.gz
refinery-c0e3f3774cd471f51d096d4980cf5f8565d13bef.tar.zst
refinery-c0e3f3774cd471f51d096d4980cf5f8565d13bef.zip
refactor(frontend): cleaner SVG export
Make sure svg can process the resulting SVG without changing visuals. In particular, we must not use specific stroke/fill values as CSS selectors, because svgo may change them into hex codes. Instead, we annotate all diagram elements with class names.
-rw-r--r--subprojects/frontend/src/graph/GraphTheme.tsx30
-rw-r--r--subprojects/frontend/src/graph/postProcessSVG.ts27
2 files changed, 40 insertions, 17 deletions
diff --git a/subprojects/frontend/src/graph/GraphTheme.tsx b/subprojects/frontend/src/graph/GraphTheme.tsx
index b3f55a35..34954345 100644
--- a/subprojects/frontend/src/graph/GraphTheme.tsx
+++ b/subprojects/frontend/src/graph/GraphTheme.tsx
@@ -27,10 +27,10 @@ function createEdgeColor(
27 '& text': { 27 '& text': {
28 fill: stroke, 28 fill: stroke,
29 }, 29 },
30 '& [stroke="black"]': { 30 '.edge-line': {
31 stroke, 31 stroke,
32 }, 32 },
33 '& [fill="black"]': { 33 '.edge-arrow': {
34 fill: fill ?? stroke, 34 fill: fill ?? stroke,
35 }, 35 },
36 }, 36 },
@@ -43,10 +43,8 @@ function createTypeHashStyles(theme: Theme, colorNodes: boolean): CSSObject {
43 } 43 }
44 const result: CSSObject = {}; 44 const result: CSSObject = {};
45 range(theme.palette.highlight.typeHash.length).forEach((i) => { 45 range(theme.palette.highlight.typeHash.length).forEach((i) => {
46 result[`.node-typeHash-${i}`] = { 46 result[`.node-typeHash-${i} .node-header`] = {
47 '& [fill="green"]': { 47 fill: theme.palette.highlight.typeHash[i]?.box,
48 fill: theme.palette.highlight.typeHash[i]?.box,
49 },
50 }; 48 };
51 }); 49 });
52 return result; 50 return result;
@@ -85,25 +83,23 @@ export function createGraphTheme({
85 fontFamily: theme.typography.fontFamily, 83 fontFamily: theme.typography.fontFamily,
86 fill: theme.palette.text.primary, 84 fill: theme.palette.text.primary,
87 }, 85 },
88 '& [stroke="black"]': { 86 '.node-outline': {
89 stroke: theme.palette.text.primary, 87 stroke: theme.palette.text.primary,
90 }, 88 },
91 '& [fill="green"]': { 89 '.node-header': {
92 fill: 90 fill:
93 theme.palette.mode === 'dark' 91 theme.palette.mode === 'dark'
94 ? theme.palette.primary.dark 92 ? theme.palette.primary.dark
95 : theme.palette.primary.light, 93 : theme.palette.primary.light,
96 }, 94 },
97 '& [fill="white"]': { 95 '.node-bg': {
98 fill: theme.palette.background.default, 96 fill: theme.palette.background.default,
99 }, 97 },
100 }, 98 },
101 '.node-INDIVIDUAL': { 99 '.node-INDIVIDUAL .node-outline': {
102 '& [stroke="black"]': { 100 strokeWidth: 2,
103 strokeWidth: 2,
104 },
105 }, 101 },
106 '.node-shadow[fill="white"]': noEmbedIcons 102 '.node-shadow.node-bg': noEmbedIcons
107 ? { 103 ? {
108 // Inkscape can't handle opacity in exported SVG. 104 // Inkscape can't handle opacity in exported SVG.
109 fill: theme.palette.text.primary, 105 fill: theme.palette.text.primary,
@@ -112,7 +108,7 @@ export function createGraphTheme({
112 : { 108 : {
113 fill: alpha(theme.palette.text.primary, shadowAlapha), 109 fill: alpha(theme.palette.text.primary, shadowAlapha),
114 }, 110 },
115 '.node-exists-UNKNOWN [stroke="black"]': { 111 '.node-exists-UNKNOWN .node-outline': {
116 strokeDasharray: '5 2', 112 strokeDasharray: '5 2',
117 }, 113 },
118 ...createTypeHashStyles(theme, colorNodes), 114 ...createTypeHashStyles(theme, colorNodes),
@@ -121,10 +117,10 @@ export function createGraphTheme({
121 fontFamily: theme.typography.fontFamily, 117 fontFamily: theme.typography.fontFamily,
122 fill: theme.palette.text.primary, 118 fill: theme.palette.text.primary,
123 }, 119 },
124 '& [stroke="black"]': { 120 '.edge-line': {
125 stroke: theme.palette.text.primary, 121 stroke: theme.palette.text.primary,
126 }, 122 },
127 '& [fill="black"]': { 123 '.edge-arrow': {
128 fill: theme.palette.text.primary, 124 fill: theme.palette.text.primary,
129 }, 125 },
130 }, 126 },
diff --git a/subprojects/frontend/src/graph/postProcessSVG.ts b/subprojects/frontend/src/graph/postProcessSVG.ts
index f434f80b..bf990f3a 100644
--- a/subprojects/frontend/src/graph/postProcessSVG.ts
+++ b/subprojects/frontend/src/graph/postProcessSVG.ts
@@ -166,6 +166,32 @@ function replaceImages(node: SVGGElement) {
166 }); 166 });
167} 167}
168 168
169function markerColorToClass(svg: SVGSVGElement) {
170 svg.querySelectorAll('.node [stroke="black"]').forEach((node) => {
171 node.removeAttribute('stroke');
172 node.classList.add('node-outline');
173 });
174 svg.querySelectorAll('.node [fill="green"]').forEach((node) => {
175 node.removeAttribute('fill');
176 node.classList.add('node-header');
177 });
178 svg.querySelectorAll('.node [fill="white"]').forEach((node) => {
179 node.removeAttribute('fill');
180 node.classList.add('node-bg');
181 });
182 svg.querySelectorAll('.edge [stroke="black"]').forEach((node) => {
183 node.removeAttribute('stroke');
184 node.classList.add('edge-line');
185 });
186 svg.querySelectorAll('.edge [fill="black"]').forEach((node) => {
187 node.removeAttribute('fill');
188 node.classList.add('edge-arrow');
189 });
190 svg.querySelectorAll('[font-family]').forEach((node) => {
191 node.removeAttribute('font-family');
192 });
193}
194
169export default function postProcessSvg(svg: SVGSVGElement) { 195export default function postProcessSvg(svg: SVGSVGElement) {
170 // svg 196 // svg
171 // .querySelectorAll<SVGTitleElement>('title') 197 // .querySelectorAll<SVGTitleElement>('title')
@@ -183,4 +209,5 @@ export default function postProcessSvg(svg: SVGSVGElement) {
183 svg.viewBox.baseVal.height + 12, 209 svg.viewBox.baseVal.height + 12,
184 ]; 210 ];
185 svg.setAttribute('viewBox', viewBox.join(' ')); 211 svg.setAttribute('viewBox', viewBox.join(' '));
212 markerColorToClass(svg);
186} 213}