maptalks开发手册——自定义图标mark、测距、测面、绘制工具、地图动画、动画效果、聚合、热力图、3D

maptalks开发手册——自定义图标mark、测距、测面、绘制工具、地图动画、动画效果、聚合、热力图、3D-three.js以及分块和事件等功能

客户需要的效果千姿百态,但也不可逃离的是功能性的变化。

下面的例子基于上一遍的例子进行

实际应用中的创建与消除

在实际应用中,mark标记,是随着用户选择的类型进行显示,那么这涉及到了mark的消除与创建。

我们先定义一个页面,如下,在地图上方留一个工具栏

<template>

<div>

<div>

<el-checkbox-group v-model="checkList" @change="handleCheckChange">

<el-checkbox :label="item.label" v-bind:key="item.value" :value="item.value" v-for="item in chooseData"></el-checkbox>

</el-checkbox-group>

</div>

<div

id="map"

/>

</div>

</template>

<style scoped>

html, body {

margin: 0px;

height: 100%;

width: 100%;

}

.container {

width: 100%;

height: 100%;

position: absolute

}

.map-toolbar {

position: relative;

z-index: 1000;

width: 500px;

height: 50px;

float: right;

top:10px;

right: 300px;

background-color: #fff;

border-radius:5px;

padding: 10px;

}

.map-container {

width: 100%;

height: 100%

}

</style>

效果不知道怎么传视频。代码已竟可能全了,没有全贴是不想占太多空间;

这里说一下,它的一些方法

layer.clear() ,他会清除图层上的所以东西;

mark.remove() , 移除mark可以用这个,不过这个需要mark对象调用,如果前端要实现上述功能,那么就要保存mark列表,这个很不明智,遇到撒点多的时候,这个前端可能承受不了;所以这里缓存了每个类型的图层,使用图层进行操作;

自定义图标

这里就以vue的logo作为替换图标进行示例

顶部require引入静态资源

const logo = require('../../assets/logo.png')

// 创建时,使用symbol替换默认的样式

const mark = new maptalks.Marker(d.center, {

symbol: {

// markerType: 'square',

markerFile: logo,

markerWidth: 40,

markerHeight: 40,

markerDx: 0,

markerDy: 0,

markerOpacity: 1

},

properties: {

// 高度设置

altitude: 0

}

}).addTo(layer)

这里markerFile才是替换图标的,markerType,marker类型,它表示的是什么样的图标,当你有markerFile属性时,它是覆盖不了的,没有markerFile时,可以以markerType进行显示,它有几种类型:ellipse cross x diamond bar square triangle pin pie,效果可以自己设置一下看看。

增加动画效果

增加了自己的mark后,可能会要求视觉上的一些效果,mark也提供了animate的方法设置自己的动画,那么我们就设置一个mark出现时的动画,vue logo的横向展开,

在上面代码的基础上增加下面代码,然后将new maptalks.Marker里默认设置的symbol.markerHeight设置为0, symbol.markerWidth设置为10,表示初始高度0, 初始宽度10,,变换到高度40, 宽度40。

当我们点击学校或医院选项时,这些撒点就自动展开,也可以增加监听,在每个动画阶段都可以做一些处理。

完整的代码:

drawMark(centerPointList, layer) {

if (!centerPointList) {

console.log('无区域中心点数据')

return

}

const info = { content: '', width: 150, minHeight: 100 }

const result = []

// 这里 d 的数据格式是数组,如:[-0.113049, 51.498568]

centerPointList.forEach(d => {

if (!d.info) {

d.info = info

}

// 设有高度、高亮的mark

const mark = new maptalks.Marker(d.center, {

symbol: {

markerType: 'square',

markerFile: logo,

markerWidth: 10,

markerHeight: 0,

markerDx: 0,

markerDy: 0,

markerOpacity: 1

},

properties: {

// 高度设置

altitude: 0

}

}).addTo(layer)

mark.setInfoWindow({

title: d.name,

content: '<div>' + d.adcode + '</div>',

// autoPan: true,

width: d.info.width,

minHeight: d.info.minHeight,

})

mark.animate({

symbol: {

markerWidth: 40,

markerHeight: 40

},

properties: {

altitude: 800

}

}, {

duration: 150,

}, function (frame) {

if (frame.state.playState === 'finished') {

console.log('animation finished');

}

});

mark.setZIndex(1000)

result.push(mark)

})

return result

},

