X

Spatial Visualization - technical tips, best practices, and news from the product team

Recent Posts

Oracle Maps V2 API: Dynamic Tile Layer (supersedes previous entry)

Oracle Maps V2 API: DynamicTile Layer by Honglei Zhu & Carol PalmerThis is an updated post with new APIs in 12.2.1.1. Overview Dynamic tile layer, a feature in Oracle MapsV2 API, is now available. This featureis very useful for visual analysis in big data analytics. Because a dynamictile layer does not rely on Oracle Maps server metadata to define the tilelayer, client side map applications can define and create tile layers accordingto ad-hoc demand dynamically. Capabilities include: · clientapplication can define dynamic tile layers directly, not relying on pre-definedtile layers on the server side. Because it is independent from Oracle Maps servermetadata definition for tile layers, any number of dynamic tile layers can becreated on the client side. · dynamic tile layer may fetch map images from eitheran Oracle Maps server or from a third party map service provider. · clientapplication may provide a URL-generation function to specify where its tileimages are to be fetched. How it works Ina map application, a dynamic tile layer is created in a similar way as aregular tile layer, but with differentparameters. Behind the scenes, the differences are fundamental. Toillustrate their similarities and differences, a regular tile layer definitionis given first as follows: Assumea variable baseURL is properly defined and the specified dataSource andtileLayer exist. A regular tile layer can be defined and instantiated (see codesnippet below). The tile layer instance can then be added into the client mapapplication. Code snippet for a regular tile layer: a regular tile layer definition. var regular_tilelayer = newOM.layer.TileLayer("tilelayer", { tileServerURL:baseURL+"/mcserver", dataSource:"mvdemo", tileLayer:"demo_map" }); Inthe above code snippet, the tile layer map images will be fetched from an Oracle Maps cache server (i.e., the /mcserversuffix in the tileServerURL property) from the given dataSource (mvdemo). Thetile layer (demo_map) should have been defined in Oracle Maps server metadatain view USER_SDO_CACHED_MAPS. Belowseveral examples show how to create a dynamic tile layer. To define a dynamictile layer, you need to create a Tile Layer Config instance and a universeinstance. You may use a built-in universe from the V2 API or create your own.For simplicity and to save space, the examples use a built-in universe. A TileLayer Config instance only needs to define the dimension of an image tile, and 256pixels for a tile image's width and height are commonly adopted. The following codesnippet creates those two instances and will be referenced by all dynamic tilelayer examples. Code snippet for universe and config: creating a universe and a TileLayer Config instance. var myuniv= new OM.universe.LatLonUniverse(); var myconfig=new OM.layer.TileLayerConfig( { tileImageWidth: 256, tileImageHeight: 256 }); Example 1: A dynamictile layer that fetches map images from an Oracle Maps server and has its map contents defined by a server basemap. Code snippets for example 1: A dynamic tile layer based on a server basemap. Step1:create a ServerMapRequest instance and set its properties var req = newOM.server.ServerMapRequest(baseURL); req.setProperties({ dataSource:"MVDEMO", basemap: 'demo_map', transparent:true, antialiase:"false", }); Step2: create an object containing properties of this dynamic tile layer var dtl_props = { universe: myuniv, tileLayerConfig: myconfig, tileServerURL: baseURL +"/omserver", enableUTFGrid: true, enableUTFGridInfoWindow: true, utfGridResolution: 4 }; Step3: create a dynamic tile layer var dynamic_tilelayer_1 = new OM.layer.DynamicTileLayer("dynamic_tl1",dtl_props, req); Inthe above example in step 2, the string value in variable tileServerURL ispointing to an Oracle Maps server (i.e., the /omserver suffix in the tileServerURLproperty) of a server instance. The variable baseURL, as required by a regulartile layer, is defined in the same way as it would be for a regular tile layer.This baseURL may point to the same server as where the web mapping applicationis deployed, or point to another Oracle Maps server instance. For example, itcan be in a form of (a) or (b) below: (a)From the same Oracle Maps server instance: varbaseURL=document.location.protocol+"//"+document.location.host+"/mapviewer"; (b) From another Oracle Maps server instance: var baseURL="http://myapp.mycorp.com/mapviewer"; Fromthis example, you notice that three statements are given to create a dynamictile layer: 1) create a map request instance, ServerMapRequest; 2) create anJSON object to contain the dynamic tile layer related properties; and 3)instantiate a dynamic tile layer. Asshown in the code snippet, a dynamic tile layer does not need a tile layer tobe pre-defined in Oracle Maps server metadata, i.e., it does not need a row inview USER_SDO_CACHED_MAPS. Anothersignificant difference is that a regular tile layer (see code snippet for aregular tile layer) fetches map images from an Oracle Maps cache server (mcserver,which retrieves map tiles from its disk-cache), but a dynamic tile layer (seecode snippet for example 1) requests map images from an Oracle Maps map server(omserver, which renders a fresh map image and does not disk-cache images). Becauseof this difference, a regular tile layer may demand large storage space fordisk-caching if a large number of regular tile layers are created. It will bean insufficient use of storage resources if the cached images are not likely tobe requested again. Example 2:A dynamic tile layer that fetchesmap images from an Oracle Maps server and has itsmap contents defined by server themes. Code snippets for example 2: A dynamic tile layer based on a list of predefinedthemes. Step1:create a ServerMapRequest instance and set its properties var req = newOM.server.ServerMapRequest(baseURL); req.setProperties({ dataSource:"MVDEMO", transparent:true, antialiase:"false", }); var t1 = newOM.server.ServerPredefinedTheme("THEME_DEMO_STATES"); var t2 = newOM.server.ServerPredefinedTheme("THEME_DEMO_HIGHWAYS"); var t3 = newOM.server.ServerPredefinedTheme("THEME_DEMO_CITIES"); req.addThemes([t1, t2, t3]); Step2: create an object containing properties of this dynamic tile layer var dtl_props = { universe: myuniv, tileLayerConfig: myconfig, tileServerURL: baseURL +"/omserver", enableUTFGrid: true, enableUTFGridInfoWindow: true, utfGridResolution: 4 }; Step3: create a dynamic tile layer var dynamic_tilelayer_2 = new OM.layer.DynamicTileLayer("dynamic_tl2",dtl_props, req); Comparing thisexample with Example 1, you notice that instead of specifying a server basemap,the ServerMapRequest instance adds some predefined themes. From a practicalperspective, it offers the flexibility of creating tile layers based on availablepredefined themes. In other words, a client side defined dynamic tile layer mayonly depend on some rows in server metadata in view USER_SDO_THEMES. Example 3:A dynamic tile layer that fetchesmap images from an Oracle Maps server and its mapcontents are dynamically specified using Oracle spatial tables. Code snippets for example 3: A dynamic tile layer based on spatialtables. Step1: create a style var myc1 = new OM.style.Color({ styleName: "mycolor1", stroke: "#333333", strokeOpacity: 1.0, fill: "#F2EFE9", fillOpacity: 1.0 }); Step2: create a JDBC theme and set its properties var jdbcTStates= newOM.server.ServerJDBCTheme('theme_jdbc_states'); jdbcTStates.setDataSourceName('mvdemo'); jdbcTStates.setSRID('8307'); jdbcTStates.setGeometryColumnName('geom'); var sql='select totpop, poppsqmi,state, state_abrv, geom from states'; jdbcTStates.setQuery(sql); jdbcTStates.addInfoColumn({column:'state_abrv', name:'State'}); jdbcTStates.addInfoColumn({column:'totpop', name:'Population'}); jdbcTStates.addInfoColumn({column:'poppsqmi', name:'Pop. Density'}); jdbcTStates.setRenderingStyleName('mycolor1'); Step3: create a ServerMapRequest instance and set its properties var req = newOM.server.ServerMapRequest(baseURL); req.setProperties({ dataSource:"MVDEMO", transparent:true, antialiase:"false", }); var t1 = newOM.server.ServerPredefinedTheme("THEME_DEMO_STATES"); var t2 = new OM.server.ServerPredefinedTheme("THEME_DEMO_HIGHWAYS"); var t3 = new OM.server.ServerPredefinedTheme("THEME_DEMO_CITIES"); req.addTheme(jdbcTStates); req.addStyle(myc1); Step4: create an object containing properties of this dynamic tile layer var dtl_props = { universe: myuniv, tileLayerConfig: myconfig, tileServerURL: baseURL +"/omserver", enableUTFGrid: true, enableUTFGridInfoWindow: true, utfGridResolution: 4 }; Step5: create a dynamic tile layer var dynamic_tilelayer_3 = new OM.layer.DynamicTileLayer("dynamic_tl3",dtl_props, req); In this example, a dynamically defined style and ServerJDBCTheme objectare created first. They are then used by the addTheme and addStyle methods of aServerMapRequest object. Example 4:A dynamic tile layer that fetchesmap images from a third party map serviceprovider; map image URLs are generated by a client provided JavaScript function. Code snippets for example 4: A dynamic tile layer's map image URLs aredefined by a client provided function. Step 1: create a URL construction function var urlb = function (w, h,minX, minY, maxX, maxY, options){ varstr="http://my.mycorp.com:8080/geoserver/ows?"; var optParams=""; str = str+"request=getmap"+ "&bbox="+minX+","+minY+","+maxX+","+maxY+ "&width="+w+ "&height="+h; if (!OM.isNull(options)){ for (var key in options){ optParams=optParams+"&"+key +"="+options[key]; } } return str+optParams; } Step2: create an object containing properties of this dynamic tile layer var dtl_props = { universe: myuniv, tileLayerConfig: myconfig, urlBuilder: urlb, urlBuilderOptions: { "layers": "topp:states,sf:sfdem,sf:roads,sf:streams", "CRS": "CRS:84", "service":"WMS", "version":"1.3.0", "format": "image/png" } }; Step3: create a dynamic tile layer var dynamic_tilelayer_4 = new OM.layer.DynamicTileLayer("dynamic_tl4",dtl_props); In thisexample, a dynamic tile layer instance (i.e., dynamic_tilelayer_4) contains a "urlBuilder"property to provide a URL generation function (i.e., urlb). The URL generationfunction will be used by the dynamic tile layer for fetching image tiles fromthe specified map service provider. This code snippet uses a third party mapprovider, a GeoServer instance, to provide map images. Additional map serviceprovider required parameters can be provided in the "urlBuilderOptions" property. In this example,it specifies several additional parameters, "layers","CRS", "service", "version", and"format", needed by the server. Example 5:A dynamic tile layer use case. Code snippet for example 5: A dynamic tile layer use case based on Oracle Maps server. Step1:get the "where" clause from an application's UI from a function, getWhereClauseFromUI(),assuming this function is provided by an application. var wherec = getWhereClauseFromUI(); Step2:create a JDBC theme and set its properties var objJDBCTheme= newOM.server.ServerJDBCTheme(); objJDBCTheme.setDataSourceName('storm'); objJDBCTheme.setSRID('3857'); objJDBCTheme.setXColumnName('long_loc'); objJDBCTheme.setYColumnName('lat_loc'); objJDBCTheme.addInfoColumn({column: 'YEAR',name:'Year'}); objJDBCTheme.addInfoColumn({column:'MONTH', name:'Month'}); objJDBCTheme.addInfoColumn({column: 'DAY',name:'Day'}); objJDBCTheme.addInfoColumn({column:'STATE', name:'State'}); objJDBCTheme.addInfoColumn({column: 'LOSS',name:'Loss'}); objJDBCTheme.addInfoColumn({column:'CROPLOSS', name:'Crop_loss'}); objJDBCTheme.addInfoColumn({column:'FATALITIES', name:'Fatalities'}); objJDBCTheme.addInfoColumn({column: 'INJURIES',name:'Injuries'}); objJDBCTheme.setName('theme_tornado'); objJDBCTheme.setQuery("SELECTs.geom.sdo_point.x long_loc,s.geom.sdo_point.ylat_loc,year,month,day,state,fatalities,injuries,loss,croploss fromtornado_3857 s"+ (wherec === "" ?"": wherec)); objJDBCTheme.setRenderingStyleName('V.TORNADO'); Step3: create a ServerMapRequest instance and set its properties var req = newOM.server.ServerMapRequest(baseURL); req.setProperties({ dataSource:'storm', transparent:true, antialiase:"false", }); req.addTheme(objJDBCTheme); Step4: create an object containing properties of this dynamic tile layer var dtl_props = { universe: myuniv, tileLayerConfig: myconfig, tileServerURL: baseURL +"/omserver", enableUTFGrid: true, enableUTFGridInfoWindow: true, utfGridResolution: 4 }; Step5: create a dynamic tile layer var tornado_damage = new OM.layer.DynamicTileLayer("tornado_damage",dtl_props, req); The above codesnippet of a dynamic tile layer use case illustrates the following characteristics: 1) Themap application fetches map images from an Oracle Maps server. Therefore, takes advantage ofall available features from an Oracle Maps server. 2) Themap image is set to be transparent (i.e., the value for property"transparent" is true). This setting makes all of the non-overlappingfeatures visible when multiple dynamic tile layers are displayed. For example,when you overlay a 'tornado_damage' layer on top of a 'hail_damage' layer, youmay see both layers on the map when event locations are not overlapping. Thissetting is more useful for multiple layers containing linear and pointfeatures. Note that since the V2 API allows you to turn on/off a layer'svisibility, you can always make a layer of interest standout and visible inyour application. 3) Thedynamic tile layer also enables Oracle Maps server'sUTFGrid support (i.e., the value for property "enableUTFGrid" is truewith a resolution of 4 be specified as the value of property " utfGridResolution "). This setting instructs V2 APIto request an additional file as a companion of a map tile image. The filecontains a JSON object to provide a two-dimensional grid that matches the tileimage plus some text attributes for each grid cell. When a mouse event istriggered (e.g., a mouse click) at an image pixel, its corresponding grid cellcan then be located and thus the text attributes of that grid cell can beretrieved and displayed in the info window. Thetext attributes in a JSON document is defined in a server theme's<hidden_info> element. The theme can be either a predefined geometry themeor a dynamically formatted JDBC theme. In the above code snippet, a JDBC themewas employed and the addInfoColumn() was used to add the info columnsto be displayed by the info window. Aresolution value (e.g., "utfGridResolution":4) indicates the window width and height in the maptile image a grid cell represents. In this example, one grid cell in theUTFGrid dataset represents 16 pixels (4x4=16). 4) Thedynamic tile layer makes use of Oracle Maps server JDBC themes when defining its map contents. In its embeddedSQL statement, the client web application has the flexibility to construct thewhole statement, including the tables to use, the columns to select and the "where"clause to refine the query. In the code snippets, it assumes that a clientfunction, getWhereClauseFromUI(),is facilitated to only construct the 'where' clause in the JDBC themedefinition. Given the abovedescription, you can see how the map application works. Its web user interface(UI) may allow a user to set value ranges for database columns of interestfirst. When a display event is invoked, then a dynamic tile layer's map is displayed.When the user clicks on a feature in the map, an info window pops-up, showingadditional text attributes of the feature clicked. Because this layer is settransparently, it may have been just one of such dynamic tile layer instances witheach dedicated for a spatial table (or each for a collection of differentspatial tables). When the user changes some values from the UI, the existing dynamictile layer instance is removed from the map application and a brand new dynamictile layer is created and its map image tiles together with additional textattributes in the UTFGrid be fetched from the Oracle Maps server. Note that ifyou prefer not to set a dynamic tile layer transparently, you may replace the 'transparent'property with a 'bgcolor' property with a background color value specified (seeOracle Maps user guide for details on background color specification). A demo case Screenshots from a demo application illustrate how dynamic tile layers canbe used in a real application. This application maps three US weather-systems(wind, tornado, and hail) that caused damage to human lives, property, and agriculturefrom 1950 to 2010. Each category is represented by one dynamic tile layer, and eachevent is shown as a point at the event location in a color coded marker symbol.The needed marker symbols are pre-defined in Oracle Maps server metadata inview USER_SDO_STYLES. There are a little over 600,000 events in total for allthree categories. This application's web UI allows an analyst to change thecriteria for extracting a subset of the data to display. Screenshot 1: Overall look and feel of the application This mapapplication contains four tile layers and their names are seen near theupper-left corner. The first layer is the background map. It is a regular tilelayer and 'Oracle' (it indicates Oracle Maps eLocation map service) is selectedin the screenshot to provide map images. The other three layers are all dynamictile layers. They are for wind, tornado, and hail respectively to display theirevent locations, and the hail layer is the last layer on top of the displaystack. When the webapplication is initially accessed, all three dynamic tile layers are visible,and each one shows all of the data points (because no filter has been appliedon the data yet, as it is designed in this application). At the initial mapzoom level, the scalable marker symbols become a dot in the map, and some areasget data points that are so dense that the top layer covers the underneathlayers. At this point, as an end user, you get the sense about how much datayou have. You would filter the dataand/or zoom in to small areas of interest for further inspection. Let's modifythe data filtration criteria first. Screenshot 2: Apply data filters to display a subset. Screenshot 2filtered the original data. The filters applied only extract events that had causedequal or more than one million-dollar property damage to be displayed. On theweb UI, when you click on the arrow icon to the right of each dynamic tilelayer, a pop-up window shows up to allow you to define the data filteringcriteria. When you click the 'Apply filters' button in the pop-up window, actionswill take place behind the scenes. There are two key actions: remove theexisting dynamic tile layer from the map application, and then create a new dynamictile layer to display new data extracted according to the modified datafiltration criteria. You may now want to drill down to a small area of interestto examine the data more closely. Screenshot 3: Zoom in to a small area of interest In screenshot3, the detailed background map and all three filtered dynamic tile layers areclearly seen: blue rectangle markers are for the wind damage event location,brown circles are for the tornados, and cyan colored diamonds are for hail. It isworth pointing out two properties of this application. 1) Because eachdynamic tile layer is set to be transparent (see code snippet example 5), the backgroundmap tile layer (i.e., the first layer that gets map images from Oracle MapseLocation) is visible, and marker symbols of other three dynamic tile layersare also visible while not covered by other layers, if any, above it. 2) If you click on an event marker symbol, theenabled UTFGrid feature allows this map application to pop-up an info window toshow additional text attributes (note that code snippet example 5 has shown howthe text attributes are specified). When should I usea dynamic tile layer? 1) You should use a dynamic tile layer when you needto define a tile layer in your web application and it does not exist in OracleMaps server metadata. In other words, a dynamic tile layer does not require arow in the Oracle Database in view USER_SDO_CASHED_MAPS to define itsspecifications. (For a regular tilelayer, a tile layer must have been defined in Oracle Maps server metadatabefore being used in a client map application.) 2) When you need the flexibility of defining tilelayers to fetch map images from different map resources from an Oracle Maps server,then you need to use a dynamic tile layer. It supports the following options: a) Use a server basemap to provide map contents (seeExample 1 for details) if the basemap has already been defined in metadata inview USER_SDO_MAPS. b) Use a list of predefined themes (see Example 2 fordetails). The themes should have already been defined in metadata in view USER_SDO_THEMES. c) Use spatial tables in an Oracle Database andconstruct server JDBC themes dynamically for map image rendering (see Examples3 and 5 for details). It only needs the Oracle spatial tables for Oracle Maps serverto render the requested image maps. 3) You need to use a dynamic tile layer when you needto fetch maps from a third party map service provider. In this case, you also need to define a URLgeneration function for the dynamic tile layer to fetch map images (see Example4 for details). Applicationsthat a dynamic tile layer best fit Because a dynamictile layer is defined on the client side and does not depend on the server sidedefinition (it does not need the server metadata in view USER_SDO_CACHED_MAPSto define it) and JDBC themes can be formulated according to a client sidedesigned user interface, dynamic tile layer instances can be createddynamically according to some ad-hoc parameters in a UI setting. It best fitsin applications where a user needs to view data from different perspectives.For example, in big data analytics and data mining, an analyst may need toapply different data filtration and segmentation techniques. A dynamic tilelayer may be constructed as needed dynamically to display the data of interest onmap images. In addition, when Oracle Maps serveris used to provide map images, a data analyst does not need to be concernedabout the server's storage space, because Oracle Mapsserver does not disk-cache dynamic tile layer's map images. Many otherfeatures provided by Oracle Maps server,such as UTFGrid support, map image transparent setting, background colorsetting, and map layer visibility control will only enhance end userexperiences for Oracle Maps basedmap applications. Dynamic tilelayer may also extend regular Oracle Maps mappingcapabilities by its client side provided URL generation function option. Thisallows a map application to easily integrate map contents from different mapservice providers to enrich the map contents delivered to the end user. Summary: The dynamictile layer type in Oracle Maps V2 API has eliminated many constraints from aregular tile layer and provides flexibility on how a dynamic tile layer isdefined and where to fetch its map images. When the mapimages are fetched from an Oracle Maps server,it does not require a tile layer to be defined in advance in server metadata,map images are freshly generated instead of using disk-cached images, and themap images are not disk-cached. When defining a dynamic tile layer, its mapcontents may come from a server basemap, a list of predefined themes, ordynamically formulated JDBC themes. When the mapimages are fetched from a third party map service provider, a dynamic tilelayer allows a web application to define its map image URLs, and thus mapimages may be fetched from any map service providers. Dynamic tilelayer feature is best suited for big data applications where visual analysis,as part of big data analytics, helps provide greater insight from that data.

