如何将数组数组映射到 react 组件中的 JSX 元素,每个内部数组都有自己的 clipPath



array_groups是数组的数组。内部数组中的对象是规则圆的坐标,它们都是近端的想法是,这些内部圆数组都应该被clipPath-ed在一起。这个想法是,当我将鼠标移动到近端圆圈的每个区域时,矩形只显示在该区域。

function Hoverpicture() {
const [image, setimage] = useState("");
const [mousepos, setmousepos] = useState({ x: 0, y: 0 });
const [radius, setradius] = useState(20)
const [label, setlabel] = useState("");
const [region, setregion] = useState([]); 
const [input, setinput] = useState("");
const [mode, setmode] = useState(1);
const [mousemove, setmousemove] = useState(()=>onmousemove);

function onlabelclick(e) {
setlabel("clicked label")
}
function onmouseclick(e) {
let newregion = region.concat({ x: e.nativeEvent.offsetX, y: e.nativeEvent.offsetY, r: radius, label: input});
setregion(newregion);
}
function checkregion(pos) {
for (let reg of region) {
let xs = pos.x - reg.x;
let ys = pos.y - reg.y;
xs*=xs;
ys*=ys;
console.log(reg);
if (reg.r-Math.sqrt( xs + ys ) > 0) {
return reg.label;
} 
}
return false;
}

function onmousemove(e) {
setmousepos({ x: e.nativeEvent.offsetX, y: e.nativeEvent.offsetY });
let displaylabel = checkregion({x: e.nativeEvent.offsetX, y: e.nativeEvent.offsetY});
if (displaylabel) {
setlabel(displaylabel);
} else {
setlabel("");
}
}
function handleinput(e) {
setinput(e.target.value);
}
function myreducer(accum,next) {
accum[next.label] = accum[next.label] || [];
accum[next.label].push(next);
return accum;
}

var grouped_region = region.reduce(function (accum,next) {
accum[next.label] = accum[next.label] || [];
accum[next.label].push(next);
return accum;
},{});

var array_groups = [];
for (let area in grouped_region) {
array_groups.push(grouped_region[area]);
}

if (mode===1)
{
return (
<div>
<div className="img-overlay-wrap">
<img src={image} alt="table with coffee"/>
<svg onMouseMove={onmousemove} viewBox="0 0 auto auto">
<circle cx={mousepos.x} cy={mousepos.y} r={radius} fill-opacity="0"/>

{array_groups.map((ar,i) =>(
<clipPath id="shape">
{ar.map(reg =>(<circle onClick={onlabelclick} cx={reg.x} cy={reg.y} r={reg.r} fill="orange"/>))}
</clipPath>
<rect x={0} y={0} width="100%" height="100%" clipPath="url(#shape)" class="label"  fill-opacity="0"/>
))}
</svg>
</div>
<div>
<h1>{ label }</h1>
<button onClick={()=>{setmode(1)}}>✏</button>
</div>
</div>

)}

CSS是这样的…

.img-overlay-wrap {
position: relative;
display: inline-block; /* <= shrinks container to image size */
transition: transform 150ms ease-in-out;
}
.img-overlay-wrap img { /* <= optional, for responsiveness */
display: block;
max-width: 100%;
height: auto;
}
.img-overlay-wrap svg {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
}
.label:hover {
fill-opacity:.5;
fill:red;
}

哦,是的,我看过。您只需要将所有相邻的标记(clipPathrect)包含在一个节点中以获得映射返回。ReactFragment在这方面会派上用场。

Fragment - keyyed Fragment

用显式<React.Fragment>语法声明的片段可能有钥匙。这样做的一个用例是将集合映射到数组碎片

{array_groups.map((ar, i) => (
<Fragment key={i}>
<clipPath id="shape">
{ar.map((reg) => (
<circle
onClick={onlabelclick}
cx={reg.x}
cy={reg.y}
r={reg.r}
fill="orange"
/>
))}
</clipPath>
<rect
x={0}
y={0}
width="100%"
height="100%"
clipPath="url(#shape)"
class="label"
fill-opacity="0"
/>
</Fragment>
))}

我不能保存我对codependency所做的编辑,但是我可以复制组件的内容。

function Hoverpicture() {
const [image, setimage] = useState("");
const [mousepos, setmousepos] = useState({ x: 0, y: 0 });
const [radius, setradius] = useState(20);
const [label, setlabel] = useState("");
const [region, setregion] = useState([]);
const [input, setinput] = useState("");
const [mode, setmode] = useState(1);
function getimage() {
storage
.child("peterRabbit.png")
.getDownloadURL()
.then((url) => {
let image = url;
setimage(image);
})
.catch((error) => {
// Handle any errors
});
}
function getlabels() {
let doc = ref.doc("01xfB3duoKI2Uoq4gtYZ");
doc.get().then((d) => {
console.log(d.data());
});
}
getlabels();
getimage();
function onlabelclick(e) {
setlabel("clicked label");
}
function onmouseclick(e) {
let newregion = region.concat({
x: e.nativeEvent.offsetX,
y: e.nativeEvent.offsetY,
r: radius,
label: input
});
setregion(newregion);
}
function getcoords() {}
function checkregion(pos) {
for (let reg of region) {
let xs = pos.x - reg.x;
let ys = pos.y - reg.y;
xs *= xs;
ys *= ys;
console.log(reg);
if (reg.r - Math.sqrt(xs + ys) > 0) {
return reg.label;
}
}
return false;
}
function onmousemove(e) {
setmousepos({ x: e.nativeEvent.offsetX, y: e.nativeEvent.offsetY });
let displaylabel = checkregion({
x: e.nativeEvent.offsetX,
y: e.nativeEvent.offsetY
});
if (displaylabel) {
setlabel(displaylabel);
} else {
setlabel("");
}
}
function handleinput(e) {
setinput(e.target.value);
}
function myreducer(accum, next) {
accum[next.label] = accum[next.label] || [];
accum[next.label].push(next);
return accum;
}
const [mousemove, setmousemove] = useState(() => onmousemove);
var grouped_region = region.reduce(function (accum, next) {
accum[next.label] = accum[next.label] || [];
accum[next.label].push(next);
return accum;
}, {});
console.log(grouped_region);
var array_groups = [];
for (let area in grouped_region) {
array_groups.push(grouped_region[area]);
}

if (mode === 0) {
return (
<div>
<div className="img-overlay-wrap">
<img src={image} alt="table with coffee" />
<svg onMouseMove={onmousemove} viewBox="0 0 auto auto">
<circle
cx={mousepos.x}
cy={mousepos.y}
r={radius}
fill-opacity="0"
/>
{array_groups.map((ar, i) => (
<>
<clipPath id="shape">
{ar.map((reg) => (
<circle
onClick={onlabelclick}
cx={reg.x}
cy={reg.y}
r={reg.r}
fill="orange"
/>
))}
</clipPath>
<rect
x={0}
y={0}
width="100%"
height="100%"
clipPath="url(#shape)"
class="label"
fill-opacity="0"
/>
</>
))}
</svg>
</div>
<div>
<h1>{label}</h1>
<button
onClick={() => {
setmode(1);
}}
>
✏
</button>
</div>
</div>
);
} else if (mode === 1) {
return (
<div>
<div className="img-overlay-wrap">
<img src={image} alt="table with coffee" />
<svg
onMouseMove={onmousemove}
onClick={onmouseclick}
viewBox="0 0 auto auto"
>
<circle
cx={mousepos.x}
cy={mousepos.y}
r={radius}
fill="rebeccapurple"
/>
{region.map((reg) => (
<circle
onClick={onlabelclick}
class="label"
cx={reg.x}
cy={reg.y}
r={reg.r}
fill="orange"
/>
))}
</svg>
</div>
<div>
<h1>
{mousepos.x} {mousepos.y}
</h1>
<h1>{label}</h1>
<input
placeholder="label"
value={input}
onChange={handleinput}
></input>
<button
onClick={() => {
setmode(0);
}}
>
✅
</button>
</div>
</div>
);
}
}

最新更新