Stories Core

@reelkit/react-stories-player を支えるエンジンです。純粋な TypeScript で、フレームワークへの依存はありません。Angular、Vue、素の JavaScript でストーリープレイヤーを作るのに使います。

フレームワークに依存しない
純粋な TypeScript で、DOM フレームワークへの依存なし
2 階層のナビゲーション
グループと、各グループ内のストーリー
RAF タイマー
requestAnimationFrame による自動送り、一時停止と再開にも対応
Canvas の進捗表示
Retina 対応の分割された進捗バー、スライドするウィンドウ付き
タップゾーン
左右のタップ判定を設定できます
リアクティブなシグナル
@reelkit/core のシグナルプリミティブの上に構築

インストール

bash

Stories コントローラー

createStoriesController(config, events?) はグループとストーリーをまたいだナビゲーションを管理します。一時停止と再開の状態を追跡し、グループごとに最後に見たストーリーを覚え、切り替えのたびにコールバックを呼びます。

設定(StoriesControllerConfig)

プロパティデフォルト説明
groupCountnumber必須ストーリーのグループの総数
storyCountsnumber[]必須各グループのストーリー数
initialGroupIndexnumber0最初のグループのインデックス
initialStoryIndexnumberresumeStoryIndex(initialGroupIndex)、なければ 0グループ内の最初のストーリーのインデックス。指定すると覚えている位置より優先されます。省略すると、開いたグループもほかのグループと同じように続きから始まります。
defaultImageDurationnumber5000画像のストーリーを自動で送るまでのデフォルトの時間(ms)
resumeStoryIndex(groupIndex: number) => numberundefinedまだ訪れていないグループが開くストーリー。そのグループにあるストーリーの範囲に収められます

イベント(StoriesControllerEvents)

イベント説明
onStoryChange(groupIndex, storyIndex) => voidアクティブなストーリーが変わったときに呼ばれます
onGroupChange(groupIndex) => voidアクティブなグループが変わったときに呼ばれます
onStoryViewed(groupIndex, storyIndex) => voidストーリーが表示されたときに呼ばれます
onStoryComplete(groupIndex, storyIndex) => voidストーリーのタイマーが終わったとき(送る前)に呼ばれます
onComplete() => void最後のグループの最後のストーリーが終わったときに呼ばれます
onClose() => voidオーバーレイを閉じるべきときに呼ばれます

状態(リアクティブなシグナル)

シグナル説明
state.activeGroupIndexSignal<number>現在アクティブなグループのインデックス
state.activeStoryIndexSignal<number>グループ内で現在アクティブなストーリーのインデックス
state.isPausedSignal<boolean>自動送りが一時停止しているかどうか

メソッド

メソッド説明
nextStory()() => voidグループ内で進みます。端に達したら次のグループへ移ります
prevStory()() => voidグループ内で戻ります。端に達したら前のグループへ移ります
nextGroup()() => void次のグループへ切り替え、最後に見たストーリーから再開します
prevGroup()() => void前のグループへ切り替え、最後に見たストーリーから再開します
goToGroup(index)(number) => voidインデックスで指定したグループへ移動します
pause()() => void自動送りを一時停止します
resume()() => void自動送りを再開します
onStoryTimerComplete()() => voidタイマーが終わったときに呼ばれ、onStoryComplete を呼んでから進みます
getLastStoryIndex(groupIndex)(number) => numberグループが開く位置です。このセッションで離れたストーリー、なければ resumeStoryIndex が示すストーリー
reportInitialView()() => voidプレイヤーが開いたときのストーリーを、一度だけ既読として報告します。描画中ではなく、マウント後に呼んでください。

typescript

タイマーコントローラー

createTimerController(config)requestAnimationFrame のループで自動送りを動かします。進捗のシグナル(0 から 1)が進捗バーに使われます。一時停止と再開では正確な位置が保たれます。

設定(TimerControllerConfig)

プロパティデフォルト説明
durationnumber必須デフォルトの長さ(ミリ秒)
onComplete() => voidundefinedタイマーが 100% に達したときに呼ばれます

