diff --git a/Sources/MapConductorCore/marker/ColorDefaultIcon.swift b/Sources/MapConductorCore/marker/ColorDefaultIcon.swift index 8b12432..2202d48 100644 --- a/Sources/MapConductorCore/marker/ColorDefaultIcon.swift +++ b/Sources/MapConductorCore/marker/ColorDefaultIcon.swift @@ -34,7 +34,7 @@ public final class ColorDefaultIcon: MarkerIconProtocol { /// ラベルをピンに対してどこへ置くか。CSS の `background-position` と同じ書き方で、 /// 横(left / center / right)と縦(top / center / bottom)のキーワードを空白区切りで /// 並べる。順序は問わず、片方だけなら残りは center。 - /// - left / right はピンの外側に置き、縦はピンの上端・頭の中心・先端に揃える。 + /// - left / right はピンの外側に置き、縦はピンの上端・上端と先端の中間・先端に揃える。 /// - center 列の top / bottom はピンの上・下の外側に置く。 public let labelPosition: String /// 指定された infoAnchor(ピン本体に対する割合)。`infoAnchor` はビットマップに対する割合へ直した値。 @@ -539,9 +539,11 @@ struct DefaultIconLayout { var cy = headCenterY if h != 0 { - // 横に置くときは、縦はピンの上端・頭の中心・先端に揃える。 + // 横に置くときは、縦はピンの上端・上端と先端の中間・先端に揃える。 + // center を頭の中心にすると、ピン全体の中央より上に見える。 if v < 0 { cy = pinTop + labelHeight / 2.0 } if v > 0 { cy = pinBottom - labelHeight / 2.0 } + if v == 0 { cy = (pinTop + pinBottom) / 2.0 } } else { // 中央列の top / bottom はピンと重ならないよう上下の外側に置く。 if v < 0 { cy = pinTop - gap - labelHeight / 2.0 } diff --git a/Tests/MapConductorCoreTests/DefaultIconLabelPositionTests.swift b/Tests/MapConductorCoreTests/DefaultIconLabelPositionTests.swift index 0cc193a..fa02e40 100644 --- a/Tests/MapConductorCoreTests/DefaultIconLabelPositionTests.swift +++ b/Tests/MapConductorCoreTests/DefaultIconLabelPositionTests.swift @@ -41,6 +41,21 @@ final class DefaultIconLabelPositionTests: XCTestCase { XCTAssertEqual(icon.anchor, icon.toBitmapIcon().anchor) } + func testSideCenterIsHalfwayDownThePin() { + // 横に置いた center は、ピンの上端と先端の真ん中(頭の中心ではない)。 + let metrics = DefaultMarkerIcon.markerPathMetrics(canvasSize: 48, iconScale: 1, strokeWidth: 1) + let middle = metrics.offsetY + 12.0 * metrics.markerScale + for position in ["right center", "left center", "right"] { + let layout = DefaultIconLayout.make( + canvasSize: 48, iconScale: 1, strokeWidth: 1, + labelSize: CGSize(width: 60, height: 16), outlineStrokeWidth: 2, + labelPosition: position + ) + XCTAssertEqual(layout.labelCenter.y - layout.markerOffsetY, middle, accuracy: 0.001, position) + XCTAssertGreaterThan(middle, 48 * 0.35 + 3, "the head's center is well above the middle") + } + } + func testLeftIsNearlyMirrorOfRight() { // ピン形は外接箱の中で 0.25 単位だけ右に寄っているので、1pt までの差は許す。 let right = tip(ColorDefaultIcon(label: label, labelPosition: "right"))