mapHelper.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. // GeoTiff 地图文件处理
  2. // todo load: leaflet
  3. import JSZip from 'jszip'
  4. import { fileUtils } from '@/utils/util.js'
  5. import mapCanvas from '@/utils/mapCanvas.js'
  6. import * as wasmMap from '@/pkg/common_wasm.js'
  7. import {
  8. fromUrl,
  9. fromArrayBuffer,
  10. fromFile
  11. } from 'geotiff'
  12. // #ifdef APP-PLUS
  13. // import io from '@/utils/io.js'
  14. // #endif
  15. let that = null
  16. let dbHelper = null
  17. let imgMap = null
  18. export default {
  19. async handleMapInfo(context, mapInfo) {
  20. that = context
  21. dbHelper = that.$dbHelper
  22. imgMap = that.$refs.imgMap
  23. console.log("[handleMapInfo]", context, mapInfo)
  24. console.log("[handleMapInfo] imgMap", imgMap)
  25. try {
  26. await dbHelper.openDB()
  27. const res = await this.dbGetMapInfo(mapInfo.shopid)
  28. let download = false
  29. let action = null
  30. let mapData = null
  31. if (res == null || res.length == 0) {
  32. console.warn('[handleMapInfo] 本地无匹配记录,需要下载地图')
  33. download = true
  34. action = 'insert'
  35. } else {
  36. const localMd5 = (res.zipImage != undefined) ? res.zipImage.md5 : res.zipImageMd5
  37. if (localMd5 != mapInfo.zipimage.md5) {
  38. console.warn('[handleMapInfo] MD5不同,需再次下载地图')
  39. download = true
  40. action = 'update'
  41. } else {
  42. console.log('[handleMapInfo] MD5相同,无需再次下载地图')
  43. download = false
  44. mapData = this.getMapDataFromDBres(res)
  45. // download = true // debug, will del
  46. // action = 'update' // debug, will del
  47. }
  48. }
  49. if (download) {
  50. const zipData = await this.getZipFiles(mapInfo.zipimage.url)
  51. // const unzipFiles = await this.unzipMap(zipData)
  52. // console.log("[handleMapInfo] download", mapInfo, unzipFiles)
  53. const unzipFiles = ''
  54. await this.dbSaveMapInfo(mapInfo, zipData, unzipFiles, action)
  55. // mapData = unzipFiles[0].fileData
  56. mapData = zipData
  57. }
  58. await dbHelper.closeDB()
  59. // await this.parseMap(mapData)
  60. // await this.parseMap2(mapData)
  61. await this.loadMap(mapData)
  62. // return mapData
  63. } catch (err) {
  64. console.error('[handleMapInfo]', err)
  65. }
  66. },
  67. // 从指定的URL下载地图压缩包
  68. async getZipFiles(zipUrl) {
  69. console.log("[getZipFiles] zipUrl:", zipUrl)
  70. if (!(zipUrl.length > 0)) {
  71. console.log("[getZipFiles] err: zipUrl 为空")
  72. return
  73. }
  74. let [err, res] = await uni.request({
  75. url: zipUrl,
  76. timeout: 60000, // 超时时间,单位 ms
  77. responseType: 'arraybuffer', // 设置响应的数据类型。合法值:text、arraybuffer
  78. });
  79. console.log("[getZipFiles]", res)
  80. return res.data
  81. },
  82. // 解包并获取包内的各文件内容数据 (arraybuffer格式)
  83. async unzipMap(zipData) {
  84. // console.log("[unzipMap] zipData: ", zipData)
  85. if (zipData == undefined || (!(zipData.byteLength > 0))) {
  86. console.log("[unzipMap] err: zipData 为空")
  87. return
  88. }
  89. console.log("[unzipMap] 压缩包大小(字节) zipData.byteLength:", zipData.byteLength)
  90. try {
  91. let jsZip = new JSZip()
  92. let zip = await jsZip.loadAsync(zipData)
  93. // console.log('zip.files', zip.files)
  94. let unzipFiles = []
  95. let i = 0
  96. for (let fileName in zip.files) { // filename为压缩包中的文件名
  97. console.log('[unzipMap] fileName', fileName)
  98. let isImage = fileUtils.isTypeImage(fileName)
  99. let fileData = ''
  100. let dataType = ''
  101. // 获取文件内容,可以使用string、arraybuffer等格式
  102. if (isImage) {
  103. fileData = await zip.file(fileName).async('arraybuffer')
  104. dataType = 'arraybuffer'
  105. } else {
  106. fileData = await zip.file(fileName).async('string')
  107. dataType = 'string'
  108. }
  109. // console.log('[unzipMap] content', content)
  110. unzipFiles[i] = {
  111. fileName: fileName,
  112. fileData: fileData,
  113. dataType: dataType
  114. }
  115. i++
  116. }
  117. return unzipFiles
  118. } catch(err) {
  119. console.error('[unzipMap]', err)
  120. }
  121. },
  122. // 将地图信息保存到本地数据库中
  123. async dbSaveMapInfo(mapInfo, zipData, unzipFiles='', action='insert') {
  124. // #ifdef H5
  125. await this.dbSaveMapInfo_H5(mapInfo, zipData, unzipFiles, action)
  126. // #endif
  127. // #ifdef APP-PLUS
  128. await this.dbSaveMapInfo_APP(mapInfo, zipData, unzipFiles, action)
  129. // #endif
  130. },
  131. // [H5端] 将地图信息保存到本地浏览器 dbHelper 数据库中
  132. async dbSaveMapInfo_H5(mapInfo, zipData, unzipFiles, action) {
  133. // console.log("[dbSaveMapInfo_H5]", mapInfo, unzipFiles)
  134. let storeName = 'mapInfo'
  135. let data = {
  136. shopId: mapInfo.shopid,
  137. mapName: mapInfo.mapname,
  138. zipImage: {
  139. url: mapInfo.zipimage.url,
  140. md5: mapInfo.zipimage.md5,
  141. },
  142. zipData: zipData,
  143. unzipFiles: unzipFiles
  144. }
  145. try {
  146. if (action == 'insert') {
  147. await dbHelper.insertData(storeName, data)
  148. } else if (action == 'update') {
  149. await dbHelper.updateData(storeName, data)
  150. } else {
  151. console.warn('[dbSaveMapInfo_H5] 参数 action 非法: ' + action)
  152. }
  153. } catch(err) {
  154. console.error('[dbSaveMapInfo_H5]', err)
  155. }
  156. },
  157. // [APP端] 将地图信息保存到手机中的 SQLITE 数据库中
  158. async dbSaveMapInfo_APP(mapInfo, zipData, unzipFiles, action) {
  159. // console.log("[dbSaveMapInfo_APP]", mapInfo, unzipFiles)
  160. let tableName = 'mapInfo'
  161. let zipFileKey = 'map_' + mapInfo.shopid
  162. let zipFileName = ''
  163. if (unzipFiles.length > 0) {
  164. zipFileName = unzipFiles[0].fileName
  165. // let zipFilePath = mapInfo.shopid + '_' + unzipFiles[0].fileName
  166. let zipFileData = uni.arrayBufferToBase64(unzipFiles[0].fileData)
  167. // await io.write(zipFilePath, zipFileData)
  168. uni.setStorageSync(zipFileKey, zipFileData);
  169. console.log("[dbSaveMapInfo_APP] setStorageSync Key:", zipFileKey)
  170. console.log("[dbSaveMapInfo_APP] setStorageSync data.fileData length:", unzipFiles[0].fileData.byteLength)
  171. // let zipFile = uni.base64ToArrayBuffer(uni.getStorageSync(zipFileKey));
  172. // console.log("-----> getStorageSync Key", zipFileKey)
  173. // console.log("-----> getStorageSync data.fileData length", zipFile.byteLength)
  174. }
  175. let data = {
  176. shopId: mapInfo.shopid,
  177. mapName: mapInfo.mapname,
  178. zipImageUrl: mapInfo.zipimage.url,
  179. zipImageMd5: mapInfo.zipimage.md5,
  180. zipFileName: zipFileName,
  181. zipFileKey: zipFileKey,
  182. // zipFilePath: zipFilePath,
  183. }
  184. try {
  185. if (action == 'insert') {
  186. await dbHelper.insertData(tableName, data)
  187. } else if (action == 'update') {
  188. let wsql = 'shopId = ' + data.shopId
  189. await dbHelper.updateData(tableName, data, wsql)
  190. } else {
  191. console.warn('[dbSaveMapInfo_APP] 参数 action 非法: ' + action)
  192. }
  193. } catch(err) {
  194. console.error('[dbSaveMapInfo_APP]', err)
  195. }
  196. },
  197. async dbGetMapInfo(shopid) {
  198. let res = null
  199. // #ifdef H5
  200. res = await this.dbGetMapInfo_H5(shopid)
  201. // #endif
  202. // #ifdef APP-PLUS
  203. res = await this.dbGetMapInfo_APP(shopid)
  204. // #endif
  205. return res
  206. },
  207. // [H5端]
  208. async dbGetMapInfo_H5(shopid) {
  209. console.log("[dbGetMapInfo_H5]", shopid)
  210. let storeName = 'mapInfo'
  211. let key = shopid
  212. try {
  213. let data = await dbHelper.getDataByKey(storeName, key)
  214. return data
  215. } catch(err) {
  216. console.error('[dbGetMapInfo_H5]', err)
  217. }
  218. },
  219. // [APP端]
  220. async dbGetMapInfo_APP(shopid) {
  221. console.log("[dbGetMapInfo_APP] shopid", shopid)
  222. let tableName = 'mapInfo'
  223. let key = shopid
  224. try {
  225. let data = await dbHelper.getDataByKey(tableName, key)
  226. if (data != '' && data.zipFileKey.length > 0) {
  227. // let zipFileData = uni.base64ToArrayBuffer(await io.read(data.zipFilePath))
  228. let zipFileData = uni.base64ToArrayBuffer(uni.getStorageSync(data.zipFileKey))
  229. console.log("[dbGetMapInfo_APP] getStorageSync Key", data.zipFileKey)
  230. console.log("[dbGetMapInfo_APP] getStorageSync data length", zipFileData.byteLength)
  231. data.zipFileData = zipFileData
  232. }
  233. // console.log("[dbGetMapInfo_APP] data", data)
  234. return data
  235. } catch(err) {
  236. console.error('[dbGetMapInfo_APP]', err)
  237. }
  238. },
  239. getMapDataFromDBres(dbres) {
  240. let arrayBuffer = null
  241. // #ifdef H5
  242. // arrayBuffer = dbres.unzipFiles[0].fileData
  243. arrayBuffer = dbres.zipData
  244. // console.log('getMapDataFromDBres', dbres.unzipFiles[0].fileName, dbres.unzipFiles[0].fileData)
  245. // #endif
  246. // #ifdef APP-PLUS
  247. arrayBuffer = dbres.zipFileData
  248. // console.log('getMapDataFromDBres', dbres.zipFileName, dbres.zipFileData)
  249. // #endif
  250. return arrayBuffer
  251. },
  252. async parseMap(arrayBuffer) {
  253. // console.log("[parseMap]", arrayBuffer)
  254. // for(let i=0; i<30; i++) {
  255. // console.log(`[parseMap] arrayBuffer[${i}] ${arrayBuffer[i]}`)
  256. // }
  257. if (arrayBuffer == undefined || (!(arrayBuffer.byteLength > 0))) {
  258. console.log("[parseMap] err: arrayBuffer 为空")
  259. return
  260. }
  261. console.log("[parseMap] MAP文件大小(字节) arrayBuffer.byteLength: " + arrayBuffer.byteLength)
  262. try {
  263. // 加载 GeoTIFF 文件
  264. const tiff = await fromArrayBuffer(arrayBuffer)
  265. console.log("[parseMap] tiff", tiff)
  266. const image = await tiff.getImage()
  267. console.log("[parseMap] image", image)
  268. const width = image.getWidth();
  269. const height = image.getHeight();
  270. const tileWidth = image.getTileWidth();
  271. const tileHeight = image.getTileHeight();
  272. console.log(
  273. `[parseMap] width: ${width} height: ${height} tileWidth: ${tileWidth} tileHeight: ${tileHeight}`
  274. )
  275. // const samplesPerPixel = image.getSamplesPerPixel();
  276. // let canvas = this.$refs.canvasMap
  277. // canvas.width = width
  278. // canvas.height = height
  279. // let ctx = canvas.getContext('2d')
  280. // let ctx = uni.createCanvasContext('canvasMap', this)
  281. // 渲染图片
  282. // ctx.drawImage(image, 0, 0)
  283. // ctx.draw()
  284. // console.log('图片渲染完成')
  285. // return
  286. let imageData = new Uint8ClampedArray(width * height * 4)
  287. // console.log("imageData:", imageData)
  288. // let src = that
  289. image.readRasters().then(function(rasters) {
  290. // console.log("rasters:", rasters)
  291. // console.log("rasters:", JSON.stringify(rasters))
  292. for (let i = 0; i < width * height; i++) {
  293. let offset = i * 4
  294. // console.log("rasters[0]:", rasters[0][i])
  295. imageData[offset + 0] = rasters[0][i]
  296. imageData[offset + 1] = rasters[1][i]
  297. imageData[offset + 2] = rasters[2][i]
  298. imageData[offset + 3] = 255
  299. }
  300. uni.canvasPutImageData({
  301. canvasId: 'canvasMap',
  302. data: imageData,
  303. x: 0,
  304. y: 0,
  305. width: width,
  306. // height: 100,
  307. success(res) {
  308. console.log("[parseMap] canvasPutImageData res", res)
  309. },
  310. fail(err) {
  311. console.log("[parseMap] canvasPutImageData err", err)
  312. }
  313. })
  314. // ctx.draw()
  315. })
  316. // // when we are actually dealing with geo-data the following methods return
  317. // // meaningful results:
  318. // const origin = image.getOrigin();
  319. // const resolution = image.getResolution();
  320. // const bbox = image.getBoundingBox();
  321. } catch (err) {
  322. console.error("[parseMap] catch err:", err)
  323. }
  324. },
  325. async parseMap2(mapData) {
  326. let binaryData = [];
  327. binaryData.push(mapData);
  328. that.mapUrl = URL.createObjectURL(new Blob(binaryData));
  329. console.log("[parseMap2] imgMap", imgMap)
  330. // imgMap.src = URL.createObjectURL(new Blob(binaryData));
  331. },
  332. async loadMap(mapData) {
  333. try {
  334. let mapPackage = wasmMap.parse_map_package(new Uint8Array(mapData))
  335. console.log("[loadMap] mapPackage", mapPackage)
  336. let binaryData = [];
  337. binaryData.push(mapPackage.map_image_data);
  338. that.mapUrl = URL.createObjectURL(new Blob(binaryData));
  339. return
  340. await mapCanvas.initCanvas('canvasMap', that)
  341. mapCanvas.handleDrawMap(that.mapUrl)
  342. // let offset = new wasmMap.Offset()
  343. // offset.x = 100
  344. // offset.y = 200
  345. // let position = mapPackage.pic_to_position(offset)
  346. // console.log("[loadMap] pic_to_position", offset, position)
  347. // let position2 = new wasmMap.Position()
  348. // position2.latitude = 36.67352331171326
  349. // position2.longitude = 117.1257123815962
  350. // let offset2 = mapPackage.position_to_pic(position2)
  351. // console.log("[loadMap] position_to_pic", position2, offset2)
  352. // 使用完毕后一定要调用free方法释放内存
  353. // position.free()
  354. // offset2.free()
  355. // mapPackage.free()
  356. // console.log("[loadMap] imgMap", imgMap)
  357. } catch (err) {
  358. console.error('[loadMap]', err)
  359. }
  360. }
  361. }