本文完整demo在下面。
大屏
在做大屏的时候,为了保证大屏完整的呈现在窗口中,一种简单的做法是大屏尺寸根据窗口尺寸做缩放调整,就像这样:
想实现上面这种效果,非常容易,监听window的resize事件,当window的resize事件触发时,根据此时window的尺寸与大屏的设计尺寸计算出一个缩放值,将大屏按照此缩放值进行transform:scale缩放。下面我用react简单做一个:
App.jsx
// App.jsx
import Screen from './components/Screen'
export default function(){
return <Screen desginWidth={1920} desginHeight={1080}>
<div>大屏区域</div>
</Screen>
}
Screen.jsx
// Screen.jsx
import { useState, useEffect } from "react"
// 大屏容器样式
const style = {
position: "absolute",
left: "50%",
top: "50%",
backgroundColor: 'red'
}
// 生成一个防抖函数
function debounce(callback, time){
let timer = null
return function(...arg){
if(timer) clearTimeout(timer)
timer = setTimeout(() => {
callback(...arg)
}, time)
}
}
// 计算缩放值
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)
// 组件首次加载时执行的逻辑
useEffect(() => {
// 当窗口触发resize事件时的回调函数
const resizeHandler = debounce(() => {
setScale(calculate(props.desginWidth, props.desginHeight))
}, 300)
// 注册窗口的resize事件
window.addEventListener('resize', resizeHandler)
resizeHandler()
// 当组件卸载时移除之前窗口注册的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>
}
地图
大屏组件有了,接下来利用高德地图api封装一个地图组件:
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
// 创建一个地图
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>
}
到目前,效果是这样的:
接下来实现鼠标点击地图某点就在该点树立一个标记点的功能。监听地图点击事件,事件参数中会有鼠标点击点的经纬度,高德地图api提供了点标记功能,能根据经纬度在地图上树立标记点。
试试效果:
期望的效果是在鼠标点击处产生标记点,但是实际上标记点的位置离鼠标点击位置有很大的偏差。
产生问题的原因
下图这个是大屏缩放正好是1的情况【transform:scale(1) 】,这个五角星的像素坐标是(784,321)。
如果将窗口缩小,大屏也会跟着缩小:
比如上图这样,此时的大屏缩放变成0.8286792452830188的情况【transform: scale(0.8286792452830188)】,五角星的像素坐标是(652,266)。你会发现像素坐标除以缩放值得到的是大屏缩放为1的情况【transform:scale(1)】的像素坐标,比如652除以0.8286792452830188得到的786,266除以0.8286792452830188得到320(计算结果有轻微偏差,因为有小数除不尽,以及我测量的也不是很准确导致)。
鼠标点击点的经纬度应该来自大屏缩放为1的情况【transform: scale(1)】的像素坐标。所以你需要将得到的像素坐标除以缩放值后再转换成经纬度,再根据该经纬度立标记点,具体实施步骤见下面的实施解决方案。
实施解决方案
通过点击地图事件的事件参数除了能拿到点击地图点的经纬度外,还可以拿到点击地图点的像素坐标,将像素坐标除以大屏目前的缩放值会得到一个新的坐标,将这个新的坐标转换成对应的经纬度(通过地图实例身上的containerToLngLat函数)作为标记点的经纬度。
试试效果:
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'
}
// 生成一个防抖函数
function debounce(callback, time){
let timer = null
return function(...arg){
if(timer) clearTimeout(timer)
timer = setTimeout(() => {
callback(...arg)
}, time)
}
}
// 计算缩放值
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)
// 组件首次加载时执行的逻辑
useEffect(() => {
// 当窗口触发resize事件时的回调函数
const resizeHandler = debounce(() => {
setScale(calculate(props.desginWidth, props.desginHeight))
}, 300)
// 注册窗口的resize事件
window.addEventListener('resize', resizeHandler)
resizeHandler()
// 当组件卸载时移除之前窗口注册的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:文章来源:https://www.toymoban.com/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
// 创建一个地图
map.current = new AMap.Map('container', {
center: [105.602725,37.076636],
})
//监听点击地图事件
map.current.on('click', function(e) {
// 鼠标点击地图点的像素坐标
const {x, y} = e.pixel
// 像素坐标除以大屏缩放值得到一个新的坐标
const pixel2 = new AMap.Pixel(x / scale, y / scale)
// 新的坐标转换成对应的经纬度
const {lng, lat} = map.current.containerToLngLat(pixel2)
// 创建点标记
const marker = new AMap.Marker({
position: new AMap.LngLat(lng,lat),
title: "一个标记点"
})
// 将点标记添加到地图上
map.current.add(marker)
})
})
return <div id='container' style={style}></div>
}
App.jsx:文章来源地址https://www.toymoban.com/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>
}
到了这里,关于解决高德地图因被transform缩放导致获取鼠标点击地图某点的经纬度不准问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!