可以看到,在一开始创建mark对象时,设置的宽度width只有10,这就是动画的开始宽度,之后在animate方法里设置的属性就是需要变化的属性,也是最终的属性,通过duration控制动画的执行的时间.

工具

这里基本都是symbol,那么这里还是要再提一次,就是symbol,涉及这个属性的,我们都可以去查它的文档,因为它是一个系统,都是统一的完整的;

下面的相关属性注释第一个比较全,后面的差不多,所以不会都标注

测距工具

API: Class: DistanceTool (maptalks.org)

距离测算,复制官方案例,进行稍微修改,增加结束事件,

/**

* 测距工具

* @returns {*}

*/

addDistanceTool () {

return new maptalks.DistanceTool({

symbol: {

lineColor: '#34495e',

lineWidth: 2

},

// 请看 symbol属性说明文档:https://github.com/maptalks/maptalks.js/wiki/Symbol-Reference

// 绘制的线的样式

vertexSymbol: {

// 绘制的marker类型,也就是简单形状,支持:ellipse cross x diamond bar square triangle pin pie

markerType: 'square',

// 绘制的marker的填充色

markerFill: '#1bbc9b',

// 绘制的线的颜色

markerLineColor: '#000',

// 绘制的线的宽度

markerLineWidth: 1,

// 绘制的marker大小

markerWidth: 10,

markerHeight: 10

},

// 文本标签属性

labelOptions: {

textSymbol: {

// 文本呈现的样式,默认是: monospace, 当你设置 textFont时会覆盖这个属性

textFaceName: 'monospace',

// 文本填充色(字体颜色)

textFill: '#fff',

// 行距

textLineSpacing: 1,

// 对齐方式

textHorizontalAlignment: 'right',

// 文本标签与marker的距离,也就是与打点的位置的距离

textDx: 20,

// 标签的线的颜色

markerLineColor: '#b4b3b3',

// 标签的填充色

markerFill: '#000'

},

boxStyle: {

// 标签的padding, 第一个值是左右的padding,第二个是上下的padding

padding: [6, 5],

symbol: {

// 绘制的marker类型,也就是简单形状,支持:ellipse cross x diamond bar square triangle pin pie

markerType: 'square',

markerFill: '#000',

markerFillOpacity: 0.9,

markerLineColor: '#b4b3b3'

}

}

},

// 清楚按钮的symbol

clearButtonSymbol: [{

markerType: 'square',

markerFill: '#000',

markerLineColor: '#b4b3b3',

markerLineWidth: 2,

markerWidth: 15,

markerHeight: 15,

markerDx: 20

}, {

markerType: 'x',

markerWidth: 10,

markerHeight: 10,

markerLineColor: '#fff',

markerDx: 20

}],

language: 'zh-CN',

once: true

}).addTo(this.mapEngine)

.on('drawend', p => {

console.log('地图坐标:' + p.coordinate)

console.log('界面坐标:' + p.containerPoint)

console.log('测量距离:' + p.drawTool.getLastMeasure() + '米')

})

},

增加工具按钮:

这里增加了测距按钮,在点击时激活测绘过年过节,再次点击时,关闭测绘

上面这个功能是,在点击测距后开启测距模式,但也有的情况下是,点击一次按钮,测一次,这个在这里也是可以实现的,maptalks提供了这样的api,只需要在options里增加“onece”属性,并为true就行了。

