ドキュメント / 基本 / ポリライン

ポリライン

座標の並びと線のスタイルを持つ状態オブジェクトを1つ作って、地図ビューに置くだけです。線の見え方・曲がり方・タップ判定はプロバイダごとにバラバラになりがちですが、MapConductor はどのプロバイダでも同じ結果になるように揃えています。

POINTS
GeoPoint[]
STROKE
color · width
GEODESIC
true / false
EVENT
onClick
プラットフォーム

01 · ポリラインの状態

PolylineState が1本の線を表します。座標列とスタイル、そしてタップハンドラを持ちます。プロパティを書き換えれば線はその場で更新され、ルートの形が変わるアプリでも作り直しは不要です。

PolylinePageViewModel.kt · Jetpack Compose
val polylineState =
    PolylineState(
        points = routePoints,
        strokeColor = Color.Red,
        strokeWidth = 4.dp,
        geodesic = true,
        onClick = { event -> viewModel.onPolylineClick(event) },
    )

// 地図の中に置くだけ
Polyline(polylineState)

// 形の変更は points を書き換えるだけ
polylineState.points = nextPoints
プロパティ
説明
points
線を構成する座標の並び。書き換えると形が変わります。
strokeColor
線の色。半透明も指定できます。
strokeWidth
線の太さ。プラットフォームの論理単位で指定し、端末の解像度によらず同じ太さに見えます。
geodesic
大圏コース(測地線)で結ぶかどうか。既定は false。
zIndex
重なり順。他のオーバーレイとの前後関係を決めます。
extra
任意の付随データ。タップ時に受け取れます。
onClick
タップハンドラ。線の状態とタップされた座標を受け取ります。

02 · 直線と大圏コース

geodesic を true にすると、2点を地球上の最短経路(大圏コース)で結びます。長距離のフライト経路などは直線ではなく弧を描きます。false のときは地図投影上の直線です。同じ座標列で両方を並べて描き比べられます。

geodesic = false
メルカトル図法上の直線。近距離では違いはほとんどありませんが、長距離では実際の最短経路からずれます。
geodesic = true
地球の丸みに沿った最短経路。高緯度側へ膨らむ弧として描かれます。
同じ座標で2本描く
Polyline(polylineState) // geodesic = true(曲線)
Polyline(
    polylineState.copy(
        id = "${polylineState.id}-straight",
        geodesic = false,
        strokeColor = Color.Blue,
    ),
)

03 · どのプロバイダでも同じに見える

地図エンジンには、大圏コースを描けるものと描けないもの、線の太さの単位が違うもの、日付変更線をまたぐ線の扱いが違うものが混在しています。素のSDKを使うと、同じ座標列でも見た目が変わってしまいます。

MapConductor はこの差を内部で吸収します。アプリ側は PolylineState を1つ渡すだけで、どのプロバイダでも同じ弧・同じ太さ・同じタップ範囲になります。

GEODESIC

曲線を描けないエンジンにも同じ弧を

大圏コースを直接描けないエンジンでは、線を細かい区間に分けた座標列に変換してから渡します。結果として、どのエンジンでも同じ弧が表示されます。

ANTIMERIDIAN

日付変更線をまたぐ線

経度180度をまたぐ線は、そのまま渡すと地球を逆向きに横断してしまうエンジンがあります。境界で線を分割して渡すことで、どのエンジンでも最短側を通ります。

STROKE WIDTH

太さの基準を揃える

線の太さはプラットフォームの論理単位で指定します。端末の画素密度やエンジンごとの単位差を内部で換算するため、実機での見た目の太さが一致します。

HIT TEST

タップ判定も共通

タップ判定はエンジンに任せず、共通のロジックで行います。指の大きさぶんの許容範囲をズームに応じたメートルに換算して判定するため、拡大率が違っても押しやすさが変わりません。曲線の場合は弧に沿って判定します。

図 · 日付変更線をまたぐとき
180°
素のまま渡した場合。経度180度をまたげず、地球を逆向きに横断する線になってしまうエンジンがあります。
180°
MapConductor 経由。経度180度で線を分割して渡すため、どのエンジンでも境界をまたいで最短側を通ります。
サンプル動画 · SwiftUI で書いた同じコードを Google Maps と MapLibre で

04 · タップ

onClick は線の状態と、線上でタップされた位置を受け取ります。タップ位置は線に最も近い点に補正された座標なので、その場所にマーカーを置いたり距離を計算したりできます。

event.state
タップされた線の状態そのもの。色や extra からデータを引けます。
event.clicked
線上の座標。指の位置ではなく、線に最も近い点です。
許容範囲
指の大きさぶんの余裕を持って判定します。ズームに応じてメートルに換算されます。
PolylineClickPageViewModel.kt
// タップ位置にマーカーを落とす
fun onPolylineClick(event: PolylineEvent) {
    markers = markers + MarkerState(
        position = event.clicked,
        animation = MarkerAnimation.Drop,
        icon = DefaultMarkerIcon(fillColor = event.state.strokeColor),
    )
}

表示範囲外の線分は判定から除外されるため、長いルートを何本も置いても反応が鈍くなりません。複数の線が重なっている場合は、最も近い線が選ばれます。

関連ページ