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