二三维地图比例尺制作
一、Openlayers比例尺
在二三维地图中如果要使用统一的比例尺控件,那么必然是使用openlayers中比例尺控件ol/control/ScaleLine
,没有用过的同学也可以去官方示例中去查询,下面是官方示例效果图:
官方示例代码如下:
import {ScaleLine} from 'ol/control.js';
const map = new Map({
layers: [
new TileLayer({
source: new OSM(),
}),
],
target: 'map',
view: new View({
projection: 'Indiana-East',
center: fromLonLat([-85.685, 39.891], 'Indiana-East'),
zoom: 7,
extent: transformExtent(
[-172.54, 23.81, -47.74, 86.46],
'EPSG:4326',
'Indiana-East'
),
minZoom: 6,
}),
});
map.addControl(new ScaleLine({units: 'us'}));
通过官方的代码不难看出,实际实现比例尺控件功能是非常的简单的,使用addControl加载比例尺控件就可以完成,不过样式并不是我们想要的,所以下面我们就来一起修改一下样式。
二、DOM元素相关类的封装
在修改比例尺样式之前,先对框架中二三维视图容器id
为map
的div
添加class
属性类名;下面进行第一步:通过ID获取Element,下面我们将document.getElementById
封装为一个类src/plugins/core/getElement.js
1、获取DOM元素模块
import DeveloperError from './DeveloperError.js';
/**
* If element is a string, look up the element in the DOM by ID. Otherwise return element.
*
* @private
*
* @exception {DeveloperError} Element with id "id" does not exist in the document.
*/
function getElement(element) {
if (typeof element === 'string') {
var foundElement = document.getElementById(element);
//>>includeStart('debug', pragmas.debug);
if (foundElement === null) {
throw new DeveloperError('id值 "' + element + '" 的元素在网页中未找到');
}
//>>includeEnd('debug');
element = foundElement;
}
return element;
}
export default getElement;
2、异常抛出模块
上面调用的src/plugins/core/DeveloperError.js
是封装了抛出代码中异常的一个类,代码如下:
import defined from './defined.js';
/**
* Constructs an exception object that is thrown due to a developer error, e.g., invalid argument,
* argument out of range, etc. This exception should only be thrown during development;
* it usually indicates a bug in the calling code. This exception should never be
* caught; instead the calling code should strive not to generate it.
* <br /><br />
* On the other hand, a {@link RuntimeError} indicates an exception that may
* be thrown at runtime, e.g., out of memory, that the calling code should be prepared
* to catch.
*
* @alias DeveloperError
* @constructor
* @extends Error
* @ignore
* @param {String} [message] The error message for this exception.
*
* @see RuntimeError
*/
function DeveloperError(message) {
/**
* 'DeveloperError' indicating that this exception was thrown due to a developer error.
* @type {String}
* @readonly
*/
this.name = 'DeveloperError';
/**
* The explanation for why this exception was thrown.
* @type {String}
* @readonly
*/
this.message = message;
//Browsers such as IE don't have a stack property until you actually throw the error.
var stack;
try {
throw new Error();
} catch (e) {
stack = e.stack;
}
/**
* The stack trace of this exception, if available.
* @type {String}
* @readonly
*/
this.stack = stack;
}
if (defined(Object.create)) {
DeveloperError.prototype = Object.create(Error.prototype);
DeveloperError.prototype.constructor = DeveloperError;
}
DeveloperError.prototype.toString = function() {
var str = this.name + ': ' + this.message;
if (defined(this.stack)) {
str += '\n' + this.stack.toString();
}
return str;
};
/**
* @private
*/
DeveloperError.throwInstantiationError = function() {
throw new DeveloperError('This function defines an interface and should not be called directly.');
};
export default DeveloperError;
3、Class属性管理模块
src/plugins/core/classManager.js
,主要是封装了对DOM元素添加修改与删除class属性的模块。
var classManager = {
addClass:function(obj, cls) {
if (!this.hasClass(obj, cls)) obj.className += " " + cls;
},
delClass:function(obj, cls) {
if (this.hasClass(obj, cls)) {
var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
obj.className = obj.className.replace(reg, ' ');
}
},
toggleClass:function(obj,cls){
if(this.hasClass(obj,cls)){
this.delClass(obj, cls);
}else{
this.addClass(obj, cls);
}
},
hasClass:function(obj, cls) {
return obj.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
}
}
export default classManager;
三、为三维容器窗口添加Class
现在我们已经将工具封装完成,然后在SworldMap.js
的构造函数中为我们的地图容器添加一个class属性
import classManager from './core/classManager';
function SworldMap(options) {
var projection = null;
if (options.initView) {
projection = options.initView.project ? options.initView.project : 'EPSG:3857'
} else {
projection = 'EPSG:3857'
}
var baseD2MapNormalUrl = this.getBase2DMapNormalUrls(projection);
var base2DMapSatelliteUrl = this.getBase2DMapSatelliteUrl(projection);
//默认参数的开关设置
>...
classManager.addClass(getElement(options.mapContainer), "SworldMap");
}
已经添加成功,可以在加载成功的地图中检查元素中进行查看。
四、比例尺样式修改
在上面的步骤中之所以大费周章的封装其一是为了让代码更加简洁,另外就是可以将一些能遇到的问题都统一整理到同一个模块中,如果产生异常也便于定位问题,那么我们通过给三维窗口添加class属性,我们可以对我们针对地图的样式进行统一的编写及管理。
那么说回比例尺样式的修改,由于官方示例中的比例尺线太细,所以我们要自己准备一个加粗边框的图片用来作为线框的背景。
在src/plugins
目录下新建styles
文件夹内容结构如下:
- plugins
- styles
- images
- border.png
main.css
- images
- styles
css文件在地图主模块SworldMap.js
中引用
import "./styles/main.css"
在main.css中对地图容器宽高进行设置,scaleLine为比例尺样式内容
html, body, #map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.SworldMap .scaleLine{
position: absolute;
bottom: 10px;
right: 10px;
height: 10px;
text-shadow: #fff 1px 0 0,#fff 0 1px 0,#fff -1px 0 0,#fff 0 -1px 0;
border: 4px solid #ffffff;
border-top: none;
border-image: url('./images/border.png') 26 26 round;
-moz-border-image: url('./images/border.png') 26 26 round; /* 老版本的 Firefox */
-webkit-border-image: url('./images/border.png') 26 26 round; /* Safari */
-o-border-image: url('./images/border.png') 26 26 round; /* Opera */
z-index: 9999 !important;
}
在地图主模块SworldMap.js
中的run
方法中我们将比例尺添加至地图中,并调整样式
import * as control from 'ol/control';
SworldMap.prototype.run = function(){
this._mapScene = new SworldScene(this._options);
this._mapScene.initMap();
//如果默认参数中模块中比例尺设置为显示的话则将比比例尺加载至二维地图
if (this._options.modules && this._options.modules.scaleLine) {
//加载至地图
this._mapScene.d2map.addControl(new control.ScaleLine);
//设置此div显示权重
document.getElementsByClassName('ol-overlaycontainer-stopevent')[0].style.zIndex = 999;
//修改比例尺中文字样式
var sl = document.getElementsByClassName('ol-scale-line-inner')[0];
sl.style.color = '#000000';
sl.style.font = '400 14px/0.875em Microsoft YaHei';
sl.style.lineHeight = '0px';
//对比例尺添加新的边框样式
sl.classList.add('scaleLine');
var bg = document.getElementsByClassName('ol-scale-line ol-unselectable')[0];
bg.style.background = 'none';
}
}
五、效果
二维中比例尺加载与三维中比例尺是同步的
三维比例尺同步显示
好了,本章内容已经完成了对二三维地图中比例尺同步的功能;如果大家觉得我的方法还有用的话,也请大家能够点赞鼓励一下,您的鼓励是我分享的动力,谢谢各位!