Placez des marqueurs interactifs sur les images à l'aide de React
P粉896751037
P粉896751037 2023-09-08 21:25:41
0
1
847

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 :

  • Au survol, le fond bleu s'agrandira pour révéler le texte "Forge" ou "Locations"
  • Une fois cliqué, il dirigera l'utilisateur vers la page « Forge » ou « Locations » correspondante.

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粉896751037
P粉896751037

répondre à tous(1)
P粉412533525

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>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal