Mapboxをキャプチャーして大きい画像を作りたい

実現したいこと

以下の流れを想定しています。

  • Mapboxである地域を表示している。幅は最大幅1080pxで高さは500pxほど
  • ボタンをクリックしたら表示している領域をキャプチャーしたい(html2canvasを利用)
  • 10000pxなど大きい画像としてダウンロードしたい。

ダウンロードの処理などはわかってるので、一番知りたいのはキャプチャーを10000pxなどの画像として保存したい。

環境はVue3のコンポジットAPIで script setupとして作成しています。
ソースコードはhtmlとjavascriptとして分割しています。

発生している問題・分からないこと

html2canvasを利用してキャプチャーを取ること自体は問題ない。
ただキャプチャーしたあとに新しいcanvasを新規に作ってそのサイズを5000pxとしても
Mapbox自体が1080pxなので余白ができる。

またMapbox自体を10000pxしようとしたがそもそもブラウザで10000pxもしくはそれ以上になる可能性もあると考えるとそもそもブラウザの幅を大きく超えてるため実現できない。

該当のソースコード

JavaScript

1let mapObj = null;2const generateImage = ref("");3 4onMounted(() => {5 initialMapBox();6});7 8const initialMapBox = () => {9 mapObj = new mapboxgl.Map({10 container: 'map',11 style: 'mapbox://styles/mapbox/streets-v12',12 center: [139.714590, 35.678184],13 zoom: 9,14 preserveDrawingBuffer: true15 });16 17 mapObj.on("load", () => {18 // 拡大・縮小コントロールを作成し、マップに追加する19 const navControl = new mapboxgl.NavigationControl();20 draw = new MapboxDraw({21 displayControlsDefault: false,22 controls: {23 trash: true24 }25 });26 27 mapObj.addControl(navControl, 'top-right')28 mapObj.addControl(draw);29 30 mapObj.on("draw.create", createDrawData);31 mapObj.on("draw.update", updateDrawData);32 mapObj.on("draw.delete", deleteDrawData);33 34 });35}36const createMapImage = () => {37 // マップの幅と高さを取得38 const mapCanvas = mapObj.getCanvas(document.querySelector('.mapboxgl-canvas'));39 const mapWidth = mapCanvas.width;40 const mapHeight = mapCanvas.height;41 42 // マップを10行10列に分割する43 const gridWidth = Math.floor(mapWidth / 10);44 const gridHeight = Math.floor(mapHeight / 10);45 46 const imagePromises = [];47 48 for (let i = 0; i < 10; i++) {49 for (let j = 0; j < 10; j++) {50 const x = j * gridWidth;51 const y = i * gridHeight;52 53 // キャプチャーのPromiseを作成し、配列に追加する54 const promise = html2canvas(mapCanvas, {55 useCORS: true,56 allowTaint: true,57 logging: true,58 x: x,59 y: y,60 width: gridWidth,61 height: gridHeight,62 scale: 463 }).then(canvas => {64 return canvas;65 });66 67 imagePromises.push(promise);68 }69 }70 71 // すべてのキャプチャーが完了したら処理を続行する72 Promise.all(imagePromises).then(Promise.all => {73 // 結合用の空のCanvasを作成する74 const combinedCanvas = document.createElement('canvas');75 combinedCanvas.width = 1000076 combinedCanvas.height = 1000077 const ctx = combinedCanvas.getContext('2d');78 79 let offsetX = 0;80 let offsetY = 0;81 for (const canvas of canvases) {82 ctx.drawImage(canvas, offsetX, offsetY);83 offsetX += gridWidth;84 if (offsetX >= mapWidth) {85 offsetX = 0;86 offsetY += gridHeight;87 }88 }89 90 // 生成された画像を設定91 generateImage.value = combinedCanvas.toDataURL();92 });93};94

html

1<div id="map"></div>2<button @click="createMapImage">画像を作成する</button>3 <img :src="generateImage" alt="キャプチャー画像" />4

試したこと・調べたこと

上記の詳細・結果

ソースコードを貼り付けていますが、試したことは以下です。

  • Mapboxをキャプチャーする際に画像を10✖️10などに分割する。
  • キャプチャーする際はhtml2canvasのscaleオプションで4として拡大してキャプチャーをとる
  • imagePromisesに一旦、分割したcanvasを保存する
  • Promise.allですべての分割が終わったらcanvasesからfor分で大きい1枚画像を作成する。

ただ処理が重すぎるため止まったりする。
また1枚画像としてできたとしてもバラバラになって綺麗にcanvasに描画できていない。

なので10000pxの画像を作る方法を知りたいです。

よろしくお願いします。

補足

以下のライブラリを使用

全体はVue3
html2canvas
Maobox

コメントを投稿

0 コメント