Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Visualise changes over time #175

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
acdca8f
Fix npm package vulnerabilities via audit
codemacabre Nov 14, 2024
02d5608
Add placeholder slider controls
codemacabre Nov 15, 2024
ec3716c
Get statementDate values from data
codemacabre Nov 18, 2024
34ae963
Update selected date when apply button pressed
codemacabre Nov 19, 2024
70f2cc9
Filter data by selected statementDate
codemacabre Nov 19, 2024
6330a4c
Filter data by closed records of various types
codemacabre Nov 19, 2024
d093709
Fix data not rendering if no duplicates
codemacabre Nov 26, 2024
6cd4b0c
Ensure unique nodes are included in rendered data
codemacabre Nov 26, 2024
946d82d
Re-render graph on slider input change & remove apply button
codemacabre Nov 26, 2024
75fd541
Fix entity nodes not displaying properties
codemacabre Nov 26, 2024
85b3d40
Render <0.4 data, accommodating changes over time
codemacabre Nov 26, 2024
0ca1646
Remove unused 'latest' function
codemacabre Nov 26, 2024
f1872cc
Process duplicate and unique statements through all filters
codemacabre Nov 26, 2024
c20c234
Set default version to 0.4
codemacabre Nov 26, 2024
ffe342f
Fix incorrect icons for unknownPerson and unknownEntity
codemacabre Nov 28, 2024
f236db7
Ensure dates are being parsed correctly
codemacabre Nov 28, 2024
17d55ed
Clear properties when new data is loaded
codemacabre Nov 28, 2024
145e3b2
Update tests to accommodate new util function
codemacabre Nov 28, 2024
eac22e8
Remove unused sets and update test to match
codemacabre Nov 28, 2024
fe59d69
Fix incorrect icons for listed companies
codemacabre Nov 28, 2024
cb05489
Ensure data with just statement.recordType is minimum valid statement
codemacabre Dec 9, 2024
a5491df
Ensure slider drag event persists & page doesn't scroll on input
codemacabre Dec 9, 2024
37d0c49
Add grab / grabbing cursor to input thumb
codemacabre Dec 9, 2024
e8ebf40
Hide tooltips on draw()
codemacabre Dec 9, 2024
d472ed5
Improve error handling of invalid JSON
codemacabre Dec 10, 2024
a3db52a
Modify the curevMonotoneX algorithm to smooth the ends of the curves
codemacabre Dec 10, 2024
cdde010
Tweak curve algorithm to be less angular
codemacabre Dec 10, 2024
8d029ac
Ensure data with just statementType is valid for <0.4 data
codemacabre Dec 11, 2024
b212b52
Add grab / grabbing cursor on base SVG
codemacabre Dec 11, 2024
778b12a
Hide tooltip on click
codemacabre Dec 11, 2024
3006086
Add more detailed comment on how <0.4 change over time data is handled
codemacabre Dec 13, 2024
9ed5ca1
Set cursor to 'not-allowed' on disabled slider input
codemacabre Dec 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ <h1>BODS Data Visualisation Demo</h1>
<button id="zoom_in">+</button>
<button id="zoom_out">-</button>
</div>
<div id="slider-container"></div>
<div id="disclosure-widget"></div>
<button id="download-svg">Download SVG</button>
<button id="download-png">Download PNG</button>
Expand Down
1 change: 1 addition & 0 deletions demo/script-tag.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ <h1>BODS Data Visualisation Demo</h1>
<button id="zoom_in">+</button>
<button id="zoom_out">-</button>
</div>
<div id="slider-container"></div>
<div id="disclosure-widget"></div>
<div class="info-container">
<p><a href="https://github.com/openownership/visualisation-tool/blob/master/docs/spec.md#data-requirements">Data requirements</a></p>
Expand Down
21 changes: 11 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import {
createUnspecifiedNode,
} from './render/renderD3';
import { setupGraph, setEdges, setNodes } from './render/renderGraph';
import { setupUI, renderMessage, renderProperties } from './render/renderUI';
import { setupUI, renderMessage, renderProperties, renderDateSlider } from './render/renderUI';
import { getDates } from './utils/bods.js';

