= !MapGuide RFC 157 - Support creating MgMap instances with initial display parameters = This page contains a change request (RFC) for the !MapGuide Open Source project. More !MapGuide RFCs can be found on the [wiki:MapGuideRfcs RFCs] page. == Status == ||RFC Template Version||(1.0)|| ||Submission Date||9 Feb 2017|| ||Last Modified||11 Apr 2017|| ||Author||Jackie Ng|| ||RFC Status||Adopted|| ||Implementation Status||Pending|| ||Proposed Milestone||3.3|| ||Assigned PSC guide(s)||(when determined)|| ||'''Voting History'''||(vote date)|| ||+1||Jackie,Crispin,Gordon|| ||+0|||| ||-0|||| ||-1|||| ||no vote|| || == Overview == This RFC proposes to add a new overload of MgMap.Create() that allows for initial display parameters (width/height/dpi/center/scale) to be set, allowing them to be used for certain MgRenderingService operations without a session id. == Motivation == A key roadblock of MapGuide scalability is the current use of session repositories. Using session repositories imposes an upper limit when vertically scaling up MapGuide. Each MapGuide session adds memory and administrative burden on the MapGuide Server. A truly scalable solution would be to completely do away with the notion of session repositories and support stateless rendering of map selection and querying. A stateless map viewer would then be responsible for the management of map selections and view state, leaving the MapGuide Server solely responsible for rendering and querying of feature data. However, the current building blocks to enable the above scenario simply do not exist in the MapGuide Web API in its current form. There are a certain set of APIs in the MgRenderingService that can accept an MgMap object. However, these APIs implicitly assume the MgMap object is to be opened from an existing session repository. It is currently not possible to create an MgMap using MgMap.Create() and immediately use this MgMap in any of the following operations: * QueryFeatureProperties * QueryFeatures * RenderDynamicOverlay * RenderMapLegend These operations require a MgMap instance that was opened from an existing session repository via a mapname/session pair, thus a MapGuide session must always be involved when using any of these operations. It is not possible to use the above APIs in a "stateless" manner without needing to create or use a MapGuide session ID/repository. The reason these operations don't work in a "stateless" context is because such operations expect the MgMap's display properties to be already set: * Display Width * Display Height * DPI * View Center * View Scale However, these properties are immutable and can only be modified through the mapagent-only GETDYNAMICMAPOVERLAYIMAGE API via: * SETDISPLAYWIDTH * SETDISPLAYHEIGHT * SETDISPLAYDPI * SETVIEWCENTERX * SETVIEWCENTERY * SETVIEWSCALE This API also requires a SESSION/MAPNAME pair meaning once again you have to have created and saved a MgMap and MgSelection into a session repository. The immutability of these display parameters hinders our ability to use certain MgRenderingService operations in a "stateless" manner without a MapGuide session id. Without the ability to use these MgRenderingService operations in a stateless manner, we do not have the required pieces to build a stateless map viewer. == Proposed Solution == To remove these limitations, we will introduce an overload of MgMap.Create() that allows these display parameters to be set as part of map creation. {{{ class MG_MAPGUIDE_API MgMap : public MgSerializable { PUBLISHED_API: ////////////////////////////////////////////////////////////////// /// \brief /// Initializes a new MgMap object given a map definition or tile set /// definition and a name for the map with initial display parameters set. /// This method is used for MapGuide Viewers or for offline map production. /// /// \remarks /// If creating a MgMap object from a tile set definition, only "Default" is the /// acceptable tile provider. Any other provider will cause this method to /// throw a MgUnsupportedTileProviderException /// /// /// \htmlinclude DotNetSyntaxTop.html /// void Create(MgResourceIdentifier mapDefinition, string mapName, int displayWidth, int displayHeight, double x, double y, double scale, int dpi); /// \htmlinclude SyntaxBottom.html /// \htmlinclude JavaSyntaxTop.html /// void Create(MgResourceIdentifier mapDefinition, String mapName, int displayWidth, int displayHeight, double x, double y, double scale, int dpi); /// \htmlinclude SyntaxBottom.html /// \htmlinclude PHPSyntaxTop.html /// void Create(MgResourceIdentifier mapDefinition, string mapName, int displayWidth, int displayHeight, double x, double y, double scale, int dpi); /// \htmlinclude SyntaxBottom.html /// /// \param resource /// An MgResourceIdentifier that specifies the /// location of the map definition in a resource /// repository. /// \param mapName /// A string that specifies the name of the map. /// \param displayWidth /// The display width to initially set for the map /// \param displayHeight /// The display height to initially set for the map /// \param x /// The view center X coordinate to initially set for the map /// \param y /// The view center Y coordinate to initially set for the map /// \param scale /// The view scale to initially set for the map /// \param dpi /// The display DPI to initially set for the map /// /// \return /// Returns nothing. /// /// /// \htmlinclude PHPExampleTop.html /// \code /// // Assuming the site connection has already been intialized /// $resourceID = new MgResourceIdentifier('Library://Calgary/Maps/Calgary.MapDefinition'); /// $map = new MgMap($site); /// // Initializes the map to be centered on the Calgary CBD at 1:5000 scale with a DPI of 96 /// $map->Create($resourceID, 'Calgary', 640, 480, -114.054565, 51.068369, 5000.0, 96); /// \endcode /// \htmlinclude ExampleBottom.html /// virtual void Create(MgResourceIdentifier* resource, CREFSTRING mapName, INT32 displayWidth, INT32 displayheight, double x, double y, double scale, INT32 dpi); }; }}} Any MgMap instance created by this new API can immediately be used for any MgRenderingService API that accepts an MgMap without requiring it be loaded from an existing session repository. == Implications == This is a new API addition. Existing forms of MgMap::Create() work as before. == Test Plan == Create MgMap instances using the new overload API and verify they can be used immediately with the following MgRenderingService operations without errors: * QueryFeatureProperties * QueryFeatures * RenderDynamicOverlay * RenderMapLegend == Funding / Resources == Community == Addendum, 11 April 2017 == It has been discovered using {{{QueryFeatures}}}, that the {{{MgFeatureInformation}}} returned has a {{{MgSelection}}} that cannot be interrogated in detail (ie. {{{GetLayers}}} on this selection will throw) The reason is the selection object is "disconnected" in that it has no internal reference to the {{{MgMap}}} it was initialized from (due to the (de)serialization of the {{{MgFeatureInformation}}} from server to web tier). There is a method {{{SetMap}}} that allows one to "attach" the original {{{MgMap}}} instance to the selection so that methods like {{{GetLayers}}} will work again, but this method is not part of the public API. To enable the selection within a {{{MgFeatureInformation}}} to be interrogated, the {{{SetMap}}} method will be promoted to {{{EXTERNAL_API}}}