Polyline
Build one state object from a list of coordinates and a stroke style, then place it in the map view. How a line curves, how thick it looks and how easily it can be tapped normally differ per provider — MapConductor makes the result identical everywhere.
01 · Polyline state
PolylineState represents one line: its coordinates, its stroke and a tap handler. Assigning to a property updates the line in place, so a changing route never needs rebuilding.
val polylineState =
PolylineState(
points = routePoints,
strokeColor = Color.Red,
strokeWidth = 4.dp,
geodesic = true,
onClick = { event -> viewModel.onPolylineClick(event) },
)
// 地図の中に置くだけ
Polyline(polylineState)
// 形の変更は points を書き換えるだけ
polylineState.points = nextPointslet polylineState = PolylineState(
points: routePoints,
strokeColor: .red,
strokeWidth: 4.0,
geodesic: true,
onClick: { event in viewModel.onPolylineClick(event) }
)
content.polylines = [Polyline(state: polylineState)]const polylineState = createPolylineState({
id: 'demo-polyline',
points,
strokeColor: '#e74c3c',
strokeWidth,
geodesic: true,
onClick: event => showToast(event.clicked),
});
<Polyline state={polylineState} />02 · Straight lines and great circles
With geodesic set to true, points are joined along the shortest path across the globe, so a long flight route draws as an arc rather than a straight line. With false you get a straight line in the map projection. The same coordinates can be drawn both ways side by side.
Polyline(polylineState) // geodesic = true(曲線)
Polyline(
polylineState.copy(
id = "${polylineState.id}-straight",
geodesic = false,
strokeColor = Color.Blue,
),
)content.polylines = [
Polyline(state: polylineState), // 曲線
Polyline(state: polylineState.copy(geodesic: false)) // 直線
]const straightPolyline = polyline.copy({
id: `${polyline.id}-straight`,
geodesic: false,
strokeColor: '#0000ff',
});
<Polyline state={polyline} />
<Polyline state={straightPolyline} />03 · The same result on every provider
Some engines can draw great circles and some cannot; stroke width units differ; lines crossing the date line are handled differently. On the raw SDKs the same coordinates give you different pictures.
MapConductor absorbs those differences internally. You pass one PolylineState and get the same arc, the same thickness and the same tap area on every provider.
The same arc even without curve support
For engines that cannot draw great circles, the line is converted into a densified list of coordinates before it is handed over, so the displayed arc matches everywhere.
Lines crossing the date line
Passed as-is, some engines route such a line the long way around the globe. Splitting it at the boundary makes every engine take the short side.
One basis for thickness
Width is given in platform logical units and converted internally for screen density and per-engine unit differences, so the line looks equally thick on real devices.
Shared tap detection
Tap detection is not left to the engine. A fingertip-sized tolerance is converted into metres for the current zoom, so lines stay equally easy to hit at any scale; geodesic lines are tested along the arc.
04 · Tapping
onClick receives the line state and the position tapped along the line. That position is snapped to the closest point on the line, so you can drop a marker there or measure from it.
The tapped line state itself — read its colour or extra payload.
A coordinate on the line: the closest point, not the raw finger position.
A fingertip-sized margin, converted into metres for the current zoom.
// タップ位置にマーカーを落とす
fun onPolylineClick(event: PolylineEvent) {
markers = markers + MarkerState(
position = event.clicked,
animation = MarkerAnimation.Drop,
icon = DefaultMarkerIcon(fillColor = event.state.strokeColor),
)
}func onPolylineClicked(_ event: PolylineEvent) {
markerState = MarkerState(
position: GeoPoint.from(position: event.clicked),
icon: DefaultMarkerIcon(fillColor: event.state.strokeColor)
)
}onClick: event => {
setClickMarkers(prev => [...prev, createMarkerState({
id: `polyline-click-${prev.length}`,
position: event.clicked,
animation: MarkerAnimation.Drop,
icon: new ColorDefaultIcon({ fillColor: event.state.strokeColor }),
})]);
},Segments outside the visible region are skipped, so many long routes stay responsive. Where lines overlap, the closest one wins.