mirror of
https://github.com/umami-software/umami.git
synced 2026-02-10 15:47:13 +01:00
Updated journey counts.
This commit is contained in:
parent
3234120bfb
commit
1463482e89
2 changed files with 116 additions and 94 deletions
|
|
@ -147,7 +147,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.end {
|
.end {
|
||||||
right: 0;
|
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
border: 0;
|
border: 0;
|
||||||
|
|
@ -161,7 +160,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.up .end {
|
.up .end {
|
||||||
width: 53px;
|
width: 52px;
|
||||||
bottom: 27px;
|
bottom: 27px;
|
||||||
right: 0;
|
right: 0;
|
||||||
border-bottom-left-radius: 100%;
|
border-bottom-left-radius: 100%;
|
||||||
|
|
@ -177,7 +176,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.down .end {
|
.down .end {
|
||||||
width: 53px;
|
width: 52px;
|
||||||
top: 30px;
|
top: 30px;
|
||||||
right: 0;
|
right: 0;
|
||||||
border-top-left-radius: 100%;
|
border-top-left-radius: 100%;
|
||||||
|
|
@ -186,16 +185,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.flat .start {
|
.flat .start {
|
||||||
|
left: 0;
|
||||||
top: 30px;
|
top: 30px;
|
||||||
width: 50px;
|
|
||||||
border-top: 3px solid var(--journey-line-color);
|
border-top: 3px solid var(--journey-line-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.flat .end {
|
.flat .end {
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 27px;
|
top: 30px;
|
||||||
width: 50px;
|
border-top: 3px solid var(--journey-line-color);
|
||||||
border-bottom: 3px solid var(--journey-line-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.start:before,
|
.start:before,
|
||||||
|
|
@ -214,14 +212,12 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.up .start:before,
|
.up .start:before {
|
||||||
.flat .start:before {
|
|
||||||
left: -8px;
|
left: -8px;
|
||||||
top: -8px;
|
top: -8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.up .end:before,
|
.up .end:before {
|
||||||
.flat .end:before {
|
|
||||||
right: -8px;
|
right: -8px;
|
||||||
bottom: -8px;
|
bottom: -8px;
|
||||||
}
|
}
|
||||||
|
|
@ -236,6 +232,16 @@
|
||||||
top: -8px;
|
top: -8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flat .start:before {
|
||||||
|
left: -8px;
|
||||||
|
top: -8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flat .end:before {
|
||||||
|
right: -8px;
|
||||||
|
top: -8px;
|
||||||
|
}
|
||||||
|
|
||||||
.line.active .segment,
|
.line.active .segment,
|
||||||
.line.active .segment:before {
|
.line.active .segment:before {
|
||||||
border-color: var(--journey-active-color);
|
border-color: var(--journey-active-color);
|
||||||
|
|
|
||||||
|
|
@ -23,61 +23,69 @@ export default function JourneyView() {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selectedPaths = selectedNode?.paths ?? [];
|
||||||
|
const activePaths = activeNode?.paths ?? [];
|
||||||
|
|
||||||
return Array(Number(parameters.steps))
|
return Array(Number(parameters.steps))
|
||||||
.fill(undefined)
|
.fill(undefined)
|
||||||
.map((column = {}, index) => {
|
.map((nodes = {}, index) => {
|
||||||
data.forEach(({ items, count }) => {
|
data.forEach(({ items, count }) => {
|
||||||
const name = items[index];
|
const name = items[index];
|
||||||
const selectedNodes = selectedNode?.paths ?? [];
|
|
||||||
|
|
||||||
if (name) {
|
if (name) {
|
||||||
const selected = !!selectedNodes.find(a => a.items[index] === name);
|
const selected = !!selectedPaths.find(path => path.items[index] === name);
|
||||||
if (!column[name]) {
|
const active = selected && !!activePaths.find(path => path.items[index] === name);
|
||||||
|
|
||||||
|
if (!nodes[name]) {
|
||||||
const paths = data.filter((d, i) => {
|
const paths = data.filter((d, i) => {
|
||||||
return i !== index && d.items[index] === name;
|
return i !== index && d.items[index] === name;
|
||||||
});
|
});
|
||||||
|
|
||||||
const from =
|
const from =
|
||||||
index > 0 &&
|
index > 0 &&
|
||||||
selected &&
|
selected &&
|
||||||
paths.reduce((obj, path) => {
|
paths.reduce((obj, path) => {
|
||||||
const { items, count } = path;
|
const { items, count } = path;
|
||||||
const name = items[index - 1];
|
const name = items[index - 1];
|
||||||
|
|
||||||
if (!obj[name]) {
|
if (!obj[name]) {
|
||||||
obj[name] = { name, count };
|
obj[name] = { name, count };
|
||||||
} else {
|
} else {
|
||||||
obj[name].count += count;
|
obj[name].count += count;
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
column[name] = {
|
nodes[name] = {
|
||||||
name,
|
name,
|
||||||
count,
|
count,
|
||||||
total: count,
|
total: count,
|
||||||
columnIndex: index,
|
columnIndex: index,
|
||||||
selected,
|
selected,
|
||||||
selectedCount: count,
|
active,
|
||||||
paths,
|
paths,
|
||||||
from: objectToArray(from),
|
from: objectToArray(from),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
column[name].selectedCount += selected ? count : 0;
|
nodes[name].total += count;
|
||||||
column[name].total += count;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
nodes: objectToArray(column).sort(firstBy('total', -1)),
|
nodes: objectToArray(nodes).sort(firstBy('total', -1)),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}, [data, selectedNode]);
|
}, [data, selectedNode, activeNode]);
|
||||||
|
|
||||||
const handleClick = (item: string, index: number, paths: any[]) => {
|
const handleClick = (name: string, index: number, paths: any[]) => {
|
||||||
if (item !== selectedNode?.item || index !== selectedNode?.index) {
|
if (name !== selectedNode?.name || index !== selectedNode?.index) {
|
||||||
setSelectedNode({ item, index, paths });
|
setSelectedNode({ name, index, paths });
|
||||||
} else {
|
} else {
|
||||||
setSelectedNode(null);
|
setSelectedNode(null);
|
||||||
|
setActiveNode(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -85,7 +93,7 @@ export default function JourneyView() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.log({ columns, selectedNode, activeNode });
|
//console.log({ data, columns, selectedNode, activeNode });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
|
|
@ -100,81 +108,89 @@ export default function JourneyView() {
|
||||||
<div className={styles.num}>{columnIndex + 1}</div>
|
<div className={styles.num}>{columnIndex + 1}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.nodes}>
|
<div className={styles.nodes}>
|
||||||
{column.nodes.map(
|
{column.nodes.map(({ name, total, selected, active, paths, from }, nodeIndex) => {
|
||||||
({ name, total, selected, paths, from, selectedCount }, nodeIndex) => {
|
const previousNodes = columns[columnIndex - 1]?.nodes;
|
||||||
const active =
|
let selectedCount = from?.length ? 0 : total;
|
||||||
selected && activeNode?.paths.find(path => path.items[columnIndex] === name);
|
let activeCount = selectedCount;
|
||||||
|
|
||||||
const lines = from?.reduce((arr, { name }: any) => {
|
const lines = from?.reduce((arr, { name, count }: any) => {
|
||||||
const fromIndex = columns[columnIndex - 1]?.nodes.findIndex(node => {
|
const fromIndex = previousNodes.findIndex(node => {
|
||||||
return node.name === name && node.selected;
|
return node.name === name && node.selected;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (fromIndex > -1) {
|
if (fromIndex > -1) {
|
||||||
arr.push([fromIndex, nodeIndex]);
|
arr.push([fromIndex, nodeIndex]);
|
||||||
}
|
selectedCount += count;
|
||||||
|
}
|
||||||
|
|
||||||
return arr;
|
if (
|
||||||
}, []);
|
previousNodes.findIndex(node => {
|
||||||
|
return node.name === name && node.active;
|
||||||
|
}) > -1
|
||||||
|
) {
|
||||||
|
activeCount += count;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return arr;
|
||||||
<div
|
}, []);
|
||||||
key={name}
|
|
||||||
className={classNames(styles.item, {
|
|
||||||
[styles.selected]: selected,
|
|
||||||
[styles.active]: active,
|
|
||||||
})}
|
|
||||||
onClick={() => handleClick(name, columnIndex, paths)}
|
|
||||||
onMouseEnter={() => selected && setActiveNode({ name, columnIndex, paths })}
|
|
||||||
onMouseLeave={() => selected && setActiveNode(null)}
|
|
||||||
>
|
|
||||||
<div className={styles.name}>{name}</div>
|
|
||||||
<div className={styles.count}>
|
|
||||||
{selected || active ? selectedCount : total}
|
|
||||||
</div>
|
|
||||||
{columnIndex < columns.length &&
|
|
||||||
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 (
|
return (
|
||||||
<div
|
<div
|
||||||
key={`${fromIndex}${nodeIndex}${i}`}
|
key={name}
|
||||||
className={classNames(styles.line, {
|
className={classNames(styles.item, {
|
||||||
[styles.active]:
|
[styles.selected]: selected,
|
||||||
active &&
|
[styles.active]: active,
|
||||||
activeNode?.paths.find(
|
})}
|
||||||
path =>
|
onClick={() => handleClick(name, columnIndex, paths)}
|
||||||
path.items[columnIndex] === name &&
|
onMouseEnter={() => selected && setActiveNode({ name, columnIndex, paths })}
|
||||||
path.items[columnIndex - 1] === nodeName,
|
onMouseLeave={() => selected && setActiveNode(null)}
|
||||||
),
|
>
|
||||||
[styles.up]: fromIndex < nodeIndex,
|
<div className={styles.name}>{name}</div>
|
||||||
[styles.down]: fromIndex > nodeIndex,
|
<div className={styles.count}>
|
||||||
[styles.flat]: fromIndex === nodeIndex,
|
{selected ? (active ? activeCount : selectedCount) : total}
|
||||||
})}
|
|
||||||
style={{ height }}
|
|
||||||
>
|
|
||||||
<div className={classNames(styles.segment, styles.start)} />
|
|
||||||
<div
|
|
||||||
className={classNames(styles.segment, styles.mid)}
|
|
||||||
style={{
|
|
||||||
height: midHeight,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div className={classNames(styles.segment, styles.end)} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
{columnIndex < columns.length &&
|
||||||
},
|
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 (
|
||||||
|
<div
|
||||||
|
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 }}
|
||||||
|
>
|
||||||
|
<div className={classNames(styles.segment, styles.start)} />
|
||||||
|
<div
|
||||||
|
className={classNames(styles.segment, styles.mid)}
|
||||||
|
style={{
|
||||||
|
height: midHeight,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className={classNames(styles.segment, styles.end)} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue