利用svg显示不规则图形,实现用户点击交互:
需求评审时产品掏出了甲方的区域图,要求实现点击后出来对应弹窗信息,但是由于是不规则图片,交由前端实现,现将实现方式记录下来
例如:项目场景:有下方有三块区域是办公区域,需要鼠标点击后出来对应区域信息。
实现步骤
1、ui将区域图设计稿导出为svg格式,并导入到项目中
###注意###:将文件导入到项目中,由于是在react上开发,所以xmlns:xlink,xmlns:href等带有冒号的代码要改为xmlnsXlink格式,将styles文件单独拎出去,放在css中,在所引入的文件将css引入。image标签引入的图片为base64导致代码太大,可以随便找个在线网站将base64转换为png引入,例如:
分析svg,实现交互:
缺点:本来是想当移入svg后,区域背景改变,点击进行交互,但是rect标签和text标签分别是独立的,移入text标签后,下方的rect标签的hover就失效了,只能退而求次,当hover的是text的时候颜色改变,点击事件也绑定在text上了
这里分析一下ui给出的svg规律,rect是每个小区域,相当于我们的div,紧接着的text是附在上面的文字,每个g标签下的最后一个rect,id为line的标签是包含整个小区域的盒子。
所以,知道了这些,我们可以将svg绑定ref,通过querySelectorAll所以g标签下的所有text,并绑定上点击事件。
className="delivery-cls-1" x="156" y="33" width="108" height="32" rx="2" ry="2" /> ... if (svgRef.current) { const gElements = svgRef.current.querySelectorAll('g'); // 获取所有 gElements.forEach((gElement) => { const textElements = gElement.querySelectorAll('text'); // 获取每个 textElements.forEach((textElement, index, array) => { textElement.addEventListener('click', (event) => { handleTextClick(event, data) }); }); }); } 附:点击后的popper组件实现 import React, { useState } from 'react' import './index.scss'; export default function index({ width, height, top, left, show, children }) { return ( visibility: show, width: width || '180px', height: height || '190px', top: top || '50%', left: left || '50%' }} >{children}
)
}
-------------------使用----------------------
useEffect(() => {
document.addEventListener('click', handleGlobalClick);
return () => {
document.removeEventListener('click', handleGlobalClick);
};
}, []);
// 全局监听点击,如果点击了别的区域关闭popper
const handleGlobalClick = (event) => {
let config = { ...popConfig, show: 'hidden' }
setPopConfig(config)
};
//打开传入 clientX, clientY位置
const { clientX, clientY } = event;
setPopConfig({
show: 'visible',
top: `${clientY}px`,
left: `${clientX}px`,
})
暂无数据!
附2 拖拽缩放
如果希望元素可以实现拖拽缩放可以引入panzoom.js
import React, { useRef, useEffect } from "react";
import panzoom from "panzoom";
export default function index() {
const svgContainerRef = useRef(null);
const scene = useRef(null);
let panzoomInstance;
useEffect(() => {
const svgContainer = svgContainerRef.current;
// 创建 panzoom 实例并将其附加到 SVG 容器上
panzoomInstance = panzoom(svgContainer, {
smoothScroll: false, // 禁用平滑滚动以增加拖拽的响应性
zoomDoubleClickSpeed: 1, // 设置双击缩放速度
});
// 清理 panzoom 实例
return () => {
if (panzoomInstance) {
panzoomInstance.dispose();
panzoomInstance = null;
}
};
}, []);
return (
ref={svgContainerRef}
style={{
width: "400px",
height: "400px",
border: "1px solid black",
overflow: "hidden",
zIndex: 120,
cursor: "pointer",
}}
onClick={() => {
console.log(11, "11");
}}
>
);
}
相关阅读
发表评论