Heim  >  Fragen und Antworten  >  Hauptteil

Platzieren Sie mit React interaktive Markierungen auf Bildern

Bitte helfen Sie. Ich habe ein Bild wie das untenstehende, das auf der Homepage angezeigt wird (ein größeres Bild). Beachten Sie, dass das „FORGE“-Haus in der Mitte eine weiße und blaue Markierung mit einem schwarzen Pfeil hat.

Das Gleiche gilt für „Mietwohnungen“.

Jede dieser Markierungen fungiert als interaktive Schaltfläche. Das Folgende ist das erwartete Interaktionsverhalten:

Außerdem möchten Sie, dass es reagiert. Wenn die Bildschirmgröße geändert wird, sollten die Schaltflächen an diesen spezifischen Positionen bleiben.

Ich versuche, absolute Positionierung und XY-Koordinaten zu verwenden, um es zum Laufen zu bringen. Aber da mir die Erfahrung mit dieser Art von Benutzeroberfläche gefällt, kann ich keine funktionierende Lösung finden. Ich bin mir nicht sicher, ob ich Canvas oder etwas anderes verwenden soll.

Jede Hilfe wäre sehr dankbar.

Mein Code sieht so aus, aber es sieht so aus, als ob ich nicht auf dem richtigen Weg bin:

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粉896751037431 Tage vor808

Antworte allen(1)Ich werde antworten

  • P粉412533525

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

    您应该将控件放置在图像容器的绝对位置。 实现取决于多种因素,例如图像放置的位置、是否全屏显示、图像之前或之后是否有内容等。 但这段代码应该向您展示主要原理。

    如果在调整窗口大小时调整图像大小,则应该创建一个与图像完全相同的容器。然后,您可以设置控件相对于该容器的位置,并使它们固定在各自的点上。

    .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>

    使用你的代码,它会是这样的(但我建议在样式文件中移动你的样式,学习如何在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>
      );
    };
    

    只需修复位置并添加正常的控制视图即可。

    为了进行控制,您应该制作单独的组件。以下是如何实现您想要的行为的示例:

    .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>

    Antwort
    0
  • StornierenAntwort