mapEngine.js 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881
  1. /* *********************************************************** */
  2. // Created by Macheng on 2019/07/31.
  3. // Description:
  4. // This is a class of map engine.
  5. // Ver 1.0 save marker path by each copy, this will cost more space.
  6. /* *********************************************************** */
  7. import * as maptalks from 'maptalks'
  8. import * as THREE from 'three'
  9. import { PathPlayerPos, PathUwbDev, PathCamera, PathUwbAGV } from './symbolSvg.js'
  10. import { Laycon, LAYER_ID_DEFS, LAYER_DEFINES } from './laycon.js'
  11. import { DrawEx } from './drawExFunc.js'
  12. import { ClusterLayer } from './MyClusterLayer'
  13. // import Color from 'color'
  14. // import colorString from 'color-string'
  15. // const ANC_DEFAULT_MARKER_FILL = '#0000FF'
  16. // const ANC_SELECT_MARKER_FILL = '#FF0000'
  17. function createResolutions() {
  18. const resolutions = []
  19. var d = 2 * 6378137 * Math.PI
  20. for (var i = 0; i < 48; i++) {
  21. resolutions[i] = d / (256 * Math.pow(2, i))
  22. }
  23. return resolutions
  24. }
  25. const ATLAS_VERSION = 210
  26. class BackgroundConf {
  27. mode = 0
  28. minLng = -10000
  29. minLat = -10000
  30. maxLng = 10000
  31. maxLat = 10000
  32. color = '#ffffff'
  33. url = 'static/img/white.png'
  34. fromJSON(jObj) {
  35. this.mode = Number(jObj['mode']) || 0
  36. if (jObj.hasOwnProperty('minLng')) {
  37. this.minLng = Number(jObj['minLng'])
  38. }
  39. if (jObj.hasOwnProperty('maxLng')) {
  40. this.maxLng = Number(jObj['maxLng'])
  41. }
  42. if (jObj.hasOwnProperty('minLat')) {
  43. this.minLat = Number(jObj['minLat'])
  44. }
  45. if (jObj.hasOwnProperty('maxLat')) {
  46. this.maxLat = Number(jObj['maxLat'])
  47. }
  48. this.url = jObj['url'] || ''
  49. this.color = jObj['color'] || '#ffffff'
  50. }
  51. toJSON() {
  52. return {
  53. mode: this.mode,
  54. minLng: this.minLng,
  55. maxLng: this.maxLng,
  56. minLat: this.minLat,
  57. maxLat: this.maxLat,
  58. url: this.url,
  59. color: this.color
  60. }
  61. }
  62. }
  63. class AtlasConf {
  64. name = ''
  65. oldVer = 0
  66. id = 0
  67. speedLimit = -1
  68. altitudeMode = 0
  69. encrypt = 1 // 0: no encrypt, 1: AES-128-CBC PKCS#7
  70. mapMode = 2
  71. centerX = 113.18553
  72. centerY = 22.01226
  73. // centerX = 0
  74. // centerY = 0
  75. zoom = 18
  76. fromJSON(jObj) {
  77. if (!jObj) jObj = {}
  78. this.name = jObj['name'] || ''
  79. this.oldVer = jObj['version'] || 0
  80. this.id = Number(jObj['id']) || 0
  81. this.speedLimit = Number(jObj['speedLimit']) || 0
  82. this.altitudeMode = Number(jObj['altitudeMode']) || 0
  83. this.mapMode = Number(jObj['mapMode']) || 0
  84. this.centerX = Number(jObj['centerX']) || 0
  85. this.centerY = Number(jObj['centerY']) || 0
  86. }
  87. toJSON() {
  88. return {
  89. id: this.id,
  90. name: this.name,
  91. version: ATLAS_VERSION,
  92. speedLimit: this.speedLimit,
  93. altitudeMode: this.altitudeMode,
  94. encrypt: 1,
  95. mapMode: this.mapMode,
  96. centerX: this.centerX,
  97. centerY: this.centerY
  98. }
  99. }
  100. }
  101. const DRAW_MODE = {
  102. SELECT: 'select',
  103. POLYGON: 'polygon',
  104. CIRCLE: 'circle',
  105. ELLIPSE: 'ellipse',
  106. RECTANGLE: 'rectangle',
  107. LABEL: 'label',
  108. TEXTBOX: 'textbox',
  109. PLAYER: 'player',
  110. ANCHOR: 'anchor'
  111. }
  112. class MapEngine {
  113. _node = null // 关联的DOM节点
  114. _tickRefresh = 0 // 刷新计时器
  115. _editable = false // 是否启用编辑
  116. _drawMode = '' // 特殊的绘制模式,如player, anchor等
  117. _drawProperties = null
  118. /**
  119. * {maptalks.Map}
  120. */
  121. mt = null // MapTalks的Map实例
  122. bearing = 0
  123. bgConf = new BackgroundConf()
  124. centerX = 0
  125. centerY = 0
  126. cfg = new AtlasConf()
  127. drawExFunc = null // DrawTool 的特殊绘制函数:基站、文本、文本框等
  128. drawTool = null // DrawTool实例
  129. drawSymbol = { // DrawTool的Symbol实例
  130. 'lineWidth': 1,
  131. 'lineColor': 'rgba(0,0,0,1)',
  132. 'textSize': 10,
  133. 'textFill': 'rgba(0,0,0,1)',
  134. 'textHaloRadius': 1,
  135. 'textHaloFill': 'rgba(255,255,255,1)',
  136. 'fillColor': 'rgba(135,135,135,1)',
  137. 'altitude': 0,
  138. 'height': 0,
  139. 'boxWidth': 200,
  140. 'boxHeight': 30
  141. }
  142. laycons = {} // 全部图层容器
  143. _layer3d = null // 特别的 3D 图层
  144. originView = null // 原始视图
  145. pitch = 0
  146. raycaster = null
  147. resolutions = createResolutions()
  148. selLaycon = null // 当前选择的图层
  149. selGeos = [] // 选择的物件
  150. zoom = 5
  151. _tags = [] // 保持关联的TAG列表
  152. _sheets = [] // 保持关联的SHEET列表
  153. _anchors = [] // 保持关联的ANCHOR列表
  154. isRt = true
  155. cbAddGeometry = null // 新增Geometry的回调函数
  156. cbAddDevice = null // 新增Device的回调函数
  157. cbOnClickCluster = null // 点击Cluster的回调函数
  158. cbOnClusterChange = null // Cluster改变回调函数
  159. cbOnClickMarker = null // 点击Marker的回调函数
  160. _clusterEnableMode = {
  161. 'sign': 21
  162. } // 保持的Cluster启用模式
  163. constructor(opts) {
  164. if (!opts) opts = {}
  165. this.init(opts)
  166. }
  167. get editable() {
  168. return this._editable
  169. }
  170. set editable(val) {
  171. this._editable = val
  172. this.resetMapOperation()
  173. }
  174. get selLayer() {
  175. return this.selLaycon ? this.selLaycon.layer : null
  176. }
  177. get toolSymbol() {
  178. return this.drawTool ? this.drawTool.options['symbol'] : null
  179. }
  180. getClusterEnable(layerName) {
  181. if (this._clusterEnableMode[layerName]) {
  182. return this._clusterEnableMode[layerName]
  183. }
  184. return null
  185. }
  186. setClusterEnable(layerName, mode) {
  187. const layer = this.getLayer(layerName)
  188. if (layer) {
  189. layer.config('maxClusterZoom', mode)
  190. this._clusterEnableMode[layerName] = mode
  191. }
  192. }
  193. _initMapClick() {
  194. this.mt.on('click', (e) => {
  195. // Editable
  196. if (this.editable) {
  197. if (this.selLaycon && this.selLaycon.layer !== this._layer3d) {
  198. if (this._drawMode) {
  199. if (this.drawExFunc) {
  200. this.drawExFunc(this, e.coordinate, this.drawSymbol, this._drawMode)
  201. }
  202. this._drawMode = null
  203. } else {
  204. if (this.drawTool && this.drawTool.isEnabled()) {
  205. return
  206. }
  207. // reset colors
  208. this.clearSelection()
  209. this.selGeos = []
  210. if (this.selLaycon && this.selLaycon.layer) {
  211. this.selLaycon.layer.forEach(function (g) {
  212. g.endEdit()
  213. g.config('draggable', false)
  214. })
  215. }
  216. // identify
  217. this.mt.identify(
  218. {
  219. 'coordinate': e.coordinate,
  220. 'layers': [this.selLaycon.layer]
  221. },
  222. (geos) => {
  223. this.selGeos = geos
  224. geos.forEach(function (g) {
  225. if (g.isLock) return
  226. g.config('draggable', true)
  227. g.startEdit()
  228. if (g.getJSONType().toLowerCase() === 'textbox' ||
  229. g.getJSONType().toLowerCase() === 'label') {
  230. // g.endEdit()
  231. }
  232. // console.log('sel geo', g)
  233. })
  234. this.adapterModel()
  235. }
  236. )
  237. }
  238. } else {
  239. const mouse = new THREE.Vector2()
  240. const width = this._node.offsetWidth
  241. const height = this._node.offsetHeight
  242. // console.log('width', width, 'height', height)
  243. mouse.x = (e.domEvent.layerX / width) * 2 - 1
  244. mouse.y = -(e.domEvent.layerY / height) * 2 + 1
  245. const objects = []
  246. if (this.selLaycon) {
  247. this.selLaycon.getScene().children.forEach(child => {
  248. if (child instanceof THREE.Mesh) {
  249. objects.push(child)
  250. }
  251. })
  252. this.raycaster.setFromCamera(mouse, this.selLaycon.getCamera())
  253. }
  254. const intersects = this.raycaster.intersectObjects(objects)
  255. if (intersects.length > 0) {
  256. const m = intersects[0]
  257. console.log('m', m)
  258. // console.log('Mesh', intersects[0])
  259. }
  260. }
  261. } else {
  262. // Not editable
  263. const signLayer = this.getLayer('sign')
  264. if (signLayer) {
  265. const rtn = signLayer.identify(e.coordinate)
  266. if (rtn && rtn.children && rtn.children.length && this.cbOnClickCluster) {
  267. this.cbOnClickCluster('sign', rtn)
  268. }
  269. }
  270. const tagLayer = this.getLayer('tag')
  271. if (tagLayer) {
  272. const rtn = tagLayer.identify(e.coordinate)
  273. if (rtn && rtn.children && rtn.children.length && this.cbOnClickCluster) {
  274. this.cbOnClickCluster('tag', rtn)
  275. }
  276. }
  277. }
  278. })
  279. }
  280. _initMapDblClick() {
  281. this.mt.on('dblclick', (e) => {
  282. if (this.editable) {
  283. const vecDisableEditType = ['dylabel']
  284. if (this.selLaycon && this.selLaycon.layer !== this._layer3d) {
  285. this.selGeos.forEach(function (g) {
  286. if (g.getJSONType().toLowerCase() === 'textbox' ||
  287. g.getJSONType().toLowerCase() === 'label') {
  288. const props = g.getProperties()
  289. if (props && props['type'] && vecDisableEditType.indexOf(props['type']) >= 0) {
  290. return
  291. }
  292. g.endEdit()
  293. g.startEditText()
  294. }
  295. })
  296. }
  297. }
  298. })
  299. }
  300. _initContextMenu() {
  301. if (this.editable) {
  302. const options = {
  303. 'items': [
  304. '-',
  305. {
  306. item: '取消绘制',
  307. click: () => {
  308. if (self.drawTool) {
  309. self.drawTool.disable()
  310. }
  311. }
  312. },
  313. {
  314. item: '取消选择',
  315. click: () => {
  316. self.clearSelection()
  317. }
  318. }
  319. ]
  320. }
  321. if (this.mt) {
  322. this.mt.setMenu(options)
  323. }
  324. } else {
  325. if (this.mt) {
  326. this.mt.removeMenu()
  327. }
  328. }
  329. }
  330. _initDrawTool() {
  331. console.log('initDrawTool')
  332. this.drawTool = new maptalks.DrawTool({
  333. mode: 'Point'
  334. }).addTo(this.mt).disable()
  335. this.drawExFunc = DrawEx
  336. this.drawTool.on('drawstart', (param) => {
  337. })
  338. this.drawTool.on('drawend', (param) => {
  339. console.log('param', param)
  340. param.geometry.properties = param.geometry.getSymbol()
  341. if (!param.geometry.properties) {
  342. param.geometry.properties = {}
  343. }
  344. param.geometry.properties['altitude'] = this.drawSymbol.altitude
  345. param.geometry.properties['height'] = this.drawSymbol.height
  346. if (this.selLaycon) {
  347. Math.random()
  348. Math.random()
  349. if (!param.geometry.getId()) {
  350. const id = this.selLaycon.name + Math.floor((new Date().getTime() / 1000) % 1000000000)
  351. param.geometry.setId(id)
  352. param.geometry.isLock = false
  353. }
  354. switch (this.selLaycon.name) {
  355. case 'border':
  356. param.geometry.properties['limit'] = 0
  357. break
  358. case 'area':
  359. param.geometry.properties['addr'] = 0
  360. param.geometry.properties['level'] = 0
  361. param.geometry.properties['delay'] = 0
  362. // this.tmpPoly = param.geometry.getCoordinates()[0]
  363. // this.tmpPoly.splice(this.tmpPoly.length - 1, 1)
  364. // console.log('area poly', this.tmpPoly)
  365. break
  366. case 'thing':
  367. // const c = param.geometry.getCoordinates()
  368. // console.log('thing', c)
  369. // if (this.tmpPoly.length) {
  370. // const b = pointInPolygon(this.tmpPoly, c)
  371. // console.log('pointInPolygon', b)
  372. // if (b) {
  373. // const vec = nearPoints(this.tmpPoly, c)
  374. // const svec = this.tmpPoly.slice(0)
  375. // console.log('near pts', svec)
  376. // for (let i = 0; i < svec.length - 1; i++) {
  377. // const co = getCrossPtInOrthByPts(svec[i], svec[i + 1], c)
  378. // if (co.x < Math.min(svec[i].x, svec[i + 1].x) ||
  379. // co.x > Math.max(svec[i].x, svec[i + 1].x) ||
  380. // co.y < Math.min(svec[i].y, svec[i + 1].y) ||
  381. // co.y > Math.max(svec[i].y, svec[i + 1].y)
  382. // ) {
  383. // continue
  384. // }
  385. // vec.push(co)
  386. // }
  387. // console.log('candidate pts', vec)
  388. // let m = -1
  389. // let pickC = null
  390. // for (const v of vec) {
  391. // const dis = (v.x - c.x) * (v.x - c.x) + (v.y - c.y) * (v.y - c.y)
  392. // if (m > dis || m < 0) {
  393. // m = dis
  394. // pickC = v
  395. // }
  396. // }
  397. // console.log('pick pt', pickC)
  398. //
  399. // const jObj = param.geometry.toJSON()
  400. // const tmpGeo = maptalks.Geometry.fromJSON(jObj)
  401. // tmpGeo.setCoordinates(pickC)
  402. // const id2 = this.selectLayer.getId() + Math.floor(Math.random() * 10000)
  403. // tmpGeo.setId(id2)
  404. // this.selectLayer.addGeometry(tmpGeo)
  405. // }
  406. // }
  407. break
  408. }
  409. if (this._drawProperties) {
  410. param.geometry.setProperties(this._drawProperties)
  411. }
  412. this._drawProperties = null
  413. param.geometry.properties['name'] = param.geometry.getId()
  414. param.geometry.properties['action'] = ''
  415. this.selLaycon.addGeometry(param.geometry)
  416. if (this.cbAddGeometry) {
  417. this.cbAddGeometry(param.geometry, this.selLaycon.name)
  418. }
  419. }
  420. // this.mapEngine.selLaycon.addGeometry(param.geometry)
  421. this.drawTool.disable()
  422. })
  423. // const toolSymbol = this.drawTool.options['symbol']
  424. // toolSymbol.lineWidth = this.drawSymbol.lineWidth
  425. // toolSymbol.lineColor = this.drawSymbol.lineColor
  426. // toolSymbol.polygonFill = this.drawSymbol.fillColor
  427. // toolSymbol.textSize = this.drawSymbol.textSize
  428. // toolSymbol.textFill = this.drawSymbol.textFill
  429. // toolSymbol.textHaloRadius = this.drawSymbol.textHaloRadius
  430. // toolSymbol.textHaloFill = this.drawSymbol.textHaloFill
  431. // toolSymbol.altitude = this.drawSymbol.altitude
  432. // toolSymbol.boxWidth = this.drawSymbol.boxWidth
  433. // toolSymbol.boxHeight = this.drawSymbol.boxHeight
  434. }
  435. adapterModel() {
  436. if (this.selGeos.length <= 0 && this.drawTool) {
  437. const toolSymbol = this.drawTool.options['symbol']
  438. this.drawSymbol.lineWidth = toolSymbol.lineWidth || this.drawSymbol.lineWidth
  439. this.drawSymbol.lineColor = toolSymbol.lineColor || this.drawSymbol.lineColor
  440. this.drawSymbol.fillColor = toolSymbol.polygonFill || this.drawSymbol.polygonFill
  441. this.drawSymbol.textSize = toolSymbol.textSize || this.drawSymbol.textSize
  442. this.drawSymbol.textFill = toolSymbol.textFill || this.drawSymbol.textFill
  443. this.drawSymbol.textHaloRadius = toolSymbol.textHaloRadius || this.drawSymbol.textHaloRadius
  444. this.drawSymbol.textHaloFill = toolSymbol.textHaloFill || this.drawSymbol.textHaloFill
  445. this.drawSymbol.altitude = toolSymbol.altitude || this.drawSymbol.altitude
  446. this.drawSymbol.height = toolSymbol.height || this.drawSymbol.height
  447. this.drawSymbol.boxWidth = toolSymbol.boxWidth || this.drawSymbol.boxWidth
  448. this.drawSymbol.boxHeight = toolSymbol.boxHeight || this.drawSymbol.boxHeight
  449. return
  450. }
  451. const m = this.selGeos[0]
  452. switch (m.getJSONType().toLowerCase()) {
  453. case 'textbox':
  454. this.drawSymbol.lineWidth = m.getBoxSymbol().markerLineWidth
  455. this.drawSymbol.lineColor = m.getBoxSymbol().markerLineColor
  456. this.drawSymbol.fillColor = m.getBoxSymbol().markerFill
  457. this.drawSymbol.textSize = m.getTextStyle().symbol.textSize
  458. this.drawSymbol.textFill = m.getTextStyle().symbol.textFill
  459. this.drawSymbol.textHaloRadius = m.getTextStyle().symbol.textHaloRadius
  460. this.drawSymbol.textHaloFill = m.getTextStyle().symbol.textHaloFill
  461. this.drawSymbol.boxWidth = m.getWidth()
  462. this.drawSymbol.boxHeight = m.getHeight()
  463. break
  464. case 'label':
  465. this.drawSymbol.lineWidth = m.getBoxStyle().symbol.markerLineWidth
  466. this.drawSymbol.lineColor = m.getBoxStyle().symbol.markerLineColor
  467. this.drawSymbol.fillColor = m.getBoxStyle().symbol.markerFill
  468. this.drawSymbol.textSize = m.getTextSymbol().textSize
  469. this.drawSymbol.textFill = m.getTextSymbol().textFill
  470. this.drawSymbol.textHaloRadius = m.getTextSymbol().textHaloRadius
  471. this.drawSymbol.textHaloFill = m.getTextSymbol().textHaloFill
  472. this.drawSymbol.boxWidth = m.getBoxStyle().minWidth
  473. this.drawSymbol.boxHeight = m.getBoxStyle().minHeight
  474. break
  475. default:
  476. this.drawSymbol.lineWidth = m.properties.lineWidth || 0
  477. this.drawSymbol.lineColor = m.properties.lineColor || '#000000'
  478. this.drawSymbol.fillColor = m.properties.polygonFill || '#333333'
  479. break
  480. }
  481. this.drawSymbol.altitude = m.properties.altitude || 0
  482. this.drawSymbol.height = m.properties.height || 0
  483. }
  484. addAnchor(anchor) {
  485. if (!anchor) return
  486. for (const v of this._anchors) {
  487. if (v.addr == anchor.addr) {
  488. return
  489. }
  490. }
  491. this._anchors.push(anchor)
  492. const start = { x: anchor.x, y: anchor.y }
  493. const geo = new maptalks.Marker(
  494. anchor.coordinate || start,
  495. {
  496. 'symbol': {
  497. 'markerType': 'path',
  498. 'markerPath': PathUwbDev,
  499. 'markerPathWidth': 1024,
  500. 'markerPathHeight': 1024,
  501. 'markerFill': '#0000ff', // will override tiger path's style properties
  502. // 'markerLineColor' : 12,
  503. 'markerWidth': 32,
  504. 'markerHeight': 32,
  505. 'markerDy': 16,
  506. 'markerDx': 0,
  507. 'textName': 'A' + anchor.addr,
  508. 'textDy': -20
  509. },
  510. 'properties': {
  511. 'altitude': anchor.altitude,
  512. 'addr': anchor.addr,
  513. 'name': anchor.name,
  514. 'jobId': anchor.jobId
  515. }
  516. }
  517. )
  518. geo.setId(anchor.id || anchor.name)
  519. geo.isLock = false
  520. geo.setCoordinates(anchor.coordinates || start)
  521. this.getLayer('anchor').addGeometry(geo)
  522. if (anchor.setGeo) {
  523. anchor.setGeo(geo)
  524. }
  525. }
  526. addArea(area) {
  527. const geo = maptalks.GeoJSON.toGeometry(area.geoJson)
  528. geo.setId(area.id || area.name)
  529. geo.updateSymbol(geo.properties)
  530. geo.isLock = false
  531. this.getLayer('area').addGeometry(geo)
  532. }
  533. addDataItem(dataItem) {
  534. const geo = maptalks.Geometry.fromJSON(dataItem.geoJson)
  535. geo.setId(dataItem.id || dataItem.name)
  536. geo.isLock = false
  537. geo.properties.defVal = geo.properties.val
  538. this.getLayer('data').addGeometry(geo)
  539. }
  540. addDevice(device) {
  541. let markerPath = []
  542. switch (device.type) {
  543. case 'camera':
  544. markerPath = PathCamera
  545. break
  546. }
  547. const geo = new maptalks.Marker(
  548. device.coordinate,
  549. {
  550. 'symbol': {
  551. 'markerType': 'path',
  552. 'markerPath': markerPath,
  553. 'markerPathWidth': 1024,
  554. 'markerPathHeight': 1024,
  555. 'markerFill': '#0000ff', // will override tiger path's style properties
  556. // 'markerLineColor' : 12,
  557. 'markerWidth': 32,
  558. 'markerHeight': 32,
  559. 'markerDy': 0,
  560. 'markerDx': 0,
  561. 'textName': '{jobId}\nA{addr}',
  562. 'textDy': 14
  563. },
  564. 'properties': device.props
  565. }
  566. )
  567. geo.setId(device.id || device.name)
  568. geo.isLock = false
  569. geo.setCoordinates(device.coordinates)
  570. this.getLayer('device').addGeometry(geo)
  571. if (this.cbAddDevice) {
  572. this.cbAddDevice(device, geo)
  573. }
  574. }
  575. addLaycon(laycon) {
  576. if (!this.laycons.hasOwnProperty(laycon.name)) {
  577. this.laycons[laycon.name] = laycon
  578. this.mt.addLayer(laycon.layer)
  579. }
  580. return this
  581. }
  582. /**
  583. *
  584. * @param {Array} signs
  585. * @param {Array} mainTypeDefs
  586. */
  587. addSigns(signs, mainTypeDefs) {
  588. const markers = []
  589. for (const sign of signs) {
  590. let symbol = {}
  591. if (mainTypeDefs && sign.mainType < mainTypeDefs.length && mainTypeDefs[sign.mainType].iconBase64) {
  592. symbol = {
  593. 'markerFile': mainTypeDefs[sign.mainType].iconBase64,
  594. 'markerPathWidth': 1024,
  595. 'markerPathHeight': 1024,
  596. 'markerFill': '#ff4444', // will override tiger path's style properties
  597. // 'markerLineColor' : 12,
  598. 'markerWidth': 32,
  599. 'markerHeight': 32,
  600. 'markerDy': 0,
  601. 'markerDx': 0,
  602. 'textName': '{id}',
  603. 'textWeight': 900,
  604. 'textDy': 10
  605. }
  606. } else {
  607. symbol = {
  608. 'markerType': 'Ellipse',
  609. 'markerPathWidth': 1024,
  610. 'markerPathHeight': 1024,
  611. 'markerFill': '#ff4444', // will override tiger path's style properties
  612. // 'markerLineColor' : 12,
  613. 'markerWidth': 32,
  614. 'markerHeight': 32,
  615. 'markerDy': 0,
  616. 'markerDx': 0,
  617. 'textName': '{id}',
  618. 'textWeight': 900,
  619. 'textDy': 10
  620. }
  621. }
  622. const m = new maptalks.Marker(
  623. [sign.lng, sign.lat],
  624. {
  625. 'symbol': symbol,
  626. 'properties': {
  627. 'id': sign.id,
  628. 'mainType': sign.mainType
  629. }
  630. }
  631. ).on('click', () => {
  632. if (this.cbOnClickMarker) {
  633. this.cbOnClickMarker(m, sign)
  634. }
  635. })
  636. markers.push(m)
  637. }
  638. const layerSign = this.getLayer('sign')
  639. if (layerSign) {
  640. layerSign.addGeometry(markers)
  641. }
  642. this.setSelLaycon('sign')
  643. }
  644. replay(line, dt, needShow, finishClear, pathCoords) {
  645. // console.log('needShow', needShow)
  646. //line's animateShow
  647. line.hide()
  648. if (needShow) {
  649. line.animateShow({
  650. duration: dt,
  651. easing: 'linear'
  652. }, function (frame) {
  653. if (frame.state.playState === 'finished') {
  654. if (finishClear) {
  655. if (line.tag) {
  656. if (line.tag.path) {
  657. line.tag.path.setCoordinates(pathCoords)
  658. }
  659. line.tag.removeLine(line)
  660. }
  661. }
  662. }
  663. })
  664. // if (line.createTime) {
  665. // line.show()
  666. // } else {
  667. //
  668. // }
  669. } else {
  670. line.hide()
  671. }
  672. }
  673. addSheet(sheet) {
  674. if (!sheet) return
  675. for (const v of this._sheets) {
  676. if (v.id === sheet.id) {
  677. return
  678. }
  679. }
  680. const geo = maptalks.GeoJSON.toGeometry(sheet.geoJson)
  681. geo.setId(sheet.id || sheet.name)
  682. geo.updateSymbol(geo.properties)
  683. geo.isLock = false
  684. geo.sheet = sheet
  685. sheet.setGeo(geo)
  686. this.getLayer(LAYER_DEFINES[LAYER_ID_DEFS.IdSheet].name).addGeometry(geo)
  687. }
  688. addPath(x, y, addr, needShow, color, lineWidth = 6) {
  689. const tag = this.getTag(addr)
  690. if (!tag) return
  691. const traceLayer = this.getLayer('trace')
  692. tag.removeLines(-1)
  693. if (!tag.path) {
  694. tag.path = new maptalks.LineString([], {
  695. smoothness: 0.2,
  696. 'symbol': {
  697. 'lineColor': color,
  698. 'lineWidth': lineWidth,
  699. 'lineJoin': 'round', //miter, round, bevel
  700. 'lineCap': 'round', //butt, round, square
  701. 'lineDasharray': null, //dasharray, e.g. [10, 5, 5]
  702. 'lineOpacity ': 0.5
  703. }
  704. }).addTo(traceLayer)
  705. }
  706. if (tag.showInAtlas) {
  707. if (tag.path) {
  708. tag.path.show()
  709. }
  710. } else {
  711. if (tag.path) {
  712. tag.path.hide()
  713. }
  714. }
  715. const pathCoords = tag.path.getCoordinates()
  716. pathCoords.push([x, y])
  717. tag.path.setCoordinates(pathCoords)
  718. }
  719. addTrace(x, y, nx, ny, dt, addr, needShow, color, nowData = -1, lineWidth = 6) {
  720. const tag = this.getTag(addr)
  721. if (!tag) return
  722. const traceLayer = this.getLayer('trace')
  723. const line = new maptalks.LineString(
  724. [
  725. [x, y],
  726. [nx, ny]
  727. ],
  728. {
  729. symbol: {
  730. 'lineColor': color,
  731. 'lineWidth': lineWidth,
  732. 'lineJoin': 'round', //miter, round, bevel
  733. 'lineCap': 'round', //butt, round, square
  734. 'lineDasharray': null, //dasharray, e.g. [10, 5, 5]
  735. 'lineOpacity ': 0.5
  736. }
  737. }
  738. ).addTo(traceLayer)
  739. tag.addLine(line)
  740. if (tag.showInAtlas) {
  741. line.show()
  742. if (tag.path) {
  743. tag.path.show()
  744. }
  745. } else {
  746. line.hide()
  747. if (tag.path) {
  748. tag.path.hide()
  749. }
  750. }
  751. if (nowData < 0) {
  752. line.createTime = -1
  753. } else {
  754. line.createTime = nowData
  755. }
  756. if (tag.showInAtlas) {
  757. let pathCoords = []
  758. if (nowData < 0) {
  759. if (!tag.path) {
  760. tag.path = new maptalks.LineString([], {
  761. 'smoothness': 0.08,
  762. 'symbol': {
  763. 'lineColor': color,
  764. 'lineWidth': lineWidth,
  765. 'lineJoin': 'round', //miter, round, bevel
  766. 'lineCap': 'round', //butt, round, square
  767. 'lineDasharray': null, //dasharray, e.g. [10, 5, 5]
  768. 'lineOpacity ': 0.5
  769. }
  770. }).addTo(traceLayer)
  771. }
  772. pathCoords = tag.path.getCoordinates()
  773. pathCoords.push(new maptalks.Coordinate([nx, ny]))
  774. }
  775. this.replay(line, dt, needShow, nowData < 0, pathCoords)
  776. }
  777. }
  778. addTag(tag, radius) {
  779. if (!tag) return
  780. for (const v of this._tags) {
  781. if (v.addr === tag.addr) {
  782. return
  783. }
  784. }
  785. const start = { x: tag.x, y: tag.y }
  786. // const end = { x: 0, y: 0 }
  787. const thingLayer = this.getLayer('tag')
  788. const geoIcon = new maptalks.Marker(start, {
  789. 'symbol': {
  790. 'markerType': 'path',
  791. 'markerPath': tag.addr > 200 ? PathUwbAGV : PathPlayerPos,
  792. 'markerPathWidth': tag.addr > 200 ? 1359 : 1024,
  793. 'markerPathHeight': 1024,
  794. 'markerFill': '#4444ff', // will override tiger path's style properties
  795. // 'markerLineColor' : 12,
  796. 'markerWidth': 24,
  797. 'markerHeight': 24,
  798. 'markerDy': 0,
  799. 'markerDx': 0,
  800. 'textFaceName': 'sans-serif',
  801. 'textName': 'name', // value from name in geometry's properties
  802. 'textWeight': 'normal', // 'bold', 'bolder'
  803. 'textStyle': 'normal', // 'italic', 'oblique'
  804. 'textSize': 20,
  805. 'textFont': null, // same as CanvasRenderingContext2D.font, override textName, textWeight and textStyle
  806. 'textFill': '#4444ff',
  807. 'textOpacity': 1,
  808. 'textHaloFill': '#fff',
  809. 'textHaloRadius': 2,
  810. 'textWrapWidth': null,
  811. 'textWrapCharacter': '\n',
  812. 'textLineSpacing': 0,
  813. 'textDx': 0,
  814. 'textDy': -40,
  815. 'textHorizontalAlignment': 'middle', // left | middle | right | auto
  816. 'textVerticalAlignment': 'middle', // top | middle | bottom | auto
  817. 'textAlign': 'center' // left | right | center | auto
  818. },
  819. 'properties': {
  820. 'altitude': 0,
  821. 'addr': tag ? tag.addr : 0,
  822. 'name': tag ? tag.playerName : '(undefined)'
  823. }
  824. })
  825. // geoIcon.hide()
  826. if (!thingLayer.geoIconList) {
  827. thingLayer.geoIconList = []
  828. }
  829. thingLayer.geoIconList.push(geoIcon)
  830. // thingLayer.geoIconList.push(geoIcon)
  831. // geoIcon.noMesh = true
  832. geoIcon.updateSymbol({ 'textName': tag.playerName })
  833. thingLayer.addGeometry(geoIcon)
  834. if (tag.setGeoIcon) {
  835. tag.setGeoIcon(geoIcon)
  836. }
  837. // const clusterLayer = this.getLayer('cluster')
  838. // const geoCluster = new maptalks.Circle(start, radius, {
  839. // 'symbol': {
  840. // lineColor: '#ffffff',
  841. // lineWidth: 2,
  842. // polygonFill: '#ff0000',
  843. // polygonOpacity: 0.4
  844. // }
  845. // })
  846. // if (!clusterLayer.clusterList) {
  847. // clusterLayer.clusterList = []
  848. // }
  849. // clusterLayer.clusterList.push(geoCluster)
  850. // clusterLayer.addGeometry(geoCluster)
  851. // tag.setGeoCluster ? tag.setGeoCluster(geoCluster) : null
  852. // tag.refreshCluster(tag.cluster)
  853. this._tags.push(tag)
  854. }
  855. clean() {
  856. this.mt.remove()
  857. }
  858. clearSelection() {
  859. for (const g of this.selGeos) {
  860. g.endEdit()
  861. g.config('draggable', false)
  862. }
  863. this.selGeos = []
  864. }
  865. visibleTag(addr, show) {
  866. const tag = this.getTag(addr)
  867. if (tag) {
  868. tag.showInAtlas = show
  869. }
  870. }
  871. sortLayers() {
  872. const sortLayerIds = []
  873. for (const v of LAYER_DEFINES) {
  874. if (this.getLayer(v.name)) {
  875. sortLayerIds.push(v.name)
  876. }
  877. }
  878. for (const layer of this.mt.getLayers()) {
  879. if (sortLayerIds.indexOf(layer.getId()) < 0) {
  880. sortLayerIds.push(layer.getId())
  881. }
  882. }
  883. const drawLayer = this.mt.getLayer('_maptalks__internal_layer_drawtool')
  884. if (drawLayer) {
  885. sortLayerIds.push(drawLayer.getId())
  886. }
  887. this.mt.sortLayers(sortLayerIds)
  888. }
  889. clearTraceByTimespan(timespan) {
  890. for (const tag of this._tags) {
  891. tag.removeLines(timespan)
  892. tag.clearPath()
  893. }
  894. }
  895. create3dMesh() {
  896. const self = this
  897. const features = []
  898. this.laycons['wall'].layer.forEach(function (g) {
  899. features.push(g.toGeoJSON())
  900. })
  901. this.laycons['thing'].layer.forEach(function (g) {
  902. if (!g.noMesh) {
  903. features.push(g.toGeoJSON())
  904. }
  905. })
  906. this._layer3d.clearMesh()
  907. this._layer3d.hide()
  908. features.forEach(function (g) {
  909. let altitude = 0
  910. let height = 0
  911. let color = '#333333'
  912. let opacity = 1
  913. if (g.properties) {
  914. altitude = g.properties.altitude || altitude
  915. height = g.properties.height || height
  916. color = g.properties.polygonFill || color
  917. opacity = g.properties.polygonOpacity || opacity
  918. }
  919. const m = new THREE.MeshPhongMaterial({ color: color, opacity: opacity })
  920. const mesh = self._layer3d.toExtrudeMesh(maptalks.GeoJSON.toGeometry(g), altitude + height, m, height)
  921. // mesh.rotateY(angle2radian(90))
  922. if (Array.isArray(mesh)) {
  923. self._layer3d.getScene().add.apply(self._layer3d.getScene(), mesh)
  924. } else {
  925. self._layer3d.getScene().add(mesh)
  926. }
  927. })
  928. this._layer3d.show()
  929. }
  930. createAni(styles, options, stepCb) {
  931. return maptalks.animation.Animation.animate(
  932. styles, options, stepCb)
  933. }
  934. recreateAtlas() {
  935. const jObj = this.toJSON()
  936. this.clean()
  937. this.fromJSON(jObj)
  938. }
  939. createAtlas(node) {
  940. this.zoom = this.cfg.zoom
  941. this._node = node
  942. this.centerX = this.cfg.centerX
  943. this.centerY = this.cfg.centerY
  944. this.mt = new maptalks.Map(node, {
  945. // zoomControl : true,
  946. center: [this.centerX, this.centerY],
  947. zoom: this.zoom,
  948. pitch: this.pitch,
  949. bearing: this.bearing,
  950. attribution: {
  951. 'content1': '<span style="padding:4px;">&copy; <a href="http://www.scenauto.com">上海迅见</a> 自主研发</span>',
  952. 'content': ''
  953. }
  954. })
  955. // const dpr = this.mt.getDevicePixelRatio()
  956. // const scaler = dpr > 1 ? 2 : 1
  957. console.log('mapMode', this.cfg.mapMode)
  958. if (this.cfg.mapMode != 0) {
  959. console.log('PROJECTIONS[this.cfg.mapMode]', PROJECTIONS[this.cfg.mapMode])
  960. this.mt.setBaseLayer(new maptalks.TileLayer('base', {
  961. maxAvailableZoom: PROJECTIONS[this.cfg.mapMode].maxAvailableZoom,
  962. urlTemplate: PROJECTIONS[this.cfg.mapMode].urlTemplate,
  963. subdomains: PROJECTIONS[this.cfg.mapMode].subdomains,
  964. attribution: ' '
  965. }))
  966. }
  967. this.mt.setSpatialReference({
  968. resolutions: PROJECTIONS[this.cfg.mapMode].resolutions,
  969. projection: PROJECTIONS[this.cfg.mapMode].projection,
  970. fullExtent: PROJECTIONS[this.cfg.mapMode].fullExtent
  971. })
  972. this.mt.setMaxZoom(24)
  973. this.originView = this.mt.getView()
  974. // this.focusZero()
  975. // this.focusCenter()
  976. this.raycaster = new THREE.Raycaster()
  977. this.initMapOperation()
  978. return this
  979. }
  980. createLaycons() {
  981. for (const item of LAYER_DEFINES) {
  982. const laycon = new Laycon(item, this)
  983. laycon.show()
  984. if (laycon.type === 'vec3d') {
  985. this._layer3d = laycon.layer
  986. }
  987. }
  988. }
  989. fitExtent(opts) {
  990. const inVec = ['border', 'wall', 'anchor', 'thing']
  991. let extent = opts
  992. if (!extent) {
  993. for (const item of LAYER_DEFINES) {
  994. if (item.type === 'vector' && inVec.indexOf(item.name) >= 0) {
  995. const layer = this.getLayer(item.name)
  996. if (layer) {
  997. const e = layer.getExtent()
  998. if (e) {
  999. if (extent == null) {
  1000. extent = new maptalks.Extent(e.xmin, e.ymin, e.xmax, e.ymax)
  1001. }
  1002. if (e.xmin < extent.xmin) {
  1003. extent.xmin = e.xmin
  1004. }
  1005. if (e.ymin < extent.ymin) {
  1006. extent.ymin = e.ymin
  1007. }
  1008. if (e.xmax > extent.xmax) {
  1009. extent.xmax = e.xmax
  1010. }
  1011. if (e.ymax > extent.ymax) {
  1012. extent.ymax = e.ymax
  1013. }
  1014. }
  1015. }
  1016. }
  1017. }
  1018. }
  1019. this.mt.fitExtent(extent, 0, { 'duration': 50 })
  1020. return extent
  1021. }
  1022. fromJSON(jObj, additionAnchors = null, additionDevices = null) {
  1023. this.mt.remove()
  1024. this._drawMode = null
  1025. this.laycons = {}
  1026. this._layer3d = null
  1027. this.selGeos = []
  1028. // load mt cfg
  1029. this.cfg.fromJSON(jObj.cfg)
  1030. this.centerX = this.cfg.centerX
  1031. this.centerY = this.cfg.centerY
  1032. let content = {}
  1033. content = jObj.content
  1034. this.zoom = this.cfg.zoom
  1035. // load mt
  1036. this.mt = maptalks.Map.fromJSON(this._node, content.mt)
  1037. this.mt.setMaxZoom(30)
  1038. if (!this.mt.getBaseLayer()) {
  1039. if (this.cfg.mapMode != 0) {
  1040. console.log('PROJECTIONS[this.cfg.mapMode]', PROJECTIONS[this.cfg.mapMode])
  1041. this.mt.setBaseLayer(new maptalks.TileLayer('base', {
  1042. maxAvailableZoom: PROJECTIONS[this.cfg.mapMode].maxAvailableZoom,
  1043. maxZoom: 24,
  1044. urlTemplate: PROJECTIONS[this.cfg.mapMode].urlTemplate,
  1045. subdomains: PROJECTIONS[this.cfg.mapMode].subdomains,
  1046. attribution: ' '
  1047. // tileSystem: PROJECTIONS[this.cfg.mapMode].tileSystem,
  1048. }))
  1049. }
  1050. }
  1051. this.mt.config('seamlessZoom', true)
  1052. this.mt.config('spatialReference', {
  1053. resolutions: PROJECTIONS[this.cfg.mapMode].resolutions,
  1054. projection: PROJECTIONS[this.cfg.mapMode].projection,
  1055. fullExtent: PROJECTIONS[this.cfg.mapMode].fullExtent
  1056. })
  1057. this.mt.config('fpsOnInteracting', 0)
  1058. // load vector layers
  1059. for (const item of LAYER_DEFINES) {
  1060. for (const layer of this.mt.getLayers()) {
  1061. if (layer.getId() === item.name) {
  1062. const laycon = new Laycon(item, this, layer)
  1063. if (this.editable) {
  1064. laycon.show()
  1065. } else {
  1066. item.runShow ? laycon.show() : laycon.hide()
  1067. }
  1068. if (laycon.type === 'vec3d') {
  1069. this._layer3d = laycon.layer
  1070. }
  1071. break
  1072. }
  1073. }
  1074. }
  1075. // load bg conf
  1076. this.bgConf.fromJSON(jObj.bgConf)
  1077. const bgLaycon = new Laycon(LAYER_DEFINES[LAYER_ID_DEFS['IdBg']], this)
  1078. this.refreshBg(this.bgConf)
  1079. bgLaycon.show()
  1080. let laycon = null
  1081. // load anchors
  1082. let idxLaycon = LAYER_ID_DEFS['IdAnchor']
  1083. laycon = new Laycon(LAYER_DEFINES[idxLaycon], this)
  1084. !this.editable && LAYER_DEFINES[idxLaycon].runShow ? laycon.show() : laycon.hide()
  1085. const anchors = jObj.content.anchors || []
  1086. for (const anc of anchors) {
  1087. this.addAnchor(anc)
  1088. }
  1089. // load data
  1090. idxLaycon = LAYER_ID_DEFS['IdData']
  1091. laycon = new Laycon(LAYER_DEFINES[idxLaycon], this)
  1092. !this.editable && LAYER_DEFINES[idxLaycon].runShow ? laycon.show() : laycon.hide()
  1093. const dataItems = content.dataItems || []
  1094. for (const d of dataItems) {
  1095. this.addDataItem(d)
  1096. }
  1097. // load devices
  1098. idxLaycon = LAYER_ID_DEFS['IdDevice']
  1099. laycon = new Laycon(LAYER_DEFINES[idxLaycon], this)
  1100. !this.editable && LAYER_DEFINES[idxLaycon].runShow ? laycon.show() : laycon.hide()
  1101. const devices = content.devices || []
  1102. for (const dev of devices) {
  1103. if (additionDevices) {
  1104. for (const v of additionDevices) {
  1105. if (Number(v.addr) === Number(dev.addr)) {
  1106. dev.jobId = v.jobId
  1107. break
  1108. }
  1109. }
  1110. }
  1111. this.addDevice(dev)
  1112. }
  1113. // load areas
  1114. idxLaycon = LAYER_ID_DEFS['IdArea']
  1115. laycon = new Laycon(LAYER_DEFINES[idxLaycon], this)
  1116. !this.editable && LAYER_DEFINES[idxLaycon].runShow ? laycon.show() : laycon.hide()
  1117. const areas = jObj.content.areas || []
  1118. for (const area of areas) {
  1119. this.addArea(area)
  1120. }
  1121. // load trace
  1122. idxLaycon = LAYER_ID_DEFS['IdTrace']
  1123. laycon = new Laycon(LAYER_DEFINES[idxLaycon], this)
  1124. !this.editable && LAYER_DEFINES[idxLaycon].runShow ? laycon.show() : laycon.hide()
  1125. // create 3D
  1126. idxLaycon = LAYER_ID_DEFS['Id3d']
  1127. laycon = new Laycon(LAYER_DEFINES[idxLaycon], this)
  1128. this._layer3d = laycon.layer
  1129. this._layer3d.clearMesh()
  1130. this._layer3d.show()
  1131. // create sheet
  1132. idxLaycon = LAYER_ID_DEFS['IdSheet']
  1133. laycon = new Laycon(LAYER_DEFINES[idxLaycon], this)
  1134. this.editable || LAYER_DEFINES[idxLaycon].runShow ? laycon.show() : laycon.hide()
  1135. // create tag
  1136. idxLaycon = LAYER_ID_DEFS['IdTag']
  1137. laycon = new Laycon(LAYER_DEFINES[idxLaycon], this)
  1138. this.editable || LAYER_DEFINES[idxLaycon].runShow ? laycon.show() : laycon.hide()
  1139. // create stat
  1140. idxLaycon = LAYER_ID_DEFS['IdStat']
  1141. laycon = new Laycon(LAYER_DEFINES[idxLaycon], this)
  1142. this.editable || LAYER_DEFINES[idxLaycon].runShow ? laycon.show() : laycon.hide()
  1143. // create heat
  1144. idxLaycon = LAYER_ID_DEFS['IdHeat']
  1145. laycon = new Laycon(LAYER_DEFINES[idxLaycon], this)
  1146. this.editable || LAYER_DEFINES[idxLaycon].runShow ? laycon.show() : laycon.hide()
  1147. // create sign
  1148. if (this.getLaycon('sign')) {
  1149. this.removeLaycon('sign')
  1150. }
  1151. idxLaycon = LAYER_ID_DEFS['IdSign']
  1152. laycon = new Laycon(LAYER_DEFINES[idxLaycon], this)
  1153. this.editable || LAYER_DEFINES[idxLaycon].runShow ? laycon.show() : laycon.hide()
  1154. const sortLayerIds = []
  1155. for (const v of LAYER_DEFINES) {
  1156. if (this.getLayer(v.name)) {
  1157. sortLayerIds.push(v.name)
  1158. }
  1159. }
  1160. this.mt.sortLayers(sortLayerIds)
  1161. // load view
  1162. const view = content.view
  1163. view ? this.mt.setView(view) : null
  1164. this.originView = this.mt.getView()
  1165. this.raycaster = new THREE.Raycaster()
  1166. this.initMapOperation()
  1167. this._tickRefresh++
  1168. this.sortLayers()
  1169. this.focusCenter()
  1170. }
  1171. getLaycon(name) {
  1172. return this.laycons[name]
  1173. }
  1174. getLayer(name) {
  1175. if (this.laycons[name]) {
  1176. return this.laycons[name].layer
  1177. }
  1178. return null
  1179. }
  1180. getMap() {
  1181. return this.mt
  1182. }
  1183. getTag(addr) {
  1184. for (const tag of this._tags) {
  1185. if (tag.addr === Number(addr)) {
  1186. return tag
  1187. }
  1188. }
  1189. return null
  1190. }
  1191. init(opts) {
  1192. if (!opts) opts = {}
  1193. }
  1194. initMapOperation() {
  1195. this._initMapClick()
  1196. this._initMapDblClick()
  1197. this.mt.on('addlayer', (type, target, layers) => {
  1198. //console.log('addlayer', type, target)
  1199. this.sortLayers()
  1200. })
  1201. this.mt.on('removelayer', (type, target, layers) => {
  1202. //console.log('removelayer', type, target)
  1203. })
  1204. this.resetMapOperation()
  1205. this.mt.on('cluster-compute-grid', () => {
  1206. if (this.cbOnClusterChange) {
  1207. this.cbOnClusterChange()
  1208. }
  1209. })
  1210. }
  1211. resetMapOperation() {
  1212. this._initContextMenu()
  1213. if (this.drawTool) {
  1214. this.removeControl(this.drawTool)
  1215. this.drawTool = null
  1216. }
  1217. if (this.editable) {
  1218. this._initDrawTool()
  1219. }
  1220. }
  1221. atlasId() {
  1222. return this.cfg.id
  1223. }
  1224. atlasName() {
  1225. return this.cfg.name
  1226. }
  1227. clearFocusTag() {
  1228. for (let i = 0; i < this._tags.length; i++) {
  1229. const tag = this._tags[i]
  1230. tag.isFocus = false
  1231. }
  1232. }
  1233. refreshBg(bgConf) {
  1234. this.bgConf.fromJSON(bgConf)
  1235. const ly = this.getLayer('bg')
  1236. if (ly) {
  1237. ly.setImages([
  1238. {
  1239. url: this.bgConf.url,
  1240. extent: [this.bgConf.minLng, this.bgConf.minLat, this.bgConf.maxLng, this.bgConf.maxLat],
  1241. opacity: 1
  1242. }
  1243. ])
  1244. } else {
  1245. console.log('not found layer bg')
  1246. }
  1247. this.focusCenter()
  1248. }
  1249. removeAllTags() {
  1250. for (let i = 0; i < this._tags.length; i++) {
  1251. const tag = this._tags[i]
  1252. tag.geoIcon ? tag.geoIcon.remove() : null
  1253. tag.geoCluster ? tag.geoCluster.remove() : null
  1254. tag.setGeoIcon(null)
  1255. tag.setGeoCluster(null)
  1256. }
  1257. this._tags.splice(0, this._tags.length)
  1258. }
  1259. removeControl(control) {
  1260. this.mt.removeControl(control)
  1261. }
  1262. removeLaycon(name) {
  1263. if (this.laycons[name]) {
  1264. this.mt.removeLayer(this.laycons[name].layer)
  1265. delete this.laycons[name]
  1266. }
  1267. }
  1268. removeAnchorByAddr(addr) {
  1269. for (let i = 0; i < this._anchors.length; i++) {
  1270. const anchor = this._anchors[i]
  1271. if (anchor.addr === Number(addr)) {
  1272. anchor.geo ? anchor.geo.remove() : null
  1273. anchor.setGeo(null)
  1274. this._anchors.splice(i, 1)
  1275. return
  1276. }
  1277. }
  1278. }
  1279. removeTagByAddr(tagAddr) {
  1280. for (let i = 0; i < this._tags.length; i++) {
  1281. const tag = this._tags[i]
  1282. if (tag.addr === Number(tagAddr)) {
  1283. tag.geoIcon ? tag.geoIcon.remove() : null
  1284. tag.geoCluster ? tag.geoCluster.remove() : null
  1285. tag.setGeoIcon(null)
  1286. tag.setGeoCluster(null)
  1287. this._tags.splice(i, 1)
  1288. return
  1289. }
  1290. }
  1291. }
  1292. returnOriginView() {
  1293. this.mt.setView(this.originView)
  1294. }
  1295. setDrawMode(opt, layerName, properties) {
  1296. if (this.editable && this.mt && this.drawTool) {
  1297. this._drawProperties = properties
  1298. switch (opt) {
  1299. case 'anchor':
  1300. this._drawMode = 'anchor'
  1301. break
  1302. case 'dylabel':
  1303. this._drawMode = 'dylabel'
  1304. break
  1305. case 'label':
  1306. this._drawMode = 'label'
  1307. break
  1308. case 'player':
  1309. this.drawTool.endDraw()
  1310. this.drawTool.setMode('point').enable()
  1311. break
  1312. case 'select':
  1313. this.drawTool.disable()
  1314. break
  1315. case 'textbox':
  1316. this._drawMode = 'textbox'
  1317. break
  1318. case 'camera':
  1319. this._drawMode = 'camera'
  1320. break
  1321. default:
  1322. this.drawTool.endDraw()
  1323. this.drawTool.setMode(opt).enable()
  1324. break
  1325. }
  1326. if (layerName) {
  1327. this.setSelLaycon(layerName)
  1328. }
  1329. }
  1330. }
  1331. focusCenter() {
  1332. this.mt.setCenter({ x: this.centerX, y: this.centerY })
  1333. }
  1334. focusPt(x, y) {
  1335. this.mt.setCenter({ x: x, y: y })
  1336. }
  1337. focusZero() {
  1338. this.mt.setCenter({ x: 0, y: 0 })
  1339. }
  1340. setCfg(cfg) {
  1341. this.cfg.fromJSON(cfg)
  1342. }
  1343. setSelLaycon(name) {
  1344. this.selLaycon = this.laycons[name]
  1345. return this
  1346. }
  1347. setZoom(zoom) {
  1348. this.mt.setZoom(zoom)
  1349. }
  1350. showLaycon(name) {
  1351. const laycon = this.getLaycon(name)
  1352. laycon ? laycon.show() : null
  1353. }
  1354. ChangeTo3D() {
  1355. const self = this
  1356. console.log('切换为3d')
  1357. console.log('layer 3d c', this._layer3d, this._layer3d.getScene())
  1358. const c2 = new maptalks.Coordinate([0.1, 0.1])
  1359. this.mt.panBy(c2, {
  1360. during: 600
  1361. })
  1362. const targetStyles = {
  1363. opacity: 1
  1364. }
  1365. const aniGlow = maptalks.animation.Animation.animate(
  1366. targetStyles,
  1367. {
  1368. duration: 1000,
  1369. easing: 'out'
  1370. },
  1371. // callback of each frame
  1372. function step(frame) {
  1373. if (frame.state.playState === 'running') {
  1374. if (self._layer3d) {
  1375. self._layer3d.setOpacity(frame.styles.opacity)
  1376. }
  1377. }
  1378. if (frame.state.playState === 'finished') {
  1379. if (self._layer3d) {
  1380. self._layer3d.setOpacity(1)
  1381. }
  1382. }
  1383. }
  1384. )
  1385. setTimeout(() => {
  1386. this.mt.config('dragRotatePitch', true)
  1387. this.mt.config('dragRotate', true)
  1388. this.mt.config('dragPitch', true)
  1389. this.mt.animateTo({
  1390. // center: [-74.10704772446428, 40.66032606133018],
  1391. // zoom: 18,
  1392. pitch: 50,
  1393. bearing: 50
  1394. }, {
  1395. duration: 1000
  1396. }, (frame) => {
  1397. if (frame.state.playState === 'finished') {
  1398. this.create3dMesh()
  1399. this._layer3d.setOpacity(0)
  1400. this._layer3d.hide()
  1401. this._layer3d.show()
  1402. setTimeout(() => {
  1403. aniGlow.play()
  1404. }, 100)
  1405. // setTimeout(() => {
  1406. // this.create3dMesh()
  1407. // this.layer3d.hide()
  1408. // this.layer3d.show()
  1409. // }, 600)
  1410. }
  1411. })
  1412. }, 650)
  1413. }
  1414. ChangeTo2D() {
  1415. console.log('2d')
  1416. this._layer3d.clearMesh()
  1417. this.mt.animateTo({
  1418. // center: [-74.10704772446428, 40.66032606133018],
  1419. // zoom: 18,
  1420. pitch: 0,
  1421. bearing: 0
  1422. }, {
  1423. duration: 1500
  1424. }, (frame) => {
  1425. if (frame.state.playState === 'finished') {
  1426. // setTimeout(() => {
  1427. // this.mt.config('dragRotate', false)
  1428. // this.mt.config('dragPitch', false)
  1429. // }, 800)
  1430. }
  1431. })
  1432. }
  1433. toggleLaycon(name) {
  1434. const laycon = this.getLaycon(name)
  1435. if (laycon) {
  1436. if (laycon.isVisible()) {
  1437. laycon.hide()
  1438. return false
  1439. } else {
  1440. laycon.show()
  1441. return true
  1442. }
  1443. }
  1444. return false
  1445. }
  1446. showAnchors() {
  1447. const laycon = this.getLaycon('anchor')
  1448. laycon.show()
  1449. }
  1450. showSheets() {
  1451. const laycon = this.getLaycon('sheet')
  1452. laycon.show()
  1453. }
  1454. hideAnchors() {
  1455. const laycon = this.getLaycon('anchor')
  1456. laycon.hide()
  1457. }
  1458. hideSheets() {
  1459. const laycon = this.getLaycon('sheet')
  1460. laycon.hide()
  1461. }
  1462. tickRefresh() {
  1463. return this._tickRefresh
  1464. }
  1465. toJSON() {
  1466. const obj = {}
  1467. // export vector layers
  1468. const layerExports = []
  1469. layerExports.push({ id: 'border' })
  1470. layerExports.push({ id: 'wall' })
  1471. layerExports.push({ id: 'thing' })
  1472. layerExports.push({ id: 'label' })
  1473. layerExports.push({ id: 'sign' })
  1474. // layerExports.push({ id: 'anchor' })
  1475. // layerExports.push({ id: 'area' })
  1476. // save map bg
  1477. obj.bgConf = this.bgConf.toJSON()
  1478. // save map defines
  1479. obj.cfg = this.cfg.toJSON()
  1480. const content = {}
  1481. content.mt = this.mt.toJSON({ layers: layerExports })
  1482. content.view = this.mt.getView()
  1483. content.anchors = []
  1484. this.getLayer('anchor').forEach((g) => {
  1485. content.anchors.push({
  1486. id: g.getId(),
  1487. name: g.properties['name'] || '',
  1488. addr: g.properties['addr'] || 0,
  1489. altitude: g.properties['altitude'] || 0,
  1490. coordinates: g.getCoordinates()
  1491. })
  1492. })
  1493. content.areas = []
  1494. this.getLayer('area').forEach((g) => {
  1495. content.areas.push({
  1496. id: g.getId(),
  1497. addr: g.properties['addr'] || 0,
  1498. level: g.properties['level'] || 0,
  1499. delay: g.properties['delay'] || 0,
  1500. coordinates: g.getCoordinates(),
  1501. geoJson: g.toGeoJSON()
  1502. })
  1503. })
  1504. content.dataItems = []
  1505. this.getLayer('data').forEach((g) => {
  1506. content.dataItems.push({
  1507. id: g.getId(),
  1508. props: g.properties,
  1509. type: g.properties['type'] || 'unknown',
  1510. coordinates: g.getCoordinates(),
  1511. geoJson: g.toJSON()
  1512. })
  1513. })
  1514. content.devices = []
  1515. this.getLayer('device').forEach((g) => {
  1516. content.devices.push({
  1517. id: g.getId(),
  1518. props: g.properties,
  1519. type: g.properties['type'] || 'unknown',
  1520. coordinates: g.getCoordinates(),
  1521. geoJson: g.toGeoJSON()
  1522. })
  1523. })
  1524. //obj.content = content
  1525. obj.content = (JSON.stringify(content))
  1526. // save anchor includes
  1527. return obj
  1528. }
  1529. updateLayconData(source) {
  1530. const ly = this.getLayer('data')
  1531. if (!ly) {
  1532. return
  1533. }
  1534. ly.forEach((g) => {
  1535. const props = g.getProperties()
  1536. const bindDev = g.properties['bindDev']
  1537. const bindAddr = g.properties['bindAddr']
  1538. const bindProp = g.properties['bindProp']
  1539. const bindEnable = g.properties['bindEnable']
  1540. if (source[bindDev]) {
  1541. const src = source[bindDev]
  1542. if (src instanceof Array) {
  1543. for (const v of src) {
  1544. if (v && Number(v['addr']) === Number(bindAddr)) {
  1545. let flag = true
  1546. if (bindEnable && !v[bindEnable]) {
  1547. flag = false
  1548. }
  1549. if (flag) {
  1550. const p = Math.pow(10, Number(props['precision']))
  1551. props['val'] = Math.round(Number(v[bindProp]) * p) / p
  1552. g.setProperties(props)
  1553. } else {
  1554. props['val'] = props['defVal']
  1555. g.setProperties(props)
  1556. }
  1557. break
  1558. }
  1559. }
  1560. } else {
  1561. if (src[bindAddr]) {
  1562. let flag = true
  1563. if (bindEnable && !src[bindAddr][bindEnable]) {
  1564. flag = false
  1565. }
  1566. if (flag) {
  1567. const p = Math.pow(10, Number(props['precision']))
  1568. props['val'] = Math.round(Number(src[bindAddr][bindProp]) * p) / p
  1569. g.setProperties(props)
  1570. } else {
  1571. props['val'] = props['defVal']
  1572. g.setProperties(props)
  1573. }
  1574. }
  1575. }
  1576. }
  1577. })
  1578. }
  1579. updateHisLayconData(src, devType) {
  1580. this.getLayer('data').forEach((g) => {
  1581. const props = g.getProperties()
  1582. const hisEnable = props['hisEnable']
  1583. if (!hisEnable) return
  1584. const bindHisDev = g.properties['bindHisDev']
  1585. if (Number(bindHisDev) !== Number(devType)) return
  1586. const bindHisAddr = g.properties['bindHisAddr']
  1587. const bindHisProp = g.properties['bindHisProp']
  1588. const bindHisEnable = g.properties['bindHisEnable']
  1589. if (src && Number(src['addr']) === Number(bindHisAddr)) {
  1590. let flag = true
  1591. if (bindHisEnable && !src[bindHisEnable]) {
  1592. flag = false
  1593. }
  1594. if (flag) {
  1595. const p = Math.pow(10, Number(props['precision']))
  1596. props['val'] = Math.round(Number(src[bindHisProp]) * p) / p
  1597. g.setProperties(props)
  1598. } else {
  1599. props['val'] = props['defVal']
  1600. g.setProperties(props)
  1601. }
  1602. }
  1603. })
  1604. }
  1605. }
  1606. const PROJECTIONS =
  1607. [
  1608. {
  1609. id: 0, name: '虚拟底图',
  1610. resolutions: createResolutions(),
  1611. projection: 'identity',
  1612. urlTemplate: null,
  1613. subdomains: null,
  1614. fullExtent: {
  1615. 'top': 10000,
  1616. 'left': -10000,
  1617. 'bottom': -10000,
  1618. 'right': 10000
  1619. }
  1620. },
  1621. {
  1622. id: 1, name: '默认底图',
  1623. resolutions: createResolutions(),
  1624. projection: null,
  1625. urlTemplate: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
  1626. subdomains: ['a', 'b', 'c', 'd']
  1627. },
  1628. {
  1629. id: 2, name: '百度底图',
  1630. resolutions: null,
  1631. // resolutions: createResolutions(),
  1632. projection: 'baidu',
  1633. maxAvailableZoom: 19,
  1634. // urlTemplate: 'https://maponline{s}.bdimg.com/tile/?qt=vtile&styles=pl&from=jsapi2_0&x={x}&y={y}&z={z}&styles=pl&scaler=1&udt=',
  1635. urlTemplate: 'https://maponline{s}.bdimg.com/tile/?qt=vtile&styles=pl&from=jsapi2_0&x={x}&y={y}&z={z}&styles=pl&scaler=1&udt=2019&scale=2',
  1636. subdomains: [0, 1, 2, 3]
  1637. },
  1638. // {
  1639. // id: 2, name: '百度底图',
  1640. // resolutions: null,
  1641. // resolutions: createResolutions(),
  1642. // // projection: 'baidu',
  1643. // maxAvailableZoom: 18,
  1644. // // urlTemplate: 'https://maponline{s}.bdimg.com/tile/?qt=vtile&styles=pl&from=jsapi2_0&x={x}&y={y}&z={z}&styles=pl&scaler=1&udt=',
  1645. // urlTemplate: 'https://swapi2.siweiearth.com/sj_raster/v6/wmts/tile/10001601/2?ak=mt5b5ec0404e8795f7b267d7f3b94fc595&tilematrix={z}&tilecol={x}&tilerow={y}&request=gettile&service=wmTs',
  1646. // subdomains: ['0', '1', '2', '3'],
  1647. // },
  1648. {
  1649. id: 3, name: '百度统计底图',
  1650. resolutions: null,
  1651. projection: 'baidu',
  1652. urlTemplate: 'https://gss{s}.bdstatic.com/8bo_dTSlRsgBo1vgoIiO_jowehsv/tile/?qt=tile&x={x}&y={y}&z={z}&styles=pl&scaler=1&udt=20170927',
  1653. subdomains: [0, 1, 2, 3]
  1654. },
  1655. {
  1656. id: 4, name: '腾讯地图',
  1657. resolutions: null,
  1658. urlTemplate: 'http://rt{s}.map.gtimg.com/realtimerender?z={z}&x={x}&y={y}&type=vector&style=0',
  1659. subdomains: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
  1660. tileSystem: 'tms-global-mercator'
  1661. },
  1662. {
  1663. id: 5, name: '高德底图',
  1664. resolutions: createResolutions(),
  1665. urlTemplate: 'http://wprd{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&z={z}&x={x}&y={y}&scl=1&ltype=11',
  1666. subdomains: ['01', '02', '03', '04']
  1667. },
  1668. {
  1669. id: 6, name: '天地图底图',
  1670. resolutions: createResolutions(),
  1671. maxAvailableZoom: 18,
  1672. urlTemplate: 'https://t5.tianditu.gov.cn/DataServer?T=img_w&X={x}&Y={y}&L={z}&tk=074d4a21c8f34a3a20cd1f69f81b26bf',
  1673. subdomains: ['a', 'b', 'c', 'd'] //负载均衡-以提高地图数据加载的效率
  1674. },
  1675. {
  1676. id: 7, name: 'ARC-GIS底图',
  1677. resolutions: createResolutions(),
  1678. maxAvailableZoom: 18,
  1679. urlTemplate: 'https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
  1680. subdomains: null
  1681. }
  1682. ]
  1683. export {
  1684. MapEngine,
  1685. DRAW_MODE,
  1686. PROJECTIONS
  1687. }