状態

シグナル説明
progressSignal<number>進捗のシグナル(0 から 1)
isRunningSignal<boolean>タイマーが動いているかどうか

メソッド

メソッド説明
start(duration?)(number?) => voidタイマーを開始(または再開始)します。長さを上書きすることもできます
pause()() => void現在の位置で進捗を止めます
resume()() => void止めた位置から続けます
reset()() => void進捗を 0 に戻して止めます
dispose()() => voidリソースを片付けます

typescript

Canvas プログレスレンダラー

createCanvasProgressRenderer(config?) は分割された進捗バーを canvas に描きます。Retina ディスプレイに合わせて拡大し、ResizeObserver でコンテナーを計測し、セグメントが収まらないときはスライドするウィンドウを使います。

設定(CanvasProgressRendererConfig)

プロパティデフォルト説明
gapnumber2セグメント間の間隔(ピクセル)
barHeightnumber2バーの高さ(ピクセル)
minSegmentWidthnumber8スライドするウィンドウに切り替わる前のセグメントの最小幅
bgColorstring'rgba(255,255,255,0.3)'塗られていないセグメントの背景色
fillColorstring'#ffffff'完了したセグメントとアクティブなセグメントの塗りの色

メソッド

メンバー説明
attach(canvas)(HTMLCanvasElement) => voidcanvas 要素に接続し、親要素で ResizeObserver を開始します
draw(totalStories, activeIndex, progress)(number, number, number) => void指定した状態で進捗バーを描きます
widthnumber (readonly)現在計測されている幅(CSS ピクセル)
dispose()() => voidResizeObserver と内部の状態を片付けます

typescript

既読の状態

createStoriesViewedState(controller, groups) は、コアの ViewedStateController を、プレイヤーが使う言葉(グループ、作者、ストーリーのインデックス)で読みます。ストア自体はそれらを何も知らないままです。StoriesViewedState を返します。アドレスバーと同じキーを使い、グループごとに追跡してストアを作れば、保存されたエントリーは共有リンクのパラメーターとまったく同じになります。

パラメーター説明
controllerViewedStateController<TwoAxisPosition>アドレスバーと同じキーで作ったコアのストアです。各グループが自分のエントリーを持つよう、twoAxisViewedTracking と一緒に展開します
groups() => StoriesGroup<T>[]現在のグループを読みます。getter なので、設定のあとでページングされたり並べ替えられたりしたフィードも、呼び出し時点で計測されます。

StoriesViewedState

メソッド説明
viewedCounts()() => Map<string, number>グループごとに見たストーリーの数で、キーは作者の id です。StoriesRingList が viewedState として受け取る形です
resumeStoryIndex(groupIndex)(number) => numberまだ見ていない最初のストーリー。グループを最後まで見ていれば 0
markViewed(groupIndex, storyIndex)(number, number) => voidストーリーを既読として記録します。onStoryViewed につないでください。

typescript

エントリーが表すのは閲覧回数の合計ではなく、到達したいちばん先のストーリーです。そのため id で指すキーなら、フィードが並べ替えられてもグループの位置は保たれ、グループの途中からストーリーが削除されると件数が減ってリングがまた点灯します。

ユーティリティ関数

タップゾーンの判定と、進捗バーの計算のための純粋関数です。

関数説明
getTapAction(tapX, containerWidth, splitRatio?)(number, number, number?) => 'prev' | 'next'位置に応じて、タップが 'prev' と 'next' のどちらになるかを決めます。splitRatio のデフォルトは 0.3 です。
getSegments(totalStories, activeIndex, progress)(number, number, number) => SegmentState[]進捗バーの各セグメントの状態と塗りの割合を計算します
getVisibleWindow(totalStories, activeIndex, progress, containerWidth, minSegmentWidth?, gap?)(number, number, number, number, number?, number?) => VisibleWindow総数がコンテナーに収まらないときに、表示するセグメントのスライドするウィンドウを計算します

@reelkit/stories-core がエクスポートするすべての型定義です。

typescript