利用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" />

牛舍01

牛舍02

牛舍05

...

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");

}}

>