Friday Nov 08, 2013

Latest MapViewer 11g patch released

Hi,

  We are glad to announce that the latest MapViewer 11g patch (version 11.1.1.7.2) has just been uploaded to OTN in the usual place. This is mostly a bug fix release, with several noticeable enhancements to the HTML5 API. For the full release note, please check it here:

 http://download.oracle.com/otndocs/products/mapviewer/mapviewer_11p6_2_readme.txt

In a related note, our hosted mapping service (elocation.oracle.com) has also updated its MapViewer server to this release.

Finally, the public demo server running all the standard mapViewer demos have been patched to 11.1.1.7.2 as well. So make sure to give the demos a spin!

http://slc02okf.oracle.com    :  show cases some of the main HTML5 mapping demos

http://slc02okf.oracle.com/mvdemo : the MapViewer Samples & Demos Application.

 Thanks

LJ 

Monday Oct 14, 2013

Updating the mapviewer in the quickstart kit

More than two (:-)) folks asked this question recently so it might worth a short note. The question is how does one deploy a new mapviewer version (e.g. 11.1.1.7.1) into the quickstart kit (which has 11.1.1.7.0)? A manual process is the simplest.

Shutdown the glassfish server if it's running.

Make a copy of the existing mapviewer.war directory and rename it (e.g. mapviewer.war.111170).

Delete the contents of the mapviewer.war directory (or create one named mapviewer.war if you just renamed, without copying, the old one).

Extract the contents of web.war in the new mapviewer.ear into the mapviewer.war directory.

Modify the mapviewerconfig.xml file so that it has the same map_data_source and other entries as the original one had.

If you're replacing 11.1.1.7.0 with 11.1.1.7.1 then you also have to edit the mds.xml (same location as mapviewerconfig.xml) to allow for the streaming of predefined and dynamic themes to the html5 client by the map data serevr. This change (data server streaming disabled by default) is new in 11.1.1.7.1.

Restart glassfish.

Monday Sep 02, 2013

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 tile storage, and file naming conventions, for map tile layers created with FMW MapViewer. The tiles are stored in a directory structure based on the data source name, map tile layer name, number of zoom levels, and tile mesh codes.

Tile Mesh Code and File Storage Structure

Each map tile layer is in 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 tile layer demo_map is in the datasource is mvdemo, then the tiles will be under /private/tilestore/MVDEMO.DEMO_MAP. The first level of subdirectories contains one directory per zoom level. So if there are 19 zoom levels then the subdirectories will be named 0 through 18. Each zoom level directory will contain tile (files) or directories. That is, tiles are stored in a tree-like directory structure with leaf nodes contain only tile image files. Non-leaf nodes contain only directories. Mesh codes are used in naming these subdirectories and tiles.

Tile Mesh Code

A tile mesh code is represented 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 for the 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 tile images that zoom level contains.

For a tile with mesh code 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_MAP tile 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 and are may change between releases. So the following description of how mesh codes are generated may not be valid in future releases.

The mesh code is computed from a tile index. The tile index (X,Y) is computed in the Oracle maps client code 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.

Directory Tree Depth (Mesh Code Length)

When the number of tile images is small for a given zoom level, all tiles may be stored in its root directory. When the number gets to millions or even larger, at higher zoom levels, they are stored in subdirectories for more efficient file retrieval.

The expected number of tiles for a given zoom level is calculated using:

maxMeshCodeX = coordinateSystem.width/tileWidth;

maxMeshCodeY = coordinateSystem.height/tileHeight;

total_tiles = maxMeshCodeX*maxMeshCodeY;

A TILING_FACTOR determines the depth of the directory tree for a given zoom level. The default value of 20 means there will be no more than 400 (20 x 20) sub-directories or tile images stored at any zoom level. The mesh code length for X equals the base-20 (or base TILING_FACTOR) logarithm of maxMeshCodeX.

Examples of converting a tile index (x,y) to Mesh Code

1) Given that 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) If the TILING_FACTOR is changed to 10, the mesh code length becomes 5. Keeping the zoom 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

Wednesday Aug 28, 2013

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:

mvdemo 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.

Thanks

LJ 

Tuesday Aug 20, 2013

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 files
C:\Program Files\GDAL>ogrinfo --formats
Supported 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.







Friday Jul 26, 2013

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 in
http://docs.oracle.com/cd/E16655_01/appdev.121/e17896/sdo_cs_concepts.htm#CIHJFBFG (Spatial), and
http://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.31

SQL>

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 8307
call 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    19847

EPSG No-Op (EPSG OP 1000000000)   1000000000

Each 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
             14231

NAD83 / North Carolina                      6269             4269
             13230

SQL>

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 1980
twork)
        6378137

North American Datum 1983        GRS 1980
        6378137

They 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)
      13230

SPCS83 Texas North zone (meters) (EPSG OP 14231)
      14231

