Marker.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. import Feature from 'ol/Feature'
  2. import Point from 'ol/geom/Point'
  3. import * as proj from 'ol/proj'
  4. import Style from 'ol/style/Style'
  5. import Text from 'ol/style/Text'
  6. import Fill from 'ol/style/Fill'
  7. import Stroke from 'ol/style/Stroke'
  8. import Icon from 'ol/style/Icon'
  9. import Overlay from 'ol/Overlay'
  10. import Common from './Common'
  11. import KBaseObject from './KBaseObject'
  12. import LngLat from './LngLat'
  13. import InfoWindow from './InfoWindow'
  14. /**
  15. * @description KMap.Marker 点标记类
  16. */
  17. class Marker extends KBaseObject{
  18. /**
  19. * @description 初始化Marker构造函数
  20. * @param {number} lng lng 经度 必填
  21. * @param {number} lat lat 纬度 必填
  22. * @param {String} markerImgUrl 点标记图标路径 必填
  23. * @param {number} offsetX X方向偏移量(正向右,负向左) 必填
  24. * @param {number} offsetY Y方向偏移量(正向下,负向上) 必填
  25. * @param {number} width 点标记尺寸宽度 必填
  26. * @param {number} height 点标记尺寸高度 必填
  27. * @param {JSON} param param.source 指定source 选填
  28. * @param {KMap.Map} [mapInstance=null] map对象,单地图的时候可不传,多地图时候需要传
  29. * @constructor
  30. */
  31. constructor(lng,lat,url,offsetX,offsetY,width,height,param,mapInstance = null){
  32. super(mapInstance)
  33. const vm = this
  34. //对于必填的参数进行验证
  35. let lnglat = [lng,lat];
  36. if(vm.map.getView().getProjection() == proj.get("EPSG:3857")){
  37. lnglat = proj.fromLonLat([lng,lat]);
  38. }
  39. vm.point = new Point(lnglat)
  40. let marker = new Feature({
  41. geometry: vm.point,
  42. properties: null
  43. })
  44. vm.marker = marker
  45. vm.source = vm.mapInstance.markerLayer.getSource()
  46. if(param && param.source){
  47. vm.source = param.source
  48. }
  49. vm.source.addFeature(marker)
  50. Common.notEmpty("url",url)
  51. vm.url = url
  52. vm.style = vm.initSyle(vm.url,offsetX,offsetY,width,height)
  53. vm.image = vm.style.getImage()
  54. vm.contentInfo = {}
  55. Common.checkLngLat(lng,lat)
  56. vm.lngLat = [lng,lat]
  57. }
  58. /**
  59. * @description 初始化Marker样式
  60. * @param {String} url marker 图片地址
  61. * @param {number} offsetX X方向偏移量(正向右,负向左) 必填
  62. * @param {number} offsetY Y方向偏移量(正向下,负向上) 必填
  63. * @param {number} width 点标记尺寸宽度 必填
  64. * @param {number} height 点标记尺寸高度 必填
  65. * @memberof Marker
  66. */
  67. initSyle(url,offsetX,offsetY,width,height){
  68. const vm = this
  69. offsetX = -offsetX/width
  70. offsetY = -offsetY/height
  71. let style = new Style({
  72. image: new Icon({
  73. src: url,
  74. anchor: [offsetX,offsetY] //点标记偏移
  75. }),
  76. zIndex: 0
  77. })
  78. vm.marker.setStyle(style)
  79. return style
  80. }
  81. /**
  82. * @description 获取点标记id
  83. * @returns {String} 点标记id
  84. */
  85. getId() {
  86. const vm = this
  87. let id = vm.marker.getId()
  88. return id
  89. }
  90. /**
  91. * @description 设置点标记id
  92. * @param {String}id 点标记id 必填
  93. */
  94. setId(id) {
  95. const vm = this
  96. vm.marker.setId(id)
  97. }
  98. /**
  99. * 点标记添加文本
  100. * @param {JSON} param json对象,文本参数,必填
  101. * param.text 文本内容,必填
  102. * param.font 字体大小,默认为13px sans-serif,选填
  103. * param.offsetX X轴偏移(正向右,负向左),选填,默认为0
  104. * param.offsetY Y轴偏移(正向下,负向上),选填,默认为25
  105. * param.rotation 旋转角度,选填,默认0
  106. * param.fill 填充颜色,选填,默认black
  107. * param.backgroundColor 背景色,选填,默认#fff
  108. * param.backgroundStroke 边框颜色,选填,默认black
  109. * param.padding padding值,选填,默认[2,5,2,5]
  110. */
  111. setText(param) {
  112. const vm = this
  113. let text = (param.text)? param.text : ""
  114. let font = (param.font)? param.font : '13px sans-serif'
  115. let offsetX = (param.offsetX)? param.offsetX : 0
  116. let offsetY = (param.offsetY)? param.offsetY : 25
  117. let rotation = (param.rotation)? param.rotation : 0
  118. let fill = (param.fill)? param.fill : "black"
  119. let backgroundColor = (param.backgroundColor)? param.backgroundColor : "#fff"
  120. let backgroundStroke = (param.backgroundStroke)? param.backgroundStroke : "black"
  121. let padding = (param.padding)? param.padding : [2,5,2,5]
  122. text = new Text({
  123. text: text,
  124. font: font,
  125. offsetX: offsetX,
  126. offsetY: offsetY,
  127. rotateWithView: false,//文本是否可旋转
  128. rotation: rotation,
  129. fill: new Fill({
  130. color: fill
  131. }),
  132. backgroundFill: new Fill({
  133. color: backgroundColor
  134. }),
  135. backgroundStroke: new Stroke({
  136. color: backgroundStroke
  137. }),
  138. padding: padding
  139. })
  140. if(text){
  141. vm.style.setText(text)
  142. }
  143. }
  144. /**
  145. * @description 显示点标记
  146. */
  147. show(){
  148. const vm = this
  149. if(!vm.source.hasFeature(vm.marker)) {
  150. vm.source.addFeature(vm.marker)
  151. if(vm.markerPopup){
  152. vm.map.removeOverlay(vm.markerPopup)
  153. }
  154. vm.showContent()
  155. }
  156. }
  157. /**
  158. * @description 隐藏点标记
  159. */
  160. hide(){
  161. const vm = this
  162. if(vm.source.hasFeature(vm.marker)) {
  163. vm.source.removeFeature(vm.marker);
  164. if(vm.markerPopup){
  165. vm.map.removeOverlay(vm.markerPopup)
  166. }
  167. vm.hideContent()
  168. }
  169. }
  170. /**
  171. * @description 删除点标记
  172. */
  173. remove(){
  174. const vm = this
  175. if(vm.source.hasFeature(vm.marker)) {
  176. vm.source.removeFeature(vm.marker)
  177. if(vm.markerPopup){
  178. vm.map.removeOverlay(vm.markerPopup)
  179. }
  180. vm.hideContent()
  181. }
  182. }
  183. /**
  184. * @description 设置点标记为透明样式
  185. */
  186. setHideStyle(){
  187. const vm = this
  188. let hideStyle = new Style({
  189. stroke: new Stroke({
  190. color: "transparent",
  191. width: 1
  192. })
  193. })
  194. vm.marker.setStyle(hideStyle)
  195. }
  196. /**
  197. * @description 获取点标记图标地址
  198. * @returns {String} 点标记图标地址
  199. */
  200. getIcon(){
  201. const vm = this
  202. let icon = vm.image.iconImage_.src_
  203. return icon
  204. }
  205. /**
  206. * @description 设置点标记图标
  207. * @param {String} url 点标记图标地址,必填
  208. */
  209. setIcon(url,offsetX,offsetY){
  210. const vm = this
  211. let style = new Style({
  212. image: new Icon({
  213. src: url,
  214. anchor: [offsetX,offsetY] //点标记偏移
  215. }),
  216. zIndex: 0
  217. })
  218. vm.marker.setStyle(style)
  219. }
  220. /**
  221. * @description 获取点标记坐标
  222. * @returns {KMap.LngLat} 返回KMap.LngLat格式的经纬度
  223. */
  224. getPosition() {
  225. const vm = this
  226. let position = proj.toLonLat(vm.point.getCoordinates())
  227. position = Common.MapLngLat2KMapLngLat(position)
  228. return position
  229. }
  230. /**
  231. * @description 设置点标记坐标
  232. * @param {KMap.LngLat} lnglat 格式的点标记经纬度,必填
  233. */
  234. setPosition(lnglat) {
  235. const vm = this
  236. lnglat = Common.KMapLngLat2MapLngLat(lnglat)
  237. let position = proj.fromLonLat(lnglat)
  238. vm.point.setCoordinates(position)
  239. // console.log(vm.source.getState())
  240. if(vm.markerPopup){
  241. vm.markerPopup.setPosition(vm.point.getCoordinates())
  242. }
  243. }
  244. /**
  245. * @description 获取点标记缩放值
  246. * @returns 点标记缩放值
  247. */
  248. getScale() {
  249. const vm = this
  250. let scale = vm.image.getScale()
  251. return scale
  252. }
  253. /**
  254. * @description 设置点标记缩放值
  255. * @param {number}scale 缩放值,必填
  256. */
  257. setScale(scale) {
  258. const vm = this
  259. vm.image.setScale(scale)
  260. }
  261. /**
  262. * @description 获取点标记旋转弧度
  263. * @returns 点标记旋转弧度
  264. */
  265. getAngle() {
  266. const vm = this
  267. let angle = vm.image.getRotation()
  268. return angle
  269. }
  270. /**
  271. * @description 设置点标记旋转弧度
  272. * @param {number} rotation 旋转弧度,必填
  273. */
  274. setAngle(rotation) {
  275. const vm = this
  276. vm.image.setRotation(rotation)
  277. }
  278. /**
  279. * @description 获取点标记叠加顺序
  280. * @returns 点标记叠加顺序
  281. */
  282. getZIndex() {
  283. const vm = this
  284. let index = vm.style.getZIndex()
  285. return index
  286. }
  287. /**
  288. * @description 设置点标记叠加顺序
  289. * @param {number} index 叠加顺序,必填,index值较大的点标记显示在上方 ,值相同时后创建的点标记显示在上方
  290. */
  291. setZIndex(index) {
  292. const vm = this
  293. vm.style.setZIndex(index)
  294. }
  295. /**
  296. * @description 设置点标记置顶,当地图有多个marker时,当isTop为true时marker将显示在最上层;当isTop为false时取消置顶
  297. * @param {boolean} isTop 必填,true:显示在最上层,false:取消置顶
  298. */
  299. setTop(isTop) {
  300. const vm = this
  301. let markers = vm.source.getFeatures()
  302. let maxIndex = 0
  303. for(let i=0; i<markers.length; i++) {
  304. if(markers[i].getStyle().getZIndex() > maxIndex)
  305. maxIndex = markers[i].getStyle().getZIndex()
  306. }
  307. if(isTop == true) {
  308. vm.style.setZIndex(++maxIndex)
  309. }
  310. else if(isTop == false) {
  311. vm.style.setZIndex(0)
  312. }
  313. }
  314. /**
  315. * @description 获取用户自定义属性
  316. * @returns {number,String,JSON} 用户自定义属性(支持数字,字符串,json)
  317. */
  318. getExtData() {
  319. const vm = this
  320. let extData = vm.marker.values_.properties
  321. return extData
  322. }
  323. /**
  324. * @description 设置用户自定义属性
  325. * @param {number/String/JSON} extData 用户自定义属性(支持数字,字符串,json),必填
  326. */
  327. setExtData(extData) {
  328. const vm = this
  329. extData = (extData)? extData : null
  330. if(extData != null) {
  331. vm.marker.values_.properties = extData
  332. }
  333. }
  334. /**
  335. * @description 获取点标记地图对象
  336. * @returns 地图对象
  337. */
  338. getMap() {
  339. const vm = this
  340. return vm.mapInstance
  341. }
  342. /**
  343. * @description 设置点标记地图对象,传入null时,移除点标记,
  344. * 建议不使用此API,使用remove方法
  345. * @param {KMap.Map} map 传入null,移除点标记
  346. */
  347. setMap(mapInstance){
  348. const vm = this
  349. mapInstance = (mapInstance)? mapInstance : null
  350. if(mapInstance == null) { //当map为null时,删除点标记
  351. if(vm.source.hasFeature(vm.marker)) {
  352. vm.source.removeFeature(vm.marker)
  353. if(vm.markerPopup){
  354. vm.map.removeOverlay(vm.markerPopup)
  355. }
  356. vm.hideContent()
  357. }
  358. }else{
  359. if(mapInstance != vm.mapInstance){
  360. vm.mapInstance = mapInstance
  361. }
  362. }
  363. }
  364. /**
  365. * @description 注册点标记事件
  366. * @param {String} eventName 鼠标事件
  367. * "click":鼠标点击事件 "mousemove":鼠标悬停事件
  368. * @param {function} callback 选中点标记时触发函数
  369. */
  370. on(eventName,callback){
  371. const vm = this
  372. if(eventName == "dblclick"){
  373. vm.map.on(eventName,function(e){
  374. let feature = vm.map.forEachFeatureAtPixel(e.pixel,function(feature) {
  375. return feature
  376. },{
  377. layerFilter:function(e){
  378. if(e.values_.name == "defaultMarkerLayer"){
  379. return true
  380. }else{
  381. return false
  382. }
  383. }
  384. })
  385. if(feature && feature == vm.marker){
  386. callback(e)
  387. }
  388. })
  389. }else{
  390. vm.marker.on(eventName,function(e) {
  391. if(eventName == "mousemove"){
  392. if(vm.marker.ol_uid != vm.mapInstance.InfowindowmoveUID)
  393. {
  394. vm.mapInstance.InfowindowmoveUID = vm.marker.ol_uid
  395. callback(e)
  396. }
  397. }
  398. else
  399. {
  400. callback(e)
  401. }
  402. })
  403. }
  404. }
  405. /**
  406. * @description 设置鼠标悬停时,点标记显示内容
  407. * @param {title} title 鼠标悬停内容(支持div模块/字符串格式),必填
  408. * @param {number} offsetX X轴方向偏移量(正向右,负向左),选填参数,默认为0
  409. * @param {number} offsetY Y轴方向偏移量(正向下,负向上),选填参数,默认为-25
  410. */
  411. setTitle(title,offsetX,offsetY) {
  412. const vm = this
  413. title = (title != undefined)? title : ""
  414. let lnglat = vm.getPosition()
  415. vm.on("mousemove",function(){
  416. let content
  417. //if(title.indexOf("div")<0) { content = "<div class='olText'>"+title+"</div>" }
  418. if(title.indexOf("div")<0) {
  419. content = "<div class='olText'><p class='olTextP' title='"+title+"'>"+title+"</p></div>"
  420. }else {
  421. content = title
  422. }
  423. let infoWindow = new InfoWindow({
  424. content: content,
  425. position: lnglat,
  426. offsetX: offsetX,
  427. offsetY: offsetY,
  428. type: "mousemove"
  429. })
  430. infoWindow.open(false) //显示标题内容
  431. })
  432. }
  433. /**
  434. * @description 设置挂载Label
  435. * @param {DOM} content DOM元素
  436. * @param {number} offsetX DOM元素X偏移,向左为负,向右为正
  437. * @param {number} offsetY DOM元素X偏移,向上为负,向下为正
  438. * @memberof Marker
  439. */
  440. setLabel(content,offsetX,offsetY){
  441. const vm = this
  442. let contentParent = document.createElement('div')
  443. contentParent.insertAdjacentHTML('beforeend',content)
  444. let offset = [0,0]
  445. if(offsetX){
  446. offset[0] = offsetX
  447. }
  448. if(offsetY){
  449. offset[1] = offsetY
  450. }
  451. vm.markerPopup = new Overlay({
  452. element: contentParent,
  453. position: proj.fromLonLat([vm.lng,vm.lat]),
  454. offset: offset//图片偏移量
  455. })
  456. vm.map.addOverlay(vm.markerPopup)
  457. }
  458. /**
  459. * @description 移除
  460. * @memberof Marker
  461. */
  462. removeLabel(){
  463. const vm = this
  464. if(vm.markerPopup){
  465. vm.map.removeOverlay(vm.markerPopup)
  466. }
  467. }
  468. /**
  469. * @description 隐藏挂载dom元素
  470. */
  471. hideContent(){
  472. const vm = this
  473. if(vm.contentInfo.overlay && vm.contentInfo.show){
  474. vm.contentInfo.show = false
  475. vm.map.removeOverlay(vm.contentInfo.overlay)
  476. }
  477. }
  478. /**
  479. * @description 显示挂载dom元素
  480. */
  481. showContent(){
  482. const vm = this
  483. if(vm.contentInfo.overlay && !vm.contentInfo.show){
  484. vm.contentInfo.show = true
  485. vm.map.addOverlay(vm.contentInfo.overlay)
  486. }
  487. }
  488. /**
  489. * @description 设设置挂载的DOM,
  490. * @param {DOM} content 挂载到Map的DOM元素
  491. * @param {number} offsetX DOM元素在地图上X偏移,向左为负,向右为正
  492. * @param {number} offsetY DOM元素在地图上Y偏移,向上为负,向下为正
  493. * @memberof Marker
  494. */
  495. setContent(content,offsetX,offsetY){
  496. const vm = this
  497. let overlay = new Overlay({
  498. element: content,
  499. offset:[offsetX,offsetY]
  500. })
  501. vm.contentInfo.content = content
  502. vm.contentInfo.offsetX = offsetX
  503. vm.contentInfo.offsetY = offsetY
  504. vm.contentInfo.overlay = overlay
  505. vm.contentInfo.show = true
  506. vm.map.addOverlay(overlay)
  507. let coordinate = vm.lngLat
  508. overlay.setPosition(proj.fromLonLat(coordinate))
  509. }
  510. /**
  511. * @description 设置挂载的DOM可变长度的,
  512. * @param {DOM} content DOM 挂载到Map的DOM元素
  513. * @param {number} offsetY DOM元素在地图上Y偏移,向上为负,向下为正
  514. * @memberof Marker
  515. */
  516. setContentChangeAbleWidth(content,offsetY){
  517. const vm = this
  518. let overlay = new Overlay({
  519. element: content,
  520. positioning:"bottom-center",
  521. offset:[0,offsetY]
  522. })
  523. vm.contentInfo.content = content
  524. vm.contentInfo.offsetX = 0
  525. vm.contentInfo.offsetY = offsetY
  526. vm.contentInfo.overlay = overlay
  527. vm.contentInfo.show = true
  528. vm.map.addOverlay(overlay)
  529. let coordinate = vm.lngLat
  530. overlay.setPosition(proj.fromLonLat(coordinate))
  531. }
  532. }
  533. export default Marker