Skip to content

Commit 8a0b1d6

Browse files
authored
Subgraph improvements (#5)
* Tidy * Mock data: update subscription data for graph view * Graph view: handle negative coords when converting graphviz edge to SVG
1 parent d3de703 commit 8a0b1d6

File tree

4 files changed

+67
-34
lines changed

4 files changed

+67
-34
lines changed

src/services/mock/json/workflows/multi.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,11 @@
141141
{
142142
"id": "~user/other/multi/run2//1/foo",
143143
"state": "waiting",
144+
"cyclePoint": "1",
144145
"isHeld": false,
145146
"isQueued": true,
146147
"isRunahead": false,
148+
"name": "foo",
147149
"task": {
148150
"meanElapsedTime": 0,
149151
"__typename": "Task"
@@ -157,9 +159,11 @@
157159
{
158160
"id": "~user/other/multi/run2//2/foo",
159161
"state": "waiting",
162+
"cyclePoint": "2",
160163
"isHeld": false,
161164
"isQueued": false,
162165
"isRunahead": false,
166+
"name": "foo",
163167
"task": {
164168
"meanElapsedTime": 0,
165169
"__typename": "Task"

src/utils/graph-utils.js

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/**
1+
/*
22
* Copyright (C) NIWA & British Crown (Met Office) & Contributors.
33
*
44
* This program is free software: you can redistribute it and/or modify
@@ -15,25 +15,42 @@
1515
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717

18+
/**
19+
* Convert graphviz edge bezier curve in dot format to SVG path .
20+
*
21+
* @param {string} pos - `pos` attribute of a graph edge in dot format.
22+
* @returns {string} The SVG path.
23+
*/
1824
export function posToPath (pos) {
25+
// pos starts with `e,` followed by a list of coordinates
26+
const parts = pos.substring(2).split(' ')
1927
// the last point comes first, followed by the others in order I.E:
2028
// -1, 0, 1, 2, ... -3, -2
21-
const parts = pos.substring(2).split(' ').map(x => x.split(','))
22-
const [last] = parts.splice(0, 1)
23-
let path = null
24-
for (const part of parts) {
25-
if (!path) {
26-
path = `M${part[0]} -${part[1]} C`
27-
} else {
28-
path = path + ` ${part[0]} -${part[1]},`
29-
}
30-
}
31-
path = path + ` L ${last[0]} -${last[1]}`
32-
return path
29+
const [last, first] = parts.splice(0, 2)
30+
const path = parts.reduce(
31+
(acc, part) => `${acc} ${getCoord(part)},`,
32+
`M${getCoord(first)} C`
33+
)
34+
return `${path} L ${getCoord(last)}`
3335
}
3436

35-
/* TODO: everything! */
36-
// eslint-disable-next-line no-extend-native
37+
/**
38+
* Convert dotcode `pos` coordinate to SVG path coordinate.
39+
*
40+
* @param {string} posCoord - A coordinate in dot format.
41+
* @returns {string}
42+
*/
43+
export function getCoord (posCoord) {
44+
const [x, y] = posCoord.split(',').map(parseFloat)
45+
return `${x} ${-y}`
46+
}
47+
48+
/**
49+
* Calculate a non-cryptographic hash value for a given string.
50+
*
51+
* @param {string} string
52+
* @returns {number}
53+
*/
3754
export function nonCryptoHash (string) {
3855
let hash = 0
3956
let i

src/views/Graph.vue

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
8686
/>
8787
</g>
8888
</g>
89-
<g v-if="groupCycle" class="graph-subgraph-container">
90-
<g v-for="(subgraph, key) in subgraphs"
91-
:key="key">
92-
<GraphSubgraph
93-
v-if="subgraph.label!='margin'"
94-
:subgraph="subgraph" />
95-
</g>
89+
<g v-if="groupCycle">
90+
<GraphSubgraph
91+
v-for="(subgraph, key) in subgraphs"
92+
:key="key"
93+
:subgraph="subgraph"
94+
/>
9695
</g>
9796
</g>
9897
</svg>
@@ -514,7 +513,7 @@ export default {
514513
* Get the nodes binned by cycle point
515514
*
516515
* @param {Object[]} nodes
517-
* @returns {{ [dateTime: string]: Object[] nodes }} mapping of node to their cycle point.
516+
* @returns {{ [dateTime: string]: Object[] }=} mapping of cycle points to nodes
518517
*/
519518
getCycles (nodes) {
520519
if (!this.groupCycle) return
@@ -764,14 +763,17 @@ export default {
764763
// update graph node positions
765764
for (const obj of json.objects) {
766765
if (obj.bb) {
767-
// if the object is a subgraph
768-
const [left, bottom, right, top] = obj.bb.split(',')
769-
this.subgraphs[obj.name] = {
770-
x: left,
771-
y: -top,
772-
width: right - left,
773-
height: top - bottom,
774-
label: obj.label
766+
// if the object is a subgraph
767+
if (obj.label !== 'margin') {
768+
// ignore the margins in the dot-code which do not need DOM elements
769+
const [left, bottom, right, top] = obj.bb.split(',')
770+
this.subgraphs[obj.name] = {
771+
x: left,
772+
y: -top,
773+
width: right - left,
774+
height: top - bottom,
775+
label: obj.label
776+
}
775777
}
776778
} else {
777779
// else the object is a node

tests/unit/utils/graph-utils.spec.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/**
1+
/*
22
* Copyright (C) NIWA & British Crown (Met Office) & Contributors.
33
*
44
* This program is free software: you can redistribute it and/or modify
@@ -39,11 +39,21 @@ describe('Graph functionality', () => {
3939
'L 211.5 -156.5'
4040
)
4141
})
42+
it('Handles negative coordinates', () => {
43+
expect(posToPath(
44+
'e,1,1 -2,-2 3,-3 -1,-0'
45+
)).to.equal(
46+
'M-2 2 C 3 3, -1 0, L 1 -1'
47+
)
48+
})
4249
})
4350

4451
describe('nonCryptoHash', () => {
45-
it('Converts a string to a stable hash', () => {
46-
expect(nonCryptoHash('foo')).to.equal(101574)
52+
it.each([
53+
['foo', 101574],
54+
['', 0],
55+
])('Converts a string to a stable hash: %o -> %i', (str, expected) => {
56+
expect(nonCryptoHash(str)).to.equal(expected)
4757
})
4858
})
4959
})

0 commit comments

Comments
 (0)