@yamat47/playmaker 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +51 -2
- package/dist/playmaker.css +2 -0
- package/dist/playmaker.d.ts +319 -0
- package/dist/playmaker.js +2827 -0
- package/dist/playmaker.js.map +1 -0
- package/package.json +68 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playmaker.js","names":["fontUrl","toDisposable","fn","DisposableStore","item","Disposable","GRID_STEP_YARDS","snapYard","yard","snapToGrid","position","isRecord","value","isFiniteNumber","isNonEmptyString","isOneOf","values","candidate","parseBoundedArray","raw","parsed","end","max","index","parse","PLAYER_SHAPE_VALUES","DEFAULT_PLAYER_SHAPE","PLAYER_FILL_VALUES","PLAYER_RADIUS_YARDS","isPlayerShape","isPlayerFill","parseFieldPosition","lateralYard","downfieldYard","normalizePlayer","normalizePlayers","clonePlayer","player","MIN_LINE_PX","YARD_LINE_WIDTH_PER_W","HASH_TICK_LENGTH_PER_U","NUMBER_HEIGHT_PER_U","NUMBER_MIN_PX","MIDFIELD_LINE_WIDTH_PER_YARD_LINE","PYLON_SIZE_PER_U","PYLON_MIN_PX","GOALPOST_CROSSBAR_HALF_PER_U","GOALPOST_UPRIGHT_LENGTH_PER_U","GOALPOST_STROKE_PER_D","GOALPOST_STROKE_MIN_PX","MARKER_LABEL_PER_D","MARKER_LABEL_MIN_PX","ROUTE_WIDTH_PER_D","ROUTE_WIDTH_MIN_PX","BLOCK_CAP_LENGTH_PER_D","ARROW_LENGTH_PER_D","ARROW_HALF_WIDTH_PER_D","MOTION_DASH_ON_PER_U","MOTION_DASH_OFF_PER_U","GRID_DOT_RADIUS_PER_U","GRID_DOT_RADIUS_MIN_PX","computeFieldMetrics","w","fieldPixelWidth","u","unitPx","yardLineWidth","d","routeWidth","EDITOR_TOOL_VALUES","NO_SELECTION","isSameSelection","a","b","isToolAvailable","tool","state","canLoadFormation","formation","Emitter","onListenerError","listener","err","CommandService","model","history","changed","command","UndoRedoService","revert","reapply","from","run","to","TEAM_SIDE_VALUES","isTeamSide","deepFreeze","child","toFormationPlayer","_id","template","normalizeFormation","players","instantiateFormation","taken","takenIds","id","ids","IdFactory","prefix","LINE_KIND_VALUES","LINE_INTERPOLATION_VALUES","DEFAULT_LINE_KIND","DEFAULT_LINE_INTERPOLATION","isLineKind","isLineInterpolation","isLineThickness","normalizeLine","validPlayerIds","normalizeLines","entry","cloneLine","line","p","lineAnchorPoints","start","playersById","indexPlayersById","map","FIELD_ZONE_VALUES","DEFAULT_FIELD_ZONE","FIELD_ZONE_LABELS","LOS_YARD_BY_ZONE","CURRENT_PLAY_DATA_VERSION","isFieldZone","fieldStateForZone","zone","clonePlayData","data","resolvePlayData","source","makeIdsUnique","items","seen","n","toV2Position","rest","absoluteYard","losYard","toV2Player","toV2Line","migrateV1ToV2","field","l","PLAY_DATA_MIGRATIONS","readDeclaredVersion","applyPlayDataMigrations","acc","step","steps","declaredVersion","migratePlayData","insertAt","what","assertNewId","message","assertWithinLimit","count","limit","assertWithinLimits","PlayModel","initialData","target","removedLines","lines","i","removal","remaining","removals","prev","next","requireApplied","SetFieldZoneCommand","LoadFormationCommand","asRecord","applyPatch","current","key","patch","patchChangesAnything","applyLinePatch","AddLineCommand","RemoveLineCommand","lineId","UpdateLineCommand","applyPlayerPatch","AddPlayerCommand","RemovePlayerCommand","playerId","UpdatePlayerCommand","FIELD_WIDTH_YARDS","HASH_CENTER_OFFSET_YARDS_BY_LEAGUE","DEFAULT_FIELD_LEAGUE","fieldZoneWindow","zoneWindowLength","endYard","startYard","fieldWindowAspect","clampToZoneWindow","displayYardNumber","yardLinesInWindow","stepYards","first","y","FieldGeometry","viewportWidth","viewportHeight","windowLength","h","x","point","segments","previous","points","polylineLength","total","path","trimPolylineEnd","distance","maxFraction","segLen","t","cubicBezierPoint","p0","c1","c2","p1","catmullRomBezierControls","p2","p3","dedupeConsecutive","out","last","sampleLinePath","pts","interpolation","samplesPerSegment","result","s","hitTestPlayer","radiusYards","r2","dx","dy","LINE_HIT_TOLERANCE_YARDS","distanceToSegment","abx","aby","apx","apy","lenSq","distanceToPolyline","only","pointDistance","min","hitTestLine","toleranceYards","byId","anchors","WAYPOINT_HANDLE_RADIUS_YARDS","hitLineHandle","within","VIEW_STATE_EQUALS","VIEW_STATE_KEYS","isSameEntry","isSameView","EditorNotifier","readView","action","view","isSamePosition","MAX_DRAFT_POINTS","startDrag","origin","pointer","dragPosition","drag","dragPatch","scene","splitDraftPoints","startDrawing","addDraftPoint","accepts","draw","committableDraft","split","anchor","draftToLine","shape","DRAFT_LINE_ID","applyDragPatch","drop","draftLine","composePreview","interaction","computeOverlay","selection","EditorController","commands","pos","moved","added","loaded","handle","hit","openDocument","store","PlaySession","normalized","opened","controller","DEFAULT_EXPORT_WIDTH","MAX_EXPORT_WIDTH","resolveImageExportWidth","width","resolveImageExportSize","options","pt","shortOf","lateral","beside","OL","FRONT_4","END_OVER_TE","FRONT_3","LB_43","LB_NICKEL","cornerSpots","depth","offensiveLine","front4","strongEnd","front3","corners","left","right","iFormation","singlebackAce","shotgunSpread","trips","empty","pistol","bunch","defense43","defense34","nickelFront","NICKEL_BASE","nickel","shell","dime","defense425","defense335","FORMATION_PRESETS","getFormationPreset","f","ARROW_TRIM_MAX_FRACTION","lineEnd","tip","length","trimForArrowHead","arrowLength","arrowHeadVertices","baseX","ux","baseY","uy","halfWidth","blockCapEndpoints","half","capLength","CIRCLE_DRAW_SCALE","playerMarkerOutline","radius","resolveKeyAction","mod","stroke","ln","play","COVER_2_SHELL","COVER_3_SHELL","PLAY_PRESETS","getPlayPreset","isFormControl","PointerInput","canvas","surface","toYard","activePointerId","onPointerDown","onPointerMove","endPress","onPointerUp","onPointerAbort","onDoubleClick","onKeyDown","listeners","root","playmaker_saira_subset_default","FIELD_FONT_NAME","FIELD_FONT_FAMILY","fieldFont","sizePx","loadFieldFont","registerFieldFont","face","context","resolveContext","ctx","normalizeCssColor","resolved","fromBlack","WHITE","BLACK","RED","BLUE","GREEN","ORANGE","GREY_100","GREY_200","GREY_400","GREY_500","THEME_TOKENS","themeReaderFrom","token","readProperty","property","fallback","createThemeReader","styles","element","ARROW_LENGTH_YARDS","ARROW_HALF_WIDTH_YARDS","ARROW_OFFSET_FROM_NUMBER_YARDS","NUMBER_FROM_SIDELINE_YARDS","NUMBER_DIGIT_SPACING_PER_HEIGHT","fieldTheme","read","FieldRenderer","frame","theme","geometry","bounds","yardWindow","metrics","yTop","yBottom","offset","center","hashLeft","hashRight","tick","goalPath","midPath","minorPath","top","bottom","leftX","rightX","arrowBaseHalfPx","halfArrowLength","gap","drawRotatedLabel","head","tail","label","rotation","drawArrow","xc","tipY","numberY","towardGoal","arrowCenterYard","pylon","drawPylon","goalY","endY","cx","crossHalf","uprightLen","dir","uprights","lineY","GridRenderer","gridDots","dots","size","LINE_COLOR_TOKENS","LineRenderer","color","isBlock","strokePath","kind","vertices","endpoints","OverlayRenderer","overlay","drawSelectedPlayer","r","drawLineHandles","fill","outline","handleHalf","paintHandle","waypoint","handles","PlayerRenderer","defaultColor","grass","fontPx","isSolid","halfSide","tm","labelY","createDefaultLayers","renderLayers","layer","layers","CanvasSurface","parent","observer","rect","clientX","clientY","height","blob","resolve","reject","dpr","clientWidth","clientHeight","editorFrame","replaceKeepingFocus","doc","container","hadFocus","update","COLOR_PALETTE","SHAPE_LABELS","FILL_LABELS","KIND_LABELS","INTERPOLATION_LABELS","createSwatch","btn","name","PropertyPanel","focusFallback","selected","shown","hint","setLabel","v","setShape","choices","opt","setPressed","choice","setKind","setInterpolation","setThickness","text","labelText","control","onReset","group","span","row","children","reset","input","onChange","swatches","isPressed","select","o","optionLabels","TOOL_LABELS","FORMATION_LIMIT_REASON","TOOL_UNAVAILABLE_REASONS","SIDE_LABELS","setEnabled","button","enabled","setTitle","reason","title","Toolbar","onClick","sep","placeholder","side","option","preset","isAnyUnavailable","isDevelopment","Playmaker","stage","mode","method","ui"],"sources":["../src/common/base/lifecycle.ts","../src/common/geometry/grid.ts","../src/common/model/guards.ts","../src/common/model/player.ts","../src/common/design/metrics.ts","../src/common/editing/editor.ts","../src/common/base/event.ts","../src/common/commands/command-service.ts","../src/common/commands/undo-redo-service.ts","../src/common/presets/shared.ts","../src/common/formations/formation.ts","../src/common/model/id-factory.ts","../src/common/model/line.ts","../src/common/model/play-data.ts","../src/common/model/migration-v2.ts","../src/common/model/migration.ts","../src/common/model/play-model.ts","../src/common/commands/command.ts","../src/common/commands/field-commands.ts","../src/common/commands/formation-commands.ts","../src/common/commands/patch.ts","../src/common/commands/line-commands.ts","../src/common/commands/player-commands.ts","../src/common/geometry/field.ts","../src/common/geometry/polyline.ts","../src/common/geometry/bezier.ts","../src/common/geometry/hit-test.ts","../src/common/editing/editor-notifier.ts","../src/common/editing/interaction.ts","../src/common/editing/preview.ts","../src/common/editing/editor-controller.ts","../src/common/editing/play-session.ts","../src/common/export/image-export.ts","../src/common/presets/alignments.ts","../src/common/formations/presets.ts","../src/common/geometry/line-decoration.ts","../src/common/geometry/player-marker.ts","../src/common/input/keymap.ts","../src/common/plays/presets.ts","../src/browser/input/pointer-input.ts","../src/assets/playmaker-saira-subset.woff2","../src/browser/theme/field-font.ts","../src/browser/theme/field-font-face.ts","../src/browser/theme/css-color.ts","../src/browser/theme/tokens.ts","../src/browser/theme/theme-reader.ts","../src/browser/rendering/field-renderer.ts","../src/browser/rendering/grid-renderer.ts","../src/browser/rendering/line-renderer.ts","../src/browser/rendering/overlay-renderer.ts","../src/browser/rendering/player-renderer.ts","../src/browser/rendering/layer.ts","../src/browser/rendering/canvas-surface.ts","../src/browser/ui/focus.ts","../src/browser/theme/palette.ts","../src/browser/ui/property-panel.ts","../src/browser/ui/toolbar.ts","../src/playmaker.ts"],"sourcesContent":["export interface IDisposable {\n dispose(): void;\n}\n\nexport function toDisposable(fn: () => void): IDisposable {\n return { dispose: fn };\n}\n\n/** まとめて解放する。解放したあとに add したものは、その場で解放する。 */\nexport class DisposableStore implements IDisposable {\n private readonly items = new Set<IDisposable>();\n private disposed = false;\n\n /** 非同期の処理が終わったとき、破棄したあとなら何もしないための判定に使える。 */\n get isDisposed(): boolean {\n return this.disposed;\n }\n\n add<T extends IDisposable>(item: T): T {\n if (this.disposed) {\n item.dispose();\n return item;\n }\n this.items.add(item);\n return item;\n }\n\n dispose(): void {\n if (this.disposed) {\n return;\n }\n this.disposed = true;\n for (const item of this.items) {\n item.dispose();\n }\n this.items.clear();\n }\n}\n\n/** `_register` に渡したものを、dispose のときに一緒に解放する。 */\nexport abstract class Disposable implements IDisposable {\n protected readonly _store = new DisposableStore();\n\n protected get isDisposed(): boolean {\n return this._store.isDisposed;\n }\n\n protected _register<T extends IDisposable>(item: T): T {\n return this._store.add(item);\n }\n\n dispose(): void {\n this._store.dispose();\n }\n}\n","import type { FieldPosition } from \"../model/player.js\";\n\n/**\n * 位置を置ける格子の刻み(ヤード)。横はサイドライン、縦は LOS を原点にする。\n * 図の中の位置はすべてこの格子点にあるので、要素同士を揃える操作が無くても縦横が揃う。\n */\nexport const GRID_STEP_YARDS = 0.5;\n\nfunction snapYard(yard: number): number {\n // -0.2 を丸めると -0 になり、Object.is で比べる toEqual が 0 と区別するので 0 に寄せる。\n return Math.round(yard / GRID_STEP_YARDS) * GRID_STEP_YARDS + 0;\n}\n\n/** 位置を最も近い格子点へ寄せる。読み込んだ値と、ドラッグやクリックで決めた値の両方に使う。 */\nexport function snapToGrid(position: FieldPosition): FieldPosition {\n return {\n lateralYard: snapYard(position.lateralYard),\n downfieldYard: snapYard(position.downfieldYard),\n };\n}\n","export function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nexport function isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\n/** 空白だけの文字列も空とみなす。 */\nexport function isNonEmptyString(value: unknown): value is string {\n return typeof value === \"string\" && value.trim() !== \"\";\n}\n\nexport function isOneOf<const T extends string>(value: unknown, values: readonly T[]): value is T {\n return values.some((candidate) => candidate === value);\n}\n\n/**\n * 配列の先頭 `max` 個だけを読み、`parse` が null を返した要素は捨てる。\n * 復元できない要素も読んだ数に入れるので、どんな入力でも読むのは `max` 個までで済む。\n */\nexport function parseBoundedArray<T>(\n raw: unknown,\n max: number,\n parse: (entry: unknown, index: number) => T | null,\n): T[] {\n if (!Array.isArray(raw)) {\n return [];\n }\n const parsed: T[] = [];\n const end = Math.min(raw.length, max);\n for (let index = 0; index < end; index += 1) {\n const value = parse(raw[index], index);\n if (value !== null) {\n parsed.push(value);\n }\n }\n return parsed;\n}\n","import { snapToGrid } from \"../geometry/grid.js\";\nimport {\n isFiniteNumber,\n isNonEmptyString,\n isOneOf,\n isRecord,\n parseBoundedArray,\n} from \"./guards.js\";\n\n/**\n * 選手マーカーの形状。種類が多いと図が散らかるので、丸と四角の 2 種だけにする。\n * どちらも外接円を当たり判定にできるので、hit-test は形状で分けない。\n */\nexport const PLAYER_SHAPE_VALUES = [\"circle\", \"square\"] as const;\n\nexport type PlayerShape = (typeof PLAYER_SHAPE_VALUES)[number];\n\n/** 形状を指定しないときの既定。 */\nexport const DEFAULT_PLAYER_SHAPE: PlayerShape = \"circle\";\n\n/**\n * 選手マーカーの塗り。枠線だけ(`outline`)か、色で塗りつぶす(`solid`)か。\n * 形状とは独立に持ち、攻守や役割の見分けに使う。パネルはこの順にスウォッチを並べる。\n */\nexport const PLAYER_FILL_VALUES = [\"outline\", \"solid\"] as const;\n\nexport type PlayerFill = (typeof PLAYER_FILL_VALUES)[number];\n\n/** 塗りを指定しないときの既定。黒板に描く図と同じく、枠線だけにする。 */\nexport const DEFAULT_PLAYER_FILL: PlayerFill = \"outline\";\n\n/**\n * 外から受け取る選手の上限。実際のプレー図は 22 人ほどなので、この上限に届くことは無い。\n * 壊れたデータや悪意のあるデータで描画が止まらないように、超えた分は正規化で捨てる。\n */\nexport const MAX_PLAYERS = 64;\n\n/**\n * 選手マーカーの半径(ヤード)。描く大きさと当たり判定の半径に同じ値を使う。\n * フィールドは縦横を同じ縮尺で描くので、ヤードでの円がそのまま画面上の円になる。\n */\nexport const PLAYER_RADIUS_YARDS = 0.93;\n\n/**\n * フィールド上の位置(ヤード)。縦は LOS(`field.losYard`)からの距離で持つので、\n * ゾーンを切り替えて LOS が動いても、図は形を保ったまま一緒に動く。\n * - lateralYard: 0 = 左サイドライン … FIELD_WIDTH_YARDS = 右サイドライン\n * - downfieldYard: 0 = LOS。正が攻撃方向(画面の上)、負がバックフィールド\n *\n * どちらも GRID_STEP_YARDS の倍数で、モデルの中に格子の外の位置は無い。\n */\nexport interface FieldPosition {\n readonly lateralYard: number;\n readonly downfieldYard: number;\n}\n\n/**\n * 1 人の選手。`color` は CSS の色の文字列で、省くとテーマの色で描く。\n * `fill` を省くと DEFAULT_PLAYER_FILL で描く。\n */\nexport interface Player {\n readonly id: string;\n readonly position: FieldPosition;\n readonly shape: PlayerShape;\n readonly label: string;\n readonly color?: string;\n readonly fill?: PlayerFill;\n}\n\nfunction isPlayerShape(value: unknown): value is PlayerShape {\n return isOneOf(value, PLAYER_SHAPE_VALUES);\n}\n\nfunction isPlayerFill(value: unknown): value is PlayerFill {\n return isOneOf(value, PLAYER_FILL_VALUES);\n}\n\n/**\n * 座標が有限な数でなければ復元できないので null を返す。返す位置は入力と共有しない。\n * 値は格子点へ寄せる。外から来た位置もドラッグで決めた位置と同じ格子に乗せ、図の中に格子の外の位置を作らない。\n */\nexport function parseFieldPosition(raw: unknown): FieldPosition | null {\n if (!isRecord(raw)) {\n return null;\n }\n const { lateralYard, downfieldYard } = raw;\n if (!isFiniteNumber(lateralYard) || !isFiniteNumber(downfieldYard)) {\n return null;\n }\n return snapToGrid({ lateralYard, downfieldYard });\n}\n\n/**\n * 外から受け取った 1 要素を Player に正規化する。位置が座標でないものは null を返して捨てる。\n * 形状、ラベル、色、塗りが欠けていても捨てずに既定で補う。古い版で保存したデータを読めなくしないため。\n */\nfunction normalizePlayer(raw: unknown, index: number): Player | null {\n if (!isRecord(raw)) {\n return null;\n }\n const position = parseFieldPosition(raw.position);\n if (position === null) {\n return null;\n }\n\n // id が無ければ配列の中の位置から決まる id を振り、同じデータを何度読んでも同じ id になるようにする。\n const id = isNonEmptyString(raw.id) ? raw.id : `p${index}`;\n return {\n id,\n position,\n shape: isPlayerShape(raw.shape) ? raw.shape : DEFAULT_PLAYER_SHAPE,\n label: typeof raw.label === \"string\" ? raw.label : \"\",\n // exactOptionalPropertyTypes では undefined を入れられないので、色と塗りがあるときだけキーを置く。\n ...(isNonEmptyString(raw.color) ? { color: raw.color } : {}),\n ...(isPlayerFill(raw.fill) ? { fill: raw.fill } : {}),\n };\n}\n\n/**\n * 外から受け取った players を Player[] に正規化する。配列でなければ空配列を返す。\n * 先頭の MAX_PLAYERS 個より後ろの要素は読まずに捨てる。\n */\nexport function normalizePlayers(raw: unknown): Player[] {\n return parseBoundedArray(raw, MAX_PLAYERS, normalizePlayer);\n}\n\n/** 位置まで複製し、元の選手と参照を共有しない。 */\nexport function clonePlayer(player: Player): Player {\n return {\n id: player.id,\n position: { ...player.position },\n shape: player.shape,\n label: player.label,\n ...(player.color === undefined ? {} : { color: player.color }),\n ...(player.fill === undefined ? {} : { fill: player.fill }),\n };\n}\n","// 寸法は px で決めず、フィールドの幅 W と 1 ヤードの px U からの比で出す。\n// フィールドの白線、ハッシュ、数字は本物の寸法の比に合わせる。\n// 選手とプレーの線は見やすさを優先して本物より大きく描き、選手マーカーの直径 D からの比で揃える。\n\nimport { PLAYER_RADIUS_YARDS } from \"../model/player.js\";\n\n// 小さく描いたときにラインが消えないよう、1 px は残す。\nconst MIN_LINE_PX = 1;\n// 本物のラインの幅 4 インチを、フィールドの幅 160 フィートで割った値。\nconst YARD_LINE_WIDTH_PER_W = 0.0021;\n// 本物のハッシュの長さ 24 インチ。\nconst HASH_TICK_LENGTH_PER_U = 0.375;\n// 本物の数字の高さは 6 フィート(2 ヤード)だが、小さく描いたときにも読めるよう少し大きくする。\nconst NUMBER_HEIGHT_PER_U = 2.4;\nconst NUMBER_MIN_PX = 10;\n// センターのヤードラインは、ほかのヤードラインより少し太くして目印にする。\nconst MIDFIELD_LINE_WIDTH_PER_YARD_LINE = 1.5;\n// エンドゾーンの隅のパイロン。本物は 4 インチ角だが、小さく描いても見えるよう少し大きくする。\nconst PYLON_SIZE_PER_U = 0.45;\nconst PYLON_MIN_PX = 3;\n// ゴールポストは真上から見た形で、横木とフィールドへ伸びる 2 本の柱だけを描く。横木の半分は本物の 18.5 フィートの半分。\nconst GOALPOST_CROSSBAR_HALF_PER_U = 1.85;\nconst GOALPOST_UPRIGHT_LENGTH_PER_U = 1.2;\nconst GOALPOST_STROKE_PER_D = 0.2;\nconst GOALPOST_STROKE_MIN_PX = 2;\n\n// 2 文字のラベルがマーカーの内側に収まる大きさ。\nconst MARKER_LABEL_PER_D = 0.5;\nconst MARKER_LABEL_MIN_PX = 8;\nconst ROUTE_WIDTH_PER_D = 0.11;\nconst ROUTE_WIDTH_MIN_PX = 1.5;\nconst BLOCK_CAP_LENGTH_PER_D = 0.4;\n// 矢じりの底辺を線の幅の 4 倍ほどにし、線の先の棘ではなく矢印に見せる。先端の角はおよそ 37 度。\nconst ARROW_LENGTH_PER_D = 0.72;\nconst ARROW_HALF_WIDTH_PER_D = 0.24;\nconst MOTION_DASH_ON_PER_U = 1.1;\nconst MOTION_DASH_OFF_PER_U = 0.7;\n// 編集中に敷く格子の点。目印になればよいので、ハッシュより細く、消えない最小の大きさは残す。\nconst GRID_DOT_RADIUS_PER_U = 0.08;\nconst GRID_DOT_RADIUS_MIN_PX = 0.75;\n\n/** 描くときの寸法(px)。 */\nexport interface FieldMetrics {\n readonly yardLineWidth: number;\n /** ゴールラインと、サイドラインを含む窓の外枠の太さ。 */\n readonly goalLineWidth: number;\n /** センター(50 ヤード)のヤードラインの太さ。 */\n readonly midfieldLineWidth: number;\n readonly hashTickLength: number;\n readonly numberHeight: number;\n /** エンドゾーンの隅に置くパイロンの一辺。 */\n readonly pylonSize: number;\n readonly goalpostCrossbarHalfLength: number;\n readonly goalpostUprightLength: number;\n readonly goalpostStroke: number;\n /** 選手マーカーの直径 D。選手とプレーの線の寸法はこの値からの比で決める。 */\n readonly tokenDiameter: number;\n readonly markerStroke: number;\n readonly markerLabelFont: number;\n readonly routeWidth: number;\n readonly blockWidth: number;\n readonly blockCapLength: number;\n readonly arrowLength: number;\n readonly arrowHalfWidth: number;\n /** motion の破線の [描く長さ, 空ける長さ]。 */\n readonly motionDash: readonly [number, number];\n /** 編集中に敷く格子の点の半径。 */\n readonly gridDotRadius: number;\n}\n\n/** 大きさ 0 のビューポートでも NaN を返さない。 */\nexport function computeFieldMetrics(fieldPixelWidth: number, unitPx: number): FieldMetrics {\n const w = Math.max(0, fieldPixelWidth);\n const u = Math.max(0, unitPx);\n const yardLineWidth = Math.max(MIN_LINE_PX, YARD_LINE_WIDTH_PER_W * w);\n const d = 2 * PLAYER_RADIUS_YARDS * u;\n const routeWidth = Math.max(ROUTE_WIDTH_MIN_PX, ROUTE_WIDTH_PER_D * d);\n return {\n yardLineWidth,\n goalLineWidth: 2 * yardLineWidth,\n midfieldLineWidth: MIDFIELD_LINE_WIDTH_PER_YARD_LINE * yardLineWidth,\n hashTickLength: HASH_TICK_LENGTH_PER_U * u,\n numberHeight: Math.max(NUMBER_MIN_PX, NUMBER_HEIGHT_PER_U * u),\n pylonSize: Math.max(PYLON_MIN_PX, PYLON_SIZE_PER_U * u),\n goalpostCrossbarHalfLength: GOALPOST_CROSSBAR_HALF_PER_U * u,\n goalpostUprightLength: GOALPOST_UPRIGHT_LENGTH_PER_U * u,\n goalpostStroke: Math.max(GOALPOST_STROKE_MIN_PX, GOALPOST_STROKE_PER_D * d),\n tokenDiameter: d,\n // 枠線だけの選手は縁取りが見た目のすべてなので、プレーの線と同じ太さで描く。\n markerStroke: routeWidth,\n markerLabelFont: Math.max(MARKER_LABEL_MIN_PX, MARKER_LABEL_PER_D * d),\n routeWidth,\n blockWidth: routeWidth,\n blockCapLength: BLOCK_CAP_LENGTH_PER_D * d,\n arrowLength: ARROW_LENGTH_PER_D * d,\n arrowHalfWidth: ARROW_HALF_WIDTH_PER_D * d,\n motionDash: [MOTION_DASH_ON_PER_U * u, MOTION_DASH_OFF_PER_U * u],\n gridDotRadius: Math.max(GRID_DOT_RADIUS_MIN_PX, GRID_DOT_RADIUS_PER_U * u),\n };\n}\n","import type { Event } from \"../base/event.js\";\nimport type { LinePatch } from \"../commands/line-commands.js\";\nimport type { PlayerPatch } from \"../commands/player-commands.js\";\nimport type { Formation } from \"../formations/formation.js\";\nimport type { Line } from \"../model/line.js\";\nimport type { FieldZone, PlayData } from \"../model/play-data.js\";\nimport type { FieldPosition, Player } from \"../model/player.js\";\n\nexport const EDITOR_TOOL_VALUES = [\"select\", \"add-player\", \"draw-line\"] as const;\n\nexport type EditorTool = (typeof EDITOR_TOOL_VALUES)[number];\n\n/**\n * 選択は id の希望であり、対象が消えても解除しない。読み取るときに実在を確かめる。\n * 何も選んでいないことは、EditorOverlay と同じく `kind: \"none\"` で表す。\n */\nexport type EditorSelection =\n | { readonly kind: \"player\"; readonly id: string }\n | { readonly kind: \"line\"; readonly id: string }\n | { readonly kind: \"none\" };\n\nexport const NO_SELECTION: EditorSelection = { kind: \"none\" };\n\nexport function isSameSelection(a: EditorSelection, b: EditorSelection): boolean {\n if (a.kind === \"none\" || b.kind === \"none\") {\n return a.kind === b.kind;\n }\n return a.kind === b.kind && a.id === b.id;\n}\n\n/** 件数の上限に達していて、そのツールで何も置けないときは false。 */\nexport function isToolAvailable(tool: EditorTool, state: EditorViewState): boolean {\n switch (tool) {\n case \"add-player\":\n return state.remainingPlayerSlots > 0;\n case \"draw-line\":\n return state.canStartLine;\n case \"select\":\n return true;\n }\n}\n\n/** 読み込むと選手の上限を超えるフォーメーションは、1 人も置かれないので false。 */\nexport function canLoadFormation(formation: Formation, state: EditorViewState): boolean {\n return formation.players.length <= state.remainingPlayerSlots;\n}\n\n/** 描画するプレー図。版は保存するときだけ要るので持たない。 */\nexport type SceneData = Omit<PlayData, \"version\">;\n\n/** 選択の強調とハンドルを描く位置(ヤード空間)。 */\nexport type EditorOverlay =\n | { readonly kind: \"none\" }\n | { readonly kind: \"player\"; readonly playerId: string }\n | {\n readonly kind: \"line\";\n readonly waypointHandles: readonly FieldPosition[];\n readonly endpointHandle: FieldPosition;\n };\n\nexport interface EditorViewState {\n readonly tool: EditorTool;\n readonly selection: EditorSelection;\n readonly canUndo: boolean;\n readonly canRedo: boolean;\n readonly fieldZone: FieldZone;\n /** 線を作図中(確定か取り消し待ち)か。 */\n readonly isDrawing: boolean;\n /** あと何人の選手を置けるか。これより多い人数を置く操作は何もしない。 */\n readonly remainingPlayerSlots: number;\n /** 線の本数が上限に達しておらず、新しい線を描き始められるか。 */\n readonly canStartLine: boolean;\n}\n\n/** オーバーレイは、scene と同じ途中の状態から求める。 */\nexport interface EditorFrame {\n /** 確定済みのプレー図に、ドラッグや作図の途中の状態を重ねたもの。 */\n readonly scene: SceneData;\n readonly overlay: EditorOverlay;\n}\n\n/** 描画と UI の同期に使う読み取り面。 */\nexport interface IEditorScene {\n /** getFrame の結果が変わったかもしれないときに、1 つの操作につき 1 回発火する。 */\n readonly onDidChangeScene: Event<void>;\n /**\n * getViewState か、選択中の選手や線の値が変わったときだけ発火する。\n * ドラッグ中の移動のように、描く図だけが変わる操作では発火しない。\n */\n readonly onDidChangeViewState: Event<void>;\n getViewState(): EditorViewState;\n /** 選手を選択していないか、対象が消えていれば undefined。 */\n getSelectedPlayer(): Player | undefined;\n /** 線を選択していないか、対象が消えていれば undefined。 */\n getSelectedLine(): Line | undefined;\n getFrame(): EditorFrame;\n}\n\n/** ポインタの操作(ヤード空間)。 */\nexport interface IEditorGestures {\n pointerDown(pos: FieldPosition): void;\n pointerMove(pos: FieldPosition): void;\n pointerUp(pos: FieldPosition): void;\n}\n\n/** ツールバー、パネル、キー操作から呼ぶ編集。 */\nexport interface IEditorActions {\n setTool(tool: EditorTool): void;\n commitLine(): void;\n cancelInteraction(): void;\n deleteSelection(): void;\n updateSelectedPlayer(patch: PlayerPatch): void;\n updateSelectedLine(patch: LinePatch): void;\n setFieldZone(zone: FieldZone): void;\n /**\n * 選手を既存の図に追記し、置いたら true を返す。\n * 置ける選手が無いときと、置くと上限を超えるときは何もせず false を返す。\n */\n loadFormation(formation: Formation): boolean;\n /** 作図中は最後の打点を取り消し、履歴には触れない。 */\n undo(): void;\n redo(): void;\n}\n\n/** ツールバーやパネルのように、表示を読んで編集を呼ぶ UI が使う面。 */\nexport type IEditorUi = IEditorActions & IEditorScene;\n\nexport interface IEditorController extends IEditorScene, IEditorGestures, IEditorActions {}\n","import { type IDisposable, toDisposable } from \"./lifecycle.js\";\n\n// common は ECMAScript の lib だけで型検査するので、ホストが持つ console には型がない。\n// どのホスト(ブラウザ、Node)にもある console.error だけを、このモジュールの中で宣言して使う。\ndeclare const console: { error(...data: unknown[]): void };\n\n/** リスナを登録し、購読をやめるための IDisposable を返す。 */\nexport type Event<T> = (listener: (e: T) => void) => IDisposable;\n\n/** リスナが throw しても、残りのリスナには通知する。 */\nexport class Emitter<T> implements IDisposable {\n private listeners = new Set<(e: T) => void>();\n private disposed = false;\n private readonly onListenerError: (err: unknown) => void;\n\n /**\n * リスナが投げた例外を受け取る。既定は console.error に出す。\n * 投げ直さないのは、1 つのリスナの失敗で、残りのリスナと fire を呼んだ側まで止めないため。\n */\n constructor(onListenerError: (err: unknown) => void = console.error) {\n this.onListenerError = onListenerError;\n }\n\n readonly event: Event<T> = (listener) => {\n if (this.disposed) {\n return toDisposable(() => {});\n }\n this.listeners.add(listener);\n return toDisposable(() => {\n this.listeners.delete(listener);\n });\n };\n\n fire(e: T): void {\n if (this.disposed) {\n return;\n }\n // 通知の途中でリスナが登録や解除をしても、この回に通知する相手は変えない。\n for (const listener of [...this.listeners]) {\n try {\n listener(e);\n } catch (err) {\n this.onListenerError(err);\n }\n }\n }\n\n dispose(): void {\n this.disposed = true;\n this.listeners.clear();\n }\n}\n","import type { IPlayModel } from \"../model/play-model.js\";\nimport type { ICommand } from \"./command.js\";\nimport type { IUndoRedoService } from \"./undo-redo-service.js\";\n\n/**\n * 編集はすべてここを通す。コマンドの適用、取り消し、やり直しを 1 か所で行い、\n * 履歴と Model を食い違わせない。\n */\nexport interface ICommandService {\n readonly canUndo: boolean;\n readonly canRedo: boolean;\n /**\n * コマンドを適用し、Model を変えたら履歴に積んで true を返す。何も変えなかったときは\n * 積まずに false を返す。適用が throw したときも積まない。\n */\n execute(command: ICommand): boolean;\n /** 取り消しが throw したら、履歴は動かさない。戻す対象が無ければ何もしない。 */\n undo(): void;\n /** やり直しが throw したら、履歴は動かさない。やり直す対象が無ければ何もしない。 */\n redo(): void;\n}\n\nexport class CommandService implements ICommandService {\n private readonly model: IPlayModel;\n private readonly history: IUndoRedoService;\n\n constructor(model: IPlayModel, history: IUndoRedoService) {\n this.model = model;\n this.history = history;\n }\n\n get canUndo(): boolean {\n return this.history.canUndo;\n }\n\n get canRedo(): boolean {\n return this.history.canRedo;\n }\n\n execute(command: ICommand): boolean {\n const changed = command.apply(this.model);\n if (changed) {\n this.history.push(command);\n }\n return changed;\n }\n\n undo(): void {\n this.history.undo((command) => command.undo(this.model));\n }\n\n redo(): void {\n this.history.redo((command) => command.apply(this.model));\n }\n}\n","import type { ICommand } from \"./command.js\";\n\n/**\n * 適用済みコマンドの履歴。Model を持たず、コマンドを実行するのは呼び出し側の役目。\n * 履歴は分岐させない。新しいコマンドを積むと redo の履歴は捨てる。\n */\nexport interface IUndoRedoService {\n readonly canUndo: boolean;\n readonly canRedo: boolean;\n /** 実行を済ませたコマンドを積む。 */\n push(command: ICommand): void;\n /**\n * 最後に積んだコマンドを revert に渡し、revert が戻ったら redo の側へ移す。\n * revert が throw したら履歴は動かさない。戻す対象が無ければ何もしない。\n */\n undo(revert: (command: ICommand) => void): void;\n /** undo の逆向き。reapply が throw したら履歴は動かさない。 */\n redo(reapply: (command: ICommand) => void): void;\n}\n\nexport class UndoRedoService implements IUndoRedoService {\n private readonly undoStack: ICommand[] = [];\n private readonly redoStack: ICommand[] = [];\n\n get canUndo(): boolean {\n return this.undoStack.length > 0;\n }\n\n get canRedo(): boolean {\n return this.redoStack.length > 0;\n }\n\n push(command: ICommand): void {\n this.undoStack.push(command);\n this.redoStack.length = 0;\n }\n\n undo(revert: (command: ICommand) => void): void {\n this.move(this.undoStack, this.redoStack, revert);\n }\n\n redo(reapply: (command: ICommand) => void): void {\n this.move(this.redoStack, this.undoStack, reapply);\n }\n\n // 実行が成功してから積み替える。先に取り出すと、実行が throw したときにコマンドが履歴から消える。\n private move(from: ICommand[], to: ICommand[], run: (command: ICommand) => void): void {\n const command = from.at(-1);\n if (command === undefined) {\n return;\n }\n run(command);\n from.pop();\n to.push(command);\n }\n}\n","import { isOneOf } from \"../model/guards.js\";\n\nexport const TEAM_SIDE_VALUES = [\"offense\", \"defense\"] as const;\n\nexport type TeamSide = (typeof TEAM_SIDE_VALUES)[number];\n\nexport function isTeamSide(value: unknown): value is TeamSide {\n return isOneOf(value, TEAM_SIDE_VALUES);\n}\n\n/**\n * 値とその中のオブジェクトをすべて凍結して返す。プリセットは全利用者が共有するので、\n * 1 人が書き換えると他の読み込み結果まで変わってしまう。\n */\nexport function deepFreeze<T>(value: T): T {\n if (typeof value === \"object\" && value !== null && !Object.isFrozen(value)) {\n Object.freeze(value);\n for (const child of Object.values(value)) {\n deepFreeze(child);\n }\n }\n return value;\n}\n","import { isNonEmptyString, isRecord } from \"../model/guards.js\";\nimport type { IIdFactory } from \"../model/id-factory.js\";\nimport { clonePlayer, normalizePlayers, type Player } from \"../model/player.js\";\nimport { isTeamSide, type TeamSide } from \"../presets/shared.js\";\n\n/**\n * 隊形の 1 人。`id` は持たず、読み込むたびに振る。同じ隊形を 2 回読んでも、\n * 図にいる選手とも Undo で戻る選手とも id がぶつからない。\n */\nexport type FormationPlayer = Omit<Player, \"id\">;\n\n/** 読み込むと、players を今の図に足す。プリセットのほかに、利用者が作った隊形も渡せる。 */\nexport interface Formation {\n readonly id: string;\n readonly name: string;\n /** 読み込んだときの選手の配置には影響しない。 */\n readonly side: TeamSide;\n /** 1 人以上。 */\n readonly players: readonly FormationPlayer[];\n}\n\n/** 省略できるキーの扱いを clonePlayer と揃え、選手に値が増えてもここを直さずに済ませる。 */\nexport function toFormationPlayer(player: Player): FormationPlayer {\n const { id: _id, ...template } = clonePlayer(player);\n return template;\n}\n\n/**\n * 外から受け取った隊形を Formation に正規化する。選手は図の選手と同じ規則で正規化し、\n * 置ける選手が 1 人もいなければ null を返す。id、name、side が欠けていても既定で補う。\n * 返り値は新しいオブジェクトで、入力と参照を共有しない。\n */\nexport function normalizeFormation(raw: unknown): Formation | null {\n if (!isRecord(raw)) {\n return null;\n }\n const players = normalizePlayers(raw.players).map(toFormationPlayer);\n if (players.length === 0) {\n return null;\n }\n return {\n id: isNonEmptyString(raw.id) ? raw.id : \"formation\",\n name: isNonEmptyString(raw.name) ? raw.name : \"フォーメーション\",\n side: isTeamSide(raw.side) ? raw.side : \"offense\",\n players,\n };\n}\n\n/**\n * 隊形の選手に id を振って Player にする。id は takenIds とも、同じ隊形のほかの選手とも重ならない。\n */\nexport function instantiateFormation(\n formation: Formation,\n ids: IIdFactory,\n takenIds: Iterable<string>,\n): Player[] {\n const taken = new Set(takenIds);\n return formation.players.map((template) => {\n const id = ids.next(\"player\", taken);\n taken.add(id);\n return { ...template, id };\n });\n}\n","export interface IIdFactory {\n /** `${prefix}-${n}` 形式で、taken に無い未使用 id を返す。 */\n next(prefix: string, taken: ReadonlySet<string>): string;\n}\n\n/**\n * prefix ごとのカウンタで id を払い出す。一度使った番号は、その id の要素が消えても使い直さない。\n * 消した要素を Undo で戻したとき、あとから足した要素と id がぶつからないようにするため。\n */\nexport class IdFactory implements IIdFactory {\n private readonly counters = new Map<string, number>();\n\n next(prefix: string, taken: ReadonlySet<string>): string {\n let n = this.counters.get(prefix) ?? 0;\n let id: string;\n do {\n n += 1;\n id = `${prefix}-${n}`;\n } while (taken.has(id));\n this.counters.set(prefix, n);\n return id;\n }\n}\n","import {\n isFiniteNumber,\n isNonEmptyString,\n isOneOf,\n isRecord,\n parseBoundedArray,\n} from \"./guards.js\";\nimport { type FieldPosition, type Player, parseFieldPosition } from \"./player.js\";\n\n/**\n * 線の種別。色ではなく終点の記法と線種で見分ける。\n * - `route`: レシーバーやランナーの走路。終点に矢印を描く\n * - `block`: ブロックの割り当て。route と同じ太さで、終点に T 字のバーを描く\n * - `motion`: スナップ前の選手の移動。破線で、終点に矢印を描く\n */\nexport const LINE_KIND_VALUES = [\"route\", \"block\", \"motion\"] as const;\n\nexport type LineKind = (typeof LINE_KIND_VALUES)[number];\n\n/**\n * 線の補間方法。どの種別の線にも効く。\n * - `straight`: 制御点を直線で結ぶ\n * - `bezier`: 制御点をすべて通る滑らかな曲線で結ぶ\n */\nexport const LINE_INTERPOLATION_VALUES = [\"straight\", \"bezier\"] as const;\n\nexport type LineInterpolation = (typeof LINE_INTERPOLATION_VALUES)[number];\n\n/** 種別を指定しないときの既定。 */\nexport const DEFAULT_LINE_KIND: LineKind = \"route\";\n\n/** 補間を指定しないときの既定。 */\nexport const DEFAULT_LINE_INTERPOLATION: LineInterpolation = \"straight\";\n\n/** 太さを指定しないときの倍率。種別ごとの既定の太さでそのまま描く。 */\nexport const DEFAULT_LINE_THICKNESS = 1;\n\n/**\n * 外から受け取る線と、1 本あたりの waypoint の上限。実際のプレー図は線 20 本ほどで、\n * waypoint も数個なので、この上限に届くことは無い。壊れたデータや悪意のあるデータで\n * 描画が止まらないように、超えた分は正規化で捨てる。\n */\nexport const MAX_LINES = 128;\nexport const MAX_WAYPOINTS_PER_LINE = 32;\n\n/**\n * 1 本の線。起点は座標ではなく選手の id で持つので、選手を動かすと線の起点も付いてくる。\n * `color` と `thickness` を省くと、テーマの色と種別ごとの既定の太さで描く。\n */\nexport interface Line {\n readonly id: string;\n readonly kind: LineKind;\n /** 起点となる選手の id。実在しない参照は復元時に除外される。 */\n readonly startPlayerId: string;\n /** 起点と終点の間の中継点(0 個可)。 */\n readonly waypoints: readonly FieldPosition[];\n /** 終点(ヤード空間)。 */\n readonly end: FieldPosition;\n readonly interpolation: LineInterpolation;\n /** CSS の色の文字列。 */\n readonly color?: string;\n /** 種別ごとの既定の太さに対する倍率。省くと DEFAULT_LINE_THICKNESS。 */\n readonly thickness?: number;\n}\n\nfunction isLineKind(value: unknown): value is LineKind {\n return isOneOf(value, LINE_KIND_VALUES);\n}\n\nfunction isLineInterpolation(value: unknown): value is LineInterpolation {\n return isOneOf(value, LINE_INTERPOLATION_VALUES);\n}\n\n/** 太さの倍率として受け付ける値か。0 以下では線が見えなくなるので受け付けない。 */\nexport function isLineThickness(value: unknown): value is number {\n return isFiniteNumber(value) && value > 0;\n}\n\n/**\n * 外から受け取った 1 要素を Line に正規化する。オブジェクトでないもの、起点の選手が実在しないもの、\n * 終点が座標でないものは null を返して捨てる。\n * 種別、補間、id が欠けていても捨てずに既定で補う。古い版で保存したデータを読めなくしないため。\n */\nfunction normalizeLine(\n raw: unknown,\n index: number,\n validPlayerIds: ReadonlySet<string>,\n): Line | null {\n if (!isRecord(raw)) {\n return null;\n }\n\n // 起点の選手が無い線は、描くことも掴むこともできないので捨てる。\n if (!isNonEmptyString(raw.startPlayerId) || !validPlayerIds.has(raw.startPlayerId)) {\n return null;\n }\n const end = parseFieldPosition(raw.end);\n if (end === null) {\n return null;\n }\n\n return {\n id: isNonEmptyString(raw.id) ? raw.id : `l${index}`,\n kind: isLineKind(raw.kind) ? raw.kind : DEFAULT_LINE_KIND,\n startPlayerId: raw.startPlayerId,\n // 数でない waypoint は個別に捨て、線自体は保持する。\n waypoints: parseBoundedArray(raw.waypoints, MAX_WAYPOINTS_PER_LINE, parseFieldPosition),\n end,\n interpolation: isLineInterpolation(raw.interpolation)\n ? raw.interpolation\n : DEFAULT_LINE_INTERPOLATION,\n // exactOptionalPropertyTypes では undefined を入れられないので、値があるときだけキーを置く。\n ...(isNonEmptyString(raw.color) ? { color: raw.color } : {}),\n ...(isLineThickness(raw.thickness) ? { thickness: raw.thickness } : {}),\n };\n}\n\n/**\n * 外から受け取った lines を Line[] に正規化する。配列でなければ空配列を返す。\n * `validPlayerIds` には正規化を済ませた選手の id を渡す。そこに無い選手を起点にする線は捨てる。\n * 先頭の MAX_LINES 個より後ろの要素は読まずに捨てる。\n */\nexport function normalizeLines(raw: unknown, validPlayerIds: ReadonlySet<string>): Line[] {\n return parseBoundedArray(raw, MAX_LINES, (entry, index) =>\n normalizeLine(entry, index, validPlayerIds),\n );\n}\n\n/** waypoints と各座標まで複製し、元の線と参照を共有しない。 */\nexport function cloneLine(line: Line): Line {\n return {\n id: line.id,\n kind: line.kind,\n startPlayerId: line.startPlayerId,\n waypoints: line.waypoints.map((p) => ({ ...p })),\n end: { ...line.end },\n interpolation: line.interpolation,\n ...(line.color === undefined ? {} : { color: line.color }),\n ...(line.thickness === undefined ? {} : { thickness: line.thickness }),\n };\n}\n\n/**\n * 線の制御点の列 [起点の選手の位置, ...waypoints, 終点] を組み立てる。\n * 起点の選手が見つからなければ undefined を返す。\n */\nexport function lineAnchorPoints(\n line: Line,\n playersById: ReadonlyMap<string, Player>,\n): FieldPosition[] | undefined {\n const start = playersById.get(line.startPlayerId);\n if (start === undefined) {\n return undefined;\n }\n return [{ ...start.position }, ...line.waypoints.map((p) => ({ ...p })), { ...line.end }];\n}\n\nexport function indexPlayersById(players: readonly Player[]): Map<string, Player> {\n const map = new Map<string, Player>();\n for (const player of players) {\n map.set(player.id, player);\n }\n return map;\n}\n","import { isOneOf, isRecord } from \"./guards.js\";\nimport { cloneLine, type Line, normalizeLines } from \"./line.js\";\nimport { clonePlayer, normalizePlayers, type Player } from \"./player.js\";\n\n/**\n * フィールドのどの範囲を映すか。\n * - `middle`: センター付近\n * - `redzone`: 相手のゴール側\n * - `own-redzone`: 自陣のゴール側\n */\nexport const FIELD_ZONE_VALUES = [\"own-redzone\", \"middle\", \"redzone\"] as const;\n\nexport type FieldZone = (typeof FIELD_ZONE_VALUES)[number];\n\n/** ゾーンを指定しないときの既定。LOS の位置を選ばない図が多いので中央にする。 */\nexport const DEFAULT_FIELD_ZONE: FieldZone = \"middle\";\n\nexport const FIELD_ZONE_LABELS = {\n \"own-redzone\": \"自陣RZ\",\n middle: \"中央\",\n redzone: \"相手RZ\",\n} as const satisfies Record<FieldZone, string>;\n\n/**\n * ゾーンごとの LOS の絶対ヤード(0 = 自ゴール、100 = 相手ゴール)。\n * 窓の中にバックフィールドとダウンフィールドの両方が収まる位置に置く。\n * - `middle`: センター\n * - `redzone`: 相手 15 ヤード\n * - `own-redzone`: 自陣 10 ヤード\n */\nexport const LOS_YARD_BY_ZONE = {\n \"own-redzone\": 10,\n middle: 50,\n redzone: 85,\n} as const satisfies Record<FieldZone, number>;\n\nexport interface FieldState {\n readonly zone: FieldZone;\n /**\n * LOS の絶対ヤード。今はゾーンから決まり、読み込んだデータの値は使わない。\n * 保存するデータから選手の絶対位置を復元できるよう、値としては持たせる。\n */\n readonly losYard: number;\n}\n\n/**\n * 今の PlayData のスキーマの版。スキーマを変えるときは 1 上げ、`PLAY_DATA_MIGRATIONS` に\n * 1 つ前の版から変換する段を足す。\n */\nexport const CURRENT_PLAY_DATA_VERSION = 2 as const;\n\n/**\n * プレー図のデータ。保存したものを `restorePlayData` に渡すと、古い版や版の無いもの、\n * 新しい版のものも今の版に寄せて読む。\n */\nexport interface PlayData {\n readonly version: typeof CURRENT_PLAY_DATA_VERSION;\n readonly field: FieldState;\n /** 後の要素ほど上に重ねて描く。 */\n readonly players: readonly Player[];\n /** 後の要素ほど上に重ねて描く。 */\n readonly lines: readonly Line[];\n}\n\n/**\n * 型付きで組み立てて読み込む図。LOS の位置は読み込むときにゾーンから決め直すので、\n * `field.losYard` は省略できる。\n */\nexport interface PlayDataInput extends Omit<PlayData, \"field\"> {\n readonly field: Omit<FieldState, \"losYard\"> & { readonly losYard?: number | undefined };\n}\n\nexport function isFieldZone(value: unknown): value is FieldZone {\n return isOneOf(value, FIELD_ZONE_VALUES);\n}\n\nexport function fieldStateForZone(zone: FieldZone): FieldState {\n return { zone, losYard: LOS_YARD_BY_ZONE[zone] };\n}\n\n/** field、選手、線まで複製し、元のデータと参照を共有しない。 */\nexport function clonePlayData(data: PlayData): PlayData {\n return {\n version: CURRENT_PLAY_DATA_VERSION,\n field: { ...data.field },\n players: data.players.map(clonePlayer),\n lines: data.lines.map(cloneLine),\n };\n}\n\n/**\n * 今の版の形をしている値を PlayData に正規化する。版を見て変換する段は通さないので、\n * 古い版のデータは `migratePlayData` に渡す。\n * 欠けた項目は既定で補い、読めない要素は捨てる。返り値は新しいオブジェクトで、入力と参照を共有しない。\n */\nexport function resolvePlayData(data: unknown): PlayData {\n const source: Record<string, unknown> = isRecord(data) ? data : {};\n const zone = isRecord(source.field) ? source.field.zone : undefined;\n // 線の起点参照を弾けるよう、先に選手を確定してから id 集合を渡す。\n // 重複した選手 id は後ろの方を振り直すので、その id を指す線は先頭の選手に付く。\n const players = makeIdsUnique(normalizePlayers(source.players));\n const validPlayerIds = new Set(players.map((p) => p.id));\n return {\n version: CURRENT_PLAY_DATA_VERSION,\n field: fieldStateForZone(isFieldZone(zone) ? zone : DEFAULT_FIELD_ZONE),\n players,\n lines: makeIdsUnique(normalizeLines(source.lines, validPlayerIds)),\n };\n}\n\n/**\n * 2 回目以降に現れた id を `${id}-2` のような未使用の id へ振り直す(先頭はそのまま)。\n * 同じ id が 2 つあると、hit-test は末尾を返すのに更新は先頭に当たり、別の要素が編集される。\n * 振り直した id は、入力にあるほかの id とも重ねない。\n */\nfunction makeIdsUnique<T extends { readonly id: string }>(items: readonly T[]): T[] {\n const taken = new Set(items.map((item) => item.id));\n const seen = new Set<string>();\n return items.map((item) => {\n if (!seen.has(item.id)) {\n seen.add(item.id);\n return item;\n }\n let n = 2;\n while (taken.has(`${item.id}-${n}`)) {\n n += 1;\n }\n const id = `${item.id}-${n}`;\n taken.add(id);\n seen.add(id);\n return { ...item, id };\n });\n}\n","import { isFiniteNumber, isRecord } from \"./guards.js\";\nimport { MAX_LINES, MAX_WAYPOINTS_PER_LINE } from \"./line.js\";\nimport { DEFAULT_FIELD_ZONE, fieldStateForZone, isFieldZone } from \"./play-data.js\";\nimport { MAX_PLAYERS } from \"./player.js\";\n\n/**\n * v1 の線の太さは CSS px だった。プロパティパネルは未指定の線を 2 px と表示していたので、\n * v2 ではその値を倍率 1 とみなして割り戻す。\n */\nexport const V1_DEFAULT_THICKNESS_PX = 2;\n\n/** 形が崩れた値はそのまま返し、捨てるかどうかは後の正規化に任せる。 */\nfunction toV2Position(raw: unknown, losYard: number): unknown {\n if (!isRecord(raw)) {\n return raw;\n }\n const { absoluteYard, ...rest } = raw;\n if (!isFiniteNumber(absoluteYard)) {\n return raw;\n }\n return { ...rest, downfieldYard: absoluteYard - losYard };\n}\n\nfunction toV2Player(raw: unknown, losYard: number): unknown {\n if (!isRecord(raw)) {\n return raw;\n }\n return { ...raw, position: toV2Position(raw.position, losYard) };\n}\n\nfunction toV2Line(raw: unknown, losYard: number): unknown {\n if (!isRecord(raw)) {\n return raw;\n }\n return {\n ...raw,\n waypoints: Array.isArray(raw.waypoints)\n ? raw.waypoints.slice(0, MAX_WAYPOINTS_PER_LINE).map((p) => toV2Position(p, losYard))\n : raw.waypoints,\n end: toV2Position(raw.end, losYard),\n thickness: isFiniteNumber(raw.thickness)\n ? raw.thickness / V1_DEFAULT_THICKNESS_PX\n : raw.thickness,\n };\n}\n\n/**\n * v1 は縦の位置を絶対ヤード(`absoluteYard`)で持っていた。v2 はゾーンの LOS からの距離\n * (`downfieldYard`)で持つので、v1 のゾーンの LOS を引いて、画面上の位置を変えずに移す。\n * 配列は正規化と同じく上限の個数までしか読まない。\n */\nexport function migrateV1ToV2(data: Readonly<Record<string, unknown>>): Record<string, unknown> {\n const zone =\n isRecord(data.field) && isFieldZone(data.field.zone) ? data.field.zone : DEFAULT_FIELD_ZONE;\n const field = fieldStateForZone(zone);\n const { losYard } = field;\n return {\n ...data,\n field,\n players: Array.isArray(data.players)\n ? data.players.slice(0, MAX_PLAYERS).map((p) => toV2Player(p, losYard))\n : data.players,\n lines: Array.isArray(data.lines)\n ? data.lines.slice(0, MAX_LINES).map((l) => toV2Line(l, losYard))\n : data.lines,\n };\n}\n","import { isFiniteNumber, isRecord } from \"./guards.js\";\nimport { migrateV1ToV2 } from \"./migration-v2.js\";\nimport { type PlayData, resolvePlayData } from \"./play-data.js\";\n\n/**\n * 古い版のデータを 1 つ上の版の形へ寄せる段。段を通したあとで resolvePlayData が形を整えるので、\n * 段は次の版で意味が変わる項目だけを変換すればよい。\n */\nexport interface PlayDataMigration {\n /** この段を通したあとの版。 */\n readonly to: number;\n migrate(data: Readonly<Record<string, unknown>>): Record<string, unknown>;\n}\n\n/** `to` の小さい順に並べる。 */\nexport const PLAY_DATA_MIGRATIONS: readonly PlayDataMigration[] = [\n { to: 2, migrate: migrateV1ToV2 },\n];\n\n/**\n * データに書かれた版を読む。有限の数でなければ 0 を返し、版を持たなかった最初期のデータとして\n * すべての段を通す。\n */\nexport function readDeclaredVersion(raw: unknown): number {\n if (isRecord(raw) && isFiniteNumber(raw.version)) {\n return raw.version;\n }\n return 0;\n}\n\n/**\n * 書かれた版より新しい段だけを、渡した順に通す。オブジェクトでない値は段を通さずにそのまま返す。\n * 最後の段より新しい版のデータも、段を通さずにそのまま返す。\n */\nexport function applyPlayDataMigrations(\n raw: unknown,\n declaredVersion: number,\n steps: readonly PlayDataMigration[],\n): unknown {\n if (!isRecord(raw)) {\n return raw;\n }\n let acc = raw;\n for (const step of steps) {\n if (step.to > declaredVersion) {\n acc = step.migrate(acc);\n }\n }\n return acc;\n}\n\n/**\n * どの版で保存したデータでも、今の版の PlayData にする。壊れたデータを渡しても投げない。\n * 返り値は新しいオブジェクトで、入力と参照を共有しない。\n * 選手、線、waypoint は MAX_PLAYERS、MAX_LINES、MAX_WAYPOINTS_PER_LINE の個数までしか読まない。\n */\nexport function migratePlayData(raw: unknown): PlayData {\n const declared = readDeclaredVersion(raw);\n const migrated = applyPlayDataMigrations(raw, declared, PLAY_DATA_MIGRATIONS);\n // 新しい版のデータも、resolvePlayData が version を今の版に書き換える。\n return resolvePlayData(migrated);\n}\n","import { Emitter, type Event } from \"../base/event.js\";\nimport { Disposable } from \"../base/lifecycle.js\";\nimport { type Line, MAX_LINES, MAX_WAYPOINTS_PER_LINE } from \"./line.js\";\nimport { migratePlayData } from \"./migration.js\";\nimport { clonePlayData, type FieldZone, fieldStateForZone, type PlayData } from \"./play-data.js\";\nimport { MAX_PLAYERS, type Player } from \"./player.js\";\n\n/**\n * 選手 1 人の削除を戻すのに要る値。選手と一緒に消えた線を元の添字付きで持ち、\n * 戻すときに同じ並びへ差し込む。\n */\nexport interface PlayerRemoval {\n readonly player: Player;\n readonly index: number;\n readonly removedLines: readonly LineRemoval[];\n}\n\n/** 線 1 本の削除を戻すのに要る値。 */\nexport interface LineRemoval {\n readonly line: Line;\n readonly index: number;\n}\n\n/**\n * プレー図の状態。実装は、起点の選手が消えた線を残さない。\n * 削除と差し替えは、戻すのに要る変更前の値を返す。\n */\nexport interface IPlayModel {\n /** いずれかの変更後に、getSnapshot と同じ値で 1 回発火する。 */\n readonly onDidChange: Event<PlayData>;\n /** 現在状態の深いコピー。呼ぶたびに図全体を複製する。 */\n getData(): PlayData;\n /**\n * 現在状態をコピーせずに返す。状態は変更のたびに新しいオブジェクトへ差し替えるので、\n * 受け取った値は後の変更で書き換わらない。\n */\n getSnapshot(): PlayData;\n getFieldZone(): FieldZone;\n /** 無ければ undefined。getSnapshot と同じく内部の値をそのまま返す。 */\n findPlayer(id: string): Player | undefined;\n /** 無ければ undefined。getSnapshot と同じく内部の値をそのまま返す。 */\n findLine(id: string): Line | undefined;\n /** findPlayer と同じだが、無い id なら throw する。 */\n getPlayer(id: string): Player;\n /** findLine と同じだが、無い id なら throw する。 */\n getLine(id: string): Line;\n /** LOS もゾーンの既定の位置へ移す。選手と線は LOS からの位置なので、図ごと一緒に動く。 */\n setFieldZone(zone: FieldZone): void;\n /**\n * 既にある id の選手を渡すと throw する。\n * 選手が MAX_PLAYERS 人を超える追加も throw する。\n */\n addPlayer(player: Player): void;\n /**\n * 何人足しても onDidChange は最後に 1 回だけ発火する。\n * 既存と重複する id があるか、MAX_PLAYERS 人を超えるときは、1 人も足さずに throw する。\n */\n addPlayers(players: readonly Player[]): void;\n /** 起点がその選手の線も一緒に消す。 */\n removePlayer(id: string): PlayerRemoval;\n /**\n * 起点が消える選手の線も一緒に消し、onDidChange は最後に 1 回だけ発火する。\n * 無い id か重複した id があれば、1 人も消さずに throw する。\n */\n removePlayers(ids: readonly string[]): PlayerRemoval[];\n /**\n * removePlayer で消した選手と線を、元の並びへ戻す。\n * 同じ id の選手が既にあるか、戻すと上限を超えるか、添字が今の並びの外を指すときは throw する。\n */\n restorePlayer(removal: PlayerRemoval): void;\n /** 同じ id の選手を差し替え、差し替える前の選手を返す。 */\n updatePlayer(player: Player): Player;\n /**\n * 既にある id の線を渡すと throw する。線が MAX_LINES 本を超えるときと、\n * waypoint が MAX_WAYPOINTS_PER_LINE 個を超える線も throw する。\n */\n addLine(line: Line): void;\n /** index は 0 から線の本数までで渡し、外れると throw する。ほかは addLine と同じ条件で throw する。 */\n insertLine(line: Line, index: number): void;\n removeLine(id: string): LineRemoval;\n /** 同じ id の線を差し替え、差し替える前の線を返す。waypoint が MAX_WAYPOINTS_PER_LINE 個を超えると throw する。 */\n updateLine(line: Line): Line;\n}\n\n// 削除の記録に無い添字で差し込むと、slice が黙って端へ寄せ、Undo で並びが崩れたことに気づけない。\nfunction insertAt<T>(items: readonly T[], index: number, item: T, what: string): T[] {\n if (!Number.isInteger(index) || index < 0 || index > items.length) {\n throw new Error(`PlayModel: ${what} index out of range: ${index} (0..${items.length})`);\n }\n return [...items.slice(0, index), item, ...items.slice(index)];\n}\n\n// 選択と編集は id で対象を決めるので、同じ id の要素を 2 つ持たせない。\nfunction assertNewId(items: readonly { id: string }[], id: string, message: string): void {\n if (items.some((item) => item.id === id)) {\n throw new Error(`${message} \"${id}\"`);\n }\n}\n\n// 件数の上限は外部データの正規化と同じ値にする。編集で超えられると、\n// getData で書き出した図を読み戻したときに黙って切り詰められる。\nfunction assertWithinLimit(count: number, limit: number, what: string): void {\n if (count > limit) {\n throw new Error(`PlayModel: too many ${what}: ${count} > ${limit}`);\n }\n}\n\nfunction assertWithinLimits(data: PlayData): void {\n assertWithinLimit(data.players.length, MAX_PLAYERS, \"players\");\n assertWithinLimit(data.lines.length, MAX_LINES, \"lines\");\n for (const line of data.lines) {\n assertWithinLimit(line.waypoints.length, MAX_WAYPOINTS_PER_LINE, \"waypoints\");\n }\n}\n\n/**\n * 変更系メソッドは、状態を新しいオブジェクトへ差し替えてから onDidChange を 1 回だけ発火する。\n * 入力は複製せずに取り込む。型が読み取り専用なので、入力も状態もあとから書き換えられない。\n * 無い id を指す操作は、編集の組み立て違いなのでその場で throw する。\n */\nexport class PlayModel extends Disposable implements IPlayModel {\n private readonly _onDidChange = this._register(new Emitter<PlayData>());\n readonly onDidChange = this._onDidChange.event;\n private state: PlayData;\n\n constructor(initialData?: unknown) {\n super();\n this.state = migratePlayData(initialData);\n }\n\n getData(): PlayData {\n return clonePlayData(this.state);\n }\n\n getSnapshot(): PlayData {\n return this.state;\n }\n\n getFieldZone(): FieldZone {\n return this.state.field.zone;\n }\n\n findPlayer(id: string): Player | undefined {\n return this.state.players.find((p) => p.id === id);\n }\n\n findLine(id: string): Line | undefined {\n return this.state.lines.find((l) => l.id === id);\n }\n\n getPlayer(id: string): Player {\n const player = this.findPlayer(id);\n if (player === undefined) {\n throw new Error(`PlayModel: unknown player id \"${id}\"`);\n }\n return player;\n }\n\n getLine(id: string): Line {\n const line = this.findLine(id);\n if (line === undefined) {\n throw new Error(`PlayModel: unknown line id \"${id}\"`);\n }\n return line;\n }\n\n setFieldZone(zone: FieldZone): void {\n // 同じゾーンでも発火する。変わらない操作を履歴に積まないのは編集の側で決める。\n this.commit({ ...this.state, field: fieldStateForZone(zone) });\n }\n\n addPlayer(player: Player): void {\n this.addPlayers([player]);\n }\n\n addPlayers(players: readonly Player[]): void {\n // 1 人でも重複があれば何も足さずに throw する。途中まで足してから投げると、\n // 通知も履歴も伴わない変更が残る。\n const taken = new Set(this.state.players.map((p) => p.id));\n for (const player of players) {\n if (taken.has(player.id)) {\n throw new Error(`PlayModel.addPlayers: duplicate player id \"${player.id}\"`);\n }\n taken.add(player.id);\n }\n this.commit({ ...this.state, players: [...this.state.players, ...players] });\n }\n\n private removePlayerCore(id: string): PlayerRemoval {\n const target = this.state.players.find((p) => p.id === id);\n if (target === undefined) {\n throw new Error(`PlayModel.removePlayer: unknown player id \"${id}\"`);\n }\n const index = this.state.players.indexOf(target);\n const removedLines: LineRemoval[] = [];\n const lines: Line[] = [];\n this.state.lines.forEach((line, i) => {\n if (line.startPlayerId === id) {\n // 起点を失う線は描けないので一緒に消し、戻すときのために添字を控える。\n removedLines.push({ line, index: i });\n } else {\n lines.push(line);\n }\n });\n // 削除では上限を超えないので commit を通さない。通知は呼び出し側がまとめて 1 回出す。\n this.state = {\n ...this.state,\n players: this.state.players.filter((p) => p !== target),\n lines,\n };\n return { player: target, index, removedLines };\n }\n\n removePlayer(id: string): PlayerRemoval {\n const removal = this.removePlayerCore(id);\n this.emitChange();\n return removal;\n }\n\n removePlayers(ids: readonly string[]): PlayerRemoval[] {\n // 1 人でも消せない id があれば何も消さずに throw する。途中まで消してから投げると、\n // 通知も履歴も伴わない変更が残る。\n const remaining = new Set(this.state.players.map((p) => p.id));\n for (const id of ids) {\n if (!remaining.delete(id)) {\n throw new Error(`PlayModel.removePlayers: unknown or repeated player id \"${id}\"`);\n }\n }\n const removals = ids.map((id) => this.removePlayerCore(id));\n this.emitChange();\n return removals;\n }\n\n restorePlayer(removal: PlayerRemoval): void {\n assertNewId(\n this.state.players,\n removal.player.id,\n \"PlayModel.restorePlayer: duplicate player id\",\n );\n const players = insertAt(this.state.players, removal.index, removal.player, \"player\");\n // 元の添字の小さい順に差し込むと、消す前の並びに戻る。\n let lines = this.state.lines;\n for (const { line, index } of [...removal.removedLines].sort((a, b) => a.index - b.index)) {\n lines = insertAt(lines, index, line, \"line\");\n }\n this.commit({ ...this.state, players, lines });\n }\n\n updatePlayer(player: Player): Player {\n const prev = this.getPlayer(player.id);\n this.commit({\n ...this.state,\n players: this.state.players.map((p) => (p === prev ? player : p)),\n });\n return prev;\n }\n\n addLine(line: Line): void {\n this.insertLine(line, this.state.lines.length);\n }\n\n insertLine(line: Line, index: number): void {\n assertNewId(this.state.lines, line.id, \"PlayModel: duplicate line id\");\n this.commit({ ...this.state, lines: insertAt(this.state.lines, index, line, \"line\") });\n }\n\n removeLine(id: string): LineRemoval {\n const target = this.state.lines.find((l) => l.id === id);\n if (target === undefined) {\n throw new Error(`PlayModel.removeLine: unknown line id \"${id}\"`);\n }\n const index = this.state.lines.indexOf(target);\n this.commit({ ...this.state, lines: this.state.lines.filter((l) => l !== target) });\n return { line: target, index };\n }\n\n updateLine(line: Line): Line {\n const prev = this.getLine(line.id);\n this.commit({\n ...this.state,\n lines: this.state.lines.map((l) => (l === prev ? line : l)),\n });\n return prev;\n }\n\n // 件数が増えうる変更はすべてここを通し、上限を超える状態を持たない。\n private commit(next: PlayData): void {\n assertWithinLimits(next);\n this.state = next;\n this.emitChange();\n }\n\n private emitChange(): void {\n this._onDidChange.fire(this.state);\n }\n}\n","import type { IPlayModel } from \"../model/play-model.js\";\n\n/**\n * 編集操作 1 つ。redo は apply をもう一度呼んで表す。\n * 取り消しに要る直前の状態は、apply のたびに各コマンドが自分で控える。\n */\nexport interface ICommand {\n /** 履歴の表示に使う日本語のラベル。 */\n readonly label: string;\n /**\n * Model を変えたら true を返す。何も変えないときは Model に触れずに false を返し、\n * 履歴に空の段を積ませない。\n */\n apply(model: IPlayModel): boolean;\n undo(model: IPlayModel): void;\n}\n\n/** apply で控えた値を undo で取り出す。apply より前に undo されたら throw する。 */\nexport function requireApplied<T>(value: T | undefined, command: ICommand): T {\n /* v8 ignore start -- 履歴は apply が済んだコマンドしか積まないので、編集の操作からは届かない。 */\n if (value === undefined) {\n throw new Error(`${command.label}: apply より前に undo された`);\n }\n /* v8 ignore stop */\n return value;\n}\n","import type { FieldZone } from \"../model/play-data.js\";\nimport type { IPlayModel } from \"../model/play-model.js\";\nimport { type ICommand, requireApplied } from \"./command.js\";\n\nexport class SetFieldZoneCommand implements ICommand {\n readonly label = \"フィールドゾーンの切替\";\n private readonly zone: FieldZone;\n private previous: FieldZone | undefined;\n\n constructor(zone: FieldZone) {\n this.zone = zone;\n }\n\n apply(model: IPlayModel): boolean {\n this.previous = model.getFieldZone();\n if (this.previous === this.zone) {\n return false;\n }\n model.setFieldZone(this.zone);\n return true;\n }\n\n undo(model: IPlayModel): void {\n model.setFieldZone(requireApplied(this.previous, this));\n }\n}\n","import type { IPlayModel } from \"../model/play-model.js\";\nimport type { Player } from \"../model/player.js\";\nimport type { ICommand } from \"./command.js\";\n\n/**\n * 採番済みの選手をまとめて追加する。既にある選手と線は残すので、攻撃と守備の隊形を順に重ねられる。\n * Model への変更は 1 回にまとめ、通知も 1 回だけにする。\n */\nexport class LoadFormationCommand implements ICommand {\n readonly label = \"フォーメーションの読み込み\";\n private readonly players: readonly Player[];\n\n constructor(players: readonly Player[]) {\n this.players = players;\n }\n\n apply(model: IPlayModel): boolean {\n if (this.players.length === 0) {\n return false;\n }\n model.addPlayers(this.players);\n return true;\n }\n\n undo(model: IPlayModel): void {\n // 追加した選手を起点にした線は、それより後のコマンドなので先に取り消されている。\n model.removePlayers(this.players.map((p) => p.id));\n }\n}\n","type OptionalKeys<T> = {\n [K in keyof T]-?: Record<never, never> extends Pick<T, K> ? K : never;\n}[keyof T];\n\n/**\n * 指定したキーだけを差し替えるパッチ。指定しないキーは今の値を保つ。\n * 省略できるキーだけは null を指定でき、値を消して既定に戻す。\n */\nexport type Patch<T> = {\n readonly [K in keyof T]?: K extends OptionalKeys<T> ? T[K] | null : T[K];\n};\n\n// Line や Player はインターフェースなので添字シグネチャを持たず、そのままではキーを文字列で引けない。\n// パッチの規則をキーの一覧に依らず 1 か所に書くため、この 2 関数の中だけ見方を変える。\nfunction asRecord(value: object): Readonly<Record<string, unknown>> {\n return value as Record<string, unknown>;\n}\n\n/** current にパッチを当てた新しいオブジェクトを返す。current は書き換えない。 */\nexport function applyPatch<T extends object>(current: T, patch: Patch<T>): T {\n const next = { ...asRecord(current) };\n for (const [key, value] of Object.entries(patch)) {\n if (value === null) {\n delete next[key];\n } else {\n next[key] = value;\n }\n }\n // パッチの値は Patch<T> で T の各キーの型に揃っているので、当てた結果も T になる。\n return next as T;\n}\n\n/** パッチを当てると、current から何か 1 つでも値が変わるか。オブジェクトの値は参照で比べる。 */\nexport function patchChangesAnything<T extends object>(current: T, patch: Patch<T>): boolean {\n const values = asRecord(current);\n return Object.entries(patch).some(([key, value]) => (value ?? undefined) !== values[key]);\n}\n","import type { Line } from \"../model/line.js\";\nimport type { IPlayModel, LineRemoval } from \"../model/play-model.js\";\nimport { type ICommand, requireApplied } from \"./command.js\";\nimport { applyPatch, type Patch, patchChangesAnything } from \"./patch.js\";\n\n/** id と起点の選手は線を見分ける鍵なので、パッチでは変えない。 */\nexport type LinePatch = Patch<Omit<Line, \"id\" | \"startPlayerId\">>;\n\nexport function applyLinePatch(current: Line, patch: LinePatch): Line {\n return applyPatch<Line>(current, patch);\n}\n\nexport class AddLineCommand implements ICommand {\n readonly label = \"線の追加\";\n private readonly line: Line;\n\n constructor(line: Line) {\n this.line = line;\n }\n\n apply(model: IPlayModel): boolean {\n model.addLine(this.line);\n return true;\n }\n\n undo(model: IPlayModel): void {\n model.removeLine(this.line.id);\n }\n}\n\n/** undo は線を元の並びの位置へ戻す。 */\nexport class RemoveLineCommand implements ICommand {\n readonly label = \"線の削除\";\n private readonly lineId: string;\n private removal: LineRemoval | undefined;\n\n constructor(lineId: string) {\n this.lineId = lineId;\n }\n\n apply(model: IPlayModel): boolean {\n this.removal = model.removeLine(this.lineId);\n return true;\n }\n\n undo(model: IPlayModel): void {\n const { line, index } = requireApplied(this.removal, this);\n model.insertLine(line, index);\n }\n}\n\n/** 種別、補間、waypoint、終点、色、太さをまとめて編集する。 */\nexport class UpdateLineCommand implements ICommand {\n readonly label = \"線の編集\";\n private readonly lineId: string;\n private readonly patch: LinePatch;\n private previous: Line | undefined;\n\n constructor(lineId: string, patch: LinePatch) {\n this.lineId = lineId;\n this.patch = { ...patch };\n }\n\n apply(model: IPlayModel): boolean {\n const current = model.getLine(this.lineId);\n if (!patchChangesAnything(current, this.patch)) {\n return false;\n }\n this.previous = model.updateLine(applyLinePatch(current, this.patch));\n return true;\n }\n\n undo(model: IPlayModel): void {\n model.updateLine(requireApplied(this.previous, this));\n }\n}\n","import type { IPlayModel, PlayerRemoval } from \"../model/play-model.js\";\nimport type { Player } from \"../model/player.js\";\nimport { type ICommand, requireApplied } from \"./command.js\";\nimport { applyPatch, type Patch, patchChangesAnything } from \"./patch.js\";\n\n/** id は選手を見分ける鍵なので、パッチでは変えない。 */\nexport type PlayerPatch = Patch<Omit<Player, \"id\">>;\n\nexport function applyPlayerPatch(current: Player, patch: PlayerPatch): Player {\n return applyPatch<Player>(current, patch);\n}\n\nexport class AddPlayerCommand implements ICommand {\n readonly label = \"選手の追加\";\n private readonly player: Player;\n\n constructor(player: Player) {\n this.player = player;\n }\n\n apply(model: IPlayModel): boolean {\n model.addPlayer(this.player);\n return true;\n }\n\n undo(model: IPlayModel): void {\n // 追加した直後の選手を起点にした線は、それより後のコマンドなので先に取り消されている。\n // 削除で控える従属線は空なので捨てる。\n model.removePlayer(this.player.id);\n }\n}\n\n/** 起点がその選手の線も一緒に消す。undo は選手と線を元の並びの位置へ戻す。 */\nexport class RemovePlayerCommand implements ICommand {\n readonly label = \"選手の削除\";\n private readonly playerId: string;\n private removal: PlayerRemoval | undefined;\n\n constructor(playerId: string) {\n this.playerId = playerId;\n }\n\n apply(model: IPlayModel): boolean {\n this.removal = model.removePlayer(this.playerId);\n return true;\n }\n\n undo(model: IPlayModel): void {\n model.restorePlayer(requireApplied(this.removal, this));\n }\n}\n\n/** 位置、ラベル、形状、色、塗りをまとめて編集する。 */\nexport class UpdatePlayerCommand implements ICommand {\n readonly label = \"選手の編集\";\n private readonly playerId: string;\n private readonly patch: PlayerPatch;\n private previous: Player | undefined;\n\n constructor(playerId: string, patch: PlayerPatch) {\n this.playerId = playerId;\n this.patch = { ...patch };\n }\n\n apply(model: IPlayModel): boolean {\n const current = model.getPlayer(this.playerId);\n if (!patchChangesAnything(current, this.patch)) {\n return false;\n }\n this.previous = model.updatePlayer(applyPlayerPatch(current, this.patch));\n return true;\n }\n\n undo(model: IPlayModel): void {\n model.updatePlayer(requireApplied(this.previous, this));\n }\n}\n","import type { FieldState, FieldZone } from \"../model/play-data.js\";\nimport type { FieldPosition } from \"../model/player.js\";\n\n/**\n * サイドラインの間の幅。規定は 160 フィート(53⅓ ヤード)だが、中央(26.5)が\n * 0.5 ヤードの格子点に乗るように 53 ヤードへ丸める。本物の寸法との差は 1 フィートで、\n * 図の見た目には出ない。\n */\nexport const FIELD_WIDTH_YARDS = 53;\n\n/**\n * middle ゾーンで映す縦の長さ。レッドゾーンの窓は、ヤード数字が端で見切れないよう\n * これより深い。窓ごとの長さは zoneWindowLength で得る。\n */\nexport const ZONE_WINDOW_LENGTH_YARDS = 30;\n\n/**\n * リーグごとの、フィールドの中央からハッシュマークまでの距離(ヤード)。\n * 左右のハッシュの間隔は NCAA が 40 フィート、NFL が 18.5 フィート、NFHS が 53⅓ フィート。\n * 選手をハッシュの上に置けるように、格子点(0.5 ヤード刻み)に丸めてある。\n * 利用者がリーグを選ぶ API は無く、DEFAULT_FIELD_LEAGUE で描く。\n */\nexport const HASH_CENTER_OFFSET_YARDS_BY_LEAGUE = {\n ncaa: 6.5,\n nfl: 3,\n nfhs: 9,\n} as const;\n\nexport type FieldLeague = keyof typeof HASH_CENTER_OFFSET_YARDS_BY_LEAGUE;\n\n/** 日本のフィールドは NCAA のハッシュの間隔で引かれていることが多い。 */\nexport const DEFAULT_FIELD_LEAGUE: FieldLeague = \"ncaa\";\n\n/**\n * レッドゾーンの窓に映す、ゴールラインから手前への奥行き。本来のレッドゾーン(20 ヤード)より\n * 広いのは、20 ヤードラインが窓の端に乗って数字が見切れるのを避けるため。\n */\nexport const RED_ZONE_DEPTH_YARDS = 25;\n\n/** ヤードラインの間隔。描くのは browser だが、格子の点をラインの上に置かないために共有する。 */\nexport const YARD_LINE_INTERVAL_YARDS = 5;\n\n/** エンドゾーンの奥行き。絶対ヤードは自陣のエンドラインの -10 から相手のエンドラインの 110 まで取る。 */\nexport const END_ZONE_DEPTH_YARDS = 10;\n\nexport interface YardWindow {\n /** 窓の手前側(画面下、攻撃方向の後方)の絶対ヤード。 */\n readonly startYard: number;\n /** 窓の奥側(画面上、攻撃方向の前方)の絶対ヤード。 */\n readonly endYard: number;\n}\n\n/**\n * ゾーンで映す絶対ヤードの範囲。絶対ヤードは自陣のゴールラインを 0、相手のゴールラインを 100 とし、\n * 大きいほど攻撃方向(画面の上)になる。レッドゾーンの窓はエンドゾーンまで映す。\n */\nexport function fieldZoneWindow(zone: FieldZone): YardWindow {\n switch (zone) {\n case \"own-redzone\":\n return { startYard: -END_ZONE_DEPTH_YARDS, endYard: RED_ZONE_DEPTH_YARDS };\n case \"redzone\":\n return { startYard: 100 - RED_ZONE_DEPTH_YARDS, endYard: 100 + END_ZONE_DEPTH_YARDS };\n case \"middle\": {\n const half = ZONE_WINDOW_LENGTH_YARDS / 2;\n return { startYard: 50 - half, endYard: 50 + half };\n }\n }\n}\n\nexport function zoneWindowLength(zone: FieldZone): number {\n const { startYard, endYard } = fieldZoneWindow(zone);\n return endYard - startYard;\n}\n\n/** ゾーンの窓の幅と縦の長さの比。レッドゾーンの窓は middle より縦に長い。 */\nexport function fieldWindowAspect(zone: FieldZone): number {\n return FIELD_WIDTH_YARDS / zoneWindowLength(zone);\n}\n\n/**\n * 位置をゾーン窓の中(左右はサイドライン間、縦は窓の端から端)へ寄せる。\n * 画面の外で離したドラッグや余白へのクリックで、見えない位置に選手や点を置かないためのもの。\n */\nexport function clampToZoneWindow(position: FieldPosition, field: FieldState): FieldPosition {\n const { startYard, endYard } = fieldZoneWindow(field.zone);\n return {\n lateralYard: Math.min(Math.max(position.lateralYard, 0), FIELD_WIDTH_YARDS),\n downfieldYard: Math.min(\n Math.max(position.downfieldYard, startYard - field.losYard),\n endYard - field.losYard,\n ),\n };\n}\n\n/**\n * 絶対ヤードに対応する、フィールドに書く番号(1..50)。両ゴールから数える(…40、50、40…)。\n * ゴールラインとエンドゾーンには番号を書かないので null を返す。\n */\nexport function displayYardNumber(absoluteYard: number): number | null {\n if (absoluteYard <= 0 || absoluteYard >= 100) {\n return null;\n }\n return 50 - Math.abs(50 - absoluteYard);\n}\n\n/** ゾーンの窓の中にある、stepYards の倍数の絶対ヤードを小さい順に返す。 */\nexport function yardLinesInWindow(zone: FieldZone, stepYards: number): number[] {\n if (stepYards <= 0) {\n throw new Error(\"Playmaker: stepYards は正の数である必要があります。\");\n }\n const { startYard, endYard } = fieldZoneWindow(zone);\n const lines: number[] = [];\n // stepYards が整数でないと足し算を重ねた誤差が出るので、\n // 窓の奥の端にあるラインを落とさないよう少し余裕を持たせる。\n const first = Math.ceil(startYard / stepYards) * stepYards;\n for (let y = first; y <= endYard + 1e-9; y += stepYards) {\n lines.push(y);\n }\n return lines;\n}\n\nexport interface CanvasPoint {\n readonly x: number;\n readonly y: number;\n}\n\n/**\n * ゾーンの窓を縦横比を保ったままビューポートの中央に収め、ヤードと Canvas の px を変換する。\n * フィールドの線や番号は絶対ヤードで、選手と線は LOS からの位置(FieldPosition)で扱う。\n */\nexport class FieldGeometry {\n readonly viewportWidth: number;\n readonly viewportHeight: number;\n readonly zone: FieldZone;\n /** LOS の絶対ヤード。FieldPosition の downfieldYard はここからの距離。 */\n readonly losYard: number;\n readonly yardWindow: YardWindow;\n /** 1 ヤードあたりの px。縦横で同じ値。 */\n readonly scale: number;\n readonly fieldPixelWidth: number;\n readonly fieldPixelHeight: number;\n /** フィールドの左上の Canvas 座標。縦横比が合わない分の余白になる。 */\n readonly offsetX: number;\n readonly offsetY: number;\n\n constructor(viewportWidth: number, viewportHeight: number, field: FieldState) {\n this.viewportWidth = viewportWidth;\n this.viewportHeight = viewportHeight;\n this.zone = field.zone;\n this.losYard = field.losYard;\n this.yardWindow = fieldZoneWindow(field.zone);\n const windowLength = this.yardWindow.endYard - this.yardWindow.startYard;\n const w = Math.max(0, viewportWidth);\n const h = Math.max(0, viewportHeight);\n this.scale = Math.min(w / FIELD_WIDTH_YARDS, h / windowLength);\n this.fieldPixelWidth = FIELD_WIDTH_YARDS * this.scale;\n this.fieldPixelHeight = windowLength * this.scale;\n this.offsetX = (w - this.fieldPixelWidth) / 2;\n this.offsetY = (h - this.fieldPixelHeight) / 2;\n }\n\n xForLateralYard(lateralYard: number): number {\n return this.offsetX + lateralYard * this.scale;\n }\n\n yForAbsoluteYard(absoluteYard: number): number {\n return this.offsetY + (this.yardWindow.endYard - absoluteYard) * this.scale;\n }\n\n toCanvas(position: FieldPosition): CanvasPoint {\n return {\n x: this.xForLateralYard(position.lateralYard),\n y: this.yForAbsoluteYard(this.losYard + position.downfieldYard),\n };\n }\n\n // 大きさ 0 のビューポートでは scale が 0 で割れないので、フィールドの左上の位置を返して NaN を出さない。\n lateralYardForX(x: number): number {\n return this.scale > 0 ? (x - this.offsetX) / this.scale : 0;\n }\n\n absoluteYardForY(y: number): number {\n return this.scale > 0\n ? this.yardWindow.endYard - (y - this.offsetY) / this.scale\n : this.yardWindow.endYard;\n }\n\n fromCanvas(point: CanvasPoint): FieldPosition {\n return {\n lateralYard: this.lateralYardForX(point.x),\n downfieldYard: this.absoluteYardForY(point.y) - this.losYard,\n };\n }\n\n /** 端も含む。 */\n containsYard(absoluteYard: number): boolean {\n return absoluteYard >= this.yardWindow.startYard && absoluteYard <= this.yardWindow.endYard;\n }\n}\n","import type { CanvasPoint } from \"./field.js\";\n\n/** 隣り合う 2 点の組を先頭から順に返す。2 点未満なら何も返さない。 */\nexport function* segments<T>(points: readonly T[]): Generator<readonly [T, T]> {\n // 前の点を箱に入れて持つ。T が undefined を含んでも「前の点が無い」と区別できる。\n let previous: { readonly point: T } | undefined;\n for (const point of points) {\n if (previous !== undefined) {\n yield [previous.point, point];\n }\n previous = { point };\n }\n}\n\n/** 隣接点間の距離を足し上げた全長。2 点未満なら 0。 */\nexport function polylineLength(path: readonly CanvasPoint[]): number {\n let total = 0;\n for (const [a, b] of segments(path)) {\n total += Math.hypot(b.x - a.x, b.y - a.y);\n }\n return total;\n}\n\n/**\n * 終点から折れ線に沿って distance だけ戻った点で終わる、新しい折れ線を返す。\n * 最後の区間だけで戻らないのは、細かく刻んだ曲線では 1 区間が distance より短いため。\n * maxFraction は削る長さの上限で、全長に対する割合で渡す。既定の 1 では上限が無く、\n * distance が全長以上なら始点 1 点だけを返す。\n */\nexport function trimPolylineEnd(\n path: readonly CanvasPoint[],\n distance: number,\n maxFraction = 1,\n): CanvasPoint[] {\n if (path.length < 2 || distance <= 0) {\n return [...path];\n }\n let remaining =\n maxFraction >= 1 ? distance : Math.min(distance, polylineLength(path) * maxFraction);\n if (remaining <= 0) {\n return [...path];\n }\n\n // 矢じりの長さは全長よりずっと短く、たいてい終点側の数区間で止まるので、配列を複製せずに遡る。\n for (let i = path.length - 1; i > 0; i--) {\n const a = path[i - 1];\n const b = path[i];\n /* v8 ignore start -- i は 1 から path.length - 1 までなので、a も b も範囲の内側にある。 */\n if (a === undefined || b === undefined) {\n break;\n }\n /* v8 ignore stop */\n const segLen = Math.hypot(b.x - a.x, b.y - a.y);\n // 等号で切ると a と同じ座標を足し、長さ 0 の区間が末尾に残る(丸キャップが点を描く)。\n if (segLen > remaining) {\n const t = (segLen - remaining) / segLen;\n return [...path.slice(0, i), { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t }];\n }\n remaining -= segLen;\n }\n return path.slice(0, 1);\n}\n","import type { LineInterpolation } from \"../model/line.js\";\nimport type { FieldPosition } from \"../model/player.js\";\nimport { segments } from \"./polyline.js\";\n\n/** ベジェの 1 区間を何分割するか。プレー図の大きさでは、これで角が見えない。 */\nexport const DEFAULT_BEZIER_SAMPLES_PER_SEGMENT = 16;\n\n/** p0 から p1 へ、制御点 c1 と c2 で曲げた 3 次ベジェの、t(0 以上 1 以下)での位置。 */\nexport function cubicBezierPoint(\n p0: FieldPosition,\n c1: FieldPosition,\n c2: FieldPosition,\n p1: FieldPosition,\n t: number,\n): FieldPosition {\n const u = 1 - t;\n const a = u * u * u;\n const b = 3 * u * u * t;\n const c = 3 * u * t * t;\n const d = t * t * t;\n return {\n lateralYard: a * p0.lateralYard + b * c1.lateralYard + c * c2.lateralYard + d * p1.lateralYard,\n downfieldYard:\n a * p0.downfieldYard + b * c1.downfieldYard + c * c2.downfieldYard + d * p1.downfieldYard,\n };\n}\n\n/**\n * p1 から p2 への区間を、前後の点 p0 と p3 から決まる向きで通す 3 次ベジェの制御点 [c1, c2]。\n * 一様な Catmull-Rom 曲線と同じ形になる。端の区間では、無い側の点に端の点そのものを渡す。\n * waypoint をそのままベジェの制御点にしないのは、曲線が waypoint を通らなくなるため。\n */\nexport function catmullRomBezierControls(\n p0: FieldPosition,\n p1: FieldPosition,\n p2: FieldPosition,\n p3: FieldPosition,\n): [FieldPosition, FieldPosition] {\n return [\n {\n lateralYard: p1.lateralYard + (p2.lateralYard - p0.lateralYard) / 6,\n downfieldYard: p1.downfieldYard + (p2.downfieldYard - p0.downfieldYard) / 6,\n },\n {\n lateralYard: p2.lateralYard - (p3.lateralYard - p1.lateralYard) / 6,\n downfieldYard: p2.downfieldYard - (p3.downfieldYard - p1.downfieldYard) / 6,\n },\n ];\n}\n\n/** 同じ座標が続くと向きが 0 になり曲線が崩れるので、1 つに畳む。 */\nfunction dedupeConsecutive(points: readonly FieldPosition[]): FieldPosition[] {\n const out: FieldPosition[] = [];\n for (const p of points) {\n const last = out[out.length - 1];\n if (\n last === undefined ||\n last.lateralYard !== p.lateralYard ||\n last.downfieldYard !== p.downfieldYard\n ) {\n out.push({ lateralYard: p.lateralYard, downfieldYard: p.downfieldYard });\n }\n }\n return out;\n}\n\n/**\n * 制御点の列を、描くときと当たり判定に使う折れ線にする。`straight` と、同じ座標を畳んで\n * 2 点以下になる列は、制御点をそのまま結ぶ。返り値は新しい配列。samplesPerSegment は 1 以上に丸める。\n */\nexport function sampleLinePath(\n points: readonly FieldPosition[],\n interpolation: LineInterpolation,\n samplesPerSegment: number = DEFAULT_BEZIER_SAMPLES_PER_SEGMENT,\n): FieldPosition[] {\n const pts = dedupeConsecutive(points);\n if (interpolation === \"straight\" || pts.length < 3) {\n return pts;\n }\n const steps = Math.max(1, Math.floor(samplesPerSegment));\n\n const result: FieldPosition[] = pts.slice(0, 1);\n for (const [i, [p1, p2]] of [...segments(pts)].entries()) {\n const p0 = pts[i - 1] ?? p1;\n const p3 = pts[i + 2] ?? p2;\n const [c1, c2] = catmullRomBezierControls(p0, p1, p2, p3);\n // t=0 の点は前の区間の終点と同じなので、t は 0 を除いて 1 まで刻む。\n for (let s = 1; s <= steps; s++) {\n result.push(cubicBezierPoint(p1, c1, c2, p2, s / steps));\n }\n }\n return result;\n}\n","import { indexPlayersById, type Line, lineAnchorPoints } from \"../model/line.js\";\nimport type { FieldPosition, Player } from \"../model/player.js\";\nimport { PLAYER_RADIUS_YARDS } from \"../model/player.js\";\nimport { sampleLinePath } from \"./bezier.js\";\nimport { segments } from \"./polyline.js\";\n\n/**\n * target に重なる選手のうち、いちばん上に描いたものを返す。後の要素ほど上に描くので末尾から探す。\n * 四角の選手も外接円で当てる。形ごとに当たりを変えるほどの差が無いため。\n */\nexport function hitTestPlayer(\n players: readonly Player[],\n target: FieldPosition,\n radiusYards: number = PLAYER_RADIUS_YARDS,\n): Player | undefined {\n if (radiusYards <= 0) {\n throw new Error(\"Playmaker: radiusYards は正の数である必要があります。\");\n }\n const r2 = radiusYards * radiusYards;\n for (const player of [...players].reverse()) {\n const dx = player.position.lateralYard - target.lateralYard;\n const dy = player.position.downfieldYard - target.downfieldYard;\n if (dx * dx + dy * dy <= r2) {\n return player;\n }\n }\n return undefined;\n}\n\n/**\n * 線に当たったとみなす距離(ヤード)。線の太さでは細すぎて掴めないので、太さとは別に持つ。\n * 選手の半径より小さくし、選手の近くを押したときに線を掴みにくくしている。\n */\nexport const LINE_HIT_TOLERANCE_YARDS = 0.6;\n\nexport function distanceToSegment(p: FieldPosition, a: FieldPosition, b: FieldPosition): number {\n const abx = b.lateralYard - a.lateralYard;\n const aby = b.downfieldYard - a.downfieldYard;\n const apx = p.lateralYard - a.lateralYard;\n const apy = p.downfieldYard - a.downfieldYard;\n const lenSq = abx * abx + aby * aby;\n // a と b が同じ点なら、a までの距離にする。\n const t = lenSq > 0 ? Math.max(0, Math.min(1, (apx * abx + apy * aby) / lenSq)) : 0;\n const dx = apx - t * abx;\n const dy = apy - t * aby;\n return Math.sqrt(dx * dx + dy * dy);\n}\n\n/** 点が 0 個なら +Infinity。 */\nfunction distanceToPolyline(p: FieldPosition, points: readonly FieldPosition[]): number {\n const only = points.length === 1 ? points[0] : undefined;\n if (only !== undefined) {\n return pointDistance(p, only);\n }\n let min = Number.POSITIVE_INFINITY;\n for (const [a, b] of segments(points)) {\n min = Math.min(min, distanceToSegment(p, a, b));\n }\n return min;\n}\n\n/**\n * target に重なる線のうち、いちばん上に描いたものを返す。描くときと同じ折れ線への距離で測るので、\n * 曲線も見えている形のとおりに当たる。起点の選手が無い線は描かれないので、当てない。\n */\nexport function hitTestLine(\n lines: readonly Line[],\n players: readonly Player[],\n target: FieldPosition,\n toleranceYards: number = LINE_HIT_TOLERANCE_YARDS,\n): Line | undefined {\n if (toleranceYards <= 0) {\n throw new Error(\"Playmaker: toleranceYards は正の数である必要があります。\");\n }\n const byId = indexPlayersById(players);\n for (const line of [...lines].reverse()) {\n const anchors = lineAnchorPoints(line, byId);\n if (anchors === undefined) {\n continue;\n }\n const polyline = sampleLinePath(anchors, line.interpolation);\n if (distanceToPolyline(target, polyline) <= toleranceYards) {\n return line;\n }\n }\n return undefined;\n}\n\n/** 選択中の線の waypoint と終点のハンドルを掴める半径(ヤード)。 */\nexport const WAYPOINT_HANDLE_RADIUS_YARDS = 0.9;\n\nexport function pointDistance(a: FieldPosition, b: FieldPosition): number {\n return Math.hypot(a.lateralYard - b.lateralYard, a.downfieldYard - b.downfieldYard);\n}\n\n/** 線のハンドルに当たったときの、掴んだハンドルとその位置。 */\nexport type LineHandleHit =\n | { readonly kind: \"endpoint\"; readonly point: FieldPosition }\n | { readonly kind: \"waypoint\"; readonly index: number; readonly point: FieldPosition };\n\n/**\n * target に当たる線のハンドルを返す。終点を waypoint より先に当て、先端を動かしたい操作を\n * 最後の waypoint に奪われないようにする。waypoint は後ろほど手前に描くので、末尾から探す。\n */\nexport function hitLineHandle(\n line: Pick<Line, \"waypoints\" | \"end\">,\n target: FieldPosition,\n): LineHandleHit | undefined {\n const within = (point: FieldPosition) =>\n pointDistance(target, point) <= WAYPOINT_HANDLE_RADIUS_YARDS;\n if (within(line.end)) {\n return { kind: \"endpoint\", point: line.end };\n }\n for (const [index, point] of [...line.waypoints.entries()].reverse()) {\n if (within(point)) {\n return { kind: \"waypoint\", index, point };\n }\n }\n return undefined;\n}\n","import { Emitter } from \"../base/event.js\";\nimport { Disposable } from \"../base/lifecycle.js\";\nimport type { Line } from \"../model/line.js\";\nimport type { Player } from \"../model/player.js\";\nimport { type EditorViewState, isSameSelection } from \"./editor.js\";\n\n/** 表示状態の通知は、この値の組が前回の通知(まだ通知していなければ構築時)と違うときだけ出す。 */\ninterface ViewSnapshot {\n readonly state: EditorViewState;\n readonly player: Player | undefined;\n readonly line: Line | undefined;\n}\n\n// 表示状態の項目ごとの比べ方。項目を足すと、比べ方を書くまでここが型エラーになる。\nconst VIEW_STATE_EQUALS: {\n readonly [K in keyof EditorViewState]: (a: EditorViewState[K], b: EditorViewState[K]) => boolean;\n} = {\n tool: Object.is,\n selection: isSameSelection,\n canUndo: Object.is,\n canRedo: Object.is,\n fieldZone: Object.is,\n isDrawing: Object.is,\n remainingPlayerSlots: Object.is,\n canStartLine: Object.is,\n};\n\nconst VIEW_STATE_KEYS = Object.keys(VIEW_STATE_EQUALS) as (keyof EditorViewState)[];\n\nfunction isSameEntry<K extends keyof EditorViewState>(\n key: K,\n a: EditorViewState,\n b: EditorViewState,\n): boolean {\n return VIEW_STATE_EQUALS[key](a[key], b[key]);\n}\n\n// 選手と線は変更のたびに差し替わるので、参照で比べれば値の変化が分かる。\nfunction isSameView(a: ViewSnapshot, b: ViewSnapshot): boolean {\n return (\n VIEW_STATE_KEYS.every((key) => isSameEntry(key, a.state, b.state)) &&\n a.player === b.player &&\n a.line === b.line\n );\n}\n\n/**\n * 描く図と表示状態の通知を出し分ける。batch の中で何度変わっても、通知は\n * batch の終わりに 1 回ずつにまとめる。Model はコマンドの apply の中で通知するので、\n * そのまま転送すると購読側が更新前の canUndo / canRedo を読んでしまう。\n */\nexport class EditorNotifier extends Disposable {\n private readonly _onDidChangeScene = this._register(new Emitter<void>());\n readonly onDidChangeScene = this._onDidChangeScene.event;\n private readonly _onDidChangeViewState = this._register(new Emitter<void>());\n readonly onDidChangeViewState = this._onDidChangeViewState.event;\n\n private readonly readView: () => ViewSnapshot;\n private depth = 0;\n private sceneChanged = false;\n private lastView: ViewSnapshot;\n\n constructor(readView: () => ViewSnapshot) {\n super();\n this.readView = readView;\n this.lastView = readView();\n }\n\n batch<T>(action: () => T): T {\n this.depth++;\n let result: T;\n try {\n result = action();\n } finally {\n this.depth--;\n }\n this.flushIfIdle();\n return result;\n }\n\n markSceneChanged(): void {\n this.sceneChanged = true;\n this.flushIfIdle();\n }\n\n private flushIfIdle(): void {\n if (this.depth === 0) {\n this.flush();\n }\n }\n\n private flush(): void {\n if (this.sceneChanged) {\n this.sceneChanged = false;\n this._onDidChangeScene.fire();\n }\n const view = this.readView();\n if (!isSameView(view, this.lastView)) {\n this.lastView = view;\n this._onDidChangeViewState.fire();\n }\n }\n}\n","import type { LinePatch } from \"../commands/line-commands.js\";\nimport type { PlayerPatch } from \"../commands/player-commands.js\";\nimport {\n DEFAULT_LINE_INTERPOLATION,\n DEFAULT_LINE_KIND,\n type Line,\n MAX_WAYPOINTS_PER_LINE,\n} from \"../model/line.js\";\nimport type { FieldPosition, Player } from \"../model/player.js\";\nimport type { SceneData } from \"./editor.js\";\n\n/** ドラッグで動かす対象。 */\nexport type DragTarget =\n | { readonly kind: \"player\"; readonly playerId: string }\n | { readonly kind: \"waypoint\"; readonly lineId: string; readonly index: number }\n | { readonly kind: \"endpoint\"; readonly lineId: string };\n\nexport interface DragInteraction {\n readonly type: \"drag\";\n readonly target: DragTarget;\n /** 掴んだときの対象の位置。 */\n readonly origin: FieldPosition;\n /** 対象の位置からポインタを引いた差。離すまで保ち、掴んだ点がずれないようにする。 */\n readonly grabOffset: FieldPosition;\n /** 窓の中へ寄せたあとの、いまの対象の位置。 */\n readonly current: FieldPosition;\n}\n\nexport interface DrawInteraction {\n readonly type: \"draw-line\";\n readonly startPlayerId: string;\n /** 作図を始めた時点の起点選手の位置。最初の打点が同じ位置かの判定に使う。 */\n readonly start: FieldPosition;\n /** 打った点。最後の点が終点になり、残りが waypoint になる。 */\n readonly points: readonly FieldPosition[];\n readonly cursor: FieldPosition;\n}\n\n/** ドラッグや作図の途中の状態。Model には載せず、描画のときに重ねる。 */\nexport type Interaction = DragInteraction | DrawInteraction;\n\n/** 座標が完全に一致するか。格子点どうしの比較では、これが「同じ点」の判定になる。 */\nexport function isSamePosition(a: FieldPosition, b: FieldPosition): boolean {\n return a.lateralYard === b.lateralYard && a.downfieldYard === b.downfieldYard;\n}\n\n/** 作図で打てる点の数。最後の点は終点になるので、waypoint の上限より 1 つ多い。 */\nexport const MAX_DRAFT_POINTS = MAX_WAYPOINTS_PER_LINE + 1;\n\nexport function startDrag(\n target: DragTarget,\n origin: FieldPosition,\n pointer: FieldPosition,\n): DragInteraction {\n return {\n type: \"drag\",\n target,\n origin,\n grabOffset: {\n lateralYard: origin.lateralYard - pointer.lateralYard,\n downfieldYard: origin.downfieldYard - pointer.downfieldYard,\n },\n current: origin,\n };\n}\n\n/** 掴んだ点とポインタのずれを保ったまま、対象を置く位置。 */\nexport function dragPosition(drag: DragInteraction, pointer: FieldPosition): FieldPosition {\n return {\n lateralYard: pointer.lateralYard + drag.grabOffset.lateralYard,\n downfieldYard: pointer.downfieldYard + drag.grabOffset.downfieldYard,\n };\n}\n\n/** ドラッグ先に対象を置く変更。プレビューと確定の両方がこれを当てるので、見た目と結果がずれない。 */\nexport type DragPatch =\n | { readonly kind: \"player\"; readonly playerId: string; readonly patch: PlayerPatch }\n | { readonly kind: \"line\"; readonly lineId: string; readonly patch: LinePatch };\n\n/** 対象を to に置く変更。対象が scene に無ければ undefined。 */\nexport function dragPatch(\n scene: SceneData,\n target: DragTarget,\n to: FieldPosition,\n): DragPatch | undefined {\n switch (target.kind) {\n case \"player\":\n return scene.players.some((p) => p.id === target.playerId)\n ? { kind: \"player\", playerId: target.playerId, patch: { position: to } }\n : undefined;\n case \"endpoint\":\n return scene.lines.some((l) => l.id === target.lineId)\n ? { kind: \"line\", lineId: target.lineId, patch: { end: to } }\n : undefined;\n case \"waypoint\": {\n const line = scene.lines.find((l) => l.id === target.lineId);\n return line === undefined\n ? undefined\n : {\n kind: \"line\",\n lineId: line.id,\n patch: { waypoints: line.waypoints.map((w, i) => (i === target.index ? to : w)) },\n };\n }\n }\n}\n\n/** 打った点を、確定する線の waypoint と終点に分ける。点が無ければ undefined。 */\nexport function splitDraftPoints(\n points: readonly FieldPosition[],\n): { readonly waypoints: readonly FieldPosition[]; readonly end: FieldPosition } | undefined {\n const end = points.at(-1);\n return end === undefined ? undefined : { waypoints: points.slice(0, -1), end };\n}\n\n/** 線の起点は必ず選手なので、選手から作図を始める。 */\nexport function startDrawing(player: Player): DrawInteraction {\n return {\n type: \"draw-line\",\n startPlayerId: player.id,\n start: player.position,\n points: [],\n cursor: player.position,\n };\n}\n\n/**\n * point に点を打つ。直前の点(まだ点が無ければ起点の選手)と同じ位置のときと、\n * 打てる点の上限に達したときは、打たずにカーソルだけ進める。\n * 同じ位置を弾くのは、ダブルクリックで確定すると pointerdown が 2 回届き、\n * 直前の点の真上にもう 1 点打ってしまうため。\n */\nexport function addDraftPoint(draw: DrawInteraction, point: FieldPosition): DrawInteraction {\n const last = draw.points.at(-1) ?? draw.start;\n const accepts = !isSamePosition(last, point) && draw.points.length < MAX_DRAFT_POINTS;\n return { ...draw, points: accepts ? [...draw.points, point] : draw.points, cursor: point };\n}\n\n/**\n * 確定する線の waypoint と終点。anchor はいまの起点選手の位置。点が無いときと、\n * 打った点がすべて anchor と同じで長さが 0 のときは undefined。長さ 0 の線は見えず、選択もできない。\n */\nexport function committableDraft(\n draw: DrawInteraction,\n anchor: FieldPosition,\n): { readonly waypoints: readonly FieldPosition[]; readonly end: FieldPosition } | undefined {\n const split = splitDraftPoints(draw.points);\n if (split === undefined) {\n return undefined;\n }\n return draw.points.every((p) => isSamePosition(p, anchor)) ? undefined : split;\n}\n\n/** 作図から線を組み立てる。プレビューと確定で同じ既定値を使う。 */\nexport function draftToLine(\n draw: DrawInteraction,\n id: string,\n shape: { readonly waypoints: readonly FieldPosition[]; readonly end: FieldPosition },\n): Line {\n return {\n id,\n kind: DEFAULT_LINE_KIND,\n startPlayerId: draw.startPlayerId,\n waypoints: shape.waypoints,\n end: shape.end,\n interpolation: DEFAULT_LINE_INTERPOLATION,\n };\n}\n","import { applyLinePatch } from \"../commands/line-commands.js\";\nimport { applyPlayerPatch } from \"../commands/player-commands.js\";\nimport type { Line } from \"../model/line.js\";\nimport type { EditorOverlay, EditorSelection, SceneData } from \"./editor.js\";\nimport {\n type DragPatch,\n type DrawInteraction,\n draftToLine,\n dragPatch,\n type Interaction,\n MAX_DRAFT_POINTS,\n splitDraftPoints,\n} from \"./interaction.js\";\n\n/** 作図中の線の id。Model には入らず、プレビューの中だけで使う。 */\nconst DRAFT_LINE_ID = \"__playmaker_draft_line__\";\n\n// 起点が選手の線は、選手を差し替えるだけで追従する。\nfunction applyDragPatch(data: SceneData, drop: DragPatch): SceneData {\n switch (drop.kind) {\n case \"player\":\n return {\n ...data,\n players: data.players.map((p) =>\n p.id === drop.playerId ? applyPlayerPatch(p, drop.patch) : p,\n ),\n };\n case \"line\":\n return {\n ...data,\n lines: data.lines.map((l) => (l.id === drop.lineId ? applyLinePatch(l, drop.patch) : l)),\n };\n }\n}\n\nfunction draftLine(draw: DrawInteraction): Line {\n // 打点が上限に達したら、確定される線と同じく最後の打点を終点として描く。\n const full = draw.points.length >= MAX_DRAFT_POINTS ? splitDraftPoints(draw.points) : undefined;\n return draftToLine(draw, DRAFT_LINE_ID, full ?? { waypoints: draw.points, end: draw.cursor });\n}\n\n/** 確定済みの図に、ドラッグや作図の途中の状態を重ねる。data は書き換えない。 */\nexport function composePreview(data: SceneData, interaction: Interaction | undefined): SceneData {\n if (interaction === undefined) {\n return data;\n }\n switch (interaction.type) {\n case \"drag\": {\n const drop = dragPatch(data, interaction.target, interaction.current);\n return drop === undefined ? data : applyDragPatch(data, drop);\n }\n case \"draw-line\":\n return { ...data, lines: [...data.lines, draftLine(interaction)] };\n }\n}\n\n/**\n * 選択の強調とハンドルの位置。scene には composePreview で途中の状態を重ねたものを渡す。\n * そうするとドラッグ中のハンドルもドラッグ先に描ける。\n */\nexport function computeOverlay(scene: SceneData, selection: EditorSelection): EditorOverlay {\n if (selection.kind === \"player\") {\n return { kind: \"player\", playerId: selection.id };\n }\n const line =\n selection.kind === \"line\" ? scene.lines.find((l) => l.id === selection.id) : undefined;\n if (line === undefined) {\n return { kind: \"none\" };\n }\n return { kind: \"line\", waypointHandles: line.waypoints, endpointHandle: line.end };\n}\n","import type { Event } from \"../base/event.js\";\nimport { Disposable } from \"../base/lifecycle.js\";\nimport type { ICommand } from \"../commands/command.js\";\nimport type { ICommandService } from \"../commands/command-service.js\";\nimport { SetFieldZoneCommand } from \"../commands/field-commands.js\";\nimport { LoadFormationCommand } from \"../commands/formation-commands.js\";\nimport {\n AddLineCommand,\n type LinePatch,\n RemoveLineCommand,\n UpdateLineCommand,\n} from \"../commands/line-commands.js\";\nimport {\n AddPlayerCommand,\n type PlayerPatch,\n RemovePlayerCommand,\n UpdatePlayerCommand,\n} from \"../commands/player-commands.js\";\nimport { type Formation, instantiateFormation } from \"../formations/formation.js\";\nimport { clampToZoneWindow } from \"../geometry/field.js\";\nimport { snapToGrid } from \"../geometry/grid.js\";\nimport { hitLineHandle, hitTestLine, hitTestPlayer } from \"../geometry/hit-test.js\";\nimport type { IIdFactory } from \"../model/id-factory.js\";\nimport { type Line, MAX_LINES } from \"../model/line.js\";\nimport type { FieldZone } from \"../model/play-data.js\";\nimport type { IPlayModel } from \"../model/play-model.js\";\nimport {\n DEFAULT_PLAYER_SHAPE,\n type FieldPosition,\n MAX_PLAYERS,\n type Player,\n} from \"../model/player.js\";\nimport {\n canLoadFormation,\n type EditorFrame,\n type EditorSelection,\n type EditorTool,\n type EditorViewState,\n type IEditorController,\n isSameSelection,\n isToolAvailable,\n NO_SELECTION,\n} from \"./editor.js\";\nimport { EditorNotifier } from \"./editor-notifier.js\";\nimport {\n addDraftPoint,\n committableDraft,\n type DragInteraction,\n type DragTarget,\n type DrawInteraction,\n draftToLine,\n dragPatch,\n dragPosition,\n type Interaction,\n isSamePosition,\n startDrag,\n startDrawing,\n} from \"./interaction.js\";\nimport { composePreview, computeOverlay } from \"./preview.js\";\n\n/**\n * ツール、選択、ジェスチャを受けてコマンドを発行する。Model を直接書き換えない。\n * ドラッグや作図の途中は Model に載せず、getFrame で重ねて見せるので、\n * 確定までは Model の onDidChange も履歴も動かない。\n */\nexport class EditorController extends Disposable implements IEditorController {\n private readonly model: IPlayModel;\n private readonly commands: ICommandService;\n private readonly ids: IIdFactory;\n\n private readonly notifier: EditorNotifier;\n readonly onDidChangeScene: Event<void>;\n readonly onDidChangeViewState: Event<void>;\n\n private tool: EditorTool = \"select\";\n private selection: EditorSelection = NO_SELECTION;\n private interaction: Interaction | undefined;\n\n constructor(model: IPlayModel, commands: ICommandService, ids: IIdFactory) {\n super();\n this.model = model;\n this.commands = commands;\n this.ids = ids;\n this.notifier = this._register(\n new EditorNotifier(() => ({\n state: this.getViewState(),\n player: this.getSelectedPlayer(),\n line: this.getSelectedLine(),\n })),\n );\n this.onDidChangeScene = this.notifier.onDidChangeScene;\n this.onDidChangeViewState = this.notifier.onDidChangeViewState;\n this._register(this.model.onDidChange(() => this.notifier.markSceneChanged()));\n }\n\n getViewState(): EditorViewState {\n const { players, lines } = this.model.getSnapshot();\n return {\n tool: this.tool,\n selection:\n this.getSelectedPlayer() === undefined && this.getSelectedLine() === undefined\n ? NO_SELECTION\n : this.selection,\n canUndo: this.commands.canUndo,\n canRedo: this.commands.canRedo,\n fieldZone: this.model.getFieldZone(),\n isDrawing: this.interaction?.type === \"draw-line\",\n remainingPlayerSlots: MAX_PLAYERS - players.length,\n canStartLine: lines.length < MAX_LINES,\n };\n }\n\n getSelectedPlayer(): Player | undefined {\n const s = this.selection;\n return s.kind === \"player\" ? this.model.findPlayer(s.id) : undefined;\n }\n\n getSelectedLine(): Line | undefined {\n const s = this.selection;\n return s.kind === \"line\" ? this.model.findLine(s.id) : undefined;\n }\n\n getFrame(): EditorFrame {\n const scene = composePreview(this.model.getSnapshot(), this.interaction);\n return { scene, overlay: computeOverlay(scene, this.selection) };\n }\n\n setTool(tool: EditorTool): void {\n if (tool === this.tool) {\n return;\n }\n this.notifier.batch(() => {\n this.tool = tool;\n this.setInteraction(undefined);\n });\n }\n\n pointerDown(pos: FieldPosition): void {\n this.notifier.batch(() => {\n switch (this.tool) {\n case \"add-player\":\n this.addPlayerAt(pos);\n return;\n case \"draw-line\":\n this.drawLinePointerDown(pos);\n return;\n case \"select\":\n this.selectPointerDown(pos);\n return;\n }\n });\n }\n\n pointerMove(pos: FieldPosition): void {\n const interaction = this.interaction;\n if (interaction === undefined) {\n return;\n }\n this.notifier.batch(() =>\n this.setInteraction(\n interaction.type === \"draw-line\"\n ? { ...interaction, cursor: this.clampToField(pos) }\n : { ...interaction, current: this.clampToField(dragPosition(interaction, pos)) },\n ),\n );\n }\n\n pointerUp(pos: FieldPosition): void {\n const interaction = this.interaction;\n // 作図はクリック(pointerDown)で点を打つので、up では何もしない。\n if (interaction?.type !== \"drag\") {\n return;\n }\n this.notifier.batch(() => {\n this.setInteraction(undefined);\n const moved = dragPosition(interaction, pos);\n // 寄せる前の位置で比べる。窓の外にある選手をクリックしただけで、窓の端へ動かさない。\n if (isSamePosition(moved, interaction.origin)) {\n return;\n }\n const to = this.clampToField(moved);\n // 同じ格子点に収まる動きは図を変えないので、履歴にも通知にも載せない。\n if (isSamePosition(to, interaction.origin)) {\n return;\n }\n const command = this.dropCommand(interaction, to);\n if (command !== undefined) {\n this.commands.execute(command);\n }\n });\n }\n\n cancelInteraction(): void {\n this.notifier.batch(() => this.setInteraction(undefined));\n }\n\n commitLine(): void {\n const interaction = this.interaction;\n if (interaction?.type !== \"draw-line\") {\n return;\n }\n this.notifier.batch(() => {\n this.setInteraction(undefined);\n const line = this.lineFromDraft(interaction);\n if (line === undefined) {\n return;\n }\n this.commands.execute(new AddLineCommand(line));\n // 作図の直後は選択ツールへ戻し、引いた線を選ぶ。続けて引くより、すぐ編集できるほうを取る。\n this.setTool(\"select\");\n this.setSelection({ kind: \"line\", id: line.id });\n });\n }\n\n deleteSelection(): void {\n const player = this.getSelectedPlayer();\n const line = this.getSelectedLine();\n this.notifier.batch(() => {\n if (player !== undefined) {\n this.commands.execute(new RemovePlayerCommand(player.id));\n } else if (line !== undefined) {\n this.commands.execute(new RemoveLineCommand(line.id));\n } else {\n return;\n }\n this.setSelection(NO_SELECTION);\n });\n }\n\n updateSelectedPlayer(patch: PlayerPatch): void {\n const player = this.getSelectedPlayer();\n if (player === undefined) {\n return;\n }\n this.notifier.batch(() => this.commands.execute(new UpdatePlayerCommand(player.id, patch)));\n }\n\n updateSelectedLine(patch: LinePatch): void {\n const line = this.getSelectedLine();\n if (line === undefined) {\n return;\n }\n this.notifier.batch(() => this.commands.execute(new UpdateLineCommand(line.id, patch)));\n }\n\n setFieldZone(zone: FieldZone): void {\n this.notifier.batch(() => {\n // 同じゾーンを選び直しただけなら、途中のドラッグや作図は残す。\n if (this.commands.execute(new SetFieldZoneCommand(zone))) {\n this.setInteraction(undefined);\n }\n });\n }\n\n loadFormation(formation: Formation): boolean {\n if (!canLoadFormation(formation, this.getViewState())) {\n return false;\n }\n const { players } = this.model.getSnapshot();\n const added = instantiateFormation(\n formation,\n this.ids,\n players.map((p) => p.id),\n );\n return this.notifier.batch(() => {\n const loaded = this.commands.execute(new LoadFormationCommand(added));\n if (loaded) {\n // 読み込んだあとは、途中の操作と元の選択に意味が無いので外す。\n this.setInteraction(undefined);\n this.setSelection(NO_SELECTION);\n }\n return loaded;\n });\n }\n\n undo(): void {\n this.notifier.batch(() => {\n const interaction = this.interaction;\n if (interaction?.type === \"draw-line\") {\n this.setInteraction(\n interaction.points.length === 0\n ? undefined\n : { ...interaction, points: interaction.points.slice(0, -1) },\n );\n return;\n }\n this.setInteraction(undefined);\n this.commands.undo();\n });\n }\n\n redo(): void {\n this.notifier.batch(() => {\n this.setInteraction(undefined);\n this.commands.redo();\n });\n }\n\n private setSelection(next: EditorSelection): void {\n if (isSameSelection(this.selection, next)) {\n return;\n }\n this.selection = next;\n this.notifier.markSceneChanged();\n }\n\n private setInteraction(next: Interaction | undefined): void {\n if (next === this.interaction) {\n return;\n }\n this.interaction = next;\n this.notifier.markSceneChanged();\n }\n\n // 窓の端(横はサイドライン、縦は LOS から整数ヤード)はどれも格子点なので、寄せてから丸めても窓の外へは出ない。\n private clampToField(pos: FieldPosition): FieldPosition {\n return snapToGrid(clampToZoneWindow(pos, this.model.getSnapshot().field));\n }\n\n // ドラッグ中に対象が消えていたら undefined を返し、コマンドを出さない。\n private dropCommand(drag: DragInteraction, to: FieldPosition): ICommand | undefined {\n const drop = dragPatch(this.model.getSnapshot(), drag.target, to);\n if (drop === undefined) {\n return undefined;\n }\n return drop.kind === \"player\"\n ? new UpdatePlayerCommand(drop.playerId, drop.patch)\n : new UpdateLineCommand(drop.lineId, drop.patch);\n }\n\n // 起点の選手が消えていれば確定しない。\n private lineFromDraft(draw: DrawInteraction): Line | undefined {\n const start = this.model.findPlayer(draw.startPlayerId);\n const split = start === undefined ? undefined : committableDraft(draw, start.position);\n if (split === undefined) {\n return undefined;\n }\n const id = this.ids.next(\"line\", new Set(this.model.getSnapshot().lines.map((l) => l.id)));\n return draftToLine(draw, id, split);\n }\n\n private selectPointerDown(pos: FieldPosition): void {\n const data = this.model.getSnapshot();\n // 選択中の線のハンドルを最優先で掴む。選手や線と重なっていても編集できるようにする。\n const handle = this.hitSelectedLineHandle(pos);\n if (handle !== undefined) {\n this.setInteraction(handle);\n return;\n }\n // 選手は選択しつつドラッグを始める。動かさずに離せばただの選択になる。\n const player = hitTestPlayer(data.players, pos);\n if (player !== undefined) {\n this.setSelection({ kind: \"player\", id: player.id });\n this.setInteraction(startDrag({ kind: \"player\", playerId: player.id }, player.position, pos));\n return;\n }\n const line = hitTestLine(data.lines, data.players, pos);\n this.setSelection(line === undefined ? NO_SELECTION : { kind: \"line\", id: line.id });\n }\n\n private hitSelectedLineHandle(pos: FieldPosition): DragInteraction | undefined {\n const line = this.getSelectedLine();\n const hit = line === undefined ? undefined : hitLineHandle(line, pos);\n if (line === undefined || hit === undefined) {\n return undefined;\n }\n const target: DragTarget =\n hit.kind === \"endpoint\"\n ? { kind: \"endpoint\", lineId: line.id }\n : { kind: \"waypoint\", lineId: line.id, index: hit.index };\n return startDrag(target, hit.point, pos);\n }\n\n private drawLinePointerDown(pos: FieldPosition): void {\n const interaction = this.interaction;\n if (interaction?.type === \"draw-line\") {\n this.setInteraction(addDraftPoint(interaction, this.clampToField(pos)));\n return;\n }\n if (!isToolAvailable(\"draw-line\", this.getViewState())) {\n return;\n }\n const data = this.model.getSnapshot();\n // 選手以外から始めようとしたら無視する。\n const player = hitTestPlayer(data.players, pos);\n if (player === undefined) {\n return;\n }\n this.setInteraction(startDrawing(player));\n }\n\n private addPlayerAt(pos: FieldPosition): void {\n if (!isToolAvailable(\"add-player\", this.getViewState())) {\n return;\n }\n const { players } = this.model.getSnapshot();\n const id = this.ids.next(\"player\", new Set(players.map((p) => p.id)));\n this.commands.execute(\n new AddPlayerCommand({\n id,\n position: this.clampToField(pos),\n shape: DEFAULT_PLAYER_SHAPE,\n label: \"\",\n }),\n );\n this.setSelection({ kind: \"player\", id });\n }\n}\n","import { Emitter, type Event } from \"../base/event.js\";\nimport { Disposable, DisposableStore } from \"../base/lifecycle.js\";\nimport { CommandService } from \"../commands/command-service.js\";\nimport { UndoRedoService } from \"../commands/undo-redo-service.js\";\nimport { type Formation, normalizeFormation } from \"../formations/formation.js\";\nimport { IdFactory } from \"../model/id-factory.js\";\nimport type { FieldZone, PlayData } from \"../model/play-data.js\";\nimport { PlayModel } from \"../model/play-model.js\";\nimport type { IEditorController } from \"./editor.js\";\nimport { EditorController } from \"./editor-controller.js\";\n\ninterface PlayDocument {\n readonly store: DisposableStore;\n readonly model: PlayModel;\n readonly controller: EditorController;\n}\n\nfunction openDocument(data: unknown): PlayDocument {\n const store = new DisposableStore();\n const model = store.add(new PlayModel(data));\n const commands = new CommandService(model, new UndoRedoService());\n const controller = store.add(new EditorController(model, commands, new IdFactory()));\n return { store, model, controller };\n}\n\n/**\n * 1 つのプレー図の編集を受け持つ。\n * setPlayData は履歴ごと作り直すので、controller も別のオブジェクトになる。\n */\nexport class PlaySession extends Disposable {\n private readonly _onDidReset = this._register(new Emitter<void>());\n /** setPlayData で controller が作り直されたあとに発火する。 */\n readonly onDidReset = this._onDidReset.event;\n\n private readonly _onDidEdit = this._register(new Emitter<void>());\n /**\n * 編集の確定ごとに 1 回、最新の図の深いコピーを渡す。構築時と setPlayData では発火しない\n * (読み込みは編集ではないため)。\n * コピーはリスナごとに作るので、受け手が書き換えても、ほかのリスナとこの図には波及しない。\n */\n readonly onDidChange: Event<PlayData> = (listener) =>\n this._onDidEdit.event(() => listener(this.getPlayData()));\n\n private readonly _onDidChangeScene = this._register(new Emitter<void>());\n /**\n * 今の controller の onDidChangeScene を転送する。setPlayData で読み直したときも、\n * onDidReset のあとに 1 回出す。controller が作り直されても購読し直さなくてよい。\n */\n readonly onDidChangeScene = this._onDidChangeScene.event;\n\n private readonly _onDidChangeViewState = this._register(new Emitter<void>());\n /**\n * 今の controller の onDidChangeViewState を転送する。setPlayData で読み直したときも、\n * 表示状態が変わったかどうかにかかわらず onDidReset のあとに 1 回出す。\n */\n readonly onDidChangeViewState = this._onDidChangeViewState.event;\n\n private document: PlayDocument;\n\n constructor(data: unknown) {\n super();\n this.document = this.open(data);\n }\n\n get controller(): IEditorController {\n return this.document.controller;\n }\n\n get fieldZone(): FieldZone {\n return this.document.model.getFieldZone();\n }\n\n /** 現在の図の深いコピー。受け取った値を書き換えても、この図には波及しない。 */\n getPlayData(): PlayData {\n return this.document.model.getData();\n }\n\n /** 現在の図をコピーせずに返す。 */\n getSnapshot(): PlayData {\n return this.document.model.getSnapshot();\n }\n\n setFieldZone(zone: FieldZone): void {\n this.document.controller.setFieldZone(zone);\n }\n\n /** 外から来た隊形を正規化してから読む。置ける選手が 1 人もいなければ何もせず false を返す。 */\n loadFormation(formation: Formation): boolean {\n const normalized = normalizeFormation(formation);\n return normalized !== null && this.document.controller.loadFormation(normalized);\n }\n\n setPlayData(data: unknown): void {\n this.document.store.dispose();\n this.document = this.open(data);\n this._onDidReset.fire();\n this._onDidChangeScene.fire();\n this._onDidChangeViewState.fire();\n }\n\n private open(data: unknown): PlayDocument {\n const opened = openDocument(data);\n const { store, model, controller } = opened;\n store.add(model.onDidChange(() => this._onDidEdit.fire()));\n store.add(controller.onDidChangeScene(() => this._onDidChangeScene.fire()));\n store.add(controller.onDidChangeViewState(() => this._onDidChangeViewState.fire()));\n return opened;\n }\n\n override dispose(): void {\n this.document.store.dispose();\n super.dispose();\n }\n}\n","import { fieldWindowAspect } from \"../geometry/field.js\";\nimport { isFiniteNumber } from \"../model/guards.js\";\nimport type { FieldZone } from \"../model/play-data.js\";\n\n/** 幅を指定しないときの PNG の幅(px)。資料に貼っても粗く見えない大きさ。 */\nexport const DEFAULT_EXPORT_WIDTH = 1600;\n\n/**\n * 書き出す幅の上限(px)。縦に長いレッドゾーンの窓でも約 1100 万画素に収まり、\n * canvas の面積を約 1678 万画素までに制限するブラウザ(iOS の Safari)でも描ける。\n */\nexport const MAX_EXPORT_WIDTH = 4096;\n\nexport interface ImageExportOptions {\n /**\n * PNG の幅(px)。高さはゾーンの窓の縦横比から決める。\n * 未指定、有限でない値、1 未満は 1600 にし、4096 を超える幅は 4096 に切り詰める。\n */\n width?: number | undefined;\n}\n\nexport interface ImageExportSize {\n readonly width: number;\n readonly height: number;\n}\n\n/**\n * 外から渡された幅を整数の px にする。有限でない値と 1 未満は既定の幅にし、上限を超える幅は上限に切り詰める。\n */\nexport function resolveImageExportWidth(width: number | undefined): number {\n if (!isFiniteNumber(width) || width < 1) {\n return DEFAULT_EXPORT_WIDTH;\n }\n return Math.min(Math.round(width), MAX_EXPORT_WIDTH);\n}\n\n/**\n * 高さをゾーンの窓の縦横比から決めるので、画像に余白は付かない。\n * 窓の縦横比は 2 未満なので、幅が 1 以上なら四捨五入した高さも 1 以上になる。\n */\nexport function resolveImageExportSize(\n zone: FieldZone,\n options: ImageExportOptions = {},\n): ImageExportSize {\n const width = resolveImageExportWidth(options.width);\n return { width, height: Math.round(width / fieldWindowAspect(zone)) };\n}\n","// 隊形とプレーのプリセットで共有する配置。縦は LOS からの位置(LOS が 0 で、攻撃方向が正)で、\n// 横はセンターを 26.5 ヤード(フィールドの中央)に置く。位置はすべて 0.5 ヤードの格子点で書く。\n// どのゾーンで読み込んでも窓に収まる。名称は英語で書く。フィールド上の表記を英語に揃えるため。\n//\n// OL は LOS の 1 ヤード後ろ、守備ラインは 1.5 ヤード前に置き、マーカーが重ならない隙間を空ける。\n// LOS 上の選手(OL、TE、外側の WR)は -1、LOS から下がる選手(スロット、フランカー)は -2、\n// センター直下の QB は -3。守備ラインは OL の肩に付ける(シェード)ので、どのギャップを誰が\n// 守るかが読める。TE が付く隊形にはオーバーで構え、強い側の E を TE の外側の肩(9 テク)に置く。\n// 守備の選手には全員ラベルを付ける。\n//\n// 選手は id を持つ。プレーの線が起点の選手を id で指すためで、隊形にするときは id を外す。\n\nimport type { FieldPosition, Player, PlayerShape } from \"../model/player.js\";\n\nexport function pt(lateralYard: number, downfieldYard: number): FieldPosition {\n return { lateralYard, downfieldYard };\n}\n\nexport function player(\n id: string,\n label: string,\n position: FieldPosition,\n shape: PlayerShape = \"circle\",\n): Player {\n return { id, position, shape, label };\n}\n\n/**\n * 相手の 1 ヤード手前。ブロックの終点に使い、T 字のバーが相手のマーカーの縁に付く。\n * lateral で相手の肩の側へずらす(リーチやダウンブロック)。\n */\nexport function shortOf(target: FieldPosition, lateral = 0): FieldPosition {\n return pt(target.lateralYard + lateral, target.downfieldYard - 1);\n}\n\n/** 相手の肩の横。コンボブロックで LB へ上がる側が経由する。lateral は 1 ヤード以上離す。 */\nexport function beside(target: FieldPosition, lateral: number): FieldPosition {\n return pt(target.lateralYard + lateral, target.downfieldYard);\n}\n\nexport const OL = {\n lt: pt(21.5, -1),\n lg: pt(24, -1),\n c: pt(26.5, -1),\n rg: pt(29, -1),\n rt: pt(31.5, -1),\n} as const;\n\n// 4 ダウンのオーバーフロント。右を強い側として、E は LT の外側の肩、N は C の弱い側の肩、\n// T は RG の外側の肩に付ける。強い側の E は、TE が無ければ RT の外側の肩に付ける。\nexport const FRONT_4 = {\n eL: pt(20.5, 1.5),\n n: pt(25.5, 1.5),\n t: pt(30, 1.5),\n eR: pt(32.5, 1.5),\n} as const;\n\n/** TE が右に付くときの強い側の E。TE の外側の肩(9 テク)。 */\nexport const END_OVER_TE = pt(35.5, 1.5);\n\n// 3 ダウンのオッドフロント。N は C の真上、E は両タックルの内側の肩。\nexport const FRONT_3 = {\n eL: pt(22.5, 1.5),\n n: pt(26.5, 1.5),\n eR: pt(30.5, 1.5),\n} as const;\n\n// 4-3 オーバーの LB。S は TE の真上に付く。\nexport const LB_43 = { w: pt(22.5, 5), m: pt(27, 5), s: pt(34.5, 5) } as const;\n\n// ニッケルの ILB 2 人と、スロットに付くニッケルバック。\nexport const LB_NICKEL = { m: pt(24, 5), w: pt(30, 5), nb: pt(14, 5) } as const;\n\nexport function cornerSpots(depth: number): { left: FieldPosition; right: FieldPosition } {\n return { left: pt(6.5, depth), right: pt(46.5, depth) };\n}\n\nexport function offensiveLine(): Player[] {\n return [\n player(\"lt\", \"LT\", OL.lt, \"square\"),\n player(\"lg\", \"LG\", OL.lg, \"square\"),\n player(\"c\", \"C\", OL.c, \"square\"),\n player(\"rg\", \"RG\", OL.rg, \"square\"),\n player(\"rt\", \"RT\", OL.rt, \"square\"),\n ];\n}\n\nexport function front4(strongEnd: FieldPosition = FRONT_4.eR): Player[] {\n return [\n player(\"de-l\", \"E\", FRONT_4.eL),\n player(\"dt-l\", \"N\", FRONT_4.n),\n player(\"dt-r\", \"T\", FRONT_4.t),\n player(\"de-r\", \"E\", strongEnd),\n ];\n}\n\nexport function front3(): Player[] {\n return [\n player(\"de-l\", \"E\", FRONT_3.eL),\n player(\"nt\", \"N\", FRONT_3.n),\n player(\"de-r\", \"E\", FRONT_3.eR),\n ];\n}\n\nexport function corners(depth: number): Player[] {\n const { left, right } = cornerSpots(depth);\n return [player(\"cb-l\", \"CB\", left), player(\"cb-r\", \"CB\", right)];\n}\n\n// ---- 攻撃の隊形 ----\n\nexport function iFormation(): Player[] {\n return [\n ...offensiveLine(),\n player(\"y\", \"Y\", pt(34.5, -1), \"square\"),\n player(\"qb\", \"QB\", pt(26.5, -3)),\n player(\"fb\", \"FB\", pt(26.5, -6)),\n player(\"rb\", \"RB\", pt(26.5, -8.5)),\n player(\"x\", \"X\", pt(6.5, -1)),\n player(\"z\", \"Z\", pt(46.5, -2)),\n ];\n}\n\nexport function singlebackAce(): Player[] {\n return [\n ...offensiveLine(),\n player(\"y\", \"Y\", pt(34.5, -1), \"square\"),\n player(\"qb\", \"QB\", pt(26.5, -3)),\n player(\"rb\", \"RB\", pt(26.5, -7.5)),\n player(\"x\", \"X\", pt(6, -1)),\n player(\"h\", \"H\", pt(40, -2)),\n player(\"z\", \"Z\", pt(47, -1)),\n ];\n}\n\nexport function shotgunSpread(): Player[] {\n return [\n ...offensiveLine(),\n player(\"qb\", \"QB\", pt(26.5, -5)),\n player(\"rb\", \"RB\", pt(29.5, -5)),\n player(\"x\", \"X\", pt(5.5, -1)),\n player(\"y\", \"Y\", pt(13, -2)),\n player(\"h\", \"H\", pt(40, -2)),\n player(\"z\", \"Z\", pt(47.5, -1)),\n ];\n}\n\nexport function trips(): Player[] {\n return [\n ...offensiveLine(),\n player(\"qb\", \"QB\", pt(26.5, -5)),\n player(\"rb\", \"RB\", pt(24, -5)),\n player(\"x\", \"X\", pt(5.5, -1)),\n player(\"y\", \"Y\", pt(34.5, -1), \"square\"),\n player(\"h\", \"H\", pt(41, -2)),\n player(\"z\", \"Z\", pt(47.5, -1)),\n ];\n}\n\nexport function empty(): Player[] {\n return [\n ...offensiveLine(),\n player(\"qb\", \"QB\", pt(26.5, -5)),\n player(\"x\", \"X\", pt(5, -1)),\n player(\"f\", \"F\", pt(12, -2)),\n player(\"y\", \"Y\", pt(34.5, -1), \"square\"),\n player(\"h\", \"H\", pt(41, -2)),\n player(\"z\", \"Z\", pt(48, -1)),\n ];\n}\n\nexport function pistol(): Player[] {\n return [\n ...offensiveLine(),\n player(\"y\", \"Y\", pt(34.5, -1), \"square\"),\n player(\"qb\", \"QB\", pt(26.5, -4.5)),\n player(\"rb\", \"RB\", pt(26.5, -7.5)),\n player(\"x\", \"X\", pt(6, -1)),\n player(\"h\", \"H\", pt(40, -2)),\n player(\"z\", \"Z\", pt(47, -1)),\n ];\n}\n\nexport function bunch(): Player[] {\n return [\n ...offensiveLine(),\n player(\"qb\", \"QB\", pt(26.5, -5)),\n player(\"rb\", \"RB\", pt(24, -5)),\n player(\"x\", \"X\", pt(5.5, -1)),\n player(\"z\", \"Z\", pt(37, -1)),\n player(\"h\", \"H\", pt(34.5, -2)),\n player(\"y\", \"Y\", pt(39.5, -2)),\n ];\n}\n\n// ---- 守備の隊形 ----\n\n/** 4-3 オーバー。TE が右に付く隊形に構える。 */\nexport function defense43(): Player[] {\n return [\n ...front4(END_OVER_TE),\n player(\"wlb\", \"W\", LB_43.w),\n player(\"mlb\", \"M\", LB_43.m),\n player(\"slb\", \"S\", LB_43.s),\n ...corners(6),\n player(\"fs\", \"FS\", pt(23, 11)),\n player(\"ss\", \"SS\", pt(32, 9)),\n ];\n}\n\nexport function defense34(): Player[] {\n return [\n ...front3(),\n player(\"wlb\", \"W\", pt(19, 2.5)),\n player(\"mlb\", \"M\", pt(24.5, 5)),\n player(\"tlb\", \"T\", pt(29, 5)),\n player(\"slb\", \"S\", pt(34.5, 2.5)),\n ...corners(6),\n player(\"fs\", \"FS\", pt(23, 11)),\n player(\"ss\", \"SS\", pt(30, 11)),\n ];\n}\n\n/** ニッケルの前の 6 人(4 ダウンと ILB 2 人)。 */\nexport function nickelFront(strongEnd: FieldPosition = FRONT_4.eR): Player[] {\n return [...front4(strongEnd), player(\"mlb\", \"M\", LB_NICKEL.m), player(\"wlb\", \"W\", LB_NICKEL.w)];\n}\n\n/** ニッケルの後ろの 5 人の置き方。カバレッジやプレッシャーごとに変わる。 */\nexport interface NickelShell {\n readonly cornerDepth: number;\n readonly fs: FieldPosition;\n readonly ss: FieldPosition;\n}\n\n/** CB 6 ヤード、セイフティ 11 ヤードの 2 ハイ。 */\nexport const NICKEL_BASE: NickelShell = { cornerDepth: 6, fs: pt(22, 11), ss: pt(31, 11) };\n\nexport function nickel(shell: NickelShell, strongEnd: FieldPosition = FRONT_4.eR): Player[] {\n return [\n ...nickelFront(strongEnd),\n player(\"nb\", \"NB\", LB_NICKEL.nb),\n ...corners(shell.cornerDepth),\n player(\"fs\", \"FS\", shell.fs),\n player(\"ss\", \"SS\", shell.ss),\n ];\n}\n\nexport function dime(): Player[] {\n return [\n ...front4(),\n player(\"mlb\", \"M\", pt(27, 5)),\n player(\"nb\", \"NB\", LB_NICKEL.nb),\n player(\"db\", \"$\", pt(39, 5)),\n ...corners(6),\n player(\"fs\", \"FS\", pt(22, 11)),\n player(\"ss\", \"SS\", pt(31, 11)),\n ];\n}\n\nexport function defense425(): Player[] {\n return [\n ...front4(),\n player(\"mlb\", \"M\", pt(24.5, 5)),\n player(\"wlb\", \"W\", LB_NICKEL.w),\n player(\"nb\", \"NB\", pt(39, 5)),\n ...corners(6),\n player(\"fs\", \"FS\", pt(23, 11)),\n player(\"ss\", \"SS\", pt(31, 9)),\n ];\n}\n\nexport function defense335(): Player[] {\n return [\n ...front3(),\n player(\"wlb\", \"W\", pt(20.5, 5)),\n player(\"mlb\", \"M\", pt(26.5, 5)),\n player(\"slb\", \"S\", pt(32.5, 5)),\n player(\"nb\", \"NB\", LB_NICKEL.nb),\n ...corners(6),\n player(\"fs\", \"FS\", pt(23, 11)),\n player(\"ss\", \"SS\", pt(31, 9)),\n ];\n}\n","// 配置は presets/alignments.ts にあり、プレーのプリセットと共有する。ここでは id を外して隊形にする。\n\nimport type { Player } from \"../model/player.js\";\nimport {\n bunch,\n defense34,\n defense43,\n defense335,\n defense425,\n dime,\n empty,\n iFormation,\n NICKEL_BASE,\n nickel,\n pistol,\n shotgunSpread,\n singlebackAce,\n trips,\n} from \"../presets/alignments.js\";\nimport { deepFreeze, type TeamSide } from \"../presets/shared.js\";\nimport { type Formation, toFormationPlayer } from \"./formation.js\";\n\nfunction formation(id: string, name: string, side: TeamSide, players: Player[]): Formation {\n return { id, name, side, players: players.map(toFormationPlayer) };\n}\n\nexport const FORMATION_PRESETS: readonly Formation[] = /* @__PURE__ */ deepFreeze([\n formation(\"i-formation\", \"I-Formation\", \"offense\", iFormation()),\n formation(\"singleback-ace\", \"Singleback Ace\", \"offense\", singlebackAce()),\n formation(\"shotgun-spread\", \"Shotgun Spread\", \"offense\", shotgunSpread()),\n formation(\"trips\", \"Trips\", \"offense\", trips()),\n formation(\"empty\", \"Empty\", \"offense\", empty()),\n formation(\"pistol\", \"Pistol\", \"offense\", pistol()),\n formation(\"bunch\", \"Bunch\", \"offense\", bunch()),\n formation(\"defense-4-3\", \"4-3 Over\", \"defense\", defense43()),\n formation(\"defense-3-4\", \"3-4\", \"defense\", defense34()),\n formation(\"defense-nickel\", \"Nickel\", \"defense\", nickel(NICKEL_BASE)),\n formation(\"defense-dime\", \"Dime\", \"defense\", dime()),\n formation(\"defense-4-2-5\", \"4-2-5\", \"defense\", defense425()),\n formation(\"defense-3-3-5\", \"3-3-5\", \"defense\", defense335()),\n]);\n\nexport function getFormationPreset(id: string): Formation | undefined {\n return FORMATION_PRESETS.find((f) => f.id === id);\n}\n","import type { CanvasPoint } from \"./field.js\";\nimport { trimPolylineEnd } from \"./polyline.js\";\n\n// 線が矢じりより短くても消えないよう、切り詰めは全長のこの割合までに留める(残りは矢じりが覆う)。\nconst ARROW_TRIM_MAX_FRACTION = 0.9;\n\ninterface LineEnd {\n readonly tip: CanvasPoint;\n /** 終点へ向かう単位ベクトル。 */\n readonly ux: number;\n readonly uy: number;\n}\n\n/**\n * 終点と、終点へ向かう向き。曲線の末尾には終点と同じ座標の点が並ぶことがあるので、\n * 終点と座標の違う直近の点から向きを求める。すべての点が同じ座標なら undefined。\n */\nfunction lineEnd(path: readonly CanvasPoint[]): LineEnd | undefined {\n const tip = path.at(-1);\n if (tip === undefined) {\n return undefined;\n }\n // 毎フレーム線ごとに呼ぶので、配列を複製せずに終点側から探す。\n for (let i = path.length - 2; i >= 0; i--) {\n const from = path[i];\n if (from !== undefined && (from.x !== tip.x || from.y !== tip.y)) {\n const dx = tip.x - from.x;\n const dy = tip.y - from.y;\n const length = Math.hypot(dx, dy);\n return { tip, ux: dx / length, uy: dy / length };\n }\n }\n return undefined;\n}\n\n/** 矢じりの根元で止めた線。矢じりより短い線も、全長の 1 割は残す。 */\nexport function trimForArrowHead(path: readonly CanvasPoint[], arrowLength: number): CanvasPoint[] {\n return trimPolylineEnd(path, arrowLength, ARROW_TRIM_MAX_FRACTION);\n}\n\n/**\n * 終点を先端にして進行方向へ向けた、矢じりの三角形の頂点(先端、根元の両端)。\n * 向きが決まらない線では undefined。\n */\nexport function arrowHeadVertices(\n path: readonly CanvasPoint[],\n arrowLength: number,\n halfWidth: number,\n): readonly [CanvasPoint, CanvasPoint, CanvasPoint] | undefined {\n const end = lineEnd(path);\n if (end === undefined) {\n return undefined;\n }\n const { tip, ux, uy } = end;\n const baseX = tip.x - arrowLength * ux;\n const baseY = tip.y - arrowLength * uy;\n return [\n tip,\n { x: baseX - halfWidth * uy, y: baseY + halfWidth * ux },\n { x: baseX + halfWidth * uy, y: baseY - halfWidth * ux },\n ];\n}\n\n/** 終点を中点にして進行方向と直交する、T 字の横棒の両端。向きが決まらない線では undefined。 */\nexport function blockCapEndpoints(\n path: readonly CanvasPoint[],\n capLength: number,\n): readonly [CanvasPoint, CanvasPoint] | undefined {\n const end = lineEnd(path);\n if (end === undefined) {\n return undefined;\n }\n const { tip, ux, uy } = end;\n const half = capLength / 2;\n return [\n { x: tip.x + half * uy, y: tip.y - half * ux },\n { x: tip.x - half * uy, y: tip.y + half * ux },\n ];\n}\n","import type { PlayerShape } from \"../model/player.js\";\n\n// 円を外接円の半径で描くと、辺が円の内側に入る正方形より一回り大きく見え、LOS 際のブロックの線を覆う。\n// 描く半径だけを正方形の辺の幅へ寄せる。円は錯視で小さく見えるので、辺の幅より少し大きくしてある。\n// 当たり判定は形状によらず外接円のままにする。\nconst CIRCLE_DRAW_SCALE = 0.82;\n\nexport type PlayerMarkerOutline =\n | { readonly kind: \"circle\"; readonly radius: number }\n | { readonly kind: \"square\"; readonly halfSide: number };\n\n/** 選手マーカーの輪郭。radius は当たり判定と同じ外接円の半径で、正方形は頂点がこの円に乗る大きさにする。 */\nexport function playerMarkerOutline(shape: PlayerShape, radius: number): PlayerMarkerOutline {\n switch (shape) {\n case \"circle\":\n return { kind: \"circle\", radius: radius * CIRCLE_DRAW_SCALE };\n case \"square\":\n return { kind: \"square\", halfSide: radius / Math.SQRT2 };\n }\n}\n","/** キー操作で呼ぶ編集。 */\nexport type KeyAction = \"cancel-interaction\" | \"commit-line\" | \"undo\" | \"redo\";\n\n/** KeyboardEvent のうち、割り当てを決めるのに読む値。 */\nexport interface KeyStroke {\n readonly key: string;\n readonly metaKey: boolean;\n readonly ctrlKey: boolean;\n readonly shiftKey: boolean;\n}\n\n/**\n * キーに割り当てた編集を返す。割り当てのないキーは null。\n * Mac の Cmd と、ほかの OS の Ctrl を同じ修飾キーとして扱う。\n * Shift を押すと key が大文字で届くので、z と y は大文字も同じキーとみなす。\n */\nexport function resolveKeyAction(stroke: KeyStroke): KeyAction | null {\n const mod = stroke.metaKey || stroke.ctrlKey;\n const key = stroke.key.toLowerCase();\n if (stroke.key === \"Escape\") {\n return \"cancel-interaction\";\n }\n if (stroke.key === \"Enter\") {\n return \"commit-line\";\n }\n if (mod && key === \"z\") {\n return stroke.shiftKey ? \"redo\" : \"undo\";\n }\n if (mod && key === \"y\") {\n return \"redo\";\n }\n return null;\n}\n","// 配置は presets/alignments.ts にあり、隊形のプリセットと共有する。middle ゾーンの窓(LOS の前後\n// 15 ヤード)に収まる。ルート、ブロック、モーションを持つのは主役の側だけで、相手の側は選手の\n// 配置だけを持つ。\n//\n// 線の決まり。ブロックの終点は相手の 1 ヤード手前(shortOf)に置き、T 字のバーが相手のマーカーの\n// 縁に付く。コンボブロックは一方が相手の手前で止まり、もう一方が相手の肩(beside)を経由して LB の\n// 手前へ上がる。穴をリードするプルは相手ではなく穴を狙うので座標で書く。走路とプルは、他の選手の\n// マーカーの中心から 1 ヤード以上離す(OL の間隔が 2.5 ヤードなので、ギャップを通る線は縁に\n// 触れる)。守備のラッシュは LOS(0)で止め、ゾーンのドロップは LOS から離れる向き(+)へ描く。\n\nimport type { Line, LineInterpolation, LineKind } from \"../model/line.js\";\nimport { CURRENT_PLAY_DATA_VERSION, fieldStateForZone } from \"../model/play-data.js\";\nimport type { FieldPosition, Player } from \"../model/player.js\";\nimport {\n beside,\n cornerSpots,\n defense43,\n END_OVER_TE,\n FRONT_4,\n iFormation,\n LB_43,\n LB_NICKEL,\n NICKEL_BASE,\n type NickelShell,\n nickel,\n nickelFront,\n offensiveLine,\n player,\n pt,\n shortOf,\n shotgunSpread,\n singlebackAce,\n trips,\n} from \"../presets/alignments.js\";\nimport { deepFreeze, type TeamSide } from \"../presets/shared.js\";\nimport type { PlayCategory, PlayPreset } from \"./play-preset.js\";\n\n/** 色は持たせず、テーマの既定の色で描く。攻守の見分けは選手の形とラベルで付ける。 */\nfunction ln(\n id: string,\n kind: LineKind,\n startPlayerId: string,\n waypoints: FieldPosition[],\n end: FieldPosition,\n interpolation: LineInterpolation,\n): Line {\n return { id, kind, startPlayerId, waypoints, end, interpolation };\n}\n\nfunction play(\n id: string,\n name: string,\n side: TeamSide,\n category: PlayCategory,\n personnel: string,\n summary: string,\n players: Player[],\n lines: Line[],\n): PlayPreset {\n return {\n id,\n name,\n side,\n category,\n personnel,\n summary,\n data: {\n version: CURRENT_PLAY_DATA_VERSION,\n field: fieldStateForZone(\"middle\"),\n players,\n lines,\n },\n };\n}\n\n// オフェンスのプレーに添える守備のうち、CB の深さとセイフティの置き方がカバレッジで変わるもの。\nconst COVER_2_SHELL = { cornerDepth: 5, fs: pt(18, 12), ss: pt(35, 12) } satisfies NickelShell;\nconst COVER_3_SHELL = { cornerDepth: 7, fs: pt(26.5, 12), ss: pt(34, 6) } satisfies NickelShell;\n\nconst INSIDE_ZONE = play(\n \"play-inside-zone\",\n \"Inside Zone\",\n \"offense\",\n \"run-zone\",\n \"11 pers\",\n \"ゾーンブロックで内側を一気に。RB は RG の内側を狙い、3 テクの動きで B ギャップか裏の A ギャップへ切る。\",\n [\n ...offensiveLine(),\n player(\"y\", \"Y\", pt(34.5, -1), \"square\"),\n player(\"qb\", \"QB\", pt(26.5, -5)),\n player(\"rb\", \"RB\", pt(24, -5)),\n player(\"x\", \"X\", pt(6, -1)),\n player(\"h\", \"H\", pt(40, -2)),\n player(\"z\", \"Z\", pt(47, -1)),\n ...defense43(),\n ],\n [\n ln(\"bl-lt\", \"block\", \"lt\", [], shortOf(FRONT_4.eL), \"straight\"),\n ln(\"bl-lg\", \"block\", \"lg\", [], shortOf(FRONT_4.n), \"straight\"),\n ln(\"bl-c\", \"block\", \"c\", [beside(FRONT_4.n, 1)], shortOf(LB_43.m), \"bezier\"),\n ln(\"bl-rg\", \"block\", \"rg\", [], shortOf(FRONT_4.t), \"straight\"),\n ln(\"bl-rt\", \"block\", \"rt\", [beside(FRONT_4.t, 1.5)], shortOf(LB_43.s), \"bezier\"),\n ln(\"bl-y\", \"block\", \"y\", [], shortOf(END_OVER_TE), \"straight\"),\n ln(\"run-rb\", \"route\", \"rb\", [pt(27.5, -2)], pt(28, 3.5), \"bezier\"),\n ],\n);\n\nconst OUTSIDE_ZONE = play(\n \"play-outside-zone\",\n \"Outside Zone\",\n \"offense\",\n \"run-zone\",\n \"11 pers\",\n \"ワイドゾーンで横へ伸ばす。RB は TE の外側を狙い、E と S の動きで外へ出るか縦に切り返す。\",\n [...singlebackAce(), ...defense43()],\n [\n ln(\"bl-lt\", \"block\", \"lt\", [], shortOf(FRONT_4.eL), \"straight\"),\n ln(\"bl-lg\", \"block\", \"lg\", [], shortOf(FRONT_4.n), \"straight\"),\n ln(\"bl-c\", \"block\", \"c\", [beside(FRONT_4.n, 1)], shortOf(LB_43.m, 0.5), \"bezier\"),\n ln(\"bl-rg\", \"block\", \"rg\", [], shortOf(FRONT_4.t, 0.5), \"straight\"),\n ln(\"bl-rt\", \"block\", \"rt\", [beside(FRONT_4.t, 1.5)], shortOf(LB_43.s, 0.5), \"bezier\"),\n ln(\"bl-y\", \"block\", \"y\", [], shortOf(END_OVER_TE, 0.5), \"straight\"),\n ln(\"run-rb\", \"route\", \"rb\", [pt(31, -5), pt(35.5, -2)], pt(37.5, 3), \"bezier\"),\n ],\n);\n\nconst POWER = play(\n \"play-power\",\n \"Power\",\n \"offense\",\n \"run-gap\",\n \"21 pers\",\n \"プレイサイドはダウンブロック、FB が 9 テクの E をキックアウト、バックサイドガードがプルして C ギャップをリードする。\",\n [...iFormation(), ...defense43()],\n [\n ln(\"bl-y\", \"block\", \"y\", [], shortOf(LB_43.s), \"straight\"),\n ln(\"bl-rt\", \"block\", \"rt\", [], shortOf(FRONT_4.t, 0.5), \"straight\"),\n ln(\"bl-rg\", \"block\", \"rg\", [beside(FRONT_4.t, -1.5)], shortOf(LB_43.m), \"bezier\"),\n ln(\"bl-c\", \"block\", \"c\", [], shortOf(FRONT_4.n), \"straight\"),\n ln(\"bl-lt\", \"block\", \"lt\", [], shortOf(FRONT_4.eL), \"straight\"),\n ln(\n \"lead-fb\",\n \"block\",\n \"fb\",\n [pt(31, -3.5), pt(33.5, -0.5)],\n shortOf(END_OVER_TE, -0.5),\n \"bezier\",\n ),\n ln(\n \"pull-lg\",\n \"block\",\n \"lg\",\n [pt(25, -4), pt(31, -4), pt(32.5, -2), pt(32.5, 1)],\n pt(31.5, 3.5),\n \"bezier\",\n ),\n ln(\"run-rb\", \"route\", \"rb\", [pt(30, -6), pt(33, -3)], pt(33.5, 4), \"bezier\"),\n ],\n);\n\nconst COUNTER = play(\n \"play-counter\",\n \"Counter (GT)\",\n \"offense\",\n \"run-gap\",\n \"21 pers\",\n \"バックサイドのガードが 9 テクの E をキックアウト、タックルが C ギャップへ巻き込み、FB がタックルの跡を埋める(GT カウンター)。\",\n [...iFormation(), ...defense43()],\n [\n ln(\"bl-y\", \"block\", \"y\", [], shortOf(LB_43.s), \"straight\"),\n ln(\"bl-rt\", \"block\", \"rt\", [], shortOf(FRONT_4.t, 0.5), \"straight\"),\n ln(\"bl-rg\", \"block\", \"rg\", [beside(FRONT_4.t, -1.5)], shortOf(LB_43.m), \"bezier\"),\n ln(\"bl-c\", \"block\", \"c\", [], shortOf(FRONT_4.n), \"straight\"),\n ln(\n \"pull-lg\",\n \"block\",\n \"lg\",\n [pt(25, -4), pt(32, -4), pt(33.5, -0.5)],\n shortOf(END_OVER_TE, -0.5),\n \"straight\",\n ),\n ln(\n \"pull-lt\",\n \"block\",\n \"lt\",\n [pt(23, -5), pt(31, -5), pt(32.5, -2), pt(32.5, 1)],\n pt(31.5, 3.5),\n \"straight\",\n ),\n ln(\"fill-fb\", \"block\", \"fb\", [pt(24, -3), pt(22.5, -0.5)], shortOf(FRONT_4.eL, 1), \"bezier\"),\n ln(\"run-rb\", \"route\", \"rb\", [pt(24, -7.5), pt(30, -6.5), pt(33, -3)], pt(33.5, 4), \"bezier\"),\n ],\n);\n\nconst FOUR_VERTICALS = play(\n \"play-four-verticals\",\n \"Four Verticals\",\n \"offense\",\n \"pass-deep\",\n \"10 pers\",\n \"トリップスから 4 本の縦。対シングルハイのシームで勝負する。\",\n [...trips(), ...nickel(COVER_3_SHELL, END_OVER_TE)],\n [\n ln(\"go-x\", \"route\", \"x\", [pt(4, 4)], pt(4, 13), \"straight\"),\n ln(\"seam-y\", \"route\", \"y\", [pt(33, 5)], pt(31, 13), \"bezier\"),\n ln(\"seam-h\", \"route\", \"h\", [pt(40, 5)], pt(38, 13), \"bezier\"),\n ln(\"go-z\", \"route\", \"z\", [pt(49, 4)], pt(49, 13), \"straight\"),\n ln(\"chk-rb\", \"route\", \"rb\", [], pt(20, -3), \"straight\"),\n ],\n);\n\nconst MESH = play(\n \"play-mesh\",\n \"Mesh\",\n \"offense\",\n \"pass-dropback\",\n \"10 pers\",\n \"浅いクロスの交差。対マン/ゾーン両対応で空いた所へ運ぶ。\",\n [...shotgunSpread(), ...nickel(NICKEL_BASE)],\n [\n ln(\"cross-y\", \"route\", \"y\", [pt(20, 3.5)], pt(38, 4), \"straight\"),\n ln(\"cross-h\", \"route\", \"h\", [pt(33, 3)], pt(15, 3.5), \"straight\"),\n ln(\"corner-x\", \"route\", \"x\", [pt(5, 5)], pt(2, 9), \"bezier\"),\n ln(\"sit-z\", \"route\", \"z\", [], pt(47, 5), \"straight\"),\n ln(\"swing-rb\", \"route\", \"rb\", [pt(33, -4)], pt(41, -3), \"straight\"),\n ],\n);\n\nconst SMASH = play(\n \"play-smash\",\n \"Smash\",\n \"offense\",\n \"pass-dropback\",\n \"11 pers\",\n \"コーナー+ヒッチのハイロー。対カバー 2 のコーナーを攻める。\",\n [...singlebackAce(), ...nickel(COVER_2_SHELL, END_OVER_TE)],\n [\n ln(\"hitch-z\", \"route\", \"z\", [], pt(47, 3), \"straight\"),\n ln(\"corner-h\", \"route\", \"h\", [pt(41, 4)], pt(46, 10), \"bezier\"),\n ln(\"dig-y\", \"route\", \"y\", [pt(34.5, 8)], pt(27, 9), \"straight\"),\n ln(\"hitch-x\", \"route\", \"x\", [], pt(6, 3), \"straight\"),\n ln(\"flat-rb\", \"route\", \"rb\", [], pt(22, -4), \"straight\"),\n ],\n);\n\nconst STICK = play(\n \"play-stick\",\n \"Stick\",\n \"offense\",\n \"pass-quick\",\n \"11 pers\",\n \"3 ステップの速攻。スティック(座り)+フラットで素早く配球する。\",\n [...singlebackAce(), ...nickel(NICKEL_BASE, END_OVER_TE)],\n [\n ln(\"stick-y\", \"route\", \"y\", [], pt(34.5, 4), \"straight\"),\n ln(\"flat-h\", \"route\", \"h\", [], pt(45, 0), \"straight\"),\n ln(\"hitch-z\", \"route\", \"z\", [], pt(47, 3), \"straight\"),\n ln(\"slant-x\", \"route\", \"x\", [pt(6, 2)], pt(10, 3), \"bezier\"),\n ln(\"chk-rb\", \"route\", \"rb\", [], pt(21, -5), \"straight\"),\n ],\n);\n\nconst RPO_BUBBLE = play(\n \"play-rpo-bubble\",\n \"RPO (IZ + Bubble)\",\n \"offense\",\n \"rpo\",\n \"11 pers\",\n \"バブル側の W を読み、W がボックスに入ればバブル、残ればインサイドゾーンへ分岐する。\",\n [...shotgunSpread(), ...nickel(NICKEL_BASE)],\n [\n ln(\"bl-lt\", \"block\", \"lt\", [], shortOf(FRONT_4.eL), \"straight\"),\n ln(\"bl-lg\", \"block\", \"lg\", [beside(FRONT_4.n, -1)], shortOf(LB_NICKEL.m), \"bezier\"),\n ln(\"bl-c\", \"block\", \"c\", [], shortOf(FRONT_4.n), \"straight\"),\n ln(\"bl-rg\", \"block\", \"rg\", [], shortOf(FRONT_4.t), \"straight\"),\n ln(\"bl-rt\", \"block\", \"rt\", [], shortOf(FRONT_4.eR), \"straight\"),\n ln(\"run-rb\", \"route\", \"rb\", [pt(26, -2.5)], pt(23, 3), \"straight\"),\n ln(\"bubble-h\", \"route\", \"h\", [pt(43, -3)], pt(46, -0.5), \"bezier\"),\n ln(\"bl-z\", \"block\", \"z\", [], shortOf(cornerSpots(NICKEL_BASE.cornerDepth).right), \"straight\"),\n ln(\"glance-y\", \"route\", \"y\", [pt(15, 1)], pt(19, 3), \"bezier\"),\n ],\n);\n\nconst PA_BOOT = play(\n \"play-pa-boot\",\n \"PA Boot (Sail)\",\n \"offense\",\n \"pa\",\n \"11 pers\",\n \"プレイアクションで QB がブートし、フラット/セイル/縦の 3 段で攻める。\",\n [...singlebackAce(), ...defense43()],\n [\n ln(\"fake-rb\", \"motion\", \"rb\", [pt(24, -6)], pt(20.5, -4.5), \"straight\"),\n ln(\"boot-qb\", \"route\", \"qb\", [pt(31, -4)], pt(36.5, -5), \"bezier\"),\n ln(\"bl-lt\", \"block\", \"lt\", [], shortOf(FRONT_4.eL), \"straight\"),\n ln(\"bl-c\", \"block\", \"c\", [], shortOf(FRONT_4.n), \"straight\"),\n ln(\"bl-rg\", \"block\", \"rg\", [], shortOf(FRONT_4.t), \"straight\"),\n ln(\"flat-y\", \"route\", \"y\", [pt(37, -0.5)], pt(43, 0.5), \"bezier\"),\n ln(\"sail-h\", \"route\", \"h\", [pt(41, 3)], pt(46, 8), \"bezier\"),\n ln(\"go-z\", \"route\", \"z\", [pt(49, 3)], pt(49, 13), \"straight\"),\n ln(\"comeback-x\", \"route\", \"x\", [pt(5, 9)], pt(7.5, 7.5), \"bezier\"),\n ],\n);\n\nconst COVER_1 = play(\n \"play-cover-1\",\n \"Cover 1 (Man Free)\",\n \"defense\",\n \"coverage\",\n \"Nickel\",\n \"1 ディープのフリーセイフティを残し、残りは全マン。W は穴(ラット)で待つ。\",\n [...nickel({ cornerDepth: 6, fs: pt(26.5, 11), ss: pt(38, 6) }), ...shotgunSpread()],\n [\n ln(\"man-cbl\", \"motion\", \"cb-l\", [], pt(5.5, 0.5), \"straight\"),\n ln(\"man-cbr\", \"motion\", \"cb-r\", [], pt(47.5, 0.5), \"straight\"),\n ln(\"man-nb\", \"motion\", \"nb\", [], pt(13, -0.5), \"straight\"),\n ln(\"man-ss\", \"motion\", \"ss\", [], pt(40, -0.5), \"straight\"),\n ln(\"man-mlb\", \"motion\", \"mlb\", [pt(27.5, 2.5), pt(27.5, -2.5)], pt(29, -3.5), \"straight\"),\n ln(\"rat-wlb\", \"motion\", \"wlb\", [], pt(27.5, 3.5), \"straight\"),\n ln(\"free-fs\", \"motion\", \"fs\", [], pt(26.5, 13), \"straight\"),\n ],\n);\n\nconst COVER_2 = play(\n \"play-cover-2\",\n \"Cover 2\",\n \"defense\",\n \"coverage\",\n \"Nickel\",\n \"2 ディープ 5 アンダーのゾーン。深いハーフを 2 人で分け、CB はフラットに座る。\",\n [...nickel({ cornerDepth: 5, fs: pt(15, 11), ss: pt(38, 11) }), ...shotgunSpread()],\n [\n ln(\"half-fs\", \"motion\", \"fs\", [], pt(13, 14), \"straight\"),\n ln(\"half-ss\", \"motion\", \"ss\", [], pt(40, 14), \"straight\"),\n ln(\"flat-cbl\", \"motion\", \"cb-l\", [], pt(9.5, 4), \"straight\"),\n ln(\"flat-cbr\", \"motion\", \"cb-r\", [], pt(43.5, 4), \"straight\"),\n ln(\"hook-mlb\", \"motion\", \"mlb\", [], pt(21.5, 10), \"straight\"),\n ln(\"hook-wlb\", \"motion\", \"wlb\", [], pt(32.5, 10), \"straight\"),\n ln(\"curl-nb\", \"motion\", \"nb\", [], pt(16, 9), \"straight\"),\n ],\n);\n\nconst COVER_3 = play(\n \"play-cover-3\",\n \"Cover 3\",\n \"defense\",\n \"coverage\",\n \"Nickel\",\n \"3 ディープ 4 アンダー。現代の基準となるシングルハイのゾーン。\",\n [...nickel(COVER_3_SHELL), ...shotgunSpread()],\n [\n ln(\"deep-cbl\", \"motion\", \"cb-l\", [], pt(7, 13), \"straight\"),\n ln(\"deep-cbr\", \"motion\", \"cb-r\", [], pt(46, 13), \"straight\"),\n ln(\"deep-fs\", \"motion\", \"fs\", [], pt(26.5, 14), \"straight\"),\n ln(\"curl-nb\", \"motion\", \"nb\", [], pt(15.5, 9), \"straight\"),\n ln(\"hook-mlb\", \"motion\", \"mlb\", [], pt(22, 10), \"straight\"),\n ln(\"hook-wlb\", \"motion\", \"wlb\", [], pt(31, 10), \"straight\"),\n ln(\"flat-ss\", \"motion\", \"ss\", [], pt(39, 4), \"straight\"),\n ],\n);\n\nconst COVER_4 = play(\n \"play-cover-4\",\n \"Cover 4 (Quarters)\",\n \"defense\",\n \"coverage\",\n \"Nickel\",\n \"4 ディープのクォーターズ。縦パスを上から踏み潰す。\",\n [...nickel({ cornerDepth: 7, fs: pt(20, 11), ss: pt(33, 11) }), ...shotgunSpread()],\n [\n ln(\"qtr-cbl\", \"motion\", \"cb-l\", [], pt(6, 13), \"straight\"),\n ln(\"qtr-cbr\", \"motion\", \"cb-r\", [], pt(47, 13), \"straight\"),\n ln(\"qtr-fs\", \"motion\", \"fs\", [], pt(18, 14), \"straight\"),\n ln(\"qtr-ss\", \"motion\", \"ss\", [], pt(35, 14), \"straight\"),\n ln(\"under-nb\", \"motion\", \"nb\", [], pt(16, 8), \"straight\"),\n ln(\"under-mlb\", \"motion\", \"mlb\", [], pt(23, 9), \"straight\"),\n ln(\"under-wlb\", \"motion\", \"wlb\", [], pt(31, 9), \"straight\"),\n ],\n);\n\nconst FIRE_ZONE = play(\n \"play-fire-zone\",\n \"Fire Zone\",\n \"defense\",\n \"pressure\",\n \"Nickel\",\n \"5 人ブリッツ+ライン 1 枚をドロップ、3 ディープ 3 アンダーで覆う。\",\n [...nickel(COVER_3_SHELL), ...shotgunSpread()],\n [\n ln(\"rush-dtl\", \"route\", \"dt-l\", [], pt(25, 0), \"straight\"),\n ln(\"rush-dtr\", \"route\", \"dt-r\", [], pt(28.5, 0), \"straight\"),\n ln(\"rush-der\", \"route\", \"de-r\", [], pt(33, 0), \"straight\"),\n ln(\"blz-wlb\", \"route\", \"wlb\", [pt(31.5, 2.5)], pt(31, 0), \"bezier\"),\n ln(\"blz-nb\", \"route\", \"nb\", [pt(17, 2.5)], pt(20, 0), \"bezier\"),\n ln(\"drop-del\", \"motion\", \"de-l\", [pt(19, 4)], pt(17, 7), \"straight\"),\n ln(\"deep-cbl\", \"motion\", \"cb-l\", [], pt(7, 13), \"straight\"),\n ln(\"deep-cbr\", \"motion\", \"cb-r\", [], pt(46, 13), \"straight\"),\n ln(\"deep-fs\", \"motion\", \"fs\", [], pt(26.5, 14), \"straight\"),\n ln(\"hook-mlb\", \"motion\", \"mlb\", [], pt(23, 9), \"straight\"),\n ln(\"flat-ss\", \"motion\", \"ss\", [], pt(39, 4), \"straight\"),\n ],\n);\n\nconst COVER_0 = play(\n \"play-cover-0\",\n \"Cover 0 Blitz\",\n \"defense\",\n \"pressure\",\n \"Nickel\",\n \"セイフティを残さず全マン、6 人で最大限の圧力をかける。FS が RB をマンで受け持つ。\",\n [...nickel({ cornerDepth: 5, fs: pt(22, 9), ss: pt(31, 9) }), ...shotgunSpread()],\n [\n ln(\"rush-del\", \"route\", \"de-l\", [], pt(20, 0), \"straight\"),\n ln(\"rush-dtl\", \"route\", \"dt-l\", [], pt(25, 0), \"straight\"),\n ln(\"rush-dtr\", \"route\", \"dt-r\", [], pt(30.5, 0), \"straight\"),\n ln(\"rush-der\", \"route\", \"de-r\", [], pt(33, 0), \"straight\"),\n ln(\"blz-mlb\", \"route\", \"mlb\", [pt(27, 2.5)], pt(27.5, 0), \"bezier\"),\n ln(\"blz-wlb\", \"route\", \"wlb\", [pt(31.5, 2.5)], pt(31, 0), \"bezier\"),\n ln(\"man-cbl\", \"motion\", \"cb-l\", [], pt(5.5, 0.5), \"straight\"),\n ln(\"man-cbr\", \"motion\", \"cb-r\", [], pt(47.5, 0.5), \"straight\"),\n ln(\"man-nb\", \"motion\", \"nb\", [], pt(13, -0.5), \"straight\"),\n ln(\"man-fs\", \"motion\", \"fs\", [pt(22, 2.5), pt(23, -2.5)], pt(28, -4), \"straight\"),\n ln(\"man-ss\", \"motion\", \"ss\", [pt(37, 4)], pt(39.5, -0.5), \"straight\"),\n ],\n);\n\n// 両 A ギャップに LB を立てるので、DT は 2 人とも 3 テクに広がる。\nconst DOUBLE_A = play(\n \"play-double-a\",\n \"Double-A Gap\",\n \"defense\",\n \"pressure\",\n \"Nickel\",\n \"両 A ギャップに 2 人を提示。実行・シム(見せ)どちらにも化ける。\",\n [\n player(\"de-l\", \"E\", FRONT_4.eL),\n player(\"dt-l\", \"T\", pt(23, 1.5)),\n player(\"dt-r\", \"T\", FRONT_4.t),\n player(\"de-r\", \"E\", FRONT_4.eR),\n player(\"mlb\", \"M\", pt(25.5, 3)),\n player(\"wlb\", \"W\", pt(27.5, 3)),\n player(\"nb\", \"NB\", LB_NICKEL.nb),\n player(\"cb-l\", \"CB\", cornerSpots(7).left),\n player(\"cb-r\", \"CB\", cornerSpots(7).right),\n player(\"fs\", \"FS\", COVER_3_SHELL.fs),\n player(\"ss\", \"SS\", COVER_3_SHELL.ss),\n ...shotgunSpread(),\n ],\n [\n ln(\"aim-mlb\", \"route\", \"mlb\", [], pt(25.5, 0.5), \"straight\"),\n ln(\"aim-wlb\", \"route\", \"wlb\", [], pt(27.5, 0.5), \"straight\"),\n ln(\"rush-del\", \"route\", \"de-l\", [], pt(20, 0), \"straight\"),\n ln(\"rush-dtl\", \"route\", \"dt-l\", [], pt(22.5, 0), \"straight\"),\n ln(\"rush-dtr\", \"route\", \"dt-r\", [], pt(30.5, 0), \"straight\"),\n ln(\"rush-der\", \"route\", \"de-r\", [], pt(33, 0), \"straight\"),\n ln(\"bail-cbl\", \"motion\", \"cb-l\", [], pt(7, 12), \"straight\"),\n ln(\"bail-cbr\", \"motion\", \"cb-r\", [], pt(46, 12), \"straight\"),\n ln(\"deep-fs\", \"motion\", \"fs\", [], pt(26.5, 14), \"straight\"),\n ln(\"curl-nb\", \"motion\", \"nb\", [], pt(15.5, 9), \"straight\"),\n ln(\"flat-ss\", \"motion\", \"ss\", [], pt(39, 4), \"straight\"),\n ],\n);\n\n// フィールド側(右)はクォーターズ、バウンダリ側(左)はカバー 2 なので、CB の深さが左右で違い、\n// ニッケルバックはフィールド側のスロットに付く。\nconst COVER_6 = play(\n \"play-cover-6\",\n \"Cover 6\",\n \"defense\",\n \"coverage\",\n \"Nickel\",\n \"クォーター×2+ハーフの分割カバー。フィールドはクォーターズ、バウンダリは 2。\",\n [\n ...nickelFront(),\n player(\"nb\", \"NB\", pt(39, 5)),\n player(\"cb-l\", \"CB\", cornerSpots(5).left),\n player(\"cb-r\", \"CB\", cornerSpots(7).right),\n player(\"fs\", \"FS\", pt(15, 11)),\n player(\"ss\", \"SS\", pt(35, 10)),\n ...shotgunSpread(),\n ],\n [\n ln(\"flat-cbl\", \"motion\", \"cb-l\", [], pt(10, 4), \"straight\"),\n ln(\"half-fs\", \"motion\", \"fs\", [], pt(12, 14), \"straight\"),\n ln(\"qtr-cbr\", \"motion\", \"cb-r\", [], pt(47, 13), \"straight\"),\n ln(\"qtr-ss\", \"motion\", \"ss\", [], pt(38, 14), \"straight\"),\n ln(\"curl-nb\", \"motion\", \"nb\", [], pt(41, 9), \"straight\"),\n ln(\"hook-mlb\", \"motion\", \"mlb\", [], pt(22, 10), \"straight\"),\n ln(\"hook-wlb\", \"motion\", \"wlb\", [], pt(31, 10), \"straight\"),\n ],\n);\n\nexport const PLAY_PRESETS: readonly PlayPreset[] = /* @__PURE__ */ deepFreeze([\n INSIDE_ZONE,\n OUTSIDE_ZONE,\n POWER,\n COUNTER,\n FOUR_VERTICALS,\n MESH,\n SMASH,\n STICK,\n RPO_BUBBLE,\n PA_BOOT,\n COVER_1,\n COVER_2,\n COVER_3,\n COVER_4,\n FIRE_ZONE,\n COVER_0,\n DOUBLE_A,\n COVER_6,\n]);\n\nexport function getPlayPreset(id: string): PlayPreset | undefined {\n return PLAY_PRESETS.find((p) => p.id === id);\n}\n","import {\n Disposable,\n type FieldPosition,\n type IEditorActions,\n type IEditorGestures,\n type IEditorScene,\n resolveKeyAction,\n toDisposable,\n} from \"../../common/index.js\";\n\n/** ポインタを受ける canvas と、その上の位置をフィールドのヤードの位置に変える手段。 */\nexport interface IPointerSurface {\n readonly canvas: HTMLCanvasElement;\n clientToYard(clientX: number, clientY: number): FieldPosition;\n}\n\n// フォーム部品に来たキーは、その部品の標準動作(テキストの Undo など)に任せる。\nfunction isFormControl(target: EventTarget | null): boolean {\n return (\n target instanceof HTMLInputElement ||\n target instanceof HTMLSelectElement ||\n target instanceof HTMLTextAreaElement\n );\n}\n\nexport class PointerInput extends Disposable {\n /**\n * @param root ショートカットを受ける要素。ツールバーのボタンを押した直後でも\n * Cmd+Z が効くよう、canvas ではなく UI 全体を包む要素に付ける。\n */\n constructor(\n root: HTMLElement,\n surface: IPointerSurface,\n controller: IEditorGestures & IEditorActions & Pick<IEditorScene, \"getViewState\">,\n ) {\n super();\n const canvas = surface.canvas;\n // canvas は既定でフォーカスを受けないので、Esc、Enter、Undo と Redo のキーが届かない。\n canvas.tabIndex = 0;\n\n const toYard = (e: PointerEvent) => surface.clientToYard(e.clientX, e.clientY);\n // 押下中のポインタ。これ以外(2 本目の指、右ボタン)の up や cancel は無視する。\n let activePointerId: number | null = null;\n\n const onPointerDown = (e: PointerEvent) => {\n if (e.button !== 0 || !e.isPrimary) {\n return;\n }\n activePointerId = e.pointerId;\n // フォーカスでページがスクロールすると、押した位置と canvas がずれる。\n canvas.focus({ preventScroll: true });\n canvas.setPointerCapture(e.pointerId);\n controller.pointerDown(toYard(e));\n };\n // 作図中の線は、ボタンを押していなくてもポインタに付いてくるので、移動は押下の有無によらず渡す。\n const onPointerMove = (e: PointerEvent) => {\n if (e.isPrimary) {\n controller.pointerMove(toYard(e));\n }\n };\n // 押下中のポインタの終わりなら控えを消して true。up の直後にブラウザが capture を外して\n // lostpointercapture を出すので、up で先に消しておき、それを中断と取り違えない。\n const endPress = (e: PointerEvent): boolean => {\n if (e.pointerId !== activePointerId) {\n return false;\n }\n activePointerId = null;\n return true;\n };\n const onPointerUp = (e: PointerEvent) => {\n if (endPress(e)) {\n controller.pointerUp(toYard(e));\n }\n };\n // タッチのスクロール開始やウィンドウ切替で up が来ないまま終わった押下。\n // 放っておくとドラッグが外れず、次の移動で選手がついてくる。\n // 作図は押下をまたいで続く操作なので、1 回の押下の中断で打った点まで捨てない。\n const onPointerAbort = (e: PointerEvent) => {\n if (endPress(e) && !controller.getViewState().isDrawing) {\n controller.cancelInteraction();\n }\n };\n const onDoubleClick = () => controller.commitLine();\n const onKeyDown = (e: KeyboardEvent) => {\n if (isFormControl(e.target)) {\n return;\n }\n switch (resolveKeyAction(e)) {\n case \"cancel-interaction\":\n controller.cancelInteraction();\n return;\n case \"commit-line\":\n // ボタン上の Enter はそのボタンを押す操作なので、作図の確定と二重にしない。\n if (!(e.target instanceof HTMLButtonElement)) {\n controller.commitLine();\n }\n return;\n case \"undo\":\n e.preventDefault();\n controller.undo();\n return;\n case \"redo\":\n e.preventDefault();\n controller.redo();\n return;\n case null:\n return;\n }\n };\n\n const listeners = new AbortController();\n const { signal } = listeners;\n canvas.addEventListener(\"pointerdown\", onPointerDown, { signal });\n canvas.addEventListener(\"pointermove\", onPointerMove, { signal });\n canvas.addEventListener(\"pointerup\", onPointerUp, { signal });\n canvas.addEventListener(\"pointercancel\", onPointerAbort, { signal });\n canvas.addEventListener(\"lostpointercapture\", onPointerAbort, { signal });\n canvas.addEventListener(\"dblclick\", onDoubleClick, { signal });\n root.addEventListener(\"keydown\", onKeyDown, { signal });\n this._register(\n toDisposable(() => {\n listeners.abort();\n canvas.removeAttribute(\"tabindex\");\n }),\n );\n }\n}\n","export default \"data:font/woff2;base64,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\"","// ヤード数字と選手ラベルは同梱のフォントに固定し、テーマでは差し替えさせない。\n// ctx.font は CSS の var() を解釈できないので、変数ではなくこの定数から組み立てる。\n// 名前はホストのページのフォントと重ならないよう、ライブラリ専用にしてある。\nexport const FIELD_FONT_NAME = \"Playmaker Saira\";\nexport const FIELD_FONT_WEIGHT = 700;\nexport const FIELD_FONT_FAMILY = `\"${FIELD_FONT_NAME}\", sans-serif`;\n\n/** 同梱フォントで sizePx の大きさに描く、ctx.font の値。 */\nexport function fieldFont(sizePx: number): string {\n return `${FIELD_FONT_WEIGHT} ${sizePx}px ${FIELD_FONT_FAMILY}`;\n}\n","// 元のフォントは Saira Condensed Bold(SIL OFL 1.1、library/assets/fonts/OFL.txt)。作り直すには make font。\nimport fontUrl from \"../../assets/playmaker-saira-subset.woff2\";\nimport { FIELD_FONT_NAME, FIELD_FONT_WEIGHT } from \"./field-font.js\";\n\nlet loaded: Promise<void> | undefined;\n\n/**\n * 同梱フォントを document.fonts に登録し、読み込み終えたら解決する。何度呼んでも登録は 1 回だけ。\n * CSS の @font-face で宣言すると、ホストが CSS を読み込むまでフォントが見えず、\n * その間に描いた数字とラベルは代わりのフォントになる。\n * 読み込めなくても代わりのフォントで描けるので、reject しない。\n */\nexport function loadFieldFont(): Promise<void> {\n loaded ??= registerFieldFont();\n return loaded;\n}\n\nasync function registerFieldFont(): Promise<void> {\n try {\n const face = new FontFace(FIELD_FONT_NAME, `url(\"${fontUrl}\")`, {\n weight: String(FIELD_FONT_WEIGHT),\n });\n document.fonts.add(face);\n await face.load();\n } catch {\n // 代わりのフォントのまま描く。\n }\n}\n","/** 色を読むためだけの 2D コンテキスト。確保できなかったことも覚えておき、毎回作り直さない。 */\ntype ColorContext =\n | { readonly status: \"unresolved\" }\n | { readonly status: \"unavailable\" }\n | { readonly status: \"ready\"; readonly ctx: CanvasRenderingContext2D };\n\nlet context: ColorContext = { status: \"unresolved\" };\n\nfunction resolveContext(): ColorContext {\n if (context.status === \"unresolved\") {\n const ctx = document.createElement(\"canvas\").getContext(\"2d\");\n context = ctx === null ? { status: \"unavailable\" } : { status: \"ready\", ctx };\n }\n return context;\n}\n\n/**\n * CSS の色を、canvas の fillStyle が返す書式にそろえる。\n * 書き方が違っても同じ色なら同じ文字列になり、不透明な色は `#rrggbb` の小文字になる。\n * 色として読めない値は undefined を返す。2D コンテキストを確保できないときは、値をそのまま返す。\n */\nexport function normalizeCssColor(value: string): string | undefined {\n const resolved = resolveContext();\n if (resolved.status !== \"ready\") {\n return value;\n }\n const { ctx } = resolved;\n // 読めない値を代入しても、fillStyle は前の値のまま残る。\n // 違う色から 2 回代入し、結果が揃えば読めた色とみなす。\n ctx.fillStyle = \"#000000\";\n ctx.fillStyle = value;\n const fromBlack = ctx.fillStyle;\n ctx.fillStyle = \"#ffffff\";\n ctx.fillStyle = value;\n return typeof fromBlack === \"string\" && ctx.fillStyle === fromBlack ? fromBlack : undefined;\n}\n","// Material Design のパレット。配色の考え方は docs/design.md の「テーマ」にある。\nconst WHITE = \"#ffffff\";\nconst BLACK = \"#212121\";\nconst RED = \"#d32f2f\";\nconst BLUE = \"#1976d2\";\nconst GREEN = \"#388e3c\";\nconst ORANGE = \"#ff9800\";\nconst GREY_100 = \"#f5f5f5\";\nconst GREY_200 = \"#eeeeee\";\nconst GREY_400 = \"#bdbdbd\";\nconst GREY_500 = \"#9e9e9e\";\nconst GREY_700 = \"#616161\";\n\ninterface ThemeToken {\n readonly property: `--playmaker-${string}`;\n readonly fallback: string;\n}\n\n/**\n * Canvas に描く色のテーマ変数と、ホストが宣言していないときの既定値。\n * ツールバーとパネルの色は CSS だけで決まるので、ここには置かない。\n */\nexport const THEME_TOKENS = {\n fieldGrass: { property: \"--playmaker-field-grass\", fallback: WHITE },\n fieldOob: { property: \"--playmaker-field-oob\", fallback: GREY_200 },\n fieldEndzone: { property: \"--playmaker-field-endzone\", fallback: GREY_100 },\n fieldLine: { property: \"--playmaker-field-line\", fallback: GREY_500 },\n fieldNumber: { property: \"--playmaker-field-number\", fallback: GREY_400 },\n fieldGoalLine: { property: \"--playmaker-field-goal-line\", fallback: GREY_700 },\n fieldPylon: { property: \"--playmaker-field-pylon\", fallback: GREY_500 },\n fieldGoalpost: { property: \"--playmaker-field-goalpost\", fallback: GREY_500 },\n fieldGrid: { property: \"--playmaker-field-grid\", fallback: \"rgba(0, 0, 0, 0.1)\" },\n /** 色を省いた選手の色。枠線だけの選手では枠とラベル、塗りつぶした選手では塗りになる。 */\n playerColor: { property: \"--playmaker-player-color\", fallback: BLACK },\n /** 塗りつぶした選手のラベルの色。枠線だけの選手のラベルは選手の色で書く。 */\n playerLabel: { property: \"--playmaker-player-label\", fallback: WHITE },\n lineRoute: { property: \"--playmaker-line-route\", fallback: BLACK },\n lineBlock: { property: \"--playmaker-line-block\", fallback: BLACK },\n lineMotion: { property: \"--playmaker-line-motion\", fallback: BLACK },\n /** パネルで選手と線に選べる 4 色。 */\n swatch1: { property: \"--playmaker-swatch-1\", fallback: BLACK },\n swatch2: { property: \"--playmaker-swatch-2\", fallback: RED },\n swatch3: { property: \"--playmaker-swatch-3\", fallback: BLUE },\n swatch4: { property: \"--playmaker-swatch-4\", fallback: GREEN },\n selection: { property: \"--playmaker-selection\", fallback: ORANGE },\n selectionOutline: { property: \"--playmaker-selection-outline\", fallback: WHITE },\n} as const satisfies Record<string, ThemeToken>;\n\nexport type ThemeTokenName = keyof typeof THEME_TOKENS;\n\nexport type ThemeReader = (token: ThemeTokenName) => string;\n\n/** 変数の値を読む関数から ThemeReader を作る。値が空か空白だけのトークンは、既定値で描く。 */\nexport function themeReaderFrom(readProperty: (property: string) => string): ThemeReader {\n return (token) => {\n const { property, fallback } = THEME_TOKENS[token];\n const value = readProperty(property).trim();\n return value === \"\" ? fallback : value;\n };\n}\n","import { normalizeCssColor } from \"./css-color.js\";\nimport { THEME_TOKENS, type ThemeReader, themeReaderFrom } from \"./tokens.js\";\n\n/**\n * element で解決したテーマ変数を読む。canvas は var() を解釈できないので、描く前に具体的な色にする。\n * 変数は作った時点ですべて読むので、あとでホストが変数を変えても、この reader が返す色は変わらない。\n * 色は書き方をそろえて返し、色として読めない値は、宣言されていないものとして既定の色にする。\n */\nexport function createThemeReader(element: Element): ThemeReader {\n const styles = getComputedStyle(element);\n const values = new Map<string, string>();\n for (const { property } of Object.values(THEME_TOKENS)) {\n values.set(property, normalizeCssColor(styles.getPropertyValue(property).trim()) ?? \"\");\n }\n return themeReaderFrom((property) => values.get(property) ?? \"\");\n}\n","import {\n DEFAULT_FIELD_LEAGUE,\n displayYardNumber,\n FIELD_WIDTH_YARDS,\n type FieldGeometry,\n type FieldMetrics,\n HASH_CENTER_OFFSET_YARDS_BY_LEAGUE,\n YARD_LINE_INTERVAL_YARDS,\n yardLinesInWindow,\n} from \"../../common/index.js\";\nimport { fieldFont } from \"../theme/field-font.js\";\nimport type { ThemeReader } from \"../theme/tokens.js\";\nimport type { ILayerRenderer, RenderFrame } from \"./layer.js\";\n\ninterface FieldTheme {\n readonly fieldColor: string;\n /** サイドラインの外と、縦横比が合わない分の余白。 */\n readonly oobColor: string;\n readonly endzoneColor: string;\n readonly lineColor: string;\n readonly goalLineColor: string;\n readonly numberColor: string;\n readonly pylonColor: string;\n readonly goalpostColor: string;\n}\n\n/** 窓に映るフィールドの外枠(px)。サイドラインが left と right、窓の上下の端が top と bottom。 */\ninterface FieldBounds {\n readonly left: number;\n readonly right: number;\n readonly top: number;\n readonly bottom: number;\n}\n\n/** ゴールポストの柱を伸ばす向き。自陣のエンドゾーンは画面の下にあるので上へ、相手のは下へ伸ばす。 */\ntype UprightDirection = \"toward-top\" | \"toward-bottom\";\n\n// 数字の横に置く、近いほうのゴールを指す三角の寸法(ヤード)。数字より目立たないよう小さくする。\nconst ARROW_LENGTH_YARDS = 0.8;\nconst ARROW_HALF_WIDTH_YARDS = 0.3;\nconst ARROW_OFFSET_FROM_NUMBER_YARDS = 2.5;\n// 数字を置く、サイドラインからの距離。三角も同じ列に置いて縦に揃える。\nconst NUMBER_FROM_SIDELINE_YARDS = 6;\n// 2 桁の数字はヤードラインをまたいで置くので、本物のフィールドと同じく桁の間を空けてラインを通す。\nconst NUMBER_DIGIT_SPACING_PER_HEIGHT = 0.18;\n\nfunction fieldTheme(read: ThemeReader): FieldTheme {\n return {\n fieldColor: read(\"fieldGrass\"),\n oobColor: read(\"fieldOob\"),\n endzoneColor: read(\"fieldEndzone\"),\n lineColor: read(\"fieldLine\"),\n goalLineColor: read(\"fieldGoalLine\"),\n numberColor: read(\"fieldNumber\"),\n pylonColor: read(\"fieldPylon\"),\n goalpostColor: read(\"fieldGoalpost\"),\n };\n}\n\nexport class FieldRenderer implements ILayerRenderer {\n /** geometry の窓に従って、1 フレーム分のフィールドを描く。 */\n draw(ctx: CanvasRenderingContext2D, frame: RenderFrame): void {\n const { geometry, metrics } = frame;\n const theme = fieldTheme(frame.theme);\n const { viewportWidth, viewportHeight, yardWindow } = geometry;\n\n const bounds: FieldBounds = {\n left: geometry.xForLateralYard(0),\n right: geometry.xForLateralYard(FIELD_WIDTH_YARDS),\n top: geometry.yForAbsoluteYard(yardWindow.endYard),\n bottom: geometry.yForAbsoluteYard(yardWindow.startYard),\n };\n\n ctx.fillStyle = theme.oobColor;\n ctx.fillRect(0, 0, viewportWidth, viewportHeight);\n ctx.fillStyle = theme.fieldColor;\n ctx.fillRect(bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top);\n\n this.drawEndZones(ctx, geometry, bounds, theme);\n this.drawHashes(ctx, geometry, bounds, metrics, theme);\n this.drawYardLines(ctx, geometry, bounds, metrics, theme);\n this.drawNumbers(ctx, geometry, metrics, theme);\n this.drawEndZoneMarkers(ctx, geometry, bounds, metrics, theme);\n }\n\n /** エンドゾーンのうち窓に映る範囲を塗る。中に線は引かない。 */\n private drawEndZones(\n ctx: CanvasRenderingContext2D,\n geometry: FieldGeometry,\n { left, right }: FieldBounds,\n theme: FieldTheme,\n ): void {\n const { startYard, endYard } = geometry.yardWindow;\n ctx.fillStyle = theme.endzoneColor;\n if (startYard < 0) {\n const yTop = geometry.yForAbsoluteYard(0);\n const yBottom = geometry.yForAbsoluteYard(startYard);\n ctx.fillRect(left, yTop, right - left, yBottom - yTop);\n }\n if (endYard > 100) {\n const yTop = geometry.yForAbsoluteYard(endYard);\n const yBottom = geometry.yForAbsoluteYard(100);\n ctx.fillRect(left, yTop, right - left, yBottom - yTop);\n }\n }\n\n /**\n * 1 ヤードごとのハッシュと、サイドラインの目盛を描く。5 ヤードの倍数はヤードラインが覆うので省き、\n * エンドゾーンには引かない。\n */\n private drawHashes(\n ctx: CanvasRenderingContext2D,\n geometry: FieldGeometry,\n { left, right }: FieldBounds,\n metrics: FieldMetrics,\n theme: FieldTheme,\n ): void {\n const offset = HASH_CENTER_OFFSET_YARDS_BY_LEAGUE[DEFAULT_FIELD_LEAGUE];\n const center = FIELD_WIDTH_YARDS / 2;\n const hashLeft = geometry.xForLateralYard(center - offset);\n const hashRight = geometry.xForLateralYard(center + offset);\n const tick = metrics.hashTickLength;\n const half = tick / 2;\n\n ctx.strokeStyle = theme.lineColor;\n ctx.lineWidth = metrics.yardLineWidth;\n ctx.beginPath();\n for (const yard of yardLinesInWindow(geometry.zone, 1)) {\n if (yard < 0 || yard > 100 || yard % YARD_LINE_INTERVAL_YARDS === 0) {\n continue;\n }\n const y = geometry.yForAbsoluteYard(yard);\n ctx.moveTo(left, y);\n ctx.lineTo(left + tick, y);\n ctx.moveTo(right - tick, y);\n ctx.lineTo(right, y);\n ctx.moveTo(hashLeft - half, y);\n ctx.lineTo(hashLeft + half, y);\n ctx.moveTo(hashRight - half, y);\n ctx.lineTo(hashRight + half, y);\n }\n ctx.stroke();\n }\n\n /** 5 ヤードごとのヤードラインと、窓の外枠を描く。ゴールラインは外枠と同じ太さで、色で見分ける。 */\n private drawYardLines(\n ctx: CanvasRenderingContext2D,\n geometry: FieldGeometry,\n { left, right, top, bottom }: FieldBounds,\n metrics: FieldMetrics,\n theme: FieldTheme,\n ): void {\n const goalPath = new Path2D();\n const midPath = new Path2D();\n const minorPath = new Path2D();\n for (const yard of yardLinesInWindow(geometry.zone, YARD_LINE_INTERVAL_YARDS)) {\n if (yard < 0 || yard > 100) {\n continue;\n }\n const y = geometry.yForAbsoluteYard(yard);\n const target = yard === 0 || yard === 100 ? goalPath : yard === 50 ? midPath : minorPath;\n target.moveTo(left, y);\n target.lineTo(right, y);\n }\n\n ctx.strokeStyle = theme.lineColor;\n ctx.lineWidth = metrics.yardLineWidth;\n ctx.stroke(minorPath);\n ctx.lineWidth = metrics.midfieldLineWidth;\n ctx.stroke(midPath);\n\n // サイドラインと、窓の上下の端。\n ctx.lineWidth = metrics.goalLineWidth;\n ctx.beginPath();\n ctx.moveTo(left, top);\n ctx.lineTo(left, bottom);\n ctx.moveTo(right, top);\n ctx.lineTo(right, bottom);\n ctx.moveTo(left, top);\n ctx.lineTo(right, top);\n ctx.moveTo(left, bottom);\n ctx.lineTo(right, bottom);\n ctx.stroke();\n\n ctx.strokeStyle = theme.goalLineColor;\n ctx.lineWidth = metrics.goalLineWidth;\n ctx.stroke(goalPath);\n }\n\n /**\n * 10 ヤードごとのヤードラインに数字と方向の三角を描く。数字は両サイドラインから読めるよう\n * 上下を反転させ、三角は近いほうのゴールを指す。センターの 50 には三角を描かず、\n * displayYardNumber が null を返すゴールラインとエンドゾーンには何も描かない。\n */\n private drawNumbers(\n ctx: CanvasRenderingContext2D,\n geometry: FieldGeometry,\n metrics: FieldMetrics,\n theme: FieldTheme,\n ): void {\n const leftX = geometry.xForLateralYard(NUMBER_FROM_SIDELINE_YARDS);\n const rightX = geometry.xForLateralYard(FIELD_WIDTH_YARDS - NUMBER_FROM_SIDELINE_YARDS);\n const arrowBaseHalfPx = ARROW_HALF_WIDTH_YARDS * geometry.scale;\n const halfArrowLength = ARROW_LENGTH_YARDS / 2;\n\n ctx.font = fieldFont(metrics.numberHeight);\n ctx.textBaseline = \"middle\";\n ctx.textAlign = \"center\";\n\n // 桁の間の隙間の中心をヤードラインに合わせ、各桁は測った幅で隙間の端から置く。\n // ctx.letterSpacing で空けないのは、末尾の字の後ろにも間隔が付き、中央揃えが片側へずれるため。\n const gap = metrics.numberHeight * NUMBER_DIGIT_SPACING_PER_HEIGHT;\n const drawRotatedLabel = (label: string, x: number, y: number, rotation: number): void => {\n const [head, tail] = [...label];\n ctx.save();\n ctx.translate(x, y);\n ctx.rotate(rotation);\n if (label.length === 2 && head !== undefined && tail !== undefined) {\n ctx.fillText(head, -gap / 2 - ctx.measureText(head).width / 2, 0);\n ctx.fillText(tail, gap / 2 + ctx.measureText(tail).width / 2, 0);\n } else {\n ctx.fillText(label, 0, 0);\n }\n ctx.restore();\n };\n const drawArrow = (xc: number, tipY: number, baseY: number): void => {\n ctx.beginPath();\n ctx.moveTo(xc, tipY);\n ctx.lineTo(xc - arrowBaseHalfPx, baseY);\n ctx.lineTo(xc + arrowBaseHalfPx, baseY);\n ctx.closePath();\n ctx.fill();\n };\n\n for (const yard of yardLinesInWindow(geometry.zone, 10)) {\n const n = displayYardNumber(yard);\n if (n === null) {\n continue;\n }\n const numberY = geometry.yForAbsoluteYard(yard);\n ctx.fillStyle = theme.numberColor;\n drawRotatedLabel(String(n), leftX, numberY, Math.PI / 2);\n drawRotatedLabel(String(n), rightX, numberY, -Math.PI / 2);\n\n if (yard === 50) {\n continue;\n }\n const towardGoal = yard < 50 ? -1 : 1;\n const arrowCenterYard = yard + towardGoal * ARROW_OFFSET_FROM_NUMBER_YARDS;\n const tipY = geometry.yForAbsoluteYard(arrowCenterYard + towardGoal * halfArrowLength);\n const baseY = geometry.yForAbsoluteYard(arrowCenterYard - towardGoal * halfArrowLength);\n ctx.fillStyle = theme.lineColor;\n drawArrow(leftX, tipY, baseY);\n drawArrow(rightX, tipY, baseY);\n }\n }\n\n /** エンドゾーンの 4 隅にパイロン、エンドライン中央にゴールポストを描く。 */\n private drawEndZoneMarkers(\n ctx: CanvasRenderingContext2D,\n geometry: FieldGeometry,\n { left, right }: FieldBounds,\n metrics: FieldMetrics,\n theme: FieldTheme,\n ): void {\n const { startYard, endYard } = geometry.yardWindow;\n const pylon = metrics.pylonSize;\n const drawPylon = (x: number, y: number): void => {\n ctx.fillStyle = theme.pylonColor;\n ctx.fillRect(x - pylon / 2, y - pylon / 2, pylon, pylon);\n };\n\n if (startYard < 0) {\n const goalY = geometry.yForAbsoluteYard(0);\n const endY = geometry.yForAbsoluteYard(startYard);\n drawPylon(left, goalY);\n drawPylon(right, goalY);\n drawPylon(left, endY);\n drawPylon(right, endY);\n this.drawGoalpost(ctx, geometry, endY, \"toward-top\", metrics, theme);\n }\n if (endYard > 100) {\n const goalY = geometry.yForAbsoluteYard(100);\n const endY = geometry.yForAbsoluteYard(endYard);\n drawPylon(left, goalY);\n drawPylon(right, goalY);\n drawPylon(left, endY);\n drawPylon(right, endY);\n this.drawGoalpost(ctx, geometry, endY, \"toward-bottom\", metrics, theme);\n }\n }\n\n /** エンドラインの中央に、横木と 2 本の柱を描く。柱はフィールドの側へ伸ばす。 */\n private drawGoalpost(\n ctx: CanvasRenderingContext2D,\n geometry: FieldGeometry,\n lineY: number,\n uprights: UprightDirection,\n metrics: FieldMetrics,\n theme: FieldTheme,\n ): void {\n const cx = geometry.xForLateralYard(FIELD_WIDTH_YARDS / 2);\n const crossHalf = metrics.goalpostCrossbarHalfLength;\n const uprightLen = metrics.goalpostUprightLength;\n const dir = uprights === \"toward-top\" ? -1 : 1;\n\n ctx.save();\n ctx.strokeStyle = theme.goalpostColor;\n ctx.lineWidth = metrics.goalpostStroke;\n ctx.lineCap = \"round\";\n ctx.beginPath();\n ctx.moveTo(cx - crossHalf, lineY);\n ctx.lineTo(cx + crossHalf, lineY);\n ctx.moveTo(cx - crossHalf, lineY);\n ctx.lineTo(cx - crossHalf, lineY + dir * uprightLen);\n ctx.moveTo(cx + crossHalf, lineY);\n ctx.lineTo(cx + crossHalf, lineY + dir * uprightLen);\n ctx.stroke();\n ctx.restore();\n }\n}\n","import {\n FIELD_WIDTH_YARDS,\n type FieldGeometry,\n GRID_STEP_YARDS,\n YARD_LINE_INTERVAL_YARDS,\n yardLinesInWindow,\n} from \"../../common/index.js\";\nimport type { EditorRenderFrame, ILayerRenderer } from \"./layer.js\";\n\n/**\n * 位置を置ける格子点を薄い点で敷く。編集中だけの層なので、PNG と view モードには出ない。\n * 格子は横がサイドライン、縦が LOS を原点にしているが、LOS は整数ヤードにあるので、\n * 絶対ヤードで GRID_STEP_YARDS ごとに置いても同じ点になる。\n */\nexport class GridRenderer implements ILayerRenderer<EditorRenderFrame> {\n // 点は数千個あり、ドラッグのたびに組み立て直すと描く時間の大半を占める。\n // 窓と縮尺が同じ間は同じ path なので、前のフレームのものを使い回す。\n private cached: { readonly key: string; readonly dots: Path2D } | undefined;\n\n draw(ctx: CanvasRenderingContext2D, frame: EditorRenderFrame): void {\n const { geometry, metrics } = frame;\n const key = [\n geometry.zone,\n geometry.offsetX,\n geometry.offsetY,\n geometry.scale,\n metrics.gridDotRadius,\n ].join(\":\");\n if (this.cached?.key !== key) {\n this.cached = { key, dots: gridDots(geometry, metrics.gridDotRadius) };\n }\n ctx.fillStyle = frame.theme(\"fieldGrid\");\n ctx.fill(this.cached.dots);\n }\n}\n\n// 点は 1〜2 px なので、円ではなく正方形で描いても見分けが付かず、塗る負荷が小さい。\nfunction gridDots(geometry: FieldGeometry, radius: number): Path2D {\n const dots = new Path2D();\n const size = 2 * radius;\n for (const yard of yardLinesInWindow(geometry.zone, GRID_STEP_YARDS)) {\n // ヤードラインと窓の端の上には置かない。窓の端はどれも 5 ヤードの倍数だが、\n // エンドゾーンの中(0 より手前と 100 より奥)にはヤードラインが無いので、そこには置く。\n const { startYard, endYard } = geometry.yardWindow;\n const onYardLine = yard >= 0 && yard <= 100 && yard % YARD_LINE_INTERVAL_YARDS === 0;\n if (onYardLine || yard === startYard || yard === endYard) {\n continue;\n }\n const y = geometry.yForAbsoluteYard(yard);\n for (let lateral = GRID_STEP_YARDS; lateral < FIELD_WIDTH_YARDS; lateral += GRID_STEP_YARDS) {\n dots.rect(geometry.xForLateralYard(lateral) - radius, y - radius, size, size);\n }\n }\n return dots;\n}\n","import {\n arrowHeadVertices,\n blockCapEndpoints,\n type CanvasPoint,\n DEFAULT_LINE_THICKNESS,\n type FieldMetrics,\n indexPlayersById,\n type LineKind,\n lineAnchorPoints,\n sampleLinePath,\n trimForArrowHead,\n} from \"../../common/index.js\";\nimport type { ThemeTokenName } from \"../theme/tokens.js\";\nimport type { ILayerRenderer, RenderFrame } from \"./layer.js\";\n\nconst LINE_COLOR_TOKENS = {\n route: \"lineRoute\",\n block: \"lineBlock\",\n motion: \"lineMotion\",\n} as const satisfies Record<LineKind, ThemeTokenName>;\n\nexport class LineRenderer implements ILayerRenderer {\n /** 起点の選手が見つからない線は描かない。 */\n draw(ctx: CanvasRenderingContext2D, frame: RenderFrame): void {\n const { geometry, metrics } = frame;\n const { lines, players } = frame.scene;\n if (geometry.scale <= 0 || lines.length === 0) {\n return;\n }\n const byId = indexPlayersById(players);\n\n for (const line of lines) {\n const anchors = lineAnchorPoints(line, byId);\n if (anchors === undefined) {\n continue;\n }\n const path = sampleLinePath(anchors, line.interpolation).map((p) => geometry.toCanvas(p));\n if (path.length < 2) {\n continue;\n }\n\n const color = line.color ?? frame.theme(LINE_COLOR_TOKENS[line.kind]);\n // thickness は既定の太さに対する倍率なので、画面と PNG のどちらの縮尺でも見え方が揃う。\n const width = this.widthFor(line.kind, metrics) * (line.thickness ?? DEFAULT_LINE_THICKNESS);\n const isBlock = line.kind === \"block\";\n\n ctx.save();\n ctx.strokeStyle = color;\n ctx.lineWidth = width;\n ctx.lineJoin = \"round\";\n ctx.lineCap = \"round\";\n if (line.kind === \"motion\") {\n ctx.setLineDash([...metrics.motionDash]);\n }\n\n // 矢印を付ける線は、矢じりの根元で止める。先端まで引くと、線の丸いキャップが細くなる三角の先から\n // はみ出して、先端に点が付いたように見える。block は T 字のバーを当てるので終点まで引く。\n // 矢じりの向きと位置は、止める前の path から求める。\n const strokePath = isBlock ? path : trimForArrowHead(path, metrics.arrowLength);\n ctx.beginPath();\n // 空のパスへの最初の lineTo は moveTo として働く。\n for (const pt of strokePath) {\n ctx.lineTo(pt.x, pt.y);\n }\n ctx.stroke();\n ctx.setLineDash([]);\n\n if (isBlock) {\n this.drawBlockCap(ctx, path, color, metrics, width);\n } else {\n this.drawArrowHead(ctx, path, color, metrics);\n }\n ctx.restore();\n }\n }\n\n private widthFor(kind: LineKind, metrics: FieldMetrics): number {\n return kind === \"block\" ? metrics.blockWidth : metrics.routeWidth;\n }\n\n /** 終点に、進む向きへ向けた三角の矢じりを描く。 */\n private drawArrowHead(\n ctx: CanvasRenderingContext2D,\n path: readonly CanvasPoint[],\n color: string,\n metrics: FieldMetrics,\n ): void {\n const vertices = arrowHeadVertices(path, metrics.arrowLength, metrics.arrowHalfWidth);\n if (vertices === undefined) {\n return;\n }\n const [tip, left, right] = vertices;\n ctx.beginPath();\n ctx.moveTo(tip.x, tip.y);\n ctx.lineTo(left.x, left.y);\n ctx.lineTo(right.x, right.y);\n ctx.closePath();\n ctx.fillStyle = color;\n ctx.fill();\n }\n\n /** 終点に、進む向きと直交する T 字のバーを描く。 */\n private drawBlockCap(\n ctx: CanvasRenderingContext2D,\n path: readonly CanvasPoint[],\n color: string,\n metrics: FieldMetrics,\n width: number,\n ): void {\n const endpoints = blockCapEndpoints(path, metrics.blockCapLength);\n if (endpoints === undefined) {\n return;\n }\n const [from, to] = endpoints;\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = width * 1.2;\n ctx.lineCap = \"round\";\n ctx.moveTo(from.x, from.y);\n ctx.lineTo(to.x, to.y);\n ctx.stroke();\n }\n}\n","import {\n type EditorOverlay,\n PLAYER_RADIUS_YARDS,\n WAYPOINT_HANDLE_RADIUS_YARDS,\n} from \"../../common/index.js\";\nimport type { EditorRenderFrame, ILayerRenderer } from \"./layer.js\";\n\n/**\n * 選択の強調と、線の waypoint と終点のハンドルを描く。\n *\n * 選択色は対象の外側に置き、対象には重ねない(選手はマーカーの外周のリング、線はハンドル)。\n * 線の色はパレットで選ばれるので、上から塗ると線の色と混ざって何色の線か読めなくなる。\n */\nexport class OverlayRenderer implements ILayerRenderer<EditorRenderFrame> {\n draw(ctx: CanvasRenderingContext2D, frame: EditorRenderFrame): void {\n const { overlay } = frame;\n switch (overlay.kind) {\n case \"none\":\n return;\n case \"player\":\n drawSelectedPlayer(ctx, frame, overlay.playerId);\n return;\n case \"line\":\n drawLineHandles(ctx, frame, overlay);\n return;\n }\n }\n}\n\nfunction drawSelectedPlayer(\n ctx: CanvasRenderingContext2D,\n frame: EditorRenderFrame,\n playerId: string,\n): void {\n const player = frame.scene.players.find((p) => p.id === playerId);\n if (player === undefined) {\n return;\n }\n const { x, y } = frame.geometry.toCanvas(player.position);\n const r = PLAYER_RADIUS_YARDS * frame.geometry.scale + 4;\n ctx.beginPath();\n ctx.arc(x, y, r, 0, Math.PI * 2);\n ctx.strokeStyle = frame.theme(\"selection\");\n ctx.lineWidth = 2;\n ctx.stroke();\n}\n\nfunction drawLineHandles(\n ctx: CanvasRenderingContext2D,\n frame: EditorRenderFrame,\n handles: Extract<EditorOverlay, { kind: \"line\" }>,\n): void {\n const { geometry } = frame;\n const fill = frame.theme(\"selection\");\n const outline = frame.theme(\"selectionOutline\");\n // アイコンは当たり判定の範囲(WAYPOINT_HANDLE_RADIUS_YARDS)の一部だけを描く。範囲いっぱいに\n // 描くとマーカー並みに大きくなるので小さく出し、掴みやすさは当たり判定の広さに任せる。\n const handleHalf = Math.max(3, 0.45 * WAYPOINT_HANDLE_RADIUS_YARDS * geometry.scale);\n // 現在の path(beginPath 済み)を、ハンドル共通の塗りと縁取りで仕上げる。\n const paintHandle = (): void => {\n ctx.fillStyle = fill;\n ctx.fill();\n ctx.lineWidth = 1.5;\n ctx.strokeStyle = outline;\n ctx.stroke();\n };\n for (const waypoint of handles.waypointHandles) {\n const { x, y } = geometry.toCanvas(waypoint);\n ctx.beginPath();\n ctx.rect(x - handleHalf, y - handleHalf, handleHalf * 2, handleHalf * 2);\n paintHandle();\n }\n // 終点のハンドルは、waypoint の四角と見分けられるよう円で描く。\n const { x, y } = geometry.toCanvas(handles.endpointHandle);\n ctx.beginPath();\n ctx.arc(x, y, handleHalf + 1, 0, Math.PI * 2);\n paintHandle();\n}\n","import {\n DEFAULT_PLAYER_FILL,\n PLAYER_RADIUS_YARDS,\n playerMarkerOutline,\n} from \"../../common/index.js\";\nimport { fieldFont } from \"../theme/field-font.js\";\nimport type { ILayerRenderer, RenderFrame } from \"./layer.js\";\n\nexport class PlayerRenderer implements ILayerRenderer {\n draw(ctx: CanvasRenderingContext2D, frame: RenderFrame): void {\n const { geometry, metrics } = frame;\n const { players } = frame.scene;\n const defaultColor = frame.theme(\"playerColor\");\n const grass = frame.theme(\"fieldGrass\");\n const label = frame.theme(\"playerLabel\");\n // 当たり判定と同じ半径の輪郭を描き、縁取りはその上に乗せる。\n const r = PLAYER_RADIUS_YARDS * geometry.scale;\n if (r <= 0) {\n return;\n }\n const fontPx = metrics.markerLabelFont;\n\n for (const player of players) {\n const center = geometry.toCanvas(player.position);\n const color = player.color ?? defaultColor;\n const isSolid = (player.fill ?? DEFAULT_PLAYER_FILL) === \"solid\";\n\n ctx.beginPath();\n const outline = playerMarkerOutline(player.shape, r);\n if (outline.kind === \"circle\") {\n ctx.arc(center.x, center.y, outline.radius, 0, Math.PI * 2);\n } else {\n const { halfSide } = outline;\n ctx.rect(center.x - halfSide, center.y - halfSide, halfSide * 2, halfSide * 2);\n }\n // 枠線だけの選手も内側を芝の色で塗り、下を通る線を隠す。エンドゾーンに置いた選手も芝の色で塗る。\n // 既定ではエンドゾーンと芝の差がわずかで気にならず、どこにいるかで塗りを変えるほどではない。\n ctx.fillStyle = isSolid ? color : grass;\n ctx.fill();\n ctx.lineWidth = metrics.markerStroke;\n ctx.strokeStyle = color;\n ctx.stroke();\n\n if (player.label !== \"\") {\n ctx.fillStyle = isSolid ? label : color;\n ctx.font = fieldFont(fontPx);\n ctx.textAlign = \"center\";\n // textBaseline を middle にすると、字の em ボックスの中央に揃うので、フォントによって上下にずれる。\n // 測った字面の中央をマーカーの中心に合わせる。\n ctx.textBaseline = \"alphabetic\";\n const tm = ctx.measureText(player.label);\n const labelY = center.y + (tm.actualBoundingBoxAscent - tm.actualBoundingBoxDescent) / 2;\n ctx.fillText(player.label, center.x, labelY);\n }\n }\n }\n}\n","import type { EditorOverlay, FieldGeometry, FieldMetrics, SceneData } from \"../../common/index.js\";\nimport type { ThemeReader } from \"../theme/tokens.js\";\nimport { FieldRenderer } from \"./field-renderer.js\";\nimport { GridRenderer } from \"./grid-renderer.js\";\nimport { LineRenderer } from \"./line-renderer.js\";\nimport { OverlayRenderer } from \"./overlay-renderer.js\";\nimport { PlayerRenderer } from \"./player-renderer.js\";\n\n/** 1 回の描画で、図の層が共有する入力。 */\nexport interface RenderFrame {\n readonly geometry: FieldGeometry;\n readonly metrics: FieldMetrics;\n readonly scene: SceneData;\n readonly theme: ThemeReader;\n}\n\n/**\n * 編集の層だけが受け取る入力。図の層にオーバーレイを渡さないので、\n * PNG に書き出した図に選択の強調やハンドルが紛れ込むことはない。\n */\nexport interface EditorRenderFrame extends RenderFrame {\n readonly overlay: EditorOverlay;\n}\n\n/**\n * 図の 1 層を描く。ctx は DPR の変換を済ませてあるので、CSS px の座標で描いてよい。\n * 層ごとに save と restore で挟むので、層の中で ctx の状態を元に戻さなくてよい。\n */\nexport interface ILayerRenderer<F extends RenderFrame = RenderFrame> {\n // メソッド記法にすると引数が双変で比べられ、編集の層を図の層に入れても型エラーにならない。\n readonly draw: (ctx: CanvasRenderingContext2D, frame: F) => void;\n}\n\n/**\n * 図を描く層(field と play)と、編集中だけ挟む層(backdrop と editor)。描く順は\n * field、backdrop、play、editor。PNG の書き出しと view モードは図の層だけで描くので、\n * 格子、選択の強調、ハンドルは書き出した画像と読み取り専用の画面に入らない。\n */\nexport interface SurfaceLayers {\n /** フィールド。図の層のうち、編集中の backdrop より下に描くもの。 */\n readonly field: readonly ILayerRenderer[];\n /** 編集中だけ、フィールドの上で線と選手の下に敷く層。位置の格子を置く。 */\n readonly backdrop: readonly ILayerRenderer<EditorRenderFrame>[];\n /** 線と選手。 */\n readonly play: readonly ILayerRenderer[];\n /** 編集中だけ、図の上に重ねる層。 */\n readonly editor: readonly ILayerRenderer<EditorRenderFrame>[];\n}\n\n/** 線は選手の下に描く。上に描くと、線の根元が選手のマーカーに重なって見える。 */\nexport function createDefaultLayers(): SurfaceLayers {\n return {\n field: [new FieldRenderer()],\n backdrop: [new GridRenderer()],\n play: [new LineRenderer(), new PlayerRenderer()],\n editor: [new OverlayRenderer()],\n };\n}\n\nexport function renderLayers<F extends RenderFrame>(\n ctx: CanvasRenderingContext2D,\n frame: F,\n layers: readonly ILayerRenderer<F>[],\n): void {\n for (const layer of layers) {\n ctx.save();\n layer.draw(ctx, frame);\n ctx.restore();\n }\n}\n","import {\n computeFieldMetrics,\n Disposable,\n type EditorOverlay,\n FieldGeometry,\n type FieldPosition,\n type ImageExportOptions,\n resolveImageExportSize,\n type SceneData,\n toDisposable,\n} from \"../../common/index.js\";\nimport { loadFieldFont } from \"../theme/field-font-face.js\";\nimport { createThemeReader } from \"../theme/theme-reader.js\";\nimport type { ThemeReader } from \"../theme/tokens.js\";\nimport {\n createDefaultLayers,\n type EditorRenderFrame,\n type RenderFrame,\n renderLayers,\n type SurfaceLayers,\n} from \"./layer.js\";\n\n/**\n * Canvas の大きさ、DPR、再描画の時機を受け持ち、渡された図を層ごとに描く。\n * 何を描くか(プレビューの合成、選択の強調)は、図を渡す側が決める。\n */\nexport class CanvasSurface extends Disposable {\n readonly canvas: HTMLCanvasElement;\n private readonly ctx: CanvasRenderingContext2D;\n private readonly layers: SurfaceLayers;\n private scene: SceneData;\n private overlay: EditorOverlay | undefined;\n private frameRequest: number | undefined;\n private dpr = 0;\n // 破棄するときに、DPR の見張りをまとめて外す。\n private readonly lifetime = new AbortController();\n\n constructor(\n parent: HTMLElement,\n scene: SceneData,\n overlay: EditorOverlay | undefined,\n layers: SurfaceLayers = createDefaultLayers(),\n ) {\n super();\n this.scene = scene;\n this.overlay = overlay;\n this.layers = layers;\n\n this.canvas = document.createElement(\"canvas\");\n this.canvas.className = \"playmaker-canvas\";\n parent.appendChild(this.canvas);\n this._register(toDisposable(() => this.canvas.remove()));\n\n const ctx = this.canvas.getContext(\"2d\");\n if (!ctx) {\n throw new Error(\"Playmaker: 2D canvas context を取得できませんでした。\");\n }\n this.ctx = ctx;\n\n const observer = new ResizeObserver(() => this.resize());\n observer.observe(parent);\n this._register(\n toDisposable(() => {\n observer.disconnect();\n this.lifetime.abort();\n this.cancelFrame();\n }),\n );\n\n // 最初の描画は、observe した直後の ResizeObserver の通知で行う。構築した時点ではホストが\n // ツールバーやパネルをまだ並べておらず、ここで描くとすぐに大きさが変わって描き直しになる。\n this.watchDevicePixelRatio();\n this.redrawWhenFontLoads();\n }\n\n /** テーマ変数は描くたびに読み直すので、ホストが変数を変えたあとに呼べば反映される。 */\n refresh(): void {\n this.invalidate();\n }\n\n /**\n * 図とオーバーレイを差し替える。描くのは次のフレームなので、\n * 同じフレームの中で何度差し替えても描くのは 1 回になる。\n * overlay を省くと、格子と選択の強調のような編集中だけの層を描かない(view モード)。\n */\n setScene(scene: SceneData, overlay: EditorOverlay | undefined): void {\n this.scene = scene;\n this.overlay = overlay;\n this.invalidate();\n }\n\n /** マウスイベントの clientX / clientY を、フィールドのヤードの位置に変える。 */\n clientToYard(clientX: number, clientY: number): FieldPosition {\n const rect = this.canvas.getBoundingClientRect();\n return this.measure().fromCanvas({ x: clientX - rect.left, y: clientY - rect.top });\n }\n\n /**\n * 指定したプレー図を PNG(Blob)として書き出す。図の層だけで描くので、格子、選択の強調、\n * ハンドルは入らない。配色は画面と同じテーマ変数から読む。\n * 同梱フォントを読み込み終えてから描くので、構築の直後でも数字とラベルは同梱フォントになる。\n */\n async exportToPngBlob(data: SceneData, options?: ImageExportOptions): Promise<Blob> {\n const { width, height } = resolveImageExportSize(data.field.zone, options);\n // 配色は呼んだ時点の変数で決める。フォントを待つ間にホストが変数を戻したり、破棄して canvas が\n // host から外れたりしても、書き出す色は変わらない。\n const theme = createThemeReader(this.host);\n await loadFieldFont();\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n throw new Error(\"Playmaker: エクスポート用 2D canvas context を取得できませんでした。\");\n }\n const geometry = new FieldGeometry(width, height, data.field);\n this.paint(ctx, this.frameFor(geometry, data, theme), undefined);\n return new Promise<Blob>((resolve, reject) => {\n canvas.toBlob((blob) => {\n if (blob) {\n resolve(blob);\n } else {\n reject(new Error(\"Playmaker: PNG への変換に失敗しました。\"));\n }\n }, \"image/png\");\n });\n }\n\n /** 初回は代わりのフォントで描いて白い画面を避け、同梱フォントを読み込めたら描き直す。 */\n private redrawWhenFontLoads(): void {\n void loadFieldFont().then(() => {\n if (!this.isDisposed) {\n this.invalidate();\n }\n });\n }\n\n /** コンテナの大きさと DPR に合わせて、描画用のバッファを作り直す。 */\n private resize(): void {\n const dpr = window.devicePixelRatio || 1;\n const { clientWidth, clientHeight } = this.host;\n const width = Math.max(1, Math.round(clientWidth * dpr));\n const height = Math.max(1, Math.round(clientHeight * dpr));\n // 要素の大きさが変わっても、バッファの大きさと DPR が同じなら描いた図がそのまま使える。\n if (width === this.canvas.width && height === this.canvas.height && dpr === this.dpr) {\n return;\n }\n this.dpr = dpr;\n this.canvas.width = width;\n this.canvas.height = height;\n // 以降は CSS px の座標で描く。geometry も CSS px で求める。\n this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n // バッファを作り直すと中身が消えるので、次のフレームを待たずに描く。\n this.cancelFrame();\n this.render();\n }\n\n // resolution の media query は、今の DPR と合わなくなったときに 1 回だけ change を出す。\n // ブラウザの拡大率やモニタが変わるたびに、新しい DPR で張り直す。\n private watchDevicePixelRatio(): void {\n const query = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);\n query.addEventListener(\n \"change\",\n () => {\n this.resize();\n this.watchDevicePixelRatio();\n },\n { once: true, signal: this.lifetime.signal },\n );\n }\n\n private invalidate(): void {\n // 最初の大きさが決まる前は描かない。決まったときに resize が描く。\n if (this.frameRequest !== undefined || this.dpr === 0) {\n return;\n }\n this.frameRequest = requestAnimationFrame(() => {\n this.frameRequest = undefined;\n this.render();\n });\n }\n\n private cancelFrame(): void {\n if (this.frameRequest !== undefined) {\n cancelAnimationFrame(this.frameRequest);\n this.frameRequest = undefined;\n }\n }\n\n private render(): void {\n const frame = this.frameFor(this.measure(), this.scene, createThemeReader(this.host));\n this.paint(this.ctx, frame, this.overlay);\n }\n\n /**\n * 層を field、backdrop、play、editor の順に描く。overlay が無いときは編集中だけの層\n * (backdrop と editor)を飛ばすので、view モードと PNG の書き出しは図の層だけになる。\n */\n private paint(\n ctx: CanvasRenderingContext2D,\n frame: RenderFrame,\n overlay: EditorOverlay | undefined,\n ): void {\n const editorFrame: EditorRenderFrame | undefined =\n overlay === undefined ? undefined : { ...frame, overlay };\n renderLayers(ctx, frame, this.layers.field);\n if (editorFrame !== undefined) {\n renderLayers(ctx, editorFrame, this.layers.backdrop);\n }\n renderLayers(ctx, frame, this.layers.play);\n if (editorFrame !== undefined) {\n renderLayers(ctx, editorFrame, this.layers.editor);\n }\n }\n\n private frameFor(geometry: FieldGeometry, scene: SceneData, theme: ThemeReader): RenderFrame {\n return {\n geometry,\n metrics: computeFieldMetrics(geometry.fieldPixelWidth, geometry.scale),\n scene,\n theme,\n };\n }\n\n private measure(): FieldGeometry {\n const { clientWidth, clientHeight } = this.host;\n return new FieldGeometry(clientWidth, clientHeight, this.scene.field);\n }\n\n // 大きさとテーマ変数は、canvas を置いた要素から読む。\n private get host(): HTMLElement {\n return this.canvas.parentElement ?? this.canvas;\n }\n}\n","/**\n * update で container の中身を作り直す。作り直す前に container の中にあったフォーカスが\n * 取り除かれた要素と一緒に消えたら、fallback へ移す。消えたフォーカスは body へ落ち、\n * ショートカットを受けている要素にキーが届かなくなるため。\n */\nexport function replaceKeepingFocus(\n container: HTMLElement,\n fallback: HTMLElement,\n update: () => void,\n): void {\n const doc = container.ownerDocument;\n const hadFocus = container.contains(doc.activeElement);\n update();\n if (hadFocus && !container.contains(doc.activeElement)) {\n fallback.focus({ preventScroll: true });\n }\n}\n","import type { ThemeTokenName } from \"./tokens.js\";\n\nexport interface ColorOption {\n readonly label: string;\n readonly token: ThemeTokenName;\n}\n\n/**\n * 選手と線の色は自由に選ばせず、白い芝の上で見分けやすい 4 色に絞る。\n * 保存する color は、テーマ変数を解決した具体的な色にする。canvas は var() を解釈できないため。\n */\nexport const COLOR_PALETTE: readonly ColorOption[] = [\n { label: \"黒\", token: \"swatch1\" },\n { label: \"赤\", token: \"swatch2\" },\n { label: \"青\", token: \"swatch3\" },\n { label: \"緑\", token: \"swatch4\" },\n];\n","import {\n DEFAULT_LINE_THICKNESS,\n DEFAULT_PLAYER_FILL,\n Disposable,\n type IEditorUi,\n isLineThickness,\n isOneOf,\n LINE_INTERPOLATION_VALUES,\n LINE_KIND_VALUES,\n type Line,\n type LineInterpolation,\n type LineKind,\n PLAYER_FILL_VALUES,\n PLAYER_SHAPE_VALUES,\n type Player,\n type PlayerFill,\n type PlayerShape,\n toDisposable,\n} from \"../../common/index.js\";\nimport { normalizeCssColor } from \"../theme/css-color.js\";\nimport { COLOR_PALETTE } from \"../theme/palette.js\";\nimport { createThemeReader } from \"../theme/theme-reader.js\";\nimport { replaceKeepingFocus } from \"./focus.js\";\n\nconst SHAPE_LABELS = {\n circle: \"丸\",\n square: \"四角\",\n} satisfies Record<PlayerShape, string>;\n\nconst FILL_LABELS = {\n outline: \"枠線\",\n solid: \"塗りつぶし\",\n} satisfies Record<PlayerFill, string>;\n\nconst KIND_LABELS = {\n route: \"ルート\",\n block: \"ブロック\",\n motion: \"モーション\",\n} satisfies Record<LineKind, string>;\n\nconst INTERPOLATION_LABELS = {\n straight: \"直線\",\n bezier: \"曲線\",\n} satisfies Record<LineInterpolation, string>;\n\n/** 色を選ぶ丸いボタン 1 つ分。枠線のスウォッチは縁だけを色にし、塗りつぶしは中まで塗る。 */\ninterface SwatchChoice {\n readonly name: string;\n readonly color: string;\n readonly fill: PlayerFill;\n}\n\nfunction createSwatch({ name, color, fill }: SwatchChoice): HTMLButtonElement {\n const btn = document.createElement(\"button\");\n btn.type = \"button\";\n btn.className = \"playmaker-panel__swatch\";\n btn.title = name;\n btn.setAttribute(\"aria-label\", name);\n if (fill === \"outline\") {\n btn.classList.add(\"playmaker-panel__swatch--outline\");\n btn.style.borderColor = color;\n } else {\n btn.style.backgroundColor = color;\n }\n return btn;\n}\n\n/** 選択中の要素。選択は 1 つなので、選手と線が同時に来ることは型で起こらない。 */\ntype SelectedItem =\n | { readonly kind: \"player\"; readonly player: Player }\n | { readonly kind: \"line\"; readonly line: Line }\n | { readonly kind: \"none\" };\n\n/** 入力に渡す値と、値が変わったときに呼ぶ関数。onReset を渡すと、既定に戻すボタンが付く。 */\ninterface InputOptions<T> {\n readonly label: string;\n readonly onChange: (value: T) => void;\n readonly onReset?: () => void;\n}\n\n/** 表示中の入力と、選択中の要素の値をその入力に書き込む関数。 */\ntype ShownFields =\n | { readonly kind: \"player\"; readonly id: string; readonly update: (player: Player) => void }\n | { readonly kind: \"line\"; readonly id: string; readonly update: (line: Line) => void }\n | { readonly kind: \"hint\" };\n\nexport class PropertyPanel extends Disposable {\n readonly element: HTMLElement;\n private readonly controller: IEditorUi;\n private readonly focusFallback: HTMLElement;\n // 選択中の要素が同じあいだは入力を作り直さず、値だけを書き込む。作り直すと、\n // 値を確定して Tab で次の入力へ移った直後に、移った先の入力ごと消えてフォーカスが外れる。\n private shown: ShownFields | undefined;\n\n /**\n * @param focusFallback 選択が変わって入力を作り直したときに、消えた入力にあったフォーカスを移す先。\n */\n constructor(parent: HTMLElement, controller: IEditorUi, focusFallback: HTMLElement) {\n super();\n this.controller = controller;\n this.focusFallback = focusFallback;\n this.element = document.createElement(\"div\");\n this.element.className = \"playmaker-panel\";\n\n parent.appendChild(this.element);\n this._register(toDisposable(() => this.element.remove()));\n this._register(controller.onDidChangeViewState(() => this.sync()));\n this.sync();\n }\n\n /** 色の既定値とスウォッチはテーマ変数から読むので、ホストが変数を変えたあとに呼べば反映される。 */\n refresh(): void {\n this.shown = undefined;\n this.sync();\n }\n\n private sync(): void {\n const selected = this.selectedItem();\n const shown = this.shown;\n if (selected.kind === \"player\" && shown?.kind === \"player\" && shown.id === selected.player.id) {\n shown.update(selected.player);\n return;\n }\n if (selected.kind === \"line\" && shown?.kind === \"line\" && shown.id === selected.line.id) {\n shown.update(selected.line);\n return;\n }\n if (selected.kind === \"none\" && shown?.kind === \"hint\") {\n return;\n }\n replaceKeepingFocus(this.element, this.focusFallback, () => {\n this.shown = this.rebuild(selected);\n });\n }\n\n private selectedItem(): SelectedItem {\n const player = this.controller.getSelectedPlayer();\n if (player !== undefined) {\n return { kind: \"player\", player };\n }\n const line = this.controller.getSelectedLine();\n if (line !== undefined) {\n return { kind: \"line\", line };\n }\n return { kind: \"none\" };\n }\n\n private rebuild(selected: SelectedItem): ShownFields {\n this.element.replaceChildren();\n switch (selected.kind) {\n case \"player\": {\n const update = this.addPlayerFields();\n update(selected.player);\n return { kind: \"player\", id: selected.player.id, update };\n }\n case \"line\": {\n const update = this.addLineFields();\n update(selected.line);\n return { kind: \"line\", id: selected.line.id, update };\n }\n case \"none\": {\n const hint = document.createElement(\"p\");\n hint.className = \"playmaker-panel__hint\";\n hint.textContent = \"対象を選択するとプロパティを編集できます\";\n this.element.appendChild(hint);\n return { kind: \"hint\" };\n }\n }\n }\n\n private addPlayerFields(): (player: Player) => void {\n const controller = this.controller;\n this.addTitle(\"選手\");\n const setLabel = this.addText({\n label: \"ラベル\",\n onChange: (v) => controller.updateSelectedPlayer({ label: v }),\n });\n const setShape = this.addSelect(\"形状\", PLAYER_SHAPE_VALUES, SHAPE_LABELS, (v) =>\n controller.updateSelectedPlayer({ shape: v }),\n );\n // 4 色それぞれの枠線と塗りつぶしを並べた 8 つのスウォッチ。上の段が枠線、下の段が塗りつぶし。\n // 「塗りつぶしか枠線か」を別の選択肢にせず、色と一緒に 1 回で選べるようにする。\n const read = createThemeReader(this.element);\n const choices = PLAYER_FILL_VALUES.flatMap((fill) =>\n COLOR_PALETTE.map((opt) => ({\n name: `${opt.label}の${FILL_LABELS[fill]}`,\n color: read(opt.token),\n fill,\n })),\n );\n const setPressed = this.addSwatches(\"色\", choices, {\n onChange: ({ color, fill }) => controller.updateSelectedPlayer({ color, fill }),\n onReset: () => controller.updateSelectedPlayer({ color: null, fill: null }),\n });\n // 色を省いた選手は、テーマの既定色の枠線のスウォッチが押された状態になる。\n const defaultColor = read(\"playerColor\");\n return (player) => {\n setLabel(player.label);\n setShape(player.shape);\n const color = player.color === undefined ? defaultColor : normalizeCssColor(player.color);\n const fill = player.fill ?? DEFAULT_PLAYER_FILL;\n setPressed((choice) => choice.color === color && choice.fill === fill);\n };\n }\n\n private addLineFields(): (line: Line) => void {\n const controller = this.controller;\n this.addTitle(\"線\");\n const setKind = this.addSelect(\"種別\", LINE_KIND_VALUES, KIND_LABELS, (v) =>\n controller.updateSelectedLine({ kind: v }),\n );\n const setInterpolation = this.addSelect(\n \"補間\",\n LINE_INTERPOLATION_VALUES,\n INTERPOLATION_LABELS,\n (v) => controller.updateSelectedLine({ interpolation: v }),\n );\n const read = createThemeReader(this.element);\n const choices = COLOR_PALETTE.map((opt) => ({\n name: opt.label,\n color: read(opt.token),\n fill: \"solid\" as const,\n }));\n const setPressed = this.addSwatches(\"色\", choices, {\n onChange: ({ color }) => controller.updateSelectedLine({ color }),\n onReset: () => controller.updateSelectedLine({ color: null }),\n });\n const setThickness = this.addNumber({\n label: \"太さ\",\n onChange: (v) => controller.updateSelectedLine({ thickness: v }),\n onReset: () => controller.updateSelectedLine({ thickness: null }),\n });\n return (line) => {\n setKind(line.kind);\n setInterpolation(line.interpolation);\n // 保存済みの色は外から渡されたデータのこともあるので、テーマの色と同じ書き方にそろえて比べる。\n const color = line.color === undefined ? undefined : normalizeCssColor(line.color);\n setPressed((choice) => choice.color === color);\n setThickness(line.thickness ?? DEFAULT_LINE_THICKNESS);\n };\n }\n\n private addTitle(text: string): void {\n const h = document.createElement(\"h2\");\n h.className = \"playmaker-panel__title\";\n h.textContent = text;\n this.element.appendChild(h);\n }\n\n private addRow(labelText: string, control: HTMLElement, onReset?: () => void): void {\n const label = document.createElement(\"label\");\n label.className = \"playmaker-panel__label\";\n label.append(this.createRowText(labelText), control);\n this.appendRow(labelText, [label], onReset);\n }\n\n /**\n * ボタンを並べた行。label で包むと、文字を押したときに先頭のボタンが押されるので、\n * ボタンの組に名前を付ける。\n */\n private addGroupRow(\n labelText: string,\n group: HTMLElement,\n onReset: (() => void) | undefined,\n ): void {\n group.setAttribute(\"role\", \"group\");\n group.setAttribute(\"aria-label\", labelText);\n this.appendRow(labelText, [this.createRowText(labelText), group], onReset);\n }\n\n private createRowText(text: string): HTMLElement {\n const span = document.createElement(\"span\");\n span.className = \"playmaker-panel__row-text\";\n span.textContent = text;\n return span;\n }\n\n /**\n * onReset を渡すと、値を消してテーマの既定に戻すボタンを行の末尾に置く。\n * 既定のときもボタンは押せるままにする。押した直後に無効にすると、フォーカスが body へ落ちる。\n */\n private appendRow(\n labelText: string,\n children: readonly HTMLElement[],\n onReset: (() => void) | undefined,\n ): void {\n const row = document.createElement(\"div\");\n row.className = \"playmaker-panel__row\";\n row.append(...children);\n if (onReset !== undefined) {\n const reset = document.createElement(\"button\");\n reset.type = \"button\";\n reset.className = \"playmaker-panel__reset\";\n reset.textContent = \"既定\";\n reset.setAttribute(\"aria-label\", `${labelText}を既定に戻す`);\n reset.addEventListener(\"click\", onReset);\n row.appendChild(reset);\n }\n this.element.appendChild(row);\n }\n\n private addText({ label, onChange, onReset }: InputOptions<string>): (value: string) => void {\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.addEventListener(\"change\", () => onChange(input.value));\n this.addRow(label, input, onReset);\n return (value) => {\n input.value = value;\n };\n }\n\n private addNumber({ label, onChange, onReset }: InputOptions<number>): (value: number) => void {\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.min = \"0.25\";\n input.step = \"0.25\";\n input.addEventListener(\"change\", () => {\n const n = Number(input.value);\n if (isLineThickness(n)) {\n onChange(n);\n }\n });\n this.addRow(label, input, onReset);\n return (value) => {\n input.value = String(value);\n };\n }\n\n /**\n * 色のスウォッチを並べた行。選んだ choice を onChange に渡す。\n * 返す関数に、押された状態にする choice の判定を渡して、表示を選択中の要素に合わせる。\n */\n private addSwatches<T extends SwatchChoice>(\n label: string,\n choices: readonly T[],\n { onChange, onReset }: Omit<InputOptions<T>, \"label\">,\n ): (isPressed: (choice: T) => boolean) => void {\n const group = document.createElement(\"div\");\n group.className = \"playmaker-panel__swatches\";\n if (choices.some((choice) => choice.fill === \"outline\")) {\n group.classList.add(\"playmaker-panel__swatches--rows\");\n }\n const swatches = choices.map((choice) => {\n const btn = createSwatch(choice);\n btn.addEventListener(\"click\", () => onChange(choice));\n group.appendChild(btn);\n return { btn, choice };\n });\n this.addGroupRow(label, group, onReset);\n return (isPressed) => {\n for (const { btn, choice } of swatches) {\n btn.setAttribute(\"aria-pressed\", String(isPressed(choice)));\n }\n };\n }\n\n private addSelect<T extends string>(\n labelText: string,\n options: readonly T[],\n optionLabels: Readonly<Record<T, string>>,\n onChange: (v: T) => void,\n ): (value: T) => void {\n const select = document.createElement(\"select\");\n for (const opt of options) {\n const o = document.createElement(\"option\");\n o.value = opt;\n o.textContent = optionLabels[opt];\n select.appendChild(o);\n }\n select.addEventListener(\"change\", () => {\n if (isOneOf(select.value, options)) {\n onChange(select.value);\n }\n });\n this.addRow(labelText, select);\n return (value) => {\n select.value = value;\n };\n }\n}\n","import {\n canLoadFormation,\n Disposable,\n EDITOR_TOOL_VALUES,\n type EditorTool,\n type EditorViewState,\n FIELD_ZONE_LABELS,\n FIELD_ZONE_VALUES,\n type FieldZone,\n FORMATION_PRESETS,\n getFormationPreset,\n type IEditorUi,\n isToolAvailable,\n MAX_LINES,\n MAX_PLAYERS,\n TEAM_SIDE_VALUES,\n type TeamSide,\n toDisposable,\n} from \"../../common/index.js\";\n\nconst TOOL_LABELS = {\n select: \"選択\",\n \"add-player\": \"選手を追加\",\n \"draw-line\": \"線を描く\",\n} satisfies Record<EditorTool, string>;\n\n// 件数の上限に達して押せない部品に、理由として出す文。\nconst FORMATION_LIMIT_REASON = `置くと ${MAX_PLAYERS} 人を超えるフォーメーションは読み込めません`;\nconst TOOL_UNAVAILABLE_REASONS: Readonly<Partial<Record<EditorTool, string>>> = {\n \"add-player\": `選手は ${MAX_PLAYERS} 人までです`,\n \"draw-line\": `線は ${MAX_LINES} 本までです`,\n};\n\nconst SIDE_LABELS = {\n offense: \"オフェンス\",\n defense: \"ディフェンス\",\n} satisfies Record<TeamSide, string>;\n\n/**\n * disabled ではなく aria-disabled で無効を示す。disabled にすると、押した直後に\n * 無効になったボタンからフォーカスが body へ落ち、\n * 編集 UI の中で受けているショートカットが効かなくなる。\n */\nfunction setEnabled(button: HTMLButtonElement, enabled: boolean, reason?: string): void {\n button.setAttribute(\"aria-disabled\", String(!enabled));\n setTitle(button, enabled ? undefined : reason);\n}\n\nfunction setTitle(element: HTMLElement, title: string | undefined): void {\n if (title === undefined) {\n element.removeAttribute(\"title\");\n } else {\n element.title = title;\n }\n}\n\nexport class Toolbar extends Disposable {\n readonly element: HTMLElement;\n private readonly toolButtons = new Map<EditorTool, HTMLButtonElement>();\n private readonly zoneButtons = new Map<FieldZone, HTMLButtonElement>();\n private readonly undoButton: HTMLButtonElement;\n private readonly redoButton: HTMLButtonElement;\n private readonly deleteButton: HTMLButtonElement;\n private readonly commitButton: HTMLButtonElement;\n private readonly cancelButton: HTMLButtonElement;\n private readonly formationPicker: HTMLSelectElement;\n\n constructor(parent: HTMLElement, controller: IEditorUi) {\n super();\n this.element = document.createElement(\"div\");\n this.element.className = \"playmaker-toolbar\";\n\n for (const tool of EDITOR_TOOL_VALUES) {\n const btn = this.addButton(TOOL_LABELS[tool], () => controller.setTool(tool));\n this.toolButtons.set(tool, btn);\n }\n this.addSeparator();\n this.undoButton = this.addButton(\"元に戻す\", () => controller.undo());\n this.redoButton = this.addButton(\"やり直す\", () => controller.redo());\n this.deleteButton = this.addButton(\"削除\", () => controller.deleteSelection());\n this.addSeparator();\n for (const zone of FIELD_ZONE_VALUES) {\n const btn = this.addButton(FIELD_ZONE_LABELS[zone], () => controller.setFieldZone(zone));\n this.zoneButtons.set(zone, btn);\n }\n this.addSeparator();\n this.formationPicker = this.addFormationPicker(controller);\n this.addSeparator();\n this.commitButton = this.addButton(\"線を確定\", () => controller.commitLine());\n this.cancelButton = this.addButton(\"取消\", () => controller.cancelInteraction());\n\n parent.appendChild(this.element);\n this._register(toDisposable(() => this.element.remove()));\n this._register(controller.onDidChangeViewState(() => this.sync(controller)));\n this.sync(controller);\n }\n\n private addButton(label: string, onClick: () => void): HTMLButtonElement {\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.textContent = label;\n button.className = \"playmaker-toolbar__button\";\n button.addEventListener(\"click\", () => {\n if (button.getAttribute(\"aria-disabled\") !== \"true\") {\n onClick();\n }\n });\n this.element.appendChild(button);\n return button;\n }\n\n private addSeparator(): void {\n const sep = document.createElement(\"span\");\n sep.className = \"playmaker-toolbar__sep\";\n sep.setAttribute(\"aria-hidden\", \"true\");\n this.element.appendChild(sep);\n }\n\n /**\n * 選んだあとはプレースホルダへ戻す。選んだ隊形を表示したままにすると、\n * 同じ隊形をもう一度選んでも change が起きず、続けて重ねられない。\n */\n private addFormationPicker(controller: IEditorUi): HTMLSelectElement {\n const select = document.createElement(\"select\");\n select.className = \"playmaker-toolbar__select\";\n select.setAttribute(\"aria-label\", \"フォーメーション\");\n\n const placeholder = document.createElement(\"option\");\n placeholder.value = \"\";\n placeholder.textContent = \"フォーメーション読込…\";\n select.appendChild(placeholder);\n\n for (const side of TEAM_SIDE_VALUES) {\n const group = document.createElement(\"optgroup\");\n group.label = SIDE_LABELS[side];\n for (const formation of FORMATION_PRESETS.filter((f) => f.side === side)) {\n const option = document.createElement(\"option\");\n option.value = formation.id;\n option.textContent = formation.name;\n group.appendChild(option);\n }\n select.appendChild(group);\n }\n\n select.addEventListener(\"change\", () => {\n const preset = getFormationPreset(select.value);\n if (preset !== undefined) {\n controller.loadFormation(preset);\n }\n select.value = \"\";\n });\n\n this.element.appendChild(select);\n return select;\n }\n\n private sync(controller: IEditorUi): void {\n const state = controller.getViewState();\n for (const [tool, btn] of this.toolButtons) {\n btn.setAttribute(\"aria-pressed\", String(tool === state.tool));\n setEnabled(btn, isToolAvailable(tool, state), TOOL_UNAVAILABLE_REASONS[tool]);\n }\n for (const [zone, btn] of this.zoneButtons) {\n btn.setAttribute(\"aria-pressed\", String(zone === state.fieldZone));\n }\n setEnabled(this.undoButton, state.canUndo);\n setEnabled(this.redoButton, state.canRedo);\n setEnabled(this.deleteButton, state.selection.kind !== \"none\");\n setEnabled(this.commitButton, state.isDrawing);\n setEnabled(this.cancelButton, state.isDrawing);\n this.syncFormationPicker(state);\n }\n\n private syncFormationPicker(state: EditorViewState): void {\n let isAnyUnavailable = false;\n for (const option of this.formationPicker.options) {\n const formation = getFormationPreset(option.value);\n option.disabled = formation !== undefined && !canLoadFormation(formation, state);\n isAnyUnavailable ||= option.disabled;\n }\n setTitle(this.formationPicker, isAnyUnavailable ? FORMATION_LIMIT_REASON : undefined);\n }\n}\n","import {\n CanvasSurface,\n PointerInput,\n PropertyPanel,\n replaceKeepingFocus,\n Toolbar,\n} from \"./browser/index.js\";\nimport {\n DisposableStore,\n type EditorOverlay,\n type Event,\n type FieldZone,\n type Formation,\n type IDisposable,\n type ImageExportOptions,\n type PlayData,\n type PlayDataInput,\n PlaySession,\n toDisposable,\n} from \"./common/index.js\";\nimport \"./styles.css\";\n\nexport type {\n Event,\n FieldPosition,\n FieldState,\n FieldZone,\n Formation,\n FormationPlayer,\n IDisposable,\n ImageExportOptions,\n Line,\n LineInterpolation,\n LineKind,\n PlayCategory,\n PlayData,\n PlayDataInput,\n Player,\n PlayerFill,\n PlayerShape,\n PlayPreset,\n TeamSide,\n} from \"./common/index.js\";\nexport {\n CURRENT_PLAY_DATA_VERSION,\n FIELD_WIDTH_YARDS,\n FIELD_ZONE_LABELS,\n FIELD_ZONE_VALUES,\n FORMATION_PRESETS,\n GRID_STEP_YARDS,\n getFormationPreset,\n getPlayPreset,\n migratePlayData,\n PLAY_PRESETS,\n} from \"./common/index.js\";\n\nexport type PlaymakerMode = \"view\" | \"edit\";\n\n// バンドラは process.env.NODE_ENV を文字列に置き換える。置き換えずにブラウザで読み込むと\n// process が無く ReferenceError になるので、そのときは本番とみなす。\ndeclare const process: { readonly env: { readonly NODE_ENV?: string } };\n\nfunction isDevelopment(): boolean {\n try {\n return process.env.NODE_ENV !== \"production\";\n } catch {\n return false;\n }\n}\n\nexport interface PlaymakerOptions {\n /**\n * 最初のモード。既定は \"edit\"。\"view\" は編集 UI を置かず、ポインタとキーの操作も受けない。\n * あとから `setMode` で切り替えられる。\n */\n mode?: PlaymakerMode | undefined;\n /** 最初に表示する図。`restorePlayData` と同じく、形を確かめずに受け取って今のスキーマへ寄せる。 */\n initialData?: unknown;\n /** 構築時に `onDidChange` へ登録するリスナ。解除するには Playmaker を dispose する。 */\n onChange?: ((data: PlayData) => void) | undefined;\n}\n\n/**\n * container の中にプレー図を描き、edit モードでは編集 UI も置く。\n * dispose すると、置いた要素をすべて取り除く。\n * dispose したあとの変更は例外を投げずに何もせず、開発時だけ console.warn で知らせる。\n * getPlayData と fieldZone は、dispose した時点の図を返す。\n */\nexport class Playmaker implements IDisposable {\n /**\n * 編集コマンドと Undo / Redo の確定ごとに 1 回、最新の図の深いコピーを渡す。\n * `version` は常に現行なので、受け取った値をそのまま永続化できる。\n * 構築時、`setPlayData` と `restorePlayData` での読み込み、PNG の書き出しでは発火しない\n * (読み込みは編集ではないため)。\n * コピーはリスナごとに作るので、受け手が書き換えても、この図とほかのリスナには波及しない。\n * 返り値を dispose すると購読をやめる。\n */\n readonly onDidChange: Event<PlayData>;\n private readonly store = new DisposableStore();\n private readonly root: HTMLElement;\n private readonly surface: CanvasSurface;\n private readonly session: PlaySession;\n private currentMode: PlaymakerMode;\n private panel: PropertyPanel | undefined;\n // 今の controller に付けた UI と入力。controller かモードが変わると付け直す。\n private ui: DisposableStore;\n\n constructor(container: HTMLElement, options: PlaymakerOptions = {}) {\n this.currentMode = options.mode ?? \"edit\";\n this.session = this.store.add(new PlaySession(options.initialData));\n this.onDidChange = this.session.onDidChange;\n if (options.onChange !== undefined) {\n this.store.add(this.session.onDidChange(options.onChange));\n }\n\n this.root = document.createElement(\"div\");\n this.root.className = \"playmaker-root\";\n this.root.dataset.mode = this.currentMode;\n container.appendChild(this.root);\n this.store.add(toDisposable(() => this.root.remove()));\n\n const stage = document.createElement(\"div\");\n stage.className = \"playmaker-stage\";\n this.root.appendChild(stage);\n const { scene, overlay } = this.session.controller.getFrame();\n this.surface = this.store.add(new CanvasSurface(stage, scene, this.surfaceOverlay(overlay)));\n // CanvasSurface は最初の大きさが決まったときに今の図を描くので、ここでは描かない。\n this.ui = this.createUi();\n this.store.add(this.session.onDidChangeScene(() => this.draw()));\n // 読み直したあとは session が描き直しを通知するので、ここでは UI だけを付け直す。\n this.store.add(this.session.onDidReset(() => this.replaceUi()));\n }\n\n get mode(): PlaymakerMode {\n return this.currentMode;\n }\n\n /**\n * モードを切り替える。図と Undo の履歴は残し、編集 UI とポインタ、キーの入力だけを付け外しする。\n * view にすると、ドラッグや作図の途中の操作は取り消し、選択の強調も描かない。\n */\n setMode(mode: PlaymakerMode): void {\n if (this.store.isDisposed) {\n this.warnIgnoredAfterDispose(\"setMode\");\n return;\n }\n if (mode === this.currentMode) {\n return;\n }\n this.currentMode = mode;\n this.root.dataset.mode = mode;\n if (mode === \"view\") {\n this.session.controller.cancelInteraction();\n }\n this.replaceUi();\n this.draw();\n }\n\n get fieldZone(): FieldZone {\n return this.session.fieldZone;\n }\n\n /**\n * LOS をそのゾーンの既定の位置へ移し、選手と線も一緒に動かす。\n * 編集なので Undo と onDidChange の対象になる。view モードでも呼べる。\n */\n setFieldZone(zone: FieldZone): void {\n if (this.store.isDisposed) {\n this.warnIgnoredAfterDispose(\"setFieldZone\");\n return;\n }\n this.session.setFieldZone(zone);\n }\n\n /**\n * 隊形の選手を今の図に追記し、置いたら true を返す。攻守の隊形を順に重ねられる。\n * 選手の位置は LOS からの相対(`lateralYard` と `downfieldYard`)で書く。\n * 外から渡した隊形は正規化してから読むので、位置の読めない選手は捨てる。\n * 置ける選手が 1 人もいないときと、置くと選手が 64 人を超えるときは、1 人も置かずに false を返す。\n * 編集なので Undo と onDidChange の対象になる。view モードでも呼べる。\n */\n loadFormation(formation: Formation): boolean {\n if (this.store.isDisposed) {\n this.warnIgnoredAfterDispose(\"loadFormation\");\n return false;\n }\n return this.session.loadFormation(formation);\n }\n\n /**\n * 型付きで組み立てた図を読み込み、今の図と置き換える。`getPlayData` の戻り値や、\n * プリセットの `data` もそのまま渡せる。\n * 型に合っていても、重複した id と件数の上限を超えた分は `restorePlayData` と同じく正規化する。\n * 読み込みは編集ではないので、Undo の履歴は消え、onDidChange は発火しない。\n */\n setPlayData(data: PlayDataInput): void {\n if (this.store.isDisposed) {\n this.warnIgnoredAfterDispose(\"setPlayData\");\n return;\n }\n this.session.setPlayData(data);\n }\n\n /**\n * 永続化しておいた値を、形を確かめずに受け取って読み込み、今の図と置き換える。\n * 旧版、版の無いもの、未来版、壊れたデータも、例外を投げずに今のスキーマへ寄せ、読めない要素だけを捨てる。\n * 選手 64 人、線 128 本、線 1 本あたり waypoint 32 個を超える分は、先頭から上限までを残して捨てる。\n * 読み込みは編集ではないので、Undo の履歴は消え、onDidChange は発火しない。\n */\n restorePlayData(raw: unknown): void {\n if (this.store.isDisposed) {\n this.warnIgnoredAfterDispose(\"restorePlayData\");\n return;\n }\n this.session.setPlayData(raw);\n }\n\n /**\n * 今の図の深いコピー。`version` は常に現行で、そのまま JSON にして永続化できる。\n * `restorePlayData` か `initialData` に戻すと、同じ図になる。\n * 編集でも件数の上限は超えられず、上限に達すると選手の追加、フォーメーションの読み込み、作図は何もしない。\n */\n getPlayData(): PlayData {\n return this.session.getPlayData();\n }\n\n /**\n * 呼んだ時点で確定しているプレー図を PNG 画像(Blob)として書き出す。\n * 選択の強調、waypoint のハンドル、ドラッグや作図の途中の形、ツールバーとパネルは入らない。\n * view と edit のどちらのモードでも使える。\n * 同梱フォントを読み込み終えてから描くので、構築の直後に呼んでもヤードの数字と選手のラベルは同梱フォントになる。\n * フォントを読み込めなかったときは代わりのフォントで描く。\n * canvas を確保できないとき、PNG に変換できないとき、dispose したあとは、例外を投げずに reject する。\n */\n exportToPng(options?: ImageExportOptions): Promise<Blob> {\n if (this.store.isDisposed) {\n return Promise.reject(new Error(\"Playmaker: dispose したあとは PNG を書き出せません。\"));\n }\n return this.surface.exportToPngBlob(this.session.getSnapshot(), options);\n }\n\n /**\n * 図とパネルの色を、テーマの CSS 変数から読み直す。CSS 変数を変えてもブラウザは知らせてこないので、\n * ホストが祖先の要素で変数を変えたあとに呼ぶ。\n */\n refresh(): void {\n if (this.store.isDisposed) {\n this.warnIgnoredAfterDispose(\"refresh\");\n return;\n }\n this.surface.refresh();\n this.panel?.refresh();\n }\n\n dispose(): void {\n this.ui.dispose();\n this.store.dispose();\n }\n\n /** dispose したあとの呼び出しは何もしないので、開発時だけそのことを知らせる。 */\n private warnIgnoredAfterDispose(method: string): void {\n if (isDevelopment()) {\n console.warn(`Playmaker: dispose したあとに ${method} を呼んだので、何もしません。`);\n }\n }\n\n private replaceUi(): void {\n // view では canvas がフォーカスを受けないので、消えたフォーカスは body に落ちたままになる。\n replaceKeepingFocus(this.root, this.surface.canvas, () => {\n this.ui.dispose();\n this.ui = this.createUi();\n });\n }\n\n private createUi(): DisposableStore {\n const ui = new DisposableStore();\n const controller = this.session.controller;\n this.panel = undefined;\n if (this.currentMode === \"edit\") {\n ui.add(new Toolbar(this.root, controller));\n this.panel = ui.add(new PropertyPanel(this.root, controller, this.surface.canvas));\n ui.add(new PointerInput(this.root, this.surface, controller));\n }\n return ui;\n }\n\n private draw(): void {\n const { scene, overlay } = this.session.controller.getFrame();\n this.surface.setScene(scene, this.surfaceOverlay(overlay));\n }\n\n /** view モードでは undefined を返し、格子や選択の強調のような編集中だけの層を描かせない。 */\n private surfaceOverlay(overlay: EditorOverlay): EditorOverlay | undefined {\n return this.currentMode === \"edit\" ? overlay : undefined;\n }\n}\n"],"mappings":"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"}
|