Mastering OpenLayers 3 - Sample Chapter
Mastering OpenLayers 3 - Sample Chapter
ee
$ 49.99 US
31.99 UK
P U B L I S H I N G
D i s t i l l e d
E x p e r i e n c e
Mastering OpenLayers 3
Gbor Farkas
C o m m u n i t y
pl
Mastering OpenLayers 3
Mastering OpenLayers 3
Sa
m
Gbor Farkas
Preface
As in every other computer-related field, the Web has also become a determining
factor in GIS. In this new trend, with some client-based knowledge, we can easily
publish our maps and layers on the Web. However, as technology rapidly develops,
we can now perform some more serious GIS-related work on the Web as well.
With enough browser capabilities and client-side computational power, an even
newer trend has emerged from the Web-based GIS world: WebGIS. This new trend
researches the possibilities of deploying powerful GIS applications on the Web,
making the most general workflows of a spatial analyst possible on a browser in a
platform-independent manner.
Thanks to OSGEO, OGC, and other initiatives, companies, individuals, and the
open source philosophy have made a quick and great impact on this brand new
field. Consequently, there is a wide palette of open source applications and libraries
to work with and build upon. One of the most original and robust web mapping
projects is OpenLayers. This library debuted a brand new, cutting-edge technology
with a major version change. OpenLayers 3 is capable of things that we could not
even imagine a few years ago.
An unplanned consequence (we could probably call it externality) of its powerful
capabilities is the added difficulty of using it and a steep learning curve. The
twisted version of a famous quote also states: with great power comes great complexity.
Creating simple maps and deploying simple web mapping applications is easy with
OpenLayers 3; however, if we need something more advanced, we need more stable
and in-depth knowledge of the library. Gaining this knowledge is a great journey,
which Mastering OpenLayers 3 is designed to start you on and aid you through.
Preface
Preface
Chapter 10, Compiling Custom Builds with Closure, shows you how to build your own
version of OpenLayers 3. Along with the custom building process, you will learn
how to bundle your own application with the library and generate a custom API
documentation automatically.
Customizing controls
[ 13 ]
Basic considerations
From now on, step by step, we will make a simple WebGIS application with
OpenLayers 3. In most of the chapters, we will extend the code created in the
previous one. To make it clear, we will consider the current goal at the beginning
of every chapter.
In this chapter, after a few warm-up examples, we will make the layout of our
application. We will make a highly adaptable full-screen application; therefore, we
will use relative units whenever it is possible. We will also make sure that our design
does not prevent the usage of the default one. For now, the application will have
three parts. The map canvas will display the map, the toolbar will contain the control
buttons (the tools), and the notification bar will inform the user about the state of our
application in various ways.
[ 14 ]
Chapter 2
On the right, you can see the rules used by the official and our custom css file on the
inspected element. On the left, you can see all the controls' DOM elements and the
classes associated with them by default. These are the classes we have to modify, in
order to alter the default appeal.
[ 15 ]
Firstly, we remove the margin around the document because this will be a full-screen
application.
The unit can be omitted when the value is zero. The margin: 0;
declaration would give exactly the same result as the preceding one.
Next, we define the size of the map element to match the size of the window. We
declare every button control's color with RGBA values. Finally, we lift the overview
map above the scale bar.
As mentioned previously, we are using relative values for styling, to
make our application is greatly adaptable. For this purpose, the em
value is a great choice, as it depends on the font size of the current
element. We also use the vh (viewport height) value, which is relative
to the viewport; therefore, it precisely stacks with it. As the vh unit has
a limited support, defining a fallback option should be considered.
Let's also change the font type the mouse position control uses to a fixed-width one:
.ol-mouse-position {
font-family: monospace;
}
[ 16 ]
Chapter 2
Finally, as drag boxes, the zoom box can also be styled with CSS; let's make a rule for
the zoom box specifically:
.ol-dragzoom {
background-color: rgba(219,63,63,.1);
border-width: 2px;
border-color: rgba(219,63,63,1);
}
If you save the current rules to a css file, link it to the example and open it up; you
will see the following screenshot:
[ 17 ]
The controls have a reddish glow instead of the original blue one, the overview map
is placed properly above the scale bar, and the coordinates are displayed with a
fixed-width font type.
With this styling option, the logo will always be on top, as it is the first element of the
list. This cannot be overridden, but as the element is now taller, we can provide our
logo as a background and optionally disable the one provided by the library. In this
case, we will use my university's seal as a logo:
.ol-attribution ul {
background-image: url(../../res/university_of_pecs_transparent.
png);
background-size: contain;
background-position: 50%;
background-repeat: no-repeat;
}
The CSS background rules do not allow you to set the opacity for the
background image. You have to modify your image with an editor (for
example, GIMP, PhotoShop, and Paint.NET) if you would like to apply
a transparency to your image.
[ 18 ]
Chapter 2
If you extend your css file with these rules and open up the results, you will see the
modified attribute control with our custom logo:
The zoom out button is placed exactly 203 pixels below the zoom in button. This
is due to a single reason: the zoom slider is declared as 200 pixels tall, the buttons
have a 1 pixel margin, and the zoom slider has a 2 pixel padding. Unfortunately, we
cannot do anything about the absolute height of the zoom slider, as the library uses it
to calculate resolutions.
[ 19 ]
We made a note about CSS specificity before. In this case, the reason
behind why we can't use the ol-zoom-in and ol-zoom-out classes
without nesting is the fact that the more specific declaration wins. As
the original declarations are more specific, they would overwrite our
rules. For this reason, we have to make our declarations at least as
specific as the original ones to overwrite them. For more information,
visit the Mozilla Developer Network's related article at https://
developer.mozilla.org/en-US/docs/Web/CSS/Specificity.
Modifying the slider is a bit trickier than customizing the buttons. There are two
main elements: the rail and the thumb. The problem is that the position of the slider
needs to be calculated from an absolute and a relative unit. Fortunately, we can
calculate values with CSS; thus, the following lines solve our problem:
.ol-zoomslider {
top: calc(1.875em + 6px);
left: calc(.5em + 12px);
width: 2px;
}
.ol-zoomslider-thumb {
background-color: rgba(219,63,63,.5);
left: -11px !important;
}
.ol-zoomslider-thumb:hover {
background-color: rgba(219,63,63,1);
}
As the rail of the slider will only be a narrow line with the thumb centered on it, the
top position of the rail should be the top position of the zoom in button (0.5 em)
added to the height of the button (1.375 em) added to the paddings and margins
(6 px). We have to correct this value by some pixels, which can be done by visual
interpretation. The left position of the rail is calculated from the element's original
left position (0.5 em) and its original width (24 pixels).
[ 20 ]
Chapter 2
We fix the thumb to the rail by setting it back to 11 pixels and making an
important exception. We must do it this way, as its left position gets reset
to 0 by the library every time the slider changes. As the code changes, the
inline styling of the element and inline rules have the most specificity; we
can only fix the thumb with the !important exception to the rail with
CSS. If there is any other way, using !important should be avoided.
If you save the whole set of rules to a css file, or use the one provided with the
example, and load it up, you will see our new zoom control in all its splendor:
If you open the example from a touch device, it will be messy and disoriented. This
is due to the library's design patterns. When the application is opened from a touch
device, a class named ol-touch gets applied to the controls, and it overrides some
of our rules. To make it compatible with touch devices, we have to make further
declarations, which you can see in the css file named ch02_touch, too:
.ol-zoomslider, .ol-touch .ol-zoomslider {
top: calc(1.875em + 6px);
left: calc(.5em + 12px);
width: 2px;
}
.ol-touch .ol-zoomslider-thumb {
width: 22px;
}
.ol-touch .ol-control button {
font-size: 1.14em;
}
[ 21 ]
As the ol-zoomslider class under the ol-touch class has declarations by default,
which we already made in our custom ol-zoomslider class, we can save lines by
applying our existing rules to the more specific class, too. We can do this by using
a logical OR operator, which is a simple comma in CSS. The rest of the issues can be
solved by making new ol-touch-specific rules.
Chapter 2
In this simple style object, we define only a point symbolizer. It is a regular shape,
which can be a simple, regular polygon. The polygon can be convex if it has only one
radius value, and concave if it has two. Our star has five points and an outer radius
of 8 pixels. The colors of its stroke, and fill, are expressed in RGBA values, which can
be done by passing an array to their color parameter with four values. As the star
will be upside down by default, we rotate it by 180 degrees The library only accepts
radian values; thus, we have to rotate the star by .
Using RGBA values is the only way to express opacity in vector styling.
For regular styling with CSS, it is also a good practice as it takes fewer
lines and all the major browsers support it.
Save the updated code, link it to the previous example, and open it up in your
favorite browser. You should see the capitals represented by green stars:
[ 23 ]
The scale bar now shows the scale in degrees, regardless of the map projection. We
will later see that, in a WebGIS application, the unit of this control will be bounded
to the unit of the current projection. However, the valid options for the controls are
only degrees, imperial, nautical, metric, and us.
[ 24 ]
Chapter 2
The overview map is now opened and cannot be closed. However, if you save these
changes and open it up in a browser, you can see that the opened overview map
covers up the scale bar again. To resolve this issue, we have to extend our CSS file
with an additional rule:
.ol-overviewmap.ol-uncollapsible {
bottom: 2em;
}
If we set an otherwise collapsible control to not collapsible, the library gives a specific
class name to the control's DOM element called ol-uncollapsible. Remember
the rules of CSS specificity: the more specific declaration wins. This way, we have
to make our rule at least as specific as the original one, which uses a logical AND
operator between the two classes. We also use this method, which can be achieved in
CSS by concatenating the two class names.
Use the overview map control with great care! It can handle the Web
Mercator projection correctly, but with other projections it is unreliable.
It cannot handle EPSG:4326 at all, and, in the case of custom
projections, it can handle the ones with metric units.
The function receives an array with two coordinates as an input, and requires a
string as an output. We separate the array members into variables and fix them to
three decimal places with JavaScript's toFixed function. Next, we return the fixed
numbers converted to a string.
[ 25 ]
Next, we create a span element in our JavaScript code to apply our newly created
custom style on it:
var infoLabel = document.createElement('span');
infoLabel.className = 'info-label';
infoLabel.textContent = 'i';
If you would like to add some text to the element, always use
textContent instead of innerHTML. As innerHTML tries to parse its
content as HTML, textContent is much faster. There are also some
security vulnerabilities behind innerHTML, but they are related to the
user input and are out of the scope of this book.
[ 26 ]
Chapter 2
Now, we just have to include our custom element in the attribution control's
constructor:
new ol.control.Attribution({
label: infoLabel
})
For the custom logo, we have to supply an object containing its attributes to the
map object. Then, the logo will appear in the attribution control. The object has a
mandatory url and an optional href parameter:
var map = new ol.Map({
[]
logo: {
src: '../../res/university_of_pecs.png',
href: 'http://www.ttk.pte.hu/en'
}
});
If the logo does not have a link, it can be directly included as a single
URL string to the logo parameter.
If you put every part of the code in place, save them and load the result in a browser;
you will see the following customized map:
[ 27 ]
You can also customize the appearance of the attribution control with some simple
CSS rules:
.ol-attribution span {
font-family: Palatino, serif;
font-style: italic;
}
However, these rules also apply to the symbol shown when the control is not
collapsed:
Chapter 2
<script type="text/javascript"
src="ch02_webgis.js"></script>
</head>
<body>
<div class="map-container">
<div id="toolbar" class="toolbar"></div>
<div id="map" class="map">
<div class="nosupport">Your browser doesn't seem
to support this application. Please, update it.</div>
</div>
<div class="notification-bar">
<div id="messageBar" class="message-bar"></div>
<div id="coordinates"></div>
</div>
</div>
</body>
</html>
Now we put everything in a map container. The sizes of the element are relative
to the container. We also put a built-in error message in the HTML, which will be
covered up by the map if the browser can load it.
Note that, in a good API, every element is created dynamically
with JavaScript. Hard coding the HTML elements is a bad practice.
We only do this for the sake of simplicity. Creating an API with
JavaScript is out of the scope of this book.
[ 29 ]
Next, we style the notification bar. It has two parts, one for the mouse position
control and one for the messages that the application will communicate. Now, we
only style the coordinate indicator:
.notification-bar {
width: 100%;
height: 1.5em;
display: table;
}
.notification-bar > div {
height: 100%;
display: table-cell;
border: 1px solid grey;
width: 34%;
box-sizing: border-box;
vertical-align: middle;
}
.notification-bar .message-bar {
width: 66%;
}
.notification-bar .ol-mouse-position {
font-family: monospace;
text-align: center;
position: static;
}
[ 30 ]
Chapter 2
Regardless of using the div elements, we style the notification bar to render tablelike. This way, we can vertically align the text messages that the application will
output in an easy manner. It needs a parent element with the table display and
child elements with the table-cell display (at least in Internet Explorer).
In an HTML document, every visible element is rendered as a box.
Every box has four edges: content, padding, border, and margin.
By default, browsers use a content-box model, which applies the
computed size only to the content. As we use a 100% width for the
element, but we apply a 1 pixel border, the resulting box will exceed
the maximum width of the screen by 4 pixels. This is why we use a
border-box model, which includes the padding, and the border to
the computed size of the box.
Finally, we style the tool bar for the controls. For now, it can only handle one line of
buttons, but it can be expanded if more controls are needed:
.toolbar {
height: 2em;
display: table;
padding-left: .2em;
}
.toolbar .ol-control {
position: static;
display: table-cell;
vertical-align: middle;
padding: 0;
}
.toolbar .ol-control button {
border-radius: 2px;
background-color: rgba(219,63,63,.5);
width: 2em;
display: inline-block;
}
.toolbar .ol-control button:hover {
background-color: rgba(219,63,63,1);
}
As before, the styling of the control buttons are basically the same. The only
difference is that we give them an inline-block display if they are in the tool
bar. This way, the zoom controls, which are vertically stacked by default, become
horizontally aligned. We vertically center the elements of the tool bar with the table
method described above.
[ 31 ]
By specifying the style of the controls under our custom classes, they will
always overwrite the default declarations. However, our styles are only
applied if the controls are placed in the appropriate containers. If they are
targeted at the map canvas, they won't be affected by our rules.
[ 32 ]
Chapter 2
target: 'coordinates'
})
],
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
We cut out the entire interactions part. This way, we don't have to save the vector
layer into a separate variable. We keep the base layer and the vector layer to have
something for our map to display. We cut out most of the controls and only define
the zoom buttons and the mouse position controls. As we do not extend the default
set of controls, but instead define some, the default ones won't be present in our map,
unless we add them manually.
The main extension to the previous examples is the placement of the controls. We can
specify where OpenLayers 3 should place a control with the target parameter. We
can provide a DOM element, or just simply the id of our element of choice. We place
our controls according to our design in the tool bar and the coordinate container. If
you save the complete example and open it up, you will see our application:
[ 33 ]
Summary
In this chapter, we learned how to style the appeal of our application with CSS and
JavaScript styling methods, effectively. Take some friendly advice: in programming,
there is rarely only one good solution. This rule greatly applies to CSS. It offers
several methods to achieve one particular effect. If you learn to utilize most of its
capabilities, you can easily create better a design than the simple ones described in
this chapter (for example, with flexible boxes, filters, and other effects).
In the next chapter, we will learn how to manage layers. We will learn to
dynamically add layers, remove layers, change their order, and draw them in a
custom layer tree.
[ 34 ]
www.PacktPub.com
Stay Connected: