| Version 4 (modified by tsauerwein, 3 years ago) |
|---|
OpenLayers with Canvas
Currently OpenLayers has already a vector renderer ( OpenLayers.Renderer.Canvas) that uses the HTML element Canvas. There are also experiments using Canvas for rendering raster layers: Transition Example.
This Wiki page will present results of performance evaluations comparing SVG and Canvas.
Vector Layers
Performance evaluation
A small test suite has been built to run the tests: performance-tests
First test/notes
Test data: World Countries Boundaries (World Countries)
# of Features: 190
# of Vertices: 6925
Geometry type: (Multi-) Polygon
Map size: 800 px x 800 px
Browser: Chromium 5.0.342.9
| Test Case | Canvas | SVG |
| Display layer | 67 ms | 215 ms |
| Display layer and pan 10 times | 1192 ms | 380 ms |
| Display layer and zoom 10 times | 1174 ms | 1181 ms |
| Select feature | 158 ms | 0 ms |
The shown numbers are the average of 10 test runs.
Notes:
- Canvas is fast! Displaying a layer for the first times is up to 3-times faster than SVG.
- But once the layer is drawn, panning is faster with SVG. The Canvas renderer simply redraws the whole layer every time the map is panned, SVG seems to profit from some internal optimization.
- Zooming takes approx. the same time for SVG and Canvas.
- Selecting features is much faster in SVG. This is because in SVG you can set click- and hover-events on geometries inside the SVG element. But for Canvas the method Canvas.getFeatureIdFromEvent(evt) has to loop all geometries to check if a bounding-box around the mouse position intersects the geometry. For large data sets this gets a performance problem especially when hovering, when the method is executed on every mouse move.
Optimization
The first test has shown that the canvas renderer compared to the SVG renderer is slower for panning and selecting features (by mouse click/hover). To improve this two operations, a spatial index based on a R-Tree ( R-Tree Library for Javascript) has been integrated.
The method Canvas.getFeatureIdFromEvent(evt) now uses the R-Tree to query the features that are near the current mouse position. The features are inserted into the R-Tree, when they are added to the renderer with Canvas.drawFeature(). Canvas.eraseFeatures() also removes the feature from the R-Tree.
Canvas.redraw() also benefits from the R-Tree. The canvas renderer used to draw all geometries even if they were not inside the current map extent. Now using a R-Tree query only those features are drawn whose bounding box is inside the current extent. If the whole map is shown, so that all geometries are rendered, this won't improve the performance. But if a smaller extent is displayed, this speeds up the render time.
The usage of the R-Tree is optional, by default no R-Tree is used for the canvas renderer. The R-Tree can be activated by setting a flag in rendererOptions for a layer (rendererOptions: {'useRTree': useRTRee}).
The canvas renderer when used without a R-Tree has also been improved. Canvas.redraw() now also only draws the geometries which are inside the map extent. These geometries are selected by checking if the bounding box of the geometry intersects the mouse position rectangle. Canvas.getFeatureIdFromEvent(evt) used to run slow intersection tests for every geometry. Now a bounding-box intersection test is executed first, and only if this test is successful, a correct intersection test with the original geometry is run.
Test of the optimizations
Canvas 1: Canvas renderer without any optimizations ( rev. 10316)
Canvas 2: Canvas renderer without R-Tree (only features in the current extent are rendered and getFeatureIdFromEvent first checks if the bounding boxes intersect)
Canvas 3: Canvas renderer with R-Tree
Test-Case 01: Show
Map size: 800 px x 800 px
Geometry type: (Multi-)Polygon
Test-Data: countries-non-simplified.json / countries-simplified-x.json (Source: Natural Earth: Admin 0 – Countries)
# of Features: 246
Test runs: 10
| Test-Data | # of Vertices | Canvas 1 | Canvas 2 | Canvas 3 (with R-Tree) | SVG |
| countries-simplified-1 | 2150 | 35 | 84 | 61 | 71 |
| countries-simplified-0.5 | 4506 | 55 | 120 | 108 | 146 |
| countries-simplified-0.05 | 45031 | 342 | 1119 | 918 | 1263 |
| countries-simplified-0.005 | 159771 | 834 | 3149 | 3015 | 3782 |
| countries-non-simplified | 403150 | 1822 | 8384 | 7076 | 8953 |
Test-Case 02: Pan 10-times in a smaller extent after the map is shown
Map size: 800 px x 800 px
Geometry type: (Multi-)Polygon
Test-Data: countries-non-simplified.json / countries-simplified-x.json (Source: Natural Earth: Admin 0 – Countries)
# of Features: 246
Test runs: 10
Start extent: 6, 45, 6.5, 45.5
| Test-Data | # of Vertices | Canvas 1 | Canvas 2 | Canvas 3 (with R-Tree) | SVG |
| countries-simplified-1 | 2150 | 524 | 301 | 358 | 85 |
| countries-simplified-0.5 | 4506 | 759 | 380 | 452 | 141 |
| countries-simplified-0.05 | 45031 | 4085 | 1384 | 1729 | 1058 |
| countries-simplified-0.005 | 159771 | 11236 | 3876 | 3452 | 3372 |
| countries-non-simplified | 403150 | 20850 | 7760 | 7279 | 5129 |
Test-Case 03: Zoom 10-times after the map is shown
Map size: 800 px x 800 px
Geometry type: (Multi-)Polygon
Test-Data: countries-non-simplified.json / countries-simplified-x.json (Source: Natural Earth: Admin 0 – Countries)
# of Features: 246
Test runs: 10
| Test-Data | # of Vertices | Canvas 1 | Canvas 2 | Canvas 3 (with R-Tree) | SVG |
| countries-simplified-1 | 2150 | 464 | 533 | 438 | 423 |
| countries-simplified-0.5 | 4506 | 699 | 818 | 654 | 653 |
| countries-simplified-0.05 | 45031 | 4151 | 4587 | 3809 | 5008 |
| countries-simplified-0.005 | 159771 | 13714 | 12649 | 12250 | 12208 |
| countries-non-simplified | 403150 | 27459 | 25091 | 23993 | 23367 |
Test-Case 04: Select 10 Features (Simulate feature selection by mouse click)
Map size: 800 px x 800 px
Geometry type: (Multi-)Polygon
Test-Data: countries-non-simplified.json / countries-simplified-x.json (Source: Natural Earth: Admin 0 – Countries)
# of Features: 246
Test runs: 10
| Test-Data | # of Vertices | Canvas 1 | Canvas 2 | Canvas 3 (with R-Tree) | SVG |
| countries-simplified-1 | 2150 | 321 | 44 | 43 | 0.6 |
| countries-simplified-0.5 | 4506 | 475 | 43 | 10 | 0.6 |
| countries-simplified-0.05 | 45031 | 2335 | 104 | 289 | 1.3 |
| countries-simplified-0.005 | 159771 | 26372 | 2451 | 1620 | 1.5 |
| countries-non-simplified | 403150 | 47912 | 4435 | 2511 | 2.0 |
Test-Case 05: Add Features
Map size: 800 px x 800 px
Geometry type: (Multi-)Polygon
Test-Data: countries-non-simplified.json / countries-simplified-x.json (Source: Natural Earth: Admin 0 – Countries)
# of Features: 246
Test runs: 10
| Test-Data | # of Vertices | Canvas 1 | Canvas 2 | Canvas 3 (with R-Tree) | SVG |
| countries-simplified-1 | 2150 | 57 | 68 | 48 | 34 |
| countries-simplified-0.5 | 4506 | 61 | 76 | 64 | 42 |
| countries-simplified-0.05 | 45031 | 323 | 338 | 286 | 50 |
| countries-simplified-0.005 | 159771 | 962 | 690 | 849 | 53 |
| countries-non-simplified | 403150 | 1799 | 1533 | 1496 | 71 |
Notes
- The improvements speed up but still can't reach the times for SVG.
- The SVG renderer is the fastest for all test cases, except for test case 01, displaying a layer for the first time. This is also because Canvas 01 does not need to calculate the bounds for all geometries, all other renderer do. This takes a large amount of the time.
- Canvas.getFeatureIdFromEvent(evt) has been improved, but editing/moving a feature does still not feel very smooth.
Evaluation
For rendering vector data the canvas renderer won't replace the SVG renderer. SVG (Scalable Vector Graphics) is optimized for displaying vector data, all improvements to the canvas renderer are actually attempts to re-invent SVG in JavaScript. And then the main limiting factor is JavaScript.
In some special cases the canvas renderer may be an alternative. For example when you just want to display features on a map, but don't want to allow any interaction with the map (similar to the Google Static Maps API and maybe also the Google Visualization API).
It could also be used to render all layers onto one canvas (including all raster layers), so that you can simply copy the image and paste it into a OpenOffice/Word document or save it as image file.
Raster Layers
Experiments:
Attachments
-
01.png
(48.2 KB) - added by tsauerwein
3 years ago.
Diagram Test Case 01
-
02.png
(44.6 KB) - added by tsauerwein
3 years ago.
Diagram Test Case 02
-
04.png
(37.2 KB) - added by tsauerwein
3 years ago.
Diagram Test Case 04
-
05.png
(37.6 KB) - added by tsauerwein
3 years ago.
Diagram Test Case 05
-
03.png
(47.0 KB) - added by tsauerwein
3 years ago.
Diagram Test Case 03
-
01-pre-calculated-bounds.png
(51.9 KB) - added by tsauerwein
3 years ago.
Diagram Test Case 01 (pre-calculated bounds)
-
01-raster.png
(39.3 KB) - added by tsauerwein
3 years ago.
Diagram Test Case 01 (Raster)
-
02-raster.png
(48.7 KB) - added by tsauerwein
3 years ago.
Diagram Test Case 02 (Raster)
-
canvas-vector-heatmap.png
(215.1 KB) - added by tsauerwein
3 years ago.
HeatMap layer example