Oracle Maps V2 API: Dynamic Tile Layer by Honglei Zhu & Carol Palmer This is an updated post with new APIs in 12.2.1.1. Overview Dynamic tile layer, a feature in Oracle MapsV2 API, is now available. This...

Script to add missing metadata to mvdemo (12.2.1.1.0) schema for DTL examples

-- Note: if the quotes (single or double) are converted to smart-quotes on copy-n-paste then the -- script may have to be manually edited to fix that-- execute the following SQL statements in sqlplus or SqlDeveloper as the mvdemo2 (or nedata) user-- to add the required theme, map, and tile layers for the Dy Tile Layer examples-- set define off is needed so that the ampersand in &gt; is not treated as a substitution variableset define off;insert into user_sdo_themes values ('UTFGRID_THEME_DEMO_CITIES', 'for utfgrid testing', 'CITIES_US', 'LOCATION','<?xml version="1.0" standalone="yes"?><styling_rules> <hidden_info> <field column="CITY" name="City"/> <field column="POP90" name="Population"/> </hidden_info> <rule> <features style="M.ALL_CITY_L2"> (pop90 between 200000 AND 1000000 ) </features> <label column="city" style="T.S07_CITIES_L2"> 1 </label> </rule> <rule> <features style="M.ALL_CITY_L3"> (pop90 between 0 and 200000) </features> <label column="city" style="T.S07_CITIES_L3"> 1 </label> </rule></styling_rules>') ;insert into user_sdo_themes values ('UTFGRID_THEME_DEMO_COUNTIES', 'for utfgrid testing', 'COUNTIES', 'GEOM','<?xml version="1.0" standalone="yes"?><styling_rules> <hidden_info> <field column="COUNTY" name="County"/> <field column="POPPSQMI" name="PopulationDensity"/> <field column="TOTPOP" name="Population"/> <field column="STATE_ABRV" name="State"/> </hidden_info> <rule> <features style="L.S06_BORDER_STATE"> </features> </rule></styling_rules>') ;insert into user_sdo_themes values ('UTFGRID_THEME_DEMO_STATES', 'for utfgrid testing', 'STATES', 'GEOM','<?xml version="1.0" standalone="yes"?><styling_rules> <hidden_info> <field column="STATE" name="State"/> <field column="STATE_ABRV" name="Abrv."/> <field column="TOTPOP" name="Population"/> </hidden_info> <rule> <features style="C.S02_COUNTRY_AREA"> </features> <label column="STATE_ABRV" style="T.S02_STATE_ABBREVS"> 1 </label> </rule></styling_rules>') ;insert into user_sdo_themes values ('UTFGRID_THEME_DEMO_HIGHWAYS', 'for utfgrid testing', 'INTERSTATES', 'GEOM','<?xml version="1.0" standalone="yes"?><styling_rules> <hidden_info> <field column="HIGHWAY" name="Highway"/> <field column="ROUTEN" name="No."/> </hidden_info> <rule> <features style="L.S04_ROAD_INTERSTATE"> </features> <label column="routen" style="M.HWY_USA_INTERSTATE_NARROW"> (3-length(routen)) </label> </rule></styling_rules>') ;insert into user_sdo_themes values ('THEME_US_DYN_HIGHWAYS', 'dynamic theme for utfgrid testing', 'INTERSTATES', 'GEOM','<?xml version="1.0" standalone="yes"?><styling_rules key_column="ROWID" caching="NORMAL"> <hidden_info> <field column="HIGHWAY" name="Highway"/> <field column="ROUTEN" name="Number"/> </hidden_info> <rule> <features style="L.PH"> ROUTEN=:1 </features> <label column="HIGHWAY" style="T.AIRPORT NAME"> 1 </label> </rule></styling_rules>') ;insert into user_sdo_themes values ('THEME_US_DYN_COUNTIES', 'dynamic theme for utfgrid testing', 'COUNTIES', 'GEOM','<?xml version="1.0" standalone="yes"?><styling_rules key_column="ROWID" caching="NORMAL"> <rule> <features style="C.COUNTIES"> COUNTY=:1 </features> <label column="COUNTY" style="T.AIRPORT NAME"> 1 </label> </rule> <rule> <features style="C.RED"> TOTPOP&gt;:2 </features> <label column="COUNTY" style="T.PARK NAME"> 1 </label> </rule></styling_rules>') ;insert into user_sdo_themes values ('THEME_US_DYN_STATES', 'dynamic theme for utfgrid testing', 'STATES', 'GEOM','<?xml version="1.0" standalone="yes"?><styling_rules key_column="ROWID" caching="NORMAL"> <rule> <features style="C.RED"> state_abrv=:1 </features> <label column="STATE" style="T.PARK NAME"> 1 </label> </rule></styling_rules>') ;insert into user_sdo_maps values ('COUNTY_UTFGRID_BASEMAP', null, '<?xml version="1.0" standalone="yes"?> <map_definition> <theme name="THEME_DEMO_COUNTY_POPDENSITY"/> <theme name="THEME_DEMO_STATES_LINE" label_min_scale="Infinity" label_max_scale="1.6E7" scale_mode="RATIO"/> <theme name="THEME_DEMO_HIGHWAYS_LINE"/> <theme name="THEME_DEMO_CITIES" min_scale="1.6E7" max_scale="0.0" scale_mode="RATIO"/> </map_definition>') ;insert into user_sdo_maps values ('UTFGRID_BASEMAP', null, '<?xml version="1.0" standalone="yes"?> <map_definition> <theme name="UTFGRID_THEME_DEMO_STATES" min_scale="1.0e20" max_scale="0.0" scale_mode="RATIO"/> <theme name="UTFGRID_THEME_DEMO_HIGHWAYS" min_scale="1.0e20" max_scale="0.0" scale_mode="RATIO"/> <theme name="UTFGRID_THEME_DEMO_CITIES" min_scale="7.5e6" max_scale="0.0" scale_mode="RATIO"/></map_definition>') ;insert into user_sdo_cached_maps values('UTFGRID_TL', null, null, 'YES', 'YES', '<?xml version = "1.0" encoding = "UTF-8"?><map_tile_layer concurrent_fetching_threads="3" fetch_larger_tiles="false" http_header_expires="168.0" image_format="PNG" name="UTFGRID_TL" utfgrid="true" utfgrid_resolution="4"> <internal_map_source base_map="UTFGRID_BASEMAP" bgcolor="none" data_source="MVDEMO" db_tile_table=""/> <tile_storage root_path="/temp/MVDEMO.UTFGRID_TL/" xyz_storage_scheme="true"/> <coordinate_system maxX="180.0" maxY="90.0" minX="-180.0" minY="-90.0" srid="8307"/> <tile_image height="256" width="256"/> <tile_dpi value="90.7142857"/> <tile_meters_per_unit value="111319.49079327358"/> <zoom_levels levels="19" max_scale="5.590822640287178E8" min_scale="2132.729583849784" min_tile_height="360.0000000566929" min_tile_width="0.0013732910158412662"> <zoom_level description="" level="0" name="" scale="5.590822640287178E8" tile_height="360.0000000566929" tile_width="360.0000000566929"/> <zoom_level description="" level="1" name="" scale="2.795411320143589E8" tile_height="180.00000002834645" tile_width="180.00000002834645"/> <zoom_level description="" level="2" name="" scale="1.3977056600717944E8" tile_height="90.00000001417322" tile_width="90.00000001417322"/> <zoom_level description="" level="3" name="" scale="6.988528300358972E7" tile_height="45.00000000708661" tile_width="45.00000000708661"/> <zoom_level description="" level="4" name="" scale="3.494264150179486E7" tile_height="22.500000003543306" tile_width="22.500000003543306"/> <zoom_level description="" level="5" name="" scale="1.747132075089743E7" tile_height="11.250000001771653" tile_width="11.250000001771653"/> <zoom_level description="" level="6" name="" scale="8735660.375448715" tile_height="5.6250000008858265" tile_width="5.6250000008858265"/> <zoom_level description="" level="7" name="" scale="4367830.1877243575" tile_height="2.8125000004429133" tile_width="2.8125000004429133"/> <zoom_level description="" level="8" name="" scale="2183915.0938621787" tile_height="1.4062500002214566" tile_width="1.4062500002214566"/> <zoom_level description="" level="9" name="" scale="1091957.5469310894" tile_height="0.7031250001107283" tile_width="0.7031250001107283"/> <zoom_level description="" level="10" name="" scale="545978.7734655447" tile_height="0.35156250005536416" tile_width="0.35156250005536416"/> <zoom_level description="" level="11" name="" scale="272989.38673277234" tile_height="0.17578125002768208" tile_width="0.17578125002768208"/> <zoom_level description="" level="12" name="" scale="136494.69336638617" tile_height="0.08789062501384104" tile_width="0.08789062501384104"/> <zoom_level description="" level="13" name="" scale="68247.34668319309" tile_height="0.04394531250692052" tile_width="0.04394531250692052"/> <zoom_level description="" level="14" name="" scale="34123.67334159654" tile_height="0.02197265625346026" tile_width="0.02197265625346026"/> <zoom_level description="" level="15" name="" scale="17061.83667079827" tile_height="0.01098632812673013" tile_width="0.01098632812673013"/> <zoom_level description="" level="16" name="" scale="8530.918335399136" tile_height="0.005493164063365065" tile_width="0.005493164063365065"/> <zoom_level description="" level="17" name="" scale="4265.459167699568" tile_height="0.0027465820316825325" tile_width="0.0027465820316825325"/> <zoom_level description="" level="18" name="" scale="2132.729583849784" tile_height="0.0013732910158412662" tile_width="0.0013732910158412662"/> </zoom_levels></map_tile_layer>', 'UTFGRID_BASEMAP', null);insert into user_sdo_cached_maps values('COUNTY_UTFGRID_TL', null, null, 'YES', 'YES', '<?xml version = "1.0" encoding = "UTF-8"?><map_tile_layer concurrent_fetching_threads="3" fetch_larger_tiles="false" http_header_expires="168.0" image_format="PNG" name="COUNTY_UTFGRID_TL" utfgrid="true" utfgrid_resolution="4"> <internal_map_source base_map="COUNTY_UTFGRID_BASEMAP" bgcolor="none" data_source="MVDEMO" db_tile_table=""/> <tile_storage root_path="/temp/MVDEMO.COUNTY_UTFGRID_TL/" xyz_storage_scheme="true"/> <coordinate_system maxX="180.0" maxY="90.0" minX="-180.0" minY="-90.0" srid="8307"/> <tile_image height="256" width="256"/> <tile_dpi value="90.7142857"/> <tile_meters_per_unit value="111319.49079327358"/> <zoom_levels levels="12" min_scale="858.0000000000007" max_scale="3.0289566E8" min_tile_width="5.220577239966284E-4" max_tile_width="184.2995557902756"> <zoom_level level="0" name="level0" description="" scale="3.0289566E8" tile_width="184.2995557902756" tile_height="184.2995557902756"/> <zoom_level level="1" name="level1" description="" scale="9.483028858852641E7" tile_width="57.70033173248195" tile_height="57.70033173248195"/> <zoom_level level="2" name="level2" description="" scale="2.9689377635134164E7" tile_width="18.064765635285003" tile_height="18.064765635285003"/> <zoom_level level="3" name="level3" description="" scale="9295122.44960365" tile_width="5.655699848846204" tile_height="5.655699848846204"/> <zoom_level level="4" name="level4" description="" scale="2910108.2014895976" tile_width="1.770681193768741" tile_height="1.770681193768741"/> <zoom_level level="5" name="level5" description="" scale="911093.9409666553" tile_width="0.5543632041587065" tile_height="0.5543632041587065"/> <zoom_level level="6" name="level6" description="" scale="285244.43484309333" tile_width="0.17355951099870603" tile_height="0.17355951099870603"/> <zoom_level level="7" name="level7" description="" scale="89304.05960402885" tile_width="0.05433784860202624" tile_height="0.05433784860202624"/> <zoom_level level="8" name="level8" description="" scale="27959.231057906272" tile_width="0.017012042576674106" tile_height="0.017012042576674106"/> <zoom_level level="9" name="level9" description="" scale="8753.449785099405" tile_width="0.005326114302946117" tile_height="0.005326114302946117"/> <zoom_level level="10" name="level10" description="" scale="2740.521832720056" tile_width="0.001667494860784266" tile_height="0.001667494860784266"/> <zoom_level level="11" name="level11" description="" scale="858.0000000000007" tile_width="5.220577239966284E-4" tile_height="5.220577239966284E-4"/> </zoom_levels></map_tile_layer>', 'COUNTY_UTFGRID_BASEMAP', null);update user_sdo_themes set styling_rules = '<?xml version="1.0" standalone="yes"?><styling_rules key_column="FIPSSTCO" fetch_size="500"> <hidden_info> <field column="COUNTY" name="County"/> <field column="STATE_ABRV" name="State"/> <field column="POPPSQMI" name="Pop_per_sq_mile"/> <field column="TOTPOP" name="TotalPopulation"/> </hidden_info> <rule column="TOTPOP"> <features asis="true" style="V.COUNTY_POP_DENSITY"> </features> </rule></styling_rules>'where name = 'THEME_DEMO_COUNTY_POPDENSITY';

