Skip to content

Commit

Permalink
Merge pull request #165 from OutSystems/ROU-4708
Browse files Browse the repository at this point in the history
ROU-4708: adding new APIs for adding/removing marker and marker events
  • Loading branch information
rugoncalves authored Mar 8, 2024
2 parents 2e48230 + 1a76aa8 commit e014979
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 37 deletions.
5 changes: 5 additions & 0 deletions src/OSFramework/Maps/Enum/ErrorCodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ namespace OSFramework.Maps.Enum {
API_FailedRemoveMarkerFromCluster = 'MAPS-API-09001',
API_FailedContainsLocation = 'MAPS-API-05005',
API_FailedGettingCenterCoordinates = 'MAPS-API-01001',
API_FailedCreateMarker = 'MAPS-API-09002',
API_FailedRemoveMarker = 'MAPS-API-09003',
API_FailedRemoveMarkers = 'MAPS-API-09004',
API_FailedSubscribeMarkerEvent = 'MAPS-API-09005',
API_FailedUnsubscribeMarkerEvent = 'MAPS-API-09006',

// Error Codes - GENeral error - General or internal Errors of the component. In the situation of simple components without different features/sections inside it, the GEN acronym should be used.
GEN_InvalidChangePropertyMap = 'MAPS-GEN-01001',
Expand Down
12 changes: 4 additions & 8 deletions src/OSFramework/Maps/Event/Marker/MarkerEventsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,27 +72,23 @@ namespace OSFramework.Maps.Event.Marker {
// The following events are being deprecated. They should get removed soon.
switch (eventType) {
case MarkerEventType.Initialized:
case MarkerEventType.OnMouseout:
case MarkerEventType.OnMouseover:
handlerEvent.trigger(
this._marker.map.widgetId, // Id of Map block that was initialized
this._marker.widgetId || this._marker.uniqueId, // Id of Marker block that was initialized
eventType,
this._marker.index // Index of Marker block that was initialized
);
break;
case MarkerEventType.OnClick:
handlerEvent.trigger(
this._marker.map.widgetId, // Id of Map block that was clicked
this._marker.widgetId || this._marker.uniqueId, // Id of Marker block that was clicked
eventType,
...args // Coordinates retrieved from the marker event that got triggered
);
break;
case MarkerEventType.OnMouseout:
case MarkerEventType.OnMouseover:
handlerEvent.trigger(
this._marker.map.widgetId, // Id of Map block that was clicked
this._marker.widgetId || this._marker.uniqueId, // Id of Marker block that was clicked
this._marker.index // Index of Marker block that was clicked
);
break;
case MarkerEventType.OnEventTriggered:
handlerEvent.trigger(
this._marker.map.widgetId, // Id of Map block that triggered the event
Expand Down
17 changes: 17 additions & 0 deletions src/OSFramework/Maps/OSMap/AbstractMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace OSFramework.Maps.OSMap {
private _heatmapLayersSet: Set<HeatmapLayer.IHeatmapLayer>;
private _isReady: boolean;
private _mapEvents: Event.OSMap.MapEventsManager;
private _mapRefreshRequest: number;
private _mapType: Enum.MapType;
private _markers: Map<string, Marker.IMarker>;
private _markersSet: Set<Marker.IMarker>;
Expand Down Expand Up @@ -38,6 +39,7 @@ namespace OSFramework.Maps.OSMap {
this._isReady = false;
this._mapEvents = new Event.OSMap.MapEventsManager(this);
this._mapType = mapType;
this._mapRefreshRequest = 0;
this._providerType = providerType;
this._zoomChanged = false;
this._mapZoomChangeCallback = this._mapZoomChangeHandler.bind(this);
Expand Down Expand Up @@ -156,6 +158,13 @@ namespace OSFramework.Maps.OSMap {
this._widgetId = Helper.GetElementByUniqueId(this.uniqueId).closest(this.mapTag).id;
}

public cancelScheduledResfresh(): void {
if (this._mapRefreshRequest !== 0) {
clearTimeout(this._mapRefreshRequest);
this._mapRefreshRequest = 0;
}
}

public changeProperty(propertyName: string, propertyValue: unknown): void {
//Update Map's config when the property is available
if (this.config.hasOwnProperty(propertyName)) {
Expand Down Expand Up @@ -404,6 +413,14 @@ namespace OSFramework.Maps.OSMap {
}
}

public scheduleRefresh(): void {
this.cancelScheduledResfresh();

this._mapRefreshRequest = setTimeout(() => {
this.refresh();
}, 0);
}

public updateHeight(): void {
// Because only some specific map providers like Leaflet Provider need to update or refresh the map after changing its height,
// this function doesn't need any logic
Expand Down
13 changes: 12 additions & 1 deletion src/OSFramework/Maps/OSMap/IMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ namespace OSFramework.Maps.OSMap {
* @returns Shape that has been created
*/
addShape(shape: OSFramework.Maps.Shape.IShape): OSFramework.Maps.Shape.IShape;
/**
* Stops the current refresh from being refreshed.
*
* @memberof IMap
*/
cancelScheduledResfresh(): void;
/**
* Change property of a drawingTools from the DrawingTools by specifying the property name and the new value
* @param drawingToolsId id of the DrawingTools
Expand Down Expand Up @@ -194,12 +200,17 @@ namespace OSFramework.Maps.OSMap {
* @param shapeId id of the shape
*/
removeShape(shapeId: string): void;
/**
* Schedules the map to be refreshed so, that the bulk operations are made fast.
* @memberof IMap
*/
scheduleRefresh(): void;
/**
* Adds a custom render to the Clusters. Applicable to some providers only.
* @param {OSFramework.Maps.Feature.IMarkerClusterer} renderer
* @memberof IMap
*/
setClusterRenderer?(renderer: OSFramework.Maps.Feature.IMarkerClustererRender);
setClusterRenderer?(renderer: OSFramework.Maps.Feature.IMarkerClustererRender): void;
/**
* Updates the Height of the Map by refreshing/updating the provider
*/
Expand Down
24 changes: 17 additions & 7 deletions src/OutSystems/Maps/MapAPI/MapManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,16 +79,23 @@ namespace OutSystems.Maps.MapAPI.MapManager {
export function GetMapById(mapId: string, raiseError = true): OSFramework.Maps.OSMap.IMap {
let map: OSFramework.Maps.OSMap.IMap;

//mapId is the UniqueId
if (maps.has(mapId)) {
// mapId = uniqueId
map = maps.get(mapId);
} else {
//Search for WidgetId
for (const p of maps.values()) {
if (p.equalsToID(mapId)) {
map = p;
break;
}
// map = widgetId
// Search for (all) the map(s) that have this WidgetId
const mapFiltered = Array.from(maps.values()).filter((p) => p.equalsToID(mapId));

// There can be situations, for example when changing from a page
// to another page that also has a "Map", in which, we'll end up
// having 2 maps, with different uniqueIds, but same Widget id.
if (mapFiltered.length > 0) {
// So we'll always pick the last map of that was found and it
// will correspond to the last map that was created in the app
// (in these cases, the new map). The other map, is the one
// that will be destroyed afterwards.
map = mapFiltered[mapFiltered.length - 1];
}
}

Expand Down Expand Up @@ -148,6 +155,9 @@ namespace OutSystems.Maps.MapAPI.MapManager {
}

map.dispose();

//Let's remove the empty markers references from the Markers API.
MarkerManager.RemoveAllMarkers(mapId, false);
}

/**
Expand Down
55 changes: 47 additions & 8 deletions src/OutSystems/Maps/MapAPI/MarkerManager.Events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,30 @@ namespace OutSystems.Maps.MapAPI.MarkerManager.Events {
* @export
* @param {string} markerId Marker where the events will get attached
* @param {OSFramework.Maps.Event.Marker.MarkerEventType} eventName name of the event to get attached
* @param {OSFramework.Maps.Callbacks.Marker.ClickEvent} callback to be invoked when the event occurs
* @param {OSFramework.Maps.Callbacks.Marker.Event} callback to be invoked when the event occurs
*/
export function Subscribe(
markerId: string,
eventName: OSFramework.Maps.Event.Marker.MarkerEventType,
// eslint-disable-next-line
callback: OSFramework.Maps.Callbacks.Marker.Event
): void {
const marker = GetMarkerById(markerId);
marker.markerEvents.addHandler(eventName, callback, markerId);
): string {
const responseObj = {
isSuccess: true,
message: 'Success',
code: '200',
};
try {
const marker = GetMarkerById(markerId);
marker.markerEvents.addHandler(eventName, callback, markerId);
// Let's make sure the events get refreshed on the Marker provider
marker.refreshProviderEvents();
} catch (error) {
responseObj.isSuccess = false;
responseObj.message = error.message;
responseObj.code = OSFramework.Maps.Enum.ErrorCodes.API_FailedSubscribeMarkerEvent;
}

return JSON.stringify(responseObj);
}

/**
Expand All @@ -78,7 +92,7 @@ namespace OutSystems.Maps.MapAPI.MarkerManager.Events {
* @export
* @param {string} eventUniqueId Id of the Event to be attached
* @param {OSFramework.Maps.Event.Map.MapEventType} eventName name fo the event to be attached
* @param {MapAPI.Callbacks.OSMap.Event} callback callback to be invoked when the event occurs
* @param {OSFramework.Maps.Callbacks.Marker.Event} callback callback to be invoked when the event occurs
*/
export function SubscribeByUniqueId(
eventUniqueId: string,
Expand Down Expand Up @@ -135,12 +149,11 @@ namespace OutSystems.Maps.MapAPI.MarkerManager.Events {
* @export
* @param {string} eventUniqueId Map where the event will be removed
* @param {OSFramework.Maps.Event.Map.MapEventType} eventName name of the event to be removed
* @param {MapAPI.Callbacks.OSMap.Event} callback callback that will be removed
* @param {OSFramework.Maps.Callbacks.Marker.Event} callback callback that will be removed
*/
export function Unsubscribe(
eventUniqueId: string,
eventName: OSFramework.Maps.Event.Marker.MarkerEventType,
// eslint-disable-next-line
callback: OSFramework.Maps.Callbacks.Marker.Event
): void {
const markerId = GetMarkerIdByEventUniqueId(eventUniqueId);
Expand All @@ -160,6 +173,32 @@ namespace OutSystems.Maps.MapAPI.MarkerManager.Events {
}
}
}

export function UnsubscribeByMarkerId(
markerId: string,
eventName: OSFramework.Maps.Event.Marker.MarkerEventType,
callback: OSFramework.Maps.Callbacks.Marker.Event
): string {
const responseObj = {
isSuccess: true,
message: 'Success',
code: '200',
};
try {
const marker = GetMarkerById(markerId);
if (marker !== undefined) {
marker.markerEvents.removeHandler(eventName, callback);
// Let's make sure the events get refreshed on the Marker provider
marker.refreshProviderEvents();
}
} catch (error) {
responseObj.isSuccess = false;
responseObj.message = error.message;
responseObj.code = OSFramework.Maps.Enum.ErrorCodes.API_FailedUnsubscribeMarkerEvent;
}

return JSON.stringify(responseObj);
}
}

/// Overrides for the old namespace - calls the new one, lets users know this is no longer in use
Expand Down
113 changes: 102 additions & 11 deletions src/OutSystems/Maps/MapAPI/MarkerManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,44 @@ namespace OutSystems.Maps.MapAPI.MarkerManager {
const markerMap = new Map<string, string>(); //marker.uniqueId -> map.uniqueId
const markerArr = new Array<OSFramework.Maps.Marker.IMarker>();

/**
* Creates and adds a marker to a map.
*
* @export
* @param {string} mapId Id of the map to which the marker should be added
* @param {string} configs Configurations for the marker
* @return {*} {string}
*/
export function AddMarker(mapId: string, configs: string): string {
const responseObj = {
isSuccess: true,
message: 'Success',
code: '200',
};

try {
const map = MapManager.GetMapById(mapId, true);
const markerId = OSFramework.Maps.Helper.GenerateUniqueId();
const marker = OSFramework.Maps.Marker.MarkerFactory.MakeMarker(
map,
markerId,
OSFramework.Maps.Enum.MarkerType.Marker,
JSON.parse(configs)
);
markerArr.push(marker);
markerMap.set(markerId, map.uniqueId);
map.addMarker(marker);

responseObj.message = markerId;
} catch (error) {
responseObj.isSuccess = false;
responseObj.message = error.message;
responseObj.code = OSFramework.Maps.Enum.ErrorCodes.API_FailedCreateMarker;
}

return JSON.stringify(responseObj);
}

/**
* Changes the property value of a given Marker.
*
Expand Down Expand Up @@ -226,18 +264,71 @@ namespace OutSystems.Maps.MapAPI.MarkerManager {
* @export
* @param {string} markerID id of the Marker that is about to be removed
*/
export function RemoveMarker(markerId: string): void {
const marker = GetMarkerById(markerId);
const map = marker.map;
export function RemoveMarker(markerId: string): string {
const responseObj = {
isSuccess: true,
message: 'Success',
code: '200',
};
try {
const marker = GetMarkerById(markerId);
const map = marker.map;
map && map.removeMarker(markerId);

markerMap.delete(markerId);
markerArr.splice(
markerArr.findIndex((p) => {
return p && p.equalsToID(markerId);
}),
1
);
} catch (error) {
responseObj.isSuccess = false;
responseObj.message = error.message;
responseObj.code = OSFramework.Maps.Enum.ErrorCodes.API_FailedRemoveMarker;
}

map && map.removeMarker(markerId);
markerMap.delete(markerId);
markerArr.splice(
markerArr.findIndex((p) => {
return p && p.equalsToID(markerId);
}),
1
);
return JSON.stringify(responseObj);
}

/**
* Removes all the markers of a given map.
*
* @export
* @param {string} mapId
* @return {*} {string}
*/
export function RemoveAllMarkers(mapId: string, removeFromMap = true): string {
const responseObj = {
isSuccess: true,
message: 'Success',
code: '200',
};
try {
if (removeFromMap) {
// First we try to remove the markers from the map.
MapManager.RemoveMarkers(mapId);
}

// Second remove the markers to destroy from local variables.
markerMap.forEach((storedMapId, storedMarkerId) => {
if (mapId === storedMapId) {
markerMap.delete(storedMarkerId);
markerArr.splice(
markerArr.findIndex((p) => {
return p && p.equalsToID(storedMarkerId);
}),
1
);
}
});
} catch (error) {
responseObj.isSuccess = false;
responseObj.message = error.message;
responseObj.code = OSFramework.Maps.Enum.ErrorCodes.API_FailedRemoveMarkers;
}

return JSON.stringify(responseObj);
}
}

Expand Down
Loading

0 comments on commit e014979

Please sign in to comment.