ポリゴン
外周の座標列と、任意の数の穴(holes)を持つ面です。塗りと線のスタイルを添えて地図ビューに置くだけで、エリアの表示やマスク表現ができます。穴の扱いは地図SDKごとに癖がありますが、MapConductor はどのプロバイダでも同じ見た目になるように揃えています。
01 · ポリゴンの状態
PolygonState が1つの面を表します。外周・穴・塗り・線・タップハンドラを持ち、プロパティを書き換えれば形はその場で更新されます。頂点マーカーをドラッグして形を編集するようなUIも、座標列を差し替えるだけで作れます。
val polygonState =
PolygonState(
points = outerRing,
holes = listOf(holeA, holeB),
strokeColor = Color.Red,
strokeWidth = 3.dp,
fillColor = Color(0x4D0064E6),
onClick = { event -> viewModel.onPolygonClick(event) },
)
Polygon(polygonState)
// 頂点や穴は書き換えるだけで更新される
polygonState.holes = nextHoleslet polygonState = PolygonState(
points: outerRing,
strokeColor: .red,
strokeWidth: 3.0,
fillColor: UIColor(red: 0, green: 0.39, blue: 0.9, alpha: 0.3),
holes: [holeA, holeB],
onClick: { event in viewModel.onPolygonClicked(event) }
)
content.polygons = [Polygon(state: polygonState)]const polygonState = createPolygonState({
id: 'demo-polygon',
points: vertices,
holes,
strokeColor: '#e74c3c',
strokeWidth,
fillColor: `rgba(0, 100, 230, ${fillOpacity})`,
onClick: () => showToast('Polygon clicked'),
});
<Polygon state={polygonState} />02 · 穴(holes)と重なりの結合
穴は外周から抜く領域です。マスク表現では「見せたい場所」を穴として複数置くことがよくありますが、そのとき穴同士が重なるのは自然に起こります。
多くの地図SDKは、重なり合う穴をそのまま渡すと重なった部分に輪郭線を描いてしまい、穴と穴の境目が見えてしまいます。MapConductor は渡された穴を結合してから描画するため、重なりは1つの穴として扱われ、余分な線は出ません。


// 重なり合う穴をそのまま渡してよい。内部で1つの穴に結合される
PolygonState(
points = outerRing,
holes =
listOf(
triangleA, // ← 互いに重なっている
triangleB,
),
fillColor = Color(0xCC787880),
)// 重なり合う穴をそのまま渡してよい。内部で1つの穴に結合される
let state = PolygonState(
points: outerRing,
fillColor: UIColor(white: 0.47, alpha: 0.8),
holes: [triangleA, triangleB]
)// 重なり合う穴をそのまま渡してよい。内部で1つの穴に結合される
const state = createPolygonState({
id: 'world-hole',
points: OUTER_POINTS,
holes, // 互いに重なる三角形2つ
fillColor: 'rgba(120, 120, 128, 0.8)',
strokeColor: '#ef4444',
strokeWidth: 2,
});03 · どのプロバイダでも同じに見える
穴の重なりのほかにも、面の描画にはエンジンごとの差が出やすいところがあります。MapConductor はそれらを内部で吸収し、同じ PolygonState から同じ絵になるようにしています。
重なる穴を結合する
穴同士の重なりは、状態を作る段階で1つの領域に結合されます。輪郭線が重なり部分に現れることも、塗りが二重になることもありません。
曲線を描けないエンジンにも同じ形を
大圏コースを直接描けないエンジンでは、辺を細かく分割した座標列に変換してから渡します。広域のエリアでも形が一致します。
日付変更線をまたぐ面
経度180度をまたぐ面は境界で分割して渡します。地球を逆向きに横断する塗りになるエンジンでも正しい側が塗られます。
タップ判定も共通
タップ判定は共通ロジックで行い、穴の内側はタップに反応しません。エンジンが穴を考慮するかどうかに関係なく、見えているとおりの判定になります。
04 · タップ
onClick は面の状態と、タップされた座標を受け取ります。塗りや extra からデータを引いて、詳細を表示するのが定番の使い方です。
fun onPolygonClicked(event: PolygonEvent) {
markerState = MarkerState(
position = event.clicked,
icon = DefaultMarkerIcon(fillColor = event.state.fillColor),
)
}func onPolygonClicked(_ event: PolygonEvent) {
let color = event.state.fillColor.withAlphaComponent(1.0)
markerState = MarkerState(
position: GeoPoint.from(position: event.clicked),
id: "clicked",
icon: DefaultMarkerIcon(fillColor: color)
)
}onClick: event => {
setMarker(createMarkerState({
id: 'clicked',
position: event.clicked,
icon: new ColorDefaultIcon({ fillColor: event.state.fillColor }),
}));
},面が重なっている場合は上(zIndex の大きい方)が優先されます。広いエリアを何面も置いても、表示範囲外の面は判定から除外されます。