When 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)
----------
         0
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
--------------------------------------------------------------------------------
Amarillo
SDO_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, NC
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_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
--------------------------------------------------------------------------------
Raleigh
SDO_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@sdolnx2
Enter 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 op
SQL> 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@sdolnx2
Enter 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       32119

Now 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
--------------------------------------------------------------------------------
Amarillo
SDO_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
--------------------------------------------------------------------------------
Raleigh
SDO_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.4


Add 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 4326
SQL> 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),3
785) 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
--------------------------------------------------------------------------------
London
SDO_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_3857
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
--------------------------------------------------------------------------------
GEOM_BNG_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA
--------------------------------------------------------------------------------
London
SDO_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)                  4230

7 rows selected.

We'll use coord_op_id 1195

call 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_3857
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
--------------------------------------------------------------------------------
GEOM_BNG_3857(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINA
--------------------------------------------------------------------------------
London
SDO_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. 

Monday Jul 22, 2013

Limitations in client side styles (for Vector Layers/FOI) in the V2 API

The V2 API (in MapViewer versions 11.1.1.7.0 and 11.1.1.7.1) currently has some limitations in styles that can be used for vector layers (aka FOI). That is, some styles which can be defined in MapBuilder and used for FOI with the V1 API cannot be used for vector layers in V2.

The current limitations are:

LINE styles in v2 have these limitations:
   1. no dash support (on any part of the line style)
   2. no marker-pattern or built-in arrow head on LINE style

AREA styles that use image as fill pattern: not supported 

TEXT styles:  some labeling hints are not supported, such as sticky, multi-line auto-wrap

DOT density style: not supported in v2



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) are

MapViewer 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:
Property
url  jdbc:oracle:thin:@mydbinstance:1522/pdborcl12c.rest_of.service.name

Uncheck 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

Monday Jul 01, 2013

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

function jenksFromGeostats(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'
    };



Wednesday Jun 26, 2013

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.

Screenshot of US state population thematic map


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 mapviewer
OM.gv.proxyEnabled =false;			// no mvproxy needed
OM.gv.setResourcePath(baseURL+"/jslib/v2/images/");  // location of resources for UI elements like nav panel buttons
var map = null;											 // the client mapviewer object 
var statesLayer = null, stateCountyLayer = null;		 // The vector layers for states and counties in a state
var layerName="States";
// initial map center and zoom
var 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 initMap

function 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 states

function 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 setStyle

function 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 stateRtClick

function 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>


Wednesday Jun 19, 2013

Upcoming MapViewer webinar (on V2/html5 API) June 27th 11AM ET

This is a repeat of LJ's Spatial User conference session on MapViewer application development. Will cover the following:

- Intro to the HTML5 API

- Templates

If you're interested contact us via email or this blog

Monday Jun 10, 2013

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"];
        }              
      }



MapViewer 11.1.1.7.1 new config settings for vector layers

In 11.1.1.7.1 the data server which sends vector layers (theme-based FOI) to the client is restricted by default. The config file mds.xml (located in the same directory as mapviewerConfig.xml) has to be updated to allow the data server to access and serve up layers from desired data sources.

The relevant readme.txt entry is

- Map Data Server (MDS), the vector theme streaming server of MapViewer, is now in 
  lock-down mode by default and will not allow themes to be streamed to a client unless 
  explicitly configured otherwise. You will need to manually edit the 
  WEB-INF/conf/mds.xml file to control which data sources and which themes can be 
  streamed to a HTML5 application client. 
  A MapViewer restart is required for the changes to take effect.

OBIEE 11.1.1.7 MapViewer error when previewing tile layers

In OBIEE 11.1.1.7 (with MapViewer 11.1.1.7 deployed in Weblogic) you may see an 500 - internal server error when previewing map tile layers in the MapViewer manage map tile layers admin page.

If so you need to modify the web.xml as described in the readme.

On certain WLS domains (mostly when ADF run-time library is deployed), you
  may see errors when trying to preview tile layers. To fix this issue, modify
the weblogic.xml descriptor file found in mapviewer.ear's WEB-INF/ folder, and
uncomment the entry for the jstl 1.2 library as shown below (note the jsf
section should remain commented-out):

<library-ref>
    <library-name>jstl</library-name>
    <specification-version>1.2</specification-version>
  </library-ref>

<!--
<library-ref>
    <library-name>jsf</library-name>
    <specification-version>2.0</specification-version>
    <exact-match>false</exact-match>
</library-ref>
-->

If you upgraded obiee from a previous 11.1.1.x release you may see this error anytime you access the mapviewer admin pages. The fix is to redeploy mapviewer.


Thursday Jun 06, 2013

A live MapViewer instance with HTML5 demos and tutorials

Hi,

  You can now access a public MapViewer 11.1.1.7.1 server and the companion Samples App using the latest MVDEMO sample data set here:

 A few notable links:

 

You can also find online Java and JS API docs under the sample  app (http://slc02okf.oracle.com/mvdemo) and many other demos.

Thanks

LJ 


 

About

Official blog for Oracle FMW MapViewer and related products.

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today