Custom map controls
Quick answer
This tutorial builds OpenLayers UI widgets by extending ol.control.Control and distinguishing them from interactions. It constructs a DOM element, passes it through the element option, applies ol-unselectable and ol-control classes, and registers a bound click handler. It then overrides setMap to subscribe and unsubscribe from moveend, converts resolution with ol.proj.getPointResolution, and mounts the control in an external toolbar. Readers can add maintainable custom controls.
Key points
- Add ol-unselectable so drag and zoom gestures do not fire through the control.
- Unbind the previous listener with ol.Observable.unByKey before re-registering in setMap.
- Use ol.proj.getPointResolution to show true ground metres per pixel.
Example
class BaseSwitcher extends ol.control.Control {
constructor(opt_options) {
const options = opt_options || {};
const button = document.createElement('button');
button.type = 'button';
button.className = 'base-switcher-btn';
button.textContent = '切换底图';
button.title = '在影像与街道底图之间切换';
const element = document.createElement('div');
element.className = 'base-switcher ol-unselectable ol-control';
element.appendChild(button);
super({ element: element, target: options.target });
this.onToggle_ = options.onToggle;
button.addEventListener('click', this.handleClick_.bind(this), false);
}
handleClick_(event) {
event.preventDefault();
if (this.onToggle_) this.onToggle_();
}
}
var switcher = new BaseSwitcher({
onToggle: function () {
var usingImagery = map.getLayers().item(0).get('name') === 'imagery';
map.getLayers().setAt(0, usingImagery ? streetLayer : imageryLayer);
}
});
map.addControl(switcher);class ResolutionReadout extends ol.control.Control {
constructor() {
const element = document.createElement('div');
element.className = 'resolution-readout ol-unselectable';
super({ element: element });
this.element_ = element;
this.moveKey_ = null;
}
setMap(map) {
if (this.moveKey_) {
ol.Observable.unByKey(this.moveKey_);
this.moveKey_ = null;
}
super.setMap(map);
if (!map) return;
this.moveKey_ = map.on('moveend', this.update_.bind(this));
this.update_();
}
update_() {
const map = this.getMap();
if (!map) return;
const view = map.getView();
const mpp = ol.proj.getPointResolution(
view.getProjection(), view.getResolution(), view.getCenter()
);
this.element_.textContent = '1 像素 ≈ ' + mpp.toFixed(1) + ' 米';
}
}
map.addControl(new ResolutionReadout());
Notes
- Anonymous arrow callbacks cannot be removed when the control is detached.
- Overriding .ol-control styles affects every built-in control on the page.
English edition written for Atlaslog. Code is taken from the original Chinese page and runs unchanged.
Atlaslog (2026). Custom map controls. https://www.jingweizhi.com/en/openlayers/tutorials/custom-control.html (accessed 2026-11-03).