前言
前段时间我司领导让做个大屏的展现我的项目,因为我司的光荣传统,咱们并没有设计师,而后领导不晓得从哪找的一堆的大屏我的项目让我参考,于是看着花花绿绿的大屏我的项目,领导灵光乍泄选中了其中的两个,并对我说,“就用这个,不过你得改改”,“怎么改?”,“咱们的主色调用这个,把两头的中国地图换掉换成安徽的,而后做成这样加一个浮动框把这个信息添上去”,并且领导还贴心的给我配了一个阐明图。
于是最初,这个大屏的地图展现成了这样:
不过这都是后话了。于是我思考片刻决定,嗯,这个原我的项目原本不就是 echarts 做的吗,我也用 echarts 改吧改吧应该能够吧。OK,说干就干,我兴致冲冲的去下载 echarts 的官网地图包,而后
啊,这。。不过没有关系,尽管 echarts 的地图下载链接没有了,然而阿里云还是贴心的提供了矢量图地图下载的配置,我只有弄一个安徽的不就行了,这一步还是很顺利,然而新的问题又呈现了,echarts 的官网曾经找不到任何一个矢量地图的样例了。啊,这。没了参考,我怎么魔改呢,尽管直到我的项目做完了我才晓得还有一个民间保护的 makepie 外面有样例能够参考,不过这也是后话了。
过后的我悲喜交集,在调研了很多的我的项目计划后,最终我决定,据说阿里他们有套本人的可视化库,不行瞅瞅去,于是在看到 L7Plot 我晓得,我能够用它来实现这个计划了。
开干
L7plot 是阿里 Antv 系列里的一个我的项目,它基于 Antv L7 的库在这个库的根底上又做了一层封装,这个库在开发地图相干的一些可视化时十分不便。
块状地图展现
入门写的也很分明装置之后引入就能够了,那么接下来的问题是,我怎么把这个地图变成一个只有轮廓线的地图,并且让地图展现在安徽这个地位上,我看到了官网的一个例子,在我钻研了一番之后我明确了操作思路了,能够说 l7plot 的想法的确挺有意思,在它的 map 配置项里有一个 style 属性,当把它改成“blank”之后就能够显示为块状的地图,然而此时你只能看到一张中国地图的轮廓,怎么让窗口显示在安徽这个中央呢?这须要批改多个中央,首先还是要在 map 属性下,批改 center 的值,这是一个数组,数组中的两个值别离代表地图加载后显示在核心地位的坐标,这个坐标即位显示中的经纬度,如果你须要让一个省显示在核心,只有找到这个省大略的核心城市替换这个值就好,而刚好合肥的地位在安徽省的核心上,所以将合肥的经纬度替换一下就行。但此时地图加载完只是扭转了显示地位,安徽会显得比拟小,这时候须要批改 minZoom 来规定一个地图最小的放大范畴就能够了。
map: {
type: "mapbox",
style: "blank",
center: [117.30794, 31.79322],
minZoom: 3,
maxZoom: 7,
zoom: 1,
pitch: 0,
},
实现了上述操作之后你其实并不能看到任何成果,因为还有较为要害的一步,这个时候看下官网样例你会发现还有这样一个属性:
plots: [
{
...
viewLevel: {
level: 'country',
adcode: '100000',
},
没错,在 plots 里有一个 viewLevel 即展现层级,这里能够抉择国家,省份,城市,区县,adcode 则为对应的标号这个标号其实就是邮编,如果是省份须要找到显示城市的邮编,这些都能查到,合肥是 340000,替换一下这里的属性就能够了。
实现到这一步基本上就算胜利了,然而怎么实现最终成果的通明底色绿色边呢,那就是咱们前端都相熟 css 啦,将背景色设置为任意通明色彩,配合 style 属性批改款式设置边框等就实现了。
城市点的实现
接下来是数据的问题,依照参考图成果,我心愿给安徽各个城市用一个点标记进去,并且原点的大小是统一的。官网样例能够看到有大小随机的点散布在各个省份的省会城市上,它的代码是这样的:
fetch(`https://gw.alipayobjects.com/os/alisis/geo-data-v0.1.1/administrative-data/area-list.json`)
.then((response) => response.json())
.then((list) => {
const data = list
.filter(({level}) => level === 'province')
.map((item) => Object.assign({}, item, { value: Math.random() * 5000 }));
获取到一个区域的 json,判断这段 json 外面的级别如果是‘province’省份级别就随机一个大小的圆。剖析一下这个 json 的大略格局
能够发现,城市区县级别的值都有一个 parent 属性,这个属性表明了这个地点属于哪一个省份,那么我的操作很简略了,我只须要判断 parent 的值是 340000 就示意这个城市是属于安徽的,而后给它们一个雷同的圆点就好了。
const data = list
.filter(({parent}) => parent === 340000)
.map((item) => Object.assign({}, item, { value: 1500}));
剩下的欠缺一下细节就好了。
tooltip 的批改
最终要实现的成果是鼠标移入有一个浮动框外面展现很多的信息,这里便用到了官网的 tooltip 属性,但官网自带的属性是实现不了这样的成果的
这里便须要本人手动该革新了,在又看了官网文档等之后发现了能够自定义 tooltip:
tooltip: {offsets: [0, 100],
anchor: "center",
items: [{ field: "name", alias: "名称"},
{field: "value", alias: "随机数值"},
],
customContent(e, data) {return domTooltip(data);
},
anchor 是锚点的地位也就是 tooltip 展现的地位。个别设置为两头,offsets 用来设置 tooltip 间隔锚点的偏移值能够微调最终 tooltip 显示的地位,像我的这个展现比拟长,就要适当的往上偏一点。items 是须要展现的数据值,这里我临时还没用到。customContent 就比拟要害了,这里返回一个函数,函数里能够通过字符串拼接等模式放入本人定义的展现板,我这里目前还都是假数据:
const domTooltip = (items) => {
return `
<div class="corner-outer">
<div class="corner-inner">
<header class="header">
<span><i class="fa fa-laptop" aria-hidden="true"></i></span>
<strong>182.23.45.12</strong>
</header>
<section class="main">
<div class="main-flex">
<section><b class="title port"> 端口 </b></section>
<section>
<div class="relative-spans">
<strong>22</strong>
<span>FTP</span>
<span>HTTP</span>
</div>
<div class="relative-spans">
<strong>8000</strong>
<span>FTP</span>
<span>HTTP</span>
<span>FTP</span>
<span>HTTP</span>
</div>
</section>
</div>
<div class="main-flex">
<section><b class="title operate"> 操作 </b></section>
<section>
<div>
<span>Apache 2.1.1</span>
<span>Discuz 2.3x</span>
</div>
</section>
</div>
</section>
<div class="timeline">
<span class="btn up"><i class="fa fa-angle-up"></i> 历史事件 </span>
<ul>
<li class='work'>
<div class="relative">
<span class='date'>2009 年 5 月 </span>
<span class='circle'></span>
</div>
<div class='content'>
<section>
<em class="biao primary"><i class="fa fa-file"></i></em>
</section>
<section>
<div class="tags">
<strong>22</strong>
<span>FTP</span>
<span>HTTP</span>
<span>Apache 2.1.1</span>
<span>Discuz 2.3x</span>
</div>
</section>
</div>
</li>
<li class='work'>
<div class="relative">
<span class='date'>2010 年 4 月 </span>
<span class='circle'></span>
</div>
<div class='content'>
<section>
<em class="biao info"><i class="fa fa-laptop"></i></em>
</section>
<section>
<p> 十有九人堪白眼,百无一用是书生 </p>
</section>
</div>
</li>
</ul>
<span class="btn down"><i class="fa fa-angle-down"></i> 查看更多 </span>
</div>
</div>
</div>
`;
};
tooltip 的地位
到这里根本实现所有的性能,然而如果此时你把鼠标移到黄山这些偏视口下一点的城市你会发现 tooltip 展现不全,你须要通过拖动鼠标把城市往上挪一挪能力显示全。
这显然是不合理的,这个时候就须要用到 L7plot 自带的一些事件了,持续通过查阅文档我找到了解决办法,利用官网的 mousemove 事件,在鼠标移入时获取鼠标本身在视口的坐标,这个值通过返回的 point 属性能够获取,同时取得 tooltip 绝对于视口的坐标,这个坐标值在官网返回的属性里plot.plots[1].tooltip.options.offsets,offsets 这个数组中第一项示意 x 轴地位,第二项示意 y 轴地位,因为我的视口宽度是固定的 600px,所以只有判断鼠标的落点 x 值大于 300 就让 tooltip 向左偏,否则都是向右偏。
plot.on("mousemove", (event) => {
event.point.x > 300
? (plot.plots[1].tooltip.options.offsets[0] = -260)
: (plot.plots[1].tooltip.options.offsets[0] = 20);
plot.plots[1].tooltip.options.offsets[1] = event.point.y;
});
最终就能够实现一个繁难的判断了。
不足之处
页面首次加载的时候因为提早,安徽地图会处于一个很小的地位,待齐全加载实现后能力显示,这个前期能够通过加个 loading 异步什么的简略解决。
因为是地图模式,所以会显示出国境线,这个疑难并不影响整体展现临时没去想怎么去掉,我也不晓得能不能去掉。
残缺代码
<template>
<div id="anhui" style="height: 510px; justify-content: center; position: relative"></div>
</template>
<script setup>
import {onMounted, nextTick} from "vue";
import {L7Plot} from "@antv/l7plot";
import list from "../../assets/data/area-list.json";
const domTooltip = (items) => {
let ps = ``;
items.forEach((item) => {ps += `<p>${item.name}: ${item.value}</p>
<li class='work'>
<div class="relative">
<span class='date'>2009 年 8 月 </span>
<span class='circle'></span>
</div>
<div class='content'>
<section>
<em class="biao danger"><i class="fa fa-exclamation-triangle"></i></em>
</section>
<section>
<p> 从久远的观点看问题,真正弱小的力量不是属于反动派,而是属于人民 </p>
</section>
</div>
</li>
`;
});
return `
<div class="corner-outer">
<div class="corner-inner">
<header class="header">
<span><i class="fa fa-laptop" aria-hidden="true"></i></span>
<strong>182.23.45.12</strong>
</header>
<section class="main">
<div class="main-flex">
<section><b class="title port"> 端口 </b></section>
<section>
<div class="relative-spans">
<strong>22</strong>
<span>FTP</span>
<span>HTTP</span>
</div>
<div class="relative-spans">
<strong>8000</strong>
<span>FTP</span>
<span>HTTP</span>
<span>FTP</span>
<span>HTTP</span>
</div>
</section>
</div>
<div class="main-flex">
<section><b class="title operate"> 操作 </b></section>
<section>
<div>
<span>Apache 2.1.1</span>
<span>Discuz 2.3x</span>
</div>
</section>
</div>
</section>
<div class="timeline">
<span class="btn up"><i class="fa fa-angle-up"></i> 历史事件 </span>
<ul>
<li class='work'>
<div class="relative">
<span class='date'>2009 年 5 月 </span>
<span class='circle'></span>
</div>
<div class='content'>
<section>
<em class="biao primary"><i class="fa fa-file"></i></em>
</section>
<section>
<div class="tags">
<strong>22</strong>
<span>FTP</span>
<span>HTTP</span>
<span>Apache 2.1.1</span>
<span>Discuz 2.3x</span>
</div>
</section>
</div>
</li>
<li class='work'>
<div class="relative">
<span class='date'>2010 年 4 月 </span>
<span class='circle'></span>
</div>
<div class='content'>
<section>
<em class="biao info"><i class="fa fa-laptop"></i></em>
</section>
<section>
<p> 十有九人堪白眼,百无一用是书生 </p>
</section>
</div>
</li>
</ul>
<span class="btn down"><i class="fa fa-angle-down"></i> 查看更多 </span>
</div>
</div>
</div>
`;
};
let plot = null;
const initMap = async () => {
const data = list
.filter(({parent}) => parent === 340000)
.map((item) => Object.assign({}, item, { value: 1500}));
plot = new L7Plot("anhui", {
map: {
type: "mapbox",
style: "blank",
center: [117.30794, 31.79322],
minZoom: 3,
maxZoom: 7,
zoom: 1,
pitch: 0,
},
plots: [
{
type: "choropleth",
zIndex: 1,
source: {data: [],
joinBy: {
sourceField: "code",
geoField: "adcode",
},
},
viewLevel: {
level: "province",
adcode: "340000",
},
autoFit: true,
color: "rgba(255,255,255,0)",
style: {
opacity: 1,
stroke: "rgb(20,112,80)",
lineWidth: 0.6,
lineOpacity: 0.8,
},
label: {
visible: true,
field: "name",
style: {// fill: "rgb(19,134,72)",
opacity: 0.8,
fontSize: 14,
stroke: "rgb(19,134,72)",
strokeWidth: 1,
textAllowOverlap: false,
padding: [5, 5],
textOffset: [0, 40],
},
},
},
{
type: "dot",
zIndex: 2,
source: {
data: data,
parser: {type: "json", x: "lng", y: "lat"},
},
color: "rgba(84, 229, 229, 0.9)",
size: {
field: "value",
value: ({value}) => value / 200,
},
style: {
opacity: 0.7,
stroke: "rgba(255,255,255,0.5)",
strokeWidth: 1,
},
tooltip: {offsets: [0, 100],
anchor: "center",
items: [{ field: "name", alias: "名称"},
{field: "value", alias: "随机数值"},
],
customContent(e, data) {return domTooltip(data);
},
},
},
],
layers: [],});
await nextTick();
document.querySelector(".l7-control-logo").remove();};
onMounted(() => {initMap();
plot.on("mousemove", (event) => {
event.point.x > 300
? (plot.plots[1].tooltip.options.offsets[0] = -260)
: (plot.plots[1].tooltip.options.offsets[0] = 20);
plot.plots[1].tooltip.options.offsets[1] = event.point.y;
});
});
</script>
<style lang="scss">
</style>