-- Note: if the quotes (single or double) are converted to smart-quotes on copy-n-paste then the -- script may have to be manually edited to fix that -- execute the following SQL statements in...

Using a container datasource in Tomcat with MapViewer 12.2.1

Using a container data source in MapViewer (12.2.1) deployed on  Tomcat requires a modification to the usual process of defining a JNDI resource in Tomcat. To get the container datasource to work with MapViewer you need to prefix the string "java:comp/env/" to the container_ds name in the <map_data_source> entry in mapViewerConfig.xml.That is, your entry should look like:  <map_data_source name="mvdemo_container_ds"                   container_ds="java:comp/env/jdbc/mvdemo"                   number_of_mappers="4"                   allow_jdbc_theme_based_foi="false"                   editable="false"   />Do this after following the standard steps for defining a JNDI resource in Tomcat which uses the Oracle JDBC driver. That is, the Oracle jdbc driver related classes (e.g. ojdbc6-12.10.jar, ora18n-12.1.0.jar) should be in TOMCAT_HOME/lib Add the resource description to MapViewer's context.xml, i.e. mapviewer_home/META-INF/context.xml should contain an entry similar to:<Resource name="jdbc/mvdemo"            auth="Container"           type="javax.sql.DataSource"            driverClassName="oracle.jdbc.OracleDriver"            url="jdbc:oracle:thin:@host:port:SID"           username="mvdemo"            password="pwd4mvdemo"           validationQuery="SELECT 1 FROM DUAL"          validationInterval="30000"          timeBetweenEvictionRunsMillis="30000"          maxActive="100"          minIdle="10"          maxIdle="100"          maxWait="10000"          initialSize="10"          removeAbandonedTimeout="60"          removeAbandoned="true"          logAbandoned="true"         accessToUnderlyingConnectionAllowed="true"    /> Add the resource description to MapViewer's web/xml (mapviewer_home/WEB-INF/web.xml). It should be similar to:<resource-ref> <description>Oracle Datasource example</description> <res-ref-name>jdbc/mvdemo</res-ref-name> <res-type>oracle.jdbc.pool.OracleDataSource</res-type> <res-auth>Container</res-auth></resource-ref>

Using a container data source in MapViewer (12.2.1) deployed on  Tomcat requires a modification to the usual process of defining a JNDI resource in Tomcat. To get the container datasource to work with...

New feature type (MapMarker) in the recent release

The javascript lib (Oracle Maps) in the recent MapViewer release (12.2.1) has a new feature class called MapMarker. The primary purpose is to simplify the process of creating adding markers from a set of POI records, with labels such as 'A' - 'Z' or '1' - 'N' on them. It also supports dragging the markers around and handling the drag events. You can for instance drag the start and destination marker on a route to re-route it. This post contains sample code showing how to do the latter, that is create draggable markers and handle the drag events. The screenshot below shows the result. The code is given below. The steps are create a map object, create one or more MapMarkers, set the dragStart and dragEnd listeners, add the markers to a MarkerLayer (a type of VectorLayer), display the map. The MapMarker class has the following attributes and methods. A constructor which takes a config object that defines the attributes and optionally the listeners.OM.MapMarker(options)where options is an object, or object literal, containing : id {String}: The unique id for the map marker. label {String}: The marker's label text. draggable {Boolean}: Optional. The marker is draggable when this param is set to true. renderingStyle {OM.style.Marker}: Optional. The rendering style for the marker. A default style will be used if none is specified. position {Object}: The marker's position. It may contain the following attributes: x {Number}: The marker's x coordinate y {Number}: The marker's y coordinate srid {Integer}: Optional. The coordinate system for the above x,y values. Default is 8307. dragStart {Function}: Optional. The drag start event listener function. dragging {Function}: Optional. The dragging event listener function. dragEnd {Function}: Optional. The drag end event listener function. And setters and getters for the above attributes. That issetId(id)getId()setLabel(label)getLabel()setDraggable(draggable)isDraggable()setPosition(x,y,srid)getPosition() which returns  an Object containing x, y, and sridsetStyle(sty)getStyle(sty) which returns a marker style, i.e. an OM.style.MarkersetDragEndListener(dragEndListenerFunction)setDragStartListener(dragStartListenerFunction)setDraggingListener(draggngListenerFunction) A marker layer (OM.layer.MarkerLayer)  is a vector layer than only contains MapMarkers. The sample code is below. This assumes the 12.2.1 Glassfish based quickstart kit is deployed. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html style='width:100%;height:100%'><head><title>Draggable map markers</title><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><style>body{width:100%;height:100%;margin:0;padding:0}</style><script type='text/javascript' src='http://localhost:8080/mapviewer/jslib/v2/oraclemapsv2.js'></script><style type= 'text/css '>body {cursor:default;}</style><script language="JavaScript" type="text/javascript"> var layer; var map; function showMap() { var baseURL = "http://localhost:8080/mapviewer"; map = new OM.Map( document.getElementById('map'), { mapviewerURL: baseURL }); var tileLayer = new OM.layer.TileLayer( "baseMap", { dataSource: "mvdemo", tileLayer: "demo_map", tileServerURL: baseURL + "/mcserver" }); map.addLayer(tileLayer); layer = new OM.layer.MarkerLayer("markerlayer1"); var dragStart = function(evt){ document.getElementById("dragstart").innerHTML="Drag started from location (x, y): ("+ evt.markerX.toFixed(4)+", "+evt.markerY.toFixed(4)+").";}; var dragEnd = function(evt){ document.getElementById("dragging").innerHTML="Dropped at location (x, y): (" +evt.markerX.toFixed(4)+", "+evt.markerY.toFixed(4)+").";}; var dragging = function(evt){ document.getElementById("dragging").innerHTML="Dragging now at location (x, y): (" +evt.markerX.toFixed(4)+", "+evt.markerY.toFixed(4)+").";}; // Create an empty MapMarker and then set all properties. srid is the default (8307) var insertMapMarker1 = function(id, cx, cy, label, draggable) { var mm = new OM.MapMarker(); layer.addMapMarker(mm); // add a map marker into marker layer mm.setPosition(cx, cy); mm.setLabel(label); // it will also set the marker text. mm.setID(id); mm.setDraggable(draggable); mm.setDragStartListener(dragStart); mm.setDragEndListener(dragEnd); mm.setDraggingListener(dragging); }; // Specify properties in the options object. srid is the default (8307) var insertMapMarker2 = function(id, cx, cy, label, draggable) { var myobj = {'id': id, 'label': label, 'draggable': draggable, 'dragStart': dragStart, 'dragEnd': dragEnd, 'dragging': dragging, 'position': {'x': cx, 'y': cy}}; var mm = new OM.MapMarker(myobj); layer.addMapMarker(mm); // add a map marker into marker layer }; // an obj with all properties to instantiate a map marker var insertMapMarker3 = function(id, cx, cy, srid, label, draggable) { var myobj = {'id': id, 'label': label, 'draggable': draggable, 'dragStart': dragStart, 'dragEnd': dragEnd, 'dragging': dragging, 'position': {'x': cx, 'y': cy, 'srid': srid}}; var mm = new OM.MapMarker(myobj); var styleForNonDragableMarker = new OM.style.Marker({src: "http://localhost:8080/mvdemo/icons/p_or_ena.png",width: 50, height: 50,textStyle: {fontSize: 12, fill: '#000000'},textOffset: {x: -2, y: -3}}); if(!mm.isDraggable()) { mm.setStyle(styleForNonDragableMarker); console.log("Setting style for non-draggable marker " + mm.getLabel()); } layer.addMapMarker(mm); // add a map marker into marker layer }; insertMapMarker1('m1', -122.3, 38.5, '11', true); // id, cx, cy, srid, label, draggable insertMapMarker2('m2', -122, 37.5, '22', true); insertMapMarker3('m3', -120.7, 38, 8307, '33', true); insertMapMarker3('m4', -121, 39, 8307, ''); // m4 will not be draggable and should use a different style map.addLayer(layer); layer.setToolTipCustomizer(featureTip); map.setMapCenter(new OM.geometry.Point(-122, 38, 8307)); map.setMapZoomLevel(5); var copyRight=new OM.control.CopyRight({anchorPosition:6,textValue:'Map data@NaturalEarth',fontSize:8,fontFamily:'Arial',fontColor:'black'}); map.addMapDecoration(copyRight); addMouseEventListener(); map.init(); } function addMouseEventListener(){ map.addListener(OM.event.MouseEvent.MOUSE_MOVE, featureMouseMove); layer.enableInfoWindow(false); } function featureMouseMove() { var mouseLoc = map.getCursorLocation(); var x = mouseLoc.getX(); var y = mouseLoc.getY(); document.getElementById("mouseLocation").innerHTML="Mouse location (x, y): (" +x.toFixed(4)+", "+y.toFixed(4)+")."; } function featureTip(f) { return "id: "+f.id+"\nlabel: "+ (f.label ? f.label : 'undefined'); }</script></head><body onload="javascript:showMap()"> <DIV id=map style="width:90%;height:90%;margin:10px;"></DIV> <span id="text">Creating draggable map markers.</span> <span id="mouseLocation"></span><br/> <span id="dragstart"></span> <span id="dragging"></span></body></html>

The javascript lib (Oracle Maps) in the recent MapViewer release (12.2.1) has a new feature class called MapMarker. The primary purpose is to simplify the process of creating adding markers from a set...

MapViewer 12cR2 (12.2.1) released. Available on OTN

MapViewer 12.2.1 is now available for download from OTN at http://www.oracle.com/technetwork/middleware/mapviewer/downloads/index.htmlThis version includes a generic EAR file which can be deployed to other JEE containers such as Tomcat or GlassFish.  The WebLogic specific EAR requires WLS with JRF.All MapViewer functionality is included in this kit, including the latest V2 JavaScript Mapping API.In addition, a new feature, dynamic tile layer, allows a client map application to define and create tile layers dynamically.  Because it is independent from MapViewer's metadata definition for tile layers any number of dynamic tile layers can be created on the client side, making it very useful for interactive analytics.  Dynamic tile layer capabilities include:APIs (V2 lib only) for defining dynamic tile layers directly, without relying on pre-defined tile layers on the serverAbility to fetch fresh map images (not cached images) from a MapViewer server or a web map service (WMS) providerAllowing a client application to provide a custom URL-generation function to specify where its tile images are to be fetchedAbility to configure a dynamic tile layer such that attribute values of all the displayed features are embedded in the tile images and displayed via info window or tooltip on mouse over any feature

MapViewer 12.2.1 is now available for download from OTN at http://www.oracle.com/technetwork/middleware/mapviewer/downloads/index.html This version includes a generic EAR file which can be deployed to...

A note on tile names and directory structure

This is a guest post by Honglei Zhu. Important: The tiling scheme described here can, and likely will, change and hence be invalid in future releases. This note outlines the tilestorage, and file naming conventions, for map tile layers created with FMWMapViewer. The tiles are stored in a directory structure based on the datasource name, map tile layer name, number of zoom levels, and tile mesh codes. TileMesh Code and File Storage Structure Each map tile layer isin a directory under $DEFAULT_TILE_STORAGE_ROOT and named [datasource.tile_layer_name].For example, if the default tile storage is /private/tilestore and the tilelayer demo_map is in the datasource is mvdemo, then the tiles will be under/private/tilestore/MVDEMO.DEMO_MAP. Thefirst level of subdirectories contains one directory per zoom level. So ifthere are 19 zoom levels then the subdirectories will be named 0 through 18. Eachzoom level directory will contain tile (files) or directories. That is, tilesare stored in a tree-like directory structure with leaf nodes contain only tileimage files. Non-leaf nodes contain only directories. Mesh codes are used innaming these subdirectories and tiles. TileMesh Code A tile mesh code isrepresented by X (horizontal) and Y (vertical) integer arrays, in a form of[meshX0, meshX1, meshX2, … meshXn] and [meshY0, meshY1, meshY2, … meshYn]. At each zoom level, the length forthe X and Y mesh code array is always the same. Different zoom levels, however,may have different length arrays. The longer the mesh code, the more tileimages that zoom level contains. For a tile with meshcode of [meshX0, meshX1, meshX2, … meshXn] and [meshY0, meshY1, meshY2, …meshYn], its filename and path is: $DEFAULT_TILE_STORAGE_ROOT/[tile_layer_name]/[zoom_level]/[meshX0]_[meshY0]/ [meshX1]_[meshY1]/ [meshX2]_[meshY2]/…/ [meshXn]_[meshYn].png. For example, a MVDEMO.DEMO_MAPtile at zoom level 10, with an X mesh code of [1, 12, 11] and a Y mesh code of[3, 12, 9] will be at: /private/tilestore/MVDEMO.DEMO_MAP/10/1_3/12_12/11_9.png Note:Tile mesh codes are internal to MapViewer andare may change between releases. So the following description of how mesh codesare generated may not be valid in future releases. The mesh code is computedfrom a tile index. The tile index (X,Y) is computed in the Oracle maps clientcode from the map tile layer definition as follows: tileIndexX = (tileMinX–CoordinateSystem.minX) / tileWidth; tileIndexY = (tileMinY–CoordinateSystem.minY) / tileHeight; The server then converts the tile index to a mesh code. DirectoryTree Depth (Mesh Code Length) When the number of tileimages is small for a given zoom level, all tiles may be stored in its rootdirectory. When the number gets to millions or even larger, at higher zoomlevels, they are stored insubdirectories for more efficient file retrieval. The expected number oftiles for a given zoom level is calculated using: maxMeshCodeX = coordinateSystem.width/tileWidth; maxMeshCodeY = coordinateSystem.height/tileHeight; total_tiles = maxMeshCodeX*maxMeshCodeY; A TILING_FACTOR determinesthe depth of the directory tree for a given zoom level. The default value of 20means there will be no more than 400 (20 x 20) sub-directories or tile imagesstored at any zoom level. The mesh code length for X equals the base-20 (orbase TILING_FACTOR) logarithm of maxMeshCodeX. Examplesof converting a tile index (x,y) to Mesh Code 1) Giventhat the TILING_FACTOR is 20, then for zoom level 6, the mesh code length is 4.If the tile index (x,y)=(6063, 7403), then its mesh code is x=[0,15,3,3],y=[0,18,10,3], and the tile is stored at:[tile_layer_name]\6\0_0\15_18\3_10\3_3.png 2) Ifthe TILING_FACTOR is changed to 10, the mesh code length becomes 5. Keeping thezoom level and tile index the same, the mesh code is x=[0, 6, 0, 6, 3],y=[0,7,4,0,3], and the tile is stored at: [tile_layer_name]\6\0_0\6_7\0_4\6_0\3_3.png

This is a guest post by Honglei Zhu.  Important: The tiling scheme described here can, and likely will, change and hence be invalid in future releases. This note outlines the tilestorage, and file...

Potential memory usage issue when using the new MVDEMO data set

Just want to let people know that there is a memory usage issue when viewing the new MVDEMO data set at very detailed zoom levels.  As you probably have seen already the tile layer named 'demo_map' contains a raster layer that looks like the below screenshot: The issue is that the base map 'demo_map' does not stop the display of this raster layer even for map scales that are way beyond the intrinsic resolution of the original raster. As a result, if you zoom in far enough, such as at zoom level 15 or beyond, the Java JAI library used for handling the raster image will cause OutOfMemory errors in the JVM and make MapViewer unresponsive. There is a very simple fix that involves running the following SQL statement in the database schema where the new MVDEMO data was imported:[code] update user_sdo_maps set definition= '<?xml version="1.0" standalone="yes"?>   <map_definition>     <theme name="WORLD_RASTER" min_scale="1.5E18" max_scale="1000000.0" scale_mode="RATIO"/>     <theme name="THEME_DEMO_STATES" min_scale="1.5E8" max_scale="0.0" scale_mode="RATIO"/>     <theme name="THEME_DEMO_COUNTIES" min_scale="8500000.0" max_scale="0.0" scale_mode="RATIO"/>     <theme name="THEME_DEMO_HIGHWAYS_LINE" min_scale="1.0E8" max_scale="4.5E7" scale_mode="RATIO"/>     <theme name="THEME_DEMO_HIGHWAYS" min_scale="4.5E7" max_scale="0.0" scale_mode="RATIO"/>     <theme name="THEME_DEMO_BIGCITIES" min_scale="4.5E7" max_scale="7500001.0" scale_mode="RATIO"/>     <theme name="THEME_DEMO_CITIES" min_scale="7500000.0" max_scale="0.0" scale_mode="RATIO"/>   </map_definition>'   where name='DEMO_MAP';commit; / [code] The above SQL changes the max_scale value for the raster layer in the basemap 'demo_map' (which the tile layer with the same name is based on).  Note that the other tile layer, 'world_map' already has the correct max_scale value for the raster theme. Remember to restart MapViewer or flush its cached metadata to pick up this new definition. ThanksLJ 

Just want to let people know that there is a memory usage issue when viewing the new MVDEMO data set at very detailed zoom levels.  As you probably have seen already the tile layer named 'demo_map'...

Basic example of using GDAL/OGR with MapViewer

This is a quick example of using gdal/ogr to access 3rd party spatial data formats in MapViewer. Specifically a MapInfo mid/mif and TAB files using the builtin ogrSDP (ogr spatial data provider class) to define and access a custom geometry theme. First, download and install GDAL. I used the prebuilt binaries for version 1.9.2 for 64-bit Windows. The precompiled supported formats list includes ESRI and MapInfo filesC:\Program Files\GDAL>ogrinfo --formatsSupported Formats:  -> "ESRI Shapefile" (read/write)  -> "MapInfo File" (read/write)... Then copy the gdal.jar file in the GDAL/Java directory over to someplace where it is in the classpath for MapViewer and MapBuilder. I copied it to the WEB-INF/lib directory for MapViewer and the directory which has MapBuilder. Start up MapBuilder with gdal in the classpath and define custom geometry themes, i.e. use something like the following command to start it.java -Xmx512M -cp .\mapbuilder.jar;.\gdal.jar oracle.mapviewer.builder.MapBuilder Then define Custom Geometry Theme(s) using the ogrSDP. The following screenshots show the definition of a VICTORIA_TAB (tab file format) and MAPINFO_EXAMPLE (mid/mif format)  of postcode boundaries for someplace in Victoria, AU in the VicGrid94 spatial reference system. The corresponding SDO srid is 82473. Once these are defined they can used as predefined themes in MapViewer. This assumes the files are accessible by the MapViewer server and the gdal.jar file is in the lib directory or in the classpath for that MapViewer server. To test it, I modified the C00 - Display a predefined vector layer sample to use a different tile and vector layer. That is, the following lines of the sample code were changed to use the MAPINFO_EXAMPLE theme instead of "customers"        var tileLayer = new OM.layer.TileLayer(        "baseMap",         {            dataSource:"mvdemo",             tileLayer:"elocation_map",             tileServerURL: baseURL+"/mcserver"        });        map.addLayer(tileLayer) ;         layer = new OM.layer.VectorLayer("layer1",         {            def:{                type:OM.layer.VectorLayer.TYPE_PREDEFINED,                 dataSource:"mvdemo2", theme:"MAPINFO_EXAMPLE",                 url: baseURL            }        });  Re-running the modified sample gives the result shown in the screenshot below.

This is a quick example of using gdal/ogr to access 3rd party spatial data formats in MapViewer. Specifically a MapInfo mid/mif and TAB files using the builtin ogrSDP (ogr spatial data provider class)...

A note on using Spherical Mercator (epsg:3785) with 11g

