コンテンツにスキップ

Highlight the PLATEAU building under the mouse

Highlighting the hovered PLATEAU Shinjuku building with setFeatureState.

plateau_hover_building.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Highlight the PLATEAU building under the mouse</title>
  <meta property="og:description" content="Highlighting the hovered PLATEAU Shinjuku building with setFeatureState." />
  <script src="./v0.10.7/mapray.min.js"></script>
  <script src="./v0.10.7/maprayui.min.js"></script>
  <link rel="stylesheet" href="./v0.10.7/mapray.css">
  <style>
    body {margin: 0; padding: 0;}
    html, body, div#mapray-container { height: 100%; }
    .map-overlay {
        font: 12px/20px "Robot", sans-serif;
        position: absolute;
        width: 300px;
        top: 0;
        left: 0;
        padding: 10px;
    }
    .map-overlay .map-overlay-inner {
        background-color: #fff;
        color: #000;
        box-shadow: 0 1px 2px rgba(0,0,0,0.1);
        border-radius: 3px;
        padding: 10px;
        margin-bottom: 10px;
    }
    .map-overlay-inner fieldset {
        border: none;
        padding: 0;
        margin: 0 0 10px;
    }
    .map-overlay-inner fieldset:last-child {
        margin: 0;
    }
    .map-overlay-inner label {
        display: block;
        font-weight: bold;
        margin: 0 0 5px;
    }
    .map-overlay-inner select, .map-overlay-inner input[type=range] {
        width: 100%;
    }
    #tooltip {
        display: none;
        position: absolute;
        pointer-events: none;
        font: 12px/20px "Robot", sans-serif;
        background-color: rgba(0, 0, 0, 0.75);
        color: #fff;
        border-radius: 3px;
        padding: 2px 8px;
        white-space: nowrap;
    }
  </style>
</head>
<body>
<div id="mapray-container"></div>
<div id="tooltip"></div>
<div class="map-overlay top">
    <div class="map-overlay-inner">
        <fieldset>
            <label>How to use</label>
            Move the mouse over a building. Drag to move the camera.
        </fieldset>
    </div>
</div>
</body>
</html>
<script>
  // Highlights the Shinjuku building under the mouse through a feature state.
  const HOVER_STYLE = {
      color: { conditions: [
          [ "${state.hover} === true", "color('#ffd400')" ],
          [ "true",                    "color('#c8c8c8')" ],
      ] },
  };

  const tooltip = document.getElementById( 'tooltip' );

  function showTooltip( properties, point ) {
      if ( !properties ) {
          tooltip.style.display = "none";
          return;
      }
      tooltip.textContent = properties["gml:name"] ?? "(no name)";
      tooltip.style.left = ( point[0] + 12 ) + "px";
      tooltip.style.top = ( point[1] + 12 ) + "px";
      tooltip.style.display = "block";
  }

  // StandardUIViewer subclass that highlights the building under the mouse.
  class Tiles3DHoverViewer extends maprayui.StandardUIViewer {
      constructor( container, options ) {
          super( container, options );
          this._hovered = null;
      }

      onMouseMove( point, event ) {
          super.onMouseMove( point, event );
          // The camera is being dragged, so the highlight is left alone.
          if ( event.buttons !== 0 ) {
              return;
          }
          const pick_result = this.viewer.pick( point );
          const found = pick_result && pick_result.category === mapray.Viewer.Category.TILES_3D &&
                        pick_result.tile_content && pick_result.tile_feature_id !== undefined;
          const content = found ? pick_result.tile_content : null;
          const feature_id = found ? pick_result.tile_feature_id : null;
          if ( this._hovered && ( this._hovered.content !== content || this._hovered.feature_id !== feature_id ) ) {
              // A state is merged into the existing one, so only the hover flag is cleared.
              scene.setFeatureState( this._hovered.content, this._hovered.feature_id, { hover: false } );
              this._hovered = null;
          }
          if ( found && !this._hovered ) {
              scene.setFeatureState( content, feature_id, { hover: true } );
              this._hovered = { content, feature_id };
          }
          showTooltip( found ? content.getFeatureProperties( feature_id ) ?? null : null, point );
      }
  }

  const cloudApi = new mapray.cloud.CloudApiV2({
        tokenType: mapray.cloud.CloudApi.TokenType.ACCESS_TOKEN,
        token: "<YOUR_MAPRAY_ACCESS_TOKEN>"
    });
    // The StandardUIView in the ui package includes mouse-based camera manipulation.
    const uiviewer = new Tiles3DHoverViewer( "mapray-container", {
        dem_provider: new mapray.StandardDemProvider( cloudApi.getDefaultDemAsResource() )
    } );
  // South-west of the Nishi-Shinjuku skyscrapers in Tokyo JP
  uiviewer.setCameraPosition({
    longitude: 139.686,
    latitude: 35.684,
    height: 500
  });
  // Tokyo Metropolitan Government Building
  uiviewer.setLookAtPosition({
    longitude: 139.6925,
    latitude: 35.6905,
    height: 100
  });
  // PLATEAU Shinjuku-ku buildings, LOD2 without textures (OGC 3D Tiles 1.0: b3dm content)
  const provider = new mapray.StandardTiles3DProvider({
    url: "https://assets.cms.plateau.reearth.io/assets/2f/d4f9a7-13ad-43cb-b984-033803199eab/13104_shinjuku-ku_pref_2025_citygml_1_op_bldg_3dtiles_13104_shinjuku-ku_lod2_no_texture/tileset.json"
  }, {
    // PLATEAU tiles carry no copyright string, so credit the dataset as the PLATEAU terms of use require (Public Data License 1.0, compatible with CC BY 4.0).
    attributions: [ "出典:「3D都市モデル(Project PLATEAU)新宿区(2025年度)」(国土交通省)" ]
  });
  const scene = uiviewer.viewer.b3d_collection.createTiles3DScene(provider, {
    show_attributions: true,
    vertical_offset: -37   // ellipsoidal height to elevation (geoid undulation around Tokyo)
  });

  // Untextured LOD2 tiles are a flat gray, so REPLACE makes the hover color appear as it is.
  scene.setStyleColorBlendMode( mapray.Tiles3DScene.StyleColorBlendMode.REPLACE );
  scene.setStyle( mapray.Tiles3DStyle.fromJson( HOVER_STYLE ) );
</script>

Info

このサンプルコードは、<YOUR_MAPRAY_ACCESS_TOKEN>を、あなたのMapray CloudのアカウントのOrganization Tokenに置き換えるまで、期待通りに動作しません。