import './style.css';

Expand All @@ -37,6 +38,14 @@ const draw = ({

defineArrowHeads(svg);

const version = data[0]?.publicationDetails?.bodsVersion || '0.4';

// TODO: detect dates in data
const dates = getDates(data);
// TODO: select data for vis; default to most recent
// TODO: add event listener to update data according to slider position
renderDateSlider(data, dates, version);

// Extract the BODS data that is required for drawing the graph
const { edges } = getEdges(data);
const { nodes } = getNodes(data, edges);
Expand Down
2 changes: 1 addition & 1 deletion src/model/edges/edges.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export const getOwnershipEdges = (bodsData) => {
};
});

return latest(mappedData, closedRecords, version);
return mappedData;
};

export const getEdges = (data) => {
Expand Down
4 changes: 2 additions & 2 deletions src/model/nodes/nodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export const getPersonNodes = (bodsData) => {
};
});

return latest(mappedData, closedRecords, version);
return mappedData;
};

// This builds up the required entity object from the BODS data, using the functions above
Expand Down Expand Up @@ -214,7 +214,7 @@ export const getEntityNodes = (bodsData) => {
};
});

return latest(mappedData, closedRecords, version);
return mappedData;
};

export const setUnknownNode = (source) => unknownNode(source);
Expand Down
37 changes: 37 additions & 0 deletions src/render/renderUI.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { compareVersions } from 'compare-versions';
import tippy, { hideAll } from 'tippy.js';
import 'tippy.js/dist/tippy.css';
import 'tippy.js/themes/light-border.css';
Expand Down Expand Up @@ -207,3 +208,39 @@ export const renderProperties = (inner, g, useTippy) => {
});
});
};

export const renderDateSlider = (data, dates, version) => {
const sliderContainer = document.querySelector('#slider-container');
if (compareVersions(version, '0.4') >= 0 && dates.length) {
sliderContainer.style.display = '';
sliderContainer.innerHTML = `
<input id="slider-input" type="range" min="${dates[0]}" max="${dates[1]}" value="${dates[1]}" list="markers" step="any"></input>
<datalist id="markers">
</datalist>
<p>Date: <output id="slider-value"></output></p>
`;
const datalist = document.querySelector('#markers');

for (let i = 0; i < dates.length - 1; i++) {
datalist.innerHTML += `
<option value="${dates[i]}"></option>
`;
}

const value = document.querySelector('#slider-value');
const input = document.querySelector('#slider-input');
value.textContent = input.value;
input.addEventListener('input', (event) => {
value.textContent = event.target.value;
});

// TODO: set slider steps to all dates values
} else if (compareVersions(version, '0.4') <= 0 && dates.length) {
sliderContainer.style.display = '';
sliderContainer.innerHTML = `
<input type="range" disabled min="0" max="1" value="1"></input>
`;
} else {
sliderContainer.style.display = 'none';
}
};
37 changes: 37 additions & 0 deletions src/utils/bods.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,42 @@
import { compareVersions } from 'compare-versions';
export const closedRecords = new Set();
export const changedRecords = new Set();

export const getDates = (statements) => {
const uniqueDates = new Set();

for (const statement of statements) {
if (!uniqueDates.has(statement.statementDate)) {
uniqueDates.add(statement.statementDate);
}
}

const arr = Array.from(uniqueDates);
return arr.sort((a, b) => {
return a - b;
});
};

export const filteredData = (statements, version) => {
if (compareVersions(version, '0.4') >= 0) {
// get all statements with matching recordId and recordType values
const recordIdCount = {};

for (const statement of statements) {
const key = `${statement.recordId}-${statement.recordType}`;
recordIdCount[key] = (recordIdCount[key] || 0) + 1;
}

const duplicates = statements.filter((statement) => {
const key = `${statement.recordId}-${statement.recordType}`;
return recordIdCount[key] > 1;
});

console.log(duplicates);
} else {
// get all statements with statementID values in replacesStatements array
codemacabre marked this conversation as resolved.
Show resolved Hide resolved
}
};

export const latest = (statements, closedRecords, version) => {
if (compareVersions(version, '0.4') >= 0) {
Expand Down