This is a brief note on how to use Web Mercator (EPSG:3785) with database 11g and MapViewer. Further details can be found in the Spatial and MapViewer documentation that is inhttp://docs.oracle.com/cd/E16655_01/appdev.121/e17896/sdo_cs_concepts.htm#CIHJFBFG (Spatial), andhttp://docs.oracle.com/cd/E28280_01/web.1111/e10145/vis_omaps.htm#BACDBCBI (MapViewer).There are two options for using Web Mercator with MapViewer.The first (and preferred option) is to use database version 11.2.0.3 (or later) and MapViewer 11.1.1.6 (or later) and use the ESPG:3857 srid instead. In order to do this the tile layer config definitions for the Google/Bing/OSM/Nokia etc. tile layers must be updated to change the SRID from 3785 to 3857. If a database entry in user_sdo_cached_maps is used to specify the tile layer (and its config) then just update the stored definition in that view. For example, if the entry is SQL> select name, definition from user_sdo_cached_maps where name='NOKIA_MAP';NAME--------------------------------DEFINITION--------------------------------------------------------------------------------NOKIA_MAP<map_tile_layer name="nokia_map">   <external_map_source url="" builtin_tile_layer="nokia">      <properties>         <property name="lib_url" value="http://api.maps.nokia.com/2.2.0/jsl.js"/>         <property name="key" value="your_api_key"/>         <property name="appId" value="your_appId"/>         <property name="map_type_values"          value="MVNokiaTileLayer.TYPE_NORMAL;MVNokiaTileLayer.TYPE_SATELLITE;MVNokiaTileLayer.TYPE_TERRAIN"/>         <property name="map_type_names" value="Normal;Satellite;Terrain"/>         <property name="default_map_type" value="MVNokiaTileLayer.TYPE_NORMAL"/>      </properties>   </external_map_source>   <coordinate_system srid="3785" minX="-2.0037508E7" minY="-2.0037508E7" maxX="2.0037508E7" maxY="2.0037508E7"/>   <tile_image width="256" height="256"/>   <zoom_levels levels="19" min_scale="0.0" max_scale="0.0" min_tile_width="76.43702697753906" min_tile_height="2.0037508E7">      <zoom_level level="0" name="" description="" scale="0.0" tile_width="2.0037508E7" tile_height="2.0037508E7"/>      <zoom_level level="1" name="" description="" scale="0.0" tile_width="1.0018754E7" tile_height="1.0018754E7"/>      <zoom_level level="2" name="" description="" scale="0.0" tile_width="5009377.0" tile_height="5009377.0"/>      <zoom_level level="3" name="" description="" scale="0.0" tile_width="2504688.5" tile_height="2504688.5"/>      <zoom_level level="4" name="" description="" scale="0.0" tile_width="1252344.25" tile_height="1252344.25"/>      <zoom_level level="5" name="" description="" scale="0.0" tile_width="626172.125" tile_height="626172.125"/>      <zoom_level level="6" name="" description="" scale="0.0" tile_width="313086.0625" tile_height="313086.0625"/>      <zoom_level level="7" name="" description="" scale="0.0" tile_width="156543.03125" tile_height="156543.03125"/>      <zoom_level level="8" name="" description="" scale="0.0" tile_width="78271.515625" tile_height="78271.515625"/>      <zoom_level level="9" name="" description="" scale="0.0" tile_width="39135.7578125" tile_height="39135.7578125"/>      <zoom_level level="10" name="" description="" scale="0.0" tile_width="19567.87890625" tile_height="19567.87890625"/>      <zoom_level level="11" name="" description="" scale="0.0" tile_width="9783.939453125" tile_height="9783.939453125"/>      <zoom_level level="12" name="" description="" scale="0.0" tile_width="4891.9697265625" tile_height="4891.9697265625"/>      <zoom_level level="13" name="" description="" scale="0.0" tile_width="2445.98486328125" tile_height="2445.98486328125"/>      <zoom_level level="14" name="" description="" scale="0.0" tile_width="1222.992431640625" tile_height="1222.992431640625"/>      <zoom_level level="15" name="" description="" scale="0.0" tile_width="611.4962158203125" tile_height="611.4962158203125"/>      <zoom_level level="16" name="" description="" scale="0.0" tile_width="305.74810791015625" tile_height="305.74810791015625"/>      <zoom_level level="17" name="" description="" scale="0.0" tile_width="152.87405395507812" tile_height="152.87405395507812"/>      <zoom_level level="18" name="" description="" scale="0.0" tile_width="76.43702697753906" tile_height="76.43702697753906"/>   </zoom_levels></map_tile_layer>where the srid="3785" then update it using a SQL statement like update user_sdo_cached_maps set definition = replace(definition, 'srid="3785"', 'srid="3857"') where name='NOKIA_MAP';If however the usage is via the OracleMaps API methods MVGoogleTileLayer or MVNokiaTileLayer etc. then set the srid to 3857 using their setSrid() method, e.g. myTileLayer.setSrid(3857);The second (and not preferred) option is to add transformation rules that assume a sphere, instead of an ellipsoid, when transforming from the source srid to 3785. So, for example, when transforming from 4326 (WGS84) to 3785 assume that the ellipsoid (WGS 84) is just a sphere. That is not really the case, however, as shown by the query below.SQL> select srid, datum_name, ellipsoid_name, semi_major_axis, semi_minor_axis from  2  sdo_coord_ref_sys c, sdo_datums d, sdo_ellipsoids e where  3  c.srid in (4326, 3785) and  4  (c.datum_id=d.datum_id or c.geog_crs_datum_id=d.datum_id) and  5   d.ellipsoid_id = e.ellipsoid_id ;      SRID DATUM_NAME                       ELLIPSOID_NAME---------- -------------------------------- -----------------------------SEMI_MAJOR_AXIS SEMI_MINOR_AXIS--------------- ---------------      3785 Popular Visualisation Datum      Popular Visualisation Sphere        6378137      4326 World Geodetic System 1984       WGS 84        6378137      6356752.31SQL>So the transformation rule says ignore that WGS84 is an ellipse and assume it's a sphere of radius 6378137 meters.The rule is specified by the following SQL statement (which must be executed by a SYS or similarly privileged user.-- For 4326, EPSG equivalent of 8307call sdo_cs.create_pref_concatenated_op( 43263785, 'CONCATENATED_OPERATION_4326_3785', TFM_PLAN(SDO_TFM_CHAIN(4326, 1000000000, 4055, 19847, 3785)), NULL); which says use the null operation (coord op id 1000000000) when transforming from the geodetic cs 4326 to the geodetic cs 4055, and thereby assume they are spheres of the same radius, and then use the spherical Mercator projection (coord op id 19847) to go to 3785.SQL> select coord_op_name, coord_op_id from sdo_coord_ops where  2  coord_op_id in (1000000000, 19847) ;COORD_OP_NAME                     COORD_OP_ID--------------------------------- -----------Popular Visualisation Mercator    19847EPSG No-Op (EPSG OP 1000000000)   1000000000Each source SRID (e.g. Texas North, or North Carolina) will need its own TFM_CHAIN to go from the projected source srid to its geodetic srid to 4055 and then to 3785 while using a No-Op when going from its datum to 4055.How are values/entries for these tfm_chain determined? Let's look at the two mentioned above (Texas North and NC).We can query cs_srs to find that srid for these are 2844 and 32119.Now query the sdo_coord_ref_sys table to find the crs_datum and projection_conv_id (i.e. coord_op_id) for them.SQL> select coord_ref_sys_name, geog_crs_datum_id, source_geog_srid, projection_conv_id from  2  sdo_coord_ref_sys where srid in (2844, 32119) ;COORD_REF_SYS_NAME             GEOG_CRS_DATUM_ID SOURCE_GEOG_SRID------------------------------ ----------------- ----------------PROJECTION_CONV_ID------------------NAD83(HARN) / Texas North                   6152             4152             14231NAD83 / North Carolina                      6269             4269             13230SQL>Next query the datums and ellipsoids tables to check the semi-major axis radius for them.SQL> select datum_name, ellipsoid_name, semi_major_axis from  2  sdo_datums d, sdo_ellipsoids e where  d.datum_id in (6269, 6152) and  3  d.ellipsoid_id=e.ellipsoid_id;DATUM_NAME                       ELLIPSOID_NAME-------------------------------- --------------------------------SEMI_MAJOR_AXIS---------------NAD83 (High Accuracy Regional Ne GRS 1980twork)        6378137North American Datum 1983        GRS 1980        6378137They both use GRS 1980 with a semi-major radius of 6378137 which is the radius for the spheroid for 4055 too so a No-Op can be used. So the tfm chain becomes 2844, -14231, 4152, 1000000000, 4055, 19847, 3785 for Texas North and 32119, -13230, 4269, 1000000000, 4055, 19847, 3785 for North Carolina.The negative values of PROJECTION_CONV_ID are used since they are the inverse of the projection. That is, projection_conv_id is the operation to go from 4152 to 2844 or from 4269 to 32119.SQL> select coord_op_name, coord_op_id from sdo_coord_ops where  2  coord_op_id in (14231, 13230) ;COORD_OP_NAME-------------------------------------------------------------------------COORD_OP_ID-----------SPCS83 North Carolina zone (meters) (EPSG OP 13230)      13230SPCS83 Texas North zone (meters) (EPSG OP 14231)      14231When a preferred tranformation rule, or operation, is defined it is added to the sdo_preferred_op_system table.SQL> desc sdo_preferred_ops_system Name                                      Null?    Type ----------------------------------------- -------- ---------------------------- SOURCE_SRID                               NOT NULL NUMBER(10) COORD_OP_ID                               NOT NULL NUMBER(10) TARGET_SRID                               NOT NULL NUMBER(10) Now let's look at the coordinate conversions without any preferred (or custom) transformation rules. SQL> select count(1) from sdo_preferred_ops_system ;  COUNT(1)----------         0SQL> select city,  2  sdo_cs.transform(location, 3857) loc_3857,  3  sdo_cs.transform(sdo_cs.transform(location, 2844), 3857) loc_2844_3857,  4  sdo_cs.transform(sdo_cs.transform(location, 2844), 3785) loc_2844_3785  5  from cities where state_abrv='TX' and city='Amarillo' ;CITY------------------------------------------LOC_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)--------------------------------------------------------------------------------LOC_2844_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA--------------------------------------------------------------------------------LOC_2844_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA--------------------------------------------------------------------------------AmarilloSDO_GEOMETRY(2001, 3857, SDO_POINT_TYPE(-11334404, 4191441.06, NULL), NULL, NULL)SDO_GEOMETRY(2001, 3857, SDO_POINT_TYPE(-11334404, 4191441.06, NULL), NULL, NULL)SDO_GEOMETRY(2001, 3785, SDO_POINT_TYPE(-11334404, 4166799.81, NULL), NULL, NULL)The first two (using srid 3857) match up while the conversion to 3785 gives a different result which is slightly offset in Y.Ditto for Raleigh, NCSQL> select city,  2  sdo_cs.transform(location, 3857) loc_3857,  3  sdo_cs.transform(sdo_cs.transform(location, 32119), 3857) loc_32119_3857,  4  sdo_cs.transform(sdo_cs.transform(location, 32119), 3785) loc_32119_3785  5  from cities where state_abrv='NC' and city='Raleigh' ;CITY------------------------------------------LOC_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)--------------------------------------------------------------------------------LOC_2844_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA--------------------------------------------------------------------------------LOC_2844_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA--------------------------------------------------------------------------------RaleighSDO_GEOMETRY(2001, 3857, SDO_POINT_TYPE(-8756252.3, 4276149.54, NULL), NULL, NULL)SDO_GEOMETRY(2001, 3857, SDO_POINT_TYPE(-8756252.3, 4276149.54, NULL), NULL, NULL)SDO_GEOMETRY(2001, 3785, SDO_POINT_TYPE(-8756252.3, 4251131.29, NULL), NULL, NULL) Now let's add the tfm rules. SQL> conn system@sdolnx2Enter password:Connected.SQL> CALL sdo_cs.create_pref_concatenated_op(  2    28443785,  3    'CONCATENATED OPERATION',  4    TFM_PLAN(SDO_TFM_CHAIN(2844, -14231, 4152, 1000000000, 4055, 19847, 3785)),  NULL);Call completed.-- Give a different id and name to the next concatenated opSQL> CALL sdo_cs.create_pref_concatenated_op(  2    321193785,  3    'CONCATENATED OPERATION 32119 3785',  4    TFM_PLAN(SDO_TFM_CHAIN(32119, -13230, 4269, 1000000000, 4055, 19847, 3785)),  NULL);Call completed.Check that these were added SQL> conn mvdemo@sdolnx2Enter password:Connected.SQL> select * from sdo_preferred_ops_system;SOURCE_SRID COORD_OP_ID TARGET_SRID----------- ----------- -----------       2844    28443785        3785       3785   -28443785        2844      32119   321193785        3785       3785  -321193785       32119Now try the above transform queries again and note that all three are the same.SQL> select city,  2  sdo_cs.transform(location, 3857) loc_3857,  3  sdo_cs.transform(sdo_cs.transform(location, 2844), 3857) loc_2844_3857,  4  sdo_cs.transform(sdo_cs.transform(location, 2844), 3785) loc_2844_3785  5  from cities where state_abrv='TX' and city='Amarillo' ;CITY------------------------------------------LOC_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)--------------------------------------------------------------------------------LOC_2844_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA--------------------------------------------------------------------------------LOC_2844_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA--------------------------------------------------------------------------------AmarilloSDO_GEOMETRY(2001, 3857, SDO_POINT_TYPE(-11334404, 4191441.06, NULL), NULL, NULL)SDO_GEOMETRY(2001, 3857, SDO_POINT_TYPE(-11334404, 4191441.06, NULL), NULL, NULL)SDO_GEOMETRY(2001, 3785, SDO_POINT_TYPE(-11334404, 4191441.06, NULL), NULL, NULL)       SQL> select city,  2  sdo_cs.transform(location, 3857) loc_3857,  3  sdo_cs.transform(sdo_cs.transform(location, 32119), 3857) loc_32119_3857,  4  sdo_cs.transform(sdo_cs.transform(location, 32119), 3785) loc_32119_3785  5  from cities where state_abrv='NC' and city='Raleigh' ;CITY------------------------------------------LOC_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)--------------------------------------------------------------------------------LOC_32119_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDIN--------------------------------------------------------------------------------LOC_32119_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDIN--------------------------------------------------------------------------------RaleighSDO_GEOMETRY(2001, 3857, SDO_POINT_TYPE(-8756252.3, 4276149.54, NULL), NULL, NULL)SDO_GEOMETRY(2001, 3857, SDO_POINT_TYPE(-8756252.3, 4276149.54, NULL), NULL, NULL)SDO_GEOMETRY(2001, 3785, SDO_POINT_TYPE(-8756252.3, 4276149.54, NULL), NULL, NULL)Lastly if the ellipsoid for the source projected system does not have the same semi-major axis value (e.g for srid 27700, British National Grid) then the chain should be source to 4326 and then to 3785.For BNG (srid 27700) the ellipsoid is Airy 1830 and the semi-major axis is 6377563.4.SQL> select e.ellipsoid_name, e.semi_major_axis from sdo_ellipsoids e,  2  sdo_datums d, sdo_coord_ref_sys c where  3  c.srid=27700 and  4  c.geog_crs_datum_id = d.datum_id and  5  d.ellipsoid_id = e.ellipsoid_id ;ELLIPSOID_NAME                        SEMI_MAJOR_AXIS----------------------------------------   ---------------Airy 1830                                    6377563.4Add the rule for 4326 to 3785 and then test the direct to 3785 and via 4326 route transforms.call sdo_cs.create_pref_concatenated_op(43263785, 'CONCATENATED_OPERATION_4326', TFM_PLAN(SDO_TFM_CHAIN(4326, 1000000000, 4055, 19847, 3785)), NULL); First without adding a 27700 to 3785 tfm rule that does not go through 4326SQL> select name, sdo_cs.transform(geometry, 27700) geom_bng,  2  sdo_cs.transform(sdo_cs.transform(geometry, 27700), 3785) geom_bng_3785,  3  sdo_cs.transform(sdo_cs.transform(sdo_cs.transform(geometry, 27700),4326),3785) geom_bng_4326_3785  4  from cities where iso_a2='UK' and name='London';NAME------------------------------GEOM_BNG(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)--------------------------------------------------------------------------------GEOM_BNG_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA--------------------------------------------------------------------------------GEOM_BNG_4326_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_O--------------------------------------------------------------------------------LondonSDO_GEOMETRY(3001, 27700, SDO_POINT_TYPE(530678.086, 179789.242, 0), NULL, NULL)SDO_GEOMETRY(3001, 3785, SDO_POINT_TYPE(-13210.033, 6677081.27, 0), NULL, NULL)SDO_GEOMETRY(3001, 3785, SDO_POINT_TYPE(-13210.033, 6710566.11, 0), NULL, NULL)Next add one for 27700 which is likely incorrect call sdo_cs.create_pref_concatenated_op(277003785, 'CONCATENATED_OPERATION_27700', TFM_PLAN(SDO_TFM_CHAIN(27700, -19916, 4277, 1000000000, 4055, 19847, 3785)), NULL); select name, sdo_cs.transform(geometry, 27700) geom_bng,sdo_cs.transform(sdo_cs.transform(geometry, 27700), 3785) geom_bng_3785,sdo_cs.transform(sdo_cs.transform(sdo_cs.transform(geometry, 27700),4326),3785) geom_bng_4326_3785,sdo_cs.transform(sdo_cs.transform(geometry, 27700), 3857) geom_bng_3857from cities where iso_a2='UK' and name='London';NAME------------------------------GEOM_BNG(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)--------------------------------------------------------------------------------GEOM_BNG_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA--------------------------------------------------------------------------------GEOM_BNG_4326_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_O--------------------------------------------------------------------------------GEOM_BNG_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA--------------------------------------------------------------------------------LondonSDO_GEOMETRY(3001, 27700, SDO_POINT_TYPE(530678.086, 179789.242, 0), NULL, NULL)SDO_GEOMETRY(3001, 3785, SDO_POINT_TYPE(-13031.112, 6710474.7, 0), NULL, NULL)SDO_GEOMETRY(3001, 3785, SDO_POINT_TYPE(-13210.033, 6710566.11, 0), NULL, NULL)SDO_GEOMETRY(3001, 3857, SDO_POINT_TYPE(-13210.033, 6710566.11, 0), NULL, NULL)The 3rd and 4th agree. The second (which is 27700 -> 3785 with the rule) disagrees with both the 27700 -> 3857 and the 27700 -> 3785 without a rule.Without a rule it is: SDO_GEOMETRY(3001, 3785, SDO_POINT_TYPE(-13210.033, 6677081.27, 0), NULL, NULL)With a rule that does not iclude 4326 in the chain it is:SDO_GEOMETRY(3001, 3785, SDO_POINT_TYPE(-13031.112, 6710474.7, 0), NULL, NULL)Now modify the rule to correct the chain to include 4326 SQL> call sdo_cs.delete_op(277003785);Call completed.SQL> select coord_op_id, coord_op_name, target_srid from sdo_coord_ops where source_srid=4277 ;COORD_OP_ID COORD_OP_NAME                                      TARGET_SRID----------- -------------------------------------------------- -----------       1195 OSGB 1936 to WGS 84 (1) (EPSG OP 1195)                    4326       1196 OSGB 1936 to WGS 84 (2) (EPSG OP 1196)                    4326       1197 OSGB 1936 to WGS 84 (3) (EPSG OP 1197)                    4326       1198 OSGB 1936 to WGS 84 (4) (EPSG OP 1198)                    4326       1199 OSGB 1936 to WGS 84 (5) (EPSG OP 1199)                    4326       1314 OSGB 1936 to WGS 84 (Petroleum) (EPSG OP 1314)            4326       1315 OSGB 1936 to ED50 (UKOOA) (EPSG OP 1315)                  42307 rows selected.We'll use coord_op_id 1195call sdo_cs.create_pref_concatenated_op(277003785, 'CONCATENATED_OPERATION_27700', TFM_PLAN(SDO_TFM_CHAIN(27700, -19916, 4277, 1195, 4326, 1000000000, 4055, 19847, 3785)), NULL); Redo the query for London to see the if the direct, via 4326, and to 3857 all agree.select name, sdo_cs.transform(geometry, 27700) geom_bng,sdo_cs.transform(sdo_cs.transform(geometry, 27700), 3785) geom_bng_3785,sdo_cs.transform(sdo_cs.transform(sdo_cs.transform(geometry, 27700),4326),3785) geom_bng_4326_3785,sdo_cs.transform(sdo_cs.transform(geometry, 27700), 3857) geom_bng_3857from cities where iso_a2='UK' and name='London';NAME------------------------------GEOM_BNG(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)--------------------------------------------------------------------------------GEOM_BNG_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA--------------------------------------------------------------------------------GEOM_BNG_4326_3785(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_O--------------------------------------------------------------------------------GEOM_BNG_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA--------------------------------------------------------------------------------LondonSDO_GEOMETRY(3001, 27700, SDO_POINT_TYPE(530678.086, 179789.242, 0), NULL, NULL)SDO_GEOMETRY(3001, 3785, SDO_POINT_TYPE(-13210.033, 6677081.27, 0), NULL, NULL)SDO_GEOMETRY(3001, 3785, SDO_POINT_TYPE(-13210.033, 6710566.11, 0), NULL, NULL)SDO_GEOMETRY(3001, 3857, SDO_POINT_TYPE(-13210.033, 6710566.11, 0), NULL, NULL)This time they do. 

