Maison  >  Questions et réponses  >  le corps du texte

Placez des marqueurs interactifs sur les images à l'aide de React

S'il vous plaît, aidez-moi. J'ai une image comme celle ci-dessous qui s'affiche sur la page d'accueil (une image plus grande). A noter que la maison "FORGE" possède un marqueur blanc et bleu au milieu avec une flèche noire.

Il en va de même pour les logements « locatifs ».

Chacun de ces marqueurs agira comme un bouton interactif. Voici le comportement d'interaction attendu :

Je veux également qu'il soit réactif, si et quand l'écran est redimensionné, les boutons doivent rester dans ces positions spécifiques.

J'essaie d'utiliser le positionnement absolu, les coordonnées x, y pour essayer de le faire fonctionner. Mais comme j’apprécie l’expérience de ce type d’interface utilisateur, je ne trouve pas de solution efficace. Je ne sais pas si je dois utiliser de la toile ou autre chose.

Toute aide serait grandement appréciée.

Mon code ressemble à ceci, mais il semble que je ne suis pas sur la bonne voie :

const ImageComponent = () => {

  const markers = [
    { name: 'Forge', x: 100, y: 200 },
    { name: 'Rentals', x: 300, y: 150 },
    // Add more 
  ];

  const handleMarkerClick = (m) => {
    // do something with marker
  };

  return (
    <div style={{ position: 'relative' }}>
      <img src="path/to/image.jpg" alt="Image with markers" />

      {markers.map((marker, index) => (
        <div
          key={index}
          className="marker"
          style={{ left: marker.x, top: marker.y, position: "absolute" }}
          onClick={() => handleMarkerClick(marker)}
        />
      ))}
    </div>
  );
};

P粉896751037P粉896751037429 Il y a quelques jours805

