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

JIDEA-168: component tests for globe #93

Merged
merged 25 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6ef9f79
Add dependencies required for unit testing with amcharts
david-mears-2 Nov 11, 2024
6dc3984
Small refactors in Globe component
david-mears-2 Nov 12, 2024
b21f78f
WIP: Writing component tests for Globe
david-mears-2 Nov 12, 2024
af2745a
Use own script to reverse geodata winding order, to fix Globe compone…
david-mears-2 Nov 13, 2024
4994839
Merge branch 'main' into jidea-168-globe-component-tests
david-mears-2 Nov 13, 2024
ca70aaa
Merge branch 'main' into jidea-168-globe-component-tests
david-mears-2 Nov 15, 2024
e0381e5
Merge branch 'main' into jidea-168-globe-component-tests
david-mears-2 Nov 15, 2024
9b857d9
Post-merge fixes
david-mears-2 Nov 15, 2024
52ea4cc
Fix globe component
david-mears-2 Nov 18, 2024
d62f350
Merge pull request #96 from jameel-institute/fix-globe-component
david-mears-2 Nov 19, 2024
d54c25b
Use correct 'chart' object in Globe component test
david-mears-2 Nov 19, 2024
66aacaf
Remove obsolete prop in test
david-mears-2 Nov 19, 2024
5e1c3fd
Comments
david-mears-2 Nov 19, 2024
45c0993
Create utility func for getting highlighted country series
david-mears-2 Nov 19, 2024
8fbdee6
Make test more robust
david-mears-2 Nov 19, 2024
533af58
Write to different file than read
david-mears-2 Nov 21, 2024
5d38a0c
remove configure step from working globe branch
EmmaLRussell Nov 22, 2024
4ecbd9a
add docker check
EmmaLRussell Nov 22, 2024
27e8519
try adding a pause
EmmaLRussell Nov 22, 2024
3f56bba
fix typo
EmmaLRussell Nov 22, 2024
bc8e27a
cut pause time
EmmaLRussell Nov 22, 2024
7083591
remove docker check
EmmaLRussell Nov 23, 2024
302cb71
add comment
EmmaLRussell Nov 23, 2024
88058db
Add comment
david-mears-2 Nov 25, 2024
d682944
Merge pull request #98 from jameel-institute/api-no-configure-globe
EmmaLRussell Nov 25, 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
42,484 changes: 21,242 additions & 21,242 deletions assets/geodata/2pc_downsampled_WHO_adm0_22102024.js

Large diffs are not rendered by default.

680 changes: 340 additions & 340 deletions assets/geodata/2pc_downsampled_WHO_disputed_areas_22102024.js

Large diffs are not rendered by default.

79,098 changes: 39,549 additions & 39,549 deletions assets/geodata/4pc_downsampled_WHO_adm0_22102024.js

Large diffs are not rendered by default.

1,420 changes: 710 additions & 710 deletions assets/geodata/4pc_downsampled_WHO_disputed_areas_22102024.js

Large diffs are not rendered by default.

40 changes: 40 additions & 0 deletions assets/geodata/reverseWindingOrder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* eslint-disable no-console */
/* eslint-disable node/prefer-global/process */
import * as fs from "node:fs";

// Get the file path from command-line arguments
const filePath = process.argv[2];

if (!filePath) {
console.error("Please provide the file path as a command-line argument.");
process.exit(1);
}

// Load the GeoJSON file
const fileContent = fs.readFileSync(filePath, "utf8");

// Extract the map object from the file content
// eslint-disable-next-line no-eval
const map = eval(fileContent.replace("export default", ""));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you could do this as a dynamic import. But it doesn't really matter!


// Function to reverse the winding order of coordinates
function reverseWindingOrder(geometry) {
if (geometry.type === "Polygon") {
geometry.coordinates = geometry.coordinates.map(ring => ring.reverse());
} else if (geometry.type === "MultiPolygon") {
geometry.coordinates = geometry.coordinates.map(polygon => polygon.map(ring => ring.reverse()));
}
}

