WEB APP: P8PSVG - поддержка групп, прозрачности заливки, верстка на Gridе
This commit is contained in:
parent
c61b8cc9c2
commit
46d078219f
@ -8,7 +8,7 @@
|
|||||||
//---------------------
|
//---------------------
|
||||||
|
|
||||||
import React, { useEffect, useRef, useState } from "react"; //Классы React
|
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"; //Контроль свойств компонента
|
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||||||
|
|
||||||
//---------
|
//---------
|
||||||
@ -17,13 +17,13 @@ import PropTypes from "prop-types"; //Контроль свойств компо
|
|||||||
|
|
||||||
//Стили
|
//Стили
|
||||||
const STYLES = {
|
const STYLES = {
|
||||||
CANVAS: { width: "100%", height: "100%" },
|
GRID_ITEM_CANVAS: { width: "100%", height: "100%" },
|
||||||
CONTROLS: { justifyContent: "center", alignItems: "center", display: "flex" }
|
CONTROLS: { justifyContent: "center", alignItems: "center", display: "flex" }
|
||||||
};
|
};
|
||||||
|
|
||||||
//Структура элемента изображения
|
//Структура элемента изображения
|
||||||
const P8P_SVG_ITEM_SHAPE = PropTypes.shape({
|
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)])
|
backgroundColor: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)])
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ const P8P_SVG_ITEM_SHAPE = PropTypes.shape({
|
|||||||
//-----------
|
//-----------
|
||||||
|
|
||||||
//Интерактивные изображения SVG
|
//Интерактивные изображения SVG
|
||||||
const P8PSVG = ({ data, items, onClick, onItemClick, canvasStyle }) => {
|
const P8PSVG = ({ data, items, onClick, onItemClick, canvasStyle, fillOpacity }) => {
|
||||||
//Собственное состояние
|
//Собственное состояние
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
images: [],
|
images: [],
|
||||||
@ -47,8 +47,8 @@ const P8PSVG = ({ data, items, onClick, onItemClick, canvasStyle }) => {
|
|||||||
//Обработка нажатия на элемент изображения
|
//Обработка нажатия на элемент изображения
|
||||||
const handleClick = e => {
|
const handleClick = e => {
|
||||||
let itemClickFired = false;
|
let itemClickFired = false;
|
||||||
if (e.target.id && items && onItemClick) {
|
if (items && onItemClick) {
|
||||||
const item = items.find(item => item.id == e.target.id);
|
const item = items.find(item => item.id == e.target?.id || item.id == e.target?.parentElement?.id);
|
||||||
if (item) {
|
if (item) {
|
||||||
onItemClick({ item });
|
onItemClick({ item });
|
||||||
itemClickFired = true;
|
itemClickFired = true;
|
||||||
@ -62,11 +62,36 @@ const P8PSVG = ({ data, items, onClick, onItemClick, canvasStyle }) => {
|
|||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
const svgE = document.getElementById(item.id);
|
const svgE = document.getElementById(item.id);
|
||||||
if (svgE) {
|
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) {
|
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;
|
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,16 +146,20 @@ const P8PSVG = ({ data, items, onClick, onItemClick, canvasStyle }) => {
|
|||||||
}, [state.images, state.currentImage, items]);
|
}, [state.images, state.currentImage, items]);
|
||||||
|
|
||||||
//При прокрутке изображений назад
|
//При прокрутке изображений назад
|
||||||
const handlePrevClick = () => switchImage(-1);
|
const handlePrevClick = () => switchImage(1);
|
||||||
|
|
||||||
//При прокрутке изображений вперёд
|
//При прокрутке изображений вперёд
|
||||||
const handleNextClick = () => switchImage(1);
|
const handleNextClick = () => switchImage(-1);
|
||||||
|
|
||||||
//Генерация содержимого
|
//Генерация содержимого
|
||||||
return (
|
return (
|
||||||
<div>
|
<Container>
|
||||||
<div ref={svgContainerRef} style={{ ...STYLES.CANVAS, ...(canvasStyle ? canvasStyle : {}) }}></div>
|
<Grid container direction="column" justifyContent="center" alignItems="center" spacing={0}>
|
||||||
|
<Grid item xs={12} sx={STYLES.GRID_ITEM_CANVAS}>
|
||||||
|
<div ref={svgContainerRef} style={{ ...(canvasStyle ? canvasStyle : {}) }}></div>
|
||||||
|
</Grid>
|
||||||
{state.imagesCount > 1 ? (
|
{state.imagesCount > 1 ? (
|
||||||
|
<Grid item xs={12}>
|
||||||
<div style={STYLES.CONTROLS}>
|
<div style={STYLES.CONTROLS}>
|
||||||
<IconButton onClick={handlePrevClick}>
|
<IconButton onClick={handlePrevClick}>
|
||||||
<Icon>arrow_left</Icon>
|
<Icon>arrow_left</Icon>
|
||||||
@ -139,8 +168,10 @@ const P8PSVG = ({ data, items, onClick, onItemClick, canvasStyle }) => {
|
|||||||
<Icon>arrow_right</Icon>
|
<Icon>arrow_right</Icon>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
|
</Grid>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</Grid>
|
||||||
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -150,7 +181,8 @@ P8PSVG.propTypes = {
|
|||||||
items: PropTypes.arrayOf(P8P_SVG_ITEM_SHAPE),
|
items: PropTypes.arrayOf(P8P_SVG_ITEM_SHAPE),
|
||||||
onClick: PropTypes.func,
|
onClick: PropTypes.func,
|
||||||
onItemClick: PropTypes.func,
|
onItemClick: PropTypes.func,
|
||||||
canvasStyle: PropTypes.object
|
canvasStyle: PropTypes.object,
|
||||||
|
fillOpacity: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------
|
//----------------
|
||||||
|
@ -24,7 +24,7 @@ const STYLES = {
|
|||||||
CONTAINER: { textAlign: "center", paddingTop: "20px" },
|
CONTAINER: { textAlign: "center", paddingTop: "20px" },
|
||||||
TITLE: { paddingBottom: "15px" },
|
TITLE: { paddingBottom: "15px" },
|
||||||
FORM: { justifyContent: "center", alignItems: "center" },
|
FORM: { justifyContent: "center", alignItems: "center" },
|
||||||
SVG: { width: "95vw", height: "30vw", display: "flex", justifyContent: "center" }
|
SVG: { height: "30vw", display: "flex", justifyContent: "center" }
|
||||||
};
|
};
|
||||||
|
|
||||||
//-----------
|
//-----------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user