This is a brief note on how to use Web Mercator (EPSG:3785) with database 11g and MapViewer. Further details can be found in the Spatial and MapViewer documentation that is inhttp://docs.oracle.com/cd/...

Connecting to a 12c database instance with MapViewer 11.1.1.7.x

The the jdbc connection string (or jdbc url) for a 12c database now requires a service name instead of a SID. In MapViewer 11.1.1.7.1 the jdbc info in the map_data_source element in the mapviewer configuration file accepts a service name but requires a different syntax. The relevant details (from the README) areMapViewer native (non-container) data sources can now use database service name in place of SID. To supply a db service name, you will use the same jdbc_sid attribute, but specify the service name with double slashes in front, e.g.: <map_data_source name="myds" jdbc_host="foo.com" jdbc_sid="//mypdb1.foo.com" jdbc_port="1522" ... ... />If you're using 11.1.1.7.0 then you need to use a container data source to connect to a 12c instance.i.e. instead of using<map_data_source name="my_12c_test"                   jdbc_host="mydbinstance"                   jdbc_sid="//pdborcl12c.foo.com"                   jdbc_port="1522"                   jdbc_user="mytestuser"                   jdbc_password="m2E7T48U3LfRjKwR0YFETQcjNb4gCMLG8/X0KWjO00Q="                   jdbc_mode="thin"                   number_of_mappers="6"                   allow_jdbc_theme_based_foi="false"                   editable="false"   />use  <map_data_source name="my_12c_test"                   container_ds="jdbc/db12c"                   number_of_mappers="6"                   allow_jdbc_theme_based_foi="false"                   editable="false"   />In my case the Glassfish 3.1.2.2 JDBC connection pool definition was:Propertyurl  jdbc:oracle:thin:@mydbinstance:1522/pdborcl12c.rest_of.service.nameUncheck the Wrap JDBC Objects option in Advanced panel, i.e. the Edit JDBC Connection Pool Advanced properties page.Add a JDBC resource for that newly created pool and use that in mapviewerconfig.xml as above

The the jdbc connection string (or jdbc url) for a 12c database now requires a service name instead of a SID. In MapViewer 11.1.1.7.1 the jdbc info in the map_data_source element in the mapviewer...

Thematic map contd.

The previous post (creating a thematic map) described the use of an advanced style (color ranged-bucket style). The bucket style definition object has an attribute ('classification') which specifies the data classification scheme to use. It's values can be one of {'equal', 'quantile', 'logarithmic', 'custom'}. We use logarithmic in the previous example. Here we'll describe how to use a custom algorithm for classification. Specifically the Jenks Natural Breaks algorithm. We'll use the Javascript implementation in geostats.js The sample code above needs a few changes which are listed below. Include the geostats.js file after or before including oraclemapsv2.js <script src="geostats.js"></script> Modify the bucket style definition to use custom classification    bucketStyleDef = {      numClasses : colorSeries[colorName].classes,      classification: 'custom', //'logarithmic',  // use a logarithmic scale       algorithm: jenksFromGeostats,      styles: theStyles,      gradient:  useGradient? 'linear' : 'off'    }; The function, which implements the custom classification scheme, is specified as the algorithm attribute value. It must accept two input parameters, an array of OM.feature and the name of the feature attribute (e.g. TOTPOP) to use in the classification, and must return an array of buckets (i.e. an array of or OM.style.Bucket  or OM.style.RangedBucket in this case). However the algorithm also needs to know the number of classes (i.e. the number of buckets to create). So we use a global to pass that info in. (Note: This bug/oversight will be fixed and the custom algorithm will be passed 3 parameters: the features array, attribute name, and number of classes). So createBucketColorStyle() has the following changes var numClasses ;function createBucketColorStyle(colorName, colorSeries, rangeName, useGradient){   var theBucketStyle;   var bucketStyleDef;   var theStyles = [];   //var numClasses ; numClasses = colorSeries[colorName].classes; ... and the function jenksFromGeostats is defined as functionjenksFromGeostats(featureArray, columnName){   var items = [] ; // array of attribute values to be classified    $.each(featureArray, function(i, feature) {        items.push(parseFloat(feature.getAttributeValue(columnName)));   });    // create the geostats object   var theSeries = new geostats(items);    // call getJenks which returns an array of bounds    var theClasses = theSeries.getJenks(numClasses);   if(theClasses)    {    theClasses[theClasses.length-1]=parseFloat(theClasses[theClasses.length-1])+1;   }   else   {    alert(' empty result from getJenks');   }   var theBuckets = [], aBucket=null ;   for(var k=0; k<numClasses; k++)   {             aBucket =new OM.style.RangedBucket(           {low:parseFloat(theClasses[k]),              high:parseFloat(theClasses[k+1])            });            theBuckets.push(aBucket);    }    return theBuckets;} A screenshot of the resulting map with 5 classes is shown below. It is also possible to simply create the buckets and supply them when defining the Bucket style instead of specifying the function (algorithm). In that case the bucket style definition object would be    bucketStyleDef = {      numClasses : colorSeries[colorName].classes,      classification: 'custom',        buckets: theBuckets, //since we are supplying all the buckets      styles: theStyles,      gradient:  useGradient? 'linear' : 'off'    };

The previous post (creating a thematic map) described the use of an advanced style (color ranged-bucket style). The bucket style definition object has an attribute ('classification') which specifies...

Creating a thematic map

