Some time ago I should have the demand of the company has developed a similar HOME LINK the function of the map to find room, I found on market now, however, to find room for HOME LINK map function complete implementation of the related articles or relatively scarce, or function is not perfect enough, for this, I feel myself to the full implementation of HOME LINK map searching function sharing or very be necessary, Including the circle house search, and how to break the whole map house search into components.

At present, the project has been online, click here to experience ~ (PC only)

start

1. Effect preview

2. Preparation

  • Technology stack

Vue family bucket + Vue – Bidu -map + BMapLib

Vue-bidu-map is a third-party library, which has encapsulated some components and can be used directly. BMapLib is baidu open source library

  • Component split

ZoneOverlay component (custom overlay):

Boundary component: < BM-boundary >

Peripheral house detailOverlay component (custom overlay):

< BM-Polygon >< BM-Polygon >

< BM-polyline >

Map initialization

The first thing we need to do is initialize the map using the Bidu-map component.

<div class="map-wrapper">
    <baidu-map id="bm-view" class="bm-view" :center="center" :zoom="zoom" :scroll-wheel-zoom="true" @ready="handler"></baidu-map>
</div>
Copy the code

Parameter Description:

Center indicates the center of the map, for example, {LNG: 116.404, LAT: 39.915}

Zoom indicates the zoom level of the map

Scroll wheel-zoom indicates whether the scroll wheel zoom is enabled

The ready event indicates the actions required after the map is loaded, such as setting the map center, or obtaining the BMap, map class, and so on

Handler ({BMap, map}) {// LNG, lat indicates the latitude and longitude you want to set this.$set(this.center, 'lng', lng)
    this.$set(this.center, 'lat', lat)
    console.log(BMap) // just console.log(BMap)
    console.log(map) // just console.log(map)
}
Copy the code

In this case, I first locate the longitude and latitude of the current province, pass the event, and then set the Center

handler ({BMap, map}) {
  this.initGeo()
},
initGeo () {
  connect.$on('cityGeoOk', data => {
    this.$set(this.center, 'lng', data[0])
    this.$set(this.center, 'lat', data[1])
  })
}
Copy the code

As for vUE communication across components, just like making a phone call, you need a base station, so create a new JS file (I’ll call it Connect here).

import Vue from 'vue'

export default new Vue()
Copy the code

$emit(‘event’, data) emits an event and listens for the event via connect.$on(‘event’, data => {}).

Finally, you need to set the zoom level of the map container Bidu-Map (I set 12, you can adjust the height), otherwise you can’t see the effect

.bm-view{ height: 100%; / *for example */
}
Copy the code

The effect is as follows:

Area bubble display

After the map is initialized, the next step is how to display the different areas on the map. Here I use the bm-overlay component and wrap the second time into the zoneOverlay component.

<div class="map-wrapper">
    <baidu-map id="bm-view" class="bm-view" :center="center" :zoom="zoom" :scroll-wheel-zoom="true" @ready="handler">
        <div>
            <zone-overlay
              v-for="(item, index) in zoneGeoPoints" :key="index"
              :position="{lng: item.lng, lat: item.lat}"
              :text="item">
            </zone-overlay>
        </div>
    </baidu-map>
</div>
Copy the code

ZoneGeoPoints is an array of regions. It is obtained from a background interface. Its elements are objects and its attributes include the latitude and longitude of the region.

// zoneOverlay.vue
<template>
  <bm-overlay
    ref="customOverlay"
    class="zone"
    pane="labelPane"
    @draw="draw"> < div > < p > {{text. The name}} < / p > < p > {{text. HouseCnt}} set < / p > < / div > < / bm - overlay > < / template > < script >export default {
  props: ['text'.'position'.'active'],
  watch: {
    position: {
      handler () {
        this.$refs.customOverlay.reload()
      },
      deep: true
    }
  },
  methods: {
    draw ({el, BMap, map}) {
      const {lng, lat} = this.position
      const pixel = map.pointToOverlayPixel(new BMap.Point(lng, lat))
      el.style.left = pixel.x - 42 + 'px'
      el.style.top = pixel.y - 42 + 'px'
    }
  }
}
</script>

<style lang="stylus" scoped>
  .zone
    transition: background-color .15s ease-in-out
    display: flex
    align-items: center
    width: 84px
    height: 84px
    background-color: rgba(58,126,255,0.9)
    overflow: hidden
    text-overflow: ellipsis
    white-space: nowrap
    color: #fff
    font-size: 12px
    text-align: center
    padding: 10px
    position: absolute
    border-radius: 50%
    box-shadow: 0 0 4px # 999Box-sizing: border-box &:hover z-index: 1 background-color: rgba(240,655,52,.9) color: RGB (255, 255, 255)#fff
    div
      display: flex
      flex-wrap: wrap
      overflow: hidden
      text-overflow: ellipsis
      white-space: nowrap
      justify-content: space-between
      p
        overflow: hidden
        text-overflow: ellipsis
        white-space: nowrap
        width: 100%
        text-align: center
        line-height: 16px
