diff --git a/src/app/(main)/reports/journey/JourneyView.module.css b/src/app/(main)/reports/journey/JourneyView.module.css index a9d94251..b4297b5f 100644 --- a/src/app/(main)/reports/journey/JourneyView.module.css +++ b/src/app/(main)/reports/journey/JourneyView.module.css @@ -5,6 +5,7 @@ --journey-line-color: var(--base600); --journey-active-color: var(--primary400); + --journey-faded-color: var(--base300); } .view { @@ -71,16 +72,21 @@ background: var(--base100); } -.selected { +.item.selected { color: var(--base75); background: var(--base900); font-weight: 400; } .item.active { + color: var(--light50); background: var(--primary400); } +.item.active .count { + background: var(--primary600); +} + .behind { color: var(--base400); } @@ -110,119 +116,136 @@ .line { position: absolute; + bottom: 0; left: -100px; width: 100px; } -.line.flat:before { - content: ''; - position: absolute; - width: 97px; - left: 3px; - border-top: 3px solid var(--journey-line-color); -} - -.line.fromUp:before { - content: ''; - position: absolute; - top: -30px; - left: 50px; - margin-top: 3px; - margin-left: -3px; - border: 0; - border-bottom-left-radius: 100%; - border-left: 3px solid var(--journey-line-color); - border-bottom: 3px solid var(--journey-line-color); - width: 50px; - height: 30px; -} - -.line.fromDown:before { - content: ''; - position: absolute; - top: 0; - left: 50px; - margin-left: -3px; - border: 0; - border-top-left-radius: 100%; - border-left: 3px solid var(--journey-line-color); - border-top: 3px solid var(--journey-line-color); - width: 50px; - height: 30px; -} - -.line.fromUp:after, -.line.fromDown:after { - content: ''; - position: absolute; - top: -6px; - right: -6px; - margin: 0; +.line.up { bottom: 0; - border-radius: 100%; - border: 3px solid var(--journey-line-color); - background: var(--base50); - width: 13px; - height: 13px; } -.line.toUp:before { - content: ''; +.line.down { + top: 0; +} + +.segment { position: absolute; - top: -30px; - margin-top: 3px; - right: -350px; - border: 0; - border-bottom-right-radius: 100%; - border-right: 3px solid var(--journey-line-color); - border-bottom: 3px solid var(--journey-line-color); +} + +.start { + left: 0; width: 50px; height: 30px; + border: 0; } -.line.toDown:before { - content: ''; - position: absolute; - top: 0; - right: -350px; +.mid { + top: 60px; + width: 50px; + border-right: 3px solid var(--journey-line-color); +} + +.end { + right: 0; + width: 50px; + height: 30px; border: 0; +} + +.up .start { + top: 30px; border-top-right-radius: 100%; - border-right: 3px solid var(--journey-line-color); border-top: 3px solid var(--journey-line-color); - width: 50px; - height: 30px; + border-right: 3px solid var(--journey-line-color); } -.line.toUp:after, -.line.toDown:after { +.up .end { + width: 53px; + bottom: 27px; + right: 0; + border-bottom-left-radius: 100%; + border-bottom: 3px solid var(--journey-line-color); + border-left: 3px solid var(--journey-line-color); +} + +.down .start { + bottom: 27px; + border-bottom-right-radius: 100%; + border-bottom: 3px solid var(--journey-line-color); + border-right: 3px solid var(--journey-line-color); +} + +.down .end { + width: 53px; + top: 30px; + right: 0; + border-top-left-radius: 100%; + border-top: 3px solid var(--journey-line-color); + border-left: 3px solid var(--journey-line-color); +} + +.flat .start { + top: 30px; + width: 50px; + border-top: 3px solid var(--journey-line-color); +} + +.flat .end { + right: 0; + bottom: 27px; + width: 50px; + border-bottom: 3px solid var(--journey-line-color); +} + +.start:before, +.end:before { content: ''; position: absolute; - top: -6px; - right: -306px; - margin: 0; - bottom: 0; border-radius: 100%; border: 3px solid var(--journey-line-color); - background: var(--base50); + background: var(--light50); width: 13px; height: 13px; } -.bar { - position: absolute; - left: -100px; - width: 50px; - height: 20px; - border-right: 3px solid var(--journey-line-color); +.line:not(.active) .start:before, +.line:not(.active) .end:before { + display: none; } -.item.active .bar, -.item.active .line:before, -.item.active .line:after { +.up .start:before, +.flat .start:before { + left: -8px; + top: -8px; +} + +.up .end:before, +.flat .end:before { + right: -8px; + bottom: -8px; +} + +.down .start:before { + left: -8px; + bottom: -8px; +} + +.down .end:before { + right: -8px; + top: -8px; +} + +.line.active .segment, +.line.active .segment:before { border-color: var(--journey-active-color); z-index: 1; } -.item.active .count { - background: var(--primary600); +.column.active .line:not(.active) .segment { + border-color: var(--journey-faded-color); +} + +.column.active .line:not(.active) .segment:before { + display: none; } diff --git a/src/app/(main)/reports/journey/JourneyView.tsx b/src/app/(main)/reports/journey/JourneyView.tsx index 1b9333c3..fe2d7729 100644 --- a/src/app/(main)/reports/journey/JourneyView.tsx +++ b/src/app/(main)/reports/journey/JourneyView.tsx @@ -9,7 +9,7 @@ import styles from './JourneyView.module.css'; const NODE_HEIGHT = 60; const NODE_GAP = 10; -const BAR_OFFSET = 3; +const LINE_WIDTH = 3; export default function JourneyView() { const [selectedNode, setSelectedNode] = useState(null); @@ -49,20 +49,6 @@ export default function JourneyView() { } return obj; }, {}); - const to = - selected && - paths.reduce((obj, path) => { - const { items, count } = path; - const name = items[index + 1]; - if (name) { - if (!obj[name]) { - obj[name] = { name, count: +count }; - } else { - obj[name].count += +count; - } - } - return obj; - }, {}); column[name] = { name, @@ -71,7 +57,6 @@ export default function JourneyView() { selected, paths, from: objectToArray(from), - to: objectToArray(to), }; } else { column[name].total += +count; @@ -103,65 +88,30 @@ export default function JourneyView() {
{columns.map((column, columnIndex) => { - const current = columnIndex === selectedNode?.index; - const behind = columnIndex <= selectedNode?.index - 1; - const ahead = columnIndex > selectedNode?.index; - return (
{columnIndex + 1}
- {column.nodes.map(({ name, total, selected, paths, from, to }, nodeIndex) => { + {column.nodes.map(({ name, total, selected, paths, from }, nodeIndex) => { const active = selected && activeNode?.paths.find(path => path.items[columnIndex] === name); - const bars = []; - const lines = from?.reduce( - (obj: { flat: boolean; fromUp: boolean; fromDown: boolean }, { name }: any) => { - const fromIndex = columns[columnIndex - 1]?.nodes.findIndex(node => { - return node.name === name && node.selected; - }); - if (fromIndex > -1) { - if (nodeIndex === fromIndex) { - obj.flat = true; - } else if (nodeIndex > fromIndex) { - obj.fromUp = true; - bars.push([fromIndex, nodeIndex, 1]); - } else if (nodeIndex < fromIndex) { - obj.fromDown = true; - bars.push([nodeIndex, fromIndex, 0]); - } - } - - return obj; - }, - {}, - ); - - to?.reduce((obj: { toUp: boolean; toDown: boolean }, { name }: any) => { - const toIndex = columns[columnIndex + 1]?.nodes.findIndex(node => { + const lines = from?.reduce((arr, { name }: any) => { + const fromIndex = columns[columnIndex - 1]?.nodes.findIndex(node => { return node.name === name && node.selected; }); - if (toIndex > -1) { - if (nodeIndex > toIndex) { - obj.toUp = true; - } else if (nodeIndex < toIndex) { - obj.toDown = true; - } + if (fromIndex > -1) { + arr.push([fromIndex, nodeIndex]); } - return obj; - }, lines); + return arr; + }, []); return (
{name}
{total}
- {Object.keys(lines).map(key => { - return
; - })} {columnIndex < columns.length && - bars.map(([a, b, d], i) => { - const height = (b - a - 1) * (NODE_HEIGHT + NODE_GAP) + NODE_GAP; + lines.map(([fromIndex, nodeIndex], i) => { + const height = + (Math.abs(nodeIndex - fromIndex) + 1) * (NODE_HEIGHT + NODE_GAP) - + NODE_GAP; + const midHeight = + (Math.abs(nodeIndex - fromIndex) - 1) * (NODE_HEIGHT + NODE_GAP) + + NODE_GAP + + LINE_WIDTH; + const nodeName = columns[columnIndex - 1]?.nodes[fromIndex].name; + return (
+ key={`${fromIndex}${nodeIndex}${i}`} + className={classNames(styles.line, { + [styles.active]: + active && + activeNode?.paths.find( + path => + path.items[columnIndex] === name && + path.items[columnIndex - 1] === nodeName, + ), + [styles.up]: fromIndex < nodeIndex, + [styles.down]: fromIndex > nodeIndex, + [styles.flat]: fromIndex === nodeIndex, + })} + style={{ height }} + > +
+
+
+
); })}