Skip to content

Commit

Permalink
MET-6274 Menu behaviour / tooltip improvements / styling / tests
Browse files Browse the repository at this point in the history
  • Loading branch information
andyjmaclean committed Dec 13, 2024
1 parent 752f27e commit f1d7807
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 123 deletions.
44 changes: 44 additions & 0 deletions cypress/e2e/home.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ context('Statistics Dashboard', () => {
cy.visit('/');
});

const delayMapUpdate = 750;
const force = { force: true };

const selCountrySelect = '.link-select-country';

const selHeader = '.header';
const selHeaderTitle = `${selHeader} + .page-title-wrapper`;
const selLinkHeader = '[data-e2e=link-home-header]';
Expand All @@ -18,6 +23,45 @@ context('Statistics Dashboard', () => {
const selMap = '#mapChart';
const selMapLegend = '#mapLegend';

it('should allow countries to be selected and deselected', () => {
const selCloseMapSelection = '[data-e2e=close-map-selection]';

cy.get(selCountrySelect).should('exist');
cy.get(selCountrySelect)
.contains('Belgium')
.filter(':visible')
.should('exist');
cy.get(selCloseMapSelection).should('not.exist');

cy.wait(delayMapUpdate);
cy.get(selCountrySelect).contains('Belgium').click(force);

cy.get(selCountrySelect).filter(':visible').should('not.exist');
cy.get(selCloseMapSelection).should('exist');
});

it('should allow countries to be browsed', () => {
const selCountryNav = '.map-navigation-link';

cy.wait(delayMapUpdate);

cy.get(selCountryNav).should('not.exist');
cy.get(selCountrySelect).contains('Belgium').click(force);

cy.wait(delayMapUpdate);

cy.get(selCountryNav).should('exist');
cy.get(selCountryNav).contains('Norway').should('exist');
cy.get(selCountryNav).contains('Bulgaria').should('exist');
cy.get(selCountryNav).contains('Croatia').should('not.exist');

cy.get(selCountryNav).contains('Bulgaria').click(force);
cy.wait(delayMapUpdate);

cy.get(selCountryNav).contains('Norway').should('not.exist');
cy.get(selCountryNav).contains('Croatia').should('exist');
});

it('should show the header with home link and title', () => {
cy.get(selHeader).should('have.length', 1);
cy.get(selHeaderTitle).should('have.length', 1);
Expand Down
1 change: 0 additions & 1 deletion src/app/_data/colours.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ export const colourHeatmapRed = colourHqRed;
export const colourHeatmapYellow = colourTotalYellow;

const primarySequence = [colour3dBlue, colourHqRed, colourTotalYellow];
//const primarySequence = ['#0A72CC', '#E11D53', '#FFAE00'];

const secondarySequence = [greenForest, pinkLight, blue];
const tertiarySequence = [pinkBright, blueLight, green];
Expand Down
4 changes: 3 additions & 1 deletion src/app/chart/map/map.component.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
@import "../../../scss/_variables";

#mapChart,
#mapChartHidden {
height: 275px;
height: $map-height;
width: 100%;
}

Expand Down
32 changes: 31 additions & 1 deletion src/app/chart/map/map.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';

import * as am4core from '@amcharts/amcharts4/core';
import * as am4maps from '@amcharts/amcharts4/maps';

import { APIService } from '../../_services';
import { MockAPIService } from '../../_mocked';
Expand Down Expand Up @@ -84,7 +85,6 @@ describe('MapComponent', () => {
component.polygonSeries = null;
expect(component.polygonSeries).toBeFalsy();
component.drawChart();
fixture.detectChanges();
expect(component.polygonSeries).not.toBeFalsy();
expect(component.polygonSeries.data.length).toEqual(0);
});
Expand All @@ -105,6 +105,36 @@ describe('MapComponent', () => {
expect(component.updateHeatRules).toHaveBeenCalled();
});

it('should add tooltips to the countries', () => {
const clicked = {
dataItem: { dataContext: { id: 'IT' } }
} as unknown as am4maps.MapPolygon;
let res = component.mapTooltipAdapter('default', clicked);
expect(res).toEqual('{name}');

component.mapData = [{ id: 'IT', value: 1881 }];
res = component.mapTooltipAdapter('default', clicked);
expect(res).toEqual('{name}: 1,881');

component.mapPercentMode = true;
res = component.mapTooltipAdapter('default', clicked);
expect(res).toEqual('{name}: 1,881%');
});

it('should handle clicks on the country', () => {
component.drawChart();
expect(component.selectedCountry).toBeFalsy();

const country = 'IT';
component._isAnimating = true;
component.countryClick(country);
component._isAnimating = false;
expect(component.selectedCountry).toBeFalsy();

component.countryClick(country);
expect(component.selectedCountry).toEqual(country);
});

it('should track which countries are shown', () => {
component.mapData = [{ id: 'IT', value: 1881 }];
spyOn(component.polygonSeries.events, 'once');
Expand Down
129 changes: 30 additions & 99 deletions src/app/chart/map/map.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export class MapComponent {
_mapData: Array<IdValue>;
chart: am4maps.MapChart;
chartHidden: am4maps.MapChart;
mapPercentMode = false;
polygonSeries: am4maps.MapPolygonSeries;
polygonSeriesHidden: am4maps.MapPolygonSeries;
legend: am4maps.HeatLegend;
Expand All @@ -62,10 +63,7 @@ export class MapComponent {
_isAnimating = false;

set isAnimating(isAnimating: boolean) {
this.log('set isAnimating(' + isAnimating + ')');

if (isAnimating === this.isAnimating) {
this.log('set returns early same val ' + isAnimating);
return;
}

Expand All @@ -75,9 +73,7 @@ export class MapComponent {
this.chart.seriesContainer.events.disableType('hit');
this.chart.chartContainer.background.events.disableType('hit');
this.polygonSeries.mapPolygons.template.events.disableType('hit');

this.chart.seriesContainer.draggable = false;
this.log(' - set drag off');
} else {
this.chart.events.enableType('hit');
this.chart.seriesContainer.events.enableType('hit');
Expand Down Expand Up @@ -291,19 +287,15 @@ export class MapComponent {

const oldCountry = this.polygonSeries.include[0];
if (this.polygonSeriesHidden.include.length === 1) {
this.log('countryMorph exit: animating!');
return;
}
if (this.polygonSeries.include.length > 1) {
this.log('countryMorph exit: not in single country mode');
return;
}
if (oldCountry === newCountry) {
this.log('countryMorph exit: old and new are the same: ' + oldCountry);
return;
}

this.log('countryMorph sets animating to true...');
this.isAnimating = true;

// curtail the hidden map to include only the
Expand All @@ -312,8 +304,6 @@ export class MapComponent {
this.selectedCountry = newCountry;

this.polygonSeriesHidden.events.once('validated', () => {
this.log('countryMorph hidden once validated...');

const polyHidden = this.polygonSeriesHidden.mapPolygons.getIndex(0);
const poly = this.polygonSeries.getPolygonById(oldCountry);

Expand All @@ -322,7 +312,6 @@ export class MapComponent {
this.polygonSeriesHidden.data = [];
this.polygonSeriesHidden.include = this.mapCountries;
setTimeout(() => {
this.log('morphAnimationEnded (setTimeout) call sci ' + newCountry);
this.setCountryInclusion([newCountry]);
});
};
Expand All @@ -336,23 +325,17 @@ export class MapComponent {
: poly.polygon.morpher.morphToCircle(1, this.animationTime);
morphAnimation.events.on('animationended', morphAnimationEnded);
} else {
this.log('WE HAVE NO POLY ' + newCountry + ' / ' + oldCountry);
morphAnimationEnded();
}
});
}

log(s: string): void {
console.log(s);
}

/** countryClick
* @param { string } country - the clicked country
* toggles selected setCountryInclusion with (optional animation)
**/
countryClick(country: string): void {
if (this.isAnimating) {
this.log('return countryClick isAnimating');
return;
}

Expand All @@ -361,8 +344,6 @@ export class MapComponent {
// revert back to full map (will invoke zoomTo with instant effect)
this.setCountryInclusion(this.mapCountries);
} else {
this.log('countryClick sets animating to true...');

this.isAnimating = true;

// set selection and zoom
Expand Down Expand Up @@ -397,13 +378,35 @@ export class MapComponent {
});
}

/** setPercentMode
* @param { boolean } percent - sets tooltip behaviour
/** mapTooltipAdapter
* customises map item tooltip
**/
setPercentMode(usePercent: boolean): void {
const polygonTemplate = this.polygonSeries.mapPolygons.template;
const suffix = usePercent ? ' %' : '';
polygonTemplate.tooltipText = '{name}: {value}' + suffix;
mapTooltipAdapter(html: string, ev: am4maps.MapPolygon): string {
const mapData = this.mapData;
const ctxtId = ev.dataItem.dataContext['id'];
const dataItem = mapData.find((item) => {
return item['id'] === ctxtId;
});
if (!dataItem) {
return '{name}';
} else {
const suffix = this.mapPercentMode ? '%' : '';
return (
'{name}: ' + Number(dataItem.value).toLocaleString('en-GB') + suffix
);
}
}

/** setMapPercentMode
* @param { boolean } usePercent
* sets the variable and adapter for tooltip behaviour
**/
setMapPercentMode(usePercent: boolean): void {
this.mapPercentMode = usePercent;
this.polygonSeries.mapPolygons.template.adapter.add(
'tooltipHTML',
this.mapTooltipAdapter.bind(this)
);
}

/** drawChart
Expand Down Expand Up @@ -529,7 +532,7 @@ export class MapComponent {
// Configure series tooltip
const polygonTemplate = polygonSeries.mapPolygons.template;

this.setPercentMode(false);
this.setMapPercentMode(false);
polygonTemplate.nonScalingStroke = true;
polygonTemplate.strokeWidth = 0.5;

Expand Down Expand Up @@ -578,84 +581,17 @@ export class MapComponent {
const [north, south, east, west] = this.getBoundingCoords(zoomTo);

if (zoomLevelIn === ZoomLevel.SINGLE) {
//this.log('aspectRatioChart single ' + aspectRatioChart);

zoomLevel = zoomLevelSingle;
if (aspectRatioChart > 2.4) {
this.log('correct single');
zoomLevel = 0.75;
}
if (aspectRatioChart > 3.4) {
this.log('correct single ++');
zoomLevel = 0.725;
}
} else if (zoomLevelIn === ZoomLevel.MULTIPLE) {
zoomLevel = zoomLevelMultiple;
} else {
const selectionHeight = north - south;
const aspectRatioSelection = (east - west) / selectionHeight;

//aspectRatioChart = this.chart.pixelWidth / this.chart.pixelHeight;
const aspectRatioCombined =
this.chart.pixelWidth /
(east - west) /
(this.chart.pixelHeight / selectionHeight);

this.log('aspectRatioChart\t\t' + aspectRatioChart.toFixed(2));
this.log('aspectRatioSelection\t\t' + aspectRatioSelection.toFixed(2));
this.log('aspectRatioCombined\t\t' + aspectRatioCombined.toFixed(2));

/*
// SLOVAKIA
aspectRatioChart 3.498181818181818
aspectRatioSelection 3.0945371279031675
aspectRatioCombined 1.130437824332118
// TURKEY
aspectRatioChart 3.498181818181818
aspectRatioSelection 3.0055379493581755
aspectRatioCombined 1.1639120440747872
the fact that slovakia is fine and turkey is not means it's more to do with size!
*/

/*
//
const getRatio = (tgt: number, val: number, rec = 0): number => {
const half = val / 2;
if (tgt > val) {
return 0;
}
if (tgt > half) {
return Math.max(rec, 1) + ((val / tgt) % 1);
//return Math.max(rec, 1) + ((val / tgt) % 1);
}
return getRatio(tgt, half, rec + 1);
};
zoomLevel = getRatio(selectionHeight, this.mapHeight);
//zoomLevel = zoomLevelSingle * zoomLevel;
// zoomLevel -= aspectRatioSelection / aspectRatioChart;
let finalSutraction = aspectRatioChart / aspectRatioSelection;
let finalSutractionAlt = Math.min(aspectRatioChart, aspectRatioSelection) / aspectRatioChart;
//zoomLevel -= finalSutraction;
this.log('aspectRatioChart: ' + aspectRatioChart + '\nspectRatioSelection = ' + aspectRatioSelection + '...');
*/
//this.log('... = finalSutraction = ' + finalSutraction.toFixed(2));
//this.log('... = finalSutractionAlt = ' + finalSutractionAlt.toFixed(2));
//this.log('... = zoomLevel to subtract from = ' + zoomLevel.toFixed(2));

//zoomLevel -= finalSutractionAlt;
zoomLevel = 1;

// zoomLevel = zoomLevel / finalSutraction;//Math.min(aspectRatioSelection, aspectRatioChart);

//zoomLevel -= aspectRatioChart;// / aspectRatioSelection;
// zoomLevel -= Math.max(aspectRatioSelection, aspectRatioChart);
// zoomLevel = Math.max(1, zoomLevel);
}

const res = this.chart.zoomToRectangle(
Expand All @@ -669,20 +605,15 @@ export class MapComponent {
);

if (duration === 0) {
this.log('zoomTo empty duration falsifies');
this.isAnimating = false;
}
//this.isAnimating = false;

res.events.on('animationstopped', () => {
if (this.isAnimating) {
this.log('zoomTo animationstopped');
this.isAnimating = false;
}
});

res.events.on('animationended', () => {
this.log('zoomTo animationended');
this.isAnimating = false;
});

Expand Down
Loading

0 comments on commit f1d7807

Please sign in to comment.