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

Fixed deselection in Slicer wasn't apply to Globe map #104

Merged
merged 12 commits into from
Apr 11, 2024
Merged
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 3.3.3.0
* Fixed deselection in Slicer wasn't apply to Globe map

## 3.3.2.0
* Fixed console error "undefined CustomVisualObjects"

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "powerbi-visuals-globemap",
"description": "GlobeMap",
"version": "3.3.2.0",
"version": "3.3.3.0",
"author": {
"name": "Microsoft",
"email": "[email protected]"
Expand Down
2 changes: 1 addition & 1 deletion pbiviz.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"displayName": "GlobeMap",
"guid": "GlobeMap1447669447625",
"visualClassName": "GlobeMap",
"version": "3.3.2.0",
"version": "3.3.3.0",
"description": "A 3D visual using WebGL for plotting locations, with category values displayed as bar heights and heat maps.\n\nShift+Click on bar to change center point. \nSlicing data points will animate to average location.\n\nAttributions:\nthree.js - https://github.com/mrdoob/three.js/\nwebgl-heatmap - https://github.com/pyalot/webgl-heatmap",
"supportUrl": "https://aka.ms/customvisualscommunity",
"gitHubUrl": "https://github.com/Microsoft/powerbi-visuals-globemap"
Expand Down
89 changes: 26 additions & 63 deletions src/cache/CacheManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,31 @@ export class CacheManager {
private memoryCache: MemoryCache;
private localStorageCache: LocalStorageCache;
private bingGeocoder: BingGeocoder;
private coordsInLocalStorage: ILocationDictionary;
private localStorageService: IVisualLocalStorageV2Service;

constructor(localStorageService: IVisualLocalStorageV2Service) {
this.memoryCache = new MemoryCache(CacheSettings.MaxCacheSize, CacheSettings.MaxCacheSizeOverflow);
this.localStorageService = localStorageService;
this.bingGeocoder = new BingGeocoder();
this.coordsInLocalStorage = {};
constructor(localStorageService: IVisualLocalStorageV2Service, memoryCache?: MemoryCache, localStorageCache?: LocalStorageCache, bingGeocoder?: BingGeocoder) {
MulyukovAidar marked this conversation as resolved.
Show resolved Hide resolved
this.memoryCache = memoryCache ?? new MemoryCache(CacheSettings.MaxCacheSize, CacheSettings.MaxCacheSizeOverflow);
this.bingGeocoder = bingGeocoder ?? new BingGeocoder();
this.localStorageCache = localStorageCache ?? new LocalStorageCache(localStorageService);
}

private createLocalStorageCache(): IPromise2<LocalStorageCache, void> {
const cache: LocalStorageCache = new LocalStorageCache(this.localStorageService);

return cache.syncStatus()
.then(status => {
private createLocalStorageCache(): Promise<LocalStorageCache> {
return new Promise<LocalStorageCache>((resolve) => {
MulyukovAidar marked this conversation as resolved.
Show resolved Hide resolved
this.localStorageCache.syncStatus()
.then((status: powerbi.PrivilegeStatus) => {
console.log(`Received local storage status: ${status}`);
this.localStorageCache = cache;
return cache
});
resolve(this.localStorageCache);
})
MulyukovAidar marked this conversation as resolved.
Show resolved Hide resolved
});
}

private getLocationsFromBing = async (locations: string[], locationsInMemory: string[], locationsDictionary: ILocationKeyDictionary): Promise<ILocationDictionary> => {
private getLocationsFromBing = async (locations: string[], locationsDictionary: ILocationKeyDictionary): Promise<ILocationDictionary> => {
console.log("Getting locations from Bing...");

locationsDictionary = locations
.reduce((obj, key) => ({ ...obj, [key]: locationsDictionary[key] }), {});

const coordinatesFromBing = await this.bingGeocoder.geocode(locations);
const resultObject = Object.assign({}, locationsInMemory, this.coordsInLocalStorage, coordinatesFromBing);

return resultObject;
return coordinatesFromBing;
MulyukovAidar marked this conversation as resolved.
Show resolved Hide resolved
}

public async loadCoordinates(locationsDictionary: ILocationKeyDictionary): Promise<ILocationDictionary> {
Expand All @@ -56,58 +50,27 @@ export class CacheManager {
let locations: string[] = Object.keys(locationsDictionary);

// Load from memory
const coordsInMemory: ILocationDictionary = await this.memoryCache.loadCoordinates(locations); // {"London": {"lat": 54, "lon": 34"}, "Moscow": {"lat": 64, "lon": 54"}
const coordsInMemory: ILocationDictionary = this.memoryCache.loadCoordinates(locations); // {"London": {"lat": 54, "lon": 34"}, "Moscow": {"lat": 64, "lon": 54"}
MulyukovAidar marked this conversation as resolved.
Show resolved Hide resolved
locationsInMemory = Object.keys(coordsInMemory);

locations = locations.filter(loc => !locationsInMemory.includes(loc));

if (locations.length === 0) {
result = Object.assign({}, coordsInMemory);
return result;
}


// Load from localStorage
if (isEmpty(this.coordsInLocalStorage)) {
return this.createLocalStorageCache()
.then(cache => cache.loadCoordinates(locations))
.then(async (coordinatesPromise: Promise<ILocationDictionary>) => {
const coordinates = await coordinatesPromise;
if (coordinates && Object.keys(coordinates).length > 0) {
if (isEmpty(this.coordsInLocalStorage)) {
this.coordsInLocalStorage = coordinates;
}

if (this.coordsInLocalStorage) {
const locationsInLocalStorage = Object.keys(this.coordsInLocalStorage);
locations = locations.filter(loc => !locationsInLocalStorage.includes(loc));

if (locations.length === 0) {
result = Object.assign({}, locationsInMemory, this.coordsInLocalStorage);
return result;
}

// Load additional locations from Bing
const locationsFromBing = await this.getLocationsFromBing(locations, locationsInMemory, locationsDictionary);
return locationsFromBing;
}
}
else {
console.log("Local storage is empty, will attempt to load the coordinates from Bing API");

const locationsFromBing = await this.getLocationsFromBing(locations, locationsInMemory, locationsDictionary);
return locationsFromBing;
}

}).catch(async (e) => {
console.error("Error while loading coordinates from local storage", e);
const locationsFromBing = await this.getLocationsFromBing(locations, locationsInMemory, locationsDictionary);
return locationsFromBing;
});
}
else {
return this.coordsInLocalStorage;
// Load from local storage
const coordsInLocalStorage: ILocationDictionary = await this.createLocalStorageCache().then(cache => cache.loadCoordinates(locations));
MulyukovAidar marked this conversation as resolved.
Show resolved Hide resolved
const locationsInlocalStorage = Object.keys(coordsInLocalStorage);
locations = locations.filter(loc => !locationsInlocalStorage.includes(loc));
if (locations.length === 0) {
result = Object.assign({}, coordsInMemory, coordsInLocalStorage);
return result;
}

// Load from Bing
const coordsFromBing: ILocationDictionary = await this.getLocationsFromBing(locations, locationsDictionary);
result = Object.assign({}, coordsInMemory, coordsInLocalStorage, coordsFromBing);
return result;
}

public saveCoordinates(coordinates: ILocationDictionary): IPromise2<void, void> {
Expand Down
6 changes: 3 additions & 3 deletions src/cache/MemoryCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ export class MemoryCache {
this.maxCacheSizeOverflow = maxCacheSizeOverflow;
}

public async loadCoordinates(keys: string[]): Promise<ILocationDictionary> {
public loadCoordinates(keys: string[]): ILocationDictionary {
console.log("Loading from memory cache...");

if (!keys || !keys.length) {
return;
}

const locations: ILocationDictionary = {};
for (const key in this.geocodeCache) {
for (const key of keys) {
if (this.geocodeCache[key]) {
this.geocodeCache[key].hitCount++;
locations[key] = this.geocodeCache[key].coordinate;
Expand All @@ -44,7 +44,7 @@ export class MemoryCache {
return locations;
}

public saveCoordinates(coordinates: ILocationDictionary): Promise<void> {
public saveCoordinates(coordinates: ILocationDictionary): void {
console.log("Saving coordinates to memory cache...");

if (!coordinates) {
Expand Down
19 changes: 12 additions & 7 deletions src/geocoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,18 @@ export class BingGeocoder {
for (let i = 0; i < responseJson.resourceSets.length; i++) {
const currentSet: BingGeocodeResourceSet = responseJson.resourceSets[i];

const coordinates: number[] = currentSet.resources[0].point.coordinates;

const latitude: number = coordinates[0];
const longitude: number = coordinates[1];

const name: string = batch[i];
result[name] = { latitude, longitude };
if (!currentSet.resources[0]?.point){
console.log(`Could not get coordinates of '${batch[i]}' from Bing`);
}
else {
const coordinates: number[] = currentSet.resources[0].point.coordinates;

const latitude: number = coordinates[0];
const longitude: number = coordinates[1];

const name: string = batch[i];
result[name] = { latitude, longitude };
}
}
}));
} catch (e) {
Expand Down
46 changes: 22 additions & 24 deletions test/visualData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,28 @@ export class GlobeMapData extends TestDataViewBuilder {
80.237908
];

public coordinatesMock: ILocationDictionary = {
"addis ababa, ethiopia": {latitude: 9.03582859, longitude: 38.75241089},
"ahmedabad, india": {latitude: 23.0145092, longitude: 72.59175873},
"cairo, egypt": {latitude: 30.04348755, longitude: 31.23529243},
"cape town, south africa": {latitude: -33.92710876, longitude: 18.42006111},
"casablanca, morocco": {latitude: 33.59451294, longitude: -7.6200285},
"chennai, india": {latitude: 13.07209206, longitude: 80.20185852},
"durban, south africa": {latitude: -29.88188934, longitude: 30.98084259},
"jakarta, indonesia": {latitude: -6.17475653, longitude: 106.82707214},
"jeddah, saudi arabia": {latitude: 21.48730469, longitude: 39.18133545},
"lagos, nigeria": {latitude: 6.45505762, longitude: 3.39417958},
"lima, peru": {latitude: -12.06210613, longitude: -77.03652191},
"london, united kingdom": {latitude: 51.50740814, longitude: -0.12772401},
"mexico city, mexico": {latitude: 19.43267822, longitude: -99.13420868},
"new taipei city, republic of china": {latitude: 25.01170921, longitude: 121.46588135},
"riyadh, saudi arabia": {latitude: 24.69496918, longitude: 46.72412872},
"shanghai, china": {latitude: 31.23036957, longitude: 121.47370148},
"shenzhen, china": {latitude: 22.54368019, longitude: 114.0579071},
"surat, india": {latitude: 21.20350838, longitude: 72.83922577},
"tehran, iran": {latitude: 35.68925095, longitude: 51.38959885}
};

public valuesValue: number[] = getRandomNumbers(this.valuesSourceDestination.length, 10, 500);

public getDataView(columnNames?: string[]): DataView {
Expand Down Expand Up @@ -147,28 +169,4 @@ export class GlobeMapData extends TestDataViewBuilder {
}
], columnNames).build();
}

public getCoordinatesMock(): ILocationDictionary{
return {
"addis ababa, ethiopia": {latitude: 9.03582859, longitude: 38.75241089},
"ahmedabad, india": {latitude: 23.0145092, longitude: 72.59175873},
"cairo, egypt": {latitude: 30.04348755, longitude: 31.23529243},
"cape town, south africa": {latitude: -33.92710876, longitude: 18.42006111},
"casablanca, morocco": {latitude: 33.59451294, longitude: -7.6200285},
"chennai, india": {latitude: 13.07209206, longitude: 80.20185852},
"durban, south africa": {latitude: -29.88188934, longitude: 30.98084259},
"jakarta, indonesia": {latitude: -6.17475653, longitude: 106.82707214},
"jeddah, saudi arabia": {latitude: 21.48730469, longitude: 39.18133545},
"lagos, nigeria": {latitude: 6.45505762, longitude: 3.39417958},
"lima, peru": {latitude: -12.06210613, longitude: -77.03652191},
"london, united kingdom": {latitude: 51.50740814, longitude: -0.12772401},
"mexico city, mexico": {latitude: 19.43267822, longitude: -99.13420868},
"new taipei city, republic of china": {latitude: 25.01170921, longitude: 121.46588135},
"riyadh, saudi arabia": {latitude: 24.69496918, longitude: 46.72412872},
"shanghai, china": {latitude: 31.23036957, longitude: 121.47370148},
"shenzhen, china": {latitude: 22.54368019, longitude: 114.0579071},
"surat, india": {latitude: 21.20350838, longitude: 72.83922577},
"tehran, iran": {latitude: 35.68925095, longitude: 51.38959885}
};
}
}
Loading
Loading