图片加载
作者: 魏聪 时间: 2021-01-13
1. 应用场景
图片加载的需求是这样的:本地加载一张图片,图片叠加到地图,调整图片大小和透明度,使图片内容和地图相关内容贴合,并且在地图缩放图片和地图始终贴合,这样用户可以直观看到图片内容和地图实际的对比情况。

2. 功能关键点
3. 实现流程
3.1 图片本地加载
提到文件本地加载,我们马上就想到了<input type=”file”>
或者拖拽上传方式,显然这次我们使用<input type=”file”>
就好了,通过文件接口我们就可以获取图片文件 File 对象了,它是继承至 Blob 对象的,我们以前获取到 File 对象或者 FileList 都是直接上传到后台的,后台在返回给我们结果,那么我们怎么在本地把 File 对象里面数据直接加载到 DOM 中呢?JS 中提供了一个操作 File 和 Blob 对象的 FileReader 类,我们可以使用这个类来异步读取文件,它有四个实用方法:
我们可以调用不同函数,从而将 Blob 类型数据或者 File 类型数据转为我们所需类型。我们这次直接转为 Base64 就好了,这样我们就获取到了图片数据。
获取图片数据之后,我们需要将图片数据加载到网页中,但是图片现在没有一个确定的宽高和坐标,所以我们需要创建一个 Image 对象,它将图片数据转为一个图片对象,通过 Image. naturalWidth 和 Image. naturalHeight 拿到图片的原始大小(图片原始大小可能过大,我在配置文件里面设置一个图片初始缩放比例,同时配置了一个初始图片经纬度坐标),通过 mapView.toScreen 就可以拿到图片的屏幕坐标了。这样可以确定图片在页面上的位置和大小了。
注意:通过 toScreen 拿到的不是真的意义上的屏幕点,它的屏幕坐标是相对地图容器的左上角。

确定图片位置信息之后,我们就可以构建 DOM 结构:外层绝对定位覆盖整个地图,为了不影响地图操作,暂时去除了它的所有事件操作(pointEvents:none),图片外面又包裹了一个容器,它的宽高靠图片进行撑开,它主要作用是容纳几个图片拖拽柄(绝对定位进行定位),另外 display 设置为 inline-block,防止宽度溢出,并且添加事件操作(pointEvents:all)。最后创建一个 img 节点,将图片对象的数据赋予它就好了。这样图片的本地加载就完成了。

3.2 图片调整
上面我们将 DOM 结构构建好了,现在就是添加事件了,图片调整主要是图片大小调整和位置调整。
- 位置调整 位置调整的思路主要是这样的:
- 图片绑定 mousedown 事件
- 在 mousedown 事件回调中给最外围容器绑定 mousemove 和 mouseup 事件,此时并保存鼠标的位置信息。
- 在 mousemove 事件计算鼠标偏移量,重设设置图片容器的 top 和 left 值。
- 在 mouseup 事件中移除 mousemove 事件和 mouseup 事件
- 鼠标偏移公式:
- top: y - this.$subInfo.mousey + this.$subInfo.top + "px"
- left: x - this.$subInfo.mousex + this.$subInfo.left + "px"
- 鼠标偏移量+原来 top,left 值,原本想直接 e.movementX 和 e.movementY,但是发现非常卡,暂时没有找到原因,可能触发频率太快,每次 e.movementX 和 e.movementY 增值都很小。
- 大小调整
大小调整的思路主要是这样的:
- 边界控制
我看了下,感觉没有做边界的必要,所以这一步省略。主要在 mousemove 事件中控制一下鼠标范围就好了。
3.3 图片始终贴合地图
图片需要始终贴合地图的话,我们首先想到需要给图片添加一个坐标系,那么怎么添加坐标系呢,那就属于图片配准的事了,这个就需要计算来进行了。
- 1、大致思路
前端通过上传图片信息到计算,计算通过图片配准来给图片添加坐标系,放置图片到工作空间目录下,前端构建一个动态服务,并且添加一个动态服务子图层来请求工作空间下的有坐标系图片,然后添加动态服务到地图中。
- 2、前期准备
一个空的动态服务,创建一个工作空间,并且工作空间绑定一个路径(生成图片将放置在这个路径下面),然后将工作空间和动态服务进行绑定。

- 3、前端逻辑
获取调整好的图片四个角坐标,转成经纬度,将其和图片文件一并通过接口传给计算:
接口响应成功后,计算返回工作空间下图片文件的名称,之后前端进行动态服务的创建,并为动态服务添加一个子图层,类型是 data-layer,这里有两种类型的子图层:map-layer 和 data-layer,类型是 map-layer 的允许你使用新的 renderers, definition expressions, opacity, scale visibility 来覆盖原来动态服务中的子图层样式,类型是 data-layer 的允许你创建一个子图层,但是图层数据可以来自注册的工作空间。它提供一个 dataSource 配置,提供了不同类型的数据源类型:
TableDataSource、QueryTableDataSource、RasterDataSource、JoinTableDataSource,
有表类型的,像 geodatabase,有栅格类型的,像各种格式图片。
我们只需要提供工作空间 ID 和对应表名和栅格文件名,就可以给子图层注册服务端数据了。
每次缩放时,会请求一张新的图片,这样我们就将服务端的有坐标信息的栅格图片数据加载到地图了。 - 4、计算逻辑
计算先进行绑定之前建立的栅格工作空间,等待前端上传图片和图片信息之后,获取参数计算获取图片左上角,右下角两个点坐标,图片高度,宽度等参数,并且根据参数 width 和 height 调整图片大小,并转换成 PNG 格式(前端可能上传 JPG 或者 PNG 格式的图片,但是最终生成的需要是 PNG 格式,因为 JPG 是不支持透明的,所以需要对 JPG 格式的图片进行格式转换),然后根据图片的左上角,右下角两个坐标,利用 AE 接口对栅格图片进行地理配准,经过地理配准之后,图片就带有了坐标信息,在我们请求图片的时候,就可以加载到对应坐标系的坐标位置上了,最后计算返回工作空间绑定目录下的图片名称给前端,至此计算完成响应。