répondre à tous(1)je répondrai

  • P粉412533525

    P粉4125335252023-09-09 17:37:18

    Vous devez placer le contrôle à la position absolue du conteneur d'image. La mise en œuvre dépend de divers facteurs, tels que l'endroit où l'image est placée, si elle est en plein écran, s'il y a du contenu avant ou après l'image, etc. Mais ce code devrait vous montrer le principe principal.

    Si l'image est redimensionnée lorsque la fenêtre est redimensionnée, vous devez créer un conteneur identique à l'image. Vous pouvez ensuite définir la position des contrôles par rapport à ce conteneur et les ancrer à leurs points respectifs.

    .container {
      width: 60vw; /* set 100vw to fit image window width*/
      position: relative;
    }
    .container img { width: 100%; display: block;}
    .container .control {
      position: absolute;
      width: 7.5%;  /* size in percents to resize controls with image */
      height: 7%;
      border-radius: 200px;
      background: red;
      transition: all 0.2s ease-in-out;
    }
    
    .container .control:hover {
      width: 20%;
    }
    
    #c1 { left: 50.4%; top: 26%; } /* position in percents, not in pixels */
    #c2 { left: 58.5%; top: 76.3%; }
    <div class="container">
      <img src="https://i.stack.imgur.com/BVaY9.jpg"/>
      <div class="control" id="c1"></div>
      <div class="control" id="c2"></div>
    </div>

    Utilisez votre code et il ressemblera à ceci (mais je vous recommande de déplacer vos styles dans le fichier de styles pour apprendre comment utiliser les styles de module dans React) :

    const ImageComponent = () => {
    
      const markers = [
        { name: 'Forge', x: 50.4, y: 26 },
        { name: 'Rentals', x: 58.5, y: 76.3 },
        // Add more 
      ];
    
      const handleMarkerClick = (m) => {
        // do something with marker
      };
    
      return (
        <div style={{ position: 'relative', width: '100vw' }}>
          <img style={{ width: '100%', display: 'block'}} src="path/to/image.jpg" alt="Image with markers" />
    
          {markers.map((marker, index) => (
            <div
              key={index}
              className="marker"
              style={{ left: `${marker.x}%`, top: `${marker.y}%`, position: "absolute" }}
              onClick={() => handleMarkerClick(marker)}
            />
          ))}
        </div>
      );
    };
    

    Corrigez simplement la position et ajoutez une vue de contrôle normale.

    Pour le contrôle, vous devez créer des composants séparés. Voici un exemple de la façon d'obtenir le comportement que vous souhaitez :

    .control {
      background: #08f;
      padding: 10px;
      width: 60px;
      box-sizing: border-box;
      border-radius: 200px;
      transition: all 0.2s ease-in-out;
      display: flex;
      align-items: center;
      overflow: hidden;
      cursor: pointer;
    }
    
    .control:hover {
      width: 200px;
    }
    
    .text {
      color: white;
      font: 30px Arial;
      margin-left: 16px;
      opacity: 0;
      transition: opacity 0.2s ease-in-out;
    }
    
    .control:hover .text {
      opacity: 1;
    }
    
    .icon {
      width: 40px;
      min-width: 40px;
      height: 40px;
      border-radius: 50%;
      box-shadow: 2px 2px 7px #0005;
      background-color: white;
      background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIFVwbG9hZGVkIHRvOiBTVkcgUmVwbywgd3d3LnN2Z3JlcG8uY29tLCBHZW5lcmF0b3I6IFNWRyBSZXBvIE1peGVyIFRvb2xzIC0tPgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIGZpbGw9IiMwMDAwMDAiIGhlaWdodD0iODAwcHgiIHdpZHRoPSI4MDBweCIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiAKCSB2aWV3Qm94PSIwIDAgMjk3IDI5NyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxnPgoJPHBhdGggZD0iTTI5NC4wNzcsMjUxLjE5OWwtNTkuMTA1LTU5LjEwN2w0Mi4xNjctMjQuMzU2YzMuMjk1LTEuOTAzLDUuMjEyLTUuNTIsNC45MzgtOS4zMTVjLTAuMjc0LTMuNzk2LTIuNjkyLTcuMTAxLTYuMjI2LTguNTEKCQlMODcuODIsNzQuOTA1Yy0zLjY4Ni0xLjQ3Mi03Ljg5NS0wLjYwNS0xMC43MDIsMi4yMDFjLTIuODA3LDIuODA4LTMuNjc0LDcuMDE2LTIuMjAzLDEwLjcwMmw3NC45OTQsMTg4LjA1MwoJCWMxLjQxLDMuNTM0LDQuNzE1LDUuOTUzLDguNTExLDYuMjI3YzMuNzk2LDAuMjc2LDcuNDE0LTEuNjQyLDkuMzE2LTQuOTM4bDI0LjM1NC00Mi4xNjdsNTkuMTAxLDU5LjEwNwoJCWMxLjg2MiwxLjg2Myw0LjM5LDIuOTEsNy4wMjMsMi45MWMyLjYzNSwwLDUuMTYxLTEuMDQ3LDcuMDIzLTIuOTFsMjguODQxLTI4Ljg0NUMyOTcuOTU2LDI2MS4zNjYsMjk3Ljk1NiwyNTUuMDc4LDI5NC4wNzcsMjUxLjE5OQoJCXoiLz4KCTxwYXRoIGQ9Ik00My42MSwyOS41NTJjLTMuODc5LTMuODc2LTEwLjE2Ni0zLjg3Ny0xNC4wNDcsMGMtMy44NzgsMy44NzktMy44NzgsMTAuMTY4LDAsMTQuMDQ3bDIyLjA2OSwyMi4wNjkKCQljMS45MzksMS45MzksNC40OCwyLjkwOSw3LjAyMywyLjkwOWMyLjU0MSwwLDUuMDgzLTAuOTcsNy4wMjItMi45MDljMy44NzktMy44NzksMy44NzktMTAuMTY3LDAtMTQuMDQ2TDQzLjYxLDI5LjU1MnoiLz4KCTxwYXRoIGQ9Ik01MS4wODksOTguMjE1YzAtNS40ODQtNC40NDctOS45MzItOS45MzMtOS45MzJIOS45NDZjLTUuNDg1LDAtOS45MzMsNC40NDctOS45MzMsOS45MzJjMCw1LjQ4NSw0LjQ0Nyw5LjkzMyw5LjkzMyw5LjkzMwoJCWgzMS4yMUM0Ni42NDIsMTA4LjE0Nyw1MS4wODksMTAzLjcsNTEuMDg5LDk4LjIxNXoiLz4KCTxwYXRoIGQ9Ik00Ny4wNjMsMTI4Ljg2OWwtMjIuMDcyLDIyLjA3MWMtMy44NzgsMy44NzktMy44NzgsMTAuMTY4LDAsMTQuMDQ2YzEuOTQsMS45MzksNC40ODIsMi45MDksNy4wMjMsMi45MDkKCQljMi41NDEsMCw1LjA4NC0wLjk3LDcuMDIzLTIuOTA5bDIyLjA3MS0yMi4wN2MzLjg3OS0zLjg3OSwzLjg3OS0xMC4xNjgsMC0xNC4wNDdDNTcuMjMsMTI0Ljk5Myw1MC45NDQsMTI0Ljk5Miw0Ny4wNjMsMTI4Ljg2OXoiLz4KCTxwYXRoIGQ9Ik05OC4yMjIsNTEuMDc4YzUuNDg1LDAsOS45MzMtNC40NDcsOS45MzMtOS45MzNWOS45MzJjMC01LjQ4NS00LjQ0Ny05LjkzMi05LjkzMy05LjkzMmMtNS40ODQsMC05LjkzMiw0LjQ0Ni05LjkzMiw5LjkzMgoJCXYzMS4yMTRDODguMjksNDYuNjMxLDkyLjczNyw1MS4wNzgsOTguMjIyLDUxLjA3OHoiLz4KCTxwYXRoIGQ9Ik0xMzUuODk0LDY0LjAwNmMyLjU0MywwLDUuMDg0LTAuOTcsNy4wMjMtMi45MDlsMjIuMDY4LTIyLjA2OWMzLjg3OS0zLjg3OSwzLjg3OS0xMC4xNjgsMC0xNC4wNDcKCQljLTMuODc5LTMuODc3LTEwLjE2OC0zLjg3Ny0xNC4wNDYsMGwtMjIuMDY4LDIyLjA3Yy0zLjg3OSwzLjg3OS0zLjg3OSwxMC4xNjgsMCwxNC4wNDYKCQlDMTMwLjgxMSw2My4wMzYsMTMzLjM1Miw2NC4wMDYsMTM1Ljg5NCw2NC4wMDZ6Ii8+CjwvZz4KPC9zdmc+');
      background-size: 60%;
      background-repeat: no-repeat;
      background-position: center;
    }
    <div class="control">
      <div class="icon"></div>
      <div class="text">Home</div>
    </div>

    répondre
    0
  • Annulerrépondre