0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Leafletで地図以外の画像を取り扱う

Posted at

適当な画像をLeafletで表示してみます。画像はコレを使用します。

画像をタイル状に変換

image-map-tilesのインストール

拡大縮小出来るようにするには、各ズーム倍率でタイル状にする必要があります。手作業ではやってられないので下記ツールを使用します。

古くてGitHubのリンクも切れてる上、現状そのままで動かないのでパッチを当てます。

mkdir image-map-tiles
cd image-map-tiles
yarn init
echo nodeLinker: node-modules> .yarnrc.yml

patch-packageをインストールして、パッチファイルを配置。

yarn add -D patch-package postinstall-postinstall

package.json に追記。

package.json
  "scripts": {
    "postinstall": "patch-package"
  },

patches フォルダを作成し、パッチファイル image-map-tiles+1.0.0.patch を配置。

patches/image-map-tiles+1.0.0.patch
diff --git a/node_modules/image-map-tiles/index.js b/node_modules/image-map-tiles/index.js
index a18cae3..5d7c417 100644
--- a/node_modules/image-map-tiles/index.js
+++ b/node_modules/image-map-tiles/index.js
@@ -174,7 +174,7 @@ module.exports = function(imagePath, options) {
 			console.log(zoomPath, tileWidth, tileHeight);
 			console.log(metadata.width, metadata.height);
 
-			var image = sharp(buffer);
+			//var image = sharp(buffer);
 
 			var num_columns = Math.ceil(metadata.width / tileWidth);
 			var num_rows = Math.ceil(metadata.height / tileHeight);
@@ -218,6 +218,7 @@ module.exports = function(imagePath, options) {
 					if (err) {
 						console.log(err);
 					} else {
+						var image = sharp(buffer);
 						image
 							.extract({ left: crop.x, top: crop.y, width: options.tileWidth, height: options.tileHeight })
 							.toFile(tilePath + crop.row + '.jpg', function(err){
@@ -254,7 +255,7 @@ module.exports = function(imagePath, options) {
 
 			thumbnail
 			.resize(250, 250)
-			.crop(sharp.gravity.center)
+			//.crop(sharp.gravity.center)
 			.toFile(outputDir + 'thumbnail.jpg', function(err){
 				if (err) {
 					console.log('Thumbnail Error', err);

パッチの準備が出来たので、image-map-tiles をインストールする。インストール時に自動的にパッチがあたる。

yarn add -D image-map-tiles

画像をタイル状に変換する

入出力用のフォルダ input, output を作成し、inputに変換したい画像を入れておく。
入出力用のフォルダと同じ階層に main.js を作成する。

main.js
const imageMapTiles = require('image-map-tiles');

let options = {
  outputDir: "./output",
  zoom: 4,
  tileHeight: 256,
  tileWidth: 256,
};

imageMapTiles("./input/AMEMAN1222044.jpg", options);

実行すると、outputフォルダに変換された画像が出来る。

node main.js

Leaflet上で表示する

タイル状になった画像を public フォルダに格納しておきます。
スクリーンショット 2024-06-23 202230.png

マップコンポーネント

スタイルシートが無いと表示されないので作成する。

customMap.css
/* 地図を画面全体に表示 */
.leaflet-container {
  width: 100vw;
  height: 100vh;
}

/* 通常カーソル */
.leaflet-grab {
  cursor: auto;
}

マップコンポートネントを作成。

customMap.tsx
'use client';

import { default as L } from 'leaflet';
import markerIcon2x from 'leaflet/dist/images/marker-icon-2x.png';
import markerIcon from 'leaflet/dist/images/marker-icon.png';
import markerIconShadow from 'leaflet/dist/images/marker-shadow.png';
import 'leaflet/dist/leaflet.css';
import { useEffect, useLayoutEffect, useState } from 'react';
import './customMap.css';

const DefaultIcon = L.icon({
  iconUrl: markerIcon.src,
  iconRetinaUrl: markerIcon2x.src,
  shadowUrl: markerIconShadow.src,
  iconAnchor: [12, 41], // アイコンのオフセット
  popupAnchor: [0, -32], // ポップアップのオフセット
});
L.Marker.prototype.options.icon = DefaultIcon;

export default function CustomMap() {
  const [layoutLoad, setLayoutLoad] = useState(false);

  useLayoutEffect(() => {
    return setLayoutLoad(true); // マップの再初期化を防ぐ
  }, [layoutLoad]);

  useEffect(() => {
    if (!layoutLoad) return; // マップの再初期化を防ぐ

    const map = L.map('map', {
      crs: L.CRS.Simple,
      maxZoom: 4,
    });
    map.setView(L.latLng(-256, 256), 0); // 初期位置

    L.tileLayer('map/{z}/{x}/{y}.jpg', {
      attribution:
        '© <a href="https://www.pakutaso.com/20200556146post-25030.html">ぱくたそ</a>',
    }).addTo(map);

    // マーカー
    L.marker(L.latLng(-512, 512), {
      draggable: true,
    }).addTo(map);
  }, [layoutLoad]);

  return (
    <div className="leaflet-container">
      <div id="map"></div>
    </div>
  );
}

ページ

作成したマップコンポーネントを読み込むわけですが、クライアントサイドでしか動かないので、ダイナミックインポートする。

page.tsx
'use client';

import dynamic from 'next/dynamic';
import { useMemo } from 'react';

export default function Home() {
  const CustomMap = useMemo(
    () =>
      dynamic(() => import('./CustomMap'), {
        loading: () => <p>map loading...</p>,
        ssr: false,
      }),
    []
  );

  return <CustomMap />;
}

実行する

実行して http://localhost:3000/custommap にアクセスするとこんな感じに表示されます。

image-1.jpg

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?