</style>
Copy the code

el.style.left = pixel.x – 42 + ‘px’

el.style.top = pixel.y – 42 + ‘px’

This is done so that the bubble cover is centered at its coordinate point, since the CSS is 84px wide and high, it looks like this:

Interaction of regional bubbles

After the zone overlay is displayed, now let’s add some interaction for them. This is when the mouse slides in an area bubble, the bubble is highlighted, and when it slides out, the bubble is restored. At first I used mouseover and Mouseleave events. But I found that the change of bubble background color did not slow down the effect,

<zone-overlay
  v-for="(item, index) in zoneGeoPoints" :key="index"
  :position="{lng: item.lng, lat: item.lat}"
  :text="item"
  :class="zoneIndex === index ? 'active':''"
  @mouseover.native="selectZone(item, index)"
  @mouseleave.native="cancelZone">
</zone-overlay>
<script>
export default {
    data () {
        return {
            zoneIndex: ' '
        }
    },
    methods: {
        selectZone (item, index) {
            this.zoneIndex = index
        },
        cancelZone () {
            this.zoneIndex = ' '
        }
    }
}
</script>
Copy the code

The modifier native is used to make the component a normal HTML tag, otherwise the mouseover and mouseleave events will not be triggered.

// zoneOverlay.vue .zone transition: background-color 1s ease-in-out &:hover z-index: 1 background-color: Rgba (240,65,52, 9) color:#fff
Copy the code

The effect is as follows:

Let’s do some interaction

We hope that when the zoom level of the local map is greater than a certain value, regional bubbles disappear, and when it is smaller than this value, regional bubbles appear again, just like the link home. In this process, we need to obtain the current zoom level of the map in real time, zoom. Vue-bidu-map provides us with an API, syncCenterAndZoom, which can be used as follows:

<div class="map-wrapper">
    <baidu-map id="bm-view" class="bm-view" :center="center" :zoom="zoom" :scroll-wheel-zoom="true" @ready="handler" @zoomend="syncCenterAndZoom">
        <div v-if="showZone">
            <zone-overlay
              v-for="(item, index) in zoneGeoPoints" :key="index"
              :position="{lng: item.lng, lat: item.lat}"
              :text="item">
            </zone-overlay>
        </div>
    </baidu-map>
</div>
Copy the code
// ZOOMBOUNDARY is constant, // const ZOOMBOUNDARY = 15 syncCenterAndZoom (e) {this.zoom = e.target.getzoom () this.showzone = this.zoom < ZOOMBOUNDARY }Copy the code

The effect is as follows:

Display of area boundaries

The BM-boundary component is used for the regional boundary. When the mouse is drawn into a regional bubble, the boundary of the region appears, while when the mouse is slid out of a regional bubble, the boundary of the region disappears.

<bm-boundary v-if="showBoundary" :name="zoneBoundary" :strokeWeight="2" strokeColor="blue" fillColor="skyblue" :fillOpacity="0.4"></bm-boundary>
Copy the code

Parameter Description:

Name Indicates the name of a region (administrative district), such as Huangpu District of Shanghai and Chaoyang District of Beijing

StrokeWeight represents the border width of the region border

StrokeColor represents the border color of the region

FillColor Indicates the filling color of the area boundary

FillOpacity indicates the opacity of the fill color of the region boundary

<template>
    <div class="map-wrapper">
        <baidu-map id="bm-view" class="bm-view" :center="center" :zoom="zoom" :scroll-wheel-zoom="true" @ready="handler" @zoomend="syncCenterAndZoom">
            <bm-boundary v-if="showBoundary" :name="zoneBoundary" :strokeWeight="2" strokeColor="blue" fillColor="skyblue" :fillOpacity="0.4"></bm-boundary>
            <div v-if="showZone">
                <zone-overlay
                  v-for="(item, index) in zoneGeoPoints" :key="index"
                  :position="{lng: item.lng, lat: item.lat}"
                  :text="item"
                  @mouseover.native="selectZone(item, index)"
                  @mouseleave.native="cancelZone">
                </zone-overlay>
            </div>
        </baidu-map>
    </div>
</template>

<script>
export default {
    data () {
        return {
            showBoundary: false
        }
    },
    methods: {
        selectZone (item, index) {
          this.zoneBoundary = `${this.posCity}${item.name}'// Boundary name, for reference only this.showboundary =true
        },
        cancelZone () {
          this.zoneBoundary = ' '
          this.showBoundary = false
        }
    }
}
</script>
Copy the code

The effect is as follows:

Since the function of finding a room on the map is a bit complicated, I have divided it into several parts, so that it is more clear how to implement this function step by step. Please wait for the rest part

Finally, post a project experience address: Poke me experience ~ (PC only)

Please spray lightly if you don’t write well ~ thanks for reading