// Process each feature in the map
map.features.forEach((feature) => {
reverseWindingOrder(feature.geometry);
});

// Convert the map object back to a string
const updatedFileContent = `const map = ${JSON.stringify(map, null, 2)};\nexport default map;`;

// Save the updated content back to the file
fs.writeFileSync(`reversed_${filePath}`, updatedFileContent, "utf8");

console.log("Winding order reversed successfully.");

Check warning on line 40 in assets/geodata/reverseWindingOrder.js

View check run for this annotation

Codecov / codecov/patch

assets/geodata/reverseWindingOrder.js#L2-L40

Added lines #L2 - L40 were not covered by tests
9 changes: 8 additions & 1 deletion assets/geodata/shapefiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,14 @@ convert_to_js_map(simplified_who_adm0$disp_area, id_col = "name", name_col = "na

You'll need to add the line `export default map;` to the end of the new js file so it can be imported.

To use this data you need to tell amCharts to reverse the polygons' points, since otherwise the borders will be inside out, and each country will be rendered as covering most of the globe except for itself! That's because the WHO data uses the opposite 'winding order' for polygons, compared to amCharts. Use amCharts' `reverseGeodata: true` option. Note that this operation seems to mutate some variable, since any immediately subsequent call does not require the same option to be passed.
### Winding order

To use this data we need to reverse the polygons' points, since otherwise the borders will be inside out, and each country will be rendered as covering most of the globe except for itself! That's because the WHO data uses the opposite 'winding order' for polygons, compared to amCharts. Although amCharts provides a `reverseGeodata: true` option, it's more complication than it's worth, since this operation seems to mutate the source geojson, such that any immediately subsequent call would require `reverseGeodata: false`. (This also pollutes the source geodata between unit tests in a test suite.) The simpler way to manage this is to reverse the winding order of the data _ourselves_, which is a pre-processing step you should perform before committing the new geodata files to git, using the script assets/geodata/reverseWindingOrder.js:

```
cd assets/geodata
node reverseWindingOrder.js simplified_WHO_adm0_22102024.js
```

### Customizations

Expand Down
6 changes: 6 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this file needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. Might be worth sticking in a comment to that effect as I for one will definitely forget that.

presets: [
["@babel/preset-env", { targets: { node: "current" } }],
"@babel/preset-typescript",
],
};
21 changes: 12 additions & 9 deletions components/Globe.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import type { MultiPolygon } from "geojson";
import WHONationalBorders from "@/assets/geodata/2pc_downsampled_WHO_adm0_22102024";
import WHODisputedAreas from "@/assets/geodata/2pc_downsampled_WHO_disputed_areas_22102024";
import { animateSeriesColourChange, type Animation, createRotateAnimation, geoPointZoomDuration, getWideGeoBounds, handlePolygonActive, initializeSeries, pauseAnimations, removeSeries, rotateToCentroid, southEastAsiaXCoordinate } from "@/components/utils/globe";
import { amountToTiltTheEarthUpwardsBy, animateSeriesColourChange, type Animation, createRotateAnimation, geoPointZoomDuration, getWideGeoBounds, handlePolygonActive, initializeSeries, pauseAnimations, removeSeries, rotateToCentroid, southEastAsiaXCoordinate } from "@/components/utils/globe";
import { rgba2hex } from "@amcharts/amcharts5/.internal/core/util/Color";
import * as am5 from "@amcharts/amcharts5/index";
import * as am5map from "@amcharts/amcharts5/map";
Expand Down Expand Up @@ -72,10 +72,11 @@
paddingTop: 20,
paddingLeft: 20,
paddingRight: 20,
pinchZoom: false,
wheelX: "none",
wheelY: "none",
rotationX: southEastAsiaXCoordinate, // Initialize map on SE Asia
rotationY: -20,
rotationY: -amountToTiltTheEarthUpwardsBy,
};
// Shared settings for countries.
const countrySeriesSettings: am5map.IMapPolygonSeriesSettings = {
Expand Down Expand Up @@ -138,7 +139,6 @@
return am5map.MapPolygonSeries.new(root, {
...highlightedCountrySeriesSettings,
geoJSON: findFeatureForCountry(appStore.globe.highlightedCountry),
reverseGeodata: false,
fill: startingColor,
});
});
Expand Down Expand Up @@ -190,17 +190,17 @@
};