This post describes how to create a simple thematic map, just a state population layer, with no underlying map tile layer. The map shows states color-coded by total population. The map is interactive with info-windows and can be panned and zoomed. The sample code demonstrates the following: Displaying an interactive vector layer with no background map tile layer (i.e. purpose and use of the Universe object) Using a dynamic (i.e. defined via the javascript client API) color bucket style Dynamically changing a layer's rendering style Specifying which attribute value to use in determining the bucket, and hence style, for a feature (FoI) The result is shown in the screenshot below. The states layer was defined, and stored in the user_sdo_themes view of the mvdemo schema, using MapBuilder. The underlying table is defined as SQL> desc states_32775  Name                                      Null?    Type ----------------------------------------- -------- ---------------------------- STATE                                              VARCHAR2(26) STATE_ABRV                                         VARCHAR2(2) FIPSST                                             VARCHAR2(2) TOTPOP                                             NUMBER PCTSMPLD                                           NUMBER LANDSQMI                                           NUMBER POPPSQMI                                           NUMBER... MEDHHINC NUMBER AVGHHINC NUMBER GEOM32775 MDSYS.SDO_GEOMETRY We'll use the TOTPOP column value in the advanced (color bucket) style for rendering the states layers. The predefined theme (US_STATES_BI) is defined as follows. SQL> select styling_rules from user_sdo_themes where name='US_STATES_BI';STYLING_RULES--------------------------------------------------------------------------------<?xml version="1.0" standalone="yes"?><styling_rules highlight_style="C.CB_QUAL_8_CLASS_DARK2_1"> <hidden_info> <field column="STATE" name="Name"/> <field column="POPPSQMI" name="POPPSQMI"/> <field column="TOTPOP" name="TOTPOP"/> </hidden_info> <rule column="TOTPOP"> <features style="states_totpop"> </features> <label column="STATE_ABRV" style="T.BLUE_SERIF_10"> 1 </label> </rule></styling_rules>SQL> The theme definition specifies that the state, poppsqmi, totpop, state_abrv, and geom columns will be queried from the states_32775 table. The state_abrv value will be used to label the state while the totpop value will be used to determine the color-fill from those defined in the states_totpop advanced style. The states_totpop style, which we will not use in our demo, is defined as shown below. SQL> select definition from user_sdo_styles where name='STATES_TOTPOP';DEFINITION--------------------------------------------------------------------------------<?xml version="1.0" ?><AdvancedStyle> <BucketStyle> <Buckets default_style="C.S02_COUNTRY_AREA"> <RangedBucket seq="0" label="10K - 5M" low="10000" high="5000000" style="C.SEQ6_01" /> <RangedBucket seq="1" label="5M - 12M" low="5000001" high="1.2E7" style="C.SEQ6_02" /> <RangedBucket seq="2" label="12M - 20M" low="1.2000001E7" high="2.0E7" style="C.SEQ6_04" /> <RangedBucket seq="3" label="&gt; 20M" low="2.0000001E7" high="5.0E7" style="C.SEQ6_05" /> </Buckets> </BucketStyle></AdvancedStyle>SQL> The demo defines additional advanced styles via the OM.style object and methods and uses those instead when rendering the states layer.   Now let's look at relevant snippets of code that defines the map extent and zoom levels (i.e. the OM.universe),  loads the states predefined vector layer (OM.layer), and sets up the advanced (color bucket) style. Defining the map extent and zoom levels. function initMap(){  //alert("Initialize map view");    // define the map extent and number of zoom levels.  // The Universe object is similar to the map tile layer configuration  // It defines the map extent, number of zoom levels, and spatial reference system  // well-known ones (like web mercator/google/bing or maps.oracle/elocation are predefined  // The Universe must be defined when there is no underlying map tile layer.   // When there is a map tile layer then that defines the map extent, srid, and zoom levels.     var uni= new OM.universe.Universe(    {        srid : 32775,        bounds : new OM.geometry.Rectangle(                        -3280000, 170000, 2300000, 3200000, 32775),        numberOfZoomLevels: 8    }); The srid specifies the spatial reference system which is Equal-Area Projection (United States). SQL> select cs_name from cs_srs where srid=32775 ;CS_NAME---------------------------------------------------Equal-Area Projection (United States) The bounds defines the map extent. It is a Rectangle defined using the lower-left and upper-right coordinates and srid. Loading and displaying the states layer This is done in the states() function. The full code is at the end of this post, however here's the snippet which defines the states VectorLayer.     // States is a predefined layer in user_sdo_themes    var  layer2 = new OM.layer.VectorLayer("vLayer2",     {        def:        {            type:OM.layer.VectorLayer.TYPE_PREDEFINED,             dataSource:"mvdemo",             theme:"us_states_bi",             url: baseURL,            loadOnDemand: false        },        boundingTheme:true     }); The first parameter is a layer name, the second is an object literal for a layer config. The config object has two attributes: the first is the layer definition, the second specifies whether the layer is a bounding one (i.e. used to determine the current map zoom and center such that the whole layer is displayed within the map window) or not. The layer config has the following attributes: type - specifies whether is a predefined one, a defined via a SQL query (JDBC), or in a json-format file (DATAPACK) theme - is the predefined theme's name url - is the location of the mapviewer server loadOnDemand - specifies whether to load all the features or just those that lie within the current map window and load additional ones as needed on a pan or zoom The code snippet below dynamically defines an advanced style and then uses it, instead of the 'states_totpop' style, when rendering the states layer. // override predefined rendering style with programmatic one   var theRenderingStyle =      createBucketColorStyle('YlBr5', colorSeries, 'States5', true);  // specify which attribute is used in determining the bucket (i.e. color) to use for the state  // It can be an array because the style could be a chart type (pie/bar)  // which requires multiple attribute columns     // Use the STATE.TOTPOP column (aka attribute) value here   layer2.setRenderingStyle(theRenderingStyle, ["TOTPOP"]); The style itself is defined in the createBucketColorStyle() function. Dynamically defining an advanced style The advanced style used here is a bucket color style, i.e. a color style is associated with each bucket. So first we define the colors and then the buckets.     numClasses = colorSeries[colorName].classes;   // create Color Styles   for (var i=0; i < numClasses; i++)    {        theStyles[i] = new OM.style.Color(                     {fill: colorSeries[colorName].fill[i],                        stroke:colorSeries[colorName].stroke[i],                      strokeOpacity: useGradient? 0.25 : 1                     });   }; numClasses is the number of buckets. The colorSeries array contains the color fill and stroke definitions and is: var colorSeries = {//multi-hue color scheme #10 YlBl. "YlBl3": {   classes:3,                 fill: [0xEDF8B1, 0x7FCDBB, 0x2C7FB8],                 stroke:[0xB5DF9F, 0x72B8A8, 0x2872A6]  },"YlBl5": {   classes:5,                 fill:[0xFFFFCC, 0xA1DAB4, 0x41B6C4, 0x2C7FB8, 0x253494],                 stroke:[0xE6E6B8, 0x91BCA2, 0x3AA4B0, 0x2872A6, 0x212F85]  },//multi-hue color scheme #11 YlBr. "YlBr3": {classes:3,                 fill:[0xFFF7BC, 0xFEC44F, 0xD95F0E],                 stroke:[0xE6DEA9, 0xE5B047, 0xC5360D]   },"YlBr5": {classes:5,                 fill:[0xFFFFD4, 0xFED98E, 0xFE9929, 0xD95F0E, 0x993404],                 stroke:[0xE6E6BF, 0xE5C380, 0xE58A25, 0xC35663, 0x8A2F04]    }, etc. Next we create the bucket style.    bucketStyleDef = {      numClasses : colorSeries[colorName].classes,//      classification: 'custom',  //since we are supplying all the buckets//      buckets: theBuckets,      classification: 'logarithmic',  // use a logarithmic scale       styles: theStyles,      gradient:  useGradient? 'linear' : 'off'//      gradient:  useGradient? 'radial' : 'off'    };   theBucketStyle = new OM.style.BucketStyle(bucketStyleDef);   return theBucketStyle; A BucketStyle constructor takes a style definition as input. The style definition specifies the number of buckets (numClasses), a classification scheme (which can be equal-ranged, logarithmic scale, or custom), the styles for each bucket, whether to use a gradient effect, and optionally the buckets (required when using a custom classification scheme). The full source for the demo <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Oracle Maps V2 Thematic Map Demo</title><script src="http://localhost:8080/mapviewer/jslib/v2/oraclemapsv2.js" type="text/javascript"></script><script type="text/javascript">//var $j = jQuery.noConflict();var baseURL="http://localhost:8080/mapviewer"; // location of mapviewerOM.gv.proxyEnabled =false;// no mvproxy neededOM.gv.setResourcePath(baseURL+"/jslib/v2/images/"); // location of resources for UI elements like nav panel buttonsvar map = null; // the client mapviewer object var statesLayer = null, stateCountyLayer = null; // The vector layers for states and counties in a statevar layerName="States";// initial map center and zoomvar mapCenterLon = -20000;var mapCenterLat = 1750000;var mapZoom = 2; var mpoint = new OM.geometry.Point(mapCenterLon,mapCenterLat,32775);var currentPalette = null, currentStyle=null;// set an onchange listener for the color palette select list// initialize the map// load and display the states layer$(document).ready( function(){ $("#demo-htmlselect").change(function() {var theColorScheme = $(this).val();useSelectedColorScheme(theColorScheme);}); initMap(); states(); });/** * color series from ColorBrewer site (http://colorbrewer2.org/). */var colorSeries = {//multi-hue color scheme #10 YlBl."YlBl3": { classes:3, fill: [0xEDF8B1, 0x7FCDBB, 0x2C7FB8], stroke:[0xB5DF9F, 0x72B8A8, 0x2872A6] },"YlBl5": { classes:5, fill:[0xFFFFCC, 0xA1DAB4, 0x41B6C4, 0x2C7FB8, 0x253494], stroke:[0xE6E6B8, 0x91BCA2, 0x3AA4B0, 0x2872A6, 0x212F85] },//multi-hue color scheme #11 YlBr. "YlBr3": {classes:3, fill:[0xFFF7BC, 0xFEC44F, 0xD95F0E], stroke:[0xE6DEA9, 0xE5B047, 0xC5360D] },"YlBr5": {classes:5, fill:[0xFFFFD4, 0xFED98E, 0xFE9929, 0xD95F0E, 0x993404], stroke:[0xE6E6BF, 0xE5C380, 0xE58A25, 0xC35663, 0x8A2F04] },// single-hue color schemes (blues, greens, greys, oranges, reds, purples)"Purples5": {classes:5, fill:[0xf2f0f7, 0xcbc9e2, 0x9e9ac8, 0x756bb1, 0x54278f], stroke:[0xd3d3d3, 0xd3d3d3, 0xd3d3d3, 0xd3d3d3, 0xd3d3d3] },"Blues5": {classes:5, fill:[0xEFF3FF, 0xbdd7e7, 0x68aed6, 0x3182bd, 0x18519C], stroke:[0xd3d3d3, 0xd3d3d3, 0xd3d3d3, 0xd3d3d3, 0xd3d3d3] },"Greens5": {classes:5, fill:[0xedf8e9, 0xbae4b3, 0x74c476, 0x31a354, 0x116d2c], stroke:[0xd3d3d3, 0xd3d3d3, 0xd3d3d3, 0xd3d3d3, 0xd3d3d3] }, "Greys5": {classes:5, fill:[0xf7f7f7, 0xcccccc, 0x969696, 0x636363, 0x454545], stroke:[0xd3d3d3, 0xd3d3d3, 0xd3d3d3, 0xd3d3d3, 0xd3d3d3] },"Oranges5": {classes:5, fill:[0xfeedde, 0xfdb385, 0xfd8d3c, 0xe6550d, 0xa63603], stroke:[0xd3d3d3, 0xd3d3d3, 0xd3d3d3, 0xd3d3d3, 0xd3d3d3] },"Reds5": {classes:5, fill:[0xfee5d9, 0xfcae91, 0xfb6a4a, 0xde2d26, 0xa50f15], stroke:[0xd3d3d3, 0xd3d3d3, 0xd3d3d3, 0xd3d3d3, 0xd3d3d3] }};function createBucketColorStyle(colorName, colorSeries, rangeName, useGradient){ var theBucketStyle; var bucketStyleDef; var theStyles = []; var theColors = []; var aBucket, aStyle, aColor, aRange; var numClasses ; numClasses = colorSeries[colorName].classes; // create Color Styles for (var i=0; i < numClasses; i++) { theStyles[i] = new OM.style.Color( {fill: colorSeries[colorName].fill[i], stroke:colorSeries[colorName].stroke[i], strokeOpacity: useGradient? 0.25 : 1 }); }; bucketStyleDef = { numClasses : colorSeries[colorName].classes,// classification: 'custom', //since we are supplying all the buckets// buckets: theBuckets, classification: 'logarithmic', // use a logarithmic scale styles: theStyles, gradient: useGradient? 'linear' : 'off'// gradient: useGradient? 'radial' : 'off' }; theBucketStyle = new OM.style.BucketStyle(bucketStyleDef); return theBucketStyle;}function initMap(){ //alert("Initialize map view"); // define the map extent and number of zoom levels. // The Universe object is similar to the map tile layer configuration // It defines the map extent, number of zoom levels, and spatial reference system // well-known ones (like web mercator/google/bing or maps.oracle/elocation are predefined // The Universe must be defined when there is no underlying map tile layer. // When there is a map tile layer then that defines the map extent, srid, and zoom levels. var uni= new OM.universe.Universe({srid : 32775,bounds : new OM.geometry.Rectangle( -3280000, 170000, 2300000, 3200000, 32775),numberOfZoomLevels: 8}); map = new OM.Map(document.getElementById('map'),{ mapviewerURL: baseURL, universe:uni}) ; var navigationPanelBar = new OM.control.NavigationPanelBar(); map.addMapDecoration(navigationPanelBar);} // end initMapfunction states(){ //alert("Load and display states"); layerName = "States"; if(statesLayer) { // states were already visible but the style may have changed // so set the style to the currently selected one var theData = $('#demo-htmlselect').val(); setStyle(theData); } else { // States is a predefined layer in user_sdo_themes var layer2 = new OM.layer.VectorLayer("vLayer2", { def: {type:OM.layer.VectorLayer.TYPE_PREDEFINED, dataSource:"mvdemo", theme:"us_states_bi", url: baseURL,loadOnDemand: false },boundingTheme:true }); // add drop shadow effect and hover style var shadowFilter = new OM.visualfilter.DropShadow({opacity:0.5, color:"#000000", offset:6, radius:10}); var hoverStyle = new OM.style.Color( {stroke:"#838383", strokeThickness:2}); layer2.setHoverStyle(hoverStyle); layer2.setHoverVisualFilter(shadowFilter); layer2.enableFeatureHover(true); layer2.enableFeatureSelection(false); layer2.setLabelsVisible(true);// override predefined rendering style with programmatic one var theRenderingStyle = createBucketColorStyle('YlBr5', colorSeries, 'States5', true); // specify which attribute is used in determining the bucket (i.e. color) to use for the state // It can be an array because the style could be a chart type (pie/bar) // which requires multiple attribute columns // Use the STATE.TOTPOP column (aka attribute) value here layer2.setRenderingStyle(theRenderingStyle, ["TOTPOP"]); currentPalette = "YlBr5"; var stLayerIdx = map.addLayer(layer2); //alert('State Layer Idx = ' + stLayerIdx); map.setMapCenter(mpoint); map.setMapZoomLevel(mapZoom) ; // display the map map.init() ; statesLayer=layer2; // add rt-click event listener to show counties for the state layer2.addListener(OM.event.MouseEvent.MOUSE_RIGHT_CLICK,stateRtClick); } // end if } // end statesfunction setStyle(styleName) { // alert("Selected Style = " + styleName); // there may be a counties layer also displayed. // that wll have different bucket ranges so create // one style for states and one for counties var newRenderingStyle = null; if (layerName === "States") { if(/3/.test(styleName)) { newRenderingStyle = createBucketColorStyle(styleName, colorSeries, 'States3', false); currentStyle = createBucketColorStyle(styleName, colorSeries, 'Counties3', false); } else { newRenderingStyle = createBucketColorStyle(styleName, colorSeries, 'States5', false); currentStyle = createBucketColorStyle(styleName, colorSeries, 'Counties5', false); } statesLayer.setRenderingStyle(newRenderingStyle, ["TOTPOP"]);if (stateCountyLayer) stateCountyLayer.setRenderingStyle(currentStyle, ["TOTPOP"]); }} // end setStylefunction stateRtClick(evt){ var foi = evt.feature; //alert('Rt-Click on State: ' + foi.attributes['_label_'] + // ' with pop ' + foi.attributes['TOTPOP']); // display another layer with counties info // layer may change on each rt-click so create and add each time. var countyByState = null ; // the _label_ attribute of a feature in this case is the state abbreviation // we will use that to query and get the counties for a state var sqlText ="select totpop,geom32775 from counties_32775_moved where state_abrv="+ "'"+foi.getAttributeValue('_label_')+"'";// alert(sqlText); if (currentStyle === null) currentStyle = createBucketColorStyle('YlBr5', colorSeries, 'Counties5', false); /* try a simple style instead new OM.style.ColorStyle( { stroke: "#B8F4FF", fill: "#18E5F4", fillOpacity:0 } ); */ // remove existing layer if any if(stateCountyLayer) map.removeLayer(stateCountyLayer); countyByState = new OM.layer.VectorLayer("stCountyLayer", {def:{type:OM.layer.VectorLayer.TYPE_JDBC, dataSource:"mvdemo", sql:sqlText, url:baseURL}}); // url:baseURL},// renderingStyle:currentStyle}); countyByState.setVisible(true); // specify which attribute is used in determining the bucket (i.e. color) to use for the state countyByState.setRenderingStyle(currentStyle, ["TOTPOP"]); var ctLayerIdx = map.addLayer(countyByState); // alert('County Layer Idx = ' + ctLayerIdx); //map.addLayer(countyByState); stateCountyLayer = countyByState;} // end stateRtClickfunction useSelectedColorScheme(theColorScheme){ if(map) { // code to update renderStyle goes here //alert('will try to change render style'); setStyle(theColorScheme); } else { // do nothing }}</script></head><body bgcolor="#b4c5cc" style="height:100%;font-family:Arial,Helvetica,Verdana"><h3 align="center">State population thematic map </h3><div id="demo" style="position:absolute; left:68%; top:44px; width:28%; height:100%"><HR/><p/>Choose Color Scheme:<select id="demo-htmlselect"><option value="YlBl3">YellowBlue3</option><option value="YlBr3">YellowBrown3</option><option value="YlBl5">YellowBlue5</option><option value="YlBr5" selected="selected">YellowBrown5</option><option value="Blues5">Blues</option><option value="Greens5">Greens</option><option value="Greys5">Greys</option><option value="Oranges5">Oranges</option><option value="Purples5">Purples</option><option value="Reds5">Reds</option></select><p/></div><div id="map" style="position:absolute; left:10px; top:50px; width:65%; height:75%; background-color:#778f99"></div><div style="position:absolute;top:85%; left:10px;width:98%" class="noprint"><HR/><p> Note: This demo uses HTML5 Canvas and requires IE9+, Firefox 10+, or Chrome. No map will show up in IE8 or earlier.</p></div></body></html>

This post describes how to create a simple thematic map, just a state population layer, with no underlying map tile layer. The map shows states color-coded by total population. The map is interactive...

Another sample using the V2 API (but with json files)

In this example we'll show how to display content from a json file on a background map tile layer. So the interactive (vector layer) content is from a file (or datapack) rather a database instance. The sample application displays lines from USA (DC) to (capitals of) other countries color coded by the number of US visitors to that country in 2009, as shown in the screenshot below. The data is stored, and read, from a json file which looks something like: {"type": "FeatureCollection",  "collectionName": "theme0","srs": 8307,  "geodetic": true,  "bbox": [-180, -41.28054, 180,88.93291],  "attr_names": ["COUNTRY_CODE","COUNTRY","NUM_VISITORS"],  "attr_types": ["string","string","double"],  "features": [{"type": "Feature","_id": "MEX",                    "geometry": {"type": "LineString",                                      "coordinates": [-77.03201,38.88951,-77.21086,38.77556, ... ]},properties": {"COUNTRY_CODE": "MEX","COUNTRY": "MEXICO","NUM_VISITORS": "1945000"} }, ... The attr_name and attr_types is a extension of the geojson format used for Mapviewer specific reasons. Broadly speaking, the application code does the following: Sets up the client map object.Sets the url for the mapviewer instance and the resources (images for UI components) it needs.Adds a tile layer.Adds a country layer.Adds a layer for visitors from US to other countires (flows layer).Sets up the color scheme for the flows layer.Sets up the mouseover interaction and tooltips. The code is <!DOCTYPE html><html> <head> <title>Number of US visitors to abroad in 2009</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script src="/mvdemo/gv.js" type="text/javascript"></script> <script> document.write('<'+'script src="'+MV.gv.mapviewer_baseURL+ '/jslib/v2/oraclemapsv2.js"'+' type="text/javascript"><'+'/script>'); </script> <script language="JavaScript" type="text/javascript"> OM.gv.proxyEnabled =false; OM.gv.setResourcePath(MV.gv.mapviewer_baseURL+"/jslib/v2/images/"); var map = null; var flowsLayer = null; var countriesLayer = null; $(document).ready(function() { var baseURL = MV.gv.mapviewer_baseURL; var center = new OM.geometry.Point(20,30,8307); map = new OM.Map(document.getElementById('map'), {mapviewerURL: baseURL}) ; var tilelayer = new OM.layer.ElocationTileLayer("oracle.maps"); map.addLayer(tilelayer) ; countriesLayer = new OM.layer.VectorLayer("countries", { def:{ type:OM.layer.VectorLayer.TYPE_DATAPACK, url:"/mvdemo/datapacks/world_countries.json" } } ); var colorStyle = new OM.style.Color({"stroke":"#cc9999", strokeThickness:1, strokeOpacity:0.8}); countriesLayer.setRenderingStyle(colorStyle); countriesLayer.enableInfoWindow(false); countriesLayer.enableFeatureSelection(true); countriesLayer.setSelectStyle(new OM.style.Color( {fill:"#ff0000", fillOpacity:0.8,stroke:"#cc9999", strokeThickness:4, strokeOpacity:0.5})) map.addLayer(countriesLayer); flowsLayer = new OM.layer.VectorLayer("flows", { def:{ type:OM.layer.VectorLayer.TYPE_DATAPACK, url:"usa_visitors_geodetic.json" } }); flowsLayer.addListener(OM.event.MouseEvent.MOUSE_OUT, hideCountry); flowsLayer.addListener(OM.event.MouseEvent.MOUSE_OVER, showCountry); var hoverStyle = new OM.style.Color({fill:"#ffffff"}); flowsLayer.setBringToTopOnMouseOver(false); flowsLayer.setToolTipCustomizer(getTooltip); flowsLayer.enableInfoWindow(false); flowsLayer.enableFeatureHover(true); flowsLayer.setHoverStyle(hoverStyle); setupFlowStyles(flowsLayer); map.addLayer(flowsLayer); map.setMapCenter( center ); map.setMapZoomLevel(2) ; map.init() ; }); function getTooltip(feature) { return feature.getAttributes()["COUNTRY"]+", "+feature.getAttributes()["NUM_VISITORS"]; } function setupFlowStyles(layer) { var lines = []; var fillColors = // 10 color multihue sequential OrRd//['#FFF9F2','#FFF7EC','#FEE8C8','#FDD49E','#FDBB84','#FC8D59','#EF6548','#D7301F','#B30000','#7F0000']; // 10 color qualitative paired['#A6CEE3','#B2DF8A','#FB9A99','#FDBF6F','#CAB2D6','#FF7F00','#1F78B4','#6A3D9A','#E31A1C','#33A02C']; for(var i=0; i<10; i++) { var lineStyle = new OM.style.Line({fillWidth:6, fill:fillColors[i], strokeThickness:1, stroke:fillColors[i]}); lines[i] = lineStyle; } var bucketStyle = new OM.style.BucketStyle( { styles: lines, numClasses:10, classification:'logarithmic', defaultStyle: lines[0] }); layer.setRenderingStyle(bucketStyle, ["NUM_VISITORS"]); } function showCountry(evt) { var feature = evt.feature; var selectedFeature; var destFeature = countriesLayer.getFeature(feature.id); if (destFeature) { selectedFeature=countriesLayer.selectFeature(destFeature); //countriesLayer.bringForward(); document.getElementById("text").innerHTML = "# of visitors from USA to "+ feature.getAttributes()["COUNTRY"] + " = " + feature.getAttributes()["NUM_VISITORS"]; } } function hideCountry(evt) { var feature = evt.feature; var selectedFeature; var destFeature = countriesLayer.getFeature(feature.id); if (destFeature) { selectedFeature = countriesLayer.deselectFeature(destFeature); //countriesLayer.sendBackward(); } } </script> </head> <body> <DIV id="map" style="width:99%;height:94%"></DIV> <span id="text">Country: </span> </body></html> There are two vector layers. The flows layers is the number of visitors from the US while the countries layer (country boundary) is used to highlight the destination country on a mouse-over. Now let's go through various code snippets. The setResourcePath() method is used to tell the client lib where the images and icons, for the various UI components such as the navigation panel, can be found. After setting the initial map center and background tile layer (oracle.maps) we add the countries vector layer from a json file (OM.layer.VectorLayer.TYPE_DATAPACK). countriesLayer = new OM.layer.VectorLayer("countries", { def:{ type:OM.layer.VectorLayer.TYPE_DATAPACK, url:"/mvdemo/datapacks/world_countries.json" } } ); Then we set up it rendering (line) and selection (red color fill) styles. And similarly the flows layer, flowsLayer = new OM.layer.VectorLayer("flows", { def:{ type:OM.layer.VectorLayer.TYPE_DATAPACK, // json file is in same directory as the html (sample code) file url:"usa_visitors_geodetic.json" } }); with listener for mouse over and mouse out to handle the highlighting and updating the message area. flowsLayer.addListener(OM.event.MouseEvent.MOUSE_OUT, hideCountry); flowsLayer.addListener(OM.event.MouseEvent.MOUSE_OVER, showCountry); Next we set up the hover style, enable info-windows, and the advanced styles for the layer itself. The advanced style is defined and used in setupFlowStyles(flowsLayer) which defines 10 line styles of the specified colors, and then a bucket style using the line styles and a built-in classification scheme. function setupFlowStyles(layer) { var lines = []; // colors from colorbrewer2.org var fillColors = // 10 color multihue sequential OrRd//['#FFF9F2','#FFF7EC','#FEE8C8','#FDD49E','#FDBB84','#FC8D59','#EF6548','#D7301F','#B30000','#7F0000']; // 10 color qualitative paired['#A6CEE3','#B2DF8A','#FB9A99','#FDBF6F','#CAB2D6','#FF7F00','#1F78B4','#6A3D9A','#E31A1C','#33A02C']; for(var i=0; i<10; i++) { var lineStyle = new OM.style.Line({fillWidth:6, fill:fillColors[i], strokeThickness:1, stroke:fillColors[i]}); lines[i] = lineStyle; } var bucketStyle = new OM.style.BucketStyle( { styles: lines, numClasses:10, classification:'logarithmic', //built-in scheme defaultStyle: lines[0] }); layer.setRenderingStyle(bucketStyle, ["NUM_VISITORS"]); } The setRenderingStyle specifies the bucketStyle to use and the attribute column whose value determines the bucket or style for a given feature. Lastly, the event listeners showCountry and hideCountry highlight and de-highlight the destination country. The id attribute of a flowsLayer feature is the country code (e.g. "_id": "MEX") and this is also the id column in the countries layer. Since the feature itself is passed in to mouse-over event handler we can use its id to fetch, and highlight, the destination country from the countries layer. This is done in the showCountry() method function showCountry(evt) { var feature = evt.feature; var selectedFeature; var destFeature = countriesLayer.getFeature(feature.id); if (destFeature) { selectedFeature=countriesLayer.selectFeature(destFeature); //update the message area document.getElementById("text").innerHTML = "# of visitors from USA to " + feature.getAttributes()["COUNTRY"] + " = " + feature.getAttributes()["NUM_VISITORS"]; } }

