🌈

Mapbox Newsletter WEEKLY TIPSの解説 -「expressionを使用してグラデーションラインを作成」

2023/10/28に公開

はじめに

この記事は、先日配信されたMapbox NewsletterのWEEKLY TIPSで紹介されていた「expressionを使用してグラデーションラインを作成」についての解説です。このサンプルではExpressionsを使ってLineStringの色をグラデーションさせる方法を例示しています。また、Newsletterの購読はこちらからお申し込みいただけます。

以下が本サンプルのデモです。

コードを確認

まずExamplesのコードを見に行きましょう。

日本語サイト

英語サイト

基本的に同じコードですが、英語版はスタイルがMapbox Light v11にアップグレードされているのでこちらを使用します。Mapbox Light v10ではデフォルトのプロジェクションがWebメルカトルであるのに対し、Mapbox Light v11ではGlobe(3D表示された地球)なので、印象がかなり異なります。

HTML/CSS

まずHTMLを見ていきましょう。

以下は地図を表示するエレメントを作成しています。

<div id="map"></div>

Mapの作成

次にJavaScriptのコードを見ていきます。以下のコードはいつも通り、Mapオブジェクトを作成しています。containerで地図を表示するHTMLエレメントのidを指定します。

const map = new mapboxgl.Map({
  container: 'map',
  // Choose from Mapbox's core styles, or make your own style with Mapbox Studio
  style: 'mapbox://styles/mapbox/light-v11',
  center: [-77.035, 38.875],
  zoom: 12
});

GeoJSONの作成

今回のサンプルは線を引くので、LineStringのデータをGeoJSONで作成しています。

const geojson = {
  'type': 'FeatureCollection',
  'features': [
    {
      'type': 'Feature',
      'properties': {},
      'geometry': {
      'coordinates': [
        [-77.044211, 38.852924],
        [-77.045659, 38.860158],
        ...
      ],
      'type': 'LineString'
      }
    }
  ]
};

ソースの追加

map.on('load', () => {}の中身を見ていきます。以下の部分でソースを追加しています。先ほど作成したGeoJSONをソースとして使用します。lineMetricstrueに設定しておかないとError: layers.line: layer "line" specifies a line-gradient, which requires a GeoJSON source with lineMetrics enabled.というエラーが発生するので注意が必要です。

map.addSource('line', {
  type: 'geojson',
  lineMetrics: true,
  data: geojson
});

レイヤーの追加

次にレイヤーの追加です。ここでいよいよグラデーションの登場です。レイヤーの役割は見た目(色や形)を指定することなので、ここでグラデーションが出てくるのは納得ですね。

まずはグラデーション以外の部分を見ていきます。線を引くのてtypelinesourceはさきほどしたソースのIDであるlineを指定します。paintプロパティではデフォルトの色として'line-color': 'red'、太さを'line-width': 14としています。また、layoutプロパティは'line-cap': 'round'で線の始点と終点を丸く、'line-join': 'roundで線のカドを丸くしています。

map.addLayer({
  type: 'line',
  source: 'line',
  id: 'line',
  paint: {
    'line-color': 'red',
    'line-width': 14,
    // 'line-gradient' must be specified using an expression
    // with the special 'line-progress' property
    'line-gradient': [
      ...
    ]
  },
  layout: {
    'line-cap': 'round',
    'line-join': 'round'
  }
});

そして以下がグラデーションです。グラデーションはExpressionsで指定します。ExpressionsはJSONの配列で表現する式で["op", "param1", ...]という形式を取ります。配列の要素0が命令、それ以降がパラメータです。ちょうどLisp言語のS式のような感じです。

    'line-gradient': [
      'interpolate',
      ['linear'],
      ['line-progress'],
      0,
      'blue',
      0.1,
      'royalblue',
      0.3,
      'cyan',
      0.5,
      'lime',
      0.7,
      'yellow',
      1,
      'red'
    ]

interpolateは補間に関するExpressionsです。第一引数がtypeでlinearなら線形補間、exponentialなら指数的な補間が使用されます。ここではlinearが指定されているので線形補間です。

第二引数が「値」の供給源の指定です。この「値」に応じて以降で指定する色が使用されます。ここではline-progressというExpressionsが使用されていますが、これはLineの始点からどれぐらいの場所かを返します。始点が0、終点が1です。

一般にinterpolateの第二引数には、['get', プロパティ名]と記述するすることでプロパティに応じてline-colorを変えるというような使い方をします。しかしline-gradientではこのような使い方はできません。これはプロパティのタイプにより決まっています。

第三引数以降が「値」「出力」の組です。ここでは0(始点)がblue0.1(10%地点)でroyalblue1(終点)がredです。

ちなみに、line-gradientのソースに使用できるのはGeoJSONのみです。Vector TilesetではLineString全体が読み込まれているとは限らず、グラデーションが計算できないからではないかと推察します。

まとめ

Lineのグラデーションはline-progressを使うということがポイントでした。lineMetricsの指定も忘れないようにしましょう。

GitHubで編集を提案
マップボックス・ジャパン合同会社

Discussion