Heim  >  Fragen und Antworten  >  Hauptteil

React + d3 – Warum reagiert mein <g>-Element nicht auf den onClick-Listener?

Ich bin relativ neu in d3 und weiß, dass es einige Konflikte zwischen React und d3 geben kann. Dies könnte einer von ihnen sein.

Ich habe ein SVG, das das skalierbare Verhalten von d3 implementiert. Ich möchte die Elemente im SVG ziehbar machen. Mein erster Versuch bestand darin, einen onClick-Listener einzufügen, um etwas in der Konsole zu protokollieren, aber es hat nicht funktioniert. Können Sie erklären, was mir hier fehlt? Ich vermute, dass das D3-Skalierungsverhalten das Klickereignis kapert. Danke. Hier ist der Code:

Raster mit Zoomfunktion.

import React, { useState, useEffect, useRef } from 'react'
import * as d3 from 'd3';
import Rect from './Rect';
import './d3-grid.css';

const zoomBehaviour = (width, height, gridSize, gridRef) => d3
    .zoom()
    .scaleExtent([0.5, 2])
    .translateExtent([[0, 0], [width, height]])
    .on('zoom', (event) => {
        const svg = d3.select(gridRef.current)

        svg.select('#grid-pattern')
            .attr('x', event.transform.x)
            .attr('y', event.transform.y)
            .attr('width', gridSize * event.transform.k)
            .attr('height', gridSize * event.transform.k)
            .selectAll('line')
            .attr('opacity', Math.min(event.transform.k, 1));
        d3.selectAll('g').attr('transform', event.transform);
    })


const D3Grid = ({ data, width, height }) => {
    const [shapes, setShapes] = useState(data);
    const svgGridRef = useRef();
    const content = useRef();

    const gridSize = 25;
    const gridColor = '#a4a4a4';

    useEffect(() => {
        const svg = d3.select(svgGridRef.current);
        var pattern = svg.append('pattern')
            .attr('id', 'grid-pattern')
            .attr('patternUnits', 'userSpaceOnUse')
            .attr('x', 0)
            .attr('y', 0)
            .attr('width', gridSize)
            .attr('height', gridSize);

        pattern.append('line')
            .attr('stroke', gridColor)
            .attr('x1', 0)
            .attr('y1', 0)
            .attr('x2', gridSize * 16)
            .attr('y2', 0);

        pattern.append('line')
            .attr('stroke', gridColor)
            .attr('x1', 0)
            .attr('y1', 0)
            .attr('x2', 0)
            .attr('y2', gridSize * 16);

        svg.append('rect')
            .attr('fill', 'url(#grid-pattern)')
            .attr('width', '100%')
            .attr('height', '100%');

        return () => {
            // Clean up any D3 elements or listeners
        };
    }, [])

    useEffect(() => {
        const svg = d3.select(svgGridRef.current);
        svg.call(zoomBehaviour(width, height, gridSize, svgGridRef));

        return () => {
            svg.on('.zoom', null);
        };
    }, []);

    return (
        <svg
            className='main-svg'
            ref={svgGridRef}
            viewBox={`0 0 ${width} ${height}`}
        >
            {
                shapes.map((shape, index) => (
                    <Rect 
                    key={index} 
                    id={shape.id} 
                    fill={shape.fill} 
                    rx={shape.rx} 
                    width={shape.width} 
                    height={shape.height} 
                    x={shape.posX} 
                    y={shape.posY} 
                />
                ))
            }
        </svg >
    )
}

export default D3Grid

Rechteckiges Bauteil. Ich habe g-Elemente und rect-Elemente ausprobiert. keine Arbeit.

const Rect = (props) => {
    return (
        <g onClick={(event) => { console.log({ event }); }}>
            <rect {...props} onClick={(event) => { console.log({ event }); }} />
        </g>

    )
}

export default Rect

P粉504080992P粉504080992286 Tage vor472

Antworte allen(1)Ich werde antworten

  • P粉773659687

    P粉7736596872024-01-30 00:06:32

    在您的代码中,useEffect 钩子将在 Rect 组件渲染后被触发,这意味着 useEffect 中的图案和相关背景矩形将渲染在 Rect 组件的顶部。然后,它们阻止事件传播到下面的矩形组件。

    要解决这个问题,有两种选择。第一个是将模式的“pointer-events”属性和相关的东西设置为“none”,第二个是将这些东西放在底部。这是现场演示。 Int 屏幕截图 演示链接

    const D3Grid = () => {
      useEffect(() => {
        const background = svg.select(".background")
        background.append("pattern");
        background.append("rect");
      });
      return (
        
        {...rects}
      );
    }

    Antwort
    0
  • StornierenAntwort