aboutsummaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
Diffstat (limited to 'web')
-rw-r--r--web/app/Application.js3
-rw-r--r--web/app/DeviceImages.js74
-rw-r--r--web/app/Style.js6
-rw-r--r--web/app/store/DeviceImages.js69
-rw-r--r--web/app/view/MapController.js88
-rw-r--r--web/images/bus.svg222
-rw-r--r--web/images/car.svg119
-rw-r--r--web/images/truck.svg127
8 files changed, 657 insertions, 51 deletions
diff --git a/web/app/Application.js b/web/app/Application.js
index fc6ff5e..a92d148 100644
--- a/web/app/Application.js
+++ b/web/app/Application.js
@@ -69,7 +69,8 @@ Ext.define('Traccar.Application', {
'ReportSummary',
'ReportTypes',
'ReportEventTypes',
- 'Statistics'
+ 'Statistics',
+ 'DeviceImages'
],
controllers: [
diff --git a/web/app/DeviceImages.js b/web/app/DeviceImages.js
new file mode 100644
index 0000000..ade88bd
--- /dev/null
+++ b/web/app/DeviceImages.js
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+Ext.define('Traccar.DeviceImages', {
+ singleton: true,
+
+ getImageIcon: function(color, zoom, angle, category) {
+ var image, device, svg, width, height, rotateTransform, scaleTransform, transform;
+ // Get right image or fallback to default arrow
+ if (category) {
+ device = Ext.getStore('DeviceImages').findRecord('key', category);
+ }
+ if (device === undefined || device === null) {
+ device = Ext.getStore('DeviceImages').findRecord('key', 'default');
+ }
+
+ // Duplicate svg object to not brake origin
+ svg = Ext.clone(device.get('svg'));
+
+ // Get original dimensions
+ width = parseFloat(svg.documentElement.getAttribute('width'));
+ height = parseFloat(svg.documentElement.getAttribute('height'));
+ // Colorize
+ svg.getElementById(device.get('fillId')).style.fill = color;
+ // Prepare rotate transformation
+ rotateTransform = 'rotate(' + angle + ' ' + (width / 2) + ' ' + (height / 2) + ')';
+
+ // Adjust size and prepare scale transformation
+ width *= device.get('scale');
+ height *= device.get('scale');
+ if (zoom) {
+ width *= Traccar.Style.mapScaleSelected;
+ height *= Traccar.Style.mapScaleSelected;
+ scaleTransform = 'scale(' + device.get('scale') * Traccar.Style.mapScaleSelected + ') ';
+ } else {
+ scaleTransform = 'scale(' + device.get('scale') + ') ';
+ }
+
+ //Apply both transformation in right order
+ transform = scaleTransform + ' ' + rotateTransform;
+ svg.getElementById(device.get('rotateId')).setAttribute('transform', transform);
+
+ // Set dimension attributes
+ svg.documentElement.setAttribute('width', width);
+ svg.documentElement.setAttribute('height', height);
+ svg.documentElement.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
+
+ image = new ol.style.Icon({
+ imgSize: [width, height], // Workaround for IE
+ src: 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent((new XMLSerializer()).serializeToString(svg.documentElement))
+ });
+ image.fill = color;
+ image.zoom = zoom;
+ image.angle = angle;
+ image.category = category;
+
+ return image;
+ }
+}); \ No newline at end of file
diff --git a/web/app/Style.js b/web/app/Style.js
index b4201bb..2353a21 100644
--- a/web/app/Style.js
+++ b/web/app/Style.js
@@ -49,9 +49,6 @@ Ext.define('Traccar.Style', {
],
mapRouteWidth: 5,
- mapArrowStrokeColor: 'rgba(50, 50, 50, 1.0)',
- mapArrowStrokeWidth: 2,
-
mapTextColor: 'rgba(50, 50, 50, 1.0)',
mapTextStrokeColor: 'rgba(255, 255, 255, 1.0)',
mapTextStrokeWidth: 2,
@@ -62,8 +59,7 @@ Ext.define('Traccar.Style', {
mapColorUnknown: 'rgba(250, 190, 77, 1.0)',
mapColorOffline: 'rgba(255, 84, 104, 1.0)',
- mapRadiusNormal: 9,
- mapRadiusSelected: 14,
+ mapScaleSelected: 1.5,
mapMaxZoom: 19,
mapDelay: 500,
diff --git a/web/app/store/DeviceImages.js b/web/app/store/DeviceImages.js
new file mode 100644
index 0000000..968f90c
--- /dev/null
+++ b/web/app/store/DeviceImages.js
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+Ext.define('Traccar.store.DeviceImages', {
+ extend: 'Ext.data.Store',
+ fields: ['key', 'name', 'url', 'svg', 'fillId', 'rotateId', 'scale'],
+
+ data: [{
+ key: 'default',
+ name: Strings.categoryDefault,
+ svg: (new DOMParser())
+ .parseFromString('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="26" height="26">'
+ + '<polygon id="arrow" points="13,4 19,22 13,19 7,22" '
+ + 'style="fill:#008000;stroke:#000000;stroke-width:2px;" transform="" /></svg>', "image/svg+xml"),
+ rotateId: 'arrow',
+ fillId: 'arrow',
+ scale: 1
+ }, {
+ key: 'car',
+ name: Strings.categoryCar,
+ url: 'images/car.svg',
+ fillId: 'path4149',
+ rotateId: 'g4207',
+ scale: 0.06,
+ }, {
+ key: 'bus',
+ name: Strings.categoryBus,
+ url: 'images/bus.svg',
+ fillId: 'path4713',
+ rotateId: 'layer2',
+ scale: 0.12,
+ }, {
+ key: 'truck',
+ name: Strings.categoryTruck,
+ url: 'images/truck.svg',
+ fillId: 'path4718',
+ rotateId: 'layer2',
+ scale: 0.1,
+ }],
+
+ constructor: function() {
+ this.callParent(arguments);
+ this.config.data.forEach(function (device) {
+ if (device.url) {
+ Ext.Ajax.request({
+ url: device.url,
+ scope: device,
+ success: function (response) {
+ this.svg = (new DOMParser()).parseFromString(response.responseText, "image/svg+xml");
+ }
+ });
+ }
+ });
+ }
+}); \ No newline at end of file
diff --git a/web/app/view/MapController.js b/web/app/view/MapController.js
index 32ea6b0..7875e94 100644
--- a/web/app/view/MapController.js
+++ b/web/app/view/MapController.js
@@ -22,7 +22,8 @@ Ext.define('Traccar.view.MapController', {
requires: [
'Traccar.model.Position',
'Traccar.model.Device',
- 'Traccar.GeofenceConverter'
+ 'Traccar.GeofenceConverter',
+ 'Traccar.DeviceImages'
],
config: {
@@ -86,17 +87,14 @@ Ext.define('Traccar.view.MapController', {
},
changeMarkerColor: function (style, color) {
- return new ol.style.Style({
- image: new ol.style.Arrow({
- radius: style.getImage().getRadius(),
- fill: new ol.style.Fill({
- color: color
- }),
- stroke: style.getImage().getStroke(),
- rotation: style.getImage().getRotation()
- }),
+ var newStyle = new ol.style.Style({
+ image: Traccar.DeviceImages.getImageIcon(color,
+ style.getImage().zoom,
+ style.getImage().angle,
+ style.getImage().category),
text: style.getText()
});
+ return newStyle;
},
updateDevice: function (store, data) {
@@ -154,18 +152,20 @@ Ext.define('Traccar.view.MapController', {
if (deviceId in this.latestMarkers) {
marker = this.latestMarkers[deviceId];
marker.setGeometry(geometry);
+ marker.setStyle(this.rotateMarker(marker.getStyle(), position.get('course')));
} else {
marker = new ol.Feature(geometry);
marker.set('record', device);
- this.latestMarkers[deviceId] = marker;
- this.getView().getLatestSource().addFeature(marker);
- style = this.getLatestMarker(this.getDeviceColor(device));
+ style = this.getLatestMarker(this.getDeviceColor(device),
+ position.get('course'),
+ device.get('category'));
style.getText().setText(device.get('name'));
marker.setStyle(style);
- }
+ this.latestMarkers[deviceId] = marker;
+ this.getView().getLatestSource().addFeature(marker);
- marker.getStyle().getImage().setRotation(position.get('course') * Math.PI / 180);
+ }
if (marker === this.selectedMarker && this.followSelected()) {
this.getView().getMapView().setCenter(marker.getGeometry().getCoordinates());
@@ -231,8 +231,7 @@ Ext.define('Traccar.view.MapController', {
this.reportMarkers[position.get('id')] = marker;
this.getView().getReportSource().addFeature(marker);
- style = this.getReportMarker(position.get('deviceId'));
- style.getImage().setRotation(position.get('course') * Math.PI / 180);
+ style = this.getReportMarker(position.get('deviceId'), position.get('course'));
/*style.getText().setText(
Ext.Date.format(position.get('fixTime'), Traccar.Style.dateTimeFormat24));*/
@@ -278,18 +277,9 @@ Ext.define('Traccar.view.MapController', {
});
},
- getMarkerStyle: function (radius, color) {
+ getMarkerStyle: function (zoom, color, angle, category) {
return new ol.style.Style({
- image: new ol.style.Arrow({
- radius: radius,
- fill: new ol.style.Fill({
- color: color
- }),
- stroke: new ol.style.Stroke({
- color: Traccar.Style.mapArrowStrokeColor,
- width: Traccar.Style.mapArrowStrokeWidth
- })
- }),
+ image: Traccar.DeviceImages.getImageIcon(color, zoom, angle, category),
text: new ol.style.Text({
textBaseline: 'bottom',
fill: new ol.style.Fill({
@@ -299,47 +289,55 @@ Ext.define('Traccar.view.MapController', {
color: Traccar.Style.mapTextStrokeColor,
width: Traccar.Style.mapTextStrokeWidth
}),
- offsetY: -radius / 2 - Traccar.Style.mapTextOffset,
+ offsetY: -Traccar.Style.mapTextOffset,
font : Traccar.Style.mapTextFont
})
});
},
- getLatestMarker: function (color) {
- return this.getMarkerStyle(
- Traccar.Style.mapRadiusNormal, color);
+ getLatestMarker: function (color, angle, category) {
+ return this.getMarkerStyle(false, color, angle, category);
},
- getReportMarker: function (deviceId) {
+ getReportMarker: function (deviceId, angle) {
var index = 0;
if (deviceId !== undefined) {
index = deviceId % Traccar.Style.mapRouteColor.length;
}
- return this.getMarkerStyle(
- Traccar.Style.mapRadiusNormal, Traccar.Style.mapRouteColor[index]);
+ return this.getMarkerStyle(false, Traccar.Style.mapRouteColor[index], angle);
},
- resizeMarker: function (style, radius) {
- return new ol.style.Style({
- image: new ol.style.Arrow({
- radius: radius,
- fill: style.getImage().getFill(),
- stroke: style.getImage().getStroke(),
- rotation: style.getImage().getRotation()
- }),
+ resizeMarker: function (style, zoom) {
+ var newStyle = new ol.style.Style({
+ image: Traccar.DeviceImages.getImageIcon(style.getImage().fill,
+ zoom,
+ style.getImage().angle,
+ style.getImage().category),
+ text: style.getText()
+ });
+ return newStyle;
+ },
+
+ rotateMarker: function (style, angle) {
+ var newStyle = new ol.style.Style({
+ image: Traccar.DeviceImages.getImageIcon(style.getImage().fill,
+ style.getImage().zoom,
+ angle,
+ style.getImage().category),
text: style.getText()
});
+ return newStyle;
},
selectMarker: function (marker, center) {
if (this.selectedMarker) {
this.selectedMarker.setStyle(
- this.resizeMarker(this.selectedMarker.getStyle(), Traccar.Style.mapRadiusNormal));
+ this.resizeMarker(this.selectedMarker.getStyle(), false));
}
if (marker) {
marker.setStyle(
- this.resizeMarker(marker.getStyle(), Traccar.Style.mapRadiusSelected));
+ this.resizeMarker(marker.getStyle(), true));
if (center) {
this.getView().getMapView().setCenter(marker.getGeometry().getCoordinates());
}
diff --git a/web/images/bus.svg b/web/images/bus.svg
new file mode 100644
index 0000000..f926055
--- /dev/null
+++ b/web/images/bus.svg
@@ -0,0 +1,222 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="500px"
+ height="500px"
+ viewBox="0 0 500.00001 500.00001"
+ id="svg4144"
+ version="1.1"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="bus.svg">
+ <defs
+ id="defs4146" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.7"
+ inkscape:cx="203.40483"
+ inkscape:cy="161.67936"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="false"
+ units="px"
+ inkscape:window-width="1920"
+ inkscape:window-height="1017"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata4149">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/" />
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/by-sa/3.0/">
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Reproduction" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Distribution" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#Notice" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#Attribution" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#ShareAlike" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Layer 2">
+ <path
+ style="opacity:1;fill:#008000;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 196.11953,55.873016 0.0829,391.607144 c 3.72662,13.54113 11.5055,22.80612 24.73849,24.46428 l 57.14286,0.35714 c 15.35608,-3.67133 22.29313,-12.95537 24.82143,-25.17856 l 0.7143,-390.892861 c -0.2913,-5.886565 -2.12374,-9.65786 -5.18591,-13.644643 l 24.97726,-0.374645 C 321.1664,37.001224 307.61725,27.363695 297.51536,40.879459 293.08957,33.592704 284.57147,29.058489 276.47667,28.015873 L 222.36952,27.8373 c -11.06058,1.916208 -17.21769,7.780519 -21.69229,14.905049 -11.14642,-16.386951 -25.50315,-2.099791 -25.63481,0.838857 l 24.90118,0.425857 c -2.37652,4.331728 -3.38012,8.63026 -3.82407,11.865953 z"
+ id="path4713"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccc" />
+ <g
+ id="g4818"
+ style="fill:#f2f2f2">
+ <path
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0"
+ id="path4735"
+ d="M 249.91072,39.732142 C 231.04598,39.712452 205.58753,37.16641 201.25,43.749999 l 5.17857,17.678572 c 7.57822,-5.855074 19.92572,-4.245259 43.21429,-4.285715 z"
+ style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0"
+ id="path4735-1"
+ d="m 249.82219,39.7043 c 18.86474,-0.01969 43.96605,-2.655018 48.30358,3.928571 l -5.17857,17.678572 c -7.57822,-5.85507 -19.79179,-4.155974 -43.08036,-4.196434 z"
+ style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0"
+ id="path4752"
+ d="m 201.14663,43.411049 c -6.8176,6.360856 -5.00544,36.02672 -5.08906,59.457411 l 8.81082,-0.0446 c 0.34555,-15.012868 -1.01474,-36.78369 1.58154,-41.29316 z"
+ style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <rect
+ y="102.85714"
+ x="196.07143"
+ height="53.660713"
+ width="8.7946253"
+ id="rect4754"
+ style="opacity:1;fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ y="156.60713"
+ x="196.11607"
+ height="53.035713"
+ width="8.7053576"
+ id="rect4756"
+ style="opacity:1;fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ y="209.73213"
+ x="196.16071"
+ height="53.035721"
+ width="8.7053614"
+ id="rect4758"
+ style="opacity:1;fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ y="262.71875"
+ x="196.20045"
+ height="53.30722"
+ width="8.6079798"
+ id="rect4760"
+ style="opacity:1;fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ y="315.89285"
+ x="196.16072"
+ height="53.839287"
+ width="8.5714283"
+ id="rect4762"
+ style="opacity:1;fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ y="369.6167"
+ x="196.23468"
+ height="53.419014"
+ width="8.4974623"
+ id="rect4764"
+ style="opacity:1;fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0"
+ id="path4752-5"
+ d="m 298.17268,43.254296 c 7.90416,5.274295 5.11759,35.914567 5.08906,59.457414 l -8.81082,-0.0446 c -0.34555,-15.012873 1.01474,-36.783695 -1.58154,-41.293165 z"
+ style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <rect
+ transform="scale(-1,1)"
+ y="102.70039"
+ x="-303.24789"
+ height="53.660713"
+ width="8.7946253"
+ id="rect4754-4"
+ style="opacity:1;fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ transform="scale(-1,1)"
+ y="156.45038"
+ x="-303.20325"
+ height="53.035713"
+ width="8.7053576"
+ id="rect4756-5"
+ style="opacity:1;fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ transform="scale(-1,1)"
+ y="209.57536"
+ x="-303.1586"
+ height="53.035721"
+ width="8.7053614"
+ id="rect4758-6"
+ style="opacity:1;fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ transform="scale(-1,1)"
+ y="262.56201"
+ x="-303.11887"
+ height="53.30722"
+ width="8.6079798"
+ id="rect4760-9"
+ style="opacity:1;fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ transform="scale(-1,1)"
+ y="315.73611"
+ x="-303.1586"
+ height="53.839287"
+ width="8.5714283"
+ id="rect4762-5"
+ style="opacity:1;fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ transform="scale(-1,1)"
+ y="369.45996"
+ x="-303.08463"
+ height="53.419014"
+ width="8.4974623"
+ id="rect4764-2"
+ style="opacity:1;fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="ccccccc"
+ inkscape:connector-curvature="0"
+ id="path4801"
+ d="m 204.47033,423.30342 c -3.64856,22.24167 9.12482,44.86492 26.42857,45.17854 l 37.14286,-0.17853 c 18.9215,0.41739 30.05186,-22.16657 26.96428,-45.53573 0.76011,18.51126 -12.10167,34.0046 -27.14285,34.10713 l -37.32617,-0.16888 c -11.82277,-0.73357 -25.86632,-12.71876 -26.06669,-33.40253 z"
+ style="opacity:1;fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ </g>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 227.05992,65.086657 0.0829,382.056203"
+ id="path4837"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 272.14286,65.043328 0.12627,382.521662"
+ id="path4839"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 249.53825,65.169597 0.0829,382.521663"
+ id="path4841"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+</svg>
diff --git a/web/images/car.svg b/web/images/car.svg
new file mode 100644
index 0000000..071d390
--- /dev/null
+++ b/web/images/car.svg
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="500"
+ height="500"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="car.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.7"
+ inkscape:cx="-332.69084"
+ inkscape:cy="476.11054"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="981"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/" />
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/by-sa/3.0/">
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Reproduction" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Distribution" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#Notice" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#Attribution" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#ShareAlike" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <g
+ id="g4207">
+ <path
+ sodipodi:nodetypes="zccczczccczcz"
+ inkscape:connector-curvature="0"
+ id="path4149"
+ d="m 164.31862,85.468446 c -4.19906,39.571694 6.55669,91.762434 6.06092,147.482284 -10.52016,-1.80797 -20.2496,-2.39539 -19.86866,17.20586 l 19.27693,-7.70658 c -1.71236,42.20755 -11.244,119.22302 -5.46918,163.23681 5.77482,44.01379 37.68226,70.86495 98.99495,68.69037 57.16171,-0.22437 86.65984,-29.45295 90.49531,-70.49531 3.83547,-41.04236 -5.62278,-121.15641 -7.1144,-159.69692 l 20.41226,5.93837 c 2.35433,-15.05893 -9.06025,-22.05503 -20.45559,-18.18275 -1.71417,-0.64282 8.60748,-110.55723 6.06091,-143.946754 -2.54656,-33.389517 -38.86205,-60.167876 -92.5497,-62.358976 -53.46176,1.44606 -91.64469,20.261919 -95.84375,59.833596 z"
+ style="fill:#008000;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="zcccccccz"
+ inkscape:connector-curvature="0"
+ id="path4151"
+ d="m 256.92615,171.78049 c -44.12883,0.0136 -75.14588,18.92974 -76.71251,52.74454 l 5.82327,27.11352 33.05682,-9.37798 38.66401,-1.22862 38.32614,0.83942 34.40484,9.26211 5.51905,-27.34552 c 0.87812,-33.65356 -34.95279,-52.02103 -79.08162,-52.00747 z"
+ style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cczccc"
+ inkscape:connector-curvature="0"
+ id="path4153"
+ d="m 198.15874,345.07766 -1.51523,52.02286 c 5.65793,29.35218 29.45066,42.46306 59.09392,42.42641 29.64326,-0.0367 60.86511,-12.41133 65.15484,-43.43656 l -0.50508,-51.51778 z"
+ style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cczc"
+ inkscape:connector-curvature="0"
+ id="path4157"
+ d="m 180.22853,226.53267 -3.03046,98.0894 c 5.0681,37.51079 14.77304,32.79101 14.39468,-18.68782 -0.37837,-51.47882 -2.37697,-64.13759 -11.36422,-79.40158 z"
+ style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cczc"
+ inkscape:connector-curvature="0"
+ id="path4157-3"
+ d="m 336.17606,224.45923 4.54569,98.61614 c -5.0681,37.51079 -14.77304,32.79101 -14.39468,-18.68782 0.37837,-51.47882 3.63966,-56.58311 9.84899,-79.92832 z"
+ style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <ellipse
+ ry="16.293392"
+ rx="12.721964"
+ cy="64.4645"
+ cx="198.43823"
+ id="path4174"
+ style="opacity:1;fill:#f9f9f9;fill-opacity:1;stroke:#000000;stroke-width:1.27035797" />
+ <ellipse
+ ry="16.293392"
+ rx="12.721964"
+ cy="63.750187"
+ cx="316.84073"
+ id="path4174-6"
+ style="opacity:1;fill:#f9f9f9;fill-opacity:1;stroke:#000000;stroke-width:1.27035797" />
+ </g>
+ </g>
+</svg>
diff --git a/web/images/truck.svg b/web/images/truck.svg
new file mode 100644
index 0000000..ef835b6
--- /dev/null
+++ b/web/images/truck.svg
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="500"
+ height="500"
+ viewBox="0 0 500.00001 500.00001"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="truck.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.4"
+ inkscape:cx="195.16338"
+ inkscape:cy="286.29962"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="false"
+ units="px"
+ inkscape:window-width="1920"
+ inkscape:window-height="981"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/" />
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/by-sa/3.0/">
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Reproduction" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Distribution" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#Notice" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#Attribution" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://creativecommons.org/ns#ShareAlike" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Layer 2">
+ <path
+ style="fill:#008000;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 190.79351,28.531817 C 177.60808,29.049025 171.0544,44.782872 171.3023,50.256254 l -0.0396,61.172316 -21.40626,-0.22779 c -16.86908,2.86168 -11.58456,23.89093 -0.28466,24.08815 l 10.97663,-0.0797 c 0.98536,-5.38348 1.35729,-10.66472 10.16589,-17.35207 l 0.71428,111.42857 c -4.24692,-0.33046 -7.28269,-0.19489 -7.22579,4.62119 l -0.16961,235.20922 c -0.23841,3.16729 1.19892,4.56696 5.67097,4.03317 l 166.39639,0.1696 c 1.15311,-0.32283 2.67054,0.26515 2.55383,-3.23223 l 0,-238.1134 c 0.0879,-3.22046 -1.18803,-3.6906 -5.20548,-3.60732 l 0.41841,-111.01388 c 8.11407,4.34267 9.84097,11.11853 11.00273,18.10969 l 12.13401,-3.7e-4 c 15.62702,-6.6151 9.83035,-22.17132 -0.75992,-24.63941 l -22.37682,0.6066 -0.59173,-65.48649 c -0.0903,-5.888911 -9.72969,-17.446043 -19.47262,-17.496921 z"
+ id="path4718"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 171.34713,229.15285 162.04573,-0.75999"
+ id="path4739"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 214.46429,28.392856 c -5.80071,1.089231 -5.50629,6.100613 -6.47005,9.466144 L 200,105.35714"
+ id="path4741"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 291.45828,28.52044 c 5.80071,1.089231 5.50629,6.100613 6.47005,9.466144 l 7.99424,67.498136"
+ id="path4741-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc" />
+ <path
+ style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 171.64234,122.98288 25.47002,27.23648 111.48924,0.0785 24.30679,-27.52665 0.0631,-5.74525 c -2.39904,-9.44151 -31.06848,-13.2503 -37.75445,-13.51078 l -84.60027,0 c -8.97913,0.17928 -34.45033,4.81556 -39.02612,13.74429 z"
+ id="path4758"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 176.7767,128.76894 0.32387,70.726 20.9633,1.17603 -0.84691,-50.51026 z"
+ id="path4760"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 329.22204,127.27242 -0.1976,72.49377 -20.9633,1.17603 0.84691,-50.51026 z"
+ id="path4760-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 203.04066,28.511299 c -1.81103,5.394916 -1.5885,11.016271 -10.6066,13.637059 l -19.1929,0.252538 c 1.93578,-3.984031 7.27783,-12.810686 16.28871,-13.889597 z"
+ id="path4801"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 302.30988,28.661154 c 1.81103,5.394916 1.5885,11.016271 10.6066,13.637059 l 19.1929,0.252538 C 330.1736,38.56672 324.83155,29.740065 315.82067,28.661154 Z"
+ id="path4801-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ </g>
+</svg>