Web based GIS and domain model integration 3/10/2008, Pieter De Graef.

Post on 30-Dec-2015

212 views 0 download

transcript

Web based GIS and domain model integration3/10/2008, Pieter De Graef

What is GeoMajas ?

• GeoMajas is:– a Web Mapping framework– based on a Java server– and an AJAX/SVG/VML client– that supports editing of complex domain

objects and geometries– and much more…of course

Where to find GeoMajas ?

• http://www.geomajas.org/ – Check out the source code– Build using Maven– Import projects into Eclipse– Run on your favorite servlet engine

Getting started

• Start up eclipse• Open the project majas-foss4g• Open the folder:

majas-foss4g/src/main/webapp/applications/workshop• The Ant build file build.xml contains targets for the 5 exercises

of this workshop• Run the target exercise1: dojo• Refresh the project majas-foss4g and start the server • Open your Web browser and enter the following URL:

http://localhost:8180/majas-foss4g/applications/dojo/html/index.html

Exercise 1: the Dojo widget system• The following

layout appears:

Exercise 1: the Dojo widget system

• The Dojo widget system offers the following functionality:– Different types of layout containers: ContentPane, SplitContainer,

AccordeonContainer, TabContainer– Different types of widgets: textfield, checkbox, combobox,

colorpalette, spinner, calendar, radionbutton, tree,… – General event handling mechanism:

dojo.connect(source,event,target,function);– Widget hierarchy:

dojo.declare("myWidget", [dijit._Widget, dijit._Templated, dijit._Container], {templatePath : "path/to/HTML/template"  postCreate : function () {…}

}

(widgets use HTML templates for their definition)

Exercise 1: todos

• Open the page html/index.html• There are 2 TODOs indicated in the page:

1. Log the id in the closure function by using the built-in log facility:log.info(id);

2. Highlight the widget by changing a style attribute:dijit.byId(id).domNode.style.backgroundColor="blue";

• Reopen the page in the browser and click on each widget to see the result

Exercise 2: Helloworld map

• The purpose of this exercise is to demonstrate elementary Majas configuration concepts

• Serious warning: after running a target for an exercise, your own writings for the previous exercises will be replaced with the solution of those exercises!

• Select the file applications/workshop/build.xml again, and run the target: exercise2: helloworld

• Then refresh the majas-foss4g project.

Exercise 2: configuration basics

• All configuration is done via XML files• Full schema validation, schemas are

available at … • Uses JAXB for generating configuration code• Uses XInclude to split up the configuration

over multiple files• Configuration changes require a restart !

Exercise 2 : application.xml

• Contains factory classes for raster and vector layers

• Refers to the other configuration files: – layerTree.xml : configuration of layer tree widget– maps.xml : configuration of map widgets– toolbar.xml : configuration of toolbar widgets– tools.xml : configuration of available tools and

actions

Exercise 2 : adding a raster layer factory

• Go to directory applications/helloworld• Open the file application.xml• Insert the following snippet:

<rasterLayerFactory id="osm"><factoryClass>OSMLayerFactory</factoryClass><parameterMap />

</rasterLayerFactory>

• factoryClass: java class name, must implement LayerFactory interface and create RasterLayer implementation

• parameterMap: a list of parameters to be passed to the factory constructor (none in this case)

Exercise 2 : overview of available raster layer factories

• GoogleLayerFactory : – Google Maps API layer– type (normal, satellite,…) determined by layer name (see further)– Needs the google maps script and key !– Spherical Mercator projection (EPSG:900913)

• OSMLayerFactory : – OpenStreetMap tile layer– http://tile.openstreetmap.org/<level>/<x>/<y>.png– Spherical Mercator projection (EPSG:900913)

• WMSLayerFactory : – Generic OGC WMS layer– <parameter name="baseWMSurl" value="<URL of the WMS server>" />– <parameter name="format" value="<format parameter>" />– <parameter name="version" value ="<version parameter>" />– <parameter name="srs" value ="<SRS parameter>" />

Exercise 2: maps.xml

• Contains the configuration of each map used by this application (usually a main and an overview map)

• Configurable parts:– Layers of the map– Layer z-order in the map– Layer order in the layer tree– Background-color, pan-buttons, scale widget– Selection styles for each geometry type (vector layers)– Coordinate Reference System (may be different from layer’s CRS !)– Maximum scale– Initial bounds– Discrete map resolutions (optional)– Overview map reference (optional, if overview map)

Exercise 2 : adding a map

• Open the file applications/helloworld/maps.xml

• Perform the following steps:– Choose a background color– Choose whether you want pan buttons and/or a

scalebar– Pick your initial bounds, see next slide !– Have a look at the layer configuration

Exercise 2 : adding a map

(0,0)

(20 037 508.34, 0)

(0,20 037 508.34)

(-20 037 508.34, 0)

(0,-20 037 508.34)

Spherical Mercator coordinates (m)

x

y

Exercise 2: adding a raster layer

• Open the file layers/osm.xml• Perform the following steps:

– Choose a display name– Add the id of the correct raster layer factory– Pick an opacity level (opacity is inverse of transparency)

• How are the resolutions calculated?– Resolution (m/pixel) is inverse of scale (pixel/m)– Tile is 256 by 256 pixels– There are 2n tiles per level, level 0 has 1 tile: the world– <distance>/<number of pixels> = (2*20037508.34)/(256*2n)

for n=0 to 17

Exercise 2: making the first HTML page ready

• Open the page helloworld/html/index.html• Uncomment the load code:

– By using dojo.addOnLoad() one can execute some custom JavaScript after the dojo widgets are loaded

– In GeoMajas, we use this to load the map configuration from the server

• Add the correct Dojo type to the map– dojoType="geomajas.widget.MapWidget"– This turns the <div> into a GeoMajas map widget

Exercise 2: have a look at your map!

• Restart your server, open your browser and go to:

• http://localhost:8180/majas-foss4g/applications/helloworld/html/

Exercise 2: tips and tricks

• You can drag the map to pan (slippy map)• You can use the mouse scroller to zoom in and out• Optional: If you uncomment the <resolutions> tag in

maps.xml and restart the server:– the zoom function will now snap to the resolutions in the list,

which are these of the tiles– The tile images will not be resized, so they should be crystal

clear!

Exercise 2: adding a toolbar

• GeoMajas has 2 styles of toolbar buttons:– Tools:

• Can be selected/deselected by clicking• Selection will normally put the map in a certain mode by

adding a specific controller to the map, deselection will remove it

• A controller interprets mouse operations in a specific way by e.g. drawing a rectangle and zooming on release

– Actions:• Can be invoked by clicking• An action can be almost anything, but usually also

involves sending a command to the server– Each action or tool has an image and a tooltip

Exercise 2: predefined actions/tools

ZoomIn Zoom in with a factor

ZoomOut Zoom out with a factor

ZoomPrevious Zoom to previous extent

ZoomNext Zoom to next extent

ZoomToSelection Zoom to selected objects

PanToSelection Pan to selected objects

EditSelected Edit selected objects

FetchPdf Fetch a PDF print of the map

Predefined actions

Exercise 2: predefined actions/tools

ZoomInMode Zoom in with a factor

ZoomOutMode Zoom out with a factor

ZoomToRectangleMode Zoom by drawing a rectangle

PanMode Pan the map by dragging

NavigateMode Recenter the map by clicking

MeasureDistanceMode Measure distance with a ruler

SelectionMode Select objects by clicking

DeselectAllMode Deselect all objects

EditMode Edit a geometry

SplitPolygonMode Split a polygon

MergePolygonMode Merge 2 polygons

FeatureInfoMode Fetch a PDF print of the map

Predefined tools

Exercise 2: adding a toolbar

• Open the file helloworld/toolbar.xml• Add one or more toolRef tags after the toolbar

separator, one for each tool• Open helloworld/html/index.html, and set the

dojoType for the toolbar: "geomajas.widget.DynamicToolbar"

• Restart the server and navigate to http://localhost:8180/majas-foss4g/applications/helloworld/html/

• Play around with the tools and actions

Exercise 2: adding an overview map

• Open the file helloworld/maps.xml• Copy the map declaration and:

– Rename the id to helloOverviewMap– Put the id of the main map inside the overview tag:

<overview>helloMap</overview>– Choose a large enough initial bounds area

• Restart the server and navigate to http://localhost:8180/majas-foss4g/applications/helloworld/html/

• See how the main map follows if you drag the blue rectangle!

Exercise 3: Simple vector map

• The purpose of this exercise is to demonstrate the vector layer capabilities of GeoMajas

• We will also demonstrate some extra widgets:– LayerTree widget– Legend widget– FeatureListTable widget– SearchTable widget– Style widgets

• Open the file applications/workshop/build.xml• First we run the target exercise3: simplevectors• Refresh the majas-foss4g project!• Go to applications/simplevectors

Exercise 3 : adding a vector layer model factory

• Open the file simplevectors/application.xml• Insert the following snippet:<layerModelFactory id="worldShape">

<factoryClass>ShapeInMemLayerModelFactory</factoryClass>

<parameterMap>

<parameter name="url" value="file:shapes/countries_world/world_adm0.shp" />

</parameterMap>

</layerModelFactory>

• factoryClass: java class name, must implement LayerFactory interface and create VectorLayer implementation

• parameterMap: a list of parameters to be passed to the factory constructor (none in this case)

Exercise 3: overview of available layer model factories

• GeotoolsLayerModelFactory: – wraps a Geotools datastore– parameters are the same as for the datastore (see geotools doc)

• HibernateLayerModelFactory: – uses hibernate to map a layer of POJO objects to a geodatabase– no parameters, configuration read from standard hibernate.cfg.xml

• ShapeInMemLayerModelFactory: – an in-memory layer model, initially based on a shape file– <parameter name="url" value="file:shapes/world/world.shp" /> – (the url path is relative to application.xml folder in this case)

• WKTLayerModelFactory: – layer model based on a WKT (Well-known-Text) text file– no parameters

• MaxCoordSimplifierLayerModelFactory:– wraps an existing factory and simplifies its geometries– <parameter name="delegate-factory" value="ShapeInMemLayerModelFactory" />– <parameter name="url" value="file:shapes/world/world.shp" />– <parameter name="distance-tolerance" value="0.01" />– <parameter name="maximum-coordinates" value="1000" />

Exercise 3: adding a layer tree

• Now open simplevectors/maps.xml• What we have to do here, is to add the new world

shapefile to the layerconfiguration.– Include the layers/countries_world.xml (layer config)– Include the layer in the mapOrder– Include the layer in the LayerTree order

• To find the ID of the world layer, open it’s XML configuration file: layers/countries_world.xml

Exercise 3: adding a layer tree

• Open the file simplevectors/html/index.html– Add the layer tree to the page by adding the correct

dojoType ("geomajas.widget.LayerTree")

• Restart the server and navigate to: http://localhost:8180/majas-foss4g/applications/simplevectors/html/index.html

Exercise 3:

visibility

labeling

zoom to South-Africa to see some featuresand test new toolbar buttons !

Exercise 3: adding a legend

• The legend widget will show a symbol for all the styles of all the visible vectorlayers

• Open the file simplevectors/html/index.html– Add the legend underneath the layer tree with the indicated width

and heigth– Put the following code snippet in the postConfiguration() function to

connect the legend to its map:var legend = dijit.byId("mainLegend");var mapWidget = dijit.byId("mainMap");legend.setMapModel(mapWidget.getMapModel());

– Remark: the postConfiguration() can be used to execute some JavaScript after the GeoMajas configuration!

• Refresh the browser page: http://localhost:8180/majas-foss4g/applications/simplevectors/html/index.html

Exercise 3: adding a legend

Exercise 3: styles and filtering

• Open the file layers/countries_world.xml• The styles are defined at the bottom, in the <styleDef> tag

• For each style, there is:– The name that will appear in the legend– The filter formula to determine on which features the style

should be applied– The style parameters: fill color, fill opacity, stroke color,

stroke opacity and stroke width

• Change the style definition for south africa, restart the server and see how it looks !

Exercise 3: styles and tables

• Navigate to: http://localhost:8180/majas-foss4g/applications/simplevectors/html/more.html

• Notice the layout has changed completely• At the bottom you will see 2 tabs. One empty and one

containing a FontStyleWidget.– The font style widget can be used to change the style of the

labeling– Turn on the labels for Africa, and fool around with the style.

Exercise 3: Adjusting layer tree

• What still needs to be done, is to determine the tools and actions for the selected layer that are shown at the top:

Exercise 3: predefined actions/tools for the layer tree

• Actions– ShowTableAction : shows a featurelist table– RefreshLayerAction : refreshes the layer

• Tools– LayerVisibleTool : makes the layer visible/invisible– LayerLabeledTool : shows/hides labels of features– LayerSnappableTool : makes features snappable

or not

Exercise 3: predefined actions/tools for the layer tree

• Open the simplevectors/layertree.xml

• Add a tool action to the list:– ShowTableAction

Exercise 3: adding a feature list table

• Open the file simplevectors/html/more.html• Add the feature list table by inserting the following

piece of xml:<div id="mainTable" dojoType="geomajas.widget.FeatureListTable" supportEditing=false style="width: 100%; height: 100%; border: 0px solid #888;"></div>

• Restart the server and navigate to http://localhost:8180/majas-foss4g/applications/simplevectors/html/more.html

Exercise 4: OpenStreetMap and complex domain modeling

• The purpose of this exercise is to demonstrate complex domain modelling with GeoMajas

• An OpenStreetMap dataset has been copied to your local PostGIS database to serve as a simple domain model

• In this exercise you will work on the Java mapping via HibernateSpatial to set up an editable map

• First we run the target exercise4: osm• Refresh the majas-foss4g project.

Exercise 4: GeoMajas complex domain modeling

• Starts from annotated Java classes and database schema

• Uses Hibernate(Spatial) to manage the O/R mapping• Has support for many-to-one, one-to-many, many-to-

many relationships• Uses metadata FeatureModel for feature access, e.g.

translating back-and-forth to JSON– Primitive attributes– Association attributes

Exercise 4: Open StreetMap data model (subset)

Node =

Way =

k="oneway" v="yes“k="created_by" v="Potlatch 0.8c“…

+ set of tags

+ set of tagsor

Exercise 4: OSM database schemacd Schema1

node_tags

column*PK id: integer = nextval('node_t...*FK node_id: integer* tag_key: varchar(255)* tag_value: varchar(255)

PK

+ pk_node_tags(integer)

index

+ pk_node_tag(integer)

FK

+ fk_node_tag_node(integer)

nodes

column*PK id: integer = nextval('nodes_...* osm_id: integer* creation_time: *FK user_id: integer geom:

PK

+ pk_nodes(integer)

index

+ pk_node(integer)+ nodes_geometry_gist()

check

+ enforce_srid_geom()+ enforce_dims_geom()+ enforce_geotype_geom()

FK

+ fk_node_user(integer)

users

column*PK id: integer = nextval('users_...* name: varchar(255)

way_tags

column*PK id: integer = nextval('way_ta...*FK way_id: integer* tag_key: varchar(255)* tag_value: varchar(255)

PK

+ pk_way_tags(integer)

index

+ pk_way_tag(integer)

FK

+ fk_way_tag_way(integer)

ways

column*PK id: integer = nextval('ways_i...* osm_id: integer* creation_time: *FK user_id: integer geom:

PK

+ pk_ways(integer)

index

+ pk_way(integer)+ ways_geometry_gist()

check

+ enforce_srid_geom()+ enforce_dims_geom()+ enforce_geotype_geom()

FK

+ fk_way_user(integer)

+fk_node_tag_node 0..*

(node_id = id)

+pk_nodes 1

+fk_node_user

0..*

(user_id = id)

+pk_users

1

+fk_way_tag_way 0..*

(way_id = id)

+pk_ways 1

+fk_way_user

0..*

(user_id = id)

+pk_users

1

one-to-many

many-to-one

Exercise 4: OSM Java classes

• Many-to-One association:@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE })@JoinColumn(name = "user_id")private User user;

– @join-column: refers to foreign key column– cascade: determines what happens if the many-

side is persisted: in this case the user will be added too if he/she is new (PERSIST) or updated if he/she already existed but has some properties changed, e.g. the name (MERGE)

Exercise 4: OSM Java classes

• One-to-Many association:@OneToMany(mappedBy = "way", fetch = FetchType.EAGER, cascade={CascadeType.ALL})@org.hibernate.annotations.Cascade(value = {

org.hibernate.annotations.CascadeType.ALL,org.hibernate.annotations.CascadeType.DELETE_ORPHAN })

private List<WayTag> tags = new ArrayList<WayTag>();

• mappedBy : makes the many-side responsible for mapping the relationship

• fetch : determines fetch type, EAGER means fetch immediately• cascade : determines what happens if the one-side is persisted:

in this case new tags will be added, updated tags will be updated (ALL) and missing (orphaned) tags will be deleted (DELETE_ORPHAN)

Exercise 4: Add an attribute

• Open osm/layers/ways.xml• Add the timestamp attribute to the list:

<attribute>

<label>Creation Date</label>

<name>timestamp</name>

<editable>true</editable>

<identifying>true</identifying>

<type>date</type>

</attribute>

Exercise 4: OSM editing

• Restart the server and navigate to http://localhost:8180/majas-foss4g/applications/osm/html/index.html

• Open the featurelist table by selecting the Ways layer and clicking on the table icon

• Double-click on a row of the table to open the editing dialog

• Edit different types of data:– Timestamp property : date primitive– User property : many-to-one– Tags property : one-to-many

Exercise 4: OSM editing

Exercise 4: Add constraints

• Open osm/layers/ways.xml• Find the timestamp attribute in the attribute list, and

add a validator after the <type>-tag:

<validator><constraints>{min:'2004-01-01', max:'2008-12-31'}</constraints><required>true</required><promptMessage>Creation date.</promptMessage><invalidMessage>The required date format is "dd/MM/yyyy".</invalidMessage><rangeMessage>Range: between 01/01/2004 and 31/12/2008.</rangeMessage>

</validator>

Exercise 4: Constraint test

• Restart the server and navigate to http://localhost:8180/majas-foss4g/applications/osm/html/index.html

• Open the featurelist table by selecting the Ways layer and clicking on the table icon

• Double-click on a row of the table to open the editing dialog

• Try to fool around with the date

Exercise 5: Creating buffers

• How to create and display a buffer around a selection of lines.

• This problem can be subdivided into many smaller problems:

1. How to get the selected features, and more importantly, their geometries?

2. Since buffer calculation is very heavy, how can we let the server do this for us?

3. How can we show the resulting geometry on the map?

Exercise 5: Creating buffers

• Starting point: a layer with lines:• Line-layer: Streets of Washington• layerType = 3 (LineString)• Run target exercise5: advanced• Refresh the majas-foss4g project.• Location:

http://localhost:8080/majas-foss4g/applications/advanced/html/index.html

Exercise 5: Creating buffers

• Todo:– Look for selection. If there is no selection in the linelayer, return

an error message.

– If there are streets selected, calculate a buffer around them.

– Problem: calculating a buffer around multiple lines, will require us to make a union first and then calculate the buffer. This is too heavy a calculation to be done in Javascript. We must let the server calculate this!

– So we need communication between client and server.

– Last but not least the result must be rendered. Problem: the streets were stored in lonlat. So we receive a lonlat geometry as buffer on the client => we must first transform this to screenspace!

Exercise 5: Creating buffers

• When the exercise starts, you can see 2 buttons and a textbox at the bottom:

• Press the « Create Buffer » button and see what happens.

• A rectangle is drawn! This has nothing to do with current selection.

Exercise 5: Creating buffers

• Open advanced/html/index.html• When looking at the code, we see:

// Execute the command for buffer calculation:

var command = new JsonCommand("org.geomajas.foss4g.command.CreateBufferCommand", null, false);

command.addParam("distance", distance);

command.addParam("streets", selStreets);

var deferred = majasConfig["dispatcher"].execute(command);

deferred.addCallback(bufferCallback);

• This executes the CreateBufferCommand

Exercise 5: Creating buffers

• How a command works:• We must fill in the exact Java classname!• Add params, with names for which setters

can be found in the Javaclass. Example:• addParam(‘distance’) results on the server

in the setter ‘setDistance’.• Last line connects a callback function that

will handle the command’s result.

Exercise 5: Creating buffers

• Open the CreateBufferCommand in Java Resources (src/main/java) ("org.geomajas.foss4g.command.CreateBufferCommand")

• Look at the required fields:private LineString[] streets;private float distance;

• Apparently we need to pass the buffer distance as a float, and an array of LineString objects. (the selected streets)

• Next take a look at the «execute» function.

Exercise 5: Creating buffers

• We see the part that writes out the rectangle:// TODO: Temporary buffer, a rectangle - Remove this:

GeometryFactory factory = new GeometryFactory();

LinearRing shell = factory.createLinearRing(new Coordinate[] {

new Coordinate(100, 100), new Coordinate(400, 100),

new Coordinate(400, 300), new Coordinate(100, 300),

new Coordinate(100, 100) });

temp = factory.createPolygon(shell, null);

// Remove until here.

• Since this is not correct, we should replace it with the loop above it:

Exercise 5: Creating buffersfor (int i = 0; i < streets.length; i++) {

LineString street = streets[i];if (temp == null) {

temp = street;} else {

temp = temp.union(street);}

}

• What this does, is create the union of all the LineStrings that have reached the server.

• Restart the server, and check again.http://localhost:8080/majas-foss4g/applications/advanced/html/index.html

Exercise 5: Creating buffers

• We create a buffer again:

• An empty array? Let’s see the Javascript again! An empty array?

• Indeed command.addParam("streets", selStreets); sends an empty array. We need to find the selection!

Exercise 5: Creating buffers

• Check if there actually is a selection:• Find this line:

// TODO: check if there actualy is a selection!

• And replace it with:var streetLayer = mapWidget.getMapModel().getLayerById("mainMap.streets");

if (streetLayer.getSelectionStore().getElementCount() == 0) {

alert("There are no streets selected!");

return;

}

Exercise 5: Creating buffers

• Now fill the array with the geometries belonging to the selected features:

• Find this line:// TODO: fill the "selStreets" array with LineStrings.

• And replace it with:var selected = streetLayer.getSelectionStore().getElements(); var keys = selected.getKeyList();for (var i=0; i<keys.length; i++) {

var street = selected.item(keys[i]);selStreets.push(street.getGeometry());

}

• Selected is a dictionary, with the feature’s ID as key.

Exercise 5: Creating buffers

• If we now check again, we should see the buffer right?

• Wrong! Something is still missing. What?

Exercise 5: Creating buffers

• Transformation from world to view!• Find the following line:

// TODO: Something is missing here!

• And replace it with:var transformer = new

WorldViewTransformation(mapWidget.getMapView());

geometry = transformer.worldGeometryToView(geometry);

• Let’s try again!http://localhost:8080/majas-foss4g/applications/advanced/html/index.html

The end!

• Thank you for your attention!• Visit us at http://www.geomajas.org/