/**

* 测距工具

* @returns {*}

*/

addDistanceTool () {

return new maptalks.DistanceTool({

// ... 省略

language: 'zh-CN',

// 只测绘一次

once: true

}).addTo(this.mapEngine)

.on('drawend', p => {

console.log('地图坐标:' + p.coordinate)

console.log('界面坐标:' + p.containerPoint)

console.log('测量距离:' + p.drawTool.getLastMeasure() + '米')

})

}

如上配置的话,在addToolbar这个方法里,我们也不需要修改,因为,这个onece的属性,在一次测绘后,也是禁用的,所以,我们addToolbar里的方法还是可以延用。

绘制工具

同样,可以直接把官方demo拿过来改改。

/**

* 绘制工具

*/

addDrawTool (layer) {

const drawTool = new maptalks.DrawTool({

mode: 'Point'

}).addTo(this.mapEngine)

// 默认是禁用的,当点击按钮后才能使用

.disable()

drawTool.on('drawend', function (param) {

layer.addGeometry(param.geometry)

})

this.drawTool = drawTool

return drawTool

}

/**

*增加绘制工具栏

*/

addDrawToolbar (layer) {

const _t = this

const items = [{code: 'Point', name: '点'},

{code: 'LineString', name: '线'},

{code: 'Polygon', name: '几何面'},

{code: 'Circle', name: '圆'},

{code: 'Ellipse', name: '椭圆'},

{code: 'Rectangle', name: '矩形'},

{code: 'FreeHandLineString', name: '自由绘制'},

{code: 'FreeHandPolygon', name: '任意几何面'}]

.map(function (value) {

return {

item: value.name,

click: function () {

_t.drawTool.setMode(value.code).enable()

}

}

})

new maptalks.control.Toolbar({

position: {

top: 100,

right: 50

},

items: [

{

item: '绘制工具',

children: items

},

{

item: '禁用',

click: function () {

_t.drawTool.disable()

}

},

{

item: '清除',

click: function () {

layer.clear()

}

}

]

}).addTo(this.mapEngine)

},

测面工具

另一个工具也是一个比较有面子的工具:

/**

* 测面工具

*/

addAreaTool () {

const areaTool = new maptalks.AreaTool({

once: true,

// 请看 symbol属性说明文档:https://github.com/maptalks/maptalks.js/wiki/Symbol-Reference

symbol: {

lineColor: '#1bbc9b',

lineWidth: 2,

polygonFill: '#fff',

polygonOpacity: 0.3

},

vertexSymbol: {

// 绘制的marker类型,也就是简单形状,支持:ellipse cross x diamond bar square triangle pin pie

markerType: 'ellipse',

// 绘制的marker的填充色

markerFill: '#34495e',

// 绘制的线的颜色

markerLineColor: '#1bbc9b',

// 绘制的线的宽度

markerLineWidth: 3,

// 绘制的marker大小

markerWidth: 10,

markerHeight: 10

},

// 文本标签属性

labelOptions: {

textSymbol: {

// 文本呈现的样式,默认是: monospace, 当你设置 textFont时会覆盖这个属性

textFaceName: 'monospace',

// 文本填充色(字体颜色)

textFill: '#fff',

// 行距

textLineSpacing: 1,

// 对齐方式

textHorizontalAlignment: 'right',

// 文本标签与marker的距离,也就是与打点的位置的距离

textDx: 15

},

boxStyle: {

// 标签的padding, 第一个值是左右的padding,第二个是上下的padding

padding: [6, 2],

symbol: {

markerType: 'square',

markerFill: '#000',

markerFillOpacity: 0.9,

markerLineColor: '#b4b3b3'

}

}

},

clearButtonSymbol: [{

markerType: 'square',

markerFill: '#000',

markerLineColor: '#b4b3b3',

markerLineWidth: 2,

markerWidth: 15,

markerHeight: 15,

markerDx: 22

}, {

markerType: 'x',

markerWidth: 10,

markerHeight: 10,

markerLineColor: '#fff',

markerDx: 22

}],

language: 'zh-CN'

}).addTo(this.mapEngine)

// 默认关闭

areaTool.disable()

this.areaTool = areaTool

return areaTool

}