const setUpBackgroundSeries = () => {
backgroundSeries = initializeSeries(root, chart, { ...backgroundSeriesSettings, reverseGeodata: true });
backgroundSeries = initializeSeries(root, chart, { ...backgroundSeriesSettings });
backgroundSeries.mapPolygons.template.setAll({ tooltipText: "{name} is not currently available", toggleKey: "active", interactive: true });
backgroundSeries.mapPolygons.template.on("active", (_active, target) => handlePolygonActive(target, prevBackgroundPolygon));
};

const setUpAntarcticaSeries = () => {
initializeSeries({ ...backgroundSeriesSettings, geoJSON: worldLow, include: ["AQ"] });
initializeSeries(root, chart, { ...backgroundSeriesSettings, geoJSON: worldLow, include: ["AQ"] });
};

const setUpSelectableCountriesSeries = () => {
selectableCountriesSeries = initializeSeries(root, chart, { ...selectableCountriesSeriesSettings, reverseGeodata: false });
selectableCountriesSeries = initializeSeries(root, chart, { ...selectableCountriesSeriesSettings });
selectableCountriesSeries.mapPolygons.template.setAll({
tooltipText: "{name}",
toggleKey: "active",
Expand Down Expand Up @@ -237,13 +237,12 @@
Object.keys(disputedLands).forEach((disputedArea) => {
disputedLands[disputedArea].mapSeries = initializeSeries(root, chart, {
...disputedLandSeriesSettings,
reverseGeodata: true,
include: [disputedArea],
fill: disputedLands[disputedArea].colorAsSelectable ? defaultLandColour : unselectableLandColor,
});
});

initializeSeries(root, chart, { ...disputedBodiesOfWaterSeriesSettings, reverseGeodata: true });
initializeSeries(root, chart, { ...disputedBodiesOfWaterSeriesSettings });
};

const setUpChart = () => {
Expand Down Expand Up @@ -289,7 +288,11 @@
rotatedToCountry.value = "";
// TODO: Make more memory efficient by not re-creating the animations every time
gentleRotateAnimation = createRotateAnimation(chart);
graduallyResetYAxis = chart.animate({ key: "rotationY", to: 0, duration: 20000, easing: am5.ease.inOut(am5.ease.cubic) });
if (graduallyResetYAxis) {
graduallyResetYAxis.play();

Check warning on line 292 in components/Globe.vue

View check run for this annotation

Codecov / codecov/patch

components/Globe.vue#L292

Added line #L292 was not covered by tests
} else {
graduallyResetYAxis = chart.animate({ key: "rotationY", to: 0, duration: 20000, easing: am5.ease.inOut(am5.ease.cubic) });
}
animations = [gentleRotateAnimation, graduallyResetYAxis];
}
};
Expand Down
2 changes: 1 addition & 1 deletion components/utils/globe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import * as am5 from "@amcharts/amcharts5/index";
import * as am5map from "@amcharts/amcharts5/map";

// To place any country of interest on the 'upper-facing' part of the globe. Just looks better.
const amountToTiltTheEarthUpwardsBy = 25;
const rotateDuration = 2000;
export const amountToTiltTheEarthUpwardsBy = 25;
export const geoPointZoomDuration = 2000;
export const southEastAsiaXCoordinate = -100;

Expand Down
Loading
Loading