diff --git a/app/components/p8p_svg.js b/app/components/p8p_svg.js index 822ce73..fb426b6 100644 --- a/app/components/p8p_svg.js +++ b/app/components/p8p_svg.js @@ -8,7 +8,7 @@ //--------------------- import React, { useEffect, useRef, useState } from "react"; //Классы React -import { IconButton, Icon } from "@mui/material"; //Интерфейсные элементы +import { IconButton, Icon, Container, Grid } from "@mui/material"; //Интерфейсные элементы import PropTypes from "prop-types"; //Контроль свойств компонента //--------- @@ -17,13 +17,13 @@ import PropTypes from "prop-types"; //Контроль свойств компо //Стили const STYLES = { - CANVAS: { width: "100%", height: "100%" }, + GRID_ITEM_CANVAS: { width: "100%", height: "100%" }, CONTROLS: { justifyContent: "center", alignItems: "center", display: "flex" } }; //Структура элемента изображения const P8P_SVG_ITEM_SHAPE = PropTypes.shape({ - id: PropTypes.string.isRequired, + id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, backgroundColor: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]) }); @@ -32,7 +32,7 @@ const P8P_SVG_ITEM_SHAPE = PropTypes.shape({ //----------- //Интерактивные изображения SVG -const P8PSVG = ({ data, items, onClick, onItemClick, canvasStyle }) => { +const P8PSVG = ({ data, items, onClick, onItemClick, canvasStyle, fillOpacity }) => { //Собственное состояние const [state, setState] = useState({ images: [], @@ -47,8 +47,8 @@ const P8PSVG = ({ data, items, onClick, onItemClick, canvasStyle }) => { //Обработка нажатия на элемент изображения const handleClick = e => { let itemClickFired = false; - if (e.target.id && items && onItemClick) { - const item = items.find(item => item.id == e.target.id); + if (items && onItemClick) { + const item = items.find(item => item.id == e.target?.id || item.id == e.target?.parentElement?.id); if (item) { onItemClick({ item }); itemClickFired = true; @@ -62,11 +62,36 @@ const P8PSVG = ({ data, items, onClick, onItemClick, canvasStyle }) => { items.forEach(item => { const svgE = document.getElementById(item.id); if (svgE) { - svgE.setAttribute("style", `${onItemClick ? "cursor: pointer" : ""}; ${item.backgroundColor ? `fill: ${item.backgroundColor}` : ""}`); + //Запомним старый стиль элемента + let styleOld = svgE.getAttribute("style") || ""; + if (styleOld && !styleOld.endsWith(";")) styleOld = `${styleOld};`; + //Сформируем стиль для заливки + let fillStyle = ""; + if (item.backgroundColor) fillStyle = `fill: ${item.backgroundColor}; ${fillOpacity ? `opacity: ${fillOpacity};` : ""}`; + //Сформируем стиль для курсора + let cursorStyle = ""; + if (onItemClick) cursorStyle = "cursor: pointer;"; + //Добавим элемент для всплывающей подсказки + let titleE = null; if (item?.title) { - const titleE = document.createElementNS("http://www.w3.org/2000/svg", "title"); + titleE = document.createElementNS("http://www.w3.org/2000/svg", "title"); titleE.textContent = item.title; - svgE.replaceChildren(titleE); + svgE.appendChild(titleE); + } + //Если нем попалась группа + if (svgE.tagName == "g") { + //Установим ей новые стили + svgE.setAttribute("style", `${styleOld}${cursorStyle}`); + //И заливку всем дочерним элементам + if (fillStyle) + for (const child of svgE.children) { + let childStyleOld = child.getAttribute("style") || ""; + if (childStyleOld && !childStyleOld.endsWith(";")) childStyleOld = `${childStyleOld};`; + child.setAttribute("style", `${childStyleOld}${fillStyle}`); + } + } else { + //Это простой элемент, не группа - просто выставляем стили + svgE.setAttribute("style", `${styleOld}${cursorStyle}${fillStyle}`); } } }); @@ -121,26 +146,32 @@ const P8PSVG = ({ data, items, onClick, onItemClick, canvasStyle }) => { }, [state.images, state.currentImage, items]); //При прокрутке изображений назад - const handlePrevClick = () => switchImage(-1); + const handlePrevClick = () => switchImage(1); //При прокрутке изображений вперёд - const handleNextClick = () => switchImage(1); + const handleNextClick = () => switchImage(-1); //Генерация содержимого return ( -
-
- {state.imagesCount > 1 ? ( -
- - arrow_left - - - arrow_right - -
- ) : null} -
+ + + +
+
+ {state.imagesCount > 1 ? ( + +
+ + arrow_left + + + arrow_right + +
+
+ ) : null} +
+
); }; @@ -150,7 +181,8 @@ P8PSVG.propTypes = { items: PropTypes.arrayOf(P8P_SVG_ITEM_SHAPE), onClick: PropTypes.func, onItemClick: PropTypes.func, - canvasStyle: PropTypes.object + canvasStyle: PropTypes.object, + fillOpacity: PropTypes.string }; //---------------- diff --git a/app/panels/samples/svg.js b/app/panels/samples/svg.js index 85455ba..efee4b5 100644 --- a/app/panels/samples/svg.js +++ b/app/panels/samples/svg.js @@ -24,7 +24,7 @@ const STYLES = { CONTAINER: { textAlign: "center", paddingTop: "20px" }, TITLE: { paddingBottom: "15px" }, FORM: { justifyContent: "center", alignItems: "center" }, - SVG: { width: "95vw", height: "30vw", display: "flex", justifyContent: "center" } + SVG: { height: "30vw", display: "flex", justifyContent: "center" } }; //-----------