绘制工具栏里,添加这个菜单;

{

item: '测面工具',

click: function () {

if (_t.areaTool.isEnabled()) {

_t.areaTool.disable()

} else {

_t.areaTool.enable()

}

}

},

地图动画

如果,你的页面一打开,镜头由上到下,慢慢的,360度旋转后定位到指定为,然后图标跳出来,这样的一个效果,一定是能够俘获大部分的心的。

在maptalks里也提供了api,我们也只是调用一下:

/**

* 地图动画

*/

mapAnimate () {

const _t = this

_t.mapEngine.animateTo({

center: [118.13245430046891, 24.495713873147764],

zoom: 13,

pitch: 0,

bearing: 20

}, {

duration: 5000

})

setTimeout(function () {

_t.mapEngine.animateTo({

center: [118.087828, 24.462059],

zoom: 14,

pitch: 65,

bearing: 360

}, {

duration: 7000

})

}, 5000)

}

这个我们软件,截不了 动图,这个可也代码跑一下就行;

而一般会带上marker,marker也是动画的,两个合起来一看就是比较完美的。

所以,我这里把上面做的学校和医院的功能,拿下来,组合一下:

/**

* 地图动画

*/

mapAnimate () {

const _t = this

_t.mapEngine.animateTo({

center: [118.13245430046891, 24.495713873147764],

zoom: 13,

pitch: 0,

bearing: 20

}, {

duration: 5000

})

setTimeout(function () {

_t.mapEngine.animateTo({

center: [118.087828, 24.462059],

zoom: 14,

pitch: 65,

bearing: 360

}, {

duration: 7000

})

}, 5000)

// 在地图动画块结束时,撒点动画加入,并设置默认值

setTimeout(function () {

_t.checkList = []

_t.checkList.push('学校')

_t.handleCheckChange(_t.checkList)

}, 9000)

}

我再增加了一个播放按钮,可以重复播放,恩。没有软件,没有gif.

聚合

聚合这个功能也不得不说,所有的地图设计到缩放,都会有这个功能。

这个单靠maptalks是有点难的,但是用maptalks的好处就是,它有很多插件,所有这个聚合功能我们也用插件来实现:

文档: GitHub - maptalks/maptalks.markercluster: A layer of maptalks to cluster markers.

引入插件:

npm install maptalks.markercluster

使用如下;

import * as maptalks from 'maptalks'

import {ClusterLayer} from 'maptalks.markercluster'

我们将之前写的marker页面修改下:

这次我们创建的图层是markercluster,会有些不一样,我们只将图层创建方式变更一下,相应注释我也添加了,再看代码会比较清晰些。

这里的symbol,我没有写全,一是直接复制官网的,二是懒了,它和其他的symbol是一样的,都可以复制的。

// 先创建图层

// 创建学校和医院的mark图层

// new maptalks.VectorLayer('schoolMark').addTo(_t.mapEngine)

// new maptalks.VectorLayer('hospitalMark').addTo(_t.mapEngine)

const symbol = {

// 聚合最大半径

maxClusterRadius: 160,

// 聚合的最大缩放比例,也就是当缩放到某一个层级时,进行聚合

maxClusterZoom: 19,

// 是否开启动画,默认true(开启)

animation: true,

// 动画时长

animationDuration: 30,

// textSumProperty: '',

// 这里的属性,可以看官网,都是统一的

// symbol: {},

textSymbol: {

// 文本呈现的样式,默认是: monospace, 当你设置 textFont时会覆盖这个属性

textFaceName: 'monospace',

// 字体大小

textSize: 16

}

}

