var Module;
var SDK_version = "7.1.67BD45A3";
/**
*
* @private
* @returns {string}
*/
function getBaseURL() {
var originURL = window.location.origin;
if (originURL.localeCompare("https://new.magiclane.com") === 0)
return originURL + "/";
else
if (originURL.localeCompare("https://internal.magiclane.com") === 0)
return originURL + "/";
else
if (originURL.localeCompare("https://developer.magiclane.com") === 0)
return originURL + "/";
else
if (originURL.localeCompare("https://new.generalmagic.com") === 0)
return originURL + "/";
else
if (originURL.localeCompare("https://internal.generalmagic.com") === 0)
return originURL + "/";
else
if (originURL.localeCompare("https://developer.generalmagic.com") === 0)
return originURL + "/";
else
if (originURL.localeCompare("https://intranet.generalmagic.com") === 0)
return originURL + "/";
else
if (originURL.localeCompare("https://testing.magiclane.com") === 0)
return originURL + "/";
return "https://www.magiclane.com/";
}
var baseURL = getBaseURL();
var sourceWebsite = baseURL + "sdk/js/" + SDK_version + "/";
/**
* @namespace gem
* @class gem
*/
class gem {
}
/**
*@namespace gem.core
*@alias gem.core
*@hideconstructor
*@memberof gem
*/
class core {
}
gem.core = core;
/**Routing And Navigation Namespace
* @namespace
* @alias gem.routesAndNavigation
* @hideconstructor
* @memberof gem
*/
gem.routesAndNavigation = class routingandnavigation {
static getEVCarModels() {
return new gem.routesAndNavigation.EVCarModelsList(Module.getEVCarModels());
}
}
/**
* @class gem.d3Scene
* @namespace gem.d3Scene
* @hideconstructor
* @memberof gem
*/
gem.d3Scene = class _3dScene {
}
/**
* @class gem.content
* @namespace gem.content
* @hideconstructor
* @memberof gem
*/
gem.content = class content {
}
/**
* @typedef {object} gem.core.Xy
* @property {number} x - x coordinate
* @property {number} y - y coordinate
*/
/**
* @typedef {object} gem.core.Coordinates
* @property {number} latitude - between -90 -> 90
* @property {number} longitude - between -180 -> 180
* @property {number} altitude - altitude
* @property {number} bearing - bearing Angle between 0 - 360
*/
/**
* @typedef {object} gem.core.RectangleFloat
* @property {number} x - bottom left X value
* @property {number} y - bottom right Y value
* @property {number} width - width of the rectangle
* @property {number} height - height of the rectangle
*/
/**
* @typedef {object} gem.core.RectangleInteger
* @property {number} x - bottom left X value
* @property {number} y - bottom right Y value
* @property {number} width - width of the rectangle
* @property {number} height - height of the rectangle
*/
/**
* @typedef {object} gem.core.ColorInfo
* @property {number} r - red channel (0-255)
* @property {number} g - green channel (0-255)
* @property {number} b - blue channel (0-255)
* @property {number} a - alpha channel (0-255)
*/
/**
* @typedef {object} gem.core.TimeAndDistance
* @property {number} totaltime
* @property {number} totaldistance
*/
/**
* @typedef {object} gem.routesAndNavigation.SurfaceSection
* @property {number} startDistanceM - Distance in meters where the section starts
* @property {gem.routesAndNavigation.ESurfaceType} categ - The type of surface
*/
/**
* @typedef {object} gem.routesAndNavigation.RoadTypeSection
* @property {number} startDistanceM - Distance in meters where the section starts
* @property {gem.routesAndNavigation.ERoadType} categ - The type of road
*/
/**
* @typedef {object} gem.routesAndNavigation.SteepSection
* @property {number} startDistanceM - Distance in meters where the section starts
* @property {number} categ - The category of steep
*/
/**
* @typedef {object} gem.core.BoundingBox
* @property {gem.core.Coordinates} leftTop - left top corner
* @property {gem.core.Coordinates} rightBottom - right bottom Corner
* @property {boolean} isEmpty - if it valid or not
*/
/**
* @typedef {object} gem.core.WikiDescriptionListener
*/
/** @typedef {object} gem.routesAndNavigation.ElectricBikeProfile
* @property {gem.routesAndNavigation.EEBikeType} type
* @property {number} bikeMass - Bike mass in kg. If 0.0 , a default value is used
* @property {number} bikerMass - Biker mass in kg. If 0.0 , a default value is used
* @property {number} auxConsumptionDay - Bike auxiliary power consumption during day in Watts. If 0.0, a default value is used
* @property {number} auxConsumptionNight - Bike auxiliary power consumption during night in Watts. If 0.0, a default value is used
* @property {boolean} ignoreLegalRestrictions - Ignore country based legal restrictions related to e-bikes
*/
/**
* Emscripten wrapper for object class
* @class Em_Object
*/
class Em_Object {
/**
* Constructor
* @param {object} origObject - Emscripten object
*/
constructor(origObject) {
this.m_object = origObject;
}
/**
*calls emscripten object destructor
*/
delete() {
this.m_object.delete();
}
/**Check if emscripten object has been deleted
* @returns {boolean}
*/
isDeleted() {
return this.m_object.isDeleted();
}
/**Returns emscripten object
* @returns {object}
*/
getRawPointer() {
return this.m_object;
}
getFormattedText() {
}
getValue() {
}
}
/**Emscripten wrapper to vector class
* @class Em_Vector
* @augments Em_Object
*/
class Em_Vector extends Em_Object {
/**
* Get item at position
* @param {number} position - position in vector
* @returns {object} - Returns item at position
*/
get(position) {
return this.m_object.get(number);
}
/**
* Returns vector size
* @returns {number}*/
size() {
return this.m_object.size();
}
/**
*
* @param {object} object
*/
push_back(object) {
this.m_object.push_back(object);
}
}
/**
* @class Em_Enum
* @param {number} value
* @hideconstructor
*/
class Em_Enum {
constructor(value) {
this.value = value;
}
}
/**
* @class EAddressDetailLevel
* @memberof gem.core
* @alias gem.core.EAddressDetailLevel
* @description A class that represents the level of detail for an address.
* @hideconstructor
*/
gem.core.EAddressDetailLevel = class TAddressDetailLevel {
static initializeData() {
/**
* @memberof gem.core.EAddressDetailLevel
* @property {Em_Enum} gem.core.EAddressDetailLevel.EAD_NoDetail - No address details available.
*/
gem.core.EAddressDetailLevel.EAD_NoDetail = (Module.TAddressDetailLevel.EAD_NoDetail);
/**
* @memberof gem.core.EAddressDetailLevel
* @property {Em_Enum} gem.core.EAddressDetailLevel.EAD_Country - Country
*/
gem.core.EAddressDetailLevel.EAD_Country = (Module.TAddressDetailLevel.EAD_Country);
/**
* @memberof gem.core.EAddressDetailLevel
*@property {Em_Enum} gem.core.EAddressDetailLevel.EAD_State - State or province.
*/
gem.core.EAddressDetailLevel.EAD_State = (Module.TAddressDetailLevel.EAD_State);
/**
* @memberof gem.core.EAddressDetailLevel
*@property {Em_Enum} gem.core.EAddressDetailLevel.EAD_County - County, which is an entity between a state and a city.
*/
gem.core.EAddressDetailLevel.EAD_County = (Module.TAddressDetailLevel.EAD_County);
/**
* @memberof gem.core.EAddressDetailLevel
* @property {Em_Enum} gem.core.EAddressDetailLevel.EAD_District -Municipal district.
*/
gem.core.EAddressDetailLevel.EAD_District = (Module.TAddressDetailLevel.EAD_District);
/**
* @memberof gem.core.EAddressDetailLevel
* @property {Em_Enum} gem.core.EAddressDetailLevel.EAD_City -Town or city.
*/
gem.core.EAddressDetailLevel.EAD_City = (Module.TAddressDetailLevel.EAD_City);
/**
* @memberof gem.core.EAddressDetailLevel
* @property {Em_Enum} gem.core.EAddressDetailLevel.EAD_Settlement - Settlement.
*/
gem.core.EAddressDetailLevel.EAD_Settlement = (Module.TAddressDetailLevel.EAD_Settlement);
/**
* @memberof gem.core.EAddressDetailLevel
* @property {Em_Enum} gem.core.EAddressDetailLevel.EAD_PostalCode - Postal Code
*/
gem.core.EAddressDetailLevel.EAD_PostalCode = (Module.TAddressDetailLevel.EAD_PostalCode);
/**
* @memberof gem.core.EAddressDetailLevel
* @property {Em_Enum} gem.core.EAddressDetailLevel.EAD_Street - Street/road name.
*/
gem.core.EAddressDetailLevel.EAD_Street = (Module.TAddressDetailLevel.EAD_Street);
/**
* @memberof gem.core.EAddressDetailLevel
* @property {Em_Enum} gem.core.EAddressDetailLevel.EAD_StreetSection - Street section subdivision.
*/
gem.core.EAddressDetailLevel.EAD_StreetSection = (Module.TAddressDetailLevel.EAD_StreetSection);
/**
* @memberof gem.core.EAddressDetailLevel
*@property {Em_Enum} gem.core.EAddressDetailLevel.EAD_StreetLane - Street lane subdivision.
*/
gem.core.EAddressDetailLevel.EAD_StreetLane = (Module.TAddressDetailLevel.EAD_StreetLane);
/**
* @memberof gem.core.EAddressDetailLevel
* @property {Em_Enum} gem.core.EAddressDetailLevel.EAD_StreetAlley -Street alley subdivision.
*/
gem.core.EAddressDetailLevel.EAD_StreetAlley = (Module.TAddressDetailLevel.EAD_StreetAlley);
/**
* @memberof gem.core.EAddressDetailLevel
*@property {Em_Enum} gem.core.EAddressDetailLevel.EAD_HouseNumber - Address field denoting house number.
*/
gem.core.EAddressDetailLevel.EAD_HouseNumber = (Module.TAddressDetailLevel.EAD_HouseNumber);
/**
* @memberof gem.core.EAddressDetailLevel
*@property {Em_Enum} gem.core.EAddressDetailLevel.EAD_Crossing - Address field denoting a street in a crossing.
*/
gem.core.EAddressDetailLevel.EAD_Crossing = (Module.TAddressDetailLevel.EAD_Crossing);
}
static convertToInternal(number) {
switch (number) {
case Module.TAddressDetailLevel.EAD_NoDetail.value:
return Module.TAddressDetailLevel.EAD_NoDetail;
case Module.TAddressDetailLevel.EAD_Country.value:
return Module.TAddressDetailLevel.EAD_Country;
case Module.TAddressDetailLevel.EAD_State.value:
return Module.TAddressDetailLevel.EAD_State;
case Module.TAddressDetailLevel.EAD_County.value:
return Module.TAddressDetailLevel.EAD_County;
case Module.TAddressDetailLevel.EAD_District.value:
return Module.TAddressDetailLevel.EAD_District;
case Module.TAddressDetailLevel.EAD_City.value:
return Module.TAddressDetailLevel.EAD_City;
case Module.TAddressDetailLevel.EAD_Settlement.value:
return Module.TAddressDetailLevel.EAD_Settlement;
case Module.TAddressDetailLevel.EAD_PostalCode.value:
return Module.TAddressDetailLevel.EAD_PostalCode;
case Module.TAddressDetailLevel.EAD_Street.value:
return Module.TAddressDetailLevel.EAD_Street;
case Module.TAddressDetailLevel.EAD_StreetSection.value:
return Module.TAddressDetailLevel.EAD_StreetSection;
case Module.TAddressDetailLevel.EAD_StreetLane.value:
return Module.TAddressDetailLevel.EAD_StreetLane;
case Module.TAddressDetailLevel.EAD_StreetAlley.value:
return Module.TAddressDetailLevel.EAD_StreetAlley;
case Module.TAddressDetailLevel.EAD_HouseNumber.value:
return Module.TAddressDetailLevel.EAD_HouseNumber;
case Module.TAddressDetailLevel.EAD_Crossing.value:
return Module.TAddressDetailLevel.EAD_Crossing;
}
}
}
const EViewDataTransitionStatus = {
VD_Complete: 0,
VD_IncompleteOnline: 1
};
const EViewCameraTransitionStatus = {
CT_Stationary: 0,
CT_Moving: 1
}
/**
* Enumeration for different types of address fields.
* @enum {number}
* @property {number} Extension - Represents the extension field of an address.
* @property {number} BuildingFloor - Represents the building floor field of an address.
* @property {number} BuildingName - Represents the building name field of an address.
* @property {number} BuildingRoom - Represents the building room field of an address.
* @property {number} BuildingZone - Represents the building zone field of an address.
* @property {number} StreetName - Represents the street name field of an address.
* @property {number} StreetNumber - Represents the street number field of an address.
* @property {number} PostalCode - Represents the postal code field of an address.
* @property {number} Settlement - Represents the settlement field of an address.
* @property {number} City - Represents the city field of an address.
* @property {number} County - Represents the county field of an address.
* @property {number} State - Represents the state field of an address.
* @property {number} StateCode - Represents the state code field of an address.
* @property {number} Country - Represents the country field of an address.
* @property {number} CountryCode - Represents the country code field of an address.
* @property {number} District - Represents the district field of an address.
* @property {number} Crossing1 - Represents the first crossing field of an address.
* @property {number} Crossing2 - Represents the second crossing field of an address.
* @property {number} SegmentName - Represents the segment name field of an address.
* @property {number} AddrLast - Represents the last address field.
*/
const EAddressField = {
Extension: 0,
BuildingFloor: 1,
BuildingName: 2,
BuildingRoom: 3,
BuildingZone: 4,
StreetName: 5,
StreetNumber: 6,
PostalCode: 7,
Settlement: 8,
City: 9,
County: 10,
State: 11,
StateCode: 12,
Country: 13,
CountryCode: 14,
District: 15,
Crossing1: 16,
Crossing2: 17,
SegmentName: 18,
AddrLast: 19,
};
gem.core.EAddressField = EAddressField;
/**
* @class gem.routesAndNavigation.ERouteType
* @description Route Type
* @property {Em_Enum} gem.routesAndNavigation.ERouteType.ERT_Fastest - Route type - fastest route type
* @property {Em_Enum} gem.routesAndNavigation.ERouteType.ERT_Shortest - Route type - shortest route type
* @property {Em_Enum} gem.routesAndNavigation.ERouteType.ERT_Economic - Route type - economical route type
* @hideconstructor
*/
gem.routesAndNavigation.ERouteType = class TRouteType {
static ERT_Fastest() {
return gem.routesAndNavigation.ERouteType.ERT_Fastest;
}
static ERT_Shortest() {
return gem.routesAndNavigation.ERouteType.ERT_Shortest;
}
static ERT_Economic() {
return gem.routesAndNavigation.ERouteType.ERT_Economic;
}
static initializeData() {
gem.routesAndNavigation.ERouteType.ERT_Fastest = Module.RouteType.ERT_Fastest;
gem.routesAndNavigation.ERouteType.ERT_Shortest = Module.RouteType.ERT_Shortest;
gem.routesAndNavigation.ERouteType.ERT_Economic = Module.RouteType.ERT_Economic;
}
}
/**
* @class gem.routesAndNavigation.ERouteTransportMode
* @description Transport Mode
* @hideconstructor
* @property {Em_Enum} gem.routesAndNavigation.ERouteTransportMode.ETM_Car - car
* @property {Em_Enum} gem.routesAndNavigation.ERouteTransportMode.ETM_Lorry - lorry/truck
* @property {Em_Enum} gem.routesAndNavigation.ERouteTransportMode.ETM_Bicycle - bicycle
* @property {Em_Enum} gem.routesAndNavigation.ERouteTransportMode.ETM_Pedestrian - on foot
* @property {Em_Enum} gem.routesAndNavigation.ERouteTransportMode.ETM_Public - public transport
* @property {Em_Enum} gem.routesAndNavigation.ERouteTransportMode.ETM_Uber - uber
* @property {Em_Enum} gem.routesAndNavigation.ERouteTransportMode.ETM_Shared_Vehicles - shared vehicle
*/
gem.routesAndNavigation.ERouteTransportMode = class TRouteTransportMode {
static ETM_Public() {
return gem.routesAndNavigation.ERouteTransportMode.ETM_Public;
}
static ETM_Lorry() {
return gem.routesAndNavigation.ERouteTransportMode.ETM_Lorry;
}
static ETM_Bicycle() {
return gem.routesAndNavigation.ERouteTransportMode.ETM_Bicycle;
}
static ETM_Pedestrian() {
return gem.routesAndNavigation.ERouteTransportMode.ETM_Pedestrian;
}
static ETM_Car() {
return gem.routesAndNavigation.ERouteTransportMode.ETM_Car;
}
static ETM_Uber() {
return gem.routesAndNavigation.ERouteTransportMode.ETM_Uber;
}
static ETM_Shared_Vehicles() {
return gem.routesAndNavigation.ERouteTransportMode.ETM_Shared_Vehicles;
}
static initializeData() {
gem.routesAndNavigation.ERouteTransportMode.ETM_Car = Module.TransportMode.ETM_Car;
gem.routesAndNavigation.ERouteTransportMode.ETM_Lorry = Module.TransportMode.ETM_Lorry;
gem.routesAndNavigation.ERouteTransportMode.ETM_Bicycle = Module.TransportMode.ETM_Bicycle;
gem.routesAndNavigation.ERouteTransportMode.ETM_Pedestrian = Module.TransportMode.ETM_Pedestrian;
gem.routesAndNavigation.ERouteTransportMode.ETM_Public = Module.TransportMode.ETM_Public;
gem.routesAndNavigation.ERouteTransportMode.ETM_Uber = Module.TransportMode.ETM_Uber;
gem.routesAndNavigation.ERouteTransportMode.ETM_Shared_Vehicles = Module.TransportMode.ETM_Shared_Vehicles;
}
}
/**
* @class gem.d3Scene.EMarkerType
* @description Data source geometry type
* @hideconstructor
*/
gem.d3Scene.EMarkerType = class TVectorDataType {
static initializeData() {
/**
*@property {Em_Enum} gem.d3Scene.EMarkerType.EVDT_Point - contains multi-points items
*/
gem.d3Scene.EMarkerType.EVDT_Point = Module.TVectorDataType.EVDT_Point;
/**
* @property {Em_Enum} gem.d3Scene.EMarkerType.EVDT_Polyline - contains polyline items
*/
gem.d3Scene.EMarkerType.EVDT_Polygon = Module.TVectorDataType.EVDT_Polygon;
/**
*@property {Em_Enum} gem.d3Scene.EMarkerType.EVDT_Polygon - contains polygon items
*/
gem.d3Scene.EMarkerType.EVDT_Polyline = Module.TVectorDataType.EVDT_Polyline;
}
}
/**
* @class gem.d3Scene.EUsableIcons
* @description API predefined icons ids
* @hideconstructor
*/
gem.d3Scene.EUsableIcons = class TUsableIcons {
static initializeData() {
/**
*@property {Em_Enum} gem.d3Scene.EUsableIcons.eNavigationLayoutBgr_SpeedAlarm
*/
gem.d3Scene.EUsableIcons.eNavigationLayoutBgr_SpeedAlarm = Module.Icons.eNavigationLayoutBgr_SpeedAlarm;
/**
* @property {Em_Enum} gem.d3Scene.EUsableIcons.eSearch_Results_Pin
*/
gem.d3Scene.EUsableIcons.eSearch_Results_Pin = Module.Icons.eSearch_Results_Pin;
/**
* @property {Em_Enum} gem.d3Scene.EUsableIcons.PublicTransport_Bus
*/
gem.d3Scene.EUsableIcons.PublicTransport_Bus = Module.Icons.PublicTransport_Bus;
/**
* @property {Em_Enum} gem.d3Scene.EUsableIcons.PublicTransport_Underground
*/
gem.d3Scene.EUsableIcons.PublicTransport_Underground = Module.Icons.PublicTransport_Underground;
/**
* @property {Em_Enum} gem.d3Scene.EUsableIcons.PublicTransport_Train
*/
gem.d3Scene.EUsableIcons.PublicTransport_Train = Module.Icons.PublicTransport_Train;
/**
* @property {Em_Enum} gem.d3Scene.EUsableIcons.PublicTransport_Tram
*/
gem.d3Scene.EUsableIcons.PublicTransport_Tram = Module.Icons.PublicTransport_Tram;
/**
* @property {Em_Enum} gem.d3Scene.EUsableIcons.PublicTransport_Water
*/
gem.d3Scene.EUsableIcons.PublicTransport_Water = Module.Icons.PublicTransport_Water;
/**
* @property {Em_Enum} gem.d3Scene.EUsableIcons.PublicTransport_Other
*/
gem.d3Scene.EUsableIcons.PublicTransport_Other = Module.Icons.PublicTransport_Other;
/**
* @property {Em_Enum} gem.d3Scene.EUsableIcons.PublicTransport_Walk
*/
gem.d3Scene.EUsableIcons.PublicTransport_Walk = Module.Icons.PublicTransport_Walk;
/**
* @property {Em_Enum} gem.d3Scene.EUsableIcons.YellowBall
*/
gem.d3Scene.EUsableIcons.YellowBall = Module.Icons.YellowBall;
/**
* @property {Em_Enum} gem.d3Scene.EUsableIcons.BlueBall
*/
gem.d3Scene.EUsableIcons.BlueBall = Module.Icons.BlueBall;
/**
* @property {Em_Enum} gem.d3Scene.EUsableIcons.Waypoint_Start
*/
gem.d3Scene.EUsableIcons.Waypoint_Start = Module.Icons.Waypoint_Start;
/**
* @property {Em_Enum} gem.d3Scene.EUsableIcons.Waypoint_Intermediary
*/
gem.d3Scene.EUsableIcons.Waypoint_Intermediary = Module.Icons.Waypoint_Intermediary;
/**
* @property {Em_Enum} gem.d3Scene.EUsableIcons.Waypoint_Finish
*/
gem.d3Scene.EUsableIcons.Waypoint_Finish = Module.Icons.Waypoint_Finish;
}
}
/**
* @class gem.d3Scene.ECursorEvent
* @description Cursor Event type on a touch event(click event) handler
* @hideconstructor
*/
gem.d3Scene.ECursorEvent = class TCursorEvent {
static initializeData() {
/**
*@property {Em_Enum} gem.d3Scene.ECursorEvent.eCursorEvent_Down - cursor has been touch down
*/
gem.d3Scene.ECursorEvent.eCursorEvent_Down = Module.CursorEvent.eCursorEvent_Down;
/**
* @property {Em_Enum} gem.d3Scene.ECursorEvent.eCursorEvent_Move - cursor has been moved
*/
gem.d3Scene.ECursorEvent.eCursorEvent_Move = Module.CursorEvent.eCursorEvent_Move;
/**
* @property {Em_Enum} gem.d3Scene.ECursorEvent.eCursorEvent_Up - cursor has been released(touch up)
*/
gem.d3Scene.ECursorEvent.eCursorEvent_Up = Module.CursorEvent.eCursorEvent_Up;
}
}
/**
* @class gem.d3Scene.EHighlightOptions
* @description Landmarks highlight display options
* @hideconstructor
*/
gem.d3Scene.EHighlightOptions = class THighlightOptions {
static initializeData() {
/**
* @property {Em_Enum} gem.d3Scene.EHighlightOptions .EHO_ShowLandmark - Shows landmark icon & text ( default )
*/
gem.d3Scene.EHighlightOptions.EHO_ShowLandmark = Module.THighlightOptions.EHO_ShowLandmark;
/**
* @property {Em_Enum} gem.d3Scene.EHighlightOptions .EHO_ShowContour - Shows landmark impact area contour ( when available )
*/
gem.d3Scene.EHighlightOptions.EHO_ShowContour = Module.THighlightOptions.EHO_ShowContour;
/**
* @property {Em_Enum} gem.d3Scene.EHighlightOptions .EHO_Group - Groups landmarks.This option is available only in conjunction with EHO_ShowLandmark
*/
gem.d3Scene.EHighlightOptions.EHO_Group = Module.THighlightOptions.EHO_Group;
/**
* @property {Em_Enum} gem.d3Scene.EHighlightOptions .EHO_Overlap - Overlap highlight over existing map data. This option is available only in conjunction with EHO_ShowLandmark
*/
gem.d3Scene.EHighlightOptions.EHO_Overlap = Module.THighlightOptions.EHO_Overlap;
/**
* @property {Em_Enum} gem.d3Scene.EHighlightOptions .EHO_NoFading - Disable highlight fading in / out. This option is available only in conjunction with EHO_ShowLandmark
*/
gem.d3Scene.EHighlightOptions.EHO_NoFading = Module.THighlightOptions.EHO_NoFading;
}
}
/**
* @class gem.routesAndNavigation.ERoadType
* @description Road Type
* @hideconstructor
*/
gem.routesAndNavigation.ERoadType = class TRoadType {
static initializeData() {
/**
* @property {Em_Enum} gem.routesAndNavigation.ERoadType.EMotorways - Motorway
*/
gem.routesAndNavigation.ERoadType.EMotorways = Module.TRoadType.EMotorways;
/**
* @property {Em_Enum} gem.routesAndNavigation.ERoadType.EStateRoad - State Road
*/
gem.routesAndNavigation.ERoadType.EStateRoad = Module.TRoadType.EStateRoad;
/**
*@property {Em_Enum} gem.routesAndNavigation.ERoadType.ERoad - Road
*/
gem.routesAndNavigation.ERoadType.ERoad = Module.TRoadType.ERoad;
/**
* @property {Em_Enum} gem.routesAndNavigation.ERoadType.EStreet - Street
*/
gem.routesAndNavigation.ERoadType.EStreet = Module.TRoadType.EStreet;
/**
*@property {Em_Enum} gem.routesAndNavigation.ERoadType.ECycleway - Cycleway
*/
gem.routesAndNavigation.ERoadType.ECycleway = Module.TRoadType.ECycleway;
/**
*@property {Em_Enum} gem.routesAndNavigation.ERoadType.EPath - Path
*/
gem.routesAndNavigation.ERoadType.EPath = Module.TRoadType.EPath;
/**
*@property {Em_Enum} gem.routesAndNavigation.ERoadType.ESingleTrack - track
*/
gem.routesAndNavigation.ERoadType.ESingleTrack = Module.TRoadType.ESingleTrack;
}
}
/**
* @class gem.routesAndNavigation.ESurfaceType
* @description Surface Type
* @hideconstructor
*/
gem.routesAndNavigation.ESurfaceType = class TSurfaceType {
static initializeData() {
/**
*@property {Em_Enum} gem.routesAndNavigation.ESurfaceType.EAsphalt - Asphalt
*/
gem.routesAndNavigation.ESurfaceType.EAsphalt = Module.TSurfaceType.EAsphalt;
/**
*@property {Em_Enum} gem.routesAndNavigation.ESurfaceType.EPaved - Paved
*/
gem.routesAndNavigation.ESurfaceType.EPaved = Module.TSurfaceType.EPaved;
/**
*@property {Em_Enum} gem.routesAndNavigation.ESurfaceType.EUnpaved - Unpaved
*/
gem.routesAndNavigation.ESurfaceType.EUnpaved = Module.TSurfaceType.EUnpaved;
/**
* @property {Em_Enum} gem.routesAndNavigation.ESurfaceType.EUnknown - Unknown
*/
gem.routesAndNavigation.ESurfaceType.EUnknown = Module.TSurfaceType.EUnknown;
}
}
/**
* @class gem.content.EContentType
* @description Content Type
* @hideconstructor
* @property {Em_Enum} gem.content.EContentType.ECT_ViewStyleHighRes - View styles for high dpi displays ( e.g. mobile phones )
* @property {Em_Enum} gem.content.EContentType.ECT_ViewStyleLowRes - View styles for low dpi displays ( e.g. desktop monitors )
* @property {Em_Enum} gem.content.EContentType.ECT_RoadMap - Road Map
*/
gem.content.EContentType = class TContentType {
static ECT_ViewStyleHighRes() {
return gem.content.EContentType.ECT_ViewStyleHighRes;
}
static ECT_ViewStyleLowRes() {
return Module.TContentType.ECT_ViewStyleLowRes;
}
static ECT_RoadMap() {
return Module.TContentType.ECT_RoadMap;
}
static initializeData() {
gem.content.EContentType.ECT_ViewStyleHighRes = Module.TContentType.ECT_ViewStyleHighRes;
gem.content.EContentType.ECT_ViewStyleLowRes = Module.TContentType.ECT_ViewStyleLowRes;
gem.content.EContentType.ECT_RoadMap = Module.TContentType.ECT_RoadMap;
}
}
/**
* @class gem.routesAndNavigation.ERouteResultDetails
* @description Routing result details
* @hideconstructor
*/
gem.routesAndNavigation.ERouteResultDetails = class ERouteResultDetails {
static ERD_Full() {
return gem.routesAndNavigation.ERouteResultDetails.ERD_Full;
}
static ERD_TimeDistance() {
return gem.routesAndNavigation.ERouteResultDetails.ERD_TimeDistance;
}
static ERD_Path() {
return gem.routesAndNavigation.ERouteResultDetails.ERD_Path;
}
static initializeData() {
/**
*@property {Em_Enum} gem.routesAndNavigation.ERouteResultDetails.ERD_Full - Path and guidance
*/
gem.routesAndNavigation.ERouteResultDetails.ERD_Full = Module.TResultDetails.ERD_Full;
/**
* @property {Em_Enum} gem.routesAndNavigation.ERouteResultDetails.ERD_TimeDistance - Path time / distance only
*/
gem.routesAndNavigation.ERouteResultDetails.ERD_TimeDistance = Module.TResultDetails.ERD_TimeDistance;
/**
*@property {Em_Enum} gem.routesAndNavigation.ERouteResultDetails.ERD_Path - Path time / distance and geometry
*/
gem.routesAndNavigation.ERouteResultDetails.ERD_Path = Module.TResultDetails.ERD_Path;
}
}
/**
* @class gem.routesAndNavigation.ERoutePathAlgorithm
* @description Path calculation algorithm
* @hideconstructor
*/
gem.routesAndNavigation.ERoutePathAlgorithm = class ERoutePathAlgorithm {
static EPA_ME() {
return gem.routesAndNavigation.ERoutePathAlgorithm.EPA_ME;
}
static EPA_ExternalCH() {
return gem.routesAndNavigation.ERoutePathAlgorithm.EPA_ExternalCH;
}
static initializeData() {
/**
* @property {Em_Enum} gem.routesAndNavigation.ERoutePathAlgorithm.EPA_ME - Path calculation algorithm - Service default - Magic Earth routing algorithm
*/
gem.routesAndNavigation.ERoutePathAlgorithm.EPA_ME = Module.TPathAlgorithm.EPA_ME;
/**
*@property {Em_Enum} gem.routesAndNavigation.ERoutePathAlgorithm.EPA_ExternalCH - Path calculation algorithm - External CH routing algorithm
*/
gem.routesAndNavigation.ERoutePathAlgorithm.EPA_ExternalCH = Module.TPathAlgorithm.EPA_ExternalCH;
}
}
/**
* @class gem.routesAndNavigation.EBikeProfile
* @hideconstructor
* @property {Em_Enum} gem.routesAndNavigation.EBikeProfile.BP_Road - Bike profile - road
* @property {Em_Enum} gem.routesAndNavigation.EBikeProfile.BP_Cross - Bike profile - cross
* @property {Em_Enum} gem.routesAndNavigation.EBikeProfile.BP_City - Bike profile - city
* @property {Em_Enum} gem.routesAndNavigation.EBikeProfile.BP_Mountain - Bike profile - mountain
*/
gem.routesAndNavigation.EBikeProfile = class EBikeProfile {
static BP_Road() {
return gem.routesAndNavigation.EBikeProfile.BP_Road;
}
static BP_Cross() {
return gem.routesAndNavigation.EBikeProfile.BP_Cross;
}
static BP_City() {
return gem.routesAndNavigation.EBikeProfile.BP_City;
}
static BP_Mountain() {
return gem.routesAndNavigation.EBikeProfile.BP_Mountain;
}
static initializeData() {
gem.routesAndNavigation.EBikeProfile.BP_Road = Module.EBikeProfile.BP_Road;
gem.routesAndNavigation.EBikeProfile.BP_Cross = Module.EBikeProfile.BP_Cross;
gem.routesAndNavigation.EBikeProfile.BP_City = Module.EBikeProfile.BP_City;
gem.routesAndNavigation.EBikeProfile.BP_Mountain = Module.EBikeProfile.BP_Mountain;
}
}
/**
* @class gem.routesAndNavigation.EEBikeType
* @description eBike type
* @hideconstructor
* @property {Em_Enum} gem.routesAndNavigation.EEBikeType.EBP_None - eBike profile - none
* @property {Em_Enum} gem.routesAndNavigation.EEBikeType.EBP_Pedelec - eBike profile - pedelec
* @property {Em_Enum} gem.routesAndNavigation.EEBikeType.EBP_PowerOnDemand - eBike profile - power-on-demand
* @property {Em_Enum} gem.routesAndNavigation.EEBikeType.EBP_SPedelec - eBike type S-pedelec
*/
gem.routesAndNavigation.EEBikeType = class EEBikeType {
static EBP_None() {
return gem.routesAndNavigation.EEBikeType.EBP_None;
}
static EBP_Pedelec() {
return gem.routesAndNavigation.EEBikeType.EBP_Pedelec;
}
static EBP_PowerOnDemand() {
return gem.routesAndNavigation.EEBikeType.EBP_PowerOnDemand;
}
static EBP_SPedelec() {
return gem.routesAndNavigation.EEBikeType.EBP_SPedelec;
}
static initializeData() {
gem.routesAndNavigation.EEBikeType.EBP_None = Module.EEBikeType.EBP_None;
gem.routesAndNavigation.EEBikeType.EBP_Pedelec = Module.EEBikeType.EBP_Pedelec;
gem.routesAndNavigation.EEBikeType.EBP_PowerOnDemand = Module.EEBikeType.EBP_PowerOnDemand;
gem.routesAndNavigation.EEBikeType.EBP_SPedelec = Module.EEBikeType.EBP_SPedelec;
}
}
/**
* @class gem.ETouchGestures
* @description A class that represents different touch gestures.
*
* This class provides properties to get the different touch gestures.
*
* @property {object} TG_OnTouch
* Represents a single touch gesture.
*
* @property {object} TG_OnLongDown
* Represents a long press gesture.
*
* @property {object} TG_OnDoubleTouch
* Represents a double touch gesture.
*
* @property {object} TG_OnTwoPointersTouch
* Represents a two pointers touch gesture.
*
* @property {object} TG_OnTwoPointersDoubleTouch
* Represents a two pointers double touch gesture.
*
* @property {object} TG_OnMove
* Represents a move gesture.
*
* @property {object} TG_OnTouchMove
* Represents a touch move gesture.
*
* @property {object} TG_OnSwipe
* Represents a swipe gesture.
*
* @property {object} TG_OnPinchSwipe
* Represents a pinch swipe gesture.
*
* @property {object} TG_OnPinch
* Represents a pinch gesture.
*
* @property {object} TG_OnRotate
* Represents a rotate gesture.
*
* @property {object} TG_OnShove
* Represents a shove gesture.
*
* @property {object} TG_OnTouchPinch
* Represents a touch pinch gesture.
*
* @property {object} TG_OnTouchShove
* Represents a touch shove gesture.
*/
gem.ETouchGestures = class ETouchGestures {
static TG_OnTouch() {
return gem.ETouchGestures.TG_OnTouch;
}
static TG_OnLongDown() {
return gem.ETouchGestures.TG_OnLongDown;
}
static TG_OnDoubleTouch() {
return gem.ETouchGestures.TG_OnDoubleTouch;
}
static TG_OnTwoPointersTouch() {
return gem.ETouchGestures.TG_OnTwoPointersTouch;
}
static TG_OnTwoPointersDoubleTouch() {
return gem.ETouchGestures.TG_OnTwoPointersDoubleTouch;
}
static TG_OnMove() {
return gem.ETouchGestures.TG_OnMove;
}
static TG_OnTouchMove() {
return gem.ETouchGestures.TG_OnTouchMove;
}
static TG_OnSwipe() {
return gem.ETouchGestures.TG_OnSwipe;
}
static TG_OnPinchSwipe() {
return gem.ETouchGestures.TG_OnPinchSwipe;
}
static TG_OnPinch() {
return gem.ETouchGestures.TG_OnPinch;
}
static TG_OnRotate() {
return gem.ETouchGestures.TG_OnRotate;
}
static TG_OnShove() {
return gem.ETouchGestures.TG_OnShove;
}
static TG_OnTouchPinch() {
return gem.ETouchGestures.TG_OnTouchPinch;
}
static TG_OnTouchShove() {
return gem.ETouchGestures.TG_OnTouchShove;
}
static initializeData() {
gem.ETouchGestures.TG_OnTouch = Module.ETouchGestures.TG_OnTouch;
gem.ETouchGestures.TG_OnLongDown = Module.ETouchGestures.TG_OnLongDown;
gem.ETouchGestures.TG_OnDoubleTouch = Module.ETouchGestures.TG_OnDoubleTouch;
gem.ETouchGestures.TG_OnTwoPointersTouch = Module.ETouchGestures.TG_OnTwoPointersTouch;
gem.ETouchGestures.TG_OnTwoPointersDoubleTouch = Module.ETouchGestures.TG_OnTwoPointersDoubleTouch;
gem.ETouchGestures.TG_OnMove = Module.ETouchGestures.TG_OnMove;
gem.ETouchGestures.TG_OnTouchMove = Module.ETouchGestures.TG_OnTouchMove;
gem.ETouchGestures.TG_OnSwipe = Module.ETouchGestures.TG_OnSwipe;
gem.ETouchGestures.TG_OnPinchSwipe = Module.ETouchGestures.TG_OnPinchSwipe;
gem.ETouchGestures.TG_OnPinch = Module.ETouchGestures.TG_OnPinch;
gem.ETouchGestures.TG_OnRotate = Module.ETouchGestures.TG_OnRotate;
gem.ETouchGestures.TG_OnShove = Module.ETouchGestures.TG_OnShove;
gem.ETouchGestures.TG_OnTouchPinch = Module.ETouchGestures.TG_OnTouchPinch;
gem.ETouchGestures.TG_OnTouchShove = Module.ETouchGestures.TG_OnTouchShove;
}
}
/**
* @class gem.core.ExternalInfo
* @description Wikipedia info. Required to get wikipedia info for Landmarks.
* @hideconstructor
*/
gem.core.ExternalInfo = class ExternalInfo extends Em_Object {
constructor(object) {
super(new Module.ExternalInfo())
}
cancelWikiInfo() {
this.m_object.cancelWikiInfo();
}
}
/**
* @enum {number}
* @description Route display options.
*/
const ERouteRenderOptions = {
/**
* Route is main route in collection (i.e., it overlaps all other siblings and has different render settings).
*/
RRS_Main: 0x1,
/**
* Display traffic status over the route. Default is true.
*/
RRS_ShowTraffic: 0x2,
/**
* Display the turn arrows associated with route guidance. Default is true.
*/
RRS_ShowTurnArrows: 0x4,
/**
* Display the route waypoints. Default is true.
*/
RRS_ShowWaypoints: 0x8,
/**
* Enable route highlights. Default is true.
* Public routes will render segments in color for bus, public & car routes; pedestrian parts are rendered differently.
*/
RRS_ShowHighlights: 0x10,
/**
* Display user waypoints images.
* If enabled, user landmark image will be displayed instead of standard pin image. Default is false.
*/
RRS_ShowUserImage: 0x20,
/**
* Display route direction arrows.
* If enabled, the direction arrows will be rendered over the route.
*/
RRS_ShowDirectionArrows: 0x40
};
gem.d3Scene.RouteRenderSettings = class RouteRenderSettings {
constructor(routeRenderSettings) {
this.options = routeRenderSettings?.options ?? [ERouteRenderOptions.RRS_ShowTraffic, ERouteRenderOptions.RRS_ShowTurnArrows, ERouteRenderOptions.RRS_ShowWaypoints, ERouteRenderOptions.RRS_ShowHighlights];
this.innerColor = routeRenderSettings?.innerColor ?? { r: 0, g: 0, b: 0, a: 0 };
this.outerColor = routeRenderSettings?.outerColor ?? { r: 0, g: 0, b: 0, a: 0 };
this.innerSz = routeRenderSettings?.innerSz ?? -1;
this.outerSz = routeRenderSettings?.outerSz ?? 0;
this.traveledInnerColor = routeRenderSettings?.traveledInnerColor ?? { r: 0, g: 0, b: 0, a: 0 };
this.turnArrowInnerColor = routeRenderSettings?.turnArrowInnerColor ?? { r: 0, g: 0, b: 0, a: 0 };
this.turnArrowOuterColor = routeRenderSettings?.turnArrowOuterColor ?? { r: 0, g: 0, b: 0, a: 0 };
this.turnArrowInnerSz = routeRenderSettings?.turnArrowInnerSz ?? -1;
this.turnArrowOuterSz = routeRenderSettings?.turnArrowOuterSz ?? 0;
}
}
/**View class
* @class gem.d3Scene.MapView
* @augments Em_Object
*/
gem.d3Scene.MapView = class MapView extends Em_Object {
/**
* Get the zoom level.
* @returns {number} The zoom value.
*/
getZoomLevel() {
return Module.View.getZoomLevel(this.m_object);
}
/**
* Get Maximum value for zoom level.
* @returns {number} The maximum zoom value.
*/
getMaxZoomLevel() {
return Module.View.getMaxZoomLevel(this.m_object);
}
/**
* Set zoom level
* @param {number} zoomLevel - The zoom value.
*/
setZoomLevel(zoomLevel) {
Module.View.setZoomLevel(this.m_object, zoomLevel);
}
/** Set zoom level, focusing in a specified screen point
* @param {number} zoomLevel - The zoom value.
* @param {number} durationMs - duration The animation duration in milliseconds (0 means no animation)
* @param {gem.core.Xy} positionInScreen Screen coordinates under which map should keep position.
*/
setZoomLevelOnPoint(zoomLevel, durationMs, positionInScreen) {
Module.View.setZoomLevelOnPoint(this.m_object, zoomLevel, durationMs, positionInScreen);
}
/** Center on a specified coordinates
* @param {gem.core.Coordinates} coordinates
* @param {number} durationMs
* @param {callback} callbackFunction
* @param {gem.core.iXy} iXy
* @param {number} zoomLevel - zoom level 0 - max zoom level. See getMaxZoomLevel()
*/
centerOnCoordinates(coordinates, durationMs, callbackFunction, iXy, zoomLevel) {
let viewRect = this.getViewport();
let xy;
if (iXy === undefined)
xy = {
x: viewRect.x + viewRect.width / 2,
y: viewRect.y + viewRect.height / 2
};
else
xy = iXy;
zoomLevel = zoomLevel === undefined ? 15 : zoomLevel;
Module.View.centerOnCoordinates(this.m_object, coordinates, durationMs === undefined ? 0 : durationMs, xy, callbackFunction, zoomLevel === undefined ? -1 : zoomLevel);
}
/** Set the map north-up oriented
* @param {number} durationMs - Animation duration in miliseconds. 0 - for instant north-up.
*/
alignNorthUp(durationMs) {
Module.View.alignNorthUp(this.m_object, durationMs);
}
/** Convert a screen coordinate to a WGS84 coordinate
* @param {gem.core.Xy} screenCoordinates - Screen coordinates
* @returns {gem.core.Coordinates} - WGS coordinates
*/
transformScreenToWgs(screenCoordinates) {
return Module.View.transformScreenToWgs(this.m_object, screenCoordinates);
}
/** Convert a WGS84 coordinate to a screen coordinate
* @param {gem.core.Coordinates} wgsCoordinates - wgs Coordinates
* @returns {gem.core.Xy} - Screen coordinates
*/
transformWgsToScreen(wgsCoordinates) {
return Module.View.transformWgsToScreen(this.m_object, wgsCoordinates);
}
/** Center the on the given WGS area specified by top left wgs coordinate and bottomright coordinate
* @param {gem.core.Coordinates} coordinatesTopLeft - top left coordinates
* @param {gem.core.Coordinates} coordinatesBottomRight - bottom right coordinates
* @param {number} durationMs - fly animation duration (milliseconds)
* @param {gem.core.RectangleFloat} rectangleFloat - custom view rectangle
* @param {callback} callbackfunction
* @param {number} zoomLevel - zoom level 0 - max zoom level. See getMaxZoomLevel()
*/
centerOnArea(coordinatesTopLeft, coordinatesBottomRight, durationMs, rectangleFloat, callbackfunction, zoomLevel) {
let viewRect = this.getViewport();
let rect;
if (rectangleFloat === undefined)
rect = viewRect;
else
rect = rectangleFloat;
if (durationMs === undefined)
Module.View.centerOnArea(this.m_object, coordinatesTopLeft, coordinatesBottomRight, -1, rect, callbackfunction, zoomLevel === undefined ? -1 : zoomLevel);
else
Module.View.centerOnArea(this.m_object, coordinatesTopLeft, coordinatesBottomRight, durationMs, rect, callbackfunction, zoomLevel === undefined ? -1 : zoomLevel);
}
/** Resize View
* @param {gem.core.RectangleFloat} rectangular - The new size as a rectangle.Values needs to be normalized from the screen size(0->1).
*/
resizeView(rectangular) {
Module.View.resizeView(this.m_object, rectangular);
}
/** set tilt angle
* @param {number} angle - tilt angle
*/
setTilt(angle) {
Module.View.setTilt(this.m_object, angle);
}
/** get tilt angle
* @returns {number} - tilt angle
*/
getTilt() {
return Module.View.getTilt(this.m_object);
}
/** Retrieve, in the given parameter, the list of landmarks under the cursor location.
* @param {gem.core.LandmarkList} resultedLandmarks - resulted Landmarks
*/
cursorSelectionLandmarks(resultedLandmarks) {
Module.View.cursorSelectionLandmarks(this.m_object, resultedLandmarks);
}
/** Set cursor position at a given position in the screen
* @param {gem.core.Xy} screenCoordinates - screen coordinates
*/
setCursorScreenPosition(screenCoordinates) {
Module.View.setCursorScreenPosition(this.m_object, screenCoordinates);
}
/** Get current cursor position as WGS Coordinates
* @returns {gem.core.Xy} - WGS Coordinates
*/
getCursorPositionWGS() {
return Module.View.getCursorPositionWGS(this.m_object);
}
/**
* set the style by id
* @param {number} nId
*/
setMapStyle(nId) {
Module.View.setMapStyle(nId);
}
getMapStyle() {
return Module.View.getMapStyle(this.m_object);
}
getLayersIdsAt(screenPosition) {
return Module.View.getLayersIdsAt(this.m_object, screenPosition);
}
/**
*
* @param {string} jsonBuffer - style buffer as a string
*/
updateCurrentStyleFromJson(jsonBuffer) {
Module.View.updateCurrentStyleFromJson(this.m_object, jsonBuffer);
}
/**
*
* @param {object} styleBuffer
*/
updateCurrentStyleFromStyleBuffer(styleBuffer) {
Module.View.updateCurrentStyleFromStyleBuffer(this.m_object, styleBuffer);
}
/**
* Toogle map perspective. Predefined tilt values switch
*/
toggleMapPerspective() {
Module.View.toggleMapPerspective(this.m_object);
}
/**
* Start following the current position.
* @param {number} maxZoomLevel - maximum zoom level
* @param {number} maxAngle - maximum angle
*/
startFollowingPosition(maxZoomLevel, maxAngle) {
Module.View.startFollowingPosition(this.m_object, maxZoomLevel === undefined ? -1 : maxZoomLevel, maxAngle === undefined ? 60 : maxAngle);
}
/**
*
* @param {gem.d3Scene.EMarkerType} dataType - type of the source
* @param {string} name - name given to the source
* @param {gem.d3Scene.MarkerCollectionDisplaySettings} markerCollectionDisplaySettings - display settings
* @returns {number} - generated source id
*/
createSource(dataType, name, markerCollectionDisplaySettings) {
if (markerCollectionDisplaySettings === undefined)
markerCollectionDisplaySettings = new gem.d3Scene.MarkerCollectionDisplaySettings();
return new gem.d3Scene.MarkerCollection(Module.View.createSource(this.m_object, dataType, name, markerCollectionDisplaySettings.getRawPointer()));
}
/**
* @callback callbackEdit
* @param {gem.d3Scene.ECursorEvent} event - event type
* @param {number} pointId - point Id
* @param {gem.core.Coordinates} coordinates - WGS Coordinates of the cursor.
* @param {gem.d3Scene.MarkerRef} parentVector - parent vector
*/
/**
*
* @param {callbackEdit} callback
*/
enableEdit(callback) {
var vectorConstructor = function (object) {
return new gem.d3Scene.Marker(new Module.Marker(object));
};
Module.View.enableEdit(this.m_object, callback, vectorConstructor);
}
/**
* Disable Edit Mode
*/
disableEdit() {
Module.View.disableEdit(this.m_object);
}
/**
* Center on Route Instruction
* @param {gem.routesAndNavigation.RouteInstruction} routeInstruction
* @param {gem.core.screenCoordinates} [screenCoordinates] - screen coordinates, where to center
* @param {number} [zoomLevel] - zoom level
*/
centerOnRouteInstruction(routeInstruction, screenCoordinates, zoomLevel) {
let viewRect = this.getViewport();
let xy;
if (screenCoordinates === undefined)
xy = {
x: viewRect.x + viewRect.width / 2,
y: viewRect.y + viewRect.width / 2
};
else
xy = screenCoordinates;
Module.View.centerOnRouteInstruction(this.m_object, routeInstruction.getRawPointer(), xy, zoomLevel === undefined ? -1 : zoomLevel);
}
/**
* Stop Following position
*/
stopFollowingPosition() {
Module.View.stopFollowingPosition(this.m_object);
}
//set map style by store content item. Get the list of available styles with gem.content.getLocalContentList(gem.content.EContentType.ECT_ViewStyleLowRes);
setMapStyleByStoreItem(contentStoreItem) {
Module.View.setMapStyleByStoreItem(this.m_object, contentStoreItem);
}
/**
* Start Orbit Mode
*/
startOrbitCamera() {
Module.View.startOrbitCamera();
}
/**
* Stop Orbit Mode
*/
stopOrbitCamera() {
Module.View.stopOrbitCamera();
}
/**
* Capture map screen
* @returns {Uint8Array} - screen buffer
*/
captureMapScreen() {
return Module.View.captureMapScreen(this.m_object);
}
/**
* Capture map screen
* @returns {gem.d3Scene.BitmapContainer}
*/
captureMapScreenAsBitmapContainer() {
return Module.View.captureMapScreenAsOffBitmap(this.m_object);
}
/**
* Check if is it in follow position mode
* @returns {boolean}
*/
isFollowingPosition() {
return Module.View.isFollowingPosition(this.m_object);
}
/**Enable the default highlight service for the given landmark list.
*
* @param {gem.core.LandmarkList} resultedLandmarks - landmark list on which to apply highlights
* @param {gem.core.ColorInfo} colorInfo - color do be used
* @param {gem.d3Scene.EHighlightOptions } options - options to be used for the landmark. Can be combined with | operator
* @param {gem.d3Scene.EUsableIcons } usableIcons - (optional) Icon to replace with
*/
activateHighlight(resultedLandmarks, colorInfo, options, usableIcons) {
if (usableIcons === undefined)
return Module.View.activateHighlight(resultedLandmarks.getRawPointer(), this.m_object, colorInfo, options, -1);
else
return Module.View.activateHighlight(resultedLandmarks.getRawPointer(), this.m_object, colorInfo, options, usableIcons);
}
/**
* Disable the highlight service.
*/
deactivateHighlight() {
Module.View.deactivateHighlight(this.m_object);
}
/**
* Add GeoJson as custom marker in the MapView
* @param {string} geojsonbuffer - Actual Geo Json string buffer.
* @param {string} name - name for the added source(s)
* @param {gem.sourceslist} sourceslist - output list of created vector sources
* @param {gem.d3Scene.ExternalRenderer} externalRenderer - optional. external renderer. If not used, the internal rendering will be used to display source data.
* @param {number} [maxGroupingLevel = 13] - maximum map level to apply grouping
*/
addGeoJsonAsCustomMarkers(geojsonbuffer, name, sourceslist, externalRenderer, maxGroupingLevel = 13) {
var constructorFunc = function (object) {
return object;
};
if (externalRenderer !== undefined)
Module.View.addGeoJsonAsCustomVector(this.m_object, geojsonbuffer, name, sourceslist.getRawPointer(), externalRenderer.callback.bind(externalRenderer), true, constructorFunc, maxGroupingLevel);
else
Module.View.addGeoJsonAsCustomVector(this.m_object, geojsonbuffer, name, sourceslist.getRawPointer(), null, false, constructorFunc, maxGroupingLevel);
}
/**
* Add Store Locations list as custom markers in the MapView
* @param {gem.core.StoreLocationList} storeList - Store List to be added to the view
* @param {string} name - Store list name
* @param {gem.sourceslist} sourceslist - output list of created vector sources
* @param {gem.d3Scene.ExternalRenderer} externalRenderer - optional. external renderer. If not used, the internal rendering will be used to display source data.
* @param {number} storeId - Store Id
* @param {number} [nMaxGroupingLevel = 13] - Maximum level on which grouping can occur
*/
addStoreListAsCustomMarkers(storeList, name, sourceslist, externalRenderer, storeId, nMaxGroupingLevel) {
var constructorFunc = function (object) {
return new gem.d3Scene.MarkerRef(object);
};
if (externalRenderer !== undefined) {
externalRenderer.mStoreList = new Map();
externalRenderer.mStoreId = storeId;
for (let i = 0; i < storeList.size(); i++) {
let it = storeList.get(i);
if (it !== undefined) {
it.mId = it.getId();
externalRenderer.mStoreList[it.mId] = it;
}
}
Module.View.addStoreListAsCustomVector(this.m_object, storeList.getRawPointer(), name, sourceslist.getRawPointer(), externalRenderer.callback.bind(externalRenderer), true, constructorFunc, nMaxGroupingLevel === undefined ? 13 : nMaxGroupingLevel);
} else
Module.View.addStoreListAsCustomVector(this.m_object, storeList.getRawPointer(), name, sourceslist.getRawPointer(), null, false, constructorFunc, 20);
}
/**
* Register click event listener for landmarks.
* @param {gem.core.LandmarkList} resultedLandmarks - used for adding the clicked landmarks
* @param {callback} callbackfunction - Click event callback
*/
registerLandmarkClickedEvent(resultedLandmarks, callbackfunction) {
Module.View.registerLandmarkClickedEvent(this.m_object, resultedLandmarks.getRawPointer(), callbackfunction);
}
/**
* @callback callbackMarkers
* @param {gem.d3Scene.OverlayItem} - markerlist - please convert to a Marker list wrapper
*/
/**
*
* @param {callbackMarkers} callbackfunction
*/
registerOverlayItemClickedEvent(callbackfunction) {
var createLandmark = function (object) {
return new gem.d3Scene.OverlayItemList(object.clone());
};
Module.View.registerMarkerClickedEvent(this.m_object, callbackfunction, createLandmark);
}
/** Add a route in the collection to be shown in the view
* @param {gem.Route} route - route that is being added
* @param {boolean} bIsMainRoute - if the route should be added as a main route or not.
* @param {boolean} bAddRouteLabels - if the route labels should be added or not.
* @param {RouteRenderSettings} routeRenderSettings - route render settings
*/
showRouteInView(route, bIsMainRoute, bAddRouteLabels,routeRenderSettings) {
if(routeRenderSettings === undefined)
routeRenderSettings = new gem.d3Scene.RouteRenderSettings();
Module.View.showRouteInView(this.m_object, route.getRawPointer(), bIsMainRoute, bAddRouteLabels === undefined ? true : bAddRouteLabels,routeRenderSettings);
}
/** Remove route from view
* @param {gem.Route} route - route that is being removed from the view
*/
removeRoutefromView(route) {
Module.View.removeRouteFromView(this.m_object, route.getRawPointer());
}
/**
* Center on a route( route overview)
* @param {gem.routesAndNavigation.Route} route
* @param {number} [durationMs = 0] - duration for animation in ms
* @param {gem.core.RectangleFloat} rectFloat - custom view rectangle
*/
centerOnRoute(route, durationMs, rectFloat) {
let rect;
if (rectFloat === undefined)
rect = this.getViewport();
else
rect = rectFloat;
Module.View.centerOnRoute(this.m_object, route.getRawPointer(), durationMs === undefined ? 0 : durationMs, rect);
}
/**
* @param {number} nId - id for the needed source
* @returns {gem.d3Scene.MarkerCollectionRef} - source
*/
getVectorSourceAt(nId) {
return new gem.d3Scene.MarkerCollection(nId, this.m_object);
}
/**
*
* @param {gem.d3Scene.MarkerCollectionRef} pSource - source that should be deleted
*/
removeVectorSource(pSource) {
Module.View.removeSource(this.m_object, pSource.getRawPointer());
}
/**
*
* @param {*} callback
*/
registerCameraChangeStateCallback(callback) {
Module.View.registerCameraChangeStateCallback(this.m_object, callback);
}
/**
* Query store locator
* @param {gem.d3Scene.ExternalQueryListener} externalQueryListener
* @param {gem.core.StoreLocationList} storeLocationList
* @param {number} storeId - store ID
* @param {boolean} bFullData - To query full data, or partial data
* @param {gem.core.GemStringList} languageList
* @param {gem.d3Scene.RectangleGeographicAreaList} rectangleList - list of regions to query for data
*/
queryStoreLocator(externalQueryListener, storeLocationList, storeId, bFullData, languageList, rectangleList) {
if (languageList === undefined)
languageList = new gem.core.GemStringList();
if (rectangleList === undefined)
rectangleList = this.transformScreenToWgsRectGeoList({
x: 0,
y: 0,
width: 0,
height: 0
});
Module.View.queryStoreLocator(this.m_object, externalQueryListener.getRawPointer(), storeLocationList.getRawPointer(), storeId, languageList.getRawPointer(), bFullData === undefined ? true : bFullData, rectangleList.getRawPointer());
}
/**
* @param {gem.d3Scene.ExternalQueryListener} externalQueryListener
* @param {number} storeId
* @param {gem.core.StoreLocationLangList} resultConfigurationList
*/
queryStoreLocatorConfiguration(externalQueryListener, storeId, resultConfigurationList) {
Module.View.queryStoreLocatorConfiguration(this.m_object, externalQueryListener.getRawPointer(), storeId, resultConfigurationList.getRawPointer());
}
/**
* Enable overlay Item with external Rendering
* @param {string} uId
* @param {gem.d3Scene.ExternalRenderer} externalRenderer
*/
enableOverlayItemWithExternalRendering(uId, externalRenderer) {
var constructorFunc = function (object) {
return new gem.d3Scene.OverlayItem(new Module.OverlayItem(object));
};
Module.View.enableMarkersWithExternalRendering(uId, this.m_object, externalRenderer.callback.bind(externalRenderer), constructorFunc);
}
/**
* Get notified when style update has finished
* @param {*} callbackStyle
*/
registerStyleUpdateFinishedCallback(callbackStyle) {
Module.View.registerStyleUpdateFinishedCallback(this.m_object, callbackStyle);
}
/**
* Set area of view clipping
* @param {gem.core.RectangleFloat} area
*/
setClippingArea(area) {
Module.View.setClippingArea(this.m_object, area);
}
/**
* Get total Number of Markers Collections
* @returns {number}
*/
getNumberOfMarkersCollections() {
return Module.View.getNumberOfSources(this.m_object);
}
/**Get View viewport
*@returns {gem.core.RectangleInteger} - viewport
*/
getViewport() {
return Module.View.getViewport(this.m_object);
}
/**
* @param {boolean} bVal
*/
enableCursor(bVal) {
Module.View.enableCursor(this.m_object, bVal);
}
/**
* Transform screen coordinates to a list of Geographic Areas (WGS coordinates)
* @param {gem.core.RectangleInteger} screenRectangle
* @returns {gem.core.RectangleGeographicAreaList} - list of Geographic Areas
*/
transformScreenToWgsRectGeoList(screenRectangle) {
return new gem.core.RectangleGeographicAreaList(Module.View.transformScreenToWgsRectGeoList(this.m_object, screenRectangle));
}
/**
* @param {bool} bFlag
*/
setNorthFixedFlag(bFlag) {
//Module.View.setNorthFixedFlag(this.m_object, bFlag);
}
/**
* @returns {bool}
*/
getNorthFixedFlag() {
//return Module.View.getNorthFixedFlag(this.m_object);
return null;
}
/**
* @param {*} callback
*/
registerForNextRenderFinished(callback) {
Module.View.registerForNextRenderFinished(this.m_object, callback);
}
/**
* @param {*} callback
*/
registerOnViewRendered(callback) {
Module.View.registerOnViewRendered(this.m_object, callback);
}
/**
* @param {*} callback
*/
registerOnTouchEvent(callback) {
Module.View.registerOnTouchEvent(this.m_object, callback);
}
registernOnLongTouchEvent(callback) {
Module.View.registernOnLongTouchEvent(this.m_object, callback);
}
registerRouteClickedEvent(callback, routeResult) {
Module.View.registerRouteClickedEvent(this.m_object, routeResult.getRawPointer(), callback)
}
deregisterRouteClickedEvent() {
Module.View.deregisterRouteClickedEvent();
}
registerHoverLandmarkCallback(callback) {
let constructorCallback = function (landmarkResult) {
if (landmarkResult !== undefined) {
let landmarkWrapped = new gem.core.Landmark(landmarkResult);
callback(landmarkWrapped);
} else
callback(undefined);
};
Module.View.registerHoverLandmarkCallback(this.m_object, constructorCallback);
}
getHighlightGroupItemIndex(nIndex) {
return Module.View.getHighlightGroupItemIndex(this.m_object, nIndex);
}
setCamera(camera) {
Module.View.setCamera(this.m_object, camera);
}
/**
* Center on a route( route overview)
* @param {gem.routesAndNavigation.Route} route
* @param {number} distBegin - distance begin
* @param {number} distEnd - distance end
* @param {number} [durationMs = 0] - duration for animation in ms
* @param {gem.core.RectangleFloat} rectFloat - custom view rectangle
*
*/
centerOnRoutePortion(route, distBegin, distEnd, durationMs, rectFloat) {
let rect;
if (rectFloat === undefined)
rect = this.getViewport();
else
rect = rectFloat;
Module.View.centerOnRoutePortion(this.m_object, route.getRawPointer(), durationMs === undefined ? 0 : durationMs, rect, distBegin, distEnd);
}
getVisibleRouteInterval(route, rectFloat) {
let rect;
if (rectFloat === undefined)
rect = this.getViewport();
else
rect = rectFloat;
return Module.View.getVisibleRouteInterval(this.m_object, route.getRawPointer(), rect);
}
getPathsCollection() {
return Module.View.getPathsCollection(this.m_object);
}
/**
Toggle Touch Gesture
@param {gem.ETouchGestures} gestures - gestures to be toggled
@param {boolean} enableFlag - enable or disable
*/
enableTouchGestures(gestures, enableFlag) {
Module.View.enableTouchGestures(this.m_object, gestures, enableFlag);
}
/**
* Add a landmark store to the view
* @param {gem.core.LandmarkStore} landmarkStore - landmark store to be added
*/
addLandmarkStore(landmarkStore) {
Module.View.addLandmarkStore(this.m_object, landmarkStore.getRawPointer());
}
/**
* Remove a landmark store from the view
* @param {gem.core.LandmarkStore} landmarkStore - landmark store to be removed
*/
removeLandmarkStore(landmarkStore) {
Module.View.removeLandmarkStore(this.m_object, landmarkStore.getRawPointer());
}
/**
*
* @param {number} qualityLevel - 0 = Low Quality / High Performance;1 = Medium Quality; 2 = High Quality/ Low Performance
*/
setMapViewDetailsQualityLevel(qualityLevel) {
Module.View.setMapViewDetailsQualityLevel(this.m_object, qualityLevel);
}
/**
* Adds a path to the view.
* @param {object} path - The path object to add.
* @param {{r: number, g: number, b: number, a: number}} borderColor - The RGBA color of the border.
* @param {{r: number, g: number, b: number, a: number}} innerColor - The RGBA color of the inner part of the path.
* @param {number} [sizeOfBorder=-1] - The size of the border. Defaults to -1 if not provided.
* @param {number} [sizeOfInner=-1] - The size of the inner part of the path. Defaults to -1 if not provided.
*/
addPath(path, borderColor, innerColor, sizeOfBorder = -1, sizeOfInner = -1) {
Module.View.addPath(this.m_object, path.getRawPointer(), borderColor, innerColor, sizeOfBorder, sizeOfInner);
}
/**
* Removes a path from the view.
* @param {object} path - The path object to remove.
*/
removePath(path) {
Module.View.removePath(this.m_object, path.getRawPointer());
}
/**
* Sets the fading of map labels.
* @param {boolean} bVal - If true, map labels will fade. If false, they will not.
*/
setMapLabelsFading(bVal) {
Module.View.setMapLabelsFading(this.m_object, bVal);
}
/**
* Sets the visibility of traffic information on the map.
* @param {boolean} bVal - If true, traffic information will be visible. If false, it will not.
*/
setTrafficVisibility(bVal) {
Module.View.setTrafficVisibility(this.m_object, bVal);
}
getMapViewMaxZoomRanges() {
return Module.View.getMapViewMaxZoomRanges();
}
getMapViewCurrentZoomRange()
{
return Module.View.getMapViewCurrentZoomRange(this.m_object);
}
}
/**
* @class gem.core.RectangleGeographicAreaList
* @hideconstructor
* @memberof gem.core
*/
gem.core.RectangleGeographicAreaList = class RectangleGeographicAreaList extends Em_Vector {
constructor(object) {
if (object)
super(object);
else
super(new Module.RectangleGeographicAreaList());
}
/**
* @param {number} idx
* @returns {RectangleGeographicArea}
*/
get(idx) {
return Module.RectangleGeographicAreaList.get(this.m_object, idx);
}
/**
* @param {RectangleGeographicArea} item
*/
push_back(item) {
Module.RectangleGeographicAreaList.push_back(this.m_object, item);
}
/**
* @returns {number}
*/
size() {
return Module.RectangleGeographicAreaList.size(this.m_object);
}
}
/**
* @namespace gem.places
* @hideconstructor
* @memberof gem
*/
gem.places = class places {
}
/**
* @class gem.places.Search
* @hideconstructor
*/
gem.places.Search = class search {
/**
* Request to search for nearby Landmarks(POIs)
* @param {gem.core.Coordinates} coordinates
* @param {*} callbackfunction
* @param {gem.core.LandmarkList} resultedLandmarks
* @param {gem.places.SearchPreferences} searchPreferences - Search Preferences
*/
static searchNearby(coordinates, callbackfunction, resultedLandmarks, searchPreferences) {
Module.searchNearby(coordinates, callbackfunction, resultedLandmarks.getRawPointer(), (searchPreferences === undefined) ? new Module.SearchPreferences() : searchPreferences.getRawPointer());
}
/**
* Search for a specific string, in a specified Area(top left / top right coordinates)
* @param {string} searchString
* @param {gem.core.Coordinates} coordinatesTopLeft
* @param {gem.core.Coordinates} coordinatesBottomRight
* @param {*} callbackfunction
* @param {gem.core.LandmarkList} resultedLandmarks
* @param {gem.core.Coordinates} pointOfInterest - Point of interest.You can use the cursor positon as input, request it via by call getCursorPositionWGS , on MapView object
*/
static searchFor(searchString, coordinatesTopLeft, coordinatesBottomRight, callbackfunction, resultedLandmarks, pointOfInterest) {
if (pointOfInterest === undefined) {
pointOfInterest = {
latitude: (coordinatesTopLeft.latitude + coordinatesBottomRight.latitude) / 2.0,
longitude: (coordinatesTopLeft.longitude + coordinatesBottomRight.longitude) / 2.0,
altitude: 0,
bearing: 0
};
}
Module.searchFor(searchString, coordinatesTopLeft, coordinatesBottomRight, callbackfunction, resultedLandmarks.getRawPointer(), pointOfInterest);
}
/**
* Search for a specific string,in a specified Area (top left / top right coordinates) with more control over the search preferences.
* @param {string} searchString
* @param {gem.core.Coordinates} coordinatesTopLeft
* @param {gem.core.Coordinates} coordinatesBottomRight
* @param {*} callbackfunction
* @param {gem.core.LandmarkList} resultedLandmarks
* @param {gem.places.SearchPreferences} searchPreferences
*/
static searchForWithPreferences(searchString, coordinatesTopLeft, coordinatesBottomRight, callbackfunction, resultedLandmarks, searchPreferences) {
Module.searchForWithPreferences(searchString, coordinatesTopLeft, coordinatesBottomRight, callbackfunction, resultedLandmarks.getRawPointer(), (searchPreferences === undefined) ? new gem.places.SearchPreferences() : searchPreferences.getRawPointer());
}
/**
* Search along a route
* @param {string} searchString
* @param {*} callbackfunction
* @param {gem.routesAndNavigation.Route} route
* @param {gem.core.LandmarkList} resultedLandmarks
* @param {gem.places.SearchPreferences} searchPreferences
*/
static searchAlongRouteEM(searchString, callbackfunction, route, resultedLandmarks, searchPreferences) {
Module.searchAlongRouteEM(searchString, callbackfunction, route.getRawPointer(), resultedLandmarks.getRawPointer(), searchPreferences.getRawPointer());
}
/**
*
* @param {string} searchString - search string
* @param {gem.core.EAddressDetailLevel } detailLevel - detail level
* @param {gem.core.Landmark} parentLandmark - parent landmark
* @param {*} callbackfunction - callback function
* @param {gem.lanmarklist} resultedLandmarks - resulted Landmarks
* @param {number} maximumResults - maximum number of results
* @param {boolean} allowFuzzyResults - allow fuzzy results
* @param {boolean} searchOnlyOnBoard - search only on board
*/
static searchByAddress(searchString, detailLevel, parentLandmark, callbackfunction, resultedLandmarks, maximumResults, allowFuzzyResults, searchOnlyOnBoard) {
Module.searchByAddress(searchString, detailLevel, parentLandmark.getRawPointer(), callbackfunction, resultedLandmarks.getRawPointer(), maximumResults, (allowFuzzyResults === undefined) ? true : allowFuzzyResults, (searchOnlyOnBoard === undefined) ? false : searchOnlyOnBoard);
}
/**
*
* @param {gem.core.LandmarkCategoryList} landmarkCategoryList
* @param {gem.core.Coordinates} coordinates
* @param {*} callback
* @param {gem.core.LandmarkList} resultedLandmarks
* @param {number} [distanceRadiusMeters]
*/
static searchPoiCategory(landmarkCategoryList, coordinates, callback, resultedLandmarks, distanceRadiusMeters) {
Module.searchPoiCategory(landmarkCategoryList.getRawPointer(), coordinates, callback, resultedLandmarks.getRawPointer(), distanceRadiusMeters ? distanceRadiusMeters : -1);
}
/**
*
* @param {gem.core.Landmark} landmark
* @returns {vector<number>}
*/
static getNextAddressDetailLevel(landmark) {
return Module.getNextAddressDetailLevel(landmark.getRawPointer());
}
static cancelSearch(resultedLandmarks) {
Module.cancelSearch(resultedLandmarks.getRawPointer());
}
}
/**searchPreferences class
* @class gem.places.SearchPreferences
* @memberof gem.places
*/
gem.places.SearchPreferences = class SearchPreferences extends Em_Object {
constructor() {
super(new Module.SearchPreferences());
}
/**
* Set/unset the exact match.
* @param {boolean} bVal
*/
setExactMatch(bVal) {
this.m_object.setExactMatch(bVal);
}
/**
* Sets the max number of matches.
* @param {number} nMaxMatches
*/
setMaxMatches(nMaxMatches) {
this.m_object.setMaxMatches(nMaxMatches);
}
/**
* Enables or disables the search through the addresses.
* @param {boolean} bVal
*/
setSearchAddresses(bVal) {
this.m_object.setSearchAddresses(bVal);
}
/**
* Enables or disables the search through map POIs.
* @param {boolean} bVal
*/
setSearchMapPOIs(bVal) {
this.m_object.setSearchMapPOIs(bVal);
}
/**
* Set the threshold distance for the operation.
* This may be used to control the reverse geocoding and search along route lookup area.
* @param {*} nThresholdDistance
*/
setThresholdDistance(nThresholdDistance) {
this.m_object.setThresholdDistance(nThresholdDistance);
}
/**
* Set the search operation time-out.
* @param {number} timeoutMs
*/
setTimeout(timeoutMs) {
this.m_object.setTimeout(timeoutMs);
}
/**
* Set the flag for onboard search.
* If this flag is true then the search will be done using only onboard data.
* By default it is false.
* @param {boolean} bVal
*/
setSearchOnlyOnboard(bVal) {
this.m_object.setSearchOnlyOnboard(bVal);
}
/**
* Add categories in which to search
* @param {gem.core.LandmarkCategoryList} landmarkcategorylist
*/
addLandmarkCategoryVector(landmarkcategorylist) {
this.m_object.addLandmarkCategoryVector(landmarkcategorylist.getRawPointer());
}
/**
* Set the references point.
* @param {gem.core.Coordinates} coordinates
*/
setReferencePoint(coordinates) {
this.m_object.setReferencePoint(coordinates);
}
}
/**Content Manager class
* @class gem.content.Manager
* @hideconstructor
* @memberof gem.content
*/
gem.content.Manager = class manager {
/**
* Request content of a certain type. Async function
* @param {gem.content.EContentType} contentType - content type
* @param {gem.content.StoreProgressListener} progressListener - when content is made available, you get notified in this object*/
static requestContentList(contentType, progressListener) {
Module.requestContentList(contentType, progressListener.getRawPointer());
}
/**
* Gets access to the installed content list
* @param {gem.content.EContentType} contentType - Content list type
* @returns {gem.content.ContentStoreList}
*/
static getLocalContentList(contentType) {
return new gem.content.ContentStoreList(Module.getLocalContentList(contentType));
}
/**
* Get generic categories list
* @returns {gem.core.LandmarkCategoryList}
*/
static getGenericCategories() {
return new gem.core.LandmarkCategoryList(Module.getGenericCategories());
}
/**
* Gets access to the store cached content list
* @param {gem.content.EContentType} contentType
* @returns {gem.content.ContentStoreList} - content store list
*/
static getStoreContentList(contentType) {
return new gem.content.ContentStoreList(Module.getStoreContentList(contentType));
}
/**
* Gets list of url for a certain service type
* @param {number} customUrlServiceId - Service type id
* @returns {gem.core.GemStringList} - list of urls
*/
static getCustomUrlList(customUrlServiceId) {
return Module.getCustomUrlList(customUrlServiceId);
}
/**
* Get List with ids of available services
* @returns vector<int>
*/
static getServicesIds() {
return Module.getServicesIds();
}
/**
*
* @param {number} nId Service id
* @returns {string} - name of service
*/
static getServiceName(nId) {
return Module.getServiceName(nId);
}
static getIconFromId(offBitmap, nId) {
return Module.getIconFromId(offBitmap.getRawPointer(), nId);
}
static getImageAspectRatio(nId) {
return Module.getImageAspectRatio(nId);
}
}
/**Navigation class
* @class gem.routesAndNavigation.Navigation
* @hideconstructor
* @memberof gem.routesAndNavigation
*/
gem.routesAndNavigation.Navigation = class Navigation {
/**
* Check if there is an active simulation in progress.
* @returns {boolean}
* @static
*/
static isSimulationActive() {
return Module.isSimulationActive();
}
/**
* Sets the speed multiplier for the simulation.
* @param {number} fVal - The new speed multiplier.
* @static
*/
static setSpeedMultiplier(fVal) {
Module.setSpeedMultiplier(fVal);
}
/**
* Gets the current speed multiplier for the simulation.
* @returns {number} The current speed multiplier.
* @static
*/
static getSpeedMultiplier() {
return Module.getSpeedMultiplier();
}
/**
* Gets the current speed of the simulation.
* @returns {number} The current speed.
* @static
*/
static getCurrentSpeed() {
let speed = Module.getCurrentSpeed();
if(speed < -990)
return undefined;
return speed;
}
/**
* Creates a new simulation listener.
* @returns {Module.SimulationListener} A new simulation listener.
* @static
*/
static createSimulationListener() {
return new Module.SimulationListener();
}
/**
*
* @param {gem.routesAndNavigation.Route} route
* @param {*} progressListener - callback
* @param {gem.routesAndNavigation.NavigationListener} navigationListener
* @returns {number} - Error code
*/
static startNavigation(route, progressListener, navigationListener) {
return Module.startNavigation(route.getRawPointer(), progressListener, navigationListener.getRawPointer());
}
/**
* Stop Navigation
*/
static stopNavigation() {
Module.stopNavigation();
}
/**
* Start Simulation
* @param {gem.routesAndNavigation.Route} route
* @param {*} progressListener - callback
* @param {gem.routesAndNavigation.NavigationListener} navigationListener
*/
static startSimulation(route, progressListener, navigationListener) {
Module.startSimulation(route.getRawPointer(), progressListener, navigationListener.getRawPointer())
}
/** Get current street name
* @returns {string}
*/
static getCurrentStreetName() {
return Module.NavigationInstruction.getCurrentStreetName();
}
/**Get the maximum speed limit on the current street in meters per second
* @returns {number} - 0 if maximum speed limit is not available
*/
static getCurrentStreetSpeedLimit() {
return Module.NavigationInstruction.getCurrentStreetSpeedLimit();
}
/** Get the current navigation instruction id.
*@returns {number}
*/
static getCurrentInstructionId() {
return Module.NavigationInstruction.getCurrentInstructionId();
}
/**Get remaining travel distance in meters and remaining traveling time in seconds.
* @returns {gem.core.TimeAndDistance}
*/
static getRemainingTravelTimeDistance() {
return Module.NavigationInstruction.getRemainingTravelTimeDistance();
}
/**Get the distance to the next turn in meters, time in seconds.
* @returns {gem.core.TimeAndDistance}
*/
static getTimeDistanceToNextTurn() {
return Module.NavigationInstruction.getTimeDistanceToNextTurn();
}
/**Get the textual description for the next turn.
*@returns {string}
*/
static getNextTurnInstruction() {
return Module.NavigationInstruction.getNextTurnInstruction();
}
/**
* Get turn image.
* @param {gem.core.BitmapContainer} bitmapContainer -Buffer where to add the image for the turn.
*/
static getNextTurnImageInBitmap(bitmapContainer) {
Module.NavigationInstruction.getNextTurnImageInBitmap(bitmapContainer.getRawPointer());
}
}
/**Routes Request class
* @class gem.routesAndNavigation.RoutesRequest
* @augments Em_Vector
* @memberof gem.routesAndNavigation
*/
gem.routesAndNavigation.RoutesRequest = class routesrequest extends Em_Vector {
constructor() {
super(new Module.Route());
}
/**
* Add a waypoint, by coordinates, for route calculation.
* @param {gem.core.Coordinates} coordinates
*/
addWaypoint(coordinates) {
this.m_object.addWaypoint(coordinates);
}
/**
* Set the route type.
* @param {gem.routesAndNavigation.ERouteType} routeType
*/
setRouteType(routeType) {
this.m_object.setRouteType(routeType);
}
/**
* Sets the avoid unpaved roads flag.
* @param {boolean} bValue
*/
setAvoidUnpavedRoads(bValue) {
this.m_object.setAvoidUnpavedRoads(bValue);
}
/**
* Set the avoid motorways flag. Default is false
* @param {boolean} bValue
*/
setAvoidMotorways(bValue) {
this.m_object.setAvoidMotorways(bValue);
}
/**
* Set the avoid toll roads flag.Default is false
* @param {boolean} bValue
*/
setAvoidTollRoads(bValue) {
this.m_object.setAvoidTollRoads(bValue);
}
/**
* Set the avoid ferries flag.
* @param {boolean} bValue
*/
setAvoidFerries(bValue) {
this.m_object.setAvoidFerries(bValue);
}
/**
* Enable/disable traffic information usage for route calculation.Default is false.
* @param {boolean} bValue
*/
setAvoidTraffic(bValue) {
this.m_object.setAvoidTraffic(bValue);
}
/**
* Set avoid biking hill factor
* @param {number} fValue - 0.0 - no avoidance, 1.0 - full avoidance
*/
setAvoidBikingHillFactor(fValue) {
this.m_object.setAvoidBikingHillFactor(fValue);
}
/**
* Sets the transport mode.
* @param {gem.routesAndNavigation.ERouteTransportMode} transportMode
*/
setTransportMode(transportMode) {
this.m_object.setTransportMode(transportMode);
}
/**
* Add a waypoint, by landmark, for route calculation.
* @param {gem.core.Landmark} landmark
*/
addWaypointFromLandmark(landmark) {
this.m_object.addWaypointFromLandmark(landmark.getRawPointer());
}
/**
*
* @param {*} callbackfunction
*/
calculateRoute(callbackfunction) {
this.m_object.calculateRoute(callbackfunction);
}
/**
* Enable terrain profile build
* @param {boolean} bValue
*/
setBuildTerrainProfile(bValue) {
this.m_object.setBuildTerrainProfile(bValue);
}
/**
* Sets the path calculation algorithm
* @param {gem.routesAndNavigation.ERoutePathAlgorithm} pathAlgorithm
*/
setPathAlgorithm(pathAlgorithm) {
this.m_object.setPathAlgorithm(pathAlgorithm);
}
/**
* Set result details
* @param {gem.routesAndNavigation.ERouteResultDetails} resultDetails
*/
setResultDetails(resultDetails) {
this.m_object.setResultDetails(resultDetails);
}
/**
* Set Bike Profile
* @param {gem.routesAndNavigation.EBikeProfile} bikeProfile - Set the bike profile to be used for the route calculation.
*/
setBikeProfile(bikeProfile) {
this.m_object.setBikeProfile(bikeProfile);
}
/**
* Set Bike Profile and Electric bike profile
* @param {gem.routesAndNavigation.EBikeProfile} bikeProfile
* @param {gem.routesAndNavigation.ElectricBikeProfile} electricBikeProfile
*/
setBikeProfileWithElectricType(bikeProfile, electricBikeProfile) {
if (typeof electricBikeProfile.type === 'function') {
electricBikeProfile.type = electricBikeProfile.type();
}
this.m_object.setBikeProfileWithElectricType(bikeProfile, electricBikeProfile);
}
/**
* Set route ranges list.A non empty range list will generate an isocost range route result
@param {object} routeranges
* @param {Array} [routeranges.rangelist] - array of range intervals. ranges units depends on route type(set by setRouteType): gem.routesAndNavigation.ERouteType.ERT_Fastest - seconds, gem.routesAndNavigation.ERouteType.ERT_Shortest - meters , gem.routesAndNavigation.ERouteType.ERT_Economic - watt-hour( Wh)
* @param {callbackMarker} [routeranges.quality] - range result quality must a valid integer in 0 - 100 range, 0 = lowest quality, 100 = highest quality
*/
setRouteRanges(routeranges) {
let array = new Module.vector$int$();
for (let i = 0; i < routeranges.rangelist.length; i++) {
array.push_back(routeranges.rangelist[i]);
}
this.m_object.setRouteRanges(array, routeranges.quality);
}
setIgnoreRestrictionsOverTrack(ignore) {
this.m_object.setIgnoreRestrictionsOverTrack(ignore);
}
/**
* @returns {number} - the number of calculated routes.
*/
size() {
return this.m_object.getRoutesListSize();
}
/**
*
* @param {number} nId
* @returns {gem.routesAndNavigation.Route} - Route Object
*/
get(nId) {
return new gem.routesAndNavigation.Route(this.m_object, nId);
}
stopRouteCalculation() {
this.m_object.stopRouteCalculation();
}
/**
*
* @param {gem.routesAndNavigation.EVProfile} evProfile
*/
setEVProfile(evProfile) {
this.m_object.setEVProfile(evProfile.getRawPointer());
}
getEVProfile() {
return new gem.routesAndNavigation.EVProfile(this.m_object.getEVProfile());
}
setCarProfile(carprofile) {
this.m_object.setCarProfile(carprofile.getRawPointer());
}
getCarProfile() {
return new gem.routesAndNavigation.CarProfile(this.m_object.getCarProfile());
}
}
/**Route class
* @class gem.routesAndNavigation.Route
* @memberof gem.routesAndNavigation
*/
gem.routesAndNavigation.Route = class route {
constructor(routesrequest, routeId) {
this.m_routesresult = routesrequest;
this.routeId = routeId;
}
getRawPointer() {
return this.m_routesresult.getRouteAt(this.routeId);
}
/**Get length in meters and estimated travel time in seconds for the route
* @returns {gem.core.TimeAndDistance}
*/
getTotalDistanceMAndTimeS() {
return this.m_routesresult.getTotalDistanceMAndTimeS(this.routeId);
}
/**
* Get route sections size
* @returns {number} - number of route sections
*/
getNavigationInstructionSectionsSize() {
return this.m_routesresult.getNavigationInstructionsSize(this.routeId);
}
/** Get list of traffic events affecting the route.
* @returns {gem.routesAndNavigation.RouteTrafficEventList} - list of traffic events along the route
*/
getTrafficEvents() {
return new gem.routesAndNavigation.RouteTrafficEventList(this.m_routesresult.getTrafficEvents(this.routeId));
}
/**
* Get the list of navigation instruction for specified route section
* @param {number} nId - id for the route section
* @returns {gem.routesAndNavigation.RouteInstructionList} - routeInstructionList
*/
getNavigationInstructionSection(nId) {
return new gem.routesAndNavigation.RouteInstructionList(this.m_routesresult.getNavigationInstruction(this.routeId, nId));
}
/**
* Get list of route sections which are flat, that is, no significant elevation change.
* @returns {vector<gem.routesAndNavigation.SurfaceSection>}
*/
getTerrainSurfaceTypeSection() {
return this.m_routesresult.getTerrainSurfaceTypeSection(this.routeId);
}
/**
* Get list of route sections which are of type road, typically, paved.
* @returns {vector<gem.routesAndNavigation.RoadTypeSection>}
*/
getTerrainRoadTypeSection() {
return this.m_routesresult.getTerrainRoadTypeSection(this.routeId);
}
/**
* Get list of route sections which are abrupt, that is, they have a significant elevation change.
* @param {vector<float>} profileVector - categs The user list of steep categories. Each entry contains the max slope for the steep category as diffX / diffY.
* @returns {vector<gem.routesAndNavigation.SteepSection>} - A positive value is for an ascension category, a negative value if a descent category
*/
getTerrainSteepeSections(profileVector) {
return this.m_routesresult.getTerrainSteepeSections(this.routeId, profileVector);
}
/**
* Get elevation samples list
* @param {number} nrOfSamples - Number of samples
* @param {number} beginMeter - Begin distance on route for sample interval
* @param {number} endMeter - End distance on route for sample interval
* @returns {vector<int>} - return Elevation samples
*/
getElevationSamples(nrOfSamples, beginMeter, endMeter) {
return this.m_routesresult.getElevationSamples(this.routeId, nrOfSamples, beginMeter, endMeter);
}
getDominantRoads() {
return this.m_routesresult.getDominantRoads(this.routeId);
}
getSegments() {
return new gem.routesAndNavigation.RouteSegmentList(this.getRawPointer().getSegments());
}
toPTRoute() {
return this.m_routesresult.toPTRoute(this.routeId);
}
getCoordinateOnRoute(distancemeters) {
return this.m_routesresult.getCoordinateOnRoute(this.routeId, distancemeters);
}
getPath(start, end) {
return this.m_routesresult.getPath(this.routeId, start, end);
}
exportAs(exportType) {
return this.m_routesresult.exportAs(this.routeId, exportType);
}
}
/**
* @class gem.core.Landmark
* @memberof gem.core
*/
gem.core.Landmark = class Landmark {
constructor(lmkraw) {
if (lmkraw === undefined) {
this.m_landmarkPtr = new Module.Landmark(undefined);
this.m_landmark = Module.Landmark.getRef(this.m_landmarkPtr);
} else
this.m_landmark = new Module.Landmark(lmkraw);
}
delete() {
this.m_landmark.delete();
if (this.m_landmarkPtr)
this.m_landmarkPtr.delete();
}
isDeleted() {
return this.m_landmark.isDeleted();
}
getRawPointer() {
return this.m_landmark;
}
/**
* Get the name of this landmark.
* @returns {string} - On return the parameter is set to the field value. It may be empty.
*/
getName() {
return Module.Landmark.getName(this.m_landmark);
}
/**
* Gets the centroid coordinates.
* @returns {gem.core.Coordinates} On return the parameter is set to the actual value. The coordinates may be invalid. This aspect needs to be checked by the API user.
*/
getCoordinates() {
return Module.Landmark.getCoordinates(this.m_landmark);
}
/** Returns the landmark ID.
* @returns {number} - ID >= 0 Success.
*/
getLandmarkId() {
return Module.Landmark.getLandmarkId(this.m_landmark);
}
/**
* get bounding box for the geographic area.
* @returns {gem.core.BoundingBox}
*/
getBoundingBox() {
return Module.Landmark.getBoundingBox(this.m_landmark);
}
/**
* Get formated text contact info
* @returns {string}
*/
getContactInfo() {
return Module.Landmark.getContactInfo(this.m_landmark);
}
/**
* Get formated text extra info,each info separated by ','
* @returns {string}
*/
getExtraInfo() {
return Module.Landmark.getExtraInfo(this.m_landmark);
}
/**
* Get the description of this landmark.
* @returns {string}
*/
getDescription() {
return Module.Landmark.getDescription(this.m_landmark);
}
/**
* Get formated text of Address.
* @returns {string}
*/
getAddress() {
return Module.Landmark.getAddress(this.m_landmark);
}
/**
* Get Address field content by name
* @param {gem.core.EAddressField} addressField - field type
* @returns {string}
*/
getAddressField(addressField) {
return Module.Landmark.getAddressField(this.m_landmark, addressField);
}
/**
* Get page url or booking url or Wikipedia page
* @returns {string} url
*/
getUrl() {
return Module.Landmark.getUrl(this.m_landmark);
}
/**
*
* @param {gem.core.BitmapContainer} bitmapContainer -output for Landmark image
*/
getImage(bitmapContainer) {
Module.Landmark.getImage(this.m_landmark, bitmapContainer.getRawPointer());
}
getLandmarkStoreId() {
return Module.Landmark.getLandmarkStoreId(this.m_landmark);
}
getLandmarkStoreType() {
return Module.Landmark.getLandmarkStoreType(this.m_landmark);
}
/**
* @callback wikipediainfocallback
* @param {object} wikipediacontainer - to use it please create a new gem.core.WikipediaContainer object around it
*/
/**
* Request wikipedia info. asnyc function
* @param {wikipediainfocallback} callbackfunction
* @param {gem.core.ExternalInfo} externalInfo - object to handle external info
* @returns {gem.core.WikiDescriptionListener} - wikipedia listener object. Please use delete method on this object, after wikipedia
*/
requestWikipediaInfo(callbackfunction, externalInfo) {
var constructorWiki = function (object, object2) {
return new gem.core.WikipediaContainer(new Module.WikipediaContainer(object, object2));
};
return Module.Landmark.requestWikipediaInfo(this.m_landmark, callbackfunction, externalInfo.getRawPointer(), constructorWiki);
}
/**
* Get formatted name
* @returns {string}
*/
getFormatedName() {
return Module.Landmark.getFormatedName(this.m_landmark);
}
/**
* Get formatted details
* @returns {string}
*/
getFormatedDetails() {
return Module.Landmark.getFormatedDetails(this.m_landmark);
}
/**
* Get value for extra info key string
* @param {string} extrakey - key string
* @returns {string}
*/
getValueForExtraInfo(extrakey) {
return Module.Landmark.getValueForExtraInfo(this.m_landmark, extrakey);
}
/**
* Returns if landmark has wikipedia info
* @param {gem.core.ExternalInfo} externalInfo - object to handle external info
* @returns {boolean}
*/
hasWikipediaInfo(externalInfo) {
return Module.Landmark.hasWikipediaInfo(this.m_landmark, externalInfo.getRawPointer());
}
/**
* Get Country ISO code
* @returns {string}
*/
getCountryIsoCode() {
return Module.Landmark.getCountryIsoCode(this.m_landmark);
}
/**
* Get the country flag for the landmark.
* @param {gem.core.BitmapContainer} bitmapContainer - output image
* @returns {boolean} - true if the flag was found, false otherwise
*/
getCountryFlagImage(bitmapContainer) {
return Module.Landmark.getCountryFlagImage(this.m_landmark, bitmapContainer.getRawPointer());
}
/**
* Sets the image for the landmark using an icon ID.
* @param {number} usableIconId - The ID of the icon to use as the image.
*/
setImage(usableIconId) {
Module.Landmark.setImage(this.m_landmark, usableIconId);
}
setImagePointer(imagePointer)
{
Module.Landmark.setImagePointer(this.m_landmark,imagePointer);
}
getImagePointer()
{
return Module.Landmark.getImagePointer(this.m_landmark);
}
/**
* Sets the coordinates for the landmark.
* @param {gem.core.Coordinates} coordinates - The new coordinates for the landmark.
*/
setCoordinates(coordinates) {
Module.Landmark.setCoordinates(this.m_landmark, coordinates);
}
/**
* Sets the name for the landmark.
* @param {string} name - The new name for the landmark.
*/
setName(name) {
Module.Landmark.setName(this.m_landmark, name);
}
/**
* Sets the description for the landmark.
* @param {string} description - The new description for the landmark.
*/
setDescription(description) {
Module.Landmark.setDescription(this.m_landmark, description);
}
/**
* Sets the image for the landmark using an image string.
* @param {string} imageString - The image string to use as the image.
*/
setImageByString(imageString) {
Module.Landmark.setImagebyString(this.m_landmark, imageString);
}
/**
* Sets the waypoint track data for the landmark.
* @param {gem.d3Scene.Path} pathData - The new waypoint track data for the landmark.
*/
setWaypointTrackData(pathData) {
Module.Landmark.setWaypointTrackData(this.m_landmark, pathData.getRawPointer());
}
}
/**
* @class gem.core.LandmarkList
* @augments Em_Vector
* @memberof gem.core
*/
gem.core.LandmarkList = class LandmarkList extends Em_Vector {
constructor(rawPointer) {
if (rawPointer === undefined)
super(new Module.LandmarkList());
else
super(rawPointer);
}
/**
* Get item at position
* @param {number} idx - position in vector
* Returns item at position
* @returns {gem.core.Landmark}
*/
get(idx) {
return new gem.core.Landmark(this.m_object.get(idx));
}
/**
* Insert a landmark
* @param {gem.core.Landmark} item
*/
push_back(item) {
this.m_object.insertLandmark(item.getRawPointer());
}
/**
* Delete landmark at a specifed id
* @param {number} number
*/
delete_at(number) {
this.m_object.deleteLandmarkAt(number);
}
}
/**
* @class gem.core.BitmapContainer
* @augments Em_Object
* @memberof gem
*/
gem.core.BitmapContainer = class bitmapContainer extends Em_Object {
constructor(width, height) {
super(new Module.OffBitmap(width, height));
}
/** Get width
* @returns {number}
*/
getWidth() {
return this.m_object.getWidth();
}
/**
* Get Height
* @returns {number}
*/
getHeight() {
return this.m_object.getHeight();
}
/**
* convert to byte array
* @returns {Array.<Byte>}
*/
toImageData() {
return this.m_object.toImageData();
}
toBMP()
{
let rawBuffer = this.m_object.toImageData();
let width = this.getWidth();
let height = this.getHeight();
const headerSize = 14;
const dibHeaderSize = 40;
const pixelArrayOffset = headerSize + dibHeaderSize;
const bitsPerPixel = 32; // 32 bits per pixel for RGBA
const rowSize = Math.ceil((bitsPerPixel * width) / 32) * 4;
const pixelDataSize = rowSize * height;
const fileSize = pixelArrayOffset + pixelDataSize;
// Create the BMP file and DIB header
const header = new ArrayBuffer(pixelArrayOffset);
const headerView = new DataView(header);
// BMP Header (14 bytes)
headerView.setUint16(0, 0x424D, false); // Signature 'BM'
headerView.setUint32(2, fileSize, true); // File size
headerView.setUint32(6, 0, true); // Reserved
headerView.setUint32(10, pixelArrayOffset, true); // Offset to pixel data
// DIB Header (40 bytes)
headerView.setUint32(14, dibHeaderSize, true); // DIB header size
headerView.setInt32(18, width, true); // Image width
headerView.setInt32(22, -height, true); // Image height (top-down)
headerView.setUint16(26, 1, true); // Color planes (must be 1)
headerView.setUint16(28, bitsPerPixel, true); // Bits per pixel (32 for RGBA)
headerView.setUint32(30, 0, true); // Compression (no compression)
headerView.setUint32(34, pixelDataSize, true); // Size of raw bitmap data
headerView.setInt32(38, 2835, true); // Horizontal resolution
headerView.setInt32(42, 2835, true); // Vertical resolution
headerView.setUint32(46, 0, true); // Colors in palette
headerView.setUint32(50, 0, true); // Important colors (0 = all)
// Combine headers and RGBA pixel data into the final buffer
const bmpBuffer = new Uint8Array(fileSize);
bmpBuffer.set(new Uint8Array(header), 0); // Add BMP and DIB headers
bmpBuffer.set(new Uint8Array(rawBuffer), pixelArrayOffset); // Add RGBA pixel data
return bmpBuffer;
}
}
/**
* @class gem.content.ContentStoreItem
* @augments Em_Object
* @memberof gem.content
*/
gem.content.ContentStoreItem = class ContentStoreItem extends Em_Object {
/**
* Delete content from local
*/
deleteContent() {
Module.ContentStoreItem.deleteContent(this.m_object);
}
/**
* Check if content is updatable
* @returns {boolean}
*/
isUpdatable() {
return Module.ContentStoreItem.isUpdatable(this.m_object);
}
/**
* Get Download Progress
* @returns {number} - progress in percentage
*/
getDownloadProgress() {
return Module.ContentStoreItem.getDownloadProgress(this.m_object);
}
/**
* Check if the content can be deleted
* @returns {boolean}
*/
canDeleteContent() {
return Module.ContentStoreItem.canDeleteContent(this.m_object);
}
/**
* Check if is downloading
* @returns {boolean}
*/
isDownloading() {
return Module.ContentStoreItem.isDownloading(this.m_object);
}
/**
* Download content item
* @param {gem.content.StoreProgressListener} storeProgressListener
*/
download(storeProgressListener) {
Module.ContentStoreItem.download(this.m_object, storeProgressListener.getRawPointer());
}
/**
* Get name of the content store item
* @returns {string}
*/
getName() {
return Module.ContentStoreItem.getName(this.m_object);
}
/**
* Check if item is downloaded
* @returns {boolean}
*/
isCompleted() {
return Module.ContentStoreItem.isCompleted(this.m_object);
}
/**
* Check if image preview is available
* @returns {boolean}
*/
isImagePreviewAvailable() {
return Module.ContentStoreItem.isImagePreviewAvailable(this.m_object);
}
/**
* Get Image Preview
* @param {gem.core.BitmapContainer} bitmap - Output bitmap
* @returns {boolean}
*/
getImagePreview(bitmap) {
return Module.ContentStoreItem.getImagePreview(this.m_object, bitmap.getRawPointer());
}
/**
* Get Country Codes list
* @returns {vector<string>}
*/
getCountryCodes() {
return Module.ContentStoreItem.getCountryCodes(this.m_object);
}
}
/**
* @class gem.content.ContentStoreList
* @augments Em_Object
* @memberof gem.content
*/
gem.content.ContentStoreList = class ContentStoreList extends Em_Vector {
/**
* Get store item at position in list
* @param {number} position
* @returns {gem.content.ContentStoreItem} - store item
*/
get(position) {
return new gem.content.ContentStoreItem(this.m_object.get(position));
}
}
/**marker class
* @class gem.d3Scene.OverlayItem
* @augments Em_Object
* @memberof gem.d3Scene
*/
gem.d3Scene.OverlayItem = class OverlayItem extends Em_Object {
/**
* Get Peview url
* @returns {string}
*/
getPreviewUrl() {
return Module.OverlayItem.getPreviewUrl(this.m_object);
}
/**
* Get Preview data
* @returns {string} - formatted as json
*/
getPreviewData() {
if (!this.previewData)
this.previewData = Module.OverlayItem.getPreviewData(this.m_object);
return this.previewData;
}
/**
* Get Coordinates
* @returns {gem.core.Coordinates}
*/
getCoordinates() {
if (!this.coordinates)
this.coordinates = Module.OverlayItem.getCoordinates(this.m_object);
return this.coordinates;
}
/**
* Retrieves the preview data for the object.
* @returns {string} The preview data.
*/
getInfo() {
return this.getPreviewData();
}
/**
* Retrieves the image for the overlay item.
* @param {gem.core.BitmapContainer} bitmapContainer - The container for the bitmap image.
*/
getImage(bitmapContainer) {
Module.OverlayItem.getImage(this.m_object, bitmapContainer.getRawPointer());
}
getOverlayInfoImage(bitmapContainer)
{
Module.OverlayItem.MarkergetOverlayInfoImage(this.m_object, bitmapContainer.getRawPointer());
}
getImagePointer()
{
return Module.OverlayItem.getImagePointer(this.m_object);
}
/**
* Caches the preview data and coordinates for the object.
*/
cacheData() {
this.getPreviewData();
this.getCoordinates();
}
}
gem.d3Scene.OverlayItemList = class OverlayItemList extends Em_Vector {
/**
* Get store item at position in list
* @param {number} position
* @returns {gem.d3Scene.OverlayItem} - overlay item
*/
get(position) {
return new gem.d3Scene.OverlayItem(this.m_object.get(position));
}
}
/**NavigationListener class
* @class gem.routesAndNavigation.NavigationListener
* @augments Em_Object
* @memberof gem.routesAndNavigation
*/
gem.routesAndNavigation.NavigationListener = class navigationListener extends Em_Object {
constructor() {
super(new Module.NavigationListener());
}
registerNavInstructionUpdateListener(callback) {
this.m_object.registerNavInstructionUpdateListener(callback);
}
registerNavInstructionOnSoundListener(callback) {
this.m_object.registerNavInstructionOnSoundListener(callback);
}
}
/**routeInstructionList class
* @class gem.routesAndNavigation.RouteInstructionList
* @augments Em_Vector
* @memberof gem.routesAndNavigation
*/
gem.routesAndNavigation.RouteInstructionList = class routeInstructionList extends Em_Vector {
constructor(object) {
if (object === undefined) {
super(new Module.vector$RouteInstruction$())
} else {
super(object);
}
}
get(number) {
return new gem.routesAndNavigation.RouteInstruction(this.m_object.get(number));
}
push_back(object) {
this.m_object.push_back(object.getRawPointer());
}
}
/**routeInstruction class
* @class gem.routesAndNavigation.RouteInstruction
* @augments Em_Object
* @memberof gem.routesAndNavigation
*/
gem.routesAndNavigation.RouteInstruction = class routeInstruction extends Em_Object {
/** Get turn instruction as text
*@returns {string}
*/
getTurnInstructionString() {
return Module.RouteInstruction.getTurnInstructionString(this.m_object);
}
/**
* Get the turn image in a bitmap
* @param {gem.core.BitmapContainer} bitmapContainer - output bitmap
*/
getTurnImageInBitmap(bitmapContainer) {
Module.RouteInstruction.getTurnImageInBitmap(this.m_object, bitmapContainer.getRawPointer());
}
/**
* Get textual description for the follow road information.
* @returns {string}
*/
getFollowRoadInstruction() {
return Module.RouteInstruction.getFollowRoadInstruction(this.m_object);
}
/**
* Get Coordinates
* @returns {gem.core.Coordinates}
*/
getCoordinates() {
return Module.RouteInstruction.getCoordinates(this.m_object);
}
/**
* Get Country Code ISO
* @returns {string}
*/
getCountryCodeISO() {
return Module.RouteInstruction.getCountryCodeISO(this.m_object);
}
/** Get remaining travel distance in meters and remaining traveling time in seconds.
* @returns {gem.core.TimeAndDistance}
*/
getRemainingTravelTimeDistance() {
return Module.RouteInstruction.getRemainingTravelTimeDistance(this.m_object);
}
/**
* Gets distance to the next turn in meters, time in seconds.
* @returns {gem.core.TimeAndDistance}
*/
getTimeDistanceToNextTurn() {
return Module.RouteInstruction.getTimeDistanceToNextTurn(this.m_object);
}
/**
* Get the traveled distance in meters and the traveled time in seconds.
* @returns {gem.core.TimeAndDistance}
*/
getTraveledTimeDistance() {
return Module.RouteInstruction.getTraveledTimeDistance(this.m_object);
}
/**
* Get image for the realistic turn information.
* @param {gem.core.BitmapContainer} bitmapContainer - output bitmap. This object will be modified by this method.
*/
getRealisticNextTurnImage(bitmapContainer) {
Module.RouteInstruction.getRealisticNextTurnImage(this.m_object, bitmapContainer.getRawPointer());
}
/**
* Check if follow road information is available.
* @returns {boolean}
*/
hasFollowRoadInfo() {
return Module.RouteInstruction.hasFollowRoadInfo(this.m_object);
}
/**
* Checks if turn information is available.
* @returns {boolean}
*/
hasTurnInfo() {
return Module.RouteInstruction.hasTurnInfo(this.m_object);
}
/**
* Check if signpost information is available.
* @returns {boolean}
*/
hasSignpostInfo() {
return Module.RouteInstruction.hasSignpostInfo(this.m_object);
}
/**
*
* @param {*} bitmapContainer - output bitmap
* @param {*} backgroundColor - background color
* @param {*} foregroundColor - foreground color
*/
getAbstractGeometryImage(bitmapContainer, backgroundColor, foregroundColor) {
Module.RouteInstruction.getAbstractGeometryImage(this.m_object, bitmapContainer.getRawPointer(), backgroundColor, foregroundColor);
}
/**
* Converts the current route instruction to a Public Transit route instruction.
* @returns {object} The converted Public Transit route instruction.
*/
toPTRouteInstruction() {
return Module.RouteInstruction.toPTRouteInstruction(this.m_object);
}
/**
* Converts the current route instruction to an Electric Vehicle route instruction.
* @returns {gem.routesAndNavigation.EVRouteInstruction} The converted Electric Vehicle route instruction.
*/
toEVRouteInstruction() {
return new gem.routesAndNavigation.EVRouteInstruction(Module.RouteInstruction.toEVRouteInstruction(this.m_object));
}
}
/**StoreProgressListener class
* @class gem.content.StoreProgressListener
* @augments Em_Object
* @memberof gem.content
*/
gem.content.StoreProgressListener = class StoreProgressListener extends Em_Object {
constructor() {
super(new Module.StoreProgressListener());
}
/**
*
* @param {*} callback
*/
registerCompleteCallback(callback) {
this.m_object.registerCompleteCallback(callback);
}
/**
*
* @param {*} callback
*/
registerProgressCallback(callback) {
this.m_object.registerProgressCallback(callback);
}
}
/**
* @class gem.core.App
*@hideconstructor
*@memberof gem.core
*/
gem.core.App = class App {
/**
*
* @param {*} callbackfunction
*/
static registerPostInitializeCallback(callbackfunction) {
Module.RegisterPostInitializeCallback(callbackfunction);
}
/**
* Destroy app resources. Should be called at page closing
*/
static destroyApp() {
try {
Module.destroyApp();
} catch (e) {
Module.destroyHasBeenCalled = true;
}
}
/**
*
* @param {*} callbackfunction
*/
static registerPreRenderCallback(callbackfunction) {
Module.registerPreRenderCallback(callbackfunction);
}
/**
* Update the url header with informations about location ( lat, lon, z = zoom level )
*/
static updateHeader() {
if (history.pushState) {
let defaultView = gem.core.App.getDefaultScreen().getDefaultMapView();
let currentPosition = defaultView.getCursorPositionWGS();
let zoomLevel = defaultView.getZoomLevel();
var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + "?lat=" + currentPosition.latitude + "&long=" + currentPosition.longitude + "&z=" + zoomLevel;
window.history.pushState({
path: newurl
}, '', newurl);
}
}
/**
* Register initial call function. Must be added before initApp() call
* @param {callback} callFunction
*/
static registerInitialCallFunction(callFunction) {
gem.core.App.m_initialFunction = callFunction;
}
/**
* Register route calculation from url parameters. Must be added before initApp() call
* @param {callback} callFunction
*/
static registerRouteCalculationFromParameters(callFunction) {
gem.core.App.m_routeCalculationFromParam = callFunction;
}
static addScriptToDom(scriptCode) {
return new Promise(function (resolve, reject) {
var script = document.createElement('script');
script.nonce = 'matching-nonce-value';
var blob = new Blob([scriptCode], {
type: 'application/javascript'
});
var objectUrl = URL.createObjectURL(blob);
script.src = objectUrl;
script.onload = function () {
script.onload = script.onerror = null; // Remove these onload and onerror handlers, because these capture the inputs to the Promise and the input function, which would leak a lot of memory!
URL.revokeObjectURL(objectUrl); // Free up the blob. Note that for debugging purposes, this can be useful to comment out to be able to read the sources in debugger.
resolve();
}
script.onerror = function (e) {
script.onload = script.onerror = null; // Remove these onload and onerror handlers, because these capture the inputs to the Promise and the input function, which would leak a lot of memory!
URL.revokeObjectURL(objectUrl);
console.error('script failed to add to dom: ' + e);
reject(e.message || "(out of memory?)");
}
document.body.appendChild(script);
});
}
static syncStorageLandmarks(direction) {
if (direction) {
try {
//create your directory where we keep our persistent data
FS.mkdir('/Data/Landmarks');
} catch (error) {
}
try {
FS.mount(IDBFS, {}, '/Data/Landmarks');
FS.syncfs(direction, function (err) {
assert(!err);
setTimeout(() => gem.core.App.syncContentWithStorage(true), 0);
});
} catch (error) {
gem.core.App.usePersistentStorage = 0;
}
} else {
FS.syncfs(function (err) { });
}
}
static syncContentWithStorage(direction) {
if (direction) {
try {
//create your directory where we keep our persistent data
FS.mkdir('/Data/Maps');
} catch (error) {
}
FS.mount(IDBFS, {}, '/Data/Maps');
var syncFlag = 0;
FS.syncfs(direction, function (err) {
assert(!err);
if (Module.refreshContentStore !== undefined) {
Module.refreshContentStore();
if (gem.core.App.persistentStorageLoadedCb)
gem.core.App.persistentStorageLoadedCb();
}
syncFlag = 1;
});
} else {
FS.syncfs(function (err) { });
}
}
static preRun(worldMapFileI) {
let baseURI = baseURL + "sdk/js/";
let worldMapFile = baseURI + worldMapFileI;
const searchString = window.location.search;
const urlParams = new URLSearchParams(searchString);
if (urlParams.has("app_key")) {
/**
*@public
@memberof gem.core
*@property {string} gem.core.App.token - App token. Must be set before initApp() call
*/
gem.core.App.token = urlParams.get("app_key");
}
Module.appAuthorizationKey = gem.core.App.token !== undefined ? gem.core.App.token : "";
var n = worldMapFile.lastIndexOf("/");
var filename = worldMapFile.substring(n);
Module.noImageDecoding = true;
FS.createPath('/', 'Data', true, true);
FS.createPath('/Data', 'Res', true, true);
FS.createPath('/Data/Res', 'Obj', true, true);
FS.createPath('/Data/Res', 'Renderer', true, true);
FS.createPath('/Data/Res', 'Weather', true, true);
FS.createPath('/Data', 'SceneRes', true, true);
gem.core.App.pathDataCreated = true;
gem.core.App.usePersistentStorage = gem.core.App.usePersistentStorage && (window.indexedDB || indexedDB) ? 1 : 0;
if (navigator.userAgent.indexOf("Firefox") != -1) {
let db = indexedDB.open("test");
db.onerror = function () {
gem.core.App.usePersistentStorage = 0;
};
db.onsuccess = function () {
gem.core.App.syncStorageLandmarks(true);
};
} else {
if (gem.core.App.usePersistentStorage) {
gem.core.App.syncStorageLandmarks(true);
}
}
try {
gem.core.App._processFileQueue();
FS.createPreloadedFile("/Data/Res", filename, baseURI + "res/map/latest/", true, true);
//FS.createPath('/Data/SceneRes', 'SceneConfig', true, true);
//FS.createPath('/Data/SceneRes', 'Schemas', true, true);
if (gem.core.App.defaultStyleFile !== undefined) {
FS.createPreloadedFile("/Data/SceneRes", 'Basic_1-1_1_1.style', gem.core.App.defaultStyleFile, true, true);
} else {
FS.createPreloadedFile("/Data/SceneRes", 'Basic_1-1_1_1.style', baseURI + 'Basic_1-1_1_1.style', true, true);
}
if (gem.core.App.preloadeddata !== undefined) {
if (gem.core.App.preloadeddata === "satellite") {
FS.createPath('/Data', 'Temporary', true, true);
FS.createPath('/Data/Temporary', 'Tiles', true, true);
FS.createPreloadedFile("/Data/Temporary/Tiles", 'prv3_prm1.vdb', baseURI + 'AppData/Data/Temporary/Tiles/prv3_prm1.vdb', true, true);
}
}
FS.createPreloadedFile("/Data/Res", 'Countries.proto', baseURI + 'res/lang/generic/Countries.proto', true, true);
FS.createPreloadedFile("/Data/Res", 'Icon.db', baseURI + 'res/icon/SDL/Icon.db', true, true);
FS.createPreloadedFile("/Data/Res", 'Ipa_Lhp.pst', baseURI + 'AppData/Data/Res/Ipa_Lhp.pst', true, true);
FS.createPreloadedFile("/Data/Res", 'Ipa_XSampa.pst', baseURI + 'AppData/Data/Res/Ipa_XSampa.pst', true, true);
//FS.createPreloadedFile("/Data/Res", 'links.stx', baseURI + 'AppData/Data/Res/links.stx', true, true);
//FS.createPreloadedFile("/Data/Res",'MapResource.proto',baseURI+'/AppData/Data/Res/MapResource.proto', true, true);
FS.createPreloadedFile("/Data/Res", 'MapScheme.proto', baseURI + 'res/lang/generic/MapScheme.proto', true, true);
//FS.createPreloadedFile("/Data/Res", 'nocap.stx', baseURI + 'AppData/Data/Res/nocap.stx', true, true);
//FS.createPreloadedFile("/Data/Res", 'squarecap.stx', baseURI + 'AppData/Data/Res/squarecap.stx', true, true);
FS.createPreloadedFile("/Data/Res", 'Traffic.proto', baseURI + 'res/lang/generic/Traffic.proto', true, true);
FS.createPreloadedFile("/Data/Res", 'Translations.proto', baseURI + 'res/lang/Controller/Translations.proto', true, true);
FS.createPreloadedFile("/Data/Res", 'Weather.proto', baseURI + 'res/lang/generic/Weather.proto', true, true);
FS.createPreloadedFile("/Data/Res/Obj", 'arrow.obj', baseURI + 'AppData/Data/Res/Obj/arrow.obj', true, true);
FS.createPreloadedFile("/Data/Res/Renderer", 'Font-2.sys', baseURI + 'AppData/Data/Res/Renderer/Font-2.sys', true, true);
FS.createPreloadedFile("/Data/Res/Renderer", 'Font-Arabic.sys', baseURI + 'AppData/Data/Res/Renderer/Font-Arabic.sys', true, true);
FS.createPreloadedFile("/Data/Res/Renderer", 'Font-Bold2.sys', baseURI + 'AppData/Data/Res/Renderer/Font-Bold2.sys', true, true);
FS.createPreloadedFile("/Data/Res/Renderer", 'Font-Cambodian.sys', baseURI + '/AppData/Data/Res/Renderer/Font-Cambodian.sys', true, true);
FS.createPreloadedFile("/Data/Res/Renderer", 'Font-Italic2.sys', baseURI + 'AppData/Data/Res/Renderer/Font-Italic2.sys', true, true);
FS.createPreloadedFile("/Data/Res/Renderer", 'Font-Myanmar.sys', baseURI + 'AppData/Data/Res/Renderer/Font-Myanmar.sys', true, true);
FS.createPreloadedFile("/Data/Res/Renderer", 'Fonts2.chf', baseURI + 'AppData/Data/Res/Renderer/Fonts2.chf', true, true);
FS.createPreloadedFile("/Data/Res/Renderer", 'Font-Ethiopia.sys', baseURI + 'AppData/Data/Res/Renderer/Font-Ethiopia.sys', true, true);
//FS.createPreloadedFile("/Data/SceneRes/SceneConfig",'SceneResource.proto',baseURI+'/AppData/Data/SceneRes/SceneConfig/SceneResource.proto', true, true);
//FS.createPreloadedFile("/Data/SceneRes/SceneConfig",'SceneResource.json',baseURI+'/AppData/Data/SceneRes/SceneConfig/SceneResource.json', true, true);
//FS.createPreloadedFile("/Data/SceneRes/Schemas",'SceneResource_Schema.json',baseURI+'/AppData/Data/SceneRes/Schemas/SceneResource_Schema.json', true, true);
FS.createPreloadedFile("/Data/Res/Weather", 'atmos.bmp', baseURI + 'AppData/Data/Res/Weather/atmos.bmp', true, true);
FS.createPreloadedFile("/Data/Res/Weather", 'colorpallet.tga', baseURI + 'AppData/Data/Res/Weather/colorpallet.tga', true, true);
FS.createPreloadedFile("/Data/Res/Weather", 'radar_colorpalette.tga', baseURI + 'AppData/Data/Res/Weather/radar_colorpalette.tga', true, true);
FS.createPreloadedFile("/Data/Res/Weather", 'SunFlare.dat', baseURI + 'AppData/Data/Res/Weather/SunFlare.dat', true, true);
FS.createPreloadedFile("/Data/Res/Weather", 'greyscale_colorbar.bmp', baseURI + 'AppData/Data/Res/Weather/greyscale_colorbar.bmp', true, true);
FS.createPreloadedFile("/Data/Res", 'Social.proto', baseURI + 'AppData/Data/Res/Social.proto', true, true);
} catch (error) {
}
}
/**
* Set the path to the style to be used at startup.Must be added before initApp() call
* @param {string} styleFilePath
*/
static setDefaultStyle(styleFilePath) {
gem.core.App.defaultStyleFile = styleFilePath;
}
static setPreloadedData(preloadeddata) {
gem.core.App.preloadeddata = preloadeddata;
}
/**
* Start the initilization process.Is an async process.Getting the resources.
* Please use gem.core.App.registerInitialCallFunction before calling this method,if you want to apply settings at application startup.
*/
static createElementCopyright() {
let cvs = document.getElementById("canvas");
let copyrightDiv = document.createElement("div");
copyrightDiv.className = 'gem-no-select';
copyrightDiv.setAttribute("id", "copyrightDiv");
copyrightDiv.style.backgroundColor = "rgba(255, 255, 255, 0.8)";
copyrightDiv.style.bottom = "0";
copyrightDiv.style.right = "4px";
copyrightDiv.style.position = "absolute";
copyrightDiv.style.fontSize = "small";
copyrightDiv.style.height = "auto";
copyrightDiv.style.padding = "0px";
copyrightDiv.innerHTML += "©•<a href='https://www.magiclane.com'>MagicLane</a>•<a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a>";
copyrightDiv.style.zIndex = "999999";
let button = document.createElement("Button");
button.setAttribute("id", "buttonCopyright");
button.setAttribute("type", "button");
button.style.position = "absolute";
button.style.bottom = "0";
button.style.right = "2px";
button.textContent = 'i';
button.style.zIndex = "999999";
button.onmouseover = function () {
let button = document.getElementById("buttonCopyright");
let cDiv = document.getElementById("copyrightDiv");
cDiv.style.right = button.offsetWidth + 2 + "px";
cDiv.style.visibility = "visible";
};
button.onmouseleave = function () {
let cDiv = document.getElementById("copyrightDiv");
cDiv.style.visibility = "hidden";
};
button.onmousedown = function () {
let cDiv = document.getElementById("copyrightDiv");
if (cDiv.style.visibility.localeCompare("hidden") === 0) {
cDiv.style.visibility = "visible";
} else
cDiv.style.visibility = "hidden";
};
cvs.parentElement.appendChild(copyrightDiv);
cvs.parentElement.appendChild(button);
function myFunction(x) {
if (x.matches) { // If media query matches
let button = document.getElementById("buttonCopyright");
button.style.visibility = "visible";
let cDiv = document.getElementById("copyrightDiv");
cDiv.style.visibility = "hidden";
} else {
let button = document.getElementById("buttonCopyright");
button.style.visibility = "hidden";
let cDiv = document.getElementById("copyrightDiv");
cDiv.style.visibility = "visible";
cDiv.style.right = "2px";
}
}
var x = window.matchMedia("(max-width: 720px)");
myFunction(x); // Call listener function at run time
x.addEventListener('change', myFunction); // Attach listener function on state changes
}
static createLoadingCircle(parentDiv) {
let svgns = "http://www.w3.org/2000/svg";
let wrapperDiv = document.createElement("div");
wrapperDiv.setAttribute("id", "wrapper");
parentDiv.insertBefore(wrapperDiv, parentDiv.firstChild);
let profilemainloader = document.createElement("div");
profilemainloader.classList.add("profile-main-loader");
wrapperDiv.appendChild(profilemainloader);
let loader = document.createElement("div");
loader.classList.add("loader");
profilemainloader.appendChild(loader);
let svg = document.createElementNS(svgns, "svg");
svg.classList.add("circular-loader");
svg.setAttribute("viewBox", "25 25 50 50");
loader.appendChild(svg);
let circle = document.createElementNS(svgns, 'circle');
circle.classList.add("loader-path");
circle.setAttributeNS(null, 'cx', 50);
circle.setAttributeNS(null, 'cy', 50);
circle.setAttributeNS(null, 'r', 20);
circle.setAttributeNS(null, 'style', 'fill: none; stroke: #70c542; stroke-width: 2px;');
svg.appendChild(circle);
}
static parseOptions() {
let defaultView = gem.core.App.getDefaultScreen().getDefaultMapView();
if (gem.core.App.initOptions.center !== undefined) {
let lat = gem.core.App.initOptions.center[0];
let lon = gem.core.App.initOptions.center[1];
let alt = gem.core.App.initOptions.center[2];
if (alt === undefined)
alt = 1000;
let coordinates = {
latitude: lat,
longitude: lon,
altitude: alt,
bearing: 0
};
let msecFlightDuration = 0;
defaultView.centerOnCoordinates(coordinates, msecFlightDuration);
}
if (gem.core.App.initOptions.zoom !== undefined) {
defaultView.setZoomLevel(gem.core.App.initOptions.zoom);
}
gem.core.App.defaultAppScreen.initFinished();
}
/**Init App . Mandatory to be called.
*@param {object} initOptions - init options
*@returns {gem.core.AppScreen} - returns AppScreen Object
*
*/
static initAppScreen(initOptions) {
return gem.core.App.initApp(initOptions);
}
static inIframe() {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
}
static _createFile(path, filename, url, canRead, canWrite) {
if (gem.core.App.pathDataCreated) {
// Use FS.createPreloadedFile before WASM is loaded
FS.createPreloadedFile(
path, // Path in the filesystem
filename, // File name
url, // URL of the file
canRead, // Read permission
canWrite // Write permission
);
} else {
// Fetch file manually
fetch(url)
.then(response => response.arrayBuffer())
.then(data => {
if ( gem.core.App.pathDataCreated && typeof FS !== "undefined") {
// If FS is available, create the file
FS.createDataFile(
path, // Path in the filesystem
filename, // File name
new Uint8Array(data), // File data as Uint8Array
canRead, // Read permission
canWrite // Write permission
);
console.log(`${filename} has been loaded into ${path}`);
} else {
// If FS is not available, store file info in the queue
gem.core.App.fileQueue.push({ path, filename, data: new Uint8Array(data), canRead, canWrite });
console.warn(`FS not available. Queued ${filename} for later.`);
}
})
.catch(err => console.error(`Failed to load ${url}: ${err.message}`));
}
}
static _processFileQueue() {
if (typeof FS === "undefined") {
console.warn("FS is still not available. Cannot process queued files yet.");
return;
}
gem.core.App.fileQueue.forEach(file => {
FS.createDataFile(
file.path,
file.filename,
file.data,
file.canRead,
file.canWrite
);
console.log(`${file.filename} has been processed and loaded into ${file.path}`);
});
gem.core.App.fileQueue.length = 0; // Clear the queue after processing
}
/**Init App . Mandatory to be called.
* @param {object} initOptions - init options
* @param {string} initOptions.container - container element id
* @param {string} [initOptions.style] - url to map style
* @param {object} [initOptions.center] - map start-up center coordinate of type [latitude, longitude, altitude]
* @param {number} [initOptions.zoom] - map start-up zoom level
*/
static initApp(initOptions) {
gem.core.App.fileQueue = [];
// fix for mobile
window.addEventListener('load', () => {
const viewport = document.querySelector('meta[name=viewport]');
if (viewport)
viewport.setAttribute('content', viewport.content + ', height=' + window.innerHeight + ', width=' + window.innerWidth);
});
if (initOptions !== undefined) {
let containerDiv = document.getElementById(initOptions.container);
gem.core.App.containerDiv = containerDiv;
containerDiv.style.overflow = "hidden";
let canvasDiv = document.createElement("canvas");
canvasDiv.classList.add("emscripten");
canvasDiv.setAttribute("id", "canvas");
canvasDiv.addEventListener('contextmenu', e => {
e.preventDefault();
});
canvasDiv.tabIndex = "0";
containerDiv.appendChild(canvasDiv);
gem.core.App.createLoadingCircle(containerDiv);
if (initOptions.style !== undefined) {
gem.core.App.defaultStyleFile = initOptions.style;
}
gem.core.App.enableDebug = initOptions.debugMode;
gem.core.App.multiThread = initOptions.multiThread;
gem.core.App.onlineStatus = initOptions.isOnlineAllowed;
gem.core.App.usePersistentStorage = initOptions.usePersistentStorage && (window.indexedDB || indexedDB) ? 1 : 0;
gem.core.App.persistentStorageLoadedCb = initOptions.persistentStorageLoadedCb;
//Module.useperisistentstorage = initOptions.usePersistentStorage ? 1 : 0;
}
if (gem.core.App.inIframe()) {
document.body.onmouseleave = function (ev) {
let cvs = document.getElementById("canvas");
if (cvs) {
var event = new MouseEvent('mouseup', {
'view': window,
'bubbles': true,
'cancelable': true
});
cvs.dispatchEvent(event);
}
};
}
Module = {
preRun: [],
postRun: [],
print: (function () {
return function (text) { };
})(),
printErr: function (text) {
text = Array.prototype.slice.call(arguments).join(' ');
console.error(text);
},
canvas: (function () {
var canvas = document.getElementById('canvas');
return canvas;
})(),
};
if (gem.core.App.enableLoggingFlag)
Module.print = (function () {
return function (text) {
text = Array.prototype.slice.call(arguments).join(' ');
console.log(text);
};
})();
gem.core.App.initOptions = initOptions;
try {
Module['preRun'].push(function () {
gem.core.App.preRun('WM_7_403.map');
Module.useperisistentstorage = 0;
Module.gemAppVariant = gem.core.App.appVariant;
if (gem.core.App.onlineStatus !== undefined) {
Module.onlineStatus = gem.core.App.onlineStatus;
}
});
Module['postRun'].push(function () {
gem.core.App.initializeStructures();
var canvas = document.getElementById('canvas');
var wrapper = document.getElementById('wrapper');
if (wrapper !== null && wrapper !== undefined)
wrapper.remove();
canvas.style.visibility = 'visible';
if (!Module.useperisistentstorage) {
if (parseInt(canvas.style.width) < 1 || parseInt(canvas.style.height) < 1) {
console.warn("Please use a valid canvas width & height");
gem.core.App.registerPostInitializeCallback(function () {
if (gem.core.App.initOptions)
gem.core.App.parseOptions();
gem.core.App.parseParameters(gem.core.App.m_routeCalculationFromParam);
var isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
if (isMobile) {
gem.core.App.getDefaultScreen().getDefaultMapView().setMapViewDetailsQualityLevel(0);
}
if (gem.core.App.m_initialFunction)
gem.core.App.m_initialFunction();
});
} else {
if (gem.core.App.initOptions)
gem.core.App.parseOptions();
if (gem.core.App.m_initialFunction)
gem.core.App.m_initialFunction();
gem.core.App.parseParameters(gem.core.App.m_routeCalculationFromParam);
}
window.addEventListener("beforeunload", e => {
gem.core.App.destroyApp();
}, {
once: true
});
}
//Module.enableLocation();
gem.core.App.createElementCopyright();
});
if (gem.core.App.multiThread !== undefined) {
let scriptEle = document.createElement("script");
scriptEle.setAttribute("src", baseURL + 'sdk/js/TutorialAppSDLdebugMulti020022.js');
scriptEle.setAttribute("type", "text/javascript");
scriptEle.setAttribute("async", true);
document.body.appendChild(scriptEle);
} else {
if (gem.core.App.enableDebug !== undefined && gem.core.App.enableDebug === true)
fetch(baseURL + 'sdk/js/' + SDK_version + '/MagicEarthdebug_0001.js').then((response) => response.arrayBuffer())
.then((bytes) => {
Module['javscriptFile'] = bytes;
gem.core.App.addScriptToDom(bytes)
});
else
fetch(baseURL + 'sdk/js/' + SDK_version + '/MagicEarthrelease_0001.js').then((response) => response.arrayBuffer())
.then((bytes) => {
Module['javscriptFile'] = bytes;
gem.core.App.addScriptToDom(bytes)
});
}
const baseURI = baseURL + "sdk/js/";
let worldMapFile = baseURI + 'WM_7_403.map';
let n = worldMapFile.lastIndexOf("/");
let filename = worldMapFile.substring(n);
//gem.core.App._createFile("/Data/Res", filename, baseURI + "res/map/latest/", true, true);
//gem.core.App._createFile("/Data/Res/Renderer", 'Font-2.sys', baseURI + 'AppData/Data/Res/Renderer/Font-2.sys', true, true);
//gem.core.App._createFile("/Data/Res", 'Countries.proto', baseURI + 'res/lang/generic/Countries.proto', true, true);
} catch (err) {
console.log(err);
//window.location.reload(true);
}
if (initOptions && initOptions.container) {
gem.core.App.defaultAppScreen = new gem.core.AppScreen(initOptions.container);
return gem.core.App.defaultAppScreen;
}
}
/**
* returns the default Screen
* @returns {gem.d3Scene.Screen} default Screen
*/
static getDefaultScreen() {
return new gem.d3Scene.Screen(Module.getDefaultScreen());
}
/**
* Get Last Known GPS position
* @returns {gem.core.Coordinates}
*/
static getLastKnownPosition() {
return Module.getLastKnownPosition();
}
static initializeStructures() {
gem.core.EAddressDetailLevel.initializeData();
gem.routesAndNavigation.ERouteType.initializeData();
gem.routesAndNavigation.ERouteTransportMode.initializeData();
gem.d3Scene.EMarkerType.initializeData();
gem.d3Scene.EUsableIcons.initializeData();
gem.d3Scene.ECursorEvent.initializeData();
gem.d3Scene.EHighlightOptions.initializeData();
gem.routesAndNavigation.ERoadType.initializeData();
gem.routesAndNavigation.ESurfaceType.initializeData();
gem.content.EContentType.initializeData();
gem.routesAndNavigation.ERouteResultDetails.initializeData();
gem.routesAndNavigation.ERoutePathAlgorithm.initializeData();
gem.routesAndNavigation.EBikeProfile.initializeData();
gem.routesAndNavigation.EEBikeType.initializeData();
gem.ETouchGestures.initializeData();
gem.routesAndNavigation.EFuelType.initializeData();
}
static parseParameters(routeCallback) {
if (gem.core.App.token !== undefined) {
let defaultView = gem.core.App.getDefaultScreen().getDefaultMapView();
const searchString = window.location.search;
const urlParams = new URLSearchParams(searchString);
let hasLat = urlParams.has("lat");
let hasLon = urlParams.has("lon");
//let hasZ = urlParams.has("z");
let hasAlt = urlParams.has("alt");
if (hasLat || hasLon) {
let coordinates = defaultView.getCursorPositionWGS();
coordinates.latitude = hasLat ? parseFloat(urlParams.get("lat")) : coordinates.latitude;
coordinates.longitude = hasLon ? parseFloat(urlParams.get("lon")) : coordinates.longitude;
coordinates.altitude = hasAlt ? parseFloat(urlParams.get("alt")) : coordinates.altitude;
defaultView.centerOnCoordinates(coordinates, 0);
}
//defaultView.setZoomLevel(hasZ?parseFloat(urlParams.get("z")):zoomLevel);
if (routeCallback !== undefined) {
let allWp = urlParams.getAll("wp");
if (allWp.length > 0) {
let waypoint = new Array();
for (let wp of allWp) {
let coordinates = {
latitude: 0,
longitude: 0,
bearing: 0,
altitude: 0
};
let splitwp = wp.split(',');
coordinates.latitude = parseFloat(splitwp[0]);
coordinates.longitude = parseFloat(splitwp[1]);
waypoint.push(coordinates);
}
routeCallback(waypoint);
}
}
if (urlParams.has("geoLocation")) {
let geoLocation = urlParams.get("geoLocation");
geoLocation = geoLocation.replace("geo:", "");
let pSplit = geoLocation.split(";");
if (pSplit.length > 0) {
let splitwp = pSplit[0].split(',');
let coordinates = defaultView.getCursorPositionWGS();
coordinates.latitude = splitwp[0];
coordinates.longitude = splitwp[1];
coordinates.altitude = 500;
defaultView.centerOnCoordinates(coordinates, 0);
}
}
if (urlParams.has("fav")) {
let featureCollection = {
type: "FeatureCollection",
features: []
};
let allFav = urlParams.getAll("fav");
for (let fav of allFav) {
let parsedFav = JSON.parse(gem.Helper.generateDecodedGeoJsonPoint(fav));
featureCollection.features.push(parsedFav);
}
gem.core.featureCollection = (JSON.stringify(featureCollection));
}
}
}
static setGeoJsonCallback(jsCallback) {
gem.core.geojsoncallback = jsCallback;
}
/**
* Register Connection status changed callback
* @param {*} callback
*/
static registerConnectionStatusChanged(callback) {
Module.registerConnectionStatusChanged(callback);
}
static enableLogging(bValue) {
if (bValue)
Module.print = function (text) {
text = Array.prototype.slice.call(arguments).join(' ');
console.log(text);
};
else
Module.print = (function () { })();
}
/**
* Returns bounding box for an array of coordinates
* @param {Array.<gem.core.Coordinates>} coordinatesArray
* @returns {gem.core.BoundingBox}
*/
static getBoundingBoxForCoordinates(coordinatesArray) {
return Module.getBoundingBoxFromCoordinatesArray(coordinatesArray);
}
/**
*
* @param {gem.core.Coordinates} coordinate1
* @param {gem.core.Coordinates} coordinate2
* @returns {number} - returns distance between the 2 coordinates
*/
static getDistanceBetween2Coordinates(coordinate1, coordinate2) {
return Module.computeDistanceBetween2Points(coordinate1, coordinate2);
}
/**
*
* @param {Array.<Byte>} image_data - canvas image data
* @param {number} width - width of canvas
* @param {number} height - height of canvas
* @param {object} canvas - canvas element
*/
static setCanvas(image_data, width, height, canvas) {
if (canvas) {
var imageData = new ImageData(new Uint8ClampedArray(image_data), width, height);
canvas.width = width;
canvas.height = height;
canvas.getContext('2d').putImageData(imageData, 0, 0);
} else {
console.error('Canvas not valid');
}
}
/**
* Retrieves the current language setting.
* @returns {string} The current language.
*/
static getLanguage() {
return Module.getLanguage();
}
/**
* Checks if location access is granted.
* @param {Function} funcReturnError - Callback function to handle error.
*/
static checkLocationAccess(funcReturnError) {
function showPosition(position) { };
if (funcReturnError !== undefined) {
navigator.geolocation.getCurrentPosition(showPosition, funcReturnError);
}
}
/**
* Requests access to location services.
*/
static requestLocationAccess() {
Module.requestLocationAccess();
}
/**
* Stops access to location services.
*/
static stopLocationAccess() {
Module.stopLocationAccess();
}
/**
* Retrieves the default scene.
* @returns {object} The default scene.
*/
static getDefaultScene() {
return Module.getDefaultScene();
}
/**
* Creates a new camera for the given scene.
* @param {object} scene - The scene for which to create a camera.
* @returns {Module.MapCamera} The created camera.
*/
static createCamera(scene) {
return new Module.MapCamera(scene);
}
/**
* Retrieves the image of the country flag based on the ISO code.
* @param {string} isoCode - The ISO code of the country.
* @param {gem.core.BitmapContainer} bitmap - The output bitmap container for the flag image.
*/
static getCountryFlagImage(isoCode, bitmap) {
Module.getCountryFlagImage(isoCode, bitmap.getRawPointer());
}
/**
* Retrieves the version of the world map.
* @returns {string} The version of the world map.
*/
static getWorldMapVersion() {
return Module.getWorldMapVersion();
}
/**
* Sets a custom URL for a specific service.
* @param {string} serviceCode - The code of the service.
* @param {string} customURL - The custom URL to set.
*/
static setCustomUrl(serviceCode, customURL) {
Module.setCustomUrl(serviceCode, customURL);
}
}
/**
* @class gem.Helper
* @memberof gem
* @hideconstructor
*/
gem.Helper = class helper {
/**
* Create a string, ready to be added to the send url as a Waypoint parameter.
* @param {gem.core.Coordinates} coordinates
* @returns {string} string ready for url.
*/
static createWaypointString(coordinates) {
return "wp=" + coordinates.latitude + "," + coordinates.longitude;
}
/**
*
* @param {gem.core.Coordinates} coordinatesI - coordinates of the item
* @param {string} properties - json properites of the item
* @returns {string} - returns encoded geojson item to be added to the send url
*/
static generateEncodedGeoJsonPoint(coordinatesI, properties) {
let geojsonPoint = {
type: "Feature",
id: 0,
geometry: {
type: "Point",
coordinates: [
coordinatesI.longitude,
coordinatesI.latitude
]
},
properties: properties
};
let encode = encodeURIComponent(JSON.stringify(geojsonPoint));
encode = encode.replaceAll('[', '%5B');
encode = encode.replaceAll(']', '%5D');
encode = encode.replaceAll('{', '%7B');
encode = encode.replaceAll('}', '%7D');
encode = encode.replaceAll(/"/g, '%22');
return ("fav=" + encode);
}
/**
* Decode previously encoded geojson for url submission
* @param {string} inputCodedGeoJson - encoded geojson
* @returns {string} - decoded geojson
*/
static generateDecodedGeoJsonPoint(inputCodedGeoJson) {
let inputReplaced = inputCodedGeoJson.replaceAll('%5B', '[');
inputReplaced = inputReplaced.replaceAll('%5D', ']');
inputReplaced = inputReplaced.replaceAll('%7B', '{');
inputReplaced = inputReplaced.replaceAll('%7D', '}');
inputReplaced = inputReplaced.replaceAll('%22', /"/g);
let decode = decodeURIComponent(inputReplaced);
return decode;
}
}
/**Route Traffic Event class
* @class gem.routesAndNavigation.RouteTrafficEvent
* @memberof gem.routesAndNavigation
*/
gem.routesAndNavigation.RouteTrafficEvent = class routetrafficEvent extends Em_Object {
/**
* Get the distance in meters from starting point on current route of the traffic event to the destination.
@returns {number} - distance in meters
*/
getDistanceToDestination() {
return Module.RouteTrafficEvent.getDistanceToDestination(this.m_object);
}
/**
* Get the image for the traffic event
* @param {gem.core.BitmapContainer} bitmapContainer - output bitmap
*/
getImage(bitmapContainer) {
Module.RouteTrafficEvent.getImage(this.m_object, bitmapContainer.getRawPointer());
}
/** Get geographical area of the traffic event
* @returns {gem.core.BoundingBox}
*/
getBoundingBox() {
return Module.RouteTrafficEvent.getBoundingBox(this.m_object);
}
/**
* Gets the estimated delay in seconds caused by the traffic event.
* @returns {number} - delay in seconds.For roadblocks it will return -1.
*/
getDelay() {
return Module.RouteTrafficEvent.getDelay(this.m_object);
}
/**
* Gets start time UTC
* @returns {number} - Epoch time
*/
getStartTime() {
return Module.RouteTrafficEvent.getStartTime(this.m_object);
}
/**
* Gets end time UTC
* @returns {number} - Epoch time
*/
getEndTime() {
return Module.RouteTrafficEvent.getEndTime(this.m_object);
}
/**Get the description of the traffic event.
* @returns {string}
*/
getDescription() {
return Module.RouteTrafficEvent.getDescription(this.m_object);
}
/**
* Get the length in meters of the road segment affected by the traffic event.
* @returns {number}
*/
getLength() {
return Module.RouteTrafficEvent.getLength(this.m_object);
}
/**
* Get the traffic event reference point
* @returns {gem.core.Coordinates} - reference point
*/
getReferencePoint() {
return Module.RouteTrafficEvent.getReferencePoint(this.m_object);
}
}
gem.routesAndNavigation.RouteTrafficEventList = class RouteTrafficEventList extends Em_Vector {
/**
* Get Route Traffic event at specifed position in list
* @param {number} nId
* @returns {gem.routesAndNavigation.RouteTrafficEvent} - traffic event
*/
get(nId) {
return new gem.routesAndNavigation.RouteTrafficEvent(this.m_object.get(nId));
}
}
/**vector class
* @class gem.d3Scene.MarkerRef
* @memberof gem.d3Scene
*/
gem.d3Scene.MarkerRef = class vector extends Em_Object {
constructor(object, vectorId) {
super(object);
if (vectorId === undefined)
this.m_id = Module.View.getVectorId(this.m_object);
else
this.m_id = vectorId;
this.initialIndex = 0;
}
/**
* Add Point by coordinates
* @param {gem.core.Coordinates} coordinates
* @param {number} nIndex
* @returns {number} - index of the point
*/
addPoint(coordinates, nIndex) {
return Module.View.addPoint(this.m_object, coordinates, nIndex);
}
/**
* Get id of the vector
* @returns {number}
*/
getId() {
return this.m_id;
}
valueOf() {
return this.m_id;
}
/**
*
* @param {number} nId - index of coordinates part
* @returns {object} - vector of coordinates
*/
getCoordinatesPartAt(nId) {
return Module.View.getCoordinatesAt(this.m_object, nId);
}
getCoordinatesAt(nId) {
return Module.View.getCoordinatesAt(this.m_object, nId);
}
/**
* size of the vector
* @returns {number} - size of the vector
*/
size() {
return Module.View.getVectorSize(this.m_object);
}
/**
* get information about the vector
* @returns {string} - information about vector
*/
getInfo() {
return Module.View.getVectorInfo(this.m_object);
}
/**
* Change position of a point
* @param {number} pointId - id of the point
* @param {gem.core.Coordinates} coordinates - coordinates where to move the point
*/
movePoint(pointId, coordinates) {
Module.View.movePoint(this.m_object, pointId, coordinates);
}
/**
* Remove point at index location
* @param {number} nId
*/
removePoint(nId) {
Module.View.removePoint(this.m_object, nId);
}
}
/**vector class
* @class gem.d3Scene.Marker
* @memberof gem.d3Scene
*/
gem.d3Scene.Marker = class vector extends Em_Object {
constructor(object, vectorId) {
super(object);
if (vectorId === undefined)
this.m_id = this.m_object.getVectorId();
else
this.m_id = vectorId;
this.initialIndex = 0;
}
/**
* Add Point by coordinates
* @param {gem.core.Coordinates} coordinates
* @param {number} nIndex
* @returns {number} - index of the point
*/
addPoint(coordinates, nIndex) {
return this.m_object.addPoint(coordinates, nIndex);
}
/**
* Get id of the vector
* @returns {number}
*/
getId() {
return this.m_id;
}
valueOf() {
return this.m_id;
}
/**
*
* @param {number} nId - index of coordinates part
* @returns {object} - vector of coordinates
*/
getCoordinatesPartAt(nId) {
return this.m_object.getCoordinatesAt(nId);
}
getCoordinatesAt(nId) {
return this.m_object.getCoordinatesAt(nId);
}
/**
* size of the vector
* @returns {number} - size of the vector
*/
size() {
return this.m_object.getPartCount();
}
/**
* get information about the vector
* @returns {string} - information about vector
*/
getInfo() {
return this.m_object.getInfo();
}
/**
* Change position of a point
* @param {number} pointId - id of the point
* @param {gem.core.Coordinates} coordinates - coordinates where to move the point
*/
movePoint(pointId, coordinates) {
this.m_object.movePoint(pointId, coordinates);
}
/**
* Remove point at index location
* @param {number} nId
*/
removePoint(nId) {
this.m_object.removePoint(nId);
}
}
/**MarkerCollectionRef class
* @class gem.d3Scene.MarkerCollectionRef
* @memberof gem.d3Scene
*/
gem.d3Scene.MarkerCollection = class markerCollection extends Em_Object {
constructor(nId, mapView) {
if (mapView === undefined)
super(nId);
else {
super(null);
this.nId = nId;
this.mapView = mapView;
}
}
setNid(nId) {
this.nId = nId;
}
/**
* Create a marker with the specifed id
* @param {number} markerId - marker id
* @param {gem.core.Coordinates} coordinates - coordinates of the marker
* @param {number} radius - radius of the marker
* @returns {gem.d3Scene.Marker}
*/
createMarker(markerId, coordinates, radius) {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
let marker = new Module.Marker(Module.View.createVector(sourceAt, markerId, coordinates === undefined ? { latitude: 0.0, longitude: 0.0, altitude: 0.0, bearing: 0.0 } : coordinates, radius === undefined ? -1.0 : radius));
let result = new gem.d3Scene.Marker(marker);
sourceAt.delete();
return result;
} else
return new gem.d3Scene.Marker(new Module.Marker(Module.View.createVector(this.m_object, markerId, coordinates === undefined ? { latitude: 0.0, longitude: 0.0, altitude: 0.0, bearing: 0.0 } : coordinates, radius === undefined ? -1.0 : radius)));
}
/**
* Remove the marker with the id
* @param {number} nId - marker id
*/
removeMarker(nId) {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
Module.View.removeVector(sourceAt, nId);
sourceAt.delete();
} else {
Module.View.removeVector(this.m_object, nId);
}
}
/**
* Get the marker with the id
* @param {number} nId - marker id
* @returns {gem.d3Scene.MarkerRef} - marker reference
*/
getMarkerAt(nId) {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
let item = Module.View.getVectorAt(sourceAt, nId);
let result = Module.VectorItem.isNull(item) ? undefined : new gem.d3Scene.MarkerRef(item);
sourceAt.delete();
return result;
} else {
let item = Module.View.getVectorAt(this.m_object, nId);
return Module.VectorItem.isNull(item) ? undefined : new gem.d3Scene.MarkerRef(item);
}
}
/**
* Returns MarkerCollection type
* @returns {gem.d3Scene.EMarkerType}
*/
getType() {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
let result = sourceAt.getType();
sourceAt.delete();
return result;
} else {
return this.m_object.getType();
}
}
/**
* Get the name of the MarkerCollection
* @returns {string}
*/
getName() {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
let result = sourceAt.getName();
sourceAt.delete();
return result;
} else {
return this.m_object.getName();
}
}
/**
* Get Bounding Box (WGS coordinates) of the MarkerCollection
* @returns {gem.core.BoundingBox}
*/
getArea() {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
let result = sourceAt.getArea();
sourceAt.delete();
return result;
} else {
return this.m_object.getArea();
}
}
/**
* Get size
* @returns {number}
*/
size() {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
let result = sourceAt.size();
sourceAt.delete();
return result;
} else {
return this.m_object.size();
}
}
/**
* Clear MarkerCollection
*/
clear() {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
sourceAt.clear();
sourceAt.delete();
} else {
this.m_object.clear();
}
}
/**
* Gets the group head marker for the given marker id
* @param {string} nId - marker id
* @returns {gem.d3Scene.MarkerRef} - If group head info is not available the function will return a reference to the queried marker
*/
getGroupHeadItem(nId) {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
let result = new gem.d3Scene.MarkerRef(sourceAt.getGroupHeadItem(nId));
sourceAt.delete();
return result;
} else {
return new gem.d3Scene.MarkerRef(this.m_object.getGroupHeadItem(nId));
}
}
getGroupItemsVector(nId) {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
let result = sourceAt.getGroupItemsVector(nId);
sourceAt.delete();
return result;
} else {
return this.m_object.getGroupItemsVector(nId);
}
}
getRawPointer() {
if (this.m_object === null)
return Module.View.getSourceAt(this.mapView, this.nId);
else
return this.m_object;
}
}
/**MarkerCollectionRef class
* @class gem.d3Scene.MarkerCollectionRef
* @memberof gem.d3Scene
*/
gem.d3Scene.MarkerCollectionRef = class source extends Em_Object {
constructor(nId, mapView) {
if (mapView === undefined)
super(nId);
else {
super(null);
this.nId = nId;
this.mapView = mapView;
}
}
setNid(nId) {
this.nId = nId;
}
/**
* Create a marker with the specifed id
* @param {number} markerId - marker id
* @param {gem.core.Coordinates} coordinates - coordinates of the marker
* @param {number} radius - radius of the marker
* @returns {gem.d3Scene.Marker} - Created marker
*/
createMarker(markerId, coordinates, radius) {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
let marker = new Module.Marker(Module.View.createVector(sourceAt, markerId, coordinates === undefined ? { latitude: 0.0, longitude: 0.0, altitude: 0.0, bearing: 0.0 } : coordinates, radius === undefined ? -1.0 : radius));
let result = new gem.d3Scene.Marker(marker);
sourceAt.delete();
return result;
} else
return new gem.d3Scene.Marker(new Module.Marker(Module.View.createVector(this.m_object, markerId, coordinates === undefined ? { latitude: 0.0, longitude: 0.0, altitude: 0.0, bearing: 0.0 } : coordinates, radius === undefined ? -1.0 : radius)));
}
/**
* Remove the marker with the id
* @param {number} nId - marker id
*/
removeMarker(nId) {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
Module.View.removeVector(sourceAt, nId);
sourceAt.delete();
} else {
Module.View.removeVector(this.m_object, nId);
}
}
/**
* Get the marker with the id
* @param {number} nId - marker id
* @returns {gem.d3Scene.MarkerRef} - marker reference
*/
getMarkerAt(nId) {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
let item = Module.View.getVectorAt(sourceAt, nId);
let result = Module.VectorItem.isNull(item) ? undefined : new gem.d3Scene.MarkerRef(item);
sourceAt.delete();
return result;
} else {
let item = Module.View.getVectorAt(this.m_object, nId);
return Module.VectorItem.isNull(item) ? undefined : new gem.d3Scene.MarkerRef(item);
}
}
/**
* Returns MarkerCollection type
* @returns {gem.d3Scene.EMarkerType}
*/
getType() {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
let result = Module.View.getSourceType(sourceAt);
sourceAt.delete();
return result;
} else {
return Module.View.getSourceType(this.m_object);
}
}
/**
* Get the name of the MarkerCollection
* @returns {string}
*/
getName() {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
let result = Module.View.getSourceName(sourceAt);
sourceAt.delete();
return result;
} else {
return Module.View.getSourceName(this.m_object);
}
}
/**
* Get Bounding Box (WGS coordinates) of the MarkerCollection
* @returns {gem.core.BoundingBox}
*/
getArea() {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
let result = Module.View.getSourceArea(sourceAt);
sourceAt.delete();
return result;
} else {
return Module.View.getSourceArea(this.m_object);
}
}
/**
* Get size
* @returns {number}
*/
size() {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
let result = Module.View.getSourceSize(sourceAt);
sourceAt.delete();
return result;
} else {
return Module.View.getSourceSize(this.m_object);
}
}
/**
* Clear MarkerCollection
*/
clear() {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
Module.View.clearSource(sourceAt);
sourceAt.delete();
} else {
Module.View.clearSource(this.m_object);
}
}
/**
* Gets the group head marker for the given marker id
* @param {string} nId - marker id
* @returns {gem.d3Scene.MarkerRef} - If group head info is not available the function will return a reference to the queried marker
*/
getGroupHeadItem(nId) {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
let result = new gem.d3Scene.MarkerRef(Module.View.getGroupHeadItem(sourceAt, nId));
sourceAt.delete();
return result;
} else {
return new gem.d3Scene.MarkerRef(Module.View.getGroupHeadItem(this.m_object, nId));
}
}
getGroupItemsVector(nId) {
if (this.m_object === null) {
let sourceAt = Module.View.getSourceAt(this.mapView, this.nId);
let result = Module.View.getGroupItemsVector(sourceAt, nId);
sourceAt.delete();
return result;
} else {
return Module.View.getGroupItemsVector(this.m_object, nId);
}
}
getRawPointer() {
if (this.m_object === null)
return Module.View.getSourceAt(this.mapView, this.nId);
else
return this.m_object;
}
}
/**MarkerCollectionRefList class
* @class gem.d3Scene.MarkerCollectionRefList
* @augments Em_Vector
* @memberof gem.d3Scene
*/
gem.d3Scene.MarkerCollectionRefList = class MarkerCollectionRefList extends Em_Vector {
constructor() {
super(new Module.VectorDataSourceRefList());
}
/**
* Get .MarkerCollection at specified position in the list
* @param {number} nId
* @returns {gem.d3Scene.MarkerCollectionRef}
*/
get(nId) {
let retVal = new gem.d3Scene.MarkerCollection(this.m_object.get(nId));
retVal.setNid(nId);
return retVal;
}
}
/**
* @class gem.core.LandmarkCategoryList
* @augments Em_Vector
* @memberof gem
*/
gem.core.LandmarkCategoryList = class landmarkcategorylist extends Em_Vector {
constructor(object) {
if (object === undefined)
super(new Module.vector$LandmarkCategory$());
else
super(object);
}
/**
* Get Landmark at specified position in list
* @param {number} nId - position in list
* @returns {gem.core.LandmarkCategory}
*/
get(nId) {
return new gem.core.LandmarkCategory(this.m_object.get(nId));
}
/**
* Add a landmark to the back of the list
* @param {gem.core.LandmarkCategory} landmark
*/
push_back(landmark) {
this.m_object.push_back(landmark.getRawPointer());
}
}
/**
* @class gem.core.LandmarkCategory
* @augments Em_Object
* @memberof gem
*/
gem.core.LandmarkCategory = class landmarkcategory extends Em_Object {
constructor(object) {
super(object);
}
/** Get Id of the landmark category.
* @returns {number}
*/
getId() {
return this.m_object.getId();
}
/** Get Name
* @returns {string}
*/
getName() {
return Module.LandmarkCategory.getNameAsString(this.m_object);
}
/**
* Get image for the landmark category
* @param {gem.core.BitmapContainer} bitmapContainer - output bitmap
*/
getImage(bitmapContainer) {
Module.LandmarkCategory.getImageLandmarkCategory(this.m_object, bitmapContainer.getRawPointer());
}
}
/**
* @class gem.core.WikipediaContainer
* @augments Em_Object
*/
gem.core.WikipediaContainer = class Wikipediacontainer extends Em_Object {
/**
* Get Wikipedia page title
* @returns {string}
*/
getWikipediaPageTitle() {
return this.m_object.getWikipediaPageTitle();
}
/**
* Get Wikipedia page description
* @returns {string}
*/
getWikiPageDescription() {
return this.m_object.getWikiPageDescription();
}
/**
* Get wikipedia page language
* @returns {string}
*/
getWikiPageLanguage() {
return this.m_object.getWikiPageLanguage();
}
/** Get Wikipedia images url list
* @returns {vector<string>}
*/
getWikiImagesUrl() {
return this.m_object.getWikiImagesUrl();
}
/** Get Wikipedia images description list
* @returns {vector<string>}
*/
getWikiImagesDescription() {
return this.m_object.getWikiImagesDescription();
}
/** Get Wikipedia image titles list
* @returns {vector<string>}
*/
getWikiImagesTitles() {
return this.m_object.getWikiImagesTitles();
}
/**Get the Wikipedia page URL
* @returns {string}
*/
getWikipediaURL() {
return this.m_object.getWikipediaURL();
}
}
/**
* @class gem.core.StoreLocationListenerContainer
*
*/
gem.core.StoreLocationListenerContainer = class StoreLocationListenerContainer {
constructor(storeItem) {
this.m_storeItem = storeItem;
}
/**
*
* @param {*} cb
*/
registerCallback(cb) {
this.m_cb = cb;
}
/**
*
* @param {number} reason
*/
callback(reason) {
if (this.mCanCallCalback) {
this.m_cb(this.m_storeItem, reason, this.htmlElement);
}
}
}
gem.d3Scene.Path = class gemPath extends Em_Object {
constructor(inputText, format) {
super(new Module.Path(inputText, format));
}
getArea() {
return this.m_object.getArea();
}
getCoordinates() {
return this.m_object.getCoordinates();
}
}
/**
* Used for creating a custom rendering for GeoJson points added to a source
* @class gem.d3Scene.ExternalRenderer
* @memberof gem.d3Scene
*/
gem.d3Scene.ExternalRenderer = class ExternalRenderer {
/**
*
* @param {string} imgSource - path to the image source used for icons.
* @param {string} sname - name of the external Renderer.
* @param {gem.d3Scene.MapView} view - View in which we are using the external renderer.
* @param {string} parentDiv - the div in which to add the created html elements.
* @param {string} [cssClass] - Custom css class
* @param {object} [options] - marker render options
* @param {string} [options.markerCssClass] - marker style class
* @param {callbackMarker} [options.markerFunction]
* @param {number} [options.markerWidth = 20]
* @param {number} [options.markerHeight = 20]
* @param {number} [options.markerHoverWidth = 25]
* @param {number} [options.markerHoverHeight = 25]
* @param {string} [options.markerPos='center'] - where to place the marker relative to the item coordinate, options are center, bottom-right, bottom-center, bottom-left, top-right, top-center, top-left, right-center, left-center
* @param {gem.control.markerGroupStyleType} [options.markerGroupStyle = gem.control.MarkersGroupStyleType.default] - set different marker groups style
* @param {callbackMarkerGroup} [options.markerGroupFunction] - fully customize marker groups
*/
constructor(imgSource, sname, view, parentDiv, cssClass, options) {
let defaultMarkerOptions = {
markerWidth: 20,
markerHeight: 20,
markerHoverWidth: 25,
markerHoverHeight: 25,
markerPos: 'center',
markerFunction: undefined /*function(jsonItemProperties){}*/,
markerGroupStyle: gem.control.MarkersGroupStyleType.default,
markerGroupFunction: undefined /*function(groupsize){}*/
};
this.options = Object.assign({}, defaultMarkerOptions, options);
this.itemImgSource = imgSource;
this.name = sname;
this.conMouseOut = undefined;
this.conMouseOver = undefined;
this.conMouseClick = undefined;
this.view = view;
this.cssClass = (cssClass && typeof cssClass === 'string' && cssClass.length > 0) ? cssClass : 'gem-marker';
this.vectorItems = new Map();
this.vectorItemsCoords = new Map();
this.vectorItemsQuery = new Map();
this.sourceIsPending = false;
if (parentDiv !== undefined)
this.parentDiv = document.getElementById(parentDiv);
}
clear() {
this.destroyHasBeenCalled = true;
for (let [key, value] of this.vectorItems) {
value.delete();
if (this.vectorItemsQuery !== undefined && this.vectorItemsQuery.has(key)) {
let it = this.vectorItemsQuery.get(key);
if (it && it.mProgressListener)
it.mProgressListener.delete();
this.vectorItemsQuery.delete(key);
}
let remitem = document.getElementById(key);
if (remitem) {
if (this.parentDiv) {
this.parentDiv.removeChild(remitem);
remitem.remove();
} else {
document.body.removeChild(remitem);
}
}
}
for (let [key, value] of this.vectorItemsCoords) {
let remitem = document.getElementById(key);
if (remitem) {
if (this.parentDiv) {
this.parentDiv.removeChild(remitem);
remitem.remove();
} else {
document.body.removeChild(remitem);
}
}
}
this.vectorItems.clear();
}
callback(id, item, status, groupsize, xy) {
if (this.destroyHasBeenCalled)
return;
if (xy !== undefined) {
xy.x = this.options.markerWidth;
xy.y = this.options.markerHeight;
}
if (item === undefined) {
if (this.itemRemovedCallback)
this.itemRemovedCallback(this.name + id, item, id);
if (this.vectorItems.has(this.name + id)) {
let removeVector = this.vectorItems.get(this.name + id);
removeVector.delete();
this.vectorItems.delete(this.name + id);
}
if (this.vectorItemsQuery !== undefined && this.vectorItemsQuery.has(this.name + id)) {
let it = this.vectorItemsQuery.get(this.name + id);
if (it && it.mProgressListener)
it.mProgressListener.delete();
this.vectorItemsQuery.delete(this.name + id);
}
let remitem = document.getElementById(this.name + id);
if (remitem) {
if (this.parentDiv) {
this.parentDiv.removeChild(remitem);
remitem.remove();
} else {
document.body.removeChild(remitem);
}
}
if (this.vectorItemsCoords && this.vectorItemsCoords.has(this.name + id)) {
this.vectorItemsCoords.delete(this.name + id);
}
} else {
let convItem = item;
if(item instanceof Module.OverlayItem)
{
convItem = new gem.d3Scene.OverlayItem(item);
}
if (status === 0) {
switch (this.options.markerGroupStyle) {
case gem.control.MarkersGroupStyleType.circle:
this.createCircleMarkerDiv(id, convItem, groupsize);
break;
case gem.control.MarkersGroupStyleType.custom:
this.createCustomMarkerDiv(id, convItem, groupsize);
break;
default:
this.createDivForButton(id, convItem, groupsize);
}
} else { // update
let remitem = document.getElementById(this.name + id);
if (!remitem)
return;
let coordsPoint = this.vectorItemsCoords.get(this.name + id);
if (coordsPoint) {
let screenCoords = this.view.transformWgsToScreen(coordsPoint);
let pos = this.getMarkerPos(this.options.markerPos, screenCoords, this.options.markerWidth, this.options.markerHeight);
remitem.style.transform = "translate3d(" + pos.dx + "px," + pos.dy + "px,0px)";
} else { // remove invalid item
if (this.parentDiv) {
this.parentDiv.removeChild(remitem);
remitem.remove();
} else {
document.body.removeChild(remitem);
}
}
}
}
}
onClickEvent(event) {
event.preventDefault();
let item = event.currentTarget;
let vectorItem = this.vectorItems.get(item.id);
if (vectorItem === undefined) {
this.clickEventRequestedForId = item.id;
} else {
let jsonBuffer = JSON.parse(vectorItem.getInfo());
let coords = vectorItem.getCoordinatesPartAt(0);
let coordsPoint = coords.get(0);
if (this.conMouseClick !== undefined) {
this.conMouseClick(item, jsonBuffer['properties'], coordsPoint);
}
this.selectedItem = {
id: item.id,
info: jsonBuffer,
coordinates: coordsPoint
};
if (this.conItemSelected)
this.conItemSelected(item);
}
}
onMouseOverEvent(event) {
let item = event.currentTarget;
item.style.width = this.options.markerHoverWidth + "px";
item.style.height = this.options.markerHoverHeight + "px";
item.style.zIndex = '4';
if (this.conMouseOver !== undefined) {
let vectorItem = this.vectorItems.get(item.id);
let info;
let storeItem;
if (this.mStoreList !== undefined) {
let theid = item.id;
theid = theid.replace(this.name, "");
storeItem = this.mStoreList[parseInt(theid)];
if (storeItem)
info = storeItem.getInfo();
} else
info = vectorItem.getInfo();
if (info && info.length) {
let jsonBuffer = JSON.parse(info);
let coords = vectorItem.getCoordinatesPartAt(0);
let coordsPoint = coords.get(0);
this.conMouseOver(item, jsonBuffer['properties'], coordsPoint);
} else {
if (this.mStoreList !== undefined && storeItem !== undefined) {
if (!this.vectorItemsQuery.has(item.id)) {
let itemQuery = new gem.core.StoreLocationListenerContainer(storeItem);
this.vectorItemsQuery.set(item.id, itemQuery);
let cb = (vectorIt, reason, itemL) => {
let jsonBuffer = JSON.parse(vectorIt.getInfo());
let coordsPoint = vectorIt.getCoordinatesAt(0);
this.conMouseOver(itemL, jsonBuffer['properties'], coordsPoint);
};
itemQuery.registerCallback(cb);
itemQuery.mCanCallCalback = true;
itemQuery.htmlElement = item;
itemQuery.mProgressListener = storeItem.queryInfo(this.view, this.mStoreId, itemQuery.callback.bind(itemQuery));
}
}
//vectorItem.queryInfo
}
}
}
onMouseOutEvent(event) {
let item = event.currentTarget;
item.style.width = this.options.markerWidth + "px";
item.style.height = this.options.markerHeight + "px";
item.style.zIndex = 'auto';
if (this.conMouseOut !== undefined) {
let itemQuery = this.vectorItemsQuery.get(item.id);
if (itemQuery !== undefined)
itemQuery.mCanCallCalback = false;
this.conMouseOut(item);
}
}
/**
*@callback callbackMouse
* @param {Element} item - html element of called evend
* @param {object} jsonData - json data of the properties field
* @param {gem.core.Coordinates} coordinates - WGS Coordinates of the item.
*/
/**
* Register mouse out callback (previously was in over state)
* @param {callbackMouse} callback
*/
registerMouseOutCallback(callback) {
this.conMouseOut = callback.bind(this);
}
/** Register Mouse click event callback.
* @param {callbackMouse} callback
*/
registerMouseClickCallback(callback) {
this.conMouseClick = callback.bind(this);
}
/**
* @callback callbackSelected
* @param {Element} - html element of selected item
*/
/**
* Register item selected callback
* @param {callbackSelected} callback
*/
registerItemSelectedCallback(callback) {
this.conItemSelected = callback.bind(this);
}
/**
* Register mouse over callback.
* @param {callbackMouse} callback
*/
registerMouseOverCallback(callback) {
this.conMouseOver = callback.bind(this);
}
registerItemAddedCallback(callback) {
this.itemAddedCallback = callback;
}
registerItemRemovedCallback(callback) {
this.itemRemovedCallback = callback;
}
getMarkerPos(option, screenCoords, width, height) {
let pos = {
dx: undefined,
dy: undefined
};
switch (option) {
case 'bottom-right':
pos.dx = screenCoords.x;
pos.dy = screenCoords.y;
return pos;
case 'bottom-center':
pos.dx = screenCoords.x - width / 2;
pos.dy = screenCoords.y;
return pos;
case 'bottom-left':
pos.dx = screenCoords.x - width;
pos.dy = screenCoords.y;
return pos;
case 'top-right':
pos.dx = screenCoords.x;
pos.dy = screenCoords.y - height;
return pos;
case 'top-center':
pos.dx = screenCoords.x - width / 2;
pos.dy = screenCoords.y - height;
return pos;
case 'top-left':
pos.dx = screenCoords.x - width;
pos.dy = screenCoords.y - height;
return pos;
case 'right-center':
pos.dx = screenCoords.x;
pos.dy = screenCoords.y - height / 2;
return pos;
case 'left-center':
pos.dx = screenCoords.x - width;
pos.dy = screenCoords.y - height / 2;
return pos;
case 'center':
default:
pos.dx = screenCoords.x - (width / 2);
pos.dy = screenCoords.y - (height / 2);
return pos;
}
}
getIconLocation(item, isFunction) {
isFunction = false;
if (typeof this.itemImgSource === 'function') {
isFunction = true;
return this.itemImgSource(item);
} else
return this.itemImgSource;
}
createMarkerElement(btnDiv, item, itemId, groupsize, screenCoords) {
if (groupsize < 2 && typeof this.itemImgSource === 'function') {
let pt = this.itemImgSource(item);
btnDiv.classList.add(pt);
} else
btnDiv.classList.add(this.cssClass);
btnDiv.style.top = "0px";
btnDiv.style.left = "0px";
let pos = this.getMarkerPos(this.options.markerPos, screenCoords, this.options.markerWidth, this.options.markerHeight);
btnDiv.style.transform = "translate3d(" + pos.dx + "px," + pos.dy + "px,0px)";
btnDiv.id = this.name + itemId;
if (this.parentDiv !== undefined) {
this.parentDiv.appendChild(btnDiv)
} else
document.body.appendChild(btnDiv);
}
createGroupSizeElement(btnDiv, groupsize) {
let grpdot = btnDiv.appendChild(document.createElement('button'));
let str = '' + groupsize;
grpdot.style.width = 10 + 6 * (str.length - 1) + "px";
grpdot.style.maxWidth = grpdot.style.width;
grpdot.textContent = groupsize;
btnDiv.addEventListener("click", this.onClickEvent.bind(this));
btnDiv.style.pointerEvents = 'none';
}
async createButton(item, itemId, groupsize, screenCoords, coordsPoint) {
let btnDiv = document.createElement("div");
if (this.cssClass !== undefined) {
this.createMarkerElement(btnDiv, item, itemId, groupsize, screenCoords);
}
if (groupsize > 1) {
this.createGroupSizeElement(btnDiv, groupsize);
if (this.itemAddedCallback)
this.itemAddedCallback(this.name, item, itemId, true);
} else {
if (this.options.markerFunction && typeof this.options.markerFunction === 'function') {
let itemStringInfo = item.getInfo();
let customMarkerDiv = this.options.markerFunction(itemStringInfo);
if (customMarkerDiv)
btnDiv.appendChild(customMarkerDiv);
}
this.dispatchMarkerDivEvents(btnDiv);
this.vectorItems.set(this.name + itemId,(item instanceof Module.Marker)?new Module.Marker(item): item);
if (this.clickEventRequestedForId && (this.clickEventRequestedForId === (this.name + itemId))) {
this.clickEventRequestedForId = undefined;
btnDiv.click();
}
if (this.itemAddedCallback)
this.itemAddedCallback(this.name, item, itemId, false);
}
this.vectorItemsCoords.set(this.name + itemId, coordsPoint);
}
createDivForButton(itemId, item, groupsize) {
let coords = item.getCoordinatesPartAt(0);
let coordsPoint = coords.get(0);
let screenCoords = this.view.transformWgsToScreen(coordsPoint);
this.createButton(item, itemId, groupsize, screenCoords, coordsPoint).then();
}
async createCircleDiv(item, itemId, groupsize, screenCoords, coordsPoint) {
let circleDiv = document.createElement('div');
if (this.cssClass && this.cssClass.length) {
if (groupsize < 2 && typeof this.itemImgSource === 'function') {
let classImg = this.itemImgSource(item);
circleDiv.classList.add(classImg);
} else
circleDiv.classList.add(this.cssClass);
} else {
circleDiv.classList.add('gem-marker');
}
circleDiv.style.top = '0px';
circleDiv.style.left = '0px';
circleDiv.style.willChange = 'transform';
let pos = this.getMarkerPos(this.options.markerPos, screenCoords, this.options.markerWidth, this.options.markerHeight);
circleDiv.style.transform = "translate3d(" + pos.dx + "px," + pos.dy + "px,0px)";
circleDiv.id = this.name + itemId;
if (this.parentDiv !== undefined) {
this.parentDiv.appendChild(circleDiv);
} else
document.body.appendChild(circleDiv);
if (groupsize > 1) {
circleDiv.classList = '';
circleDiv.classList.add('gem-marker-group');
// large group
if (groupsize > 100) {
circleDiv.classList.add('large');
}
// medium group
else if (groupsize > 50) {
circleDiv.classList.add('medium');
}
// small group
else {
circleDiv.classList.add('small');
}
let textGroupSize = circleDiv.appendChild(document.createElement('span'));
textGroupSize.textContent = groupsize;
circleDiv.addEventListener("click", this.onClickEvent.bind(this));
circleDiv.style.pointerEvents = 'none';
if (this.itemAddedCallback)
this.itemAddedCallback(this.name, item, itemId, true);
} else {
if (this.options.markerFunction && typeof this.options.markerFunction === 'function') {
let customMarkerDiv = this.options.markerFunction(item.getInfo());
if (customMarkerDiv)
circleDiv.appendChild(customMarkerDiv);
}
this.dispatchMarkerDivEvents(circleDiv);
this.vectorItems.set(this.name + itemId,(item instanceof Module.Marker)?new Module.Marker(item):new gem.d3Scene.OverlayItem(new Module.OverlayItem(item)));
if (this.clickEventRequestedForId && (this.clickEventRequestedForId === (this.name + itemId))) {
this.clickEventRequestedForId = undefined;
circleDiv.click();
}
if (this.itemAddedCallback)
this.itemAddedCallback(this.name, item, itemId, false);
}
this.vectorItemsCoords.set(this.name + itemId, coordsPoint);
}
createCircleMarkerDiv(itemId, item, groupsize) {
let coords = item.getCoordinatesPartAt(0);
let coordsPoint = coords.get(0);
let screenCoords = this.view.transformWgsToScreen(coordsPoint);
this.createCircleDiv(item, itemId, groupsize, screenCoords, coordsPoint).then();
}
async createCustomDiv(item, itemId, groupsize, screenCoords, coordsPoint) {
let customDiv;
if (groupsize < 2) {
customDiv = document.createElement('div');
if (this.cssClass && this.cssClass.length) {
if (typeof this.itemImgSource === 'function') {
let classImg = this.itemImgSource(item);
customDiv.classList.add(classImg);
} else
customDiv.classList.add(this.cssClass);
} else {
customDiv.classList.add('gem-marker');
}
if (this.options.markerFunction) {
let customMarkerDiv = this.options.markerFunction(item.getInfo());
if (customMarkerDiv)
customDiv.appendChild(customMarkerDiv);
}
this.dispatchMarkerDivEvents(customDiv);
this.vectorItems.set(this.name + itemId,(item instanceof Module.Marker)?new Module.Marker(item): new gem.d3Scene.OverlayItem(new Module.OverlayItem(item)));
if (this.clickEventRequestedForId && (this.clickEventRequestedForId === (this.name + itemId))) {
this.clickEventRequestedForId = undefined;
customDiv.click();
}
if (this.itemAddedCallback)
this.itemAddedCallback(this.name, item, itemId, false);
} else {
if (this.options.markerGroupFunction && typeof this.options.markerGroupFunction === 'function')
customDiv = this.options.markerGroupFunction(groupsize);
if (customDiv) {
customDiv.addEventListener("click", this.onClickEvent.bind(this));
customDiv.style.pointerEvents = 'none';
if (this.itemAddedCallback)
this.itemAddedCallback(this.name, item, itemId, true);
}
}
if (customDiv) {
customDiv.style.top = '0px';
customDiv.style.left = '0px';
customDiv.style.position = 'absolute';
customDiv.style.willChange = 'transform';
let pos = this.getMarkerPos(this.options.markerPos, screenCoords, this.options.markerWidth, this.options.markerHeight);
customDiv.style.transform = "translate3d(" + pos.dx + "px," + pos.dy + "px,0px)";
customDiv.id = this.name + itemId;
if (this.parentDiv !== undefined) {
this.parentDiv.appendChild(customDiv);
} else
document.body.appendChild(customDiv);
}
this.vectorItemsCoords.set(this.name + itemId, coordsPoint);
}
createCustomMarkerDiv(itemId, item, groupsize) {
let coords = item.getCoordinatesPartAt(0);
let coordsPoint = coords.get(0);
let screenCoords = this.view.transformWgsToScreen(coordsPoint);
this.createCustomDiv(item, itemId, groupsize, screenCoords, coordsPoint).then();
}
dispatchMarkerDivEvents(markerDiv) {
markerDiv.addEventListener("click", this.onClickEvent.bind(this));
markerDiv.addEventListener("mouseover", this.onMouseOverEvent.bind(this));
markerDiv.addEventListener("mouseout", this.onMouseOutEvent.bind(this));
markerDiv.addEventListener("wheel", function (e) {
markerDiv.addEventListener("wheel", function (event) {
if (Module.canvas)
Module.canvas.dispatchEvent(new event.constructor(event.type, event));
event.preventDefault();
event.stopPropagation();
});
});
/*markerDiv.addEventListener("mousedown", function (e) {
markerDiv.addEventListener("mousedown", function (event) {
event.preventDefault();
event.stopPropagation();
if (Module.canvas)
Module.canvas.dispatchEvent(new event.constructor(event.type, event));
});
});
markerDiv.addEventListener("mouseup", function (e) {
markerDiv.addEventListener("mouseup", function (event) {
event.preventDefault();
event.stopPropagation();
if (Module.canvas)
Module.canvas.dispatchEvent(new event.constructor(event.type, event));
});
});*/
markerDiv.addEventListener("focusout", function (event) {
this.onMouseOutEvent.bind(this);
});
}
}
/**
*@class gem.d3Scene.ExternalQueryListener
*@memberof gem.d3Scene
*@augments Em_Object
*/
gem.d3Scene.ExternalQueryListener = class ExternalQueryListener extends Em_Object {
constructor(callback) {
super(new Module.ExternalQueryListener(callback));
}
}
/**
*@class gem.core.StoreLocationList
*@memberof gem.core
* @augments Em_Object
*/
gem.core.StoreLocationList = class StoreLocationList extends Em_Object {
constructor() {
super(new Module.StoreLocationResult());
}
/**
* @returns {number} - the size of List
*/
size() {
return Module.StoreLocationResult.getSize(this.m_object);
}
/**
* @returns {number} - Returns total number of items (including group count)
*/
getTotalCount() {
return Module.StoreLocationResult.getCount(this.m_object);
}
/**
*
* @param {number} nId
* @returns {gem.core.StoreLocation} - Store location at given id position.
*/
get(nId) {
return new gem.core.StoreLocation(Module.StoreLocationResult.getItem(this.m_object, nId));
}
getMarkerAt(nId) {
return this.get(nId);
}
push_back(storeLocation) {
Module.StoreLocationResult.push_back(this.m_object, storeLocation.getRawPointer());
}
queryInfo(pView, storeId, cb) {
return Module.StoreLocation.queryStoreLocation(pView.getRawPointer(), storeId, this.m_object, cb);
}
}
/**
*@class gem.core.StoreLocation
*@memberof gem.core
* @augments Em_Object
*/
gem.core.StoreLocation = class StoreLocation extends Em_Object {
/**
*@returns {string} - Json buffer that contains informations about Store Location
*/
getInfo() {
return Module.StoreLocation.getInfo(this.m_object);
}
/**
*
* @param {number} nId
* @returns {gem.core.Coordinates} - Coordinates for Location Store
*/
getCoordinatesAt(nId) {
return Module.StoreLocation.getCoordinatesAt(this.m_object, nId);
}
/**
* @returns {number} - Store Location id
*/
getId() {
return this.mId !== undefined ? this.mId : this.mId = Module.StoreLocation.getStoreLocationId(this.m_object);
}
/**
*
* @param {gem.d3Scene.MapView} pView
* @param {number} storeId
* @param {*} cb
* @returns {object} - Progress Listener
*/
queryInfo(pView, storeId, cb) {
if (this.resultInfo === undefined) {
this.resultInfo = new Module.StoreLocationResult();
Module.StoreLocationResult.push_back(this.resultInfo, this.m_object);
}
return Module.StoreLocation.queryStoreLocation(pView.getRawPointer(), storeId, this.resultInfo, cb);
}
/**
* Delete Store Location (C++ delete function)
*/
delete() {
this.m_object.delete();
if (this.resultInfo) {
this.resultInfo.delete();
}
}
}
gem.d3Scene.ExternalRendererMarkers = class externalRendererMarkers extends gem.d3Scene.ExternalRenderer {
callback(id, item, status, groupsize, xy) {
if (xy !== undefined) {
xy.x = this.options.markerWidth;
xy.y = this.options.markerHeight;
}
if (item === undefined) {
let remitem = document.getElementById(this.name + id);
if (this.itemRemovedCallback)
this.itemRemovedCallback(this.name + id, item, id);
if (this.vectorItems.has(this.name + id)) {
let toRemove = this.vectorItems.get(this.name + id);
//toRemove.delete();
this.vectorItems.delete(this.name + id);
}
if (this.parentDiv) {
let parDiv = this.parentDiv;
parDiv.removeChild(remitem);
remitem.remove();
} else
document.body.removeChild(remitem);
} else {
let convItem = item;
if(item instanceof Module.OverlayItem)
{
convItem = new gem.d3Scene.OverlayItem(new Module.OverlayItem(item));
}
if (status === 0) {
switch (this.options.markerGroupStyle) {
case gem.control.MarkersGroupStyleType.circle:
this.createCircleMarkerDiv(id, convItem, groupsize);
break;
case gem.control.MarkersGroupStyleType.custom:
this.createCustomMarkerDiv(id, convItem, groupsize);
break;
default:
this.createDivForButton(id, convItem, groupsize);
}
} else {
let remitem = document.getElementById(this.name + id);
let coordsPoint = convItem.getCoordinates(0);
let screenCoords = this.view.transformWgsToScreen(coordsPoint);
let pos = this.getMarkerPos(this.options.markerPos, screenCoords, this.options.markerWidth, this.options.markerHeight);
remitem.style.transform = "translate(" + pos.dx + "px," + pos.dy + "px)";
}
}
}
createDivForButton(itemId, item, groupsize) {
let coordsPoint = item.getCoordinates();
let screenCoords = this.view.transformWgsToScreen(coordsPoint);
super.createButton(item, itemId, groupsize, screenCoords, coordsPoint).then();
}
createCircleMarkerDiv(itemId, item, groupsize) {
let coordsPoint = item.getCoordinates();
let screenCoords = this.view.transformWgsToScreen(coordsPoint);
super.createCircleDiv(item, itemId, groupsize, screenCoords, coordsPoint).then();
}
createCustomMarkerDiv(itemId, item, groupsize) {
let coordsPoint = item.getCoordinates();
let screenCoords = this.view.transformWgsToScreen(coordsPoint);
super.createCustomDiv(item, itemId, groupsize, screenCoords, coordsPoint).then();
}
onClickEvent(event) {
let item = event.currentTarget;
let vectorItem = this.vectorItems.get(item.id);
if (vectorItem === undefined) {
this.clickEventRequestedForId = item.id;
} else {
let vectorItem = this.vectorItems.get(item.id);
let jsonBuffer = JSON.parse(vectorItem.getInfo());
let coordsPoint = vectorItem.getCoordinates();
this.selectedItem = {
id: item.id,
info: jsonBuffer,
coordinates: coordsPoint
};
if (this.conItemSelected)
this.conItemSelected(item);
if (this.conMouseClick !== undefined) {
this.conMouseClick(item, jsonBuffer['properties'], coordsPoint);
}
}
}
onMouseOverEvent(event) {
let item = event.currentTarget;
item.style.width = this.options.markerHoverWidth + "px";
item.style.height = this.options.markerHoverHeight + "px";
item.style.zIndex = '4';
if (this.conMouseOver !== undefined) {
let vectorItem = this.vectorItems.get(item.id);
let info;
info = vectorItem.getPreviewData();
if (info.length) {
try {
let jsonBuffer = JSON.parse(info);
var coordsPoint = vectorItem.getCoordinates();
if (jsonBuffer['properties'])
this.conMouseOver(item, jsonBuffer['properties'], coordsPoint);
else if (jsonBuffer['parameters']) {
let jsonProps = {};
for (const param of jsonBuffer['parameters'].keyvals) {
jsonProps[param.key] = param.value;
}
this.conMouseOver(item, jsonProps, coordsPoint);
}
} catch (err) { }
}
//vectorItem.queryInfo
}
}
onMouseOutEvent(event) {
let item = event.currentTarget;
item.style.width = this.options.markerWidth + "px";
item.style.height = this.options.markerHeight + "px";
item.style.zIndex = 'auto';
if (this.conMouseOut !== undefined) {
this.conMouseOut(item);
}
}
}
/**@class gem.d3Scene.Screen
* @description Screen
* @memberof gem.d3Scene
*@hideconstructor
*/
gem.d3Scene.Screen = class Screen extends Em_Object {
/**
* returns the default view
* @returns {gem.d3Scene.MapView} default view
*/
getDefaultMapView() {
return new gem.d3Scene.MapView(Module.getDefaultView());
}
/**
* Toggle Full Screen
*/
toggleFullScreen() {
Module.toggleFullScreen();
}
/**
* Get Screen Viewport
* @returns {gem.core.RectangleInteger}
*/
getViewport() {
return this.m_object.getViewport();
}
/**
* Create a view in screen at the specified position and size
* @param {gem.core.RectangleFloat} rectangular - use normalized values from screen size. Valid values 0.0 -> 1.0;
* @returns {gem.d3Scene.MapView} - created MapView
*/
createView(rectangular) {
return new gem.d3Scene.MapView(new Module.View(rectangular));
}
/**
* Resize the screen
* @param {number} width - Width in pixels
* @param {number} height - Height in pixels
*/
resize(width, height) {
Module.resizeScreen(width, height);
}
}
gem.core.GemStringList = class GemStringList extends Em_Vector {
constructor() {
super(new Module.vector$gemString$());
}
push_back(item) {
if (typeof (item) === 'string')
this.m_object.push_back(Module.createGemString(item));
else
this.m_object.push_back(item);
}
size() {
return this.m_object.size();
}
}
/**
* @class gem.core.StoreLocationLang
* @hideconstructor
*/
gem.core.StoreLocationLang = class StoreLocationLang extends Em_Object {
constructor(object) {
super(object);
this.lang = Module.View.getStoreLocationLangLang(this.m_object);
}
/**
* @returns {number}
*/
getCount() {
return Module.View.getStoreLocationLangCount(this.m_object);
}
/**
* @returns {string}
*/
getLangAsString() {
return Module.View.getStoreLocationLangString(this.m_object);
}
/**
* Get Formatted Text
* @returns {string} - formatted text
*/
getFormattedText() {
return this.getLangAsString();
}
getValue() {
return this.getLangAsString();
}
}
/**
* @class gem.core.StoreLocationLangList
* @hideconstructor
*/
gem.core.StoreLocationLangList = class StoreLocationLangList extends Em_Object {
constructor() {
super(new Module.StoreLocationConfigurationList());
}
push_back(nItem) {
Module.StoreLocationConfigurationList.push_back(this.m_object, nItem);
}
/**
*
* @param {number} nId
* @returns {gem.core.StoreLocationLang} - StoreLocation Langs
*/
get(nId) {
return new gem.core.StoreLocationLang(Module.StoreLocationConfigurationList.get(this.m_object, nId));
}
/**
*@returns {number}
*/
size() {
return Module.StoreLocationConfigurationList.size(this.m_object)
}
}
/**
*@namespace gem.control
*/
gem.control = class control {
}
gem.control.TConntrolExecuteType = Object.freeze({
NONE: 0,
STYLE: 1,
ONCONNECTED: 2
});
gem.control.TConntrolItemUpdateMode = Object.freeze({
LIST: 0,
INDIVIDUAL: 1
});
gem.control.LISTSORTMODE = Object.freeze({
DISTANCE: 0,
ALPHABETICAL: 1
});
// z-index levels for various controls
gem.control.zIndex = Object.freeze({
none: 'auto',
markerSelected: 9,
markerHover: 10
});
// External Renderer Grouped Markers Predefined Styles
/**
* @property {number} gem.control.MarkersGroupStyleType.default - default style with group size displayed in the bottom right corner of the icon
* @property {number} gem.control.MarkersGroupStyleType.circle - style the marker groups with circles with the group size displayed in the center
* @property {number} gem.control.MarkersGroupStyleType.custom - style the marker groups with custom rules
*/
gem.control.MarkersGroupStyleType = Object.freeze({
default: 0,
circle: 1,
custom: 2
});
gem.routesAndNavigation.PTRouteSegment = class PTRouteSegment extends Em_Object {
/**
* Get Name
* @returns {string}
*/
getName() {
return this.m_object.getName();
}
/**
* Get Platform Code
*@returns {string}
*/
getPlatformCode() {
return this.m_object.getPlatformCode();
}
/**
* Get Arrival Time
* @returns {Date}
*/
getArrivalTime() {
return this.m_object.getArrivalTime();
}
/**
* Get Departure Time
* @returns {Date}
*/
getDepartureTime() {
return this.m_object.getDepartureTime()
}
/**
* Get Wheelchair Support
* @returns {boolean}
*/
getHasWheelchairSupport() {
return this.m_object.getHasWheelchairSupport();
}
/**
*Get short name
@returns {string}
*/
getShortName() {
return this.m_object.getShortName();
}
/**
* Get Route URL
* @returns {string}
*/
getRouteUrl() {
return this.m_object.getRouteUrl();
}
/**
* Get Agency Name
* @returns {string}
*/
getAgencyName() {
return this.m_object.getAgencyName();
}
/**
* Get Agency Phone number
* @returns {string}
*/
getAgencyPhone() {
return this.m_object.getAgencyPhone();
}
/**
* Get Agency URL
* @returns {string}
*/
getAgencyUrl() {
return this.m_object.getAgencyUrl();
}
/**
*Get Agency Fare URL
@returns {string}
*/
getAgencyFareUrl() {
return this.m_object.getAgencyFareUrl();
}
/**
* Get Line From
* @returns {string}
*/
getLineFrom() {
return this.m_object.getLineFrom();
}
/**
*Get Line Towards
*@returns {string}
*/
getLineTowards() {
return this.m_object.getLineTowards();
}
/**
* Get Arrival Delay in seconds
* @returns {number}
*/
getArrivalDelayInSeconds() {
return this.m_object.getArrivalDelayInSeconds();
}
/**
* Get Departure Delay in seconds
* @returns {number}
*/
getDepartureDelayInSeconds() {
return this.m_object.getDepartureDelayInSeconds();
}
/**
* Get Bicycle Support
* @returns {boolean}
*/
getHasBicycleSupport() {
return this.m_object.getHasBicycleSupport();
}
/**
* Get Stay on same Transit
* @returns {boolean}
*/
getStayOnSameTransit() {
return this.m_object.getStayOnSameTransit();
}
/**
* Get Transit Type
* @returns {number}
*/
getTransitType() {
return this.m_object.getTransitType();
}
/**
*Get Realtime Status
@returns {string} - Realtime Status
*/
getRealtimeStatus() {
return this.m_object.getRealtimeStatus();
}
/**
* Get Line Block ID
* @returns {number}
*/
getLineBlockID() {
return this.m_object.getLineBlockID();
}
/**
* Get Line Color
* @returns {gem.core.ColorInfo}
*/
getLineColor() {
return this.m_object.getLineColor();
}
/**
* Get Line Text Color
* @returns {gem.core.ColorInfo}
*/
getLineTextColor() {
return this.m_object.getLineTextColor();
}
/**
* Get number of alerts for this PT information.
* @returns {number}
*/
getCountAlerts() {
return this.m_object.getCountAlerts();
}
/**
* Get alert specified by index.
* @param {number} nIndex - index of alert
* @returns {gem.core.Alert}
*/
getAlert(nIndex) {
return this.m_object.getAlert(nIndex);
}
/**
* Return true if this is significant. (worth showing information about it)
* @returns {boolean}
*/
isSignificant() {
return this.m_object.isSignificant();
}
/**
* Check if this is a station walk.
* @returns {boolean}
*/
isStationWalk() {
return this.m_object.isStationWalk();
}
}
/**
* @class gem.routesAndNavigation.RouteSegment
*/
gem.routesAndNavigation.RouteSegment = class RouteSegment extends Em_Object {
/**
* @returns {gem.routesAndNavigation.PTRouteSegment} ptRouteSegment
*/
toPTRouteSegment() {
return new gem.routesAndNavigation.PTRouteSegment(this.m_object.toPTRouteSegment());
}
isCommon() {
return this.m_object.isCommon();
}
getTimeDistance() {
return this.m_object.getTimeDistance();
}
}
gem.routesAndNavigation.RouteSegmentList = class RouteSegmentList extends Em_Vector {
get(position) {
return new gem.routesAndNavigation.RouteSegment(this.m_object.get(position));
}
}
gem.core.LandmarkStore = class LandmarkStore extends Em_Object {
constructor(name) {
super(new Module.LandmarkStore(name));
}
getName() {
return this.m_object.getName();
}
addLandmark(landmark, categoryId) {
this.m_object.addLandmark(landmark.getRawPointer(), categoryId ? categoryId : -2);
if (gem.core.App.usePersistentStorage)
gem.core.App.syncStorageLandmarks(false);
}
getLandmarks(categoryId) {
return new gem.core.LandmarkList(this.m_object.getLandmarks(categoryId ? categoryId : -2));
}
getLandmarksInArea(geographicArea, categoryId) {
return new gem.core.LandmarkList(this.m_object.getLandmarksInArea(geographicArea.getRawPointer(), categoryId ? categoryId : -2));
}
removeLandmark(landmark) {
this.m_object.removeLandmark(landmark.getLandmarkId());
if (gem.core.App.usePersistentStorage)
gem.core.App.syncStorageLandmarks(false);
}
removeAllLandmarks() {
this.m_object.removeAllLandmarks();
if (gem.core.App.usePersistentStorage)
gem.core.App.syncStorageLandmarks(false);
}
startFastUpdateMode() {
this.m_object.startFastUpdateMode();
}
stopFastUpdateMode() {
this.m_object.stopFastUpdateMode();
}
}
gem.control.BaseControl = class BaseControl {
constructor(whenToTriggerInit) {
this.mType = whenToTriggerInit;
}
initControl(parentDiv, mapView) {
}
cameraChangedCallback() {
}
preRenderCallback() {
}
getType() {
return this.mType;
}
show() {
}
hide() {
}
}
/**
* Control for drawing an area on the map canvas
* @class gem.control.DrawAreaOnMapControl
*
* @param {gem.control.CustomQueryAddedDataControl} addedDataControl
* @param {object} drawOptions - draw area control options
* @param {object} drawOptions.button - start/stop drawing button options
* @param {string} drawOptions.button.parentContainer - the parent element id where to add the draw button element
* @param {string} [drawOptions.button.activateText = 'Draw area on map'] - button text to display for starting a draw area operation
* @param {string} [drawOptions.button.deactivateText = 'Stop drawing'] - button text to display for stopping a draw area operation
* @param {string} [drawOptions.button.cssClass = 'gem-draw-button'] - set custom style rules for the start/stop draw button
* @param {object} [drawOptions.dialogPopup] - dialog popup for invalid area options
* @param {string} [drawOptions.dialogPopup.cssClass = 'gem-dialog-popup'] - set custom style rules for the dialog
* @param {string} [drawOptions.dialogPopup.textInfo = 'Please draw an area'] - text to display in the dialog
* @param {string} [drawOptions.dialogPopup.cssDismissButton = 'gem-draw-button'] - set custom style rules for the dismiss dialog button
* @param {string} [drawOptions.dialogPopup.dismissText = 'Ok'] - text to display in the dismiss dialog button
* @param {object} [drawOptions.drawStyle] - specify custom drawing options for the area
* @param {number} [drawOptions.drawStyle.lineWidth = 3] - set custom line width in px
* @param {string} [drawOptions.drawStyle.lineCap = 'round'] - other options are 'butt' or 'square'
* @param {string} [drawOptions.drawStyle.lineJoin = 'round'] - other options are 'bevel' or 'miter'
* @param {string} [drawOptions.drawStyle.stroke = 'rgba(55, 71, 79, 0.9)'] - set custom stroke style
* @param {string} [drawOptions.drawStyle.fill = 'rgba(129, 156, 169, 0.4)'] - set custom fill style
* @param {object} [drawOptions.areaData] - options for data source inside the area
* @param {number} [drawOptions.areaData.maxCoords = 900] - specify maximum number of coordinates to collect from the drawing
* @param {number} [drawOptions.areaData.markerGroupMaxLevel = 13] - specify markers maximum grouping level
*/
gem.control.DrawAreaOnMapControl = class DrawAreaOnMapControl extends gem.control.BaseControl {
constructor(addedDataControl, drawOptions) {
super(gem.control.TConntrolExecuteType.ONCONNECTED);
this.addedDataControl = addedDataControl;
this.mouseDown = this.mouseDown.bind(this);
this.mouseMove = this.mouseMove.bind(this);
this.mouseUp = this.mouseUp.bind(this);
let defaultOptions = {
button: {
parentContainer: '',
activateText: 'Draw area on map',
deactivateText: 'Stop drawing',
cssClass: 'gem-draw-button'
},
dialogPopup: {
cssClass: 'gem-dialog-popup',
textInfo: 'Please draw an area',
cssDismissButton: 'gem-draw-button',
dismissText: 'Ok'
},
drawStyle: {
lineWidth: 3,
lineCap: 'round', // other options 'butt', 'square'
lineJoin: 'round', // other options 'bevel', 'miter'
stroke: 'rgba(55, 71, 79, 0.9)',
fill: 'rgba(129, 156, 169, 0.4)'
},
areaData: {
maxCoords: 900,
markerGroupMaxLevel: 13
}
};
this.options = defaultOptions;
if (drawOptions) {
this.options = Object.assign({}, defaultOptions, drawOptions);
if (drawOptions.button)
this.options.button = Object.assign({}, defaultOptions.button, drawOptions.button);
if (drawOptions.dialogPopup)
this.options.dialogPopup = Object.assign({}, defaultOptions.dialogPopup, drawOptions.dialogPopup);
if (drawOptions.drawStyle)
this.options.drawStyle = Object.assign({}, defaultOptions.drawStyle, drawOptions.drawStyle);
if (drawOptions.areaData)
this.options.areaData = Object.assign({}, defaultOptions.areaData, drawOptions.areaData);
}
}
initControl(mapContainer, mapView) {
if (!this.addedDataControl) {
console.log('please specify a connected data source control');
return;
}
this.mapParentContainer = document.getElementById(mapContainer);
if (!this.mapParentContainer) {
console.log('draw controls cannot be used without map');
return;
}
this.defaultMapView = mapView;
this.drawActivate = undefined;
this.isDrawing = undefined;
this.screenDrawCoords = [];
this.mapDrawCoords = [];
this.mapDrawBoundsInit = {
minLon: 180.0,
minLat: 90.0,
maxLon: -180.0,
maxLat: -90.0
};
const elParent = document.getElementById(this.options.button.parentContainer);
if (elParent)
this.createDrawControls(elParent);
}
createDrawControls(parentContainer) {
this.mapCanvas = document.getElementById('canvas');
// draw canvas
this.drawCanvas = this.mapParentContainer.appendChild(document.createElement('canvas'));
this.drawCanvas.id = 'draw-canvas';
this.drawCanvas.width = this.mapParentContainer.clientWidth;
this.drawCanvas.height = this.mapParentContainer.clientHeight;
this.drawCanvas.style.display = 'none';
this.drawCanvas.style.position = 'absolute';
this.drawCanvas.style.left = '0';
this.drawCanvas.style.top = '0';
this.drawContext = this.drawCanvas.getContext('2d');
// button
const buttonDraw = parentContainer.appendChild(document.createElement('button'));
buttonDraw.className = this.options.button.cssClass;
const buttonText = buttonDraw.appendChild(document.createElement('div'));
buttonText.className = 'gem-draw-button-text';
buttonText.textContent = this.options.button.activateText;
const drawIcon = buttonDraw.appendChild(document.createElement('div'));
drawIcon.classList.add('gem-draw-icon');
const cancelDrawIcon = buttonDraw.appendChild(document.createElement('div'));
cancelDrawIcon.classList.add('gem-cancel-draw-icon');
cancelDrawIcon.style.display = 'none';
cancelDrawIcon.textContent = '×';
buttonDraw.addEventListener('click', (ev) => {
if (this.drawActivate === undefined || this.drawActivate) {
buttonText.textContent = this.options.button.deactivateText;
drawIcon.style.display = 'none';
cancelDrawIcon.style.display = '';
this.drawActivate = false;
this.enableDrawing();
} else {
buttonText.textContent = this.options.button.activateText;
drawIcon.style.display = '';
cancelDrawIcon.style.display = 'none';
this.drawActivate = true;
this.disableDrawing();
}
}, false);
}
enableDrawing() {
this.addedDataControl.toggleCameraCallback();
this.screenDrawCoords.length = 0;
this.mapDrawCoords.length = 0;
this.drawContext.clearRect(0, 0, this.drawCanvas.width, this.drawCanvas.height);
this.drawCanvas.style.display = '';
this.drawCanvas.style.cursor = 'crosshair';
this.drawCanvas.style.pointerEvents = '';
this.drawCanvas.addEventListener('mousedown', this.mouseDown, false);
this.drawCanvas.addEventListener('mousemove', this.mouseMove, false);
this.drawCanvas.addEventListener('mouseup', this.mouseUp, false);
this.drawCanvas.addEventListener('touchstart', this.mouseDown, false);
this.drawCanvas.addEventListener('touchmove', this.mouseMove, false);
this.drawCanvas.addEventListener('touchend', this.mouseUp, false);
}
disableDrawing() {
this.drawCanvas.style.display = 'none';
this.drawCanvas.style.cursor = 'auto';
this.drawCanvas.removeEventListener('mousedown', this.mouseDown, false);
this.drawCanvas.removeEventListener('mousemove', this.mouseMove, false);
this.drawCanvas.removeEventListener('mouseup', this.mouseUp, false);
this.drawCanvas.removeEventListener('touchstart', this.mouseDown, false);
this.drawCanvas.removeEventListener('touchmove', this.mouseMove, false);
this.drawCanvas.removeEventListener('touchend', this.mouseUp, false);
this.addedDataControl.toggleCameraCallback();
}
updateDrawBounds(mapCoord) {
this.drawBounds.minLon = Math.min(mapCoord.longitude, this.drawBounds.minLon);
this.drawBounds.minLat = Math.min(mapCoord.latitude, this.drawBounds.minLat);
this.drawBounds.maxLon = Math.max(mapCoord.longitude, this.drawBounds.maxLon);
this.drawBounds.maxLat = Math.max(mapCoord.latitude, this.drawBounds.maxLat);
}
zoomToDraw(buffer) {
let viewRectangle = this.defaultMapView.getViewport();
viewRectangle.x += buffer;
viewRectangle.y += buffer;
viewRectangle.width -= 2 * buffer;
viewRectangle.height -= 2 * buffer;
const drawLeftTop = {
longitude: this.drawBounds.minLon,
latitude: this.drawBounds.maxLat,
altitude: 0,
bearing: 0
};
const drawRightBottom = {
longitude: this.drawBounds.maxLon,
latitude: this.drawBounds.minLat,
altitude: 0,
bearing: 0
};
this.defaultMapView.centerOnArea(drawLeftTop, drawRightBottom, 0, viewRectangle);
}
mouseDown(e) {
this.isDrawing = true;
this.skipNextCoord = false;
this.screenDrawCoords.length = 0;
this.mapDrawCoords.lengh = 0;
this.drawBounds = Object.create(this.mapDrawBoundsInit);
const screenCoord = this.getScreenCoordinate(e);
this.screenDrawCoords.push(screenCoord);
const mapCoord = this.getMapCoordinate(screenCoord);
this.mapDrawCoords.push(mapCoord);
this.updateDrawBounds(mapCoord);
this.drawCanvas.style.pointerEvents = '';
this.drawCanvas.style.cursor = 'crosshair';
e.preventDefault();
}
mouseMove(e) {
if (this.isDrawing) {
e.preventDefault();
if (!this.skipNextCoord) {
const screenCoord = this.getScreenCoordinate(e);
this.screenDrawCoords.push(screenCoord);
const mapCoord = this.getMapCoordinate(screenCoord);
this.mapDrawCoords.push(mapCoord);
this.updateDrawBounds(mapCoord);
this.drawOnCanvas(this);
}
this.skipNextCoord = !this.skipNextCoord;
// restrict coordinates length
if (this.screenDrawCoords.length > this.options.areaData.maxCoords) {
this.mouseUp();
}
}
}
mouseUp(e) {
if (this.isDrawing) {
if (e)
e.preventDefault();
this.isDrawing = false;
this.screenDrawCoords.push(this.screenDrawCoords[0]);
this.mapDrawCoords.push(this.mapDrawCoords[0]);
this.drawOnCanvas();
if (this.mapDrawCoords.length < 4) {
const popup = this.createDialogPopup();
if (popup && this.drawCanvas.parentNode)
this.drawCanvas.parentNode.appendChild(popup);
} else {
this.addedDataControl.notifyAreaSelection(this.mapDrawCoords, this.options.areaData.markerGroupMaxLevel);
this.zoomToDraw(50);
}
this.drawCanvas.style.cursor = 'auto';
this.drawCanvas.style.pointerEvents = 'none';
}
}
drawOnCanvas() {
this.drawCanvas.width = this.mapParentContainer.clientWidth;
this.drawCanvas.height = this.mapParentContainer.clientHeight;
this.drawContext.strokeStyle = this.options.drawStyle.stroke;
this.drawContext.lineWidth = this.options.drawStyle.lineWidth;
this.drawContext.lineCap = this.options.drawStyle.lineCap;
this.drawContext.lineJoin = this.options.drawStyle.lineJoin;
this.drawContext.clearRect(0, 0, this.drawCanvas.width, this.drawCanvas.height);
this.drawContext.beginPath();
this.screenDrawCoords.forEach((elem, index) => {
if (index === 0) {
this.drawContext.moveTo(elem.x, elem.y);
} else {
this.drawContext.lineTo(elem.x, elem.y);
}
});
if (!this.isDrawing) {
this.drawContext.fillStyle = this.options.drawStyle.fill;
this.drawContext.fill();
}
this.drawContext.stroke();
}
preRenderCallback() {
if (this.drawActivate === false && this.isDrawing === false) {
this.drawCanvas.width = this.mapParentContainer.clientWidth;
this.drawCanvas.height = this.mapParentContainer.clientHeight;
this.drawContext.strokeStyle = this.options.drawStyle.stroke;
this.drawContext.lineWidth = this.options.drawStyle.lineWidth;
this.drawContext.lineCap = this.options.drawStyle.lineCap;
this.drawContext.lineJoin = this.options.drawStyle.lineJoin;
this.drawContext.fillStyle = this.options.drawStyle.fill;
this.drawContext.clearRect(0, 0, this.drawCanvas.width, this.drawCanvas.height);
this.drawContext.beginPath();
this.mapDrawCoords.forEach((elem, index) => {
const screenCoord = this.defaultMapView.transformWgsToScreen(elem);
if (index === 0) {
this.drawContext.moveTo(screenCoord.x, screenCoord.y);
} else {
this.drawContext.lineTo(screenCoord.x, screenCoord.y);
}
});
this.drawContext.stroke();
this.drawContext.fill();
}
}
getScreenCoordinate(e) {
if (e.offsetX && e.offsetY) {
return {
x: e.offsetX,
y: e.offsetY
};
} else if (e.targetTouches && e.targetTouches.length) {
const rectangle = e.target.getBoundingClientRect();
return {
x: (e.targetTouches[0].clientX - rectangle.left),
y: (e.targetTouches[0].clientY - rectangle.top)
};
}
}
getMapCoordinate(screenCoord) {
const mapCoord = this.defaultMapView.transformScreenToWgs(screenCoord);
mapCoord.longitude = Math.round(mapCoord.longitude * 1e5) / 1e5;
mapCoord.latitude = Math.round(mapCoord.latitude * 1e5) / 1e5;
return mapCoord;
}
createDialogPopup() {
const popup = document.createElement('div');
popup.className = this.options.dialogPopup.cssClass;
const textInfo = popup.appendChild(document.createElement('p'));
textInfo.textContent = this.options.dialogPopup.textInfo;
const button = popup.appendChild(document.createElement('button'));
button.className = this.options.dialogPopup.cssDismissButton;
button.textContent = this.options.dialogPopup.dismissText;
button.addEventListener('click', () => {
popup.remove();
});
return popup;
}
}
/**
* Control for displaying free text search on map
* @class gem.control.SearchControl
*
* @param {object} [searchOptions]
* @param {object} searchOptions.highlightOptions - customize search result highlight on map options
* @param {bool} searchOptions.highlightOptions.showContour - default true, show search result contour if available
* @param {object} searchOptions.highlightOptions.contourColor - search result highlight contour color, default {r: 255, g: 0, b: 0, a: 255}
* @param {bool} searchOptions.highlightOptions.overlap - default true, overlap highlight over existing map data
* @param {bool} searchOptions.highlightOptions.noFading - default false, disable highlight fading in / out
* @param {bool} searchOptions.highlightOptions.group - default false, group landmarks
* @param {bool} searchOptions.highlightOptions.searchResultPin - default true - use search result pin icon, if false - highlight result landmark icon
* @param {object} searchOptions.searchPreferences - customize search preferences
* @param {bool} searchOptions.searchPreferences.exactMatch - default true
* @param {number} searchOptions.searchPreferences.maximumMatches - no. of search results to display, default 5, maximum 5
* @param {bool} searchOptions.searchPreferences.addressSearch - default false
* @param {bool} searchOptions.searchPreferences.mapPoisSearch - default false
* @param {object} searchOptions.searchPreferences.mapEnvelope - default entire map, map area in which to restrict the search results
* @param {gem.core.Coordinates} searchOptions.searchPreferences.mapEnvelope.topLeft - default {latitude: 90, longitude: -180, altitude: 0, bearing: 0}
* @param {gem.core.Coordinates} searchOptions.searchPreferences.mapEnvelope.bottomRight - default {latitude: -90, longitude: 180, altitude: 0, bearing: 0}
* @param {bool} searchOptions.searchPreferences.setCursorReferencePoint - default false( reference point is center of map envelope ), if set to true the search reference coordinate is set at the last cursor position
* @param {string} searchOptions.searchPreferences.placeholderText - set custom placeholder text for search box
* @param {object} searchOptions.searchResults - options for configuring the free text search results
* @param {bool} searchOptions.searchResults.showLandmarkIcons - default false
* @param {string} searchOptions.searchResults.initialPlaceSearch - default no value, specify a start-up location
* @param {number} [searchOptions.searchResults.flyToResultAltitude = 1000] - fly to result altitude in meters
* @param {object} searchOptions.cssClasses - specify custom style rules classes
* @param {string} searchOptions.cssClasses.container
* @param {string} searchOptions.cssClasses.inputContainer
* @param {string} searchOptions.cssClasses.inputText
* @param {string} searchOptions.cssClasses.searchIcon
* @param {string} searchOptions.cssClasses.searchLoader
* @param {string} searchOptions.cssClasses.searchClear
* @param {string} searchOptions.cssClasses.searchFocus
* @param {string} searchOptions.cssClasses.searchResults
* @param {string} searchOptions.cssClasses.searchResultItem
* @param {string} searchOptions.cssClasses.searchResultCanvas
* @param {string} searchOptions.cssClasses.searchResultContent
* @param {string} searchOptions.cssClasses.searchResultTitle
* @param {string} searchOptions.cssClasses.searchResultType
*/
gem.control.SearchControl = class SearchControl extends gem.control.BaseControl {
constructor(searchOptions) {
super(gem.control.TConntrolExecuteType.ONCONNECTED);
this.doneSearchTyping = 800;
// search control option defaults
let defaultSearchOptions = {
highlightOptions: {
showContour: true,
contourColor: {
r: 255,
g: 0,
b: 0,
a: 255
},
overlap: true,
noFading: false,
group: false,
searchResultPin: true
},
searchPreferences: {
exactMatch: true,
maximumMatches: 5,
addressSearch: false,
mapPoisSearch: false,
mapEnvelope: {
topLeft: {
latitude: 90,
longitude: -180,
altitude: 0,
bearing: 0
},
bottomRight: {
latitude: -90,
longitude: 180,
altitude: 0,
bearing: 0
}
},
placeholderText: 'Search on map',
setCursorReferencePoint: false
},
searchResults: {
showLandmarkIcons: false,
initialPlaceSearch: "",
flyToResultAltitude: 1000
},
cssClasses: {
container: 'gem-search-control',
inputContainer: 'gem-search-input',
inputText: 'gem-search-input-text',
searchIcon: 'gem-search-icon',
searchLoader: 'gem-search-loader',
searchClear: 'gem-clear-search',
searchFocus: 'gem-search-focus',
searchResults: 'gem-search-results',
searchResultItem: 'gem-search-result',
searchResultCanvas: 'gem-search-result-canvas',
searchResultContent: 'gem-search-result-content',
searchResultTitle: 'gem-search-result-content-title',
searchResultType: 'gem-search-result-type'
}
}
this.options = defaultSearchOptions;
if (searchOptions && searchOptions.highlightOptions)
this.options.highlightOptions = Object.assign({}, defaultSearchOptions.highlightOptions, searchOptions.highlightOptions);
if (searchOptions && searchOptions.searchPreferences)
this.options.searchPreferences = Object.assign({}, defaultSearchOptions.searchPreferences, searchOptions.searchPreferences);
if (searchOptions && searchOptions.searchResults)
this.options.searchResults = Object.assign({}, defaultSearchOptions.searchResults, searchOptions.searchResults);
if (searchOptions && searchOptions.cssClasses)
this.options.cssClasses = Object.assign({}, defaultSearchOptions.cssClasses, searchOptions.cssClasses);
if (searchOptions)
this.selectionListeners = searchOptions.selectionListener;
if (this.selectionListeners) {
for (let i = 0; i < this.selectionListeners.length; i++)
this.selectionListeners[i].setControlMode('dependend');
}
}
createSearchControls(mapDiv, mapTopLeft, mapBottomRight) {
// search controls + results container
let searchControlsDiv = document.createElement('div');
searchControlsDiv.id = this.options.cssClasses.container;
searchControlsDiv.className = this.options.cssClasses.container;
// search input container
let searchInputDiv = searchControlsDiv.appendChild(document.createElement('div'));
searchInputDiv.id = this.options.cssClasses.inputContainer;
searchInputDiv.className = this.options.cssClasses.inputContainer;
// search icon
let searchIcon = searchInputDiv.appendChild(document.createElement('div'));
searchIcon.className = this.options.cssClasses.searchIcon;
// input
let inputDiv = searchInputDiv.appendChild(document.createElement('input'));
inputDiv.id = this.options.cssClasses.inputText;
inputDiv.className = this.options.cssClasses.inputText;
inputDiv.type = 'text';
inputDiv.placeholder = this.options.searchPreferences.placeholderText;
// search loading animation
let searchLoader = searchInputDiv.appendChild(document.createElement('div'));
searchLoader.id = this.options.cssClasses.searchLoader;
searchLoader.className = this.options.cssClasses.searchLoader;
searchLoader.style.visibility = 'hidden';
// clear search icon
let clearSearchDiv = searchInputDiv.appendChild(document.createElement('span'));
clearSearchDiv.id = this.options.cssClasses.searchClear;
clearSearchDiv.className = this.options.cssClasses.searchClear;
clearSearchDiv.textContent = '×';
clearSearchDiv.style.visibility = 'hidden';
// search results
this.searchResultsDiv = searchControlsDiv.appendChild(document.createElement('div'));
this.searchResultsDiv.id = this.options.cssClasses.searchResults;
this.searchResultsDiv.className = this.options.cssClasses.searchResults;
this.searchResultsDiv.style.display = 'none';
// onclick event listener for search icon
searchIcon.addEventListener('click', function () {
this.searchOnMap(inputDiv, this.searchResultsDiv, mapTopLeft, mapBottomRight, this.searchPrefs);
}.bind(this));
// keyup event listener for input
inputDiv.addEventListener('keyup', function (event) {
this.onSearchInputKeyUp(event, inputDiv, this.searchResultsDiv, mapTopLeft, mapBottomRight, this.searchPrefs);
}.bind(this));
// onclick event listener for clear search
clearSearchDiv.addEventListener('click', function () {
this.clearSearchText();
}.bind(this));
// add the search controls to the map
mapDiv.appendChild(searchControlsDiv);
// check if initial place search has been set
if (this.options.searchResults.initialPlaceSearch.length) {
let text = this.options.searchResults.initialPlaceSearch;
this.searchResults = new gem.core.LandmarkList();
let cbSearchFinished = function (reason) {
if (this.searchResults && this.searchResults.size()) {
let result = this.searchResults.get(0);
this.resultOnClick(result, inputDiv);
inputDiv.value = text;
document.getElementById(this.options.cssClasses.searchClear).style.visibility = 'visible';
}
}.bind(this);
let mapTopLeft = this.options.searchPreferences.mapEnvelope.topLeft;
let mapBottomRight = this.options.searchPreferences.mapEnvelope.bottomRight;
gem.places.Search.searchFor(text, mapTopLeft, mapBottomRight, cbSearchFinished, this.searchResults);
}
}
initControl(container, mapView) {
this.defaultMapView = mapView;
// interpret search preferences
let mapTopLeft = {
latitude: 90,
longitude: -180,
altitude: 0,
bearing: 0
};
let mapBottomRight = {
latitude: -90,
longitude: 180,
altitude: 0,
bearing: 0
};
if (this.options.searchPreferences) {
this.searchPrefs = new gem.places.SearchPreferences();
if (this.options.searchPreferences.mapEnvelope) {
mapTopLeft = this.options.searchPreferences.mapEnvelope.topLeft;
mapBottomRight = this.options.searchPreferences.mapEnvelope.bottomRight;
}
if (this.options.searchPreferences.exactMatch)
this.searchPrefs.setExactMatch(this.options.searchPreferences.exactMatch);
if (this.options.searchPreferences.maximumMatches)
this.searchPrefs.setMaxMatches(this.options.searchPreferences.maximumMatches);
if (this.options.searchPreferences.addressSearch)
this.searchPrefs.setSearchAddresses(this.options.searchPreferences.maximumMatches);
if (this.options.searchPreferences.mapPoisSearch)
this.searchPrefs.setSearchMapPOIs(this.options.searchPreferences.mapPoisSearch);
}
// interpret highlight options
this.chosenHighlightOpts = gem.d3Scene.EHighlightOptions.EHO_ShowLandmark.value; // mandatory
if (this.options.highlightOptions.showContour)
this.chosenHighlightOpts |= gem.d3Scene.EHighlightOptions.EHO_ShowContour.value;
if (this.options.highlightOptions.overlap)
this.chosenHighlightOpts |= gem.d3Scene.EHighlightOptions.EHO_Overlap.value;
if (this.options.highlightOptions.noFading)
this.chosenHighlightOpts |= gem.d3Scene.EHighlightOptions.EHO_NoFading;
if (this.options.highlightOptions.group)
this.chosenHighlightOpts |= gem.d3Scene.EHighlightOptions.EHO_Group;
this.resultPin = undefined;
if (this.options.highlightOptions.searchResultPin)
this.resultPin = gem.d3Scene.EUsableIcons.eSearch_Results_Pin.value;
let mapCanvasDiv = document.getElementById(container);
this.createSearchControls(mapCanvasDiv, mapTopLeft, mapBottomRight);
}
onSearchInputKeyUp(event, searchInputDiv, searchResultsDiv, mapTopLeft, mapBottomRight, searchPreferences) {
if (event.code === 'Enter') {
clearTimeout(this.searchTypingTimer);
if (this.searchResults != undefined && !this.searchResults.isDeleted() && this.searchResults.size() > 0) {
let typedString = searchInputDiv.value.toLowerCase();
let firstResult = this.searchResults.get(0).getName().toLowerCase();
if (typedString && firstResult.startsWith(typedString)) {
this.resultOnClick(this.searchResults.get(0), searchInputDiv);
return;
}
}
this.searchOnMap(searchInputDiv, searchResultsDiv, mapTopLeft, mapBottomRight, searchPreferences);
} else {
clearTimeout(this.searchTypingTimer);
if (searchInputDiv.value) {
document.getElementById(this.options.cssClasses.searchClear).style.visibility = 'visible';
this.searchTypingTimer = setTimeout(() => {
this.searchOnMap(searchInputDiv, searchResultsDiv, mapTopLeft, mapBottomRight, searchPreferences);
}, this.doneSearchTyping);
} else {
if (!document.getElementsByClassName(this.options.cssClasses.searchResultItem))
document.getElementById(this.options.cssClasses.searchClear).style.visibility = 'hidden';
}
}
}
searchOnMap(searchInputDiv, searchResultsDiv, mapTopLeft, mapBottomRight, searchPreferences) {
this.clearSearchResults();
searchInputDiv.parentElement.classList.add(this.options.cssClasses.searchFocus);
const text = searchInputDiv.value;
if (text == "") {
searchInputDiv.disabled = false;
return;
}
this.toggleSearchLoaderOn();
let callbackSearchFinished = function (reason) {
if (reason != 0) {
this.toggleSearchLoaderOff();
return;
}
this.displayResults(this.searchResults, searchInputDiv, searchResultsDiv);
}.bind(this);
this.searchResults = new gem.core.LandmarkList();
if (searchPreferences) {
if (this.options.searchPreferences.setCursorReferencePoint) {
let cursorCoord = this.defaultMapView.getCursorPositionWGS();
searchPreferences.setReferencePoint(cursorCoord);
} else {
searchPreferences.setReferencePoint({
latitude: (mapTopLeft.latitude + mapBottomRight.latitude) / 2.0,
longitude: (mapTopLeft.longitude + mapBottomRight.longitude) / 2.0,
altitude: 0,
bearing: 0
});
}
gem.places.Search.searchForWithPreferences(text, mapTopLeft, mapBottomRight, callbackSearchFinished, this.searchResults, searchPreferences);
} else
gem.places.Search.searchFor(text, mapTopLeft, mapBottomRight, callbackSearchFinished, this.searchResults);
}
displayResults(resultList, searchInputDiv, searchResultsDiv) {
this.toggleSearchLoaderOff();
if (!searchResultsDiv)
return;
const resultsCount = resultList.size();
if (resultsCount && resultsCount > 0) {
searchResultsDiv.innerHTML = "";
for (let i = 0; i < resultsCount; i++) {
let result = resultList.get(i);
// Result item
const container = document.createElement('div');
container.className = this.options.cssClasses.searchResultItem;
// add mouse click event for search result item
container.addEventListener('click', function () {
this.resultOnClick(result, searchInputDiv);
}.bind(this), false);
// search result icon ( optional )
let imgCanvas = undefined;
if (this.options.searchResults.showLandmarkIcons) {
const offbitmap = new gem.core.BitmapContainer(20, 20);
result.getImage(offbitmap);
imgCanvas = document.createElement('canvas');
imgCanvas.className = this.options.cssClasses.searchResultCanvas;
imgCanvas.setAttribute('width', '20');
imgCanvas.setAttribute('height', '20');
imgCanvas.style.backgroundColor = 'transparent';
gem.core.App.setCanvas(offbitmap.toImageData(), 20, 20, imgCanvas);
offbitmap.delete();
}
// Result link
const resultContent = document.createElement('div');
resultContent.className = this.options.cssClasses.searchResultContent;
const resultContentName = document.createElement('div');
resultContentName.className = this.options.cssClasses.searchResultTitle;
resultContentName.textContent = result.getFormatedName();
const resultContentDescription = document.createElement('span');
resultContentDescription.className = this.options.cssClasses.searchResultType;
// details + distance from cursor position to searched location
const distanceToNearby = gem.core.App.getDistanceBetween2Coordinates(this.defaultMapView.getCursorPositionWGS(), result.getCoordinates());
let resultDescription = result.getFormatedDetails();
resultDescription += this.getFormattedDistanceMetric(distanceToNearby);
resultContentDescription.textContent = resultDescription;
resultContent.appendChild(resultContentName);
resultContent.appendChild(resultContentDescription);
// Append content to item
if (imgCanvas)
container.appendChild(imgCanvas);
container.appendChild(resultContent);
// Append result to list
searchResultsDiv.appendChild(container);
}
}
// no search results
if (resultList.size() == 0) {
searchResultsDiv.innerHTML = "";
const container = document.createElement('div');
container.className = this.options.cssClasses.searchResultItem;
const resultContent = document.createElement('div');
resultContent.className = this.options.cssClasses.searchResultContent;
const resultContentName = document.createElement('div');
resultContentName.className = this.options.cssClasses.searchResultTitle;
resultContentName.textContent = "Nothing was found";
resultContent.appendChild(resultContentName);
container.appendChild(resultContent);
searchResultsDiv.appendChild(container);
}
searchResultsDiv.style.display = 'inline-block';
}
resultOnClick(pickedResult, searchInputDiv) {
searchInputDiv.value = pickedResult.getName();
var highlightList = new gem.core.LandmarkList();
highlightList.push_back(pickedResult);
this.defaultMapView.activateHighlight(highlightList, this.options.highlightOptions.contourColor, this.chosenHighlightOpts, this.resultPin);
highlightList.delete();
this.clearSearchResults();
searchInputDiv.parentElement.classList.remove(this.options.cssClasses.searchFocus);
let box = pickedResult.getBoundingBox();
if (!box.isEmpty) {
box.leftTop.altitude = this.options.searchResults.flyToResultAltitude;
box.rightBottom.altitude = this.options.searchResults.flyToResultAltitude;
this.defaultMapView.centerOnArea(box.leftTop, box.rightBottom, 0);
} else {
let coords = pickedResult.getCoordinates();
coords.altitude = this.options.searchResults.flyToResultAltitude;
this.defaultMapView.centerOnCoordinates(coords, 2000);
}
if (this.selectionListeners)
this.notifySearchSelectionListeners(pickedResult);
}
toggleSearchLoaderOn() {
document.getElementById(this.options.cssClasses.searchLoader).style.visibility = "visible";
}
toggleSearchLoaderOff() {
document.getElementById(this.options.cssClasses.searchLoader).style.visibility = "hidden";
}
clearSearchResults() {
document.getElementById(this.options.cssClasses.container).style.height = 'auto';
document.getElementById(this.options.cssClasses.searchResults).innerHTML = "";
document.getElementById(this.options.cssClasses.searchResults).style.display = 'none';
}
clearSearchText() {
document.getElementById(this.options.cssClasses.inputText).value = '';
document.getElementById(this.options.cssClasses.inputContainer).classList.remove(this.options.cssClasses.searchFocus);
document.getElementById(this.options.cssClasses.searchClear).style.visibility = 'hidden';
this.clearSearchResults();
if (this.selectionListeners)
this.notifySearchSelectionListeners();
this.defaultMapView.deactivateHighlight();
document.getElementById(this.options.cssClasses.inputText).focus();
}
getFormattedDistanceMetric(distance) {
let formattedDistance = "";
if (distance > 1000) {
if (distance >= 10000)
formattedDistance += " (" + (distance / 1000).toFixed(0) + "km)";
if (distance < 10000)
formattedDistance += " (" + (distance / 1000).toFixed(1) + "km)";
} else {
if (distance < 100)
formattedDistance += " (" + this.roundToNearestMultiple(distance.toFixed(0), 5) + "m)";
else
formattedDistance += " (" + this.roundToNearestMultiple(distance.toFixed(0), 25) + "m)";
}
return formattedDistance;
}
roundToNearestMultiple(number, multiple) {
// Larger multiple
var a = Math.ceil(number / multiple) * multiple;
// Smaller multiple
var b = Math.floor(number / multiple) * multiple;;
// Return of closest of two
return (a - number > number - b) ? b : a;
}
notifySearchSelectionListeners(item) {
for (let it = 0; it < this.selectionListeners.length; it++) {
this.selectionListeners[it].notifySearchSelection(item);
}
}
setLandmarkResult(landmarkresult) {
let searchInput = document.getElementById(this.options.cssClasses.inputText);
searchInput.value = landmarkresult.getName();
this.resultOnClick(landmarkresult, searchInput);
}
hide() {
document.getElementById(this.options.cssClasses.container).style.visibility = 'hidden';
document.getElementById(this.options.cssClasses.inputContainer).style.visibility = 'hidden';
document.getElementById(this.options.cssClasses.searchClear).style.visibility = 'hidden';
}
show() {
document.getElementById(this.options.cssClasses.container).style.visibility = 'visible';
document.getElementById(this.options.cssClasses.inputContainer).style.visibility = 'visible';
document.getElementById(this.options.cssClasses.searchClear).style.visibility = 'visible';
}
}
gem.control.NavigationControl = class NavigationControl extends gem.control.BaseControl {
constructor(initOptions) {
super(gem.control.TConntrolExecuteType.ONCONNECTED);
if (initOptions) {
this.autoStart = initOptions.autoStart;
}
}
initControl(parentDiv, mapView) {
this.parentDiv = parentDiv;
this.synthesis = window.speechSynthesis;
}
createBottomNavigationPanel() {
this.bottomPanel = document.createElement("div");
this.bottomPanel.classList.add("bottomPanel");
this.bottomPanelRemainingDistance = document.createElement("div");
this.bottomPanelRemainingDistance.classList.add("bottomPanelRemainingDistance");
this.bottomPanelRemainingTime = document.createElement("div");
this.bottomPanelRemainingTime.classList.add("bottomPanelRemainingTime");
this.bottomPanel.appendChild(this.bottomPanelRemainingDistance);
this.bottomPanel.appendChild(this.bottomPanelRemainingTime);
document.getElementById(this.parentDiv).appendChild(this.bottomPanel);
}
createTopNavigationPanel() {
this.topPanel = document.createElement("div");
this.topPanel.style.cursor = 'pointer';
this.topPanel.onclick = function () {
if (this.instructionsList) {
this.instructionsList.remove();
this.instructionsList = undefined;
} else {
this.instructionsList = document.createElement("div");
this.instructionsList.classList.add("navigationPanel");
this.instructionsList.style.top = this.topPanel.offsetTop + this.topPanel.offsetHeight + 2 + 'px';
this.instructionsList.style.height = '400px';
this.instructionsList.style.overflow = 'auto';
this.instructionsList.appendChild(this.instructionULList);
document.getElementById(this.parentDiv).appendChild(this.instructionsList);
}
}.bind(this);
this.topPanel.classList.add("navigationPanel");
this.navigationText = document.createElement("div");
this.navigationText.classList.add("navigationText");
this.canvasins = document.createElement("CANVAS");
this.canvasins.classList.add("canvasins");
this.canvasins.style.width = "60px";
this.canvasins.style.height = "60px";
this.canvasins.style.float = 'left';
this.topPanel.appendChild(this.navigationText);
this.topPanel.appendChild(this.canvasins);
document.getElementById(this.parentDiv).appendChild(this.topPanel);
}
getTrafficEvents() {
let trafficEvents = this.route.getTrafficEvents();
for (let i = 0; i < trafficEvents.size(); i++) {
let trafficEvent = trafficEvents.get(i);
console.log('Traffic Event:' + trafficEvent.getDescription());
}
}
createNavInstructionList() {
//this.getTrafficEvents();
this.instructionULList = document.createElement("UL");
this.instructionULList.style = 'list-style-type:none; padding-left: 0;';
let instructionSet = this.route.getNavigationInstructionSection(0);
for (let i = 1; i < instructionSet.size(); i++) {
var bitmapContainer = new gem.core.BitmapContainer(30, 30);
let instruction = instructionSet.get(i);
instruction.getTurnImageInBitmap(bitmapContainer);
let canvasinss = document.createElement("CANVAS");
canvasinss.style.width = "30px";
canvasinss.style.height = "30px";
canvasinss.style.position = "relative";
gem.core.App.setCanvas(bitmapContainer.toImageData(), 30, 30, canvasinss);
var x = document.createElement("LI");
x.setAttribute("id", "navInstructionList" + i);
var xdiv = document.createElement("div");
xdiv.style.display = 'flex';
let navText = document.createElement("div");
//navText.classList.add("navigationText");
navText.innerHTML = '<p>' + instruction.getTurnInstructionString() + '</p>';
xdiv.onclick = function () {
this.mapView.centerOnRouteInstruction(instruction);
}.bind(this);
xdiv.onmouseover = function () {
navText.style.backgroundColor = 'gold';
}
xdiv.onmouseout = function () {
navText.style.backgroundColor = '';
}
xdiv.style.cursor = 'pointer';
xdiv.appendChild(canvasinss);
xdiv.appendChild(navText);
x.appendChild(xdiv);
this.instructionULList.appendChild(x);
}
}
navInstructionUpdate() {
let currentId = gem.routesAndNavigation.Navigation.getCurrentInstructionId();
var bitmapContainer = new gem.core.BitmapContainer(60, 60);
gem.routesAndNavigation.Navigation.getNextTurnImageInBitmap(bitmapContainer);
gem.core.App.setCanvas(bitmapContainer.toImageData(), 60, 60, this.canvasins);
var distancetoNext =
gem.routesAndNavigation.Navigation.getTimeDistanceToNextTurn().totaldistance;
var unit = " meters "
if (distancetoNext > 1000) {
distancetoNext = distancetoNext / 1000.0;
unit = " Km ";
}
this.navigationText.innerHTML = "<p> In " + distancetoNext.toFixed(2) +
unit + gem.routesAndNavigation.Navigation.getNextTurnInstruction() + "</p>";
var remainedTimeDistance = gem.routesAndNavigation.Navigation.getRemainingTravelTimeDistance();
this.bottomPanelRemainingDistance.innerHTML = (remainedTimeDistance.totaldistance / 1000).toFixed(2) + "km";
var measuredTime = new Date(null);
measuredTime.setSeconds(remainedTimeDistance.totaltime); // specify value in seconds
var MHSTime = measuredTime.toISOString().substr(11, 5);
this.bottomPanelRemainingTime.innerHTML = MHSTime + "hr";
bitmapContainer.delete();
}
populateVoiceList() {
if (typeof window.speechSynthesis === 'undefined') {
return;
}
var voices = window.speechSynthesis.getVoices();
for (var i = 0; i < voices.length; i++) {
if (voices[i].default) {
console.log("Voice is " + voices[i]);
}
}
}
PopulateVoicesInternal() {
this.populateVoiceList();
if (typeof window.speechSynthesis !== 'undefined' && window.speechSynthesis.onvoiceschanged !== undefined) {
window.speechSynthesis.onvoiceschanged = this.populateVoiceList;
}
}
startNavigation(route, mapView, notSimulation) {
this.PopulateVoicesInternal();
this.mapView = mapView;
this.route = route;
this.createNavInstructionList();
this.navigationInstructionEM = new gem.routesAndNavigation.NavigationListener();
let progressListener = function () {
// Set the camera to follow the simulated position of the green arrow along the route on the map
this.mapView.startFollowingPosition();
this.createBottomNavigationPanel();
this.createTopNavigationPanel();
};
this.navigationInstructionEM.registerNavInstructionUpdateListener(this.navInstructionUpdate.bind(this));
if (this.synthesis)
this.navigationInstructionEM.registerNavInstructionOnSoundListener(this.navInstructionSound.bind(this));
if (notSimulation) {
gem.routesAndNavigation.Navigation.startNavigation(route, progressListener.bind(this), this.navigationInstructionEM)
} else {
gem.routesAndNavigation.Navigation.startSimulation(route, progressListener.bind(this),
this.navigationInstructionEM);
}
}
navInstructionSound(soundString) {
if (this.notAllowedAudio)
return;
let flagVoiceFirst = false;
if (!this.firstTime) {
let confirmId = document.createElement("DIV");
confirmId.id = "id_confrmdiv";
confirmId.className = "id_confrmdiv";
let buttonTrue = document.createElement("BUTTON");
buttonTrue.id = "id_truebtn";
let buttonFalse = document.createElement("BUTTON");
buttonFalse.id = "id_falsebtn";
buttonTrue.innerHTML = "Yes";
buttonFalse.innerHTML = "No";
var para = document.createElement("P"); // Create a <p> element
para.innerText = "Enable audible instructions?";
confirmId.appendChild(para);
confirmId.appendChild(buttonTrue);
confirmId.appendChild(buttonFalse);
confirmId.style.zIndex = "!999999";
confirmId.style.display = "block";
try {
console.log("Added Confirm div to body");
window.document.body.appendChild(confirmId);
} catch (error) {
console.log(error);
}
this.notAllowedAudio = true;
buttonTrue.onclick = function () {
let flagVoiceFirst = false;
if (!this.voice) {
flagVoiceFirst = true;
let lang = window.navigator.language;
lang = lang.replace(/[^a-zA-Z ]/g, "");
this.voice = this.synthesis.getVoices().filter(function (voice) {
let voicelang = voice.lang.replace(/[^a-zA-Z ]/g, "");
console.log("The voice lang is " + voicelang + " compared to " + lang);
return (voicelang === lang);
})[0];
}
this.utterance = new SpeechSynthesisUtterance(soundString);
this.utterance.voice = this.voice;
this.utterance.pitch = 1.0;
this.utterance.rate = 1.0;
this.utterance.volume = 0.8; // Do your delete operation
this.synthesis.speak(this.utterance);
this.notAllowedAudio = false;
document.getElementById("id_confrmdiv").style.display = 'none';
}.bind(this);
buttonFalse.onclick = function () {
this.notAllowedAudio = true;
document.getElementById("id_confrmdiv").style.display = 'none';
}.bind(this);
this.firstTime = true;
} else {
if (!this.voice) {
this.synthesis = window.speechSynthesis;
var lang = window.navigator.language;
lang = lang.replace(/[^a-zA-Z ]/g, "");
this.voice = this.synthesis.getVoices().filter(function (voice) {
let voicelang = voice.lang.replace(/[^a-zA-Z ]/g, "");
return (voicelang === lang);
})[0];
}
this.utterance = new SpeechSynthesisUtterance(soundString);
this.utterance.voice = this.voice;
this.utterance.pitch = 1.0;
this.utterance.rate = 1.0;
this.utterance.volume = 0.8;
this.synthesis.speak(this.utterance);
}
}
/**
* Follow GPS Arrow
* @param {number} zoomLevel - Zoom Level
* @param {number} maxAngle - Max Angle
*/
startFollowingPosition(zoomLevel, maxAngle) {
this.mapView.startFollowingPosition(zoomLevel, maxAngle);
}
/**
* Stop Navigation
*/
stopNavigation() {
this.mapView.stopFollowingPosition();
gem.routesAndNavigation.Navigation.stopNavigation();
this.bottomPanel.remove();
this.topPanel.remove();
}
}
/**
* @callback callbackRouteSelected
* @param {number} routeId - Selected route id
* @param { gem.d3Scene.ECursorEvent} cursorEvent - Cursor Event
* @class gem.control.RouteControl
* @memberof namespace:gem.control
* @param {object} [initOptions] - options for calculating routes
* @param {gem.core.Coordinates[]} initOptions.waypoints - Waypoints
* @param {object} [initOptions.preferences]
* @param {gem.routesAndNavigation.ERouteType} initOptions.preferences.routeType - route type
* @param {boolean} initOptions.preferences.avoidUnpavedRoads - avoid unpaved roads
* @param {boolean} initOptions.preferences.avoidMotorways - avoid motorways
* @param {boolean} initOptions.preferences.avoidTollRoads - Avoid toll roads
* @param {boolean} initOptions.preferences.avoidFerries - Avoid ferries
* @param {boolean} initOptions.preferences.avoidTraffic - Avoid Traffic
* @param {number} initOptions.preferences.avoidBikingHillFactor - avoid biking hill factor 0.0 - no avoidance, 1.0 - full avoidance
* @param {gem.routesAndNavigation.ERouteTransportMode} initOptions.preferences.transportMode - transport mode
* @param {boolean} initOptions.preferences.buildTerrainProfile - Build Terrain Profile
* @param {object} initOptions.preferences.routeRanges - route ranges settings
* @param {number[]} initOptions.preferences.routeRanges.rangelist
* @param {number} initOptions.preferences.routeRanges.quality
* @param {object} initOptions.preferences.bikeProfile - bike profile settings
* @param {gem.routesAndNavigation.ERoutePathAlgorithm} initOptions.preferences.pathAlgorithm - Path Algorithm
* @param {gem.routesAndNavigation.ERouteResultDetails} initOptions.preferences.resultDetails - Result Details
* @param {gem.control.NavigationControl} navigationControl - Navigation Control Object (optional)
* @param {callbackRouteSelected} resultCallback - route selected callback
*/
gem.control.RouteControl = class RouteControl extends gem.control.BaseControl {
constructor(initOptions) {
super(gem.control.TConntrolExecuteType.ONCONNECTED);
if (initOptions) {
this.waypoints = new Map();
if (initOptions.waypoints) {
if (initOptions.waypoints.length === 1) {
this.destinationWaypoint = initOptions.waypoints[0];
} else {
this.destinationWaypoint = initOptions.waypoints[initOptions.waypoints.length - 1];
this.departureWaypoint = initOptions.waypoints[0];
}
}
this.preferences = initOptions.preferences;
this.resultCallback = initOptions.resultCallback;
this.navigationControl = initOptions.navigationControl;
this.activeRouteId = 0;
}
}
setControlMode(mode) {
this.controlMode = mode;
}
notifySearchSelection(item) {
if (item === undefined) {
this.clearRouteResult();
} else {
this.addDestination(item);
}
}
routeCallback() {
//var msecFlightDuration = 3000;
if (this.defaultRoute.size() > this.activeRouteId) {
// center on route
if (this.preferences.routeRanges)
this.mapView.centerOnRoute(this.defaultRoute.get(this.defaultRoute.size() - 1));
else
this.mapView.centerOnRoute(this.defaultRoute.get(this.activeRouteId));
if (this.navigationControl && this.navigationControl.autoStart) {
this.mapView.deregisterRouteClickedEvent();
this.mapView.showRouteInView(this.defaultRoute.get(this.activeRouteId), true, false);
this.navigationControl.startNavigation(this.defaultRoute.get(this.activeRouteId), this.mapView);
} else {
this.mapView.showRouteInView(this.defaultRoute.get(this.activeRouteId), true);
for (let i = 0; i < this.defaultRoute.size(); i++)
if (i !== this.activeRouteId)
this.mapView.showRouteInView(this.defaultRoute.get(i), false);
if (this.resultCallback) {
this.resultCallback(this.defaultRoute);
}
}
}
}
startNavigation(notSimulation) {
if (this.navigationControl) {
this.mapView.deregisterRouteClickedEvent();
this.mapView.showRouteInView(this.defaultRoute.get(this.activeRouteId), true, false);
for (let i = 0; i < this.defaultRoute.size(); i++)
if (i !== this.activeRouteId)
this.mapView.removeRoutefromView(this.defaultRoute.get(i));
this.navigationControl.startNavigation(this.defaultRoute.get(this.activeRouteId), this.mapView, notSimulation);
}
}
stopNavigation() {
if (this.navigationControl) {
this.mapView.removeRoutefromView(this.defaultRoute.get(this.activeRouteId));
this.navigationControl.stopNavigation();
}
}
getRouteResult() {
return this.defaultRoute;
}
getTrafficEvents() {
let trafficEvents = this.defaultRoute.get(this.activeRouteId).getTrafficEvents();
for (let i = 0; i < trafficEvents.size(); i++) {
let trafficEvent = trafficEvents.get(i);
console.log('Traffic Event:' + trafficEvent.getDescription());
}
}
routeSelectedCallback(nId, cursorEvent) {
if (cursorEvent === gem.d3Scene.ECursorEvent.eCursorEvent_Down && nId !== -1) {
this.mapView.removeRoutefromView(this.defaultRoute.get(this.activeRouteId));
this.mapView.showRouteInView(this.defaultRoute.get(this.activeRouteId), false);
this.activeRouteId = nId;
this.mapView.removeRoutefromView(this.defaultRoute.get(nId));
this.mapView.showRouteInView(this.defaultRoute.get(nId), true);
} else {
if (nId === -1)
Module.setCursorStyle("")
else
Module.setCursorStyle("pointer")
}
}
clearRouteResult() {
if (this.defaultRoute !== undefined) {
for (let i = 0; i < this.defaultRoute.size(); i++) {
this.mapView.removeRoutefromView(this.defaultRoute.get(i));
}
this.defaultRoute.delete();
this.defaultRoute = undefined;
}
}
computeRoute() {
this.defaultRoute = new gem.routesAndNavigation.RoutesRequest();
if (this.preferences) {
if (this.preferences.routeType) {
this.defaultRoute.setRouteType((typeof this.preferences.routeType === 'function') ? this.preferences.routeType() : this.preferences.routeType);
}
if (this.preferences.avoidUnpavedRoads) {
this.defaultRoute.setAvoidUnpavedRoads((typeof this.preferences.avoidUnpavedRoads === 'function') ? this.preferences.avoidUnpavedRoads() : this.preferences.avoidUnpavedRoads);
}
if (this.preferences.avoidMotorways) {
this.defaultRoute.setAvoidMotorways((typeof this.preferences.avoidMotorways === 'function') ? this.preferences.avoidMotorways() : this.preferences.avoidMotorways);
}
if (this.preferences.avoidTollRoads) {
this.defaultRoute.setAvoidTollRoads((typeof this.preferences.avoidTollRoads === 'function') ? this.preferences.avoidTollRoads() : this.preferences.avoidTollRoads);
}
if (this.preferences.avoidFerries) {
this.defaultRoute.setAvoidFerries((typeof this.preferences.avoidFerries === 'function') ? this.preferences.avoidFerries() : this.preferences.avoidFerries);
}
if (this.preferences.avoidTraffic) {
this.defaultRoute.setAvoidTraffic((typeof this.preferences.avoidTraffic === 'function') ? this.preferences.avoidTraffic() : this.preferences.avoidTraffic);
}
if (this.preferences.avoidBikingHillFactor) {
this.defaultRoute.setAvoidBikingHillFactor((typeof this.preferences.avoidBikingHillFactor === 'function') ? this.preferences.avoidBikingHillFactor() : this.preferences.avoidBikingHillFactor);
}
if (this.preferences.transportMode) {
this.defaultRoute.setTransportMode((typeof this.preferences.transportMode === 'function') ? this.preferences.transportMode() : this.preferences.transportMode);
}
if (this.preferences.buildTerrainProfile) {
this.defaultRoute.setBuildTerrainProfile((typeof this.preferences.buildTerrainProfile === 'function') ? this.preferences.buildTerrainProfile() : this.preferences.buildTerrainProfile);
}
if (this.preferences.pathAlgorithm) {
this.defaultRoute.setPathAlgorithm((typeof this.preferences.pathAlgorithm === 'function') ? this.preferences.pathAlgorithm() : this.preferences.pathAlgorithm);
}
if (this.preferences.resultDetails) {
this.defaultRoute.setResultDetails((typeof this.preferences.resultDetails === 'function') ? this.preferences.resultDetails() : this.preferences.resultDetails);
}
if (this.preferences.routeRanges) {
this.defaultRoute.setRouteRanges((typeof this.preferences.routeRanges === 'function') ? this.preferences.routeRanges() : this.preferences.routeRanges);
}
if (this.preferences.bikeProfile) {
if (this.preferences.eBikeProfile)
this.defaultRoute.setBikeProfileWithElectricType((typeof this.preferences.routeRanges === 'function') ? this.preferences.bikeProfile() : this.preferences.bikeProfile, (typeof this.preferences.eBikeProfile === 'function') ? this.preferences.eBikeProfile() : this.preferences.eBikeProfile);
else
this.defaultRoute.setBikeProfile((typeof this.preferences.routeRanges === 'function') ? this.preferences.bikeProfile() : this.preferences.bikeProfile);
}
}
this.mapView.registerRouteClickedEvent(this.routeSelectedCallback.bind(this), this.defaultRoute);
if (this.departureWaypoint) {
this.defaultRoute.addWaypoint(this.departureWaypoint);
} else {
this.defaultRoute.addWaypoint(gem.core.App.getLastKnownPosition());
}
(this.destinationWaypoint.m_landmark === undefined) ? this.defaultRoute.addWaypoint(this.destinationWaypoint) : this.defaultRoute.addWaypointFromLandmark(this.destinationWaypoint);
this.defaultRoute.calculateRoute(this.routeCallback.bind(this));
}
initControl(parentDiv, mapView) {
this.parentDiv = parentDiv;
this.mapView = mapView;
if (this.controlMode === undefined)
this.computeRoute();
}
addDestination(destination) {
this.destinationWaypoint = destination;
}
addDeparture(departure) {
this.departureWaypoint = departure;
}
addWaypoint() {
}
clearWaypoints() {
}
}
/**
* @callback callbackMarker
* @param {string} properties - marker item properties
*/
/**
* @callback callbackMarkerBubble
* @param {HTMLDivElement} elMarkerBubble - html parent element
* @param {object} properties - properties json
* @param {gem.core.Coordinates} coords - WGS coordinates of the marker item
*/
/**
* @callback callbackMarkerGroup
* @param {number} groupsize - marker group size
*/
/** Base class for added data controls
* @class gem.control.AddedDataControl
* @memberof namespace:gem.control
*
* @param {object} whenToTriggerInit
* @param {object} loadingMethod
* @param {object} [dataOptions] - options for displaying data source items
* @param {object} dataOptions.marker - options for markers display on map
* @param {string} dataOptions.marker.cssClass - specify custom marker style rules
* @param {string} dataOptions.marker.highlightClass - specify selected marker custom highlight style rules
* @param {number} [dataOptions.marker.width = 20]
* @param {number} [dataOptions.marker.height = 20]
* @param {number} [dataOptions.marker.hoverWidth = 25]
* @param {number} [dataOptions.marker.hoverHeight = 25]
* @param {string} [dataOptions.marker.markerPos = 'center'] - where to place the marker relative to the item coordinate
* @param {callbackMarker} dataOptions.marker.markerFunction - fully customize marker appearance
* @param {object} dataOptions.markerBubble - options for styling the marker bubble on click/hover
* @param {string[]} dataOptions.markerBubble.title - data source properties to use for marker bubble title text
* @param {string} dataOptions.markerBubble.image - data source image url property to use for marker bubble image
* @param {number} [dataOptions.markerBubble.width = 240] - bubble width in px
* @param {number} [dataOptions.markerBubble.height = 200] - bubble height in px
* @param {bool} [dataOptions.markerBubble.enableHover = true] - disable marker bubble interaction on hover
* @param {bool} [dataOptions.markerBubble.enableClick = true] - disable marker bubble interaction on click
* @param {string} dataOptions.markerBubble.markerBubbleClass - custom css class for marker bubble
* @param {callbackMarkerBubble} dataOptions.markerBubble.markerBubbleFunction - fully customize marker bubble
* @param {object} dataOptions.markerGrouping - marker grouping options
* @param {number} [dataOptions.markerGrouping.maxLevel = 13] - maximum map level to apply grouping ( max allowed 15 ), not available for studio data
* @param {object} [dataOptions.markerGrouping.style = gem.control.MarkersGroupStyleType.default] - style to apply to marker groups
* @param {callbackMarkerGroup} [dataOptions.markerGrouping.markerGroupFunction] - fully customize marker groups style
* @param {bool} [dataOptions.disableZoomToData = false ] - disables zooming to the data source area at start-up
*/
gem.control.AddedDataControl = class AddedDataControl extends gem.control.BaseControl {
constructor(whenToTriggerInit, loadingMethod, dataOptions) {
super(whenToTriggerInit);
this.loadingMethod = loadingMethod;
this.visibilityCallbacks = new Array();
this.selectedItemClass = 'gem-marker-selected';
// added data source options defaults
let defaultOptions = {
marker: {
cssClass: 'gem-marker',
highlightClass: 'gem-highlight-icon',
width: 20,
height: 20,
hoverWidth: 25,
hoverHeight: 25,
markerPos: 'center',
markerFunction: undefined /*function (jsonItemProperties)*/
},
markerBubble: {
title: [''],
image: [''],
width: 240,
height: 200,
enableHover: true,
enableClick: true,
markerBubbleClass: 'gem-marker-bubble',
markerBubbleFunction: undefined /*function (elMarkerBubble, properties, coords)*/
},
markerGrouping: {
maxLevel: 13,
style: gem.control.MarkersGroupStyleType.default,
markerGroupFunction: undefined /*function(groupsize)*/
},
disableZoomToData: false
};
this.options = Object.assign({}, defaultOptions, dataOptions);
if (dataOptions && dataOptions.marker)
this.options.marker = Object.assign({}, defaultOptions.marker, dataOptions.marker);
if (dataOptions && dataOptions.markerBubble)
this.options.markerBubble = Object.assign({}, defaultOptions.markerBubble, dataOptions.markerBubble);
if (dataOptions && dataOptions.markerGrouping)
this.options.markerGrouping = Object.assign({}, defaultOptions.markerGrouping, dataOptions.markerGrouping);
// set max grouping level to 15
if (this.options.markerGrouping.maxLevel > 15)
this.options.markerGrouping.maxLevel = 15;
this.rendererOptions = {
markerWidth: this.options.marker.width,
markerHeight: this.options.marker.height,
markerHoverWidth: this.options.marker.hoverWidth,
markerHoverHeight: this.options.marker.hoverHeight,
markerPos: this.options.marker.markerPos,
markerFunction: this.options.marker.markerFunction,
markerGroupStyle: this.options.markerGrouping.style,
markerGroupFunction: this.options.markerGrouping.markerGroupFunction
}
}
cameraChangedCallback() {
if (this.mCameraCallback) {
this.mCameraCallback();
}
}
mouseClick(item, jsonObject, position) {
// deactivate other store list items
let activeListing = document.getElementsByClassName('active');
if (activeListing[0]) {
activeListing[0].classList.remove('active');
}
}
mouseOver(item, jsonObject, position) {
if (!this.options.markerBubble.enableHover)
return;
if (item.lastChild && item.lastChild.id === this.options.markerBubble.markerBubbleClass)
return;
// hide selected bubble
if (this.selectedItem) {
let selectedBubble = this.selectedItem.getElementsByClassName(this.options.markerBubble.markerBubbleClass);
if (selectedBubble && selectedBubble.length)
selectedBubble[0].style.visibility = 'hidden';
}
// mouse over on top of selected item
item.style.zIndex = gem.control.zIndex.markerHover;
if (this.options.markerBubble.markerBubbleFunction) {
let bubble = document.createElement('div');
bubble.id = this.options.markerBubble.markerBubbleClass;
bubble.className = this.options.markerBubble.markerBubbleClass;
this.options.markerBubble.markerBubbleFunction(bubble, jsonObject, position);
item.append(bubble);
} else {
let bubble = this.createMarkerBubble(item, jsonObject);
if (bubble)
item.appendChild(bubble);
}
}
mouseOut(item) {
if (!this.options.markerBubble.enableHover)
return;
try {
if (item.lastChild !== undefined && item.lastChild.classList.contains(this.options.markerBubble.markerBubbleClass))
item.removeChild(item.lastChild);
// remove z-index
item.style.zIndex = gem.control.zIndex.none;
// show selected bubble
if (this.selectedItem) {
let selectedBubble = this.selectedItem.getElementsByClassName(this.options.markerBubble.markerBubbleClass);
if (selectedBubble && selectedBubble.length)
selectedBubble[0].style.visibility = '';
}
} catch (err) { }
}
formatJson(p) {
let outputString = "";
if (this.popupProperties) {
for (let i = 0; i < this.popupProperties.length; i++) {
let key = this.popupProperties[i];
if (p.hasOwnProperty(key)) {
if (p[key].includes(",")) {
outputString += "<span>" + (key + ": " + p[key].replace(",", ", ")) + "<span />" + "<br />";
} else {
outputString += "<span>" + (key + ": " + p[key]) + "<span />" + "<br />";
}
}
}
} else {
for (var key in p) {
if (p.hasOwnProperty(key)) {
if (typeof p[key] === 'string' || p[key] instanceof String) {
if (p[key].includes("http")) {
if (p[key].includes(".jpg") || p[key].includes(".png")) {
outputString += "<img src=" + p[key] + " style='max-width: 100%'> </img>";
}
} else {
if (p[key].includes(",")) {
outputString += "<span>" + (key + ": " + p[key].replace(",", ", ")) + "</span>" + "</br>";
} else {
outputString += "<span>" + (key + ": " + p[key]) + "</span>" + "</br>";
}
}
}
}
}
}
return outputString;
}
getItemsList() {
}
getItemsSource() {
}
registerListChangedNotifier(notifier) {
this.listChangedNotifier = notifier;
}
registerListChangedFilterNotifier(notifier) {
this.listChangedFilterNotifier = notifier;
}
registerListLoadingOnNotifier(notifier) {
this.listLoadingNotifier = notifier;
}
registerListLoadingOffNotifier(notifier) {
this.listLoadingDoneNotifier = notifier;
}
registerItemAddedNotifier(notifier) {
this.itemAddedNotifier = notifier;
}
registerItemRemovedNotifier(notifier) {
this.itemRemovedNotifier = notifier;
}
setPointOfInterestAndRadius(coords, radius) {
this.centerPoint = coords;
this.radius = radius;
}
notifySearchSelection(item) {
}
requestFieldValues(key, callback) {
}
registerVisibilityNotifier(callback) {
this.visibilityCallbacks.push(callback);
}
notifyVisibility(value) {
for (let i = 0; i < this.visibilityCallbacks.length; i++) {
this.visibilityCallbacks[i](value);
}
}
setControlMode(mode) {
}
notifyChangeFilterData(type, name, values) {
}
notifyAreaSelection(area, areaMarkerGroupMaxLevel = this.options.markerGrouping.maxLevel) {
}
preRenderCallback() {
if (this.selectedItem && this.externalRenderObj && this.externalRenderObj.selectedItem) {
let item = document.getElementById(this.externalRenderObj.selectedItem.id);
if (item)
item.style.display = 'none';
let coordsPoint = this.externalRenderObj.selectedItem.coordinates;
let screenCoords = this.mapView.transformWgsToScreen(coordsPoint);
let pos = this.externalRenderObj.getMarkerPos(this.externalRenderObj.options.markerPos, screenCoords, this.externalRenderObj.options.markerWidth, this.externalRenderObj.options.markerHeight);
this.selectedItem.style.transform = "translate3d(" + pos.dx + "px," + pos.dy + "px,0px)";
}
}
itemSelected(item) {
if (this.selectedItem) {
this.selectedItem.remove();
let item = document.getElementById(this.selectedItemObj.id);
if (item)
item.style.display = '';
}
this.mapView.registerOnTouchEvent(function (coords) {
if (this.selectedItem) {
this.selectedItem.remove();
let item = document.getElementById(this.selectedItemObj.id);
if (item)
item.style.display = '';
this.selectedItem = undefined;
if (this.itemSelectionNotifier)
this.itemSelectionNotifier();
}
}.bind(this));
this.selectedItem = item.cloneNode();
this.selectedItemObj = this.externalRenderObj.selectedItem;
this.selectedItem.id = "selectedItem";
this.selectedItem.className = this.selectedItemClass;
this.selectedItem.style.pointerEvents = 'none';
this.selectedItem.style.zIndex = gem.control.zIndex.markerSelected;
item.style.display = 'none';
var event = new MouseEvent('mouseout', {
'view': window,
'bubbles': true,
'cancelable': true
});
item.dispatchEvent(event);
let prevBubble = this.selectedItem.getElementsByClassName(this.options.markerBubble.markerBubbleClass);
if (prevBubble && prevBubble.length)
prevBubble[0].remove();
let jsonProps = {};
if (this.selectedItemObj.info.properties)
jsonProps = this.selectedItemObj.info.properties;
else if (this.selectedItemObj.info.parameters) {
for (const param of this.selectedItemObj.info.parameters.keyvals) {
jsonProps[param.key] = param.value;
}
}
if (this.options.markerBubble.enableClick) {
if (this.options.markerBubble.markerBubbleFunction) {
let selectedBubble = document.createElement('div');
selectedBubble.id = this.options.markerBubble.markerBubbleClass;
selectedBubble.className = this.options.markerBubble.markerBubbleClass;
this.options.markerBubble.markerBubbleFunction(selectedBubble, jsonProps, this.selectedItemObj.coordinates);
this.selectedItem.appendChild(selectedBubble);
} else {
let selectedBubble = this.createMarkerBubble(this.selectedItem, jsonProps);
if (selectedBubble)
this.selectedItem.appendChild(selectedBubble);
}
}
// highlight selected item image
let elHighlightImage = this.selectedItem.appendChild(document.createElement('div'));
elHighlightImage.className = item.className;
elHighlightImage.classList.add(this.options.marker.highlightClass);
item.parentElement.appendChild(this.selectedItem);
// add item children if there are any
if (item.firstChild) {
let itemChildren = item.firstChild.cloneNode(true);
if (itemChildren)
elHighlightImage.appendChild(itemChildren);
}
if (this.itemSelectionNotifier)
this.itemSelectionNotifier(this.selectedItemObj);
}
registerItemSelectionListener(callback) {
this.itemSelectionNotifier = callback;
}
createMarkerBubble(item, jsonProperties) {
// validate bubble options
if (!this.options || !this.options.markerBubble)
return;
let optionsBubble = this.options.markerBubble;
if (!optionsBubble.title.length && !optionsBubble.image.length)
return this.createDefaultBubble(item, jsonProperties);
if (!optionsBubble.title[0].length && !optionsBubble.image[0].length)
return this.createDefaultBubble(item, jsonProperties);
let bubble = document.createElement('div');
bubble.style.height = 'auto';
bubble.style.width = this.options.markerBubble.width + "px";
bubble.id = this.options.markerBubble.markerBubbleClass;
bubble.className = this.options.markerBubble.markerBubbleClass;
// image
let imgUrl = jsonProperties ? jsonProperties[this.options.markerBubble.image] : undefined;
if (imgUrl) {
let elImgContainer = document.createElement('div');
elImgContainer.className = 'gem-popup-img-container';
let elImg = document.createElement('img');
elImg.className = 'gem-popup-img';
elImg.onload = () => {
elImgContainer.appendChild(elImg);
bubble.style.height = this.options.markerBubble.height + "px";
};
elImg.onerror = () => {
bubble.style.height = 'auto';
};
elImg.src = imgUrl;
bubble.appendChild(elImgContainer);
} else {
bubble.style.height = 'auto';
}
// text container
let popUpTextContainer = document.createElement('div');
popUpTextContainer.className = 'gem-marker-bubble-text';
// title
let popUpTitle = document.createElement('div');
popUpTitle.className = 'gem-marker-bubble-title';
popUpTitle.textContent = this.getPropertyString(jsonProperties, this.options.markerBubble.title, ',');
if (!popUpTitle.textContent.length)
return undefined;
popUpTextContainer.appendChild(popUpTitle);
bubble.appendChild(popUpTextContainer);
this.adjustBubbleLocation(item, bubble, this.options.markerBubble.height, this.options.markerBubble.width, imgUrl ? true : false);
return bubble;
}
createDefaultBubble(item, jsonObject) {
let bubble = document.createElement('div');
bubble.id = this.options.markerBubble.markerBubbleClass;
bubble.classList = this.options.markerBubble.markerBubbleClass;
bubble.style.width = this.options.markerBubble.width + "px";
bubble.style.height = this.options.markerBubble.height + "px";
let popupText = bubble.appendChild(document.createElement('div'));
popupText.className = 'gem-marker-bubble-text';
let popupDetails = popupText.appendChild(document.createElement('div'));
popupDetails.className = 'gem-marker-bubble-details';
popupDetails.innerHTML = this.formatJson(jsonObject);
let imgUrl = jsonObject[this.imageProperty];
if (imgUrl) {
let elImgContainer = document.createElement('div');
elImgContainer.className = 'gem-popup-img-container';
let elImg = document.createElement('img');
elImg.className = 'gem-popup-img';
elImg.src = imgUrl;
elImgContainer.appendChild(elImg);
bubble.appendChild(elImgContainer);
} else {
bubble.style.height = 'auto';
}
this.adjustBubbleLocation(item, bubble, this.options.markerBubble.height, this.options.markerBubble.width, imgUrl ? true : false);
return bubble;
}
adjustBubbleLocation(item, bubble, bubbleHeight, bubbleWidth, hasImage) {
let mapCanvas = document.getElementById(gem.core.App.initOptions.container);
let itemTransform = item.style.transform;
let arrTransform = itemTransform.match(/\d+([\.,]\d+)?/g).map(Number);
let itemX;
let itemY;
if (itemTransform.indexOf('translate3d') > -1) {
itemX = arrTransform[1];
itemY = arrTransform[2];
} else if (itemTransform.indexOf('translate') > -1) {
itemX = arrTransform[0];
itemY = arrTransform[1];
}
if (!itemX || !itemY) {
bubble.classList.add('gem-marker-bubble--top-center');
bubble.style.marginLeft = "-" + (this.options.markerBubble.width / 2) + "px";
return bubble;
}
if (itemY < bubbleHeight) {
if (itemX < bubbleWidth / 2)
bubble.classList.add('gem-marker-bubble--bottom-right');
else if (itemX > mapCanvas.offsetWidth - bubbleWidth / 2)
bubble.classList.add('gem-marker-bubble--bottom-left');
else {
bubble.classList.add('gem-marker-bubble--bottom-center');
bubble.style.marginLeft = "-" + (this.options.markerBubble.width / 2) + "px";
}
} else if (itemX < bubbleWidth / 2) {
if (itemY > mapCanvas.offsetHeight - bubbleHeight / 2)
bubble.classList.add('gem-marker-bubble--top-right');
else {
if (hasImage)
bubble.classList.add('gem-marker-bubble--right-center');
else
bubble.classList.add('gem-marker-bubble-no-img--right-center');
}
} else if (itemX > mapCanvas.offsetWidth - bubbleWidth / 2) {
if (itemY > mapCanvas.offsetHeight - bubbleHeight / 2)
bubble.classList.add('gem-marker-bubble--top-left');
else {
if (hasImage)
bubble.classList.add('gem-marker-bubble--left-center');
else
bubble.classList.add('gem-marker-bubble-no-img--left-center');
}
} else {
bubble.classList.add('gem-marker-bubble--top-center');
bubble.style.marginLeft = "-" + (this.options.markerBubble.width / 2) + "px";
}
}
getPropertyString(markerProps, arrProperties, separator = ', ') {
if (!markerProps)
return;
let stringProperty = '';
for (let i = 0; i < arrProperties.length; i++) {
let propValue = markerProps[arrProperties[i]];
if (propValue && propValue.length) {
stringProperty += propValue;
if (stringProperty.length > 0 && i < arrProperties.length - 1)
stringProperty += separator;
}
}
return stringProperty;
}
checkFiltersOnJsonProperties(jsonProperties, filtersMap) {
let filtersCount = filtersMap.size;
for (const [name, filters] of filtersMap.entries()) {
if (filters) {
for (let i = 0; i < filters.length; i++) {
if (!filters[i].key.length) {
filtersCount--;
continue;
}
let prop = jsonProperties[filters[i].key];
if (prop) {
if (!filters[i].value.length)
filtersCount--;
else if (prop == filters[i].value)
filtersCount--;
}
if (filtersCount <= 0)
return true;
}
if (!filters.length)
filtersCount--;
}
}
return filtersCount <= 0;
}
iconFilter(item) {
try {
let jsonBuffer = JSON.parse(item.getInfo());
let jsonProperties = {};
if (jsonBuffer.properties)
jsonProperties = jsonBuffer.properties;
else if (jsonBuffer.parameters) {
for (const param of jsonBuffer.parameters.keyvals) {
jsonProperties[param.key] = param.value;
}
}
for (let i = 0; i < this.iconFilter.length; i++) {
let propValue = jsonProperties[this.iconFilter[i].key];
if (propValue && propValue.length) {
if (propValue.includes(this.iconFilter[i].value))
return this.iconFilter[i].iconClass;
}
}
} catch (e) {
}
return this.options.marker.cssClass;
}
}
/** Control for displaying data from a Studio defined data source
* @class gem.control.StudioAddedDataControl
* @memberof gem.control
*
* @param {string} layerMarkersId - studio defined data source id
* @param {string} iconLocation - path/url to marker image
* @param {object} dataOptions - options for displaying data source items
* @param {object} dataOptions.marker - options for markers display on map
* @param {string} dataOptions.marker.cssClass - specify custom marker style rules
* @param {string} dataOptions.marker.highlightClass - specify selected marker custom highlight style rules
* @param {number} [dataOptions.marker.width = 20]
* @param {number} [dataOptions.marker.height = 20]
* @param {number} [dataOptions.marker.hoverWidth = 25]
* @param {number} [dataOptions.marker.hoverHeight = 25]
* @param {string} [dataOptions.marker.markerPos = 'center'] - where to place the marker relative to the item coordinate
* @param {callbackMarker} dataOptions.marker.markerFunction - fully customize marker appearance
* @param {object} dataOptions.markerBubble - options for styling the marker bubble on click/hover
* @param {string[]} dataOptions.markerBubble.title - data source properties to use for marker bubble title text
* @param {string} dataOptions.markerBubble.image - data source image url property to use for marker bubble image
* @param {number} [dataOptions.markerBubble.width = 240] - bubble width in px
* @param {number} [dataOptions.markerBubble.height = 200] - bubble height in px
* @param {bool} [dataOptions.markerBubble.enableHover = true] - disable marker bubble interaction on hover
* @param {bool} [dataOptions.markerBubble.enableClick = true] - disable marker bubble interaction on click
* @param {string} dataOptions.markerBubble.markerBubbleClass - custom css class for marker bubble
* @param {callbackMarkerBubble} dataOptions.markerBubble.markerBubbleFunction - fully customize marker bubble
* @param {object} dataOptions.markerGrouping - marker grouping options
* @param {object} [dataOptions.markerGrouping.style = gem.control.MarkersGroupStyleType.default] - style to apply to marker groups
* @param {callbackMarkerGroup} [dataOptions.markerGrouping.markerGroupFunction] - fully customize marker groups style
* @param {object[]} [iconFilter] - filters for applying different icons to markers based on their properties
* @param {string} iconFilter[].key - data source item property key
* @param {string} iconFilter[].value - data source item property value
* @param {string} iconFilter[].iconClass - css class to use for this filter
*/
gem.control.StudioAddedDataControl = class StudioAddedDataControl extends gem.control.AddedDataControl {
constructor(layerMarkersId, iconLocation, dataOptions, iconFilter) {
super(gem.control.TConntrolExecuteType.STYLE, gem.control.TConntrolItemUpdateMode.INDIVIDUAL, dataOptions);
this.layerMarkersId = layerMarkersId;
this.iconLocation = iconLocation;
this.itemsMap = new Map();
if (iconFilter) {
this.iconFilter = iconFilter;
this.iconLocation = super.iconFilter.bind(this);
}
this.mouseOver = super.mouseOver;
this.mouseOut = super.mouseOut;
this.mouseClick = function (item, jsonObject, position) {
return false;
};
}
initControl(parentDiv, mapView) {
this.mapView = mapView;
// The markers on the map are shown using the icon.svg file which is
// located in the same directory as this JavaScript code
this.externalRenderObj = new gem.d3Scene.ExternalRendererMarkers(
this.iconLocation, "myCollection", mapView, parentDiv, this.options.marker.cssClass, this.rendererOptions);
this.externalRenderObj.registerMouseOverCallback(this.mouseOver.bind(this));
this.externalRenderObj.registerMouseOutCallback(this.mouseOut.bind(this));
this.externalRenderObj.registerMouseClickCallback(this.mouseClick.bind(this));
this.externalRenderObj.registerItemAddedCallback(function (itemElementHtmlId, item, itemId, isGroup) {
return this.addItemToList(itemElementHtmlId, item, itemId, isGroup);
}.bind(this));
this.externalRenderObj.registerItemRemovedCallback(function (itemElementHtmlId, item, itemId) {
this.removeItemFromList(itemElementHtmlId, item, itemId);
}.bind(this));
if (this.selectedItemClass)
this.externalRenderObj.registerItemSelectedCallback(this.itemSelected.bind(this));
mapView.enableOverlayItemWithExternalRendering(this.layerMarkersId, this.externalRenderObj);
let cameraMovedCallback = function () {
this.mapView.registerForNextRenderFinished(this.filterData.bind(this));
}
this.canShowData = true;
this.mCameraCallback = cameraMovedCallback.bind(this);
if (this.controlMode && this.controlMode != 'automatic') {
this.notifyVisibility('hidden');
this.canShowData = false;
return;
}
}
addItemToList(itemElementHtmlId, item, itemId, isGroup) {
let it = this.itemsMap.get(itemId);
if (item)
item.cacheData();
let visible = true;
if (!this.checkFilters(item)) {
let pt = document.getElementById(itemElementHtmlId + itemId);
if (pt)
pt.style.visibility = 'hidden';
visible = false;
} else {
let pt = document.getElementById(itemElementHtmlId + itemId);
if (pt)
pt.style.visibility = 'visible';
visible = true;
}
if (it === undefined) {
this.itemsMap.set(itemId, {
marker: item,
isGroup: isGroup,
visible: visible,
itemElementHtmlId: itemElementHtmlId
});
} else {
it.visible = visible;
}
if (!this.hasSearchSelection)
this.mapView.registerForNextRenderFinished(this.filterData.bind(this));
}
checkFilters(item) {
if (!this.canShowData)
return false;
if (this.centerPoint && this.radius) {
let distance = gem.core.App.getDistanceBetween2Coordinates(item.getCoordinates(), this.centerPoint);
if (distance > this.radius) {
return false;
}
}
if (this.filtersMap && this.filtersMap.size) {
try {
let jsonBuffer = JSON.parse(item.getInfo());
if (jsonBuffer.parameters && jsonBuffer.parameters.keyvals) {
let jsonProperties = {};
for (const param of jsonBuffer.parameters.keyvals) {
jsonProperties[param.key] = param.value;
}
return super.checkFiltersOnJsonProperties(jsonProperties, this.filtersMap);
}
} catch (e) {
return false;
}
}
return true;
}
notifySearchSelection(item) {
this.hasSearchSelection = true;
if (item === undefined) {
this.notifyVisibility('hidden');
this.canShowData = false;
this.filterData();
this.itemsMap.clear();
if (this.selectedItem) {
this.selectedItem.remove();
this.selectedItem = undefined;
}
return;
}
if (this.selectedItem) {
this.selectedItem.remove();
this.selectedItem = undefined;
}
this.itemsMap.clear();
this.notifyVisibility('visible');
this.canShowData = true;
if (this.radius === undefined)
this.radius = 10000;
this.setPointOfInterestAndRadius(item.getCoordinates(), this.radius);
}
filterData() {
let filteredMap = new Map();
function logMapElements(value, key, map) {
if (!this.checkFilters(value.marker)) {
let pt = document.getElementById(value.itemElementHtmlId + key);
if (pt)
pt.style.visibility = 'hidden';
value.visible = false;
} else {
let pt = document.getElementById(value.itemElementHtmlId + key);
if (pt)
pt.style.visibility = 'visible';
value.visible = true;
}
if (value.visible)
filteredMap.set(key, value);
}
this.itemsMap.forEach(logMapElements.bind(this));
if (this.listChangedNotifier)
this.listChangedNotifier(filteredMap, this.externalRenderObj.name, this.mapView);
}
removeItemFromList(itemElementHtmlId, item, itemId) {
if (!this.hasSearchSelection) {
this.itemsMap.delete(itemId);
this.mapView.registerForNextRenderFinished(this.filterData.bind(this));
}
}
/**
*
* @param {gem.core.Coordinates} coords
* @param {number} radius - radius in meters
*/
setPointOfInterestAndRadius(coords, radius) {
this.centerPoint = coords;
this.radius = radius;
this.geographicList = new gem.core.RectangleGeographicAreaList();
let geographicArea = new Module.RectangleGeographicArea();
let offset = (this.radius / 6371000) * 57.295779513;
let topLeft = {
latitude: this.centerPoint.latitude + offset,
longitude: this.centerPoint.longitude - offset,
altitude: this.centerPoint.altitude,
bearing: this.centerPoint.bearing
};
let bottomRight = {
latitude: this.centerPoint.latitude - offset,
longitude: this.centerPoint.longitude + offset,
altitude: this.centerPoint.altitude,
bearing: this.centerPoint.bearing
};
geographicArea.setTopLeft(topLeft);
geographicArea.setBottomRight(bottomRight);
this.geographicList.push_back(geographicArea);
this.mapView.centerOnArea(topLeft, bottomRight, 0);
this.filterData();
}
cameraChangedCallback() {
if (this.mCameraCallback) {
this.mCameraCallback();
}
}
notifyChangeFilterData(type, name, values) {
switch (type) {
case 'distance': {
this.radius = parseFloat(values) * 1000;
if (this.centerPoint)
this.setPointOfInterestAndRadius(this.centerPoint, this.radius);
break;
}
case 'category': {
if (!this.filtersMap)
this.filtersMap = new Map();
this.filtersMap.set(name, values);
this.filterData();
break;
}
}
}
setControlMode(mode) {
this.controlMode = mode;
}
}
/**
* @class gem.core.AppScreen
*@memberof gem.core
*/
gem.core.AppScreen = class AppScreen {
constructor(container) {
this.controlsStyleArray = new Array();
this.controlsOnConnectedArray = new Array();
this.connectionChangedArray = new Array();
this.container = container;
}
registerOnConnectionChangedCallback(cb) {
this.connectionChangedArray.push(cb);
}
initFinished() {
gem.core.App.registerConnectionStatusChanged(function (online) {
// Search requires a network connection, so check if online
if (online) {
let i;
for (i = 0; i < this.controlsOnConnectedArray.length; i++) {
this.controlsOnConnectedArray[i].initControl(this.container, this.defaultMap);
}
for (i = 0; i < this.connectionChangedArray.length; i++) {
this.connectionChangedArray[i](online);
}
}
}.bind(this));
this.defaultScreen = gem.core.App.getDefaultScreen();
this.defaultMap = this.defaultScreen.getDefaultMapView();
this.defaultMap.registerStyleUpdateFinishedCallback(function () {
let i;
for (i = 0; i < this.controlsStyleArray.length; i++) {
this.controlsStyleArray[i].initControl(this.container, this.defaultMap);
}
}.bind(this));
this.defaultMap.registerCameraChangeStateCallback(
function (camState) {
if (camState != 0)
return;
let i = 0;
for (i = 0; i < this.controlsOnConnectedArray.length; i++) {
this.controlsOnConnectedArray[i].cameraChangedCallback();
}
for (i = 0; i < this.controlsStyleArray.length; i++) {
this.controlsStyleArray[i].cameraChangedCallback();
}
}.bind(this)
)
Module.registerPostRenderCallback(
function () {
let i = 0;
for (i = 0; i < this.controlsOnConnectedArray.length; i++) {
this.controlsOnConnectedArray[i].preRenderCallback();
}
for (i = 0; i < this.controlsStyleArray.length; i++) {
this.controlsStyleArray[i].preRenderCallback();
}
}.bind(this)
);
}
/**
*
* @param {gem.control.BaseControl} pControl
*/
addControl(pControl) {
if (this.defaultMap !== undefined) {
pControl.initControl(this.container, this.defaultMap);
} else {
switch (pControl.getType()) {
case gem.control.TConntrolExecuteType.STYLE:
this.controlsStyleArray.push(pControl);
break;
case gem.control.TConntrolExecuteType.ONCONNECTED:
this.controlsOnConnectedArray.push(pControl);
break;
}
}
}
}
/**
* Control for displaying data from a GeoJSON source
* @class gem.control.GeoJsonAddedDataControl
* @memberof gem.control
*
* @param {string} geoJsonFileOrObject - GeoJSON data file path/url or string object
* @param {string} iconLocation - path/url to marker image/icon
* @param {object[]} [iconFilter] - filters for applying different icons to markers based on their properties
* @param {string} iconFilter[].key - data source item property key
* @param {string} iconFilter[].value - data source item property value
* @param {string} iconFilter[].iconClass - css class to use for this filter
* @param {object} [dataOptions] - options for displaying data source items
* @param {object} dataOptions.marker - options for markers display on map
* @param {string} [dataOptions.marker.cssClass] - specify custom marker style rules
* @param {string} [dataOptions.marker.highlightClass] - specify selected marker custom highlight style rules
* @param {number} [dataOptions.marker.width = 20]
* @param {number} [dataOptions.marker.height = 20]
* @param {number} [dataOptions.marker.hoverWidth = 25]
* @param {number} [dataOptions.marker.hoverHeight = 25]
* @param {string} [dataOptions.marker.markerPos = 'center'] - where to place the marker relative to the item coordinate
* @param {callbackMarker} dataOptions.marker.markerFunction - fully customize marker appearance
* @param {object} dataOptions.markerBubble - options for styling the marker bubble on click/hover
* @param {string[]} dataOptions.markerBubble.title - data source properties to use for marker bubble title text
* @param {string} dataOptions.markerBubble.image - data source image url property to use for marker bubble image
* @param {number} [dataOptions.markerBubble.width = 240] - bubble width in px
* @param {number} [dataOptions.markerBubble.height = 200] - bubble height in px
* @param {bool} [dataOptions.markerBubble.enableHover = true] - disable marker bubble interaction on hover
* @param {bool} [dataOptions.markerBubble.enableClick = true] - disable marker bubble interaction on click
* @param {string} [dataOptions.markerBubble.markerBubbleClass] - custom css class for marker bubble
* @param {callbackMarkerBubble} [dataOptions.markerBubble.markerBubbleFunction] - fully customize marker bubble
* @param {object} [dataOptions.markerGrouping] - marker grouping options
* @param {number} [dataOptions.markerGrouping.maxLevel = 13] - maximum map level to apply grouping ( max allowed 15 )
* @param {object} [dataOptions.markerGrouping.style = gem.control.MarkersGroupStyleType.default] - style to apply to marker groups
* @param {callbackMarkerGroup} [dataOptions.markerGrouping.markerGroupFunction] - fully customize marker groups style
* @param {bool} [dataOptions.disableZoomToData = false ] - disables zooming to the data source area at start-up
*/
gem.control.GeoJsonAddedDataControl = class GeoJsonAddedDataControl extends gem.control.AddedDataControl {
constructor(geoJsonFileOrObject, iconLocation, iconFilter, dataOptions) {
super(gem.control.TConntrolExecuteType.ONCONNECTED, gem.control.TConntrolItemUpdateMode.LIST, dataOptions);
if (typeof geoJsonFileOrObject === 'string' && geoJsonFileOrObject.substring(geoJsonFileOrObject.length - 4).toUpperCase() === 'JSON')
this.geojsonFile = geoJsonFileOrObject;
else
this.geoJsonString = geoJsonFileOrObject;
this.iconLocation = iconLocation;
if (iconFilter) {
this.iconFilter = iconFilter;
this.iconLocation = super.iconFilter.bind(this);
}
this.mouseOver = super.mouseOver;
this.mouseOut = super.mouseOut;
this.mouseClick = super.mouseClick;
}
doParseData(parentDiv, mapView) {
// The markers on the map are shown using the icon.svg file which is
// located in the same directory as this JavaScript code
mapView.addGeoJsonAsCustomMarkers(JSON.stringify(this.geoJsonString),
this.controlName, this.tvectorSources, this.externalRenderObj, this.options.markerGrouping.maxLevel);
if (!this.options.disableZoomToData) {
let sourceArea = this.tvectorSources.get(0).getArea();
if (!sourceArea.isEmpty) {
// adjust center on rectangle
const viewBuffer = 50;
let viewRectangle = mapView.getViewport();
viewRectangle.x += viewBuffer;
viewRectangle.y += viewBuffer;
viewRectangle.width -= 2 * viewBuffer;
viewRectangle.height -= 2 * viewBuffer;
mapView.centerOnArea(sourceArea.leftTop, sourceArea.rightBottom, 0, viewRectangle);
}
else
{
// may be the case of a single point
if(this.tvectorSources.size()==1)
{
let markerColl = this.tvectorSources.get(0);
if(markerColl.size() == 1)
{
let marker = markerColl.getMarkerAt(0);
let coords = marker.getCoordinatesPartAt(0);
let coordsPoint = coords.get(0);
mapView.centerOnCoordinates(coordsPoint);
}
}
}
}
if (this.listChangedNotifier)
this.listChangedNotifier(this.externalRenderObj.name, mapView);
}
initControl(parentDiv, mapView) {
this.itemsMap = new Map();
this.mapView = mapView;
this.controlName = "geojsonAddedData";
this.tvectorSources = new gem.d3Scene.MarkerCollectionRefList();
this.externalRenderObj = new gem.d3Scene.ExternalRenderer(
this.iconLocation, this.controlName, mapView, parentDiv, this.options.marker.cssClass, this.rendererOptions);
this.externalRenderObj.registerMouseOverCallback(this.mouseOver.bind(this));
this.externalRenderObj.registerMouseOutCallback(this.mouseOut.bind(this));
this.externalRenderObj.registerMouseClickCallback(this.mouseClick.bind(this));
if (this.selectedItemClass)
this.externalRenderObj.registerItemSelectedCallback(this.itemSelected.bind(this));
this.externalRenderObj.registerItemAddedCallback(function (itemElementHtmlId, item, itemId, isGroup) {
if (this.itemAddedNotifier) this.itemAddedNotifier(itemElementHtmlId, item, itemId, isGroup);
}.bind(this));
this.externalRenderObj.registerItemRemovedCallback(function (itemElementHtmlId, item, itemId) {
if (this.itemRemovedNotifier) this.itemRemovedNotifier(itemElementHtmlId, item, itemId);
}.bind(this));
let cameraMovedCallback = function () {
this.mapView.registerForNextRenderFinished(this.filterData.bind(this));
}
this.mCameraCallback = cameraMovedCallback.bind(this);
if (this.geojsonFile) {
fetch(this.geojsonFile)
.then(response => response.text())
.then(textData => JSON.parse(textData))
.then(jsonData => {
this.geoJsonString = jsonData;
this.doParseData(parentDiv, mapView);
});
} else
this.doParseData(parentDiv, mapView);
}
cameraChangedCallback() {
if (this.mCameraCallback)
this.mCameraCallback();
}
getItemsList() {
return this.tvectorSources.get(0);
}
getItemsSource() {
return this.tvectorSources.get(0);
}
itemAddedNotifier(itemElementHtmlId, item, itemId, isGroup) {
let it = this.itemsMap.get(itemId);
let visible = true;
let pt = document.getElementById(itemElementHtmlId + itemId);
if (!this.checkFilters(item)) {
if (pt)
pt.style.visibility = 'hidden';
visible = false;
} else {
if (pt)
pt.style.visibility = 'visible';
visible = true;
}
if (it === undefined) {
this.itemsMap.set(itemId, {
marker: item,
isGroup: isGroup,
visible: visible,
itemElementHtmlId: itemElementHtmlId
});
} else {
it.visible = visible;
it.marker = item;
it.isGroup = isGroup;
}
// get group children and filter
if (visible && isGroup) {
let source = this.getItemsList();
if (source) {
let children = source.getGroupItemsVector(String(itemId));
let childrenSize = children.size();
for (let i = 0; i < childrenSize; i++) {
let child = children.get(i);
//let id = child.getId();
//let childMarker = new gem.d3Scene.MarkerRef(child);
//if (!this.checkFilters(childMarker))
// childrenSize--;
//console.log(child);
}
//console.log("children size", childrenSize);
}
}
if (!this.hasSearchSelection)
this.mapView.registerForNextRenderFinished(this.filterData.bind(this));
}
itemRemovedNotifier(itemElementHtmlId, item, itemId) {
if (!this.hasSearchSelection) {
this.itemsMap.delete(itemId);
this.mapView.registerForNextRenderFinished(this.filterData.bind(this));
}
}
notifyChangeFilterData(type, name, values) {
switch (type) {
case 'distance':
this.radius = parseFloat(values) * 1000;
if (this.centerPoint)
this.setPointOfInterestAndRadius(this.centerPoint, this.radius);
break;
case 'category':
if (!this.filtersMap)
this.filtersMap = new Map();
this.filtersMap.set(name, values);
this.filterData();
break;
}
}
setPointOfInterestAndRadius(coords, radius) {
this.centerPoint = coords;
this.radius = radius;
this.geographicList = new gem.core.RectangleGeographicAreaList();
let geographicArea = new Module.RectangleGeographicArea();
let offset = (this.radius / 6371000) * 57.295779513;
let topLeft = {
latitude: this.centerPoint.latitude + offset,
longitude: this.centerPoint.longitude - offset,
altitude: this.centerPoint.altitude,
bearing: this.centerPoint.bearing
};
let bottomRight = {
latitude: this.centerPoint.latitude - offset,
longitude: this.centerPoint.longitude + offset,
altitude: this.centerPoint.altitude,
bearing: this.centerPoint.bearing
};
geographicArea.setTopLeft(topLeft);
geographicArea.setBottomRight(bottomRight);
this.geographicList.push_back(geographicArea);
this.mapView.centerOnArea(topLeft, bottomRight, 0);
this.filterData();
}
checkFilters(item) {
if (this.centerPoint && this.radius) {
let coords;
if (item)
coords = item.getCoordinatesAt(0).get(0);
let distance = gem.core.App.getDistanceBetween2Coordinates(coords, this.centerPoint);
if (distance > this.radius) {
return false;
}
}
if (this.filtersMap && this.filtersMap.size) {
try {
let jsonBuffer = JSON.parse(item.getInfo());
let jsonProperties = jsonBuffer.properties;
return super.checkFiltersOnJsonProperties(jsonProperties, this.filtersMap);
} catch (e) {
return false;
}
}
return true;
}
filterData() {
if (!this.filtersMap || !this.filtersMap.size)
return;
let filteredMap = new Map();
function logMapElements(value, key, map) {
if (!this.checkFilters(value.marker)) {
let pt = document.getElementById(value.itemElementHtmlId + key);
if (pt)
pt.style.visibility = 'hidden';
value.visible = false;
} else {
let pt = document.getElementById(value.itemElementHtmlId + key);
if (pt)
pt.style.visibility = 'visible';
value.visible = true;
}
if (value.visible)
filteredMap.set(key, value);
}
this.itemsMap.forEach(logMapElements.bind(this));
if (this.listChangedFilterNotifier)
this.listChangedFilterNotifier(filteredMap, this.externalRenderObj.name, this.mapView);
}
}
/** Control for displaying data from SQL server data source
* @class gem.control.QueryAddedDataControl
* @memberof gem.control
*
* @param {object} initQueryAddedDataOptions - options for initializing the SQL query source
* @param {string[]} initQueryAddedDataOptions.languages - list of language iso codes
* @param {number} initQueryAddedDataOptions.storeId - available options store id 1 or 2
* @param {string} iconLocation - path/url to marker image/icon
* @param {object} dataOptions - options for displaying data source items
* @param {object} [dataOptions.marker] - options for markers display on map
* @param {string} [dataOptions.marker.cssClass] - specify custom marker style rules
* @param {string} [dataOptions.marker.highlightClass] - specify selected marker custom highlight style rules
* @param {number} [dataOptions.marker.width = 20]
* @param {number} [dataOptions.marker.height = 20]
* @param {number} [dataOptions.marker.hoverWidth = 25]
* @param {number} [dataOptions.marker.hoverHeight = 25]
* @param {string} [dataOptions.marker.markerPos = 'center'] - where to place the marker relative to the item coordinate
* @param {callbackMarker} [dataOptions.marker.markerFunction] - fully customize marker appearance
* @param {object} dataOptions.markerBubble - options for styling the marker bubble on click/hover
* @param {string[]} dataOptions.markerBubble.title - data source properties to use for marker bubble title text
* @param {string} dataOptions.markerBubble.image - data source image url property to use for marker bubble image
* @param {number} [dataOptions.markerBubble.width = 240] - bubble width in px
* @param {number} [dataOptions.markerBubble.height = 200] - bubble height in px
* @param {bool} [dataOptions.markerBubble.enableHover = true] - disable marker bubble interaction on hover
* @param {bool} [dataOptions.markerBubble.enableClick = true] - disable marker bubble interaction on click
* @param {string} dataOptions.markerBubble.markerBubbleClass - custom css class for marker bubble
* @param {callbackMarkerBubble} dataOptions.markerBubble.markerBubbleFunction - fully customize marker bubble
* @param {object} dataOptions.markerGrouping - marker grouping options
* @param {number} dataOptions.markerGrouping.maxLevel - maximum map level to apply grouping ( max allowed 15 )
* @param {object} [dataOptions.markerGrouping.style = gem.control.MarkersGroupStyleType.default] - style to apply to marker groups
* @param {callbackMarkerGroup} [dataOptions.markerGrouping.markerGroupFunction] - fully customize marker groups style
*/
gem.control.QueryAddedDataControl = class QueryAddedDataControl extends gem.control.AddedDataControl {
constructor(initQueryAddedDataOptions, iconLocation, dataOptions) {
super(gem.control.TConntrolExecuteType.ONCONNECTED, gem.control.TConntrolItemUpdateMode.LIST, dataOptions);
this.iconLocation = iconLocation;
if (initQueryAddedDataOptions.languages)
this.languageList = initQueryAddedDataOptions.languages;
else
this.languageList = ["en"];
if (initQueryAddedDataOptions.storeId) {
this.storeId = initQueryAddedDataOptions.storeId;
}
if (initQueryAddedDataOptions.center) {
this.centerPoint = initQueryAddedDataOptions.center;
}
if (initQueryAddedDataOptions.radius) {
this.radius = initQueryAddedDataOptions.radius;
}
this.mouseOver = super.mouseOver;
this.mouseOut = super.mouseOut;
this.mouseClick = super.mouseClick;
}
cameraChangedCallback() {
if (this.mCameraCallback) {
this.mCameraCallback();
}
}
setControlMode(mode) {
this.controlMode = mode;
}
initControl(parentDiv, mapView) {
this.mapView = mapView;
// View of the map
this.resultStoreList = new gem.core.StoreLocationList();
// The query result is shown on the map using the icon.svg
// file which is located in the same directory as this JavaScript code
this.externalRenderObj = new gem.d3Scene.ExternalRenderer(
this.iconLocation, "myCollection", mapView, parentDiv, this.options.marker.cssClass, this.rendererOptions);
this.externalRenderObj.registerMouseOutCallback(this.mouseOut.bind(this));
this.externalRenderObj.registerMouseOverCallback(this.mouseOver.bind(this));
this.externalRenderObj.registerMouseClickCallback(this.mouseClick.bind(this));
if (this.selectedItemClass)
this.externalRenderObj.registerItemSelectedCallback(this.itemSelected.bind(this));
// this.externalRenderObj.registerItemAddedCallback(function (itemElementHtmlId, item) {
// if (this.itemAddedNotifier) this.itemAddedNotifier(itemElementHtmlId, item);
// }.bind(this));
// this.externalRenderObj.registerItemRemovedCallback(function (itemElementHtmlId, item, itemId) {
// if (this.itemRemovedNotifier) this.itemRemovedNotifier(itemElementHtmlId, item, itemId);
// }.bind(this));
// This function is called when the query results (more store locations) arrive
this.callbackquery = function (reason) {
if (this.tvectorSources) {
if (this.tvectorSources.size() > 0) {
if (this.externalRenderObj) {
this.externalRenderObj.sourceIsPending = true;
this.externalRenderObj.clear();
this.externalRenderObj.destroyHasBeenCalled = undefined;
}
this.mapView.removeVectorSource(this.tvectorSources.get(0));
}
this.tvectorSources.delete();
this.tvectorSources = new gem.d3Scene.MarkerCollectionRefList();
} else
this.tvectorSources = new gem.d3Scene.MarkerCollectionRefList();
// Add store markers to the map
mapView.addStoreListAsCustomMarkers(this.resultStoreList,
"storeLocator", this.tvectorSources, this.externalRenderObj, this.storeId, this.options.markerGrouping.maxLevel);
if (this.listChangedNotifier) {
this.listChangedNotifier(this.externalRenderObj.name, mapView, this.storeId);
}
}.bind(this);
this.externalQueryListener = new gem.d3Scene.ExternalQueryListener(this.callbackquery);
this.listLang = new gem.core.GemStringList();
// This function is called if the camera moved or changed orientation.
// Search the store locator again, in case more stores have appeared in view
let i;
for (i = 0; i < this.languageList.length; i++) {
this.listLang.push_back(this.languageList[i]);
}
if (this.centerPoint && this.radius) {
this.geographicList = new gem.core.RectangleGeographicAreaList();
let geographicArea = new Module.RectangleGeographicArea();
let offset = (this.radius / 6371) * 57.295779513;
let topLeft = {
latitude: this.centerPoint.latitude + offset,
longitude: this.centerPoint.longitude - offset,
altitude: this.centerPoint.altitude,
bearing: this.centerPoint.bearing
};
let bottomRight = {
latitude: this.centerPoint.latitude - offset,
longitude: this.centerPoint.longitude + offset,
altitude: this.centerPoint.altitude,
bearing: this.centerPoint.bearing
};
geographicArea.setTopLeft(topLeft);
geographicArea.setBottomRight(bottomRight);
this.geographicList.push_back(geographicArea);
mapView.centerOnArea(topLeft, bottomRight, 0);
mapView.queryStoreLocator(this.externalQueryListener, this.resultStoreList, this.storeId, false, this.listLang, this.geographicList);
} else {
if (this.controlMode && this.controlMode != 'automatic') {
this.mCameraCallback = undefined;
this.notifyVisibility('hidden');
return;
}
var cameraMovedCallback = function (state) {
mapView.queryStoreLocator(this.externalQueryListener, this.resultStoreList, this.storeId, false, this.listLang);
}.bind(this);
this.mCameraCallback = cameraMovedCallback;
cameraMovedCallback();
}
}
getItemsList() {
return this.resultStoreList;
}
getItemsSource() {
return this.tvectorSources.get(0);
}
setPointOfInterestAndRadius(coords, radius) {
super.setPointOfInterestAndRadius(coords, radius);
if (this.callbackquery) {
this.mCameraCallback = undefined;
this.geographicList = new gem.core.RectangleGeographicAreaList();
let geographicArea = new Module.RectangleGeographicArea();
let offset = (this.radius / 6371) * 57.295779513;
let topLeft = {
latitude: this.centerPoint.latitude + offset,
longitude: this.centerPoint.longitude - offset,
altitude: this.centerPoint.altitude,
bearing: this.centerPoint.bearing
};
let bottomRight = {
latitude: this.centerPoint.latitude - offset,
longitude: this.centerPoint.longitude + offset,
altitude: this.centerPoint.altitude,
bearing: this.centerPoint.bearing
};
geographicArea.setTopLeft(topLeft);
geographicArea.setBottomRight(bottomRight);
this.geographicList.push_back(geographicArea);
this.mapView.centerOnArea(topLeft, bottomRight, 0);
this.mapView.queryStoreLocator(this.externalQueryListener, this.resultStoreList, this.storeId, false, this.listLang, this.geographicList);
}
}
notifySearchSelection(item) {
if (item === undefined) {
if (this.tvectorSources.size() > 0) {
this.mapView.removeVectorSource(this.tvectorSources.get(0));
}
this.notifyVisibility('hidden');
// Free memory of previous result, if any
this.tvectorSources.delete();
this.tvectorSources = undefined;
this.resultStoreList.delete();
if (this.selectedItem) {
this.selectedItem.remove();
this.selectedItem = undefined;
}
this.resultStoreList = new gem.core.StoreLocationList();
if (this.listChangedNotifier) {
this.listChangedNotifier(this.externalRenderObj.name, this.mapView, this.storeId);
}
return;
}
this.notifyVisibility('visible');
if (this.radius === undefined)
this.radius = 10;
this.setPointOfInterestAndRadius(item.getCoordinates(), this.radius);
}
notifyChangeFilterData(type, name, values) {
switch (type) {
case 'distance': {
this.radius = parseFloat(values);
if (this.centerPoint) {
if (this.selectedItem) {
this.selectedItem.remove();
this.selectedItem = undefined;
}
this.setPointOfInterestAndRadius(this.centerPoint, this.radius);
}
break;
}
case 'languages': {
let pt = parseInt(values[0].value);
if (this.listLang) {
this.listLang.delete();
}
this.listLang = new gem.core.GemStringList();
this.listLang.push_back(this.locationConfigurationList.get(pt).getValue());
if (this.selectedItem) {
this.selectedItem.remove();
this.selectedItem = undefined;
}
this.setPointOfInterestAndRadius(this.centerPoint, this.radius);
break;
}
case 'category':
if (this.listLang) {
this.listLang.delete();
}
this.listLang = new gem.core.GemStringList();
for (let i = 0; i < values.length; i++) {
if (values[i].key === 'language')
this.listLang.push_back(values[i].value);
}
if (!values.length)
this.listLang.push_back('all');
if (this.centerPoint && this.radius)
this.setPointOfInterestAndRadius(this.centerPoint, this.radius);
break;
}
}
requestFieldValues(key, cb) {
switch (key) {
case 'languages': {
var locationConfigurationList = new gem.core.StoreLocationLangList();
var callbackqueryLang = function (reason) {
this.locationConfigurationList = locationConfigurationList;
cb(this.locationConfigurationList);
}.bind(this);
var externalQueryListener2 = new gem.d3Scene.ExternalQueryListener(callbackqueryLang);
this.mapView.queryStoreLocatorConfiguration(externalQueryListener2, this.storeId, locationConfigurationList);
}
break;
}
}
}
/**
* @callback callbackListItem
* @param {HTMLDivElement} elMarker - html parent element
* @param {object} properties - json properties from data source item associated to the list item
*/
/**
* Control for displaying an interactive data source list
* @class gem.control.ListControl
*
* @param {object} initOptions
* @param {string} [initOptions.container] - id of HTML parent element
* @param {gem.control.BaseControl} initOptions.sourceControl - Linked data source control
* @param {string} [initOptions.menuName] - Menu list name
* @param {boolean} [initOptions.displayCount = true] - display information about number of items
* @param {number} [initOptions.itemsToLoadAtATime = 20] - no. of list items to load a time when scrolling
* @param {string[]} initOptions.titleProperties - data source item properties to use for list item title
* @param {string[]} initOptions.detailsProperties - data source item properties to use for list item details
* @param {string} initOptions.imageProperty - data source item property that contains an image url
* @param {bool} [initOptions.displayCount = true] - display list items count
* @param {number} [initOptions.itemsToLoadAtATime = 20] - number of list items to load at a time
* @param {number} [initOptions.flyToItemAltitude = 1000] - set marker fly to altitude in meters
* @param {object} [initOptions.cssClasses] - specify custom style rules for list elements
* @param {object} [initOptions.cssClasses.divMenu]
* @param {string} [initOptions.cssClasses.divMenu.className = 'gem-markers-menu']
* @param {string} [initOptions.cssClasses.divMenu.type = 'div']
* @param {object} [initOptions.cssClasses.listHeader]
* @param {string} [initOptions.cssClasses.listHeader.className = 'gem-markers-menu-name']
* @param {string} [initOptions.cssClasses.listHeader.type = 'div']
* @param {object} [initOptions.cssClasses.divList]
* @param {string} [initOptions.cssClasses.divList.className = 'gem-markers-menu-list']
* @param {string} [initOptions.cssClasses.divList.type = 'div']
* @param {object} [initOptions.cssClasses.divItem]
* @param {string} [initOptions.cssClasses.divItem.className = 'gem-marker-list-item']
* @param {string} [initOptions.cssClasses.divItem.type = 'div']
* @param {object} [initOptions.cssClasses.divItemImage]
* @param {string} [initOptions.cssClasses.divItemImage.className = 'gem-marker-list-item-image']
* @param {string} [initOptions.cssClasses.divItemImage.type = 'div']
* @param {object} [initOptions.cssClasses.divItemContent]
* @param {string} [initOptions.cssClasses.divItemContent.className = 'gem-marker-list-item-content']
* @param {string} [initOptions.cssClasses.divItemContent.type = 'div']
* @param {object} [initOptions.cssClasses.divItemTitle]
* @param {string} [initOptions.cssClasses.divItemTitle.className = 'gem-marker-list-item-title']
* @param {string} [initOptions.cssClasses.divItemTitle.type = 'div']
* @param {object} [initOptions.cssClasses.divItemNoResultsCss]
* @param {string} [initOptions.cssClasses.divItemNoResultsCss.className = 'gem-marker-list-no-results']
* @param {string} [initOptions.cssClasses.divItemNoResultsCss.type = 'div']
* @param {object} [initOptions.cssClasses.divListCountCss]
* @param {string} [initOptions.cssClasses.divListCountCss.className = 'gem-markers-list-count-info']
* @param {string} [initOptions.cssClasses.divListCountCss.type = 'div']
* @param {object} [initOptions.cssClasses.divListLoaderCss]
* @param {string} [initOptions.cssClasses.divListLoaderCss.className = 'gem-marker-list-loader']
* @param {string} [initOptions.cssClasses.divListLoaderCss.type = 'div']
* @param {string} [initOptions.selectedItemClass] - css class for selected marker item
* @param {callbackListItem} [initOptions.populateItemFunction] - fully customize the list item
*/
gem.control.ListControl = class ListControl extends gem.control.BaseControl {
constructor(initOptions) {
super(gem.control.TConntrolExecuteType.ONCONNECTED);
const defaultListOptions = {
sourceControl: undefined,
sortMode: gem.control.LISTSORTMODE.DISTANCE,
container: "gem-markers-menu-container",
menuName: "",
titleProperties: "name",
detailsProperties: "",
imageProperty: "",
displayCount: true,
itemsToLoadAtATime: 20,
flyToItemAltitude: 1000,
cssClasses: {
divMenu: {
className: "gem-markers-menu",
type: "div"
},
listHeader: {
className: "gem-markers-menu-name",
type: "div"
},
divList: {
className: "gem-markers-menu-list",
type: "div"
},
divItem: {
className: "gem-marker-list-item",
type: "div"
},
divItemImage: {
className: "gem-marker-list-item-image",
type: "div"
},
divItemContent: {
className: "gem-marker-list-item-content",
type: "div"
},
divItemTitle: {
className: "gem-marker-list-item-title",
type: "div"
},
divItemNoResultsCss: {
className: "gem-marker-list-no-results",
type: "div"
},
divListCountCss: {
className: "gem-markers-list-count-info",
type: "div"
},
divListLoaderCss: {
className: "gem-marker-list-loader",
type: "div"
}
},
selectedItemClass: "gem-marker-selected",
populateItemFunction: undefined /*function (elMarker, properties)*/
}
this.options = defaultListOptions;
if (initOptions)
this.options = Object.assign({}, defaultListOptions, initOptions);
if (initOptions && initOptions.cssClasses)
this.options.cssClasses = Object.assign({}, defaultListOptions.cssClasses, initOptions.cssClasses);
if (!this.options.sourceControl) {
console.log("need to specify a data source control");
return;
}
this.control = this.options.sourceControl;
this.control.registerItemSelectionListener(this.itemSelectionNotifier.bind(this));
if (this.control.loadingMethod === gem.control.TConntrolItemUpdateMode.LIST)
this.control.registerListChangedNotifier(this.updateList.bind(this));
else {
this.control.registerListChangedNotifier(this.updateIndividualList.bind(this));
this.sortMode = this.options.sortMode;
}
this.control.registerListChangedFilterNotifier(this.updateFilteredList.bind(this));
this.control.registerListLoadingOnNotifier(this.toggleListLoadingOn.bind(this));
this.control.registerListLoadingOffNotifier(this.toggleListLoadingOff.bind(this));
this.externalItemCreator = this.options.populateItemFunction;
this.selectedItemClass = this.control.selectedItemClass;
}
itemSelectionNotifier(item) {
if (!item) {
let activeListing = this.elMenuList.getElementsByClassName('active');
if (activeListing[0]) {
activeListing[0].classList.remove('active');
}
} else {
let markerId = item.id.replace(this.htmlIdentifier, '');
let elMarkerItem = this.createListItem(markerId, item.coordinates, item.info.properties);
if (elMarkerItem) {
this.elMenuList.appendChild(elMarkerItem);
elMarkerItem.classList.add('active');
elMarkerItem.scrollIntoView({
behaviour: 'smooth',
block: 'nearest',
inline: 'nearest'
});
} else {
let activeListing = this.elMenuList.getElementsByClassName('active');
if (activeListing[0]) {
activeListing[0].classList.remove('active');
}
let markerId = item.id.replace(this.htmlIdentifier, '');
// check if list item exists
let elMarkerItem = document.getElementById(this.options.cssClasses.divItem.className + markerId);
if (elMarkerItem) {
elMarkerItem.classList.add('active');
elMarkerItem.scrollIntoView({
behaviour: 'smooth',
block: 'nearest',
inline: 'nearest'
});
}
}
}
}
initControl(parentDiv, mapView) {
if (this.elMenuList !== undefined)
return;
this.vectorItemsQuery = new Map();
this.intersectCount = 0;
if (this.options.container) {
this.elementDiv = document.getElementById(this.options.container);
//create list
if (this.options.cssClasses.divList.className) {
this.elMenuList = document.createElement(this.options.cssClasses.divList.type);
this.elMenuList.className = this.options.cssClasses.divList.className;
this.elMenuList.id = this.options.cssClasses.divList.className;
// create markers menu container
if (this.options.cssClasses.divMenu.className) {
let elMarkersMenu = document.createElement(this.options.cssClasses.divMenu.type);
elMarkersMenu.className = this.options.cssClasses.divMenu.className;
// menu name
if (this.options.cssClasses.listHeader.className && this.options.menuName && this.options.menuName.length) {
this.elMenuName = document.createElement(this.options.cssClasses.listHeader.type);
this.elMenuName.className = this.options.cssClasses.listHeader.className;
this.elMenuName.id = this.options.cssClasses.listHeader.className;
let headingMenuName = document.createElement('h2');
headingMenuName.innerHTML = this.options.menuName;
this.elMenuName.appendChild(headingMenuName);
elMarkersMenu.appendChild(this.elMenuName);
}
elMarkersMenu.appendChild(this.elMenuList);
this.elementDiv.appendChild(elMarkersMenu);
// update this here, otherwise menu name clientHeight is always 0
if (this.elMenuName)
this.elMenuList.style.height = "calc(100% - " + (this.elMenuName.offsetHeight + 1) + "px)";
} else
this.elementDiv.appendChild(this.elMenuList);
} else {
this.elMenuList = this.elementDiv;
}
} else {
let containerDiv = document.getElementById(parentDiv);
this.elementDiv = document.createElement("div");
this.elementDiv.classList.add("vertical-menu");
containerDiv.appendChild(this.elementDiv);
}
this.mapView = mapView;
}
updateIndividualList(list, htmlIdentifier, mapView) {
if (mapView && this.elMenuList === undefined)
this.initControl(undefined, mapView);
this.htmlIdentifier = htmlIdentifier;
//this.control.externalRenderObj.registerMouseClickCallback(this.mouseClick.bind(this));
while (this.elMenuList.firstChild) this.elMenuList.removeChild(this.elMenuList.lastChild);
if (this.options.displayCount) {
let elCountInfo = document.getElementsByClassName(this.options.cssClasses.divListCountCss.className);
if (elCountInfo.length > 0)
elCountInfo[0].parentNode.removeChild(elCountInfo[0]);
}
if (!list.size) {
let elNoResults = this.createNoResultsItem();
if (elNoResults)
this.elMenuList.appendChild(elNoResults);
return;
}
function logMapElements(value, key, map) {
let it = value;
let markerId = key;
let markerCoord = it.marker.getCoordinatesAt ? it.marker.getCoordinatesAt(0).get(0) : it.marker.getCoordinates();
let jsonProps = undefined;
if (it.marker.getInfo()) {
try {
let markerInfo = JSON.parse(it.marker.getInfo());
if (markerInfo && markerInfo.properties)
jsonProps = markerInfo.properties;
else if (markerInfo && markerInfo.parameters) {
jsonProps = {};
for (const param of markerInfo.parameters.keyvals) {
jsonProps[param.key] = param.value;
}
}
} catch (e) {
console.log("List control: error in Json string.");
return false;
}
}
let elMarkerItem = this.createListItem(markerId, markerCoord, jsonProps);
if (elMarkerItem)
this.elMenuList.appendChild(elMarkerItem);
}
list.forEach(logMapElements.bind(this));
this.setActiveListItem();
if (this.options.displayCount)
this.createDisplayCount(list.size);
}
updateList(htmlIdentifier, mapView, storeId) {
if (this.elMenuList === undefined)
this.initControl(undefined, mapView);
this.intersectCount = 0;
this.storeId = storeId;
// clean-up previous
while (this.elMenuList.firstChild) this.elMenuList.removeChild(this.elMenuList.lastChild);
if (this.options.displayCount) {
let elCountInfo = document.getElementsByClassName(this.options.cssClasses.divListCountCss.className);
if (elCountInfo.length > 0)
elCountInfo[0].parentNode.removeChild(elCountInfo[0]);
}
this.htmlIdentifier = htmlIdentifier;
let source = this.control.getItemsList();
try {
if (!source || !source.size()) {
let elNoResults = this.createNoResultsItem();
if (elNoResults)
this.elMenuList.appendChild(elNoResults);
return;
}
} catch (e) {
console.log("list control error ", e);
}
// list count info
if (this.options.displayCount) {
let markersInview = source.getTotalCount ? source.getTotalCount() : undefined;
let markersMenu = document.getElementsByClassName(this.options.cssClasses.divMenu.className);
if (markersMenu && markersMenu.length > 0) {
let elListCount = markersMenu[0].insertBefore(document.createElement(this.options.cssClasses.divListCountCss.type), this.elMenuList);
elListCount.className = this.options.cssClasses.divListCountCss.className;
let elCountInfo = elListCount.appendChild(document.createElement('span'));
if (markersInview) {
elCountInfo.textContent = "Showing " + source.size().toLocaleString() + " of " + markersInview.toLocaleString() +
(source.size() > 1 ? " results" : " result") + " in this area.";
} else {
elCountInfo.textContent = "Showing " + source.size().toLocaleString() +
(source.size() > 1 ? " results." : " result.");
}
let adjustListHeight = (this.elMenuName ? this.elMenuName.clientHeight : 0) + elListCount.clientHeight;
this.elMenuList.style.height = "calc(100% - " + adjustListHeight + "px)";
}
}
// populate markers list
let loadMarkersCount = Math.min(source.size(), this.options.itemsToLoadAtATime);
this.vectorItemsQuery.clear();
if (source.size() && source.getMarkerAt(0).queryInfo) {
if (this.arrayOfMarkers)
this.arrayOfMarkers.delete();
this.arrayOfMarkers = new gem.core.StoreLocationList();
for (let i = 0; i < loadMarkersCount; i++) {
let marker = source.getMarkerAt(i);
this.arrayOfMarkers.push_back(marker);
marker.delete();
}
let cb = (vectorIt, reason, itemL) => {
for (let i = 0; i < this.arrayOfMarkers.size(); i++) {
let marker = this.arrayOfMarkers.get(i);
let markerId = marker.getId();
let markerCoord = marker.getCoordinatesAt ? marker.getCoordinatesAt(0).get(0) : marker.getCoordinates();
let jsonProps = marker.getInfo() ? JSON.parse(marker.getInfo()).properties : undefined;
let elMarkerItem = this.createListItem(markerId, markerCoord, jsonProps);
if (elMarkerItem)
this.elMenuList.appendChild(elMarkerItem);
}
//check if selected item exists and add the active status to the newly added list item
if (this.control.selectedItem && this.control.selectedItemObj) {
let markerId = this.control.selectedItemObj.id.replace(this.htmlIdentifier, '');
let listItemId = this.divItemCss + markerId;
let activeListItem = document.getElementById(listItemId);
if (activeListItem)
activeListItem.classList.add('active');
}
if (this.elMenuList.lastChild && this.control.getItemsList().size() > this.options.itemsToLoadAtATime) {
this.createMenuListItemObserver(this.elMenuList.lastChild);
}
};
this.arrayQuery = new gem.core.StoreLocationListenerContainer(this.arrayOfMarkers);
this.arrayQuery.registerCallback(cb);
this.arrayOfMarkers.queryInfo(this.mapView, this.storeId, cb);
this.arrayQuery.mProgressListener = this.arrayOfMarkers.queryInfo(this.mapView, this.storeId, this.arrayQuery.callback.bind(this.arrayQuery));
} else {
for (let i = 0; i < loadMarkersCount; i++) {
let marker = source.getMarkerAt(i);
let markerId = marker.getId();
let markerCoord = marker.getCoordinatesAt ? marker.getCoordinatesAt(0).get(0) : marker.getCoordinates();
let jsonProps;
if (marker.getInfo()) {
try {
let markerInfo = JSON.parse(marker.getInfo());
if (markerInfo && markerInfo.properties)
jsonProps = markerInfo.properties;
} catch (e) {
console.log("List control: error in Json string.");
}
}
let elMarkerItem = this.createListItem(markerId, markerCoord, jsonProps);
if (elMarkerItem)
this.elMenuList.appendChild(elMarkerItem);
}
this.setActiveListItem();
// add intersect observer to last item loaded
if (this.elMenuList.lastChild && source.size() > this.options.itemsToLoadAtATime) {
this.createMenuListItemObserver(this.elMenuList.lastChild);
}
}
}
updateFilteredList(list, htmlIdentifier, mapView) {
if (mapView && this.elMenuList === undefined)
this.initControl(undefined, mapView);
this.htmlIdentifier = htmlIdentifier;
while (this.elMenuList.firstChild) this.elMenuList.removeChild(this.elMenuList.lastChild);
if (this.options.displayCount) {
let elCountInfo = document.getElementsByClassName(this.options.cssClasses.divListCountCss.className);
if (elCountInfo.length > 0)
elCountInfo[0].parentNode.removeChild(elCountInfo[0]);
}
if (!list.size) {
const elNoResults = this.createNoResultsItem();
if (elNoResults)
this.elMenuList.appendChild(elNoResults);
return;
}
function logMapElements(value, key, map) {
let it = value;
let markerId = key;
let markerCoord = it.marker.getCoordinatesAt(0).get(0);
let jsonProps = undefined;
if (it.marker.getInfo()) {
try {
let markerInfo = JSON.parse(it.marker.getInfo());
if (markerInfo && markerInfo.properties)
jsonProps = markerInfo.properties;
} catch (e) {
console.log("List control: error in Json string.");
return false;
}
}
let elMarkerItem = this.createListItem(String(markerId), markerCoord, jsonProps);
if (elMarkerItem)
this.elMenuList.appendChild(elMarkerItem);
}
list.forEach(logMapElements.bind(this));
this.setActiveListItem();
if (this.options.displayCount)
this.createDisplayCount(list.size);
}
setActiveListItem() {
//check if selected item exists and add the active status to the newly added list item
if (this.control.selectedItem && this.control.selectedItemObj) {
let markerId = this.control.selectedItemObj.id.replace(this.htmlIdentifier, '');
let listItemId = this.options.cssClasses.divItem.className + markerId;
let activeListItem = document.getElementById(listItemId);
if (activeListItem)
activeListItem.classList.add('active');
}
}
createDisplayCount(listCount) {
let markersMenu = document.getElementsByClassName(this.options.cssClasses.divMenu.className);
if (markersMenu) {
let elListCount = markersMenu[0].insertBefore(document.createElement('div'), this.elMenuList);
elListCount.className = this.options.cssClasses.divListCountCss.className;
let elCountInfo = elListCount.appendChild(document.createElement('span'));
elCountInfo.textContent = "Showing " + listCount.toLocaleString() +
(listCount > 1 ? " results" : " result") + " in this area.";
let adjustListHeight = this.elMenuName.clientHeight + elListCount.clientHeight;
this.elMenuList.style.height = "calc(100% - " + adjustListHeight + "px)";
}
}
createNoResultsItem() {
let elNoResults = document.createElement(this.options.cssClasses.divItemNoResultsCss.type);
elNoResults.className = this.options.cssClasses.divItemNoResultsCss.className;
let elMarkerTitle = elNoResults.appendChild(document.createElement(this.options.cssClasses.divItemTitle.type));
elMarkerTitle.className = this.options.cssClasses.divItemTitle.className;
elMarkerTitle.textContent = "No results found";
let elMarkerDetails = elNoResults.appendChild(document.createElement('p'));
elMarkerDetails.textContent = "Try zooming out or zooming in or try a different location.";
return elNoResults;
}
createMenuListItemObserver(listItem) {
let observer;
let storesContainer = this.elMenuList;
let options = {
root: storesContainer,
rootMargin: "0px",
threshold: [0.0, 0.25, 0.5, 0.75, 1.0]
};
observer = new IntersectionObserver(this.handleMenuListItemIntersect.bind(this), options);
observer.observe(listItem);
}
handleMenuListItemIntersect(entries, observer) {
let source = this.control.getItemsList();
if (!source || source.size())
entries.forEach(entry => {
if (entry.isIntersecting) {
this.intersectCount++;
// unobserve this entry target
observer.unobserve(entry.target);
// load next results
let elMenuList = this.elMenuList;
let firstStoreIdx = this.options.itemsToLoadAtATime * this.intersectCount;
let lastStoreIdx = Math.min(source.size(), this.options.itemsToLoadAtATime * (this.intersectCount + 1));
if (source.getMarkerAt(firstStoreIdx).queryInfo) {
if (this.arrayOfMarkers)
this.arrayOfMarkers.delete();
this.arrayOfMarkers = new gem.core.StoreLocationList();
for (let i = firstStoreIdx; i < lastStoreIdx; i++) {
let marker = source.getMarkerAt(i);
this.arrayOfMarkers.push_back(marker);
marker.delete();
}
let cb = (vectorIt, reason, itemL) => {
for (let i = 0; i < this.arrayOfMarkers.size(); i++) {
let marker = this.arrayOfMarkers.get(i);
let markerId = marker.getId();
let markerCoord = marker.getCoordinatesAt ? marker.getCoordinatesAt(0).get(0) : marker.getCoordinates();
let jsonProps = marker.getInfo() ? JSON.parse(marker.getInfo()).properties : undefined;
let elMarkerItem = this.createListItem(markerId, markerCoord, jsonProps);
if (elMarkerItem)
this.elMenuList.appendChild(elMarkerItem);
}
if (source.size() > this.options.itemsToLoadAtATime * (this.intersectCount + 1))
this.createMenuListItemObserver(this.elMenuList.lastChild);
}
this.arrayQuery = new gem.core.StoreLocationListenerContainer(this.arrayOfMarkers);
this.arrayQuery.registerCallback(cb);
this.arrayOfMarkers.queryInfo(this.mapView, this.storeId, cb);
this.arrayQuery.mProgressListener = this.arrayOfMarkers.queryInfo(this.mapView, this.storeId, this.arrayQuery.callback.bind(this.arrayQuery));
} else {
for (let i = firstStoreIdx; i < lastStoreIdx; i++) {
let marker = source.getMarkerAt(i);
let markerId = marker.getId();
let markerCoord = marker.getCoordinatesAt ? marker.getCoordinatesAt(0).get(0) : marker.getCoordinates();
let jsonProps = marker.getInfo() ? JSON.parse(marker.getInfo()).properties : undefined;
let elMarkerItem = this.createListItem(markerId, markerCoord, jsonProps);
if (elMarkerItem)
elMenuList.appendChild(elMarkerItem);
}
// observe next entry
if (source.size() > this.options.itemsToLoadAtATime * (this.intersectCount + 1))
this.createMenuListItemObserver(this.elMenuList.lastChild);
}
}
});
}
createListItem(markerId, markerCoord, jsonProperties) {
// check if list item exists
if (document.getElementById(this.options.cssClasses.divItem.className + markerId))
return;
try {
let markerProps = jsonProperties;
let elMarkerItem = document.createElement(this.options.cssClasses.divItem.type);
elMarkerItem.id = this.options.cssClasses.divItem.className + markerId;
elMarkerItem.className = this.options.cssClasses.divItem.className;
if (this.externalItemCreator) {
this.externalItemCreator(elMarkerItem, markerProps);
} else { // default
// image
if (this.options.imageProperty && this.options.imageProperty.length) {
const strImageUrl = markerProps[this.options.imageProperty];
if (strImageUrl && strImageUrl.length) {
const liImage = elMarkerItem.appendChild(document.createElement(this.options.cssClasses.divItemImage.type));
liImage.className = this.options.cssClasses.divItemImage.className;
const img = document.createElement('img');
img.onload = () => {
elContent.className = this.options.cssClasses.divItemContent.className;
elContent.style.width = '60%';
liImage.appendChild(img);
};
img.onerror = () => {
liImage.style.display = 'none';
};
img.src = strImageUrl;
}
}
// content
const elContent = elMarkerItem.appendChild(document.createElement(this.options.cssClasses.divItemContent.type));
elContent.className = this.options.cssClasses.divItemContent.className;
// title
const elMarkerTitle = elContent.appendChild(document.createElement(this.options.cssClasses.divItemTitle.type));
elMarkerTitle.className = this.options.cssClasses.divItemTitle.className;
elMarkerTitle.textContent = this.control.getPropertyString(markerProps, this.options.titleProperties, ', ');
// details
const elMarkerDetails = elContent.appendChild(document.createElement('div'));
elMarkerDetails.innerHTML = this.control.getPropertyString(markerProps, this.options.detailsProperties, ' · ');
}
// event listener for mouse over
elMarkerItem.addEventListener('mouseover', function () {
let groupId = markerId;
if (this.control.getItemsSource()) {
let groupParent = this.control.getItemsSource().getGroupHeadItem(markerId);
groupId = groupParent.getId();
}
let markerDivId = this.htmlIdentifier + groupId;
let storeMarker = document.getElementById(markerDivId);
if (storeMarker) {
storeMarker.classList.add('active');
}
}.bind(this), false);
// event listener for mouse over
elMarkerItem.addEventListener('mouseout', function () {
let groupId = markerId;
if (this.control.getItemsSource()) {
let groupParent = this.control.getItemsSource().getGroupHeadItem(markerId);
groupId = groupParent.getId();
}
let markerDivId = this.htmlIdentifier + groupId;
let storeMarker = document.getElementById(markerDivId);
if (storeMarker) {
storeMarker.classList.remove('active');
}
}.bind(this), false);
// event listener for mouse click
elMarkerItem.addEventListener('click', function (e) {
e.preventDefault();
// fly to store
this.flyToMarker(markerId, markerCoord);
// highlight listing in sidebar and remove highlight for all other listings
const activeListing = this.elMenuList.getElementsByClassName('active');
if (activeListing[0]) {
activeListing[0].classList.remove('active');
}
elMarkerItem.scrollIntoView({
behaviour: 'smooth',
block: 'nearest',
inline: 'nearest'
});
e.currentTarget.parentNode.classList.add('active');
}.bind(this), false);
return elMarkerItem;
} catch (e) {
console.log("List Control: error creating list item");
}
}
retainSelectedItem(item, jsonObject, position) {
this.selectedItemElement = item.cloneNode(true);
if (this.selectedItemClass)
item.className = this.selectedItemClass;
item.id = 'selectedItem';
item.style.display = 'none';
item.parentElement.appendChild(this.selectedItemElement);
}
cameraChangedCallback() {
if (this.mCameraCallback)
this.mCameraCallback();
}
flyToMarker(markerId, markerCoords) {
let callbackCameraChange = function (reason) {
this.mCameraCallback = undefined;
let markerDivId = this.htmlIdentifier + markerId;
let storeMarker = document.getElementById(markerDivId);
if (storeMarker) {
const event = new MouseEvent('mouseover', {
'view': window,
'bubbles': true,
'cancelable': true
});
storeMarker.dispatchEvent(event);
storeMarker.click();
}
// else marker is in group
};
let callbackFinishedFly = function (reason) {
this.mCameraCallback = callbackCameraChange.bind(this);
}.bind(this);
markerCoords.altitude = this.options.flyToItemAltitude; // altitude has to be lower than max group level
this.mapView.centerOnCoordinates(markerCoords, 2000 /*ms fly time*/, callbackFinishedFly);
}
toggleListLoadingOn() {
let elCount = document.getElementsByClassName(this.options.cssClasses.divListCountCss.className);
if (elCount.length)
elCount[0].style.opacity = '0.5';
let elListMenu = document.getElementsByClassName(this.options.cssClasses.divList.className);
if (elListMenu.length) {
elListMenu[0].style.opacity = '0.5';
elListMenu[0].style.pointerEvents = 'none';
}
let listLoader = document.getElementById(this.options.cssClasses.divListLoaderCss.className);
if (!listLoader) {
let elListContainer = document.getElementsByClassName(this.options.cssClasses.divMenu.className);
if (elListContainer.length)
listLoader = this.createLoadingCircle(elListContainer[0]);
}
if (listLoader) {
listLoader.style.display = '';
listLoader.style.visibility = 'visible';
}
}
toggleListLoadingOff() {
let elCount = document.getElementsByClassName(this.options.cssClasses.divListCountCss.className);
if (elCount.length)
elCount[0].style.opacity = '1';
let elListMenu = document.getElementsByClassName(this.options.cssClasses.divList.className);
if (elListMenu.length) {
elListMenu[0].style.opacity = '1';
elListMenu[0].style.pointerEvents = 'auto';
}
let listLoader = document.getElementById(this.options.cssClasses.divListLoaderCss.className);
if (listLoader)
listLoader.style.display = 'none';
}
createLoadingCircle(parentDiv) {
let svgns = "http://www.w3.org/2000/svg";
let wrapperDiv = parentDiv.insertBefore(document.createElement(this.options.cssClasses.divListLoaderCss.type), parentDiv.firstChild);
wrapperDiv.id = this.options.cssClasses.divListLoaderCss.className;
wrapperDiv.className = this.options.cssClasses.divListLoaderCss.className;
let svg = document.createElementNS(svgns, "svg");
svg.classList.add("circular-loader");
svg.setAttribute("viewBox", "25 25 50 50");
wrapperDiv.appendChild(svg);
let circle = document.createElementNS(svgns, 'circle');
circle.classList.add("loader-path");
circle.setAttributeNS(null, 'cx', 50);
circle.setAttributeNS(null, 'cy', 50);
circle.setAttributeNS(null, 'r', 20);
circle.setAttributeNS(null, 'style', 'fill: none; stroke: #70c542; stroke-width: 2px;');
svg.appendChild(circle);
return wrapperDiv;
}
}
/**
* Control for displaying search nearby control
* @class gem.control.SearchNearbyControl
*
* @param {object} initSearchNearbyControlOptions
* @param {object} initSearchNearbyControlOptions.categoryfilter
* @param {string} initSearchNearbyControlOptions.container
* @param {gem.core.Coordinates} initSearchNearbyControlOptions.center
* @param {callback} initSearchNearbyControlOptions.populateItemFunction
* @param {callback} initSearchNearbyControlOptions.selectedItemCallback
* @param {gem.control.BaseControl} initSearchNearbyControlOptions.categorylistcontrol
*/
gem.control.SearchNearbyControl = class SearchNearbyControl extends gem.control.BaseControl {
constructor(initSearchNearbyControlOptions) {
super(gem.control.TConntrolExecuteType.ONCONNECTED);
if (initSearchNearbyControlOptions) {
this.categoryfilter = initSearchNearbyControlOptions.categoryfilter;
this.customContainer = initSearchNearbyControlOptions.container;
this.center = initSearchNearbyControlOptions.center;
this.populateItemFunction = initSearchNearbyControlOptions.populateItemFunction;
this.onSelectCallback = initSearchNearbyControlOptions.selectedItemCallback;
this.categorylistcontrol = initSearchNearbyControlOptions.categorylistcontrol;
if (this.categorylistcontrol) {
this.categorylistcontrol.registerListUpdatedNotifier(this.updateCategoryList.bind(this));
}
}
}
updateCenter(center) {
}
setControlMode(mode) {
this.controlMode = mode;
}
notifySearchSelection(item) {
if (item) {
this.center = item.getCoordinates();
}
if (this.elNearbyListContainer)
this.elNearbyListContainer.style.visibility = 'hidden';
this.elementDiv.style.visibility = 'hidden';
}
initControl(parentDiv, mapView) {
this.parentDiv = parentDiv;
this.resultList = new gem.core.LandmarkList();
this.elementDiv = document.createElement("div");
if (this.controlMode && this.controlMode === 'dependend')
this.elementDiv.style.visibility = 'hidden';
this.elementDiv.style.overflow = 'auto';
this.elementDiv.classList.add("gem-markers-menu-list");
let containerDiv;
if (this.customContainer)
containerDiv = document.getElementById(this.customContainer);
else {
this.elNearbyListContainer = document.createElement('div');
this.elNearbyListContainer.className = 'gem-nearby-lmks-list-container';
let lstchild = document.getElementById(parentDiv).lastChild;
if (lstchild && lstchild.id !== 'buttonCopyright')
this.elNearbyListContainer.style.top = lstchild.offsetTop + lstchild.offsetHeight + 2 + 'px';
document.getElementById(parentDiv).appendChild(this.elNearbyListContainer);
containerDiv = this.elNearbyListContainer;
if (this.controlMode && this.controlMode === 'dependend')
this.elNearbyListContainer.style.visibility = 'hidden';
}
containerDiv.appendChild(this.elementDiv);
//var cameraMovedCallback = function (state) {
// this.center = this.mapView.getCursorPositionWGS();
// this.updateNearby();
//}.bind(this);
if (this.center === undefined) {
this.center = mapView.getCursorPositionWGS();
}
//mapView.registerCameraChangeStateCallback(cameraMovedCallback);
this.mapView = mapView;
}
preRenderCallback() {
if (this.selectedButton && this.selectedLandmark) {
let coordsPoint = this.selectedLandmark.getCoordinates();
let screenCoords = this.mapView.transformWgsToScreen(coordsPoint);
let dx = (screenCoords.x - this.selectedButton.halfsizeX);
let dy = (screenCoords.y - this.selectedButton.halfsizeY);
this.selectedButton.style.transform = "translate3d(" + dx + "px," + dy + "px,0px)";
}
}
showSelectedBubble() {
if (!this.selectedButton || !this.selectedLandmark)
return;
let coordsPoint = this.selectedLandmark.getCoordinates();
let screenCoords = this.mapView.transformWgsToScreen(coordsPoint);
let dx = (screenCoords.x - this.selectedButton.halfsizeX);
let dy = (screenCoords.y - this.selectedButton.halfsizeY);
this.selectedButton.style.transform = "translate3d(" + dx + "px," + dy + "px,0px)";
this.selectedButton.style.visibility = '';
this.selectedBubble = document.getElementById('gem-landmark-bubble');
if (!this.selectedBubble) {
this.selectedBubble = this.selectedButton.appendChild(document.createElement('div'));
this.selectedBubble.id = 'gem-landmark-bubble';
this.selectedBubble.className = 'gem-landmark-bubble';
let elLmkBubbleText = this.selectedBubble.appendChild(document.createElement('div'));
elLmkBubbleText.className = 'gem-landmark-bubble-text';
let elLmkBubbleTitle = elLmkBubbleText.appendChild(document.createElement('div'));
elLmkBubbleTitle.id = 'gem-landmark-bubble-title';
elLmkBubbleTitle.className = 'gem-landmark-bubble-title';
}
document.getElementById('gem-landmark-bubble-title').innerHTML = this.selectedLandmark.getName();
this.selectedBubble.style.visibility = '';
}
updateNearby() {
if (this.selectedFilter) {
if (this.selectedFilter.size() !== 0) {
if (this.resultList === undefined) {
this.resultList = new gem.core.LandmarkList();
}
let resultTouched = new gem.core.LandmarkList();
let callbackFunction = function (reason) {
this.elementDiv.style.visibility = 'visible';
if (this.elNearbyListContainer)
this.elNearbyListContainer.style.visibility = 'visible';
if (this.customContainer)
document.getElementById(this.customContainer).style.display = 'block';
console.log("Reason is " + reason);
// Set the result highlight color (rgba) to red
this.mapView.activateHighlight(this.resultList, {
r: 255,
g: 0,
b: 0,
a: 255
},
gem.d3Scene.EHighlightOptions.EHO_ShowLandmark.value |
gem.d3Scene.EHighlightOptions.EHO_Overlap.value | gem.d3Scene.EHighlightOptions.EHO_Group.value, -1);
let cb = function (resultedTouches) {
if (resultTouched.size()) {
let pickedLmkId = resultTouched.get(0).getLandmarkId();
let pickedLmkName = resultTouched.get(0).getName();
let pickedLmkCoords = resultTouched.get(0).getCoordinates();
let pickedLmkDescr = resultTouched.get(0).getDescription();
let idx;
for (let i = 0; i < this.resultList.size(); i++) {
let resultCoords = this.resultList.get(i).getCoordinates();
// use this check because landmark ids are not unique (they are the landmark type codes)
if (this.resultList.get(i).getLandmarkId() == pickedLmkId &&
this.resultList.get(i).getName() == pickedLmkName &&
this.resultList.get(i).getDescription() == pickedLmkDescr &&
resultCoords.longitude === pickedLmkCoords.longitude &&
resultCoords.latitude === pickedLmkCoords.latitude) {
this.selectedLandmark = this.resultList.get(i);
idx = i;
// activate list item
let selectedListItem = document.getElementById("nearbyList" + idx);
if (selectedListItem) {
let selectedItems = document.getElementsByClassName(selectedListItem.className + ' active');
if (selectedItems && selectedItems.length)
selectedItems[0].classList.remove('active');
selectedListItem.classList.add('active');
selectedListItem.scrollIntoView({
behaviour: 'smooth',
block: 'nearest',
inline: 'nearest'
});
}
this.showSelectedBubble();
break;
}
}
}
}.bind(this);
this.mapView.registerLandmarkClickedEvent(resultTouched, cb);
this.updateResultList();
}.bind(this);
// Search around specified coordinates
gem.places.Search.searchPoiCategory(this.selectedFilter, this.center, callbackFunction, this.resultList, 4000);
} else {
while (this.elementDiv.firstChild) {
this.elementDiv.firstChild.remove();
}
if (this.elNearbyListContainer)
this.elNearbyListContainer.style.visibility = 'hidden';
this.elementDiv.style.visibility = 'hidden';
if (this.customContainer)
document.getElementById(this.customContainer).style.visibility = 'none';
this.mapView.deactivateHighlight();
}
}
}
updateResultList() {
while (this.elementDiv.firstChild) {
this.elementDiv.firstChild.remove();
}
if (!this.selectedButton) {
this.selectedButton = document.createElement('div');
this.selectedButton.className = 'gem-highlight-landmark-icon';
document.getElementById(this.parentDiv).appendChild(this.selectedButton);
}
this.selectedButton.style.top = "0px";
this.selectedButton.style.left = "0px";
this.selectedButton.style.width = "30px";
this.selectedButton.style.height = "30px";
this.selectedButton.style.visibility = "hidden";
this.selectedButton.halfsizeY = 20;
this.selectedButton.halfsizeX = 20;
let resultCoordinates = [];
for (let i = 0; i < this.resultList.size(); i++) {
let pElement = document.createElement("div");
let resultLandmark = this.resultList.get(i);
resultCoordinates.push(resultLandmark.getCoordinates());
if (this.populateItemFunction) {
this.populateItemFunction(pElement, resultLandmark);
} else {
pElement.className = 'gem-marker-list-item';
pElement.innerText = resultLandmark.getFormatedName();
}
let id = i;
pElement.id = "nearbyList" + id;
pElement.style.cursor = 'pointer';
pElement.onmouseenter = function () {
if (this.selectedBubble)
this.selectedBubble.style.visibility = 'hidden';
this.selectedButton.style.visibility = 'visible';
this.selectedLandmark = resultLandmark;
let groupId = this.mapView.getHighlightGroupItemIndex(id);
let groupLandmark = this.resultList.get(groupId);
let coordsPoint = groupLandmark.getCoordinates();
let screenCoords = this.mapView.transformWgsToScreen(coordsPoint);
let dx = (screenCoords.x - this.selectedButton.halfsizeX);
let dy = (screenCoords.y - this.selectedButton.halfsizeY);
this.selectedButton.style.transform = "translate3d(" + dx + "px," + dy + "px,0px)";
let bitmapContainer = new gem.core.BitmapContainer(40, 40);
resultLandmark.getImage(bitmapContainer);
let canvasIcon = document.createElement('canvas');
canvasIcon.className = "scale";
gem.core.App.setCanvas(bitmapContainer.toImageData(), 40, 40, canvasIcon);
this.selectedButton.appendChild(canvasIcon);
}.bind(this);
pElement.onmouseleave = function () {
this.selectedButton.style.visibility = 'hidden';
while (this.selectedButton.firstChild)
this.selectedButton.removeChild(this.selectedButton.firstChild);
this.mapView.activateHighlight(this.resultList, {
r: 255,
g: 0,
b: 0,
a: 255
},
gem.d3Scene.EHighlightOptions.EHO_ShowLandmark.value | gem.d3Scene.EHighlightOptions.EHO_NoFading.value |
gem.d3Scene.EHighlightOptions.EHO_Overlap.value | gem.d3Scene.EHighlightOptions.EHO_Group.value, -1);
let selectedItems = this.elementDiv.getElementsByClassName('active');
if (selectedItems && selectedItems.length) {
let idx = parseInt(selectedItems[0].id.replace('nearbyList', ''));
this.selectedLandmark = this.resultList.get(idx);
let coordsPoint = this.selectedLandmark.getCoordinates();
let screenCoords = this.mapView.transformWgsToScreen(coordsPoint);
let dx = (screenCoords.x - this.selectedButton.halfsizeX);
let dy = (screenCoords.y - this.selectedButton.halfsizeY);
this.selectedButton.style.transform = "translate3d(" + dx + "px," + dy + "px,0px)";
this.selectedButton.style.visibility = 'visible';
this.showSelectedBubble();
}
}.bind(this);
pElement.onclick = function () {
this.selectedButton.style.visibility = 'hidden';
this.selectedLandmark = resultLandmark;
let selectedItems = document.getElementsByClassName(pElement.className + ' active');
if (selectedItems && selectedItems.length)
selectedItems[0].classList.remove('active');
pElement.classList.add('active');
let listWithoutI = new gem.core.LandmarkList();
for (let j = 0; j < this.resultList.size(); j++) {
if (j !== id)
listWithoutI.push_back(this.resultList.get(j));
}
this.mapView.activateHighlight(listWithoutI, {
r: 255,
g: 0,
b: 0,
a: 255
},
gem.d3Scene.EHighlightOptions.EHO_ShowLandmark.value | gem.d3Scene.EHighlightOptions.EHO_NoFading.value | gem.d3Scene.EHighlightOptions.EHO_Group.value |
gem.d3Scene.EHighlightOptions.EHO_Overlap.value, -1);
if (this.onSelectCallback)
this.onSelectCallback(resultLandmark);
else {
this.showSelectedBubble();
let coords = resultLandmark.getCoordinates();
coords.altitude = 200;
this.mapView.centerOnCoordinates(coords, 2000);
}
}.bind(this);
this.elementDiv.appendChild(pElement);
}
// zoom to bounding box
let resultsBBox = gem.core.App.getBoundingBoxForCoordinates(resultCoordinates);
if (!resultsBBox.isEmpty) {
// adjust bbox
let mapCanvas = document.getElementById(this.parentDiv);
if (mapCanvas) {
let adjustRectangle = {
x: mapCanvas.offsetLeft + mapCanvas.offsetWidth / 4,
y: mapCanvas.offsetTop + mapCanvas.offsetHeight / 4,
width: mapCanvas.offsetWidth / 2,
height: mapCanvas.offsetHeight / 2
};
this.mapView.centerOnArea(resultsBBox.leftTop, resultsBBox.rightBottom, 2000, adjustRectangle);
} else
this.mapView.centerOnArea(resultsBBox.leftTop, resultsBBox.rightBottom, 2000);
}
}
updateCategoryList(categoryList) {
this.selectedFilter = categoryList;
this.updateNearby();
}
}
gem.control.POICategoryListControl = class POICategoryListControl extends gem.control.BaseControl {
constructor(initOptions) {
super(gem.control.TConntrolExecuteType.ONCONNECTED);
if (initOptions) {
this.customContainer = initOptions.container;
}
}
resetList() {
while (this.elementDiv.firstChild) {
this.elementDiv.firstChild.remove();
}
this.arrayList.clear();
let i = 0;
for (i = 0; i < this.listItems.size(); i++) {
let categoryItem = this.listItems.get(i);
let pElement = document.createElement("div");
pElement.className = 'gem-marker-list-item';
pElement.style.cursor = 'pointer';
var bitmapContainer = new gem.core.BitmapContainer(20, 20);
let poiIcon = document.createElement("CANVAS");
poiIcon.style = "margin-top: auto;margin-bottom: auto;";
categoryItem.getImage(bitmapContainer);
gem.core.App.setCanvas(bitmapContainer.toImageData(), 20, 20, poiIcon);
pElement.appendChild(poiIcon);
bitmapContainer.delete();
let textPart = document.createElement('SPAN');
textPart.innerText = categoryItem.getName();
pElement.appendChild(textPart);
pElement.onclick = function () {
if (pElement.getElementsByTagName('SPAN').length > 1) {
let elementSpan = pElement.getElementsByTagName('SPAN')[1];
pElement.removeChild(elementSpan);
this.arrayList.delete(categoryItem.getId());
this.updateList();
} else {
var x = document.createElement("SPAN");
x.innerHTML = '✓';
pElement.appendChild(x);
this.arrayList.set(categoryItem.getId(), categoryItem);
this.updateList();
}
}.bind(this);
this.elementDiv.appendChild(pElement);
}
}
initControl(parentDiv, mapView) {
this.selectedFilter = new gem.core.LandmarkCategoryList();
this.elementDiv = document.createElement("div");
this.elementDiv.classList.add("gem-markers-menu-list");
let containerDiv = document.getElementById(this.customContainer ? this.customContainer : parentDiv);
containerDiv.appendChild(this.elementDiv);
this.mapView = mapView;
this.arrayList = new Map();
this.listItems = gem.content.Manager.getGenericCategories();
this.resetList();
if (this.controlMode && this.controlMode === 'dependend') {
this.elementDiv.style.visibility = 'hidden';
if (this.customContainer)
document.getElementById(this.customContainer).style.display = 'none';
}
}
registerListUpdatedNotifier(pListNotifier) {
this.pListNotifier = pListNotifier;
}
updateList() {
if (this.pListNotifier) {
let i = 0;
this.selectedFilter.delete();
this.selectedFilter = new gem.core.LandmarkCategoryList();
function iterateMapElements(value, key, map) {
this.selectedFilter.push_back(value);
}
this.arrayList.forEach(iterateMapElements.bind(this));
this.pListNotifier(this.selectedFilter);
}
}
setControlMode(mode) {
this.controlMode = mode;
}
notifySearchSelection(item) {
this.resetList();
if (!item) {
this.elementDiv.style.visibility = 'hidden';
if (this.customContainer)
document.getElementById(this.customContainer).style.display = 'none';
} else {
this.elementDiv.style.visibility = 'visible';
if (this.customContainer)
document.getElementById(this.customContainer).style.display = 'block';
}
}
show() {
this.elementDiv.style.visibility = 'visible';
if (this.customContainer)
document.getElementById(this.customContainer).style.display = 'block';
}
hide() {
this.elementDiv.style.visibility = 'hidden';
if (this.customContainer)
document.getElementById(this.customContainer).style.display = 'none';
}
}
/**
* @callback callbackMarkersFeed
* @param {number} mapCenterLon - visible map center longitude
* @param {number} mapCenterLat - visible map center latitude
* @param {number} mapLonMin - visible map minimum longitude
* @param {number} mapLatMin - visible map minimum latitude
* @param {number} mapLonMax - visible map maximum longitude
* @param {number} mapLatMax - visible map maximum latitude
* @param {object} filters - filters map
* @param {string} filters.name - unique name of the filter
* @param {object[]} filters.values - filter values
* @param {string} filter.values.key - item property key to use for filter option
* @param {string} filter.values.value - item property value to use for filter option
* @param {AbortController.signal} signal - use in request to cancel if a new request has been triggered
*/
/**
* @callback callbackMarkersAreaSelection
* @param {object} area - area coordinates array
* @param {object} filters - filters map
* @param {AbortController.signal} signal - use in request to cancel if a new request has been triggered
*/
/** Control for displaying data on a map using a server database as source
* @class gem.control.CustomQueryAddedDataControl
*
* @param {string} iconUrl - path/url to marker image/icon
* @param {object[]} [iconFilter] - filters for applying different icons to markers based on their poperties
* @param {string} iconFilter[].key - data source item property key
* @param {string} iconFilter[].value - data source item property value
* @param {string} iconFilter[].iconClass - css class to use for this filter
* @param {object} [dataOptions] - options for displaying data source items
* @param {object} dataOptions.marker - options for markers display on map
* @param {string} dataOptions.marker.cssClass - specify custom marker style rules
* @param {string} dataOptions.marker.highlightClass - specify selected marker custom highlight style rules
* @param {number} [dataOptions.marker.width = 20]
* @param {number} [dataOptions.marker.height = 20]
* @param {number} [dataOptions.marker.hoverWidth = 25]
* @param {number} [dataOptions.marker.hoverHeight = 25]
* @param {string} [dataOptions.marker.markerPos = 'center'] - where to place the marker relative to the item coordinate
* @param {callbackMarker} dataOptions.marker.markerFunction - fully customize marker appearance
* @param {object} dataOptions.markerBubble - options for styling the marker bubble on click/hover
* @param {string[]} dataOptions.markerBubble.title - data source properties to use for marker bubble title text
* @param {string} dataOptions.markerBubble.image - data source image url property to use for marker bubble image
* @param {number} [dataOptions.markerBubble.width = 240] - bubble width in px
* @param {number} [dataOptions.markerBubble.height = 200] - bubble height in px
* @param {bool} [dataOptions.markerBubble.enableHover = true] - disable marker bubble interaction on hover
* @param {bool} [dataOptions.markerBubble.enableClick = true] - disable marker bubble interaction on click
* @param {string} dataOptions.markerBubble.markerBubbleClass - custom css class for marker bubble
* @param {callbackMarkerBubble} dataOptions.markerBubble.markerBubbleFunction - fully customize marker bubble
* @param {object} dataOptions.markerGrouping - marker grouping options
* @param {number} [dataOptions.markerGrouping.maxLevel = 13] - maximum map level to apply grouping ( max allowed 15 ), not available for studio data
* @param {object} [dataOptions.markerGrouping.style = gem.control.MarkersGroupStyleType.default] - style to apply to marker groups
* @param {callbackMarkerGroup} [dataOptions.markerGrouping.markerGroupFunction] - fully customize marker groups style
* @param {object} feedDataOptions
* @param {bool} [feedDataOptions.populateForMapBrowse = true]
* @param {callbackMarkersFeed} feedDataOptions.markersFeedFunction - callback for adding data during map browse
* @param {callbackMarkersAreaSelection} feedDataOptions.markersAreaSelectionFunction - callback for adding data in the selected area
*/
gem.control.CustomQueryAddedDataControl = class CustomQueryAddedDataControl extends gem.control.AddedDataControl {
constructor(iconUrl, iconFilter, dataOptions, feedDataOptions) {
super(gem.control.TConntrolExecuteType.ONCONNECTED, gem.control.TConntrolItemUpdateMode.LIST, dataOptions);
this.iconUrl = iconUrl;
if (iconFilter) {
this.iconFilter = iconFilter;
this.iconUrl = super.iconFilter.bind(this);
}
const defaultFeedDataOptions = {
populateForMapBrowse: true,
markersFeedFunction: undefined,
/*function(mapCenterLon, mapCenterLat, mapLonMin, mapLatMin, mapLonMax, mapLatMax, filters, signal)*/
markersAreaSelectionFunction: undefined /*function(area, filters, signal) */
}
this.feedDataOptions = Object.assign({}, defaultFeedDataOptions, feedDataOptions);
this.doneMapBrowsing = 1000; /*ms*/
this.filterCategories = new Map();
}
cameraChangedCallback() {
if (this.mCameraCallback) {
clearTimeout(this.mapMoveTymer);
this.mapMoveTymer = setTimeout(() => {
if (this.mCameraCallback)
this.mCameraCallback().catch(err => {
console.log('camera callback cancelled', err);
});
}, this.doneMapBrowsing);
}
}
initControl(parentDiv, mapView) {
this.controlName = "customQueryAdded";
this.mapView = mapView;
this.mapView.setNorthFixedFlag(true);
this.externalRenderObj = new gem.d3Scene.ExternalRenderer(
this.iconUrl, this.controlName, mapView, parentDiv, this.options.marker.cssClass, this.rendererOptions);
this.externalRenderObj.registerMouseOverCallback(this.mouseOver.bind(this));
this.externalRenderObj.registerMouseOutCallback(this.mouseOut.bind(this));
this.externalRenderObj.registerMouseClickCallback(this.mouseClick.bind(this));
if (this.selectedItemClass)
this.externalRenderObj.registerItemSelectedCallback(this.itemSelected.bind(this));
this.externalRenderObj.registerItemAddedCallback(function (itemElementHtmlId, item, isGroup) {
if (this.addItemToList)
this.addItemToList(itemElementHtmlId, item, isGroup);
}.bind(this));
this.externalRenderObj.registerItemRemovedCallback(function (itemElementHtmlId, item, isGroup) {
if (this.removeItemFromList)
this.removeItemFromList(itemElementHtmlId, item, isGroup);
}.bind(this));
// markers finished rendering callback
this.callbackMarkersRendered = (reason) => {
if (this.externalRenderObj) {
this.externalRenderObj.sourceIsPending = false;
}
if (this.listChangedNotifier)
this.listChangedNotifier(this.externalRenderObj.name, this.mapView);
if (this.listLoadingDoneNotifier)
this.listLoadingDoneNotifier();
};
this.cameraMoveInProgress = false;
let requestAborted = false;
this.abortController = new AbortController();
// camera moved callback
this.cameraMovedCallback = async function () {
if (this.cameraMoveInProgress) {
this.abortController.abort();
requestAborted = true;
}
this.cameraMoveInProgress = true;
if (this.listLoadingNotifier)
this.listLoadingNotifier();
let data;
if (this.feedDataOptions.populateForMapBrowse && this.feedDataOptions.markersFeedFunction) {
let mapCanvas = document.getElementById(gem.core.App.initOptions.container);
if (mapCanvas) {
this.mapWgsCenter = this.mapView.getCursorPositionWGS();
let mapScreenTopLeft = {
x: mapCanvas.clientLeft,
y: mapCanvas.clientTop
};
let mapScreenBottomRight = {
x: mapCanvas.clientLeft + mapCanvas.clientWidth,
y: mapCanvas.clientTop + mapCanvas.clientHeight
}
let mapWgsTopLeft = this.mapView.transformScreenToWgs(mapScreenTopLeft);
let mapWgsBottomRight = this.mapView.transformScreenToWgs(mapScreenBottomRight);
this.mapWgsLonMin = mapWgsTopLeft.longitude;
this.mapWgsLonMax = mapWgsBottomRight.longitude;
this.mapWgsLatMin = Math.min(mapWgsTopLeft.latitude, mapWgsBottomRight.latitude);
this.mapWgsLatMax = Math.max(mapWgsTopLeft.latitude, mapWgsBottomRight.latitude);
this.abortController = new AbortController();
data = await this.feedDataOptions.markersFeedFunction(this.mapWgsCenter.longitude, this.mapWgsCenter.latitude,
this.mapWgsLonMin, this.mapWgsLatMin, this.mapWgsLonMax, this.mapWgsLatMax, this.filterCategories, this.abortController.signal);
}
}
if (!requestAborted) {
try {
// clear previous source store data if exists
if (this.sourcesList) {
if (this.sourcesList.size() > 0) {
if (this.externalRenderObj) {
this.externalRenderObj.sourceIsPending = true;
this.externalRenderObj.clear();
this.externalRenderObj.destroyHasBeenCalled = undefined;
}
this.mapView.removeVectorSource(this.sourcesList.get(0));
}
this.sourcesList.delete();
this.sourcesList = new gem.d3Scene.MarkerCollectionRefList();
} else
this.sourcesList = new gem.d3Scene.MarkerCollectionRefList();
this.mapView.addGeoJsonAsCustomMarkers(JSON.stringify(data), this.controlName, this.sourcesList, this.externalRenderObj, this.options.markerGrouping.maxLevel);
if (!data || !data.features || !data.features.length) {
if (this.listChangedNotifier)
this.listChangedNotifier(this.externalRenderObj.name, this.mapView);
if (this.listLoadingDoneNotifier)
this.listLoadingDoneNotifier();
}
} catch (e) {
console.log("CustomQueryAddedDataControl error: invalid data for markers");
}
this.mapView.registerForNextRenderFinished(this.callbackMarkersRendered);
} else
requestAborted = false;
this.cameraMoveInProgress = false;
}.bind(this);
this.mCameraCallback = this.cameraMovedCallback.bind(this);
this.cameraMovedCallback();
}
getItemsList() {
if (!this.sourcesList || !this.sourcesList.size())
return undefined;
return this.sourcesList.get(0);
}
getItemsSource() {
if (!this.sourcesList || !this.sourcesList.size())
return undefined;
return this.sourcesList.get(0);
}
notifyChangeFilterData(type, name, values) {
this.filterCategories.set(name, values);
this.updateDataSource();
}
updateDataSource() {
if (this.mCameraCallback)
this.mCameraCallback();
else
this.areaSelection();
}
toggleCameraCallback() {
if (this.mCameraCallback) {
this.mCameraCallback = undefined;
} else {
this.mCameraCallback = this.cameraMovedCallback.bind(this);
this.mCameraCallback();
}
}
notifyAreaSelection(area, areaMarkerGroupMaxLevel) {
this.area = area;
this.areaMarkerGroupMaxLevel = areaMarkerGroupMaxLevel;
this.updateDataSource();
}
async areaSelection() {
let requestAborted = false;
if (this.listLoadingNotifier)
this.listLoadingNotifier();
let data;
if (this.feedDataOptions && this.feedDataOptions.markersAreaSelectionFunction) {
this.abortController = new AbortController();
data = await this.feedDataOptions.markersAreaSelectionFunction(this.area, this.filterCategories, this.abortController.signal);
}
if (!requestAborted) {
try {
// clear previous source store data if exists
if (this.sourcesList) {
if (this.sourcesList.size() > 0) {
if (this.externalRenderObj) {
this.externalRenderObj.sourceIsPending = true;
this.externalRenderObj.clear();
this.externalRenderObj.destroyHasBeenCalled = undefined;
}
this.mapView.removeVectorSource(this.sourcesList.get(0));
}
this.sourcesList.delete();
this.sourcesList = new gem.d3Scene.MarkerCollectionRefList();
} else
this.sourcesList = new gem.d3Scene.MarkerCollectionRefList();
this.mapView.addGeoJsonAsCustomMarkers(JSON.stringify(data), this.controlName, this.sourcesList, this.externalRenderObj, this.areaMarkerGroupMaxLevel);
if (!data || !data.features || !data.features.length) {
if (this.listChangedNotifier)
this.listChangedNotifier(this.externalRenderObj.name, this.mapView);
if (this.listLoadingDoneNotifier)
this.listLoadingDoneNotifier();
}
} catch (e) {
console.log("CustomQueryAddedDataControl error: invalid data for markers");
}
this.mapView.registerForNextRenderFinished(this.callbackMarkersRendered);
} else
requestAborted = false;
}
}
/** Control for displaying data from a studio data source query around a location
* @class gem.control.StudioQueryDataControl
*
* @param {number} dataSourceId - studio data source id
* @param {string} iconUrl - path/url to marker image/icon
* @param {object} [dataOptions] - options for displaying data source items
* @param {object} dataOptions.marker - options for markers display on map
* @param {string} dataOptions.marker.cssClass - specify custom marker style rules
* @param {string} dataOptions.marker.highlightClass - specify selected marker custom highlight style rules
* @param {number} [dataOptions.marker.width = 20]
* @param {number} [dataOptions.marker.height = 20]
* @param {number} [dataOptions.marker.hoverWidth = 25]
* @param {number} [dataOptions.marker.hoverHeight = 25]
* @param {string} [dataOptions.marker.markerPos = 'center'] - where to place the marker relative to the item coordinate
* @param {callbackMarker} dataOptions.marker.markerFunction - fully customize marker appearance
* @param {object} dataOptions.markerBubble - options for styling the marker bubble on click/hover
* @param {string[]} dataOptions.markerBubble.title - data source properties to use for marker bubble title text
* @param {string} dataOptions.markerBubble.image - data source image url property to use for marker bubble image
* @param {number} [dataOptions.markerBubble.width = 240] - bubble width in px
* @param {number} [dataOptions.markerBubble.height = 200] - bubble height in px
* @param {bool} [dataOptions.markerBubble.enableHover = true] - disable marker bubble interaction on hover
* @param {bool} [dataOptions.markerBubble.enableClick = true] - disable marker bubble interaction on click
* @param {string} dataOptions.markerBubble.markerBubbleClass - custom css class for marker bubble
* @param {callbackMarkerBubble} dataOptions.markerBubble.markerBubbleFunction - fully customize marker bubble
* @param {object} dataOptions.markerGrouping - marker grouping options
* @param {number} [dataOptions.markerGrouping.maxLevel = 13] - maximum map level to apply grouping ( max allowed 15 ), not available for studio data
* @param {object} [dataOptions.markerGrouping.style = gem.control.MarkersGroupStyleType.default] - style to apply to marker groups
* @param {callbackMarkerGroup} [dataOptions.markerGrouping.markerGroupFunction] - fully customize marker groups style
* @param {object[]} [iconFilter] - filters for applying different icons to markers based on their properties
* @param {string} iconFilter[].key - data source item property key
* @param {string} iconFilter[].value - data source item property value
* @param {string} iconFilter[].iconClass - css class to use for this filter
*/
gem.control.StudioQueryDataControl = class StudioQueryDataControl extends gem.control.AddedDataControl {
constructor(dataSourceId, iconUrl, dataOptions, iconFilter) {
super(gem.control.TConntrolExecuteType.ONCONNECTED, gem.control.TConntrolItemUpdateMode.LIST, dataOptions);
this.dataSourceId = dataSourceId;
this.iconUrl = iconUrl;
if (iconFilter) {
this.iconFilter = iconFilter;
this.iconUrl = super.iconFilter.bind(this);
}
}
cameraChangedCallback() {
if (this.mCameraCallback) {
this.mCameraCallback();
}
}
initControl(parentDiv, mapView) {
this.controlName = "studioQueryData";
this.sourcesList = new gem.d3Scene.MarkerCollectionRefList();
this.externalRenderObj = new gem.d3Scene.ExternalRenderer(
this.iconUrl, this.controlName, mapView, parentDiv, this.options.marker.cssClass, this.rendererOptions);
this.externalRenderObj.registerMouseOverCallback(this.mouseOver.bind(this));
this.externalRenderObj.registerMouseOutCallback(this.mouseOut.bind(this));
this.externalRenderObj.registerMouseClickCallback(this.mouseClick.bind(this));
if (this.selectedItemClass)
this.externalRenderObj.registerItemSelectedCallback(this.itemSelected.bind(this));
this.externalRenderObj.registerItemAddedCallback(function (itemElementHtmlId, item) {
if (this.itemAddedNotifier)
this.itemAddedNotifier(itemElementHtmlId, item);
}.bind(this));
this.externalRenderObj.registerItemRemovedCallback(function (itemElementHtmlId, item) {
if (this.itemRemovedNotifier)
this.itemRemovedNotifier(itemElementHtmlId, item);
}.bind(this));
this.mapView = mapView;
// overlay tiles db search request
let urlService = "";
let serviceIds = gem.content.Manager.getServicesIds();
for(const id of serviceIds)
{
if (gem.content.Manager.getServiceName(id) === "Overlays")
{
urlService = gem.content.Manager.getCustomUrlList(id);
break;
}
}
if (!urlService || !urlService.size()) {
return;
}
this.strServiceUrl = urlService.get(0) + "/overlays/search/";
this.filterCategories = new Map(); /* key - filter name, values - selected filter values */
this.distanceRadius = 10; /*km*/
}
getItemsList() {
if (!this.sourcesList || !this.sourcesList.size())
return undefined;
return this.sourcesList.get(0);
}
getItemsSource() {
if (!this.sourcesList || !this.sourcesList.size())
return undefined;
return this.sourcesList.get(0);
}
notifyChangeFilterData(type, name, values) {
switch (type) {
case 'category':
if (values && values.length > 0) {
this.filterCategories.set(name, values);
}
break;
case 'distance':
if (values && values.length && !isNaN(values)) {
this.distanceRadius = values;
}
}
this.updateDataSource();
}
updateDataSource() {
if (!this.refLocation) {
console.log("no reference location");
return;
}
// check reference location coords validity
let refCoordinates = this.refLocation.getCoordinates();
if (refCoordinates.latitude < -90 || refCoordinates.latitude > 90 ||
refCoordinates.longitude < -180 || refCoordinates > 180) {
console.log("invalid coords");
return;
}
// clear previous store data if exists
if (this.sourcesList) {
if (this.sourcesList.size() > 0)
{
if (this.externalRenderObj) {
this.externalRenderObj.sourceIsPending = true;
this.externalRenderObj.clear();
this.externalRenderObj.destroyHasBeenCalled = undefined;
}
this.mapView.removeVectorSource(this.sourcesList.get(0));
}
this.sourcesList.delete();
this.sourcesList = new gem.d3Scene.MarkerCollectionRefList();
}
var searchUrl = new URL(this.strServiceUrl);
let strfilter = '';
if (this.filterCategories && this.filterCategories.size) {
for (const [name, filters] of this.filterCategories.entries()) {
if (filters) {
strfilter += '|';
for (let i = 0; i < filters.length; i++) {
if (!filters[i] || !filters[i].key || !filters[i].key.length)
continue;
strfilter += '$k=' + filters[i].key;
if (filters[i].value)
strfilter += ';v=' + filters[i].value + '$';
}
strfilter += '|';
}
}
}
let strparams = encodeURI("&provider_id=6¶m_id=" + this.dataSourceId + "&lon=" + refCoordinates.longitude +
"&lat=" + refCoordinates.latitude + "&distance=" + this.distanceRadius + "&unit=" + this.distanceUnit + "&filters=" + strfilter);
searchUrl += strparams;
const searchHeaders = new Headers();
const searchRequest = new Request(searchUrl, {
method: "GET",
headers: searchHeaders
});
let kFlyDuration = 1000; /*ms*/
// add stores on map as geojson source
fetch(searchRequest)
.then(response => response.text())
.then(data => {
var jsonData = JSON.parse(data);
if (jsonData.features.length > 0) {
this.mapView.addGeoJsonAsCustomMarkers(data, this.controlName, this.sourcesList, this.externalRenderObj);
// fly to stores bounding box
if (this.sourcesList.size() > 0) {
var storesBbox = this.sourcesList.get(0).getArea();
if (storesBbox.isEmpty == true) {
let coordsItem = this.sourcesList.get(0).getMarkerAt(0).getCoordinatesPartAt(0).get(0);
this.mapView.centerOnCoordinates(coordsItem, kFlyDuration);
} else {
this.mapView.centerOnArea(storesBbox.leftTop, storesBbox.rightBottom, kFlyDuration);
}
}
} else {
// no stores found around location
this.mapView.centerOnCoordinates(refCoordinates, kFlyDuration);
}
// list change
if (this.listChangedNotifier)
this.listChangedNotifier(this.externalRenderObj.name, this.mapView);
})
.catch(e => {
console.log(e);
});
}
}
/** Control for displaying a distance filter applied to a data source control
* @param {object} filterOptions - distance filter options
* @param {string} filterOptions.parentContainer - the parent element id where to add the filter element
* @param {string} filterOptions.name - unique name of the filter
* @param {string} [filterOptions.title] - title text to display for the filter
* @param {string} [filterOptions.eUnit = 'km'] - available options 'km', 'mile'
* @param {number[]} [filterOptions.thresholds = [10, 25, 50, 100, 200]] - specify filter distance options
* @param {string} [filterOptions.style = 'dropdown']
* @param {object} [filterOptions.cssClasses] - customize filter style rules
* @param {string} [filterOptions.cssClasses.container]
* @param {string} [filterOptions.cssClasses.selectContainer]
* @param {string} [filterOptions.cssClasses.titleContainer]
* @param {gem.control.AddedDataControl} addedDataControl - data source control
*/
gem.control.DistanceFilterControl = class DistanceFilterControl extends gem.control.BaseControl {
constructor(filterOptions, addedDataControl) {
super(gem.control.TConntrolExecuteType.ONCONNECTED);
this.addedDataControl = addedDataControl;
let defaultOptions = {
parentContainer: '',
name: '',
title: '',
eUnit: 'km',
thresholds: [10, 25, 50, 100, 200],
style: 'dropdown',
cssClasses: {
container: 'gem-markers-filter-distance',
selectContainer: 'gem-markers-filter-distance-select',
titleContainer: 'gem-markers-filter-distance-title'
}
}
this.options = Object.assign({}, defaultOptions, filterOptions);
this.type = 'distance';
}
initControl(parentDiv, mapView) {
if (!this.addedDataControl.notifyChangeFilterData) {
console.log("data source control does not support distance filter");
return;
}
if (this.addedDataControl.feedDataOptions && this.addedDataControl.feedDataOptions.populateForMapBrowse) {
console.log("data source control does not support distance filter");
return;
}
this.mapView = mapView;
let elFiltersContainer = document.getElementById(this.options.parentContainer);
if (!elFiltersContainer) {
elFiltersContainer = document.createElement('div');
elFiltersContainer.id = this.options.parentContainer;
elFiltersContainer.className = this.options.parentContainer;
document.getElementById(parentDiv).appendChild(elFiltersContainer);
}
this.createDistanceFilterControl(elFiltersContainer);
}
createDistanceFilterControl(parentDiv) {
if (!this.options.thresholds) {
console.log("no distance thresholds set for distanceFilter");
return;
}
let elDistance = document.createElement('div');
elDistance.className = this.options.cssClasses.container;
// distance radius thresholds
let distanceThresholds = this.options.thresholds;
let elSelect = document.createElement('select');
elSelect.className = this.options.cssClasses.selectContainer;
for (let i = 0; i < distanceThresholds.length; i++) {
let distanceOption = document.createElement('option');
distanceOption.setAttribute('value', distanceThresholds[i]);
distanceOption.textContent = distanceThresholds[i];
elSelect.appendChild(distanceOption);
}
elDistance.appendChild(elSelect);
// first value default selected
this.addedDataControl.notifyChangeFilterData(this.type, this.options.name, distanceThresholds[0]);
// event listener on change
this.addedDataControl.distanceUnit = this.options.eUnit;
elSelect.addEventListener('change', () => {
this.addedDataControl.notifyChangeFilterData(this.type, this.options.name, elSelect.value);
});
// title - optional
if (this.options.title) {
let elTitle = document.createElement('div');
elTitle.className = this.options.cssClasses.titleContainer;
let spanTitle = document.createElement('span');
spanTitle.textContent = this.options.title;
elTitle.appendChild(spanTitle);
elDistance.insertBefore(elTitle, elDistance.firstChild);
}
parentDiv.appendChild(elDistance);
}
}
/** Control for displaying a categories (properties) filter applied to a data source control
* @param {object} filterOptions - category filter options
* @param {string} filterOptions.parentContainer - the parent element id where to add the filter element
* @param {bool} [filterOptions.collapsible = true] - create a collapsible filter
* @param {bool} [filterOptions.startCollapsed = true] - show filter categories collapsed at start-up
* @param {string} filterOptions.name - unique name of the filter
* @param {string} [filterOptions.title] - title text to display for the filter
* @param {object[]} filterOptions.categories
* @param {string} filterOptions.categories.label - label text to display for the filter option
* @param {object} filterOptions.categories.filter
* @param {string} filterOptions.categories.filter.key - data source item property key to filter
* @param {string} filterOptions.categories.filter.value - data source item property value to filter
* @param {object} filterOptions.categories.children - applicable for 'checkboxes' style
* @param {string} [filterOptions.style = 'radio'] - available options 'radio', 'checkboxes'
* @param {object} [filterOptions.cssClasses] - customize filter style rules
* @param {string} [filterOptions.cssClasses.container]
* @param {string} [filterOptions.cssClasses.filterHeader]
* @param {string} [filterOptions.cssClasses.collapsible]
* @param {string} [filterOptions.cssClasses.inputContainer]
* @param {string} [filterOptions.cssClasses.titleContainer]
* @param {gem.control.AddedDataControl} addedDataControl - data source control
*/
gem.control.CategoryFilterControl = class CategoryFilterControl extends gem.control.BaseControl {
constructor(filterOptions, addedDataControl) {
super(gem.control.TConntrolExecuteType.ONCONNECTED);
this.addedDataControl = addedDataControl;
let defaultOptions = {
parentContainer: '',
collapsible: true,
startCollapsed: true,
name: '',
title: '',
categories: [{
label: 'All',
filter: {
key: '',
value: ''
}
}],
style: 'radio',
cssClasses: {
container: 'gem-markers-filter-categories',
filterHeader: 'gem-markers-filter-header',
collapsible: 'gem-markers-filter-collapsible',
inputContainer: 'gem-markers-filter-input',
titleContainer: 'gem-markers-filter-categories-title'
}
};
this.options = Object.assign({}, defaultOptions, filterOptions);
this.type = 'category';
}
initControl(parentDiv, mapView) {
if (!this.addedDataControl || !this.addedDataControl.notifyChangeFilterData) {
console.log("data source control does not support category filters");
return;
}
this.mapView = mapView;
this.filterCategory = [ /* {key: '', value: ''} */];
let elCategoryFilter = document.getElementById(this.options.parentContainer);
if (!elCategoryFilter) {
elCategoryFilter = document.createElement('div');
elCategoryFilter.id = this.options.parentContainer;
elCategoryFilter.className = this.options.parentContainer;
document.getElementById(parentDiv).appendChild(elCategoryFilter);
}
this.createFilterCategoryControl(elCategoryFilter);
}
createFilterCategoryControl(parentDiv) {
if (!this.options.categories) {
console.log("no categories were set for categoryFilters");
return;
}
let elCategories = document.createElement('div');
elCategories.className = this.options.cssClasses.container;
let elCategoriesFilters = elCategories.appendChild(document.createElement('div'));
switch (this.options.style) {
case 'radio':
this.createRadioCategories(this.options.categories, elCategoriesFilters);
break;
case 'checkboxes':
this.createCheckboxCategories(this.options.categories, elCategoriesFilters);
break;
default:
console.log("filter style not supported");
break;
}
if (this.options.title || this.options.collapsible) {
let elCategoriesHeader = document.createElement('div');
elCategoriesHeader.className = this.options.cssClasses.filterHeader;
if (this.options.collapsible) {
if (this.options.startCollapsed)
elCategoriesFilters.style.display = 'none';
let elCollapse = elCategoriesHeader.appendChild(document.createElement('button'));
elCollapse.className = this.options.cssClasses.collapsible;
elCollapse.addEventListener('click', (e) => {
elCollapse.classList.toggle('active');
if (elCategoriesFilters.style.display === 'none')
elCategoriesFilters.style.display = '';
else
elCategoriesFilters.style.display = 'none';
});
if (!this.options.startCollapsed)
elCollapse.classList.add('active');
}
if (this.options.title) {
let elTitle = elCategoriesHeader.appendChild(document.createElement('div'));
elTitle.className = this.options.cssClasses.titleContainer;
let spanTitle = document.createElement('span');
spanTitle.innerHTML = this.options.title;
elTitle.appendChild(spanTitle);
}
elCategories.insertBefore(elCategoriesHeader, elCategories.firstChild);
}
parentDiv.appendChild(elCategories);
}
createRadioCategories(categories, elParent) {
for (let i = 0; i < categories.length; i++) {
let elCategory = document.createElement('div');
let inputCategory = document.createElement('input');
inputCategory.className = this.options.cssClasses.inputContainer;
inputCategory.setAttribute('type', 'radio');
inputCategory.setAttribute('name', this.options.parentContainer);
inputCategory.setAttribute('value', categories[i].label);
inputCategory.setAttribute('id', categories[i].label);
// set first option default checked
if (i === 0) {
inputCategory.checked = true;
this.filterCategory[0] = categories[i].filter;
this.addedDataControl.notifyChangeFilterData(this.type, this.options.name, this.filterCategory);
}
// on click update data source
inputCategory.addEventListener('click', () => {
this.filterCategory[0] = categories[i].filter;
this.addedDataControl.notifyChangeFilterData(this.type, this.options.name, this.filterCategory);
});
elCategory.appendChild(inputCategory);
let labelCategory = document.createElement('label');
labelCategory.setAttribute('for', categories[i].label);
labelCategory.innerHTML = categories[i].label;
elCategory.appendChild(labelCategory);
elParent.appendChild(elCategory);
}
}
createCheckboxCategories(categories, elParent) {
for (let i = 0; i < categories.length; i++) {
let elCategory = elParent.appendChild(document.createElement('div'));
let inputCategory = elCategory.appendChild(document.createElement('input'));
inputCategory.className = this.options.cssClasses.inputContainer;
inputCategory.setAttribute('type', 'checkbox');
inputCategory.setAttribute('name', this.options.parentContainer);
inputCategory.setAttribute('value', categories[i].label);
inputCategory.setAttribute('id', categories[i].label);
inputCategory.addEventListener('change', () => {
if (inputCategory.checked) {
// check all children and add to filter
if (elCategory.children) {
let children = elCategory.querySelectorAll('.' + this.options.cssClasses.inputContainer);
// check without parent input
if (children.length > 1 && children.length - 1 === categories[i].children.length) {
for (let c = 1; c < children.length; c++) {
children[c].checked = true;
let filter = categories[i].children[c - 1].filter;
let findFilter = this.filterCategory.find(findFilter => findFilter.key === filter.key && findFilter.value === filter.value);
if (!findFilter)
this.filterCategory.push(filter);
}
}
}
this.addedDataControl.notifyChangeFilterData(this.type, this.options.name, this.filterCategory);
} else {
// uncheck all children and remove from filter
if (elCategory.children) {
let children = elCategory.querySelectorAll('.' + this.options.cssClasses.inputContainer);
// check without parent input
if (children.length > 1 && children.length - 1 === categories[i].children.length) {
for (let c = 1; c < children.length; c++) {
children[c].checked = false;
let childCateg = categories[i].children[c - 1];
const idxRem = this.filterCategory.indexOf(childCateg.filter);
if (idxRem > -1)
this.filterCategory.splice(idxRem, 1);
}
}
}
this.addedDataControl.notifyChangeFilterData(this.type, this.options.name, this.filterCategory);
}
});
let label = elCategory.appendChild(document.createElement('label'));
label.setAttribute('for', categories[i].label);
label.innerHTML = categories[i].label;
// child checkboxes
if (categories[i].children) {
for (let j = 0; j < categories[i].children.length; j++) {
let childCateg = categories[i].children[j];
let elChild = elCategory.appendChild(document.createElement('div'));
let inputChild = elChild.appendChild(document.createElement('input'));
inputChild.className = this.options.cssClasses.inputContainer;
inputChild.style.marginLeft = '7%';
inputChild.setAttribute('type', 'checkbox');
inputChild.setAttribute('name', this.options.parentContainer);
inputChild.setAttribute('value', childCateg.label);
inputChild.setAttribute('id', childCateg.label);
inputChild.addEventListener('change', () => {
if (inputChild.checked) {
// all children checked or set parent indeterminate
if (elCategory.children && elCategory.children.length > 1) {
let countChildrenChecked = 0;
let children = elCategory.querySelectorAll('.' + this.options.cssClasses.inputContainer);
// check without parent input
for (let c = 1; c < children.length; c++) {
if (children[c].checked)
countChildrenChecked++;
}
// set parent input state
if (countChildrenChecked === children.length - 1) {
children[0].checked = true;
children[0].indeterminate = false;
} else {
children[0].checked = false;
children[0].indeterminate = true;
}
}
this.filterCategory.push(childCateg.filter);
} else {
// all children unchecked and set parent unchecked or set parent indeterminate
if (elCategory.children && elCategory.children.length > 1) {
let countChildrenChecked = 0;
let children = elCategory.querySelectorAll('.' + this.options.cssClasses.inputContainer);
// check without parent input
for (let c = 1; c < children.length; c++) {
if (children[c].checked) {
countChildrenChecked++;
break;
}
}
// set parent input state
if (countChildrenChecked === 0) {
children[0].checked = false;
children[0].indeterminate = false;
} else {
children[0].checked = false;
children[0].indeterminate = true;
}
}
const idxRem = this.filterCategory.indexOf(childCateg.filter);
if (idxRem > -1)
this.filterCategory.splice(idxRem, 1);
}
this.addedDataControl.notifyChangeFilterData(this.type, this.options.name, this.filterCategory);
});
let labelChild = elChild.appendChild(document.createElement('label'));
labelChild.setAttribute('for', childCateg.label);
labelChild.innerHTML = childCateg.label;
}
}
}
}
}
gem.control.DataQuerySearchControl = class DataQuerySearchControl extends gem.control.SearchControl {
constructor(searchOptions, addedDataControl) {
super(searchOptions);
this.addedDataControl = addedDataControl;
}
async resultOnClick(pickedResult, searchInputDiv) {
super.resultOnClick(pickedResult, searchInputDiv);
if (this.addedDataControl) {
this.addedDataControl.refLocation = pickedResult;
this.addedDataControl.centerPoint = pickedResult.getCoordinates();
if (this.addedDataControl.updateDataSource)
this.addedDataControl.updateDataSource();
else if (this.addedDataControl.feedDataOptions && this.addedDataControl.feedDataOptions.markersFeedFunction) {
let mapCanvas = document.getElementById(gem.core.App.initOptions.container);
if (mapCanvas) {
let mapScreenTopLeft = {
x: mapCanvas.clientLeft,
y: mapCanvas.clientTop
};
let mapScreenBottomRight = {
x: mapCanvas.clientLeft + mapCanvas.clientWidth,
y: mapCanvas.clientTop + mapCanvas.clientHeight
}
let mapWgsTopLeft = this.addedDataControl.mapView.transformScreenToWgs(mapScreenTopLeft);
let mapWgsBottomRight = this.addedDataControl.mapView.transformScreenToWgs(mapScreenBottomRight);
let mapWgsLonMin = mapWgsTopLeft.longitude;
let mapWgsLonMax = mapWgsBottomRight.longitude;
let mapWgsLatMin = Math.min(mapWgsTopLeft.latitude, mapWgsBottomRight.latitude);
let mapWgsLatMax = Math.max(mapWgsTopLeft.latitude, mapWgsBottomRight.latitude);
let data = await this.addedDataControl.feedDataOptions.markersFeedFunction(pickedResult.longitude, pickedResult.latitude,
mapWgsLonMin, mapWgsLatMin, mapWgsLonMax, mapWgsLatMax);
try {
this.addedDataControl.mapView.addGeoJsonAsCustomMarkers(JSON.stringify(data), this.addedDataControl.controlName, this.addedDataControl.sourcesList, this.addedDataControl.externalRenderObj, this.addedDataControl.options.markerGrouping.maxLevel);
if (!data || !data.features || !data.features.length) {
if (this.listChangedNotifier)
this.listChangedNotifier(this.externalRenderObj.name, this.mapView);
if (this.listLoadingDoneNotifier)
this.listLoadingDoneNotifier();
}
} catch (e) {
console.log("CustomQueryAddedDataControl error: invalid data for markers");
}
}
} else
return;
}
}
}
class FiltersControl extends gem.control.BaseControl {
constructor(initFiltersOptions) {
super(gem.control.TConntrolExecuteType.ONCONNECTED);
this.datacontrol = initFiltersOptions.datacontrol;
if (this.datacontrol)
this.datacontrol.registerVisibilityNotifier(this.visibilityReceiver.bind(this));
if (initFiltersOptions.container)
this.container = initFiltersOptions.container;
// distance
if (initFiltersOptions.filterKey) {
this.filterKey = initFiltersOptions.filterKey;
this.filterValues = initFiltersOptions.filterValues;
if (this.filterValues && this.filterValues.length > 0)
this.selectedFilterValue = initFiltersOptions.filterValues[0];
}
this.title = initFiltersOptions.title;
};
visibilityReceiver(visibility) {
if (this.elContainer)
this.elContainer.style.visibility = visibility;
else
this.visibility = visibility;
}
initControl(parentDiv, mapView) {
this.mapView = mapView;
if (this.container) {
let elContainer = document.getElementById(this.container);
if (this.visibility)
elContainer.style.visibility = this.visibility;
this.elContainer = elContainer;
if (this.filterKey)
this.createDistanceFilterControl(elContainer);
}
// create default container
else {
let elFiltersContainer = document.createElement('div');
this.elContainer = elFiltersContainer;
if (this.visibility)
this.elContainer.style.visibility = this.visibility;
elFiltersContainer.className = 'gem-markers-filter-container';
if (this.filterKey) {
if (this.filterValues)
this.createDistanceFilterControl(elFiltersContainer);
else {
this.filterContainer = elFiltersContainer;
this.datacontrol.requestFieldValues(this.filterKey, this.populateFilterControl.bind(this));
}
}
let lstchild = document.getElementById(parentDiv).lastChild;
if (lstchild && lstchild.id !== 'buttonCopyright')
elFiltersContainer.style.top = lstchild.offsetTop + lstchild.offsetHeight + 2 + 'px';
document.getElementById(parentDiv).appendChild(elFiltersContainer);
}
};
populateFilterControl(itemsList) {
if (itemsList.size() === 0)
return;
let elDistance = document.createElement('div');
elDistance.id = 'gem-markers-filter-distance';
elDistance.className = 'gem-markers-filter-distance';
let elSelect = document.createElement('select');
elSelect.className = 'gem-markers-filter-distance-select';
for (let i = 0; i < itemsList.size(); i++) {
let distanceOption = document.createElement('option');
distanceOption.setAttribute('value', i + "");
distanceOption.innerHTML = itemsList.get(i).getFormattedText();
elSelect.appendChild(distanceOption);
}
elDistance.appendChild(elSelect);
let self = this;
elSelect.addEventListener('change', function () {
self.datacontrol.notifyChangeFilterData(self.filterKey, 'distanceFilter', elSelect.value);
});
if (this.title) {
let elTitle = document.createElement('div');
elTitle.id = 'gem-markers-filter-distance-title';
elTitle.className = 'gem-markers-filter-distance-title';
let spanTitle = document.createElement('span');
spanTitle.innerHTML = this.title;
elTitle.appendChild(spanTitle);
elDistance.insertBefore(elTitle, elDistance.firstChild);
}
this.filterContainer.appendChild(elDistance);
}
createDistanceFilterControl(parentDiv) {
if (!this.filterValues) {
console.log("no distance thresholds set for distanceFilter");
return;
}
let elDistance = document.createElement('div');
elDistance.id = 'gem-markers-filter-distance';
elDistance.className = 'gem-markers-filter-distance';
// distance radius thresholds
let distanceThresholds = this.filterValues;
let elSelect = document.createElement('select');
elSelect.className = 'gem-markers-filter-distance-select';
for (let i = 0; i < distanceThresholds.length; i++) {
let distanceOption = document.createElement('option');
distanceOption.setAttribute('value', distanceThresholds[i]);
distanceOption.innerHTML = distanceThresholds[i];
elSelect.appendChild(distanceOption);
}
elDistance.appendChild(elSelect);
let self = this;
elSelect.addEventListener('change', function () {
self.datacontrol.notifyChangeFilterData(self.filterKey, 'distanceFilter', elSelect.value);
});
if (this.title) {
let elTitle = document.createElement('div');
elTitle.id = 'gem-markers-filter-distance-title';
elTitle.className = 'gem-markers-filter-distance-title';
let spanTitle = document.createElement('span');
spanTitle.innerHTML = this.title;
elTitle.appendChild(spanTitle);
elDistance.insertBefore(elTitle, elDistance.firstChild);
}
parentDiv.appendChild(elDistance);
}
}
gem.control.WikipediaControl = class WikipediaControl extends gem.control.BaseControl {
constructor(initFiltersOptions) {
super(gem.control.TConntrolExecuteType.ONCONNECTED);
if (initFiltersOptions) {
if (initFiltersOptions.container)
this.container = initFiltersOptions.container;
if (initFiltersOptions.populateItemFunction)
this.populateItemFunction = initFiltersOptions.populateItemFunction;
}
}
initControl(parentDiv, mapView) {
this.mapView = mapView;
if (this.container) {
let elContainer = document.getElementById(this.container);
if (this.visibility)
elContainer.style.visibility = this.visibility;
this.elContainer = elContainer;
} else {
let wikipediaContainer = document.createElement('div');
wikipediaContainer.className = 'gem-markers-filter-container';
this.elContainer = wikipediaContainer;
if (this.visibility)
this.elContainer.style.visibility = this.visibility;
let lstchild = document.getElementById(parentDiv).lastChild;
if (lstchild && lstchild.id !== 'buttonCopyright')
wikipediaContainer.style.top = lstchild.offsetTop + lstchild.offsetHeight + 2 + 'px';
document.getElementById(parentDiv).appendChild(wikipediaContainer);
}
}
cameraChangedCallback() {
}
preRenderCallback() {
}
setControlMode(mode) {
}
notifySearchSelection(item) {
while (this.elContainer.firstChild) {
this.elContainer.firstChild.remove();
}
if (!this.pExternalInfo)
this.pExternalInfo = new gem.core.ExternalInfo();
if (item) {
if (item.hasWikipediaInfo(this.pExternalInfo)) {
item.requestWikipediaInfo(this.wikipediainfocallback.bind(this), this.pExternalInfo);
} else {
this.elContainer.style.visibility = 'hidden';
}
} else {
this.elContainer.innerHTML = "";
this.elContainer.style.visibility = 'hidden';
}
}
wikipediainfocallback(wikiResult) {
if (this.populateItemFunction) {
this.elContainer.style.visibility = 'visible';
this.populateItemFunction(this.elContainer, wikiResult);
} else {
let pageDescription = document.createElement('div');
pageDescription.className = 'gem-wikipedia-description';
pageDescription.innerHTML = "<p>" + wikiResult.getWikiPageDescription() + "</p>";
this.elContainer.style.visibility = 'visible';
if (wikiResult.getWikiImagesUrl().size())
this.elContainer.innerHTML = '<img src="' + wikiResult.getWikiImagesUrl().get(0) + '" alt="Snow" style="width:100%">';
this.elContainer.appendChild(pageDescription);
let pageImages = document.createElement('div');
pageImages.className = 'gem-wikipedia-container';
let whatToAdd = '<div class="row">';
for (let i = 1; i < wikiResult.getWikiImagesUrl().size(); i++) {
whatToAdd += '<div class="column"><img src="' + wikiResult.getWikiImagesUrl().get(i) + '"loading="lazy" style="width:100%"></div>';
}
whatToAdd += '</div>';
pageImages.innerHTML = whatToAdd;
this.elContainer.appendChild(pageImages);
}
}
visibilityReceiver(visibility) {
if (this.elContainer)
this.elContainer.style.visibility = visibility;
else
this.visibility = visibility;
}
}
gem.control.ContentStoreControl = class ContentStoreControl extends gem.control.BaseControl {
constructor(initOptions) {
super(gem.control.TConntrolExecuteType.ONCONNECTED);
if (initOptions) {
this.contentType = initOptions.contentType;
this.customContainer = initOptions.container;
this.createElementFunction = initOptions.createElementFunction;
}
}
initControl(parentDiv, mapView) {
this.elementDiv = document.createElement("div");
this.elementDiv.classList.add("gem-markers-menu-list");
let containerDiv = document.getElementById(this.customContainer ? this.customContainer : parentDiv);
let searchControlsDiv = document.createElement('div');
searchControlsDiv.id = "searchIn";
searchControlsDiv.className = "gem-search-input";
let searchControlsDivParent = document.createElement('div');
searchControlsDivParent.id = "searchControl";
searchControlsDivParent.className = "gem-search-control";
searchControlsDivParent.appendChild(searchControlsDiv);
containerDiv.appendChild(this.elementDiv);
containerDiv.appendChild(searchControlsDivParent);
this.requestContentList();
}
requestContentList() {
this.mStoreProgressListener = new gem.content.StoreProgressListener();
this.mStoreProgressListener.registerCompleteCallback(this.completeCallback.bind(this));
gem.content.Manager.requestContentList((typeof this.contentType === 'function') ? this.contentType() : this.contentType, this.mStoreProgressListener);
}
completeCallback() {
this.contentStoreList = gem.content.Manager.getStoreContentList((typeof this.contentType === 'function') ? this.contentType() : this.contentType);
this.resetList();
}
preRenderCallback() {
if (this.notifySaveDataToDisk) {
gem.core.App.syncContentWithStorage(false);
this.notifySaveDataToDisk = false;
}
}
populateElement(pElement, categoryItem) {
while (pElement.firstChild) {
pElement.firstChild.remove();
}
let bitmapSize = 20;
const offbitmap = new gem.core.BitmapContainer(bitmapSize, bitmapSize);
let countryCodes = categoryItem.getCountryCodes();
gem.core.App.getCountryFlagImage(countryCodes.get(0), offbitmap);
let imgCanvas = document.createElement('canvas');
imgCanvas.setAttribute('width', '' + bitmapSize);
imgCanvas.setAttribute('height', '' + bitmapSize);
imgCanvas.style.backgroundColor = 'transparent';
gem.core.App.setCanvas(offbitmap.toImageData(), bitmapSize, bitmapSize, imgCanvas);
offbitmap.delete();
let pElementCanvas = document.createElement("div");
pElementCanvas.setAttribute('width', '' + bitmapSize);
pElementCanvas.setAttribute('height', '' + bitmapSize);
pElementCanvas.appendChild(imgCanvas);
let pElementTitle = document.createElement("div");
pElementTitle.className = 'gem-marker-list-item-title';
pElementTitle.style.cursor = 'pointer';
let textPart = document.createElement('SPAN');
textPart.innerText = categoryItem.getName();
pElementTitle.appendChild(textPart);
pElementCanvas.appendChild(pElementTitle);
pElement.appendChild(pElementCanvas);
let pElementContent = document.createElement("div");
if (!categoryItem.isCompleted()) {
pElement.onclick = function () {
console.log("Check category test");
let progressDiv = document.createElement("DIV");
let progressElement = document.createElement("progress");
progressElement.setAttribute("value", "0");
progressElement.setAttribute("max", "100");
progressDiv.style.lineHeight = 'line-height:normal'
progressDiv.style.display = 'inline-block';
progressDiv.style.verticalAlign = 'bottom';
progressDiv.appendChild(progressElement);
pElement.appendChild(progressDiv);
this.mStoreProgressListener = new gem.content.StoreProgressListener();
let functionCompleted = function () {
console.log("Completed The download !");
progressElement.remove();
this.populateElement(pElement, categoryItem);
this.notifySaveDataToDisk = true;
}.bind(this);
let functionProgressCallback = function (val) {
progressElement.setAttribute("value", val + "");
}.bind(this);
Module.m_progressListenerHTTP = functionProgressCallback;
this.mStoreProgressListener.registerCompleteCallback(functionCompleted);
this.mStoreProgressListener.registerProgressCallback(functionProgressCallback);
categoryItem.download(this.mStoreProgressListener);
}.bind(this);
} else {
console.log("Item " + categoryItem.getName() + " is downloaded!");
let textPart2 = document.createElement("BUTTON");
textPart2.innerText = "delete";
textPart2.onclick = function (event) {
categoryItem.deleteContent();
pElement.removeChild(textPart2);
this.populateElement(pElement, categoryItem);
event.stopPropagation();
this.notifySaveDataToDisk = true;
}.bind(this);
pElement.appendChild(textPart2);
if (categoryItem.isUpdatable()) {
let updateBt = document.createElement("BUTTON");
updateBt.innerText = "update";
}
}
}
resetList() {
while (this.elementDiv.firstChild) {
this.elementDiv.firstChild.remove();
}
let i = 0;
for (i = 0; i < this.contentStoreList.size(); i++) {
let categoryItem = this.contentStoreList.get(i);
let pElement = document.createElement("div");
pElement.className = 'gem-marker-list-item';
pElement.style.cursor = 'pointer';
pElement.style.flexDirection = 'column';
this.populateElement(pElement, categoryItem);
this.elementDiv.appendChild(pElement);
//var bitmapContainer = new gem.core.BitmapContainer(20, 20);
//let poiIcon = document.createElement("CANVAS");
//poiIcon.style = "margin-top: auto;margin-bottom: auto;";
//categoryItem.getImage(bitmapContainer);
//gem.core.App.setCanvas(bitmapContainer.toImageData(), 20, 20, poiIcon);
//pElement.appendChild(poiIcon);
//bitmapContainer.delete();
;
}
}
}
gem.control.TouchEventControl = class TouchEventControl extends gem.control.BaseControl {
constructor(initOptions) {
super(gem.control.TConntrolExecuteType.ONCONNECTED);
if (initOptions) {
this.onTapEvent = initOptions.tapEvent;
this.onLongTapEvent = initOptions.longTapEvent;
}
}
initControl(parentDiv, mapView) {
if (this.onTapEvent)
mapView.registerOnTouchEvent(this.onTapEvent);
if (this.onLongTapEvent)
mapView.registernOnLongTouchEvent(this.onLongTapEvent);
}
}
/**
* @class gem.d3Scene.MarkerCollectionDisplaySettings
* @description A class that represents the display settings for a marker collection.
*
* This class provides methods to manage the display settings of a marker collection.
*
* @description Initializes a new instance of the `gemMarkerCollectionDisplaySettings` class.
*
* @function setPolylineInnerColor
* @description Sets the inner color of the polyline.
* @param {object} color - The color to set in RGBA format.
*
* @function setPolylineOuterColor
* @description Sets the outer color of the polyline.
* @param {object} color - The color to set in RGBA format.
*
* @function setPolygonFillColor
* @description Sets the fill color of the polygon.
* @param {object} color - The color to set in RGBA format.
*
* @function setPolylineInnerSize
* @description Sets the inner size of the polyline.
* @param {number} innerSize - The size to set.
*
* @function setPolylineOuterSize
* @description Sets the outer size of the polyline.
* @param {number} outerSize - The size to set.
*
* @function getRawPointer
* @description Gets the raw pointer to the `Module.gemMarkerCollectionDisplaySettings` object.
* @returns {Module.gemMarkerCollectionDisplaySettings} The raw pointer.
*
* @example
* ```javascript
* let displaySettings = new gem.d3Scene.MarkerCollectionDisplaySettings();
* displaySettings.setPolylineInnerColor({r: 255, g: 0, b: 0, a: 255});
* displaySettings.setPolylineOuterColor({r: 0, g: 255, b: 0, a: 255});
* displaySettings.setPolygonFillColor({r: 0, g: 0, b: 255, a: 255});
* displaySettings.setPolylineInnerSize(5);
* displaySettings.setPolylineOuterSize(10);
* console.log(displaySettings.getRawPointer()); // Outputs: Module.gemMarkerCollectionDisplaySettings
* ```
*/
gem.d3Scene.MarkerCollectionDisplaySettings = class gemMarkerCollectionDisplaySettings {
constructor() {
this.m_object = new Module.gemMarkerCollectionDisplaySettings();
}
setPolylineInnerColor(color) {
this.m_object.setPolylineInnerColor(color);
}
setPolylineOuterColor(color) {
this.m_object.setPolylineOuterColor(color);
}
setPolygonFillColor(color) {
this.m_object.setPolygonFillColor(color);
}
setPolylineInnerSize(innerSize) {
this.m_object.setPolylineInnerSize(innerSize);
}
setPolylineOuterSize(outerSize) {
this.m_object.setPolylineOuterSize(outerSize);
}
getRawPointer() {
return this.m_object;
}
}
/**
* @description A constant that represents different types of Electric Vehicle (EV) charging connectors.
*
* This constant is an object where each property represents a unique type of EV charging connector.
*
* @property {number} EVC_J1772 - Represents the J1772 type of EV charging connector.
* @property {number} EVC_Mennekes - Represents the Mennekes type of EV charging connector.
* @property {number} EVC_Type2 - Represents the Type 2 type of EV charging connector.
* @property {number} EVC_Type3 - Represents the Type 3 type of EV charging connector.
* @property {number} EVC_GBT_AC - Represents the GBT AC type of EV charging connector.
* @property {number} EVC_GBT_DC - Represents the GBT DC type of EV charging connector.
* @property {number} EVC_CHAdeMO - Represents the CHAdeMO type of EV charging connector.
* @property {number} EVC_CSS1 - Represents the CSS1 type of EV charging connector.
* @property {number} EVC_CSS2 - Represents the CSS2 type of EV charging connector.
* @property {number} EVC_Tesla - Represents the Tesla type of EV charging connector.
* @property {number} EVC_SuperTesla - Represents the SuperTesla type of EV charging connector.
* @property {number} EVC_SuperTeslaCCS - Represents the SuperTesla CCS type of EV charging connector.
* @property {number} EVC_TeslaDestination - Represents the Tesla Destination type of EV charging connector.
*
* @example
* ```javascript
* console.log(EEVChargingConnector.EVC_J1772); // Outputs: 0x1
* console.log(EEVChargingConnector.EVC_Mennekes); // Outputs: 0x2
* console.log(EEVChargingConnector.EVC_Type2); // Outputs: 0x4
* // ...
* ```
*/
const EEVChargingConnector = {
EVC_J1772: 0x1,
EVC_Mennekes: 0x2,
EVC_Type2: 0x4,
EVC_Type3: 0x8,
EVC_GBT_AC: 0x10,
EVC_GBT_DC: 0x20,
EVC_CHAdeMO: 0x40,
EVC_CSS1: 0x80,
EVC_CSS2: 0x100,
EVC_Tesla: 0x200,
EVC_SuperTesla: 0x400,
EVC_SuperTeslaCCS: 0x800,
EVC_TeslaDestination: 0x1000
};
/**
* @class gem.routesAndNavigation.EVCarModel
* @augments Em_Object
* @description A class that represents a model of an Electric Vehicle (EV).
*
* This class provides properties and methods to manage EV car models.
*
* @param {Module.EVCarModel|object} obj - If the argument is an instance of `Module.EVCarModel`, it will be used to initialize the object. Otherwise, a new `Module.EVCarModel` object will be created.
*
* @property {number} id - The ID of the EV car model.
* @property {string} name - The name of the EV car model.
* @property {number} batteryCapacity - The battery capacity of the EV car model.
* @property {boolean} towbarPossible - Indicates whether the EV car model can have a towbar.
* @property {Array} ports - The ports of the EV car model.
* @property {number} vehicleRange - The range of the EV car model.
* @property {number} efficiency - The efficiency of the EV car model.
* @property {boolean} fastCharge - Indicates whether the EV car model supports fast charging.
*
* @example
* ```javascript
* let evCarModel = new gem.routesAndNavigation.EVCarModel({id: 1, name: 'Model S', batteryCapacity: 100, towbarPossible: true, ports: [], vehicleRange: 500, efficiency: 0.85, fastCharge: true});
* console.log(evCarModel.name); // Outputs: Model S
* console.log(evCarModel.batteryCapacity); // Outputs: 100
* console.log(evCarModel.towbarPossible); // Outputs: true
* console.log(evCarModel.vehicleRange); // Outputs: 500
* console.log(evCarModel.efficiency); // Outputs: 0.85
* console.log(evCarModel.fastCharge); // Outputs: true
* ```
*/
gem.routesAndNavigation.EVCarModel = class EVCarModel extends Em_Object {
constructor(obj) {
super(obj ? obj : new Module.EVCarModel());
}
// Properties from EVCarModel
get id() {
return this.m_object.id;
}
set id(value) {
this.m_object.id = value;
}
get name() {
return this.m_object.name.toStdString(0, -1);
}
set name(value) {
this.m_object.name = new Module.String(value);
}
get batteryCapacity() {
return this.m_object.batteryCapacity;
}
set batteryCapacity(value) {
this.m_object.batteryCapacity = value;
}
get towbarPossible() {
return this.m_object.towbarPossible;
}
set towbarPossible(value) {
this.m_object.towbarPossible = value;
}
get ports() {
return this.m_object.ports;
}
set ports(value) {
this.m_object.ports = value;
}
get vehicleRange() {
return this.m_object.vehicleRange;
}
set vehicleRange(value) {
this.m_object.vehicleRange = value;
}
get efficiency() {
return this.m_object.efficiency;
}
set efficiency(value) {
this.m_object.efficiency = value;
}
get fastCharge() {
return this.m_object.fastCharge;
}
set fastCharge(value) {
this.m_object.fastCharge = value;
}
};
/**
* @class gem.routesAndNavigation.EVProfile
* @description A class that represents a profile for an Electric Vehicle (EV).
*
* This class provides properties and methods to manage EV profiles. It extends the `EVCarModel` class with additional properties and methods.
*
* @param {Module.EVProfile|gem.routesAndNavigation.EVCarModel} objOrCarModel - If the first argument is an instance of `Module.EVProfile`, it will be used to initialize the object. Otherwise, the argument is used as the car model to initialize a new `Module.EVProfile` object.
*
* @property {gem.routesAndNavigation.EVCarModel} carModel - The car model of the EV.
* @property {number} batteryCapacity - The battery capacity of the EV.
* @property {number} chargeSpeed - The charge speed of the EV.
*
* @example
* ```javascript
* let evProfile = new gem.routesAndNavigation.EVProfile(gem.routesAndNavigation.EVCarModel, 100, 50);
* console.log(evProfile.carModel); // Outputs: EVCarModel
* console.log(evProfile.batteryCapacity); // Outputs: 100
* console.log(evProfile.chargeSpeed); // Outputs: 50
* ```
*/
gem.routesAndNavigation.EVProfile = class EVProfile extends gem.routesAndNavigation.EVCarModel {
constructor(obj) {
if (obj === undefined)
super(new Module.EVProfile);
else
super(obj);
self = this;
// Expose properties of EVProfile
Object.defineProperty(this, 'departureSoc', {
get: function () {
return this.m_object.departureSoc;
},
set: function (value) {
this.m_object.departureSoc = value;
}
});
Object.defineProperty(this, 'destinationSoc', {
get: function () {
return this.m_object.destinationSoc;
},
set: function (value) {
this.m_object.destinationSoc = value;
}
});
Object.defineProperty(this, 'chargerDepSoc', {
get: function () {
return this.m_object.chargerDepSoc;
},
set: function (value) {
this.m_object.chargerDepSoc = value;
}
});
Object.defineProperty(this, 'chargerDestSoc', {
get: function () {
return this.m_object.chargerDestSoc;
},
set: function (value) {
this.m_object.chargerDestSoc = value;
}
});
Object.defineProperty(this, 'chargerOverheadMins', {
get: function () {
return this.m_object.chargerOverheadMins;
},
set: function (value) {
this.m_object.chargerOverheadMins = value;
}
});
Object.defineProperty(this, 'batteryHealth', {
get: function () {
return this.m_object.batteryHealth;
},
set: function (value) {
this.m_object.batteryHealth = value;
}
});
}
setCarModel(carModel) {
this.m_object.setCarModel(carModel.getRawPointer());
}
};
/**
* @class gem.routesAndNavigation.EFuelType
* @description
*
* This class provides static methods that return different types of fuel. Each method represents a unique fuel type.
*
* @example
* ```javascript
* let fuelType = gem.routesAndNavigation.EFuelType.FT_Petrol;
* console.log(fuelType); // Outputs: FT_Petrol
* ```
*/
gem.routesAndNavigation.EFuelType = class EFuelType {
static FT_Petrol() {
return EFuelType.FT_Petrol;
}
static FT_Diesel() {
return EFuelType.FT_Diesel;
}
static FT_LPG() {
return EFuelType.FT_LPG;
}
static FT_Electric() {
return EFuelType.FT_Electric;
}
/**
* @private
*/
static initializeData() {
EFuelType.FT_Petrol = Module.EFuelType.FT_Petrol;
EFuelType.FT_Diesel = Module.EFuelType.FT_Diesel;
EFuelType.FT_LPG = Module.EFuelType.FT_LPG;
EFuelType.FT_Electric = Module.EFuelType.FT_Electric;
}
}
/**
* @class gem.routesAndNavigation.CarProfile
* @augments Em_Object
* @description A class that represents a profile for a car, including its fuel type, mass, and maximum speed.
*
* @param {Module.CarProfile|gem.routesAndNavigation.EFuelType} objOrFuel - If the first argument is an instance of `Module.CarProfile`, it will be used to initialize the object. Otherwise, the argument is used as the fuel type to initialize a new `Module.CarProfile` object.
* @param {number} mass - The mass of the car.
* @param {number} maxSpeed - The maximum speed of the car.
*
* @property {gem.routesAndNavigation.EFuelType} fuel - The fuel type of the car.
* @property {number} mass - The mass of the car.
* @property {number} maxSpeed - The maximum speed of the car.
*
* @example
* ```javascript
* let carProfile = new gem.routesAndNavigation.CarProfile(gem.routesAndNavigation.EFuelType.FT_Petrol, 1500, 200);
* console.log(carProfile.fuel); // Outputs: FT_Petrol
* console.log(carProfile.mass); // Outputs: 1500
* console.log(carProfile.maxSpeed); // Outputs: 200
* ```
*/
gem.routesAndNavigation.CarProfile = class CarProfile extends Em_Object {
constructor(objOrFuel, mass, maxSpeed) {
if (objOrFuel && objOrFuel instanceof Module.CarProfile) {
super(objOrFuel);
}
else {
if (objOrFuel === undefined) {
objOrFuel = gem.routesAndNavigation.EFuelType.FT_Petrol;
}
if (mass === undefined) {
mass = 0.0;
}
if (maxSpeed === undefined) {
maxSpeed = 0.0;
}
super(new Module.CarProfile(objOrFuel, mass, maxSpeed));
}
// Expose properties of CarProfile
Object.defineProperty(this, 'fuel', {
get: function () {
return this.m_object.fuel;
},
set: function (value) {
this.m_object.fuel = value;
}
});
Object.defineProperty(this, 'mass', {
get: function () {
return this.m_object.mass;
},
set: function (value) {
this.m_object.mass = value;
}
});
Object.defineProperty(this, 'maxSpeed', {
get: function () {
return this.m_object.maxSpeed;
},
set: function (value) {
this.m_object.maxSpeed = value;
}
});
}
}
/**
* @class gem.routesAndNavigation.EVCarModelsList
* @augments Em_Vector
* @description A class that represents a list of Electric Vehicle (EV) car models.
*
* @function get
* @param {number} position - The position (index) of the `EVCarModel` object in the list.
* @returns {gem.routesAndNavigation.EVCarModel} The `EVCarModel` object at the specified position in the list.
*
* @example
* ```javascript
* let evCarModelsList = new gem.routesAndNavigation.EVCarModelsList();
* let carModel = evCarModelsList.get(0); // Get the first EVCarModel in the list
* ```
*/
gem.routesAndNavigation.EVCarModelsList = class EVCarModelsList extends Em_Vector {
/** This method takes a position (index) as an argument and returns the `EVCarModel` object at that position in the list.
* @param {number} position - The position (index) of the `EVCarModel` object in the list.
* @returns {gem.routesAndNavigation.EVCarModel} The `EVCarModel` object at the specified position in the list.
**/
get(position) {
return new gem.routesAndNavigation.EVCarModel(this.m_object.get(position));
}
}
/**
* Represents an electric vehicle route instruction.
* @class gem.routesAndNavigation.EVRouteInstruction
* @memberof gem.routesAndNavigation
* @augments gem.core.Em_Object
* @hideconstructor
*/
gem.routesAndNavigation.EVRouteInstruction = class EVRouteInstruction extends Em_Object {
/**
* Get the begin state of charge
* @returns {number} the begin state of charge
**/
getBeginSoC() {
return this.m_object.getBeginSoC();
}
/**
* Get the end state of charge
* @returns {number} the end state of charge
**/
getEndSoC() {
return this.m_object.getEndSoC();
}
/**
* Get the charging time
* @returns {number} the charging time
**/
getChargingTime() {
return this.m_object.getChargingTime();
}
/**
* Check if stop is a charger
* @returns {boolean} true if stop is a charger
**/
isChargeStop() {
return this.m_object.isChargeStop();
}
}
gem.control.SingleMarkerController = class SingleMarkerController extends gem.control.GeoJsonAddedDataControl {
constructor(coordinates,propertiesJson,iconLocation)
{
let geoJsonObject = {
"type": "FeatureCollection", "features": [
{ "type": "Feature", "id": 1, "geometry": { "type": "Point", "coordinates": [coordinates.latitude,coordinates.longitude] }, "properties": propertiesJson }
]
};
super(geoJsonObject,iconLocation,"",undefined);
}
moveTo(coordinates){
if(this.tvectorSources.size()==1)
{
let markerColl = this.tvectorSources.get(0);
if(markerColl.size() == 1)
{
let marker = markerColl.getMarkerAt(0);
marker.movePoint(0,coordinates);
}
}
}
}