In this example we'll show how to display content from a json file on a background map tile layer. So the interactive (vector layer) content is from a file (or datapack) rather a database instance. The...

A sample application using the V2 API

This entry describes a simple Oracle Maps V2 application which displays a predefined vector layer (aka theme) on a tile layer. The vector layer is called 'Customers' and the tile layer is named 'demo_map'.  The vector layer is based on a database table named CUSTOMERS and it's definition (in user_sdo_themes) is as follows: SQL> select base_table, geometry_column, styling_rules from user_sdo_themes  2  where name='CUSTOMERS';BASE_TABLE----------------------------------------------------------------GEOMETRY_COLUMN-------------------------------------------------------------------------------STYLING_RULES-------------------------------------------------------------------------------CUSTOMERSLOCATION<?xml version="1.0" standalone="yes"?><styling_rules key_column="NAME">  <hidden_info>    <field column="NAME" name="Name"/>    <field column="CITY" name="City"/>    <field column="SALES" name="Sales"/>    <field column="ACCOUNT_MGR" name="Account Manager"/>  </hidden_info>  <rule>    <features style="M.SMALL TRIANGLE"> </features>    <label column="NAME" style="T.RED STREET"> 1 </label>  </rule></styling_rules>  The above means that the predefined vector layer will select the name, city, sales, account_mgr, and location columns from the customers table and render the location using the marker style named "M.SMALL TRIANGLE" and label the locations (when possible) with the value of the NAME column using the text styles "T.RED STREET". The end result will look something like the screenshot below. The source code for the sample application is: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html><head><META http-equiv="Content-Type" content="text/html; charset=UTF-8"><TITLE>A sample Oracle Maps V2 application</TITLE><script language="Javascript" src="/mapviewer/jslib/v2/oraclemapsv2.js"></script><script language=javascript>var customersLayer=null;$(document).ready(function() { var baseURL = "http://"+document.location.host+"/mapviewer"; // Create an OM.Map instance to display the map var mapview = new OM.Map(document.getElementById("map"), { mapviewerURL:baseURL }); // Add a map tile layer as background. var tileLayer = new OM.layer.TileLayer( "baseMap", { dataSource:"mvdemo", tileLayer:"demo_map", tileServerURL:baseURL+"/mcserver" }); mapview.addLayer(tileLayer); // Set the initial map center and zoom level var mapCenterLon = -122.45; var mapCenterLat = 37.7706; var mapZoom = 4; var mpoint = new OM.geometry.Point(mapCenterLon,mapCenterLat,8307); mapview.setMapCenter(mpoint); mapview.setMapZoomLevel(mapZoom); // Add a theme-based FOI layer to display customers on the map customersLayer = new OM.layer.VectorLayer("customers", { def: { type:OM.layer.VectorLayer.TYPE_PREDEFINED, dataSource:"mvdemo", theme:"customers", url: baseURL, loadOnDemand: false } }); mapview.addLayer(customersLayer); // Add a navigation panel on the right side of the map var navigationPanelBar = new OM.control.NavigationPanelBar(); navigationPanelBar.setStyle({backgroundColor:"#FFFFFF",buttonColor:"#008000",size:12}); mapview.addMapDecoration(navigationPanelBar); // Add a scale bar var mapScaleBar = new OM.control.ScaleBar(); mapview.addMapDecoration(mapScaleBar); // Display the map. // Note: Change from V1. In V2 initialization and initial display is done just once mapview.init();});function setLayerVisible(checkBox){ // Show the customers vector layer if the check box is checked and // hide it otherwise. if(checkBox.checked) customersLayer.setVisible(true) ; else customersLayer.setVisible(false);}</script></head><body><h2>A Sample Oracle Maps V2 Application</h2><INPUT TYPE="checkbox" onclick="setLayerVisible(this)" checked/>Show customers<div id="map" style="width: 600px; height: 500px"></div> </body></html> The above code has an html portion and some javscript code which uses the Oracle Maps API. The html portion consists of a header, a checkbox to determine whether the customers layer is displayed or hidden, and a DIV 600 pixels in width and 500 pixels in height. The javascript code first loads the oraclemapsv2 library <script language="Javascript" src="/mapviewer/jslib/v2/oraclemapsv2.js"></script>  and since oraclemapsv2.js also includes and loads jquery (1.7.2) we can now use the jquery object (or its alias $) and its methods within our code. So we use the ready() method to specify the function, containing our OracleMaps code, to execute when the DOM is ready. The OracleMaps code must do the following: Create an OM.Map object and associate it with the HTML DIV where the map will be displayed.Create one or more tile layers (i.e. the background map)Set a map center and zoom levelOptionally, add one or more interactive vector layersOptionally, add some map controls and decorations such as a navigation panel and scale barInitialize and display the map The first step is done in the following code snippet: var baseURL = "http://"+document.location.host+"/mapviewer"; // Create an OM.Map instance to display the map var mapview = new OM.Map(document.getElementById("map"), { mapviewerURL:baseURL }); An OM.Map object needs to know where to display a map and which mapviewer instance will handle its requests. So there are two parameters, the "map" DIV and the mapviewerURL. The next step is to define the background map, or the tile layers. // Add a map tile layer as background. var tileLayer = new OM.layer.TileLayer( "baseMap", { dataSource:"mvdemo", tileLayer:"demo_map", tileServerURL:baseURL+"/mcserver" }); mapview.addLayer(tileLayer); A tile layer comes from a specified datasource, has a unique name, and is rendered by a specified mapviewer instance. Now we need to specify the initial map center and zoom level. // Set the initial map center and zoom level var mapCenterLon = -122.45; var mapCenterLat = 37.7706; var mapZoom = 4; var mpoint = new OM.geometry.Point(mapCenterLon,mapCenterLat,8307); mapview.setMapCenter(mpoint); mapview.setMapZoomLevel(mapZoom); The Point constructor takes a X, Y and an SRID. In this case it is 8307 which is the SRID for spatial reference system commonly used for GPS devices. SQL> select cs_name from cs_srs where srid=8307; CS_NAME--------------------------------------------------------------------------------Longitude / Latitude (WGS 84) Once that's done we add an interactive vector layer. // Add a vector(theme-based FOI) layer to display customers on the map customersLayer = new OM.layer.VectorLayer("customers", { def: { type:OM.layer.VectorLayer.TYPE_PREDEFINED, dataSource:"mvdemo", theme:"customers", url: baseURL, loadOnDemand: false } }); mapview.addLayer(customersLayer); Like a tile layer, a predefined vector layer comes from a specified datasource, has a unique name, and is rendered by a specified mapviewer instance. Next we add some map decorations and controls and finally initialize and display the map. // Add a navigation panel on the right side of the map var navigationPanelBar = new OM.control.NavigationPanelBar(); navigationPanelBar.setStyle({backgroundColor:"#FFFFFF",buttonColor:"#008000",size:12}); mapview.addMapDecoration(navigationPanelBar); // Add a scale bar var mapScaleBar = new OM.control.ScaleBar(); mapview.addMapDecoration(mapScaleBar); // Display the map. // Note: Change from V1. In V2 initialization and initial display is done just once mapview.init(); The last piece is the function which toggles the display of the Customers layer. function setLayerVisible(checkBox){ // Show the customers vector layer if the check box is checked and // hide it otherwise. if(checkBox.checked) customersLayer.setVisible(true) ; else customersLayer.setVisible(false);}

This entry describes a simple Oracle Maps V2 application which displays a predefined vector layer (aka theme) on a tile layer. The vector layer is called 'Customers' and the tile layer is named...

Intro to the V2 API

So what is the V2 API? Same as the V1 (oracle maps javascript) API but different :-) The key differences are:  Client side rendering of themes (or theme-based FOI) using SVG or html5 canvas. Themes are called vector layers in V2. FOI are called Features. A map tile layer is not required in order to display a vector layer (theme). That is, a layer (such as county_population_density) can be displayed just by itself and have specified (fixed) zoom levels without any background tile layer. In other words you can have interactive, zoom-able, thematic maps. A namespace (OM) and a different way of specifying parameters. (This is best explained by examples and will be done below) Support for json files as a data source, aka data packs. What then are the similarities? Well the same concepts (tile layers, themes, styles, styling rules), architecture, and content organization apply. They both depend on Oracle Spatial for spatial data management and analysis. And while one could define all styles and tile layer definitions dynamically, the ones defined via MapBuilder still work. The table below (from the user guide. Thanks Chuck) lists the correspondence between methods in V1 and V2. V1 API Class V2 API Class MVMapView OM.Map MVMapTileLayer, MVBingTileLayer, built-in tile layers OM.layer.TileLayer, OM.layer.BingTileLayer, ElocationTileLayer, NokiaTileLayer, OSMTileLayer MVCustomMapTileLayer Custom tile layers are not directly supported in the current release of V2. However, you can use custom tile layers by extending OM.layer.TileLayer and supplying a getTileURL callback function. MVThemeBasedFOI OM.layer.VectorLayer MVFOI OM.Feature MVSdoGeometry OM.geometry and its subclasses MVEvent OM.event and its subclasses MVInfoWindowTab OM.infowindow.MVInfoWindowTab Styles (MVStyleColor, MVXMLStyle, MVBucketStyle, MVBarChartStyle, and so on) OM.style and its subclasses Tools (MVToolbar, MVDistanceTool, MVCircleTool, and so on) OM.tool and its subclasses Decorations and controls (MVNavigationPanel, MVMapDecoration, MVScaleBar, and so on) OM.control and its subclasses  The V2 API has the following top-level classes and subpackages, all of which are in the namespace OM: The Map class is the main class of the API. The Feature class represents individual geo features (or FOIs as they were known in V1). The MapContext class a top-level class encapsulating some essential contextual information, such as the current map center point and zoom level. It is typically passed into event listeners. The control package contains all the map controls, such as navigation bar and overview map. The event package contains all the map and layer event classes. The filter package contains all the client-side filters (spatial or relational) for selecting, or subsetting, the displayed vector layer features. The geometry package contains various geometry classes. The layer package contains various tile and vector layer classes. The tile layer classes include access to a few online map services such as Oracle, Nokia, Bing, and OpenStreetMap. The vector layers are interactive feature layers and correspond to the MVThemeBasedFOI and MVFOI classes of V1. The infowindow package contains the customizable information windows and their styles. The style package contains styles applicable to vector data on the client side. It also includes visual effects such as animation, gradients, and drop shadows. The tool package contains various map tools such as for distance measuring, red-lining, and geometry drawing. The universe package contains built-in, or predefined, map universes. A map universe defines the bounding box and set of zoom level definitions for the map content. It is similar to a tile layer configuration in the V1 API. The util package contains various utility classes. The visualfilter package provides an interface for the various visual effects, such as gradients and drop shadows. OM.Map is the main entry class for all map operations inside the web browser. This and other classes provide interfaces for adding application-specific logic, operations, and interactivity in web mapping applications. In the next post we'll look at a simple example of using the V2 API.

So what is the V2 API? Same as the V1 (oracle maps javascript) API but different :-) The key differences are:  Client side rendering of themes (or theme-based FOI) using SVG or html5 canvas. Themes are...

Oracle

Integrated Cloud Applications & Platform Services