地図の上の丸いボタンMapControlButtonExperimental
地図や canvas(図を一面に描く画面の部分)の上に浮かせる、アイコンだけの丸いボタンです。拡大・縮小・選んだ地点へ移動・現在地へ移動に使います。オン・使えない・取得中・失敗の状態を、色だけに頼らず見せます。
プレビュー
状態とバリエーション
大きさ
sm は 40px(下限)、default は 44px、lg は 48px。スマートフォンでボタンを縦にいくつも並べるときは sm、タブレットは lg。
オン
オン・オフを切り替えるボタン(現在地を追う など)がオンのとき。ボタン全体が塗られます。読み上げには aria-pressed で伝わります。
使えない
まだ地点を選んでいないなど。薄くなり、理由がツールチップに出ます。
取得中
押して始めた処理(現在地の取得など)の終わりを待っているあいだ。アイコンが明滅し、aria-busy が付きます。端末で「動きを減らす」設定をオンにしている人には明滅しません。
現在地を取得しています
失敗
取得に失敗したとき。注意の色の縁と「!」の印が付き、statusLabel が読み上げられます。
現在地を取得できませんでした
プロパティ
表は横にスクロールできます
| プロパティ | 型 | 初期値 | 説明 |
|---|---|---|---|
| label | string | - | 何をするボタンか。読み上げの名前とツールチップを兼ねます。 |
| children | ReactNode | - | アイコン。 |
| pressed | boolean | - | オン・オフを切り替えるボタンで、いまオンか。渡さなければ切り替えのボタンになりません。 |
| status | "idle" | "busy" | "error" | "idle" | 取得中か、失敗したか。 |
| statusLabel | string | - | 取得中・失敗のときに読み上げ、ツールチップに出す言葉。 |
| disabledReason | string | - | 押せない理由。押せないあいだのツールチップになります。 |
| size | "default" | "sm" | "lg" | "default" | 44px/40px(下限)/48px。 |
| tooltipSide | "top" | "right" | "bottom" | "left" | "left" | ツールチップを出す向き。 |
使い方
"use client";
import * as React from "react";
import { MapControlButton } from "@gunjo/ui";
import { IconCircleDot, IconMapPin, IconMinus, IconPlus } from "@tabler/icons-react";
export function MapColumn() {
const [zoom, setZoom] = React.useState(3);
const [following, setFollowing] = React.useState(false);
const [status, setStatus] = React.useState<"idle" | "busy" | "error">("idle");
const picked = null; // 地点を選ぶまでは null
const locate = () => {
if (following) return setFollowing(false);
setStatus("busy");
navigator.geolocation.getCurrentPosition(
() => {
setStatus("idle");
setFollowing(true);
},
() => {
setStatus("error");
// 失敗の印は短く。消すのは呼び出し側です
window.setTimeout(() => setStatus("idle"), 1600);
},
);
};
return (
<div className="flex flex-col items-center gap-2">
<MapControlButton label="拡大" onClick={() => setZoom(zoom + 1)}>
<IconPlus />
</MapControlButton>
<MapControlButton label="縮小" onClick={() => setZoom(zoom - 1)}>
<IconMinus />
</MapControlButton>
{/* 選んだ地点は ◎。現在地のピンと混ぜません */}
<MapControlButton
label="選んだ地点へ"
disabled={picked === null}
disabledReason="先に地図で地点を選んでください"
>
<IconCircleDot />
</MapControlButton>
<MapControlButton
label="現在地へ"
pressed={following}
status={status}
statusLabel={status === "busy" ? "現在地を取得しています" : "現在地を取得できませんでした"}
onClick={locate}
>
<IconMapPin />
</MapControlButton>
</div>
);
}設計の判断
- Button の変種にしていません。ふつうのボタンの後ろは、ページの無地の背景です。このボタンの後ろにあるのは海・街・雲の写真です。 どの上でも読めるように、半透明の背景色・後ろのぼかし・細い縁を、コンポーネントの側で持ちます。
- 状態を色だけに載せません。オンのときはボタン全体を塗り、取得中はアイコンが明滅し、失敗には「!」の印が付きます。
- 失敗の印を、時間が来たら自動で消す仕組みは持ちません。どれだけ出しておくかは画面ごとに違うので、status を戻すのは、このコンポーネントを使う側のコードです。
- 押せないボタンにも理由を言わせます。ボタン自体は、押してもキーボードで移動しても反応しません。代わりにボタンを包む枠がキーボードのフォーカスを受け、理由をツールチップに出します。
使用コンポーネント
関連コンポーネント
- Button
ふつうのページに置くボタン。後ろに地図はありません。
- TooltipButton
ふつうのページに置く、アイコンだけのボタン。取得中・失敗の状態は持たない。
- LayerMenu
このボタンから開く、地図に重ねて出すもの(雲・雨など)の選択。
- ScaleBar
同じ地図の上で、いまの縮尺を見せる物差し。
いつ・なぜ使うか(UIXHERO)
「いつ・なぜ使うか」の判断は、姉妹サイト UIXHERO の記事で解説しています。