new ClusterLayer('schoolMark', symbol).addTo(this.mapEngine)

new ClusterLayer('hospitalMark', symbol).addTo(this.mapEngine)

addMarker方法修改:

drawMark (centerPointList, layer) {

if (!centerPointList) {

console.log('无区域中心点数据')

return

}

const info = {content: '', width: 150, minHeight: 100}

const result = []

// 这里 d 的数据格式是数组,如:[-0.113049, 51.498568]

centerPointList.forEach(d => {

if (!d.info) {

d.info = info

}

// 设有高度、高亮的mark

const mark = new maptalks.Marker(d.center, {

symbol: {

markerType: 'square',

markerFile: logo,

markerWidth: 10,

markerHeight: 0,

markerDx: 0,

markerDy: 0,

markerOpacity: 1

},

properties: {

// 高度设置

altitude: 0

}

})

mark.setInfoWindow({

title: d.name,

content: '<div>' + d.adcode + '</div>',

// autoPan: true,

width: d.info.width,

minHeight: d.info.minHeight

})

mark.animate({

symbol: {

markerWidth: 40,

markerHeight: 40

},

properties: {

altitude: 800

}

}, {

duration: 150

}, function (frame) {

if (frame.state.playState === 'finished') {

console.log('animation finished')

}

})

mark.setZIndex(1000)

result.push(mark)

})

layer.addMarker(result)

return result

},

热力图

热力图,它是集成了heatmap.js

增加热力图层插件

npm install maptalks.heatmap

添加方式也是它的一个方式,它的数据是一个坐标数组,自己变量添加就行,这里就把做

// 获取热力点

const h1 = []

for (let i = 0; i < simingAreaData.length; i++) {

const s = simingAreaData[i]

s.pointList.forEach(ss => {

ss.forEach(sss => {

sss.push(i + '100')

h1.push(sss)

})

})

}

// 创建图层

new HeatLayer('heat', h1, {

// 热力比例(我的理解是,在0-1之间,也就是0-100%,一个热力点,的热力程度是多少

heatValueScale: 0.7,

// 旋转时强制刷新

forceRenderOnRotating: true,

// 移动时强制刷新

forceRenderOnMoving: true,

// 模糊因子, 值越大,越平滑,默认值是15

// blur: 20,

// 每个数据点的半径(默认值25,也建议25,我建议不能小于20)

// radius: 25,

// 最小不透明读,越小越透明

// minOpacity: 0.8,

// 热力梯度,是热力点外围的颜色值,从外围到里,值是递增的,最大值就是中心的位置

// gradient: {

// 0.4: 'blue',

// 0.6: 'cyan',

// 0.7: 'lime',

// 0.8: 'yellow',

// 1.0: 'red'

// }

}).addTo(this.mapEngine)

首先要了解一下热力的呈现方式

以点为中心向外渐变;

多个点可以叠加,或多个点在聚集在一起,呈现出面;

每个点的显示是一样的,都有一个热力梯度,就是从外到内的一个颜色变化(从浅到什);

所以它和上面的几何不一样,几何需要3个点以上,而热力图最少只需要一个:

上面代码也对热力属性进行了标注:

heatValueScale: 这个值的作用不是很理解,

forceRenderOnRotating:旋转时强制刷新

forceRenderOnMoving:移动时强制刷新

blur:模糊因子, 值越大,越平滑,默认值是15

radius:每个数据点的半径(默认值25,也建议25,我建议不能小于20)

minOpacity:最小不透明读,越小越透明

gradient:热力梯度,是热力点外围的颜色值,从外围到里,值是递增的,最大值就是中心的位置

上述值都有默认配置,可以直接使用,也可以自定义;

评论可见,查看隐藏内容

na.png

本网站文章未经允许禁止转载,合作/权益/投稿 请联系平台管理员 Email:epebiz@outlook.com