本文完整demo在下面。
大屏
在做大屏的時(shí)候,為了保證大屏完整的呈現(xiàn)在窗口中,一種簡(jiǎn)單的做法是大屏尺寸根據(jù)窗口尺寸做縮放調(diào)整,就像這樣:
想實(shí)現(xiàn)上面這種效果,非常容易,監(jiān)聽(tīng)window的resize事件,當(dāng)window的resize事件觸發(fā)時(shí),根據(jù)此時(shí)window的尺寸與大屏的設(shè)計(jì)尺寸計(jì)算出一個(gè)縮放值,將大屏按照此縮放值進(jìn)行transform:scale縮放。下面我用react簡(jiǎn)單做一個(gè):
App.jsx
// App.jsx
import Screen from './components/Screen'
export default function(){
return <Screen desginWidth={1920} desginHeight={1080}>
<div>大屏區(qū)域</div>
</Screen>
}
Screen.jsx
// Screen.jsx
import { useState, useEffect } from "react"
// 大屏容器樣式
const style = {
position: "absolute",
left: "50%",
top: "50%",
backgroundColor: 'red'
}
// 生成一個(gè)防抖函數(shù)
function debounce(callback, time){
let timer = null
return function(...arg){
if(timer) clearTimeout(timer)
timer = setTimeout(() => {
callback(...arg)
}, time)
}
}
// 計(jì)算縮放值
function calculate(desginWidth, desginHeight){
const { innerWidth, innerHeight } = window
if(innerWidth / innerHeight < desginWidth / desginHeight) {
return innerWidth / desginWidth
}
return innerHeight / desginHeight
}
// props: { designWidth:number, desginHeight:number }
export default (props) => {
// 縮放值
const [scale, setScale] = useState(1)
// 組件首次加載時(shí)執(zhí)行的邏輯
useEffect(() => {
// 當(dāng)窗口觸發(fā)resize事件時(shí)的回調(diào)函數(shù)
const resizeHandler = debounce(() => {
setScale(calculate(props.desginWidth, props.desginHeight))
}, 300)
// 注冊(cè)窗口的resize事件
window.addEventListener('resize', resizeHandler)
resizeHandler()
// 當(dāng)組件卸載時(shí)移除之前窗口注冊(cè)的resize事件
return () => { window.removeEventListener('resize', resizeHandler) }
}, [])
return <div
style={{
...style,
width: `${props.desginWidth}px`,
height: `${props.desginHeight}px`,
transform:`translate(-50%, -50%) scale(${scale})`
}}
>
{props.children}
</div>
}
地圖
大屏組件有了,接下來(lái)利用高德地圖api封裝一個(gè)地圖組件:
Map.jsx
// Map.jsx
import AMapLoader from '@amap/amap-jsapi-loader'
import { useRef } from 'react'
const style = {
width: "100%",
height: "100%"
}
export default () => {
const map = useRef(null)
AMapLoader.load({
key: "2a49071d959081b738749e17f8207278",
}).then(() => {
const {AMap} = window
// 創(chuàng)建一個(gè)地圖
map.current = new AMap.Map('container', {
center: [105.602725,37.076636],
})
})
return <div id='container' style={style}></div>
}
將地圖組件安置到大屏里:
App.jsx
// App.jsx
import Screen from './components/Screen'
import Map from './components/Map'
export default function(){
return <Screen desginWidth={1920} desginHeight={1080}>
<Map />
</Screen>
}
到目前,效果是這樣的:
接下來(lái)實(shí)現(xiàn)鼠標(biāo)點(diǎn)擊地圖某點(diǎn)就在該點(diǎn)樹(shù)立一個(gè)標(biāo)記點(diǎn)的功能。監(jiān)聽(tīng)地圖點(diǎn)擊事件,事件參數(shù)中會(huì)有鼠標(biāo)點(diǎn)擊點(diǎn)的經(jīng)緯度,高德地圖api提供了點(diǎn)標(biāo)記功能,能根據(jù)經(jīng)緯度在地圖上樹(shù)立標(biāo)記點(diǎn)。
試試效果:
期望的效果是在鼠標(biāo)點(diǎn)擊處產(chǎn)生標(biāo)記點(diǎn),但是實(shí)際上標(biāo)記點(diǎn)的位置離鼠標(biāo)點(diǎn)擊位置有很大的偏差。
產(chǎn)生問(wèn)題的原因
下圖這個(gè)是大屏縮放正好是1的情況【transform:scale(1) 】,這個(gè)五角星的像素坐標(biāo)是(784,321)。
如果將窗口縮小,大屏也會(huì)跟著縮?。?br>比如上圖這樣,此時(shí)的大屏縮放變成0.8286792452830188的情況【transform: scale(0.8286792452830188)】,五角星的像素坐標(biāo)是(652,266)。你會(huì)發(fā)現(xiàn)像素坐標(biāo)除以縮放值得到的是大屏縮放為1的情況【transform:scale(1)】的像素坐標(biāo),比如652除以0.8286792452830188得到的786,266除以0.8286792452830188得到320(計(jì)算結(jié)果有輕微偏差,因?yàn)橛行?shù)除不盡,以及我測(cè)量的也不是很準(zhǔn)確導(dǎo)致)。
鼠標(biāo)點(diǎn)擊點(diǎn)的經(jīng)緯度應(yīng)該來(lái)自大屏縮放為1的情況【transform: scale(1)】的像素坐標(biāo)。所以你需要將得到的像素坐標(biāo)除以縮放值后再轉(zhuǎn)換成經(jīng)緯度,再根據(jù)該經(jīng)緯度立標(biāo)記點(diǎn),具體實(shí)施步驟見(jiàn)下面的實(shí)施解決方案。
實(shí)施解決方案
通過(guò)點(diǎn)擊地圖事件的事件參數(shù)除了能拿到點(diǎn)擊地圖點(diǎn)的經(jīng)緯度外,還可以拿到點(diǎn)擊地圖點(diǎn)的像素坐標(biāo),將像素坐標(biāo)除以大屏目前的縮放值會(huì)得到一個(gè)新的坐標(biāo),將這個(gè)新的坐標(biāo)轉(zhuǎn)換成對(duì)應(yīng)的經(jīng)緯度(通過(guò)地圖實(shí)例身上的containerToLngLat函數(shù))作為標(biāo)記點(diǎn)的經(jīng)緯度。
試試效果:
nice
完整demo
/ -
- App.jsx
- components
- Screen.jsx
- Map.jsx
- node_modules
- package.json
Screen.jsx:
import { useState, useEffect, createContext } from "react"
export const context = createContext({
scale: 1
})
// 大屏容器樣式
const style = {
position: "absolute",
left: "50%",
top: "50%",
backgroundColor: 'red'
}
// 生成一個(gè)防抖函數(shù)
function debounce(callback, time){
let timer = null
return function(...arg){
if(timer) clearTimeout(timer)
timer = setTimeout(() => {
callback(...arg)
}, time)
}
}
// 計(jì)算縮放值
function calculate(desginWidth, desginHeight){
const { innerWidth, innerHeight } = window
if(innerWidth / innerHeight < desginWidth / desginHeight) {
return innerWidth / desginWidth
}
return innerHeight / desginHeight
}
// props: { designWidth:number, desginHeight:number }
export default (props) => {
// 縮放值
const [scale, setScale] = useState(1)
// 組件首次加載時(shí)執(zhí)行的邏輯
useEffect(() => {
// 當(dāng)窗口觸發(fā)resize事件時(shí)的回調(diào)函數(shù)
const resizeHandler = debounce(() => {
setScale(calculate(props.desginWidth, props.desginHeight))
}, 300)
// 注冊(cè)窗口的resize事件
window.addEventListener('resize', resizeHandler)
resizeHandler()
// 當(dāng)組件卸載時(shí)移除之前窗口注冊(cè)的resize事件
return () => { window.removeEventListener('resize', resizeHandler) }
}, [])
return <div
style={{
...style,
width: `${props.desginWidth}px`,
height: `${props.desginHeight}px`,
transform:`translate(-50%, -50%) scale(${scale})`
}}
>
<context.Provider value={{ scale }}>
{props.children}
</context.Provider>
</div>
}
Map.jsx:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-491235.html
import AMapLoader from '@amap/amap-jsapi-loader'
import { useRef, useContext } from 'react'
import { context } from '../components/Screen'
const style = {
width: "100%",
height: "100%",
}
export default () => {
const map = useRef(null)
const {scale} = useContext(context)
AMapLoader.load({
key: "2a49071d959081b738749e17f8207278",
}).then(() => {
const {AMap} = window
// 創(chuàng)建一個(gè)地圖
map.current = new AMap.Map('container', {
center: [105.602725,37.076636],
})
//監(jiān)聽(tīng)點(diǎn)擊地圖事件
map.current.on('click', function(e) {
// 鼠標(biāo)點(diǎn)擊地圖點(diǎn)的像素坐標(biāo)
const {x, y} = e.pixel
// 像素坐標(biāo)除以大屏縮放值得到一個(gè)新的坐標(biāo)
const pixel2 = new AMap.Pixel(x / scale, y / scale)
// 新的坐標(biāo)轉(zhuǎn)換成對(duì)應(yīng)的經(jīng)緯度
const {lng, lat} = map.current.containerToLngLat(pixel2)
// 創(chuàng)建點(diǎn)標(biāo)記
const marker = new AMap.Marker({
position: new AMap.LngLat(lng,lat),
title: "一個(gè)標(biāo)記點(diǎn)"
})
// 將點(diǎn)標(biāo)記添加到地圖上
map.current.add(marker)
})
})
return <div id='container' style={style}></div>
}
App.jsx:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-491235.html
import Screen from './components/Screen'
import Map from './components/Map'
export default function(){
return <Screen desginWidth={1920} desginHeight={1080}>
<Map />
</Screen>
}
到了這里,關(guān)于解決高德地圖因被transform縮放導(dǎo)致獲取鼠標(biāo)點(diǎn)擊地圖某點(diǎn)的經(jīng)緯度不準(zhǔn)問(wèn)題的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!