先看效果
前言
关于日本排放核污水,在B站看了很多UP主各路跟踪报道和整活儿,有制作末日视频的,有写末日小说的,有奇怪图片创作的,当时的一个想法是难道就只有B友整活没有掘友用技术整活是吗?
现在日本排污已经3轮了,热度也凉透了,现在都在关注巴以冲突,之前的想法总算是拖拖拉拉实现了,接下来就来捋一下动图中用到的技术点和实现思路
技术栈
- vue: 2.6.10
- leaflet: 1.9.4
- vuetify: 2.5.10
- typescript: 3.4.3
实现思路
先实现一个地图,这里的地图使用了 leaflet
,设置地图的中心点,给地图的中心点加上标记,基于标记的中心点获取附近的表地图经纬度坐标点,然后根据经纬度坐标点绘制热力图模拟核污染水影响的区域,绘制结束后,添加图片爆炸效果
1. 实现 leaflet
地图
html
部分一个只有一个 div
标签
<div id="map" class="map" style="height: calc(100vh - 90px)"></div>
js
部分初始化地图,地图初始化的时候需要设置中心点,这里我使用的是福岛核电站的 GoogleMap
经纬度坐标
import L from 'leaflet' import 'leaflet/dist/leaflet.css' private centerLatitude: number = 37.3165735 // 福岛核电站,GoogleMap经纬度坐标 private centerLongitude: number = 141.0223689 const map = L.map('map', { center: [this.centerLatitude, this.centerLongitude], zoom: 14 })
坐标点获取在 GoogleMap
中搜一下 福岛第二核电站
,然后选择后,会有标记,鼠标移到在标记点右键就出来经纬度坐标了
这时候 leaflet
地图初始化后显示就正常了,中心点是 福岛第二核电站
,可以根据实际效果效果调整 zoom
参数,这里我设置的 zoom: 14
2. 添加标记
在地图中如果不添加 标记
整个看起来不知道重点在哪,因此我们也添加一个类似于搜索结果的标记,设置 marker
属性就可以了,这里也需要一个经纬度坐标,直接使用 福岛第二核电站
的坐标,这样标记点位置和地图中心点位置一样,也很直观
L.marker([this.centerLatitude, this.centerLongitude]).addTo(map)
在 vue2
项目设置完 marker
后默认图片不显示的,查看网络资源请求对应路径下没有对应的标记图片,这里需要手动扒一下 leaflet
官方的标记图
官方首页的 Demo 中就有图片,下载好以后,放到项目的指定位置
这时候标记点出来了,但是标记图片周围有个框,一开始我以为是样式问题,查了样式代码发现没问题,后来发现原来是另一个图片没有正常显示,标记图标为了显示立体感,还有一个阴影效果的图片 marker-shadow.png
,仔细看下面图片中的效果
也从官网的例子中把图片扒下来放到项目对应位置就行了,这时候的地图展示效果如下
提示
标记点图也可以自定义设置,自定设置使用的图片,位置不准,相对默认标记点图会有点偏移
3. 获取热力图坐标点
leaflet
中热力图实现使用的引入的 leaflet-heat
,热力图的渲染需要先有真实的经纬度坐标点,模拟 福岛第二核电站
排污后的效果,需要的是福岛周围对应效果的经纬度坐标,绘制热力图的效果需要的坐标点不少,一个个去地图找然后记录这个不显示,下面提供了两种思路
使用 geolib
生成坐标点
使用 geolib 库生成坐标点,可以通过中心点设置附近范围的方式,例如 福岛第二核电站
方圆50公里以内的坐标点,示例代码如下
// 1度约等于111公里 const degreeInKm = 111 console.log('111: ', geolib) const num = 0 const num2 = 0 for (let lat = -90; lat <= 90; lat = lat + 0.1) { for (let lon = -180; lon <= 180; lon = lon + 0.1) { const distance = geolib.getDistance( { latitude: this.centerLatitude, longitude: this.centerLongitude }, { latitude: lat, longitude: lon } ) / 1000 // 转换为千米 console.log('distance: ', distance) if (distance <= this.radiusKm) { coordinates.push({ latitude: lat, longitude: lon }) } } }
这种生成出来的坐标点渲染出来的效果是一个圆,还需要按需清理才能调整效果
根据绘制好的热力图,获取坐标点
先通过鼠标绘制热力图,绘制好效果后,然后把热力图层的坐标点下载下来,然后保存成需要的数组格式
[ { lat: 37.316659685008695, lng: 141.0264301300049 }, { lat: 37.316659685008695, lng: 141.02668762207034 }, { lat: 37.316659685008695, lng: 141.02694511413577 }, { lat: 37.316659685008695, lng: 141.02711677551272 }, { lat: 37.316659685008695, lng: 141.02728843688968 }, ... ]
我使用的这个方案
4. 绘制热力图效果
得到热力图点的数据集后,为了模拟真实世界核污水排放后的效果,排放后的核污染水造成的污染是慢慢形成的,所以绘制的过程也要慢慢来,添加热力图效果使用了 setInterval
import { addressPoints } from '../../assets/js/realworld-fudao-point' const id = setInterval(() => { len = addressPoints.length if (len > 0) { i = parseInt((Math.random() * len).toString(), 10) n++ this.heat.addLatLng(addressPoints[i]) this.heat.addLatLng(addressPoints[i + 1]) this.heat.addLatLng(addressPoints[i + 2]) this.heat.addLatLng(addressPoints[i + 3]) this.heat.addLatLng(addressPoints[i + 4]) this.heat.addLatLng(addressPoints[i + 5]) this.heat.addLatLng(addressPoints[i + 6]) this.heat.addLatLng(addressPoints[i + 7]) this.heat.addLatLng(addressPoints[i + 8]) this.heat.addLatLng(addressPoints[i + 9]) addressPoints.splice(i, 10) } else { console.log('绘制完了, n=' + n + ' len=' + lenBase) clearInterval(id) } }, 0.01)
realworld-fudao-point.js
文件是获取的 福岛第二核电站
热力图经纬度坐标点,使用 heat.addLatLng
添加热力图坐标点,并使用随机的方式,使热力点更真实模拟随机污染区域,这里一次添加十个点是为了录制视频的时能相对比较快的看到最终效果,当坐标点都绘制完的时候,停止 setInterval
定时器
5. 添加爆炸效果
当热力图绘制结束后,由于 福岛第二核电站
附近污染太严重,引发了各种异常的情况,附近区域地震,海啸,飓风等极端现象频发,最终整个核电站及附近城市设备陆续出现损坏从而大规模爆炸
<img v-if="showImg" src="../../assets/img/boom3.gif" class="img-boom" style="top: 48%; left: 52%; transform: translate(-50%, -50%)" /> this.showImg = true setTimeout(() => { this.showImg1 = true }, 1000) ...
好了,技术上的完整实现到这里就结束了
项目完整代码地址
写在最后
这种不顾全社会的反对,不负责任排放核污染水的行为,最终会让日本走向灭亡,让我们拭目以待吧