本文已参与「新人创作礼」活动,一起开启掘金创作之路。
目录
和以往的项目进行对比,添加了一些新的东西,这里总结一下(后续更新):
使用到的技术栈 | ||
vue-cli3 | ||
vue-router | ||
Apache ECharts | ||
DataV | ||
[蚂蚁地理空间数据可视化 | L7](l7.antv.vision/zh "蚂蚁地理空间数据可视化 | L7") |
使用json模拟数据结构 |
引入dataV
npm install @jiaminghi/data-view
main.js中需要引入以下安装包
import router from "./router";
import dataV from "@jiaminghi/data-view";
import "./plugins/wyz-echarts/wyz-echarts.js";
Vue.use(dataV);
用L7里面的东西可以通过页面进行局部引入
import { Scene, PointLayer, Popup } from "@antv/l7";
import { GaodeMap } from "@antv/l7-maps";
引入地图L7地图:
首先需要一个容器来包裹这个全屏的大地图
<div id="userMap"></div>
安装L7(里面包含了地图)
npm install --save @antv/l7
L7相关概念
构造函数Scene
const scene = new Scene({
id: "userMap", // 需传入 dom 容器或者容器 id
logoVisible:false, // 关闭L7的logo
map: new GaodeMap({
pitch: 0,// pitch 地图倾角
style: "dark", //地图样式,L7内置了三种主体默认样式,dark,light,normal
mapStyle: "amap://styles/darkblue",
center: [113.631419, 34.753439], // center 地图中心
zoom: 5, // 地图初始显示级别 {number} Mapbox (0-24) 高德 (2-19)
token: "ced0d726cd96553ba8b5b3521671aaf4",
}),
});
打印构造函数的结构 ,如下图所示:
PointLayer
点数据的展示,根据经纬点绘制图形,数据源支持 JSON、GeoJSON、CSV 三种数据格式。
基本用法
const pointLayer = new PointLayer({ zIndex: 1 }) // zIndex的作用:图层绘制顺序,数值大绘制在上层,可以控制图层绘制的上下层级
.source(cityData.data.cityList, {
parser: {
type: "json",
x: "longitude", //lng
y: "latitude", //lat
},
})
.shape("square") //shape 类型 //'simple', 'circle', 'square', 'hexagon', 'triangle', 'pentagon', 'octogon', 'hexagram','rhombus', 'vesica',
.animate(true)
.size("count", [0, 45]) // 使用字段映射到大小,并指定最大值和最小值
.color("count", ["#3CA0FF", "#3CA0FF", "#3CA0FF"]) //将数据值映射到图形的颜色上的方法。
.active(true)
.style({
opacity: 0.5, //opacity 设置透明度 大部分图层都支持
/* stroke 线填充颜色 仅点图层支持 */
strokeWidth: 0, //strokeWidth 线的宽度 仅点图层支持
});
shape 类型
'simple', 'circle', 'square', 'hexagon',
'triangle', 'pentagon', 'octogon',
'hexagram','rhombus', 'vesica'
style
类似于这种效果
城市气泡:(使用canvas划出气泡)
// 用户城市气泡
initUserPopover(arrList) {
let canvas = document.getElementById("cityPopover");
let ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
//填充画布
ctx.lineWidth = 8;
let beginDeg = Math.PI * 1.5;
let endDeg = Math.PI * 1.5;
arrList.forEach((t, index) => {
t.percentageData.forEach((l) => {
endDeg = beginDeg + 2 * Math.PI * l.value;
ctx.beginPath();
ctx.strokeStyle = l.color;
ctx.arc(60, 60, t.radius, beginDeg, endDeg, false);
ctx.stroke();
beginDeg = endDeg;
ctx.closePath();
ctx.moveTo(0, 0); //移动笔触到原点
ctx.fillStyle = "white"; //文本颜色
ctx.font = "12px normal ";
ctx.textAlign = "right";
ctx.fillText(`${(t.value * 100).toFixed(1)}%`, 55, (index + 1) * 16);
});
});
},
效果如下:
tips:(这里是一个样式,可以直接通过.tips修改器样式)
地图事件
scene.on('loaded', () => {}); //地图加载完成触发
scene.on('mapmove', () => {}); // 地图平移时触发事件
scene.on('movestart', () => {}); // 地图平移开始时触发
scene.on('moveend', () => {}); // 地图移动结束后触发,包括平移,以及中心点变化的缩放。如地图有拖拽缓动效果,则在缓动结束后触发
scene.on('zoomchange', () => {}); // 地图缩放级别更改后触发
scene.on('zoomstart', () => {}); // 缩放开始时触发
scene.on('zoomend', () => {}); // 缩放停止时触发
Popup信息框
地图标注信息窗口,用于展示地图要素的属性信息
option
- closeButton 是否显示关闭按钮,布尔值,默认为 true。
- closeButtonOffsets 显示关闭按钮时生效,[number, number],默认为 [0, 0],以右上角为起始点。
- closeOnClick 是否在点击地图的时候关闭弹框,布尔值,默认为 true
- maxWidth 弹框最宽值,默认为 240px
- anchor 弹框锚点,默认值为 bottom,可选值有 center、top、top-left、left、bottom-left、bottom、bottom-right、right、top-right
- offsets
Array
偏移量 [ 0, 0 ] 分别表示 X, Y 的偏移量
方法:setLnglat
设置 popup 的经纬度位置
支持数组
[112, 32];
经纬度对象
const lnglat = {
lng: 112.323,
lat: 30.456,
};
popup.setLnglat([112, 32]);
方法:setDOMContent
- 参数 htmlNode dom 对象 区别于 setHtml 对象只能传字符串
全屏效果实现
给图片设置点击事件
<img class="full-img" @click="showFullScreen" src="@/assets/fullscreen.png" alt="" />
// 全屏
showFullScreen () {
let element = document.documentElement
if (this.fullscreen) {
if (document.exitFullscreen) {
document.exitFullscreen()
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen()
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen()
} else if (document.msExitFullscreen) {
document.msExitFullscreen()
}
} else {
if (element.requestFullscreen) {
element.requestFullscreen()
} else if (element.webkitRequestFullScreen) {
element.webkitRequestFullScreen()
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen()
} else if (element.msRequestFullscreen) {
// IE11
element.msRequestFullscreen()
}
}
this.fullscreen = !this.fullscreen
},
数字翻牌器效果实现
<span :class="[{'flop-figure': !isNaN(ls)}, {'flop-comma': isNaN(ls)}]" v-for="(ls, index) in item.valueArr" :key="item.id + index">
<i v-if="!isNaN(ls)">0123456789</i>
<span v-else>{{ls}}</span>
</span>
// 数字翻牌器效果
.flop-figure {
position: relative;
display: flex;
font-size: 36px;
width: 23px;
height: 100%;
color: #4a90e2;
line-height: 23px;
overflow: hidden;
writing-mode: vertical-lr;
text-orientation: upright;
i {
position: absolute;
font-style: normal;
transition: transform 0.6s ease-in-out;
letter-spacing: 10px;
}
}
this.timedRefresh(this.cityInfoList, "city"); //重复刷新数字翻牌器
// 设置文字滚动
setNumberTransform(item) {
const numberItems = document.querySelectorAll(`.${item.id} i`);
// const numberItems = this.$refs[`${item.id}`]
const numberArr = item.valueArr.filter((item) => !isNaN(item));
numberItems.forEach((t) => {
t.style.transition = "transform 0s ease-in-out";
t.style.transform = `translateY(-0%)`;
});
setTimeout(() => {
numberItems.forEach((ls, index) => {
ls.style.transition = "transform 0.8s ease-in-out";
ls.style.transform = `translateY(-${numberArr[index] * 10}%)`;
});
}, 15);
},
// 刷新数字翻牌器
timedRefresh(targetList, type) {
let cityTimer;
let userTimer;
let deviceTimer;
if (type === "city") {
cityTimer = this.initInterval(targetList, 1000);
}
this.$once("hook:beforeDestroy", () => {
clearInterval(cityTimer);
clearInterval(userTimer);
clearInterval(deviceTimer);
userTimer = null;
cityTimer = null;
deviceTimer = null;
});
},
// 定时
initInterval (targetList, time) {
const { setNumberTransform } = this
return setInterval((function fn(){
targetList.forEach(t => {
setTimeout(() => {
setNumberTransform(t)
}, 50)
})
return fn
})(), time)
},
因为受全屏影响,这里要在mounted生命周期中来删除监听到的高度
mounted() {
this.setElementHeight()
// 调整浏览器窗口大小时执行
window.addEventListener('resize', this.setElementHeight)
this.$once('hook:beforeDestroy', () => {
window.removeEventListener('resize', this.setElementHeight)
})
this.initUserMap();
}
// 设置DOM高度
setElementHeight () {
clearTimeout(this.timer)
this.timer = setTimeout(() => {
this.showLoading()
this.height = `${(this.$refs.sectionRef.offsetHeight - 30) / 3}px`
console.log(this.height);
}, 100)
},
效果如下:
\