diff --git a/examples/scale-line.html b/examples/scale-line.html index 275a2b8ecd..bd0819c86a 100644 --- a/examples/scale-line.html +++ b/examples/scale-line.html @@ -14,3 +14,19 @@ tags: "scale-line, openstreetmap" + + + + + +
diff --git a/examples/scale-line.js b/examples/scale-line.js index 14b5421ebf..5c6fdb2be0 100644 --- a/examples/scale-line.js +++ b/examples/scale-line.js @@ -4,12 +4,27 @@ import {defaults as defaultControls, ScaleLine} from '../src/ol/control.js'; import TileLayer from '../src/ol/layer/Tile.js'; import OSM from '../src/ol/source/OSM.js'; +let scaleType = 'scaleline'; +let scaleBarSteps = 4; +let scaleBarText = true; +let control; -const scaleLineControl = new ScaleLine(); - +function scaleControl() { + if (scaleType === 'scaleline') { + control = new ScaleLine(); + return control; + } + control = new ScaleLine({ + scaleBar: true, + scaleBarSteps: scaleBarSteps, + scaleBarText: scaleBarText, + minWidth: 200 + }); + return control; +} const map = new Map({ controls: defaultControls().extend([ - scaleLineControl + scaleControl() ]), layers: [ new TileLayer({ @@ -23,10 +38,40 @@ const map = new Map({ }) }); - const unitsSelect = document.getElementById('units'); +const typeSelect = document.getElementById('type'); +const stepsSelect = document.getElementById('steps'); +const scaleTextCheckbox = document.getElementById('showScaleText'); +const showScaleTextDiv = document.getElementById('showScaleTextDiv'); function onChange() { - scaleLineControl.setUnits(unitsSelect.value); + control.setUnits(unitsSelect.value); +} +function onChangeType() { + scaleType = typeSelect.value; + if (typeSelect.value === 'scalebar') { + stepsSelect.style.display = 'inline'; + showScaleTextDiv.style.display = 'inline'; + map.removeControl(control); + map.addControl(scaleControl()); + } else { + stepsSelect.style.display = 'none'; + showScaleTextDiv.style.display = 'none'; + map.removeControl(control); + map.addControl(scaleControl()); + } +} +function onChangeSteps() { + scaleBarSteps = parseInt(stepsSelect.value, 10); + map.removeControl(control); + map.addControl(scaleControl()); +} +function onChangeScaleText() { + scaleBarText = scaleTextCheckbox.checked; + map.removeControl(control); + map.addControl(scaleControl()); } unitsSelect.addEventListener('change', onChange); +typeSelect.addEventListener('change', onChangeType); +stepsSelect.addEventListener('change', onChangeSteps); +scaleTextCheckbox.addEventListener('change', onChangeScaleText); onChange(); diff --git a/src/ol/control/ScaleLine.js b/src/ol/control/ScaleLine.js index 66dfb8f6ac..10d2e478fd 100644 --- a/src/ol/control/ScaleLine.js +++ b/src/ol/control/ScaleLine.js @@ -45,6 +45,11 @@ const LEADING_DIGITS = [1, 2, 5]; * @property {HTMLElement|string} [target] Specify a target if you want the control * to be rendered outside of the map's viewport. * @property {Units|string} [units='metric'] Units. + * @property {boolean} [scaleBar=false] Render scalebars instead of a line. + * @property {number} [scaleBarSteps=4] Number of steps the scalebar should use. Use even numbers + * for best results. Only useful when `scaleBar` is `true`. + * @property {boolean} [scaleBarText=false] Render a scale ontop of the scalebar. Only useful + * when `scaleBar` is `true`. */ @@ -57,6 +62,8 @@ const LEADING_DIGITS = [1, 2, 5]; * viewport center cannot be calculated in the view projection. * By default the scale line will show in the bottom left portion of the map, * but this can be changed by using the css selector `.ol-scale-line`. + * When specifying `scaleBar` as `true`, a scalebar will be rendered instead + * of a scaleline. * * @api */ @@ -69,7 +76,8 @@ class ScaleLine extends Control { const options = opt_options ? opt_options : {}; - const className = options.className !== undefined ? options.className : 'ol-scale-line'; + const className = options.className !== undefined ? options.className : + options.scaleBar !== undefined ? 'ol-scale-bar' : 'ol-scale-line'; super({ element: document.createElement('div'), @@ -123,6 +131,24 @@ class ScaleLine extends Control { this.setUnits(/** @type {Units} */ (options.units) || Units.METRIC); + /** + * @private + * @type {boolean} + */ + this.scaleBar_ = options.scaleBar || false; + + /** + * @private + * @type {number} + */ + this.scaleBarSteps_ = options.scaleBarSteps || 4; + + /** + * @private + * @type {boolean} + */ + this.scaleBarText_ = options.scaleBarText || false; + } /** @@ -257,7 +283,13 @@ class ScaleLine extends Control { ++i; } - const html = count + ' ' + suffix; + let html; + if (this.scaleBar_) { + html = this.createScaleBar(width, count, suffix); + } else { + html = count + ' ' + suffix; + } + if (this.renderedHTML_ != html) { this.innerElement_.innerHTML = html; this.renderedHTML_ = html; @@ -274,8 +306,125 @@ class ScaleLine extends Control { } } -} + /** + * @private + * @param {number} width The current width of the scalebar. + * @param {number} scale The current scale. + * @param {string} suffix The suffix to append to the scale text. + * @returns {string} The stringified HTML of the scalebar. + */ + createScaleBar(width, scale, suffix) { + let mapScale = Math.round(this.getScaleForResolution()); + mapScale = '1 : ' + mapScale.toLocaleString().replace(/,/g, '.'); + const scaleSteps = []; + const stepWidth = width / this.scaleBarSteps_; + let backgroundColor = '#ffffff'; + for (let i = 0; i < this.scaleBarSteps_; i++) { + if (i === 0) { + // create the first marker at position 0 + scaleSteps.push(this.createMarker('absolute', i)); + } + scaleSteps.push( + '