387 Commits

Author SHA1 Message Date
harukin-expo-dev-env
59e7ba5290 Merge commit '83539d5df30b6569bf7259d7ef79400b6f88a5e3' into patch/6.x 2025-09-25 03:00:11 +00:00
harukin-expo-dev-env
83539d5df3 伊予大洲で表示に失敗していた問題を修正 2025-09-25 02:59:59 +00:00
harukin-expo-dev-env
9e831ecd6e Merge commit '4e367d1e3cec6320dc709003783142370fb2acce' into patch/6.x 2025-09-24 16:59:52 +00:00
harukin-expo-dev-env
4e367d1e3c Merge commit '4151f3f0569d83d2476dbba71bd5f3464c730c7a' into develop 2025-09-24 16:27:42 +00:00
harukin-expo-dev-env
4151f3f056 StationDiagramViewを一端封鎖(ユーザー指定) 2025-09-24 16:27:34 +00:00
harukin-expo-dev-env
1073d1f681 RC 6.1.8 2025-09-24 16:25:07 +00:00
harukin-expo-dev-env
7f0e56e86c Merge commit '8702b22cddfadcfed34e30dede2ad90f2647a0da' into develop 2025-09-24 16:24:08 +00:00
harukin-expo-dev-env
8702b22cdd 通休編を自動挿入される通過にも適用されるように変更 2025-09-24 16:14:35 +00:00
harukin-expo-dev-env
3dbcc93448 追跡ができなくなったら解除するように変更 2025-09-24 13:05:55 +00:00
harukin-expo-dev-env
211e361285 宇多津関係の挙動を変更 2025-09-24 12:55:30 +00:00
harukin-expo-dev-env
e05da6e2d3 不要なcnsleを削除 2025-09-24 11:30:12 +00:00
harukin-expo-dev-env
ba074a181c 特急停車駅の処理ミスを修正 2025-09-24 11:00:32 +00:00
harukin-expo-dev-env
525fbaa717 推定位置移動を作成、デザインを調整 2025-09-24 10:48:34 +00:00
harukin-expo-dev-env
7ab402d35f 伊予若宮信号所の処理を詳細化 2025-09-24 09:45:08 +00:00
harukin-expo-dev-env
c0a29fab0d エリア指定のミスを修正 2025-09-24 08:11:18 +00:00
harukin-expo-dev-env
f7e59cd75b 不要な内容の整理とコードの並び替え 2025-09-24 07:11:34 +00:00
harukin-expo-dev-env
7ae6bc8801 Merge commit 'ba65389596851e99fe0a3f4fad95b4fd6ea0448c' into develop 2025-09-23 17:58:35 +00:00
harukin-expo-dev-env
ba65389596 Fixが起動している間は画面を消さないように変更 2025-09-23 16:37:35 +00:00
harukin-expo-dev-env
83e45e1aa3 stringサイズ条件のミスを修正 2025-09-23 16:33:30 +00:00
harukin-expo-dev-env
2d6a67c793 拡大縮小ボタンの当たり判定を修正 2025-09-23 16:32:15 +00:00
harukin-expo-dev-env
6b6c2d7eba Merge commit 'd36195df697d4ba9f356c0c9840f1af494eda2e4' into develop 2025-09-23 15:41:02 +00:00
harukin-expo-dev-env
d36195df69 検索ボックス候補機能を暫定作成 2025-09-23 14:45:51 +00:00
harukin-expo-dev-env
8ddf3a3e8d フォント実装、臨時列車のフィルタリング機能強化 2025-09-19 14:15:45 +00:00
harukin-expo-dev-env
1b26afb37b フィルタリング項目での駅名検索での前後関係を見るように変更 2025-09-19 05:21:06 +00:00
harukin-expo-dev-env
25ff4a8019 Merge commit 'c8119e23731a23984f7aabfed0874a9a96303afd' into develop 2025-09-19 04:34:37 +00:00
harukin-expo-dev-env
c8119e2373 各種調整 2025-09-19 04:34:26 +00:00
harukin-expo-dev-env
85fd66b728 fixedTrainBoxのレイアウト変更 2025-09-16 11:29:05 +00:00
harukin-expo-dev-env
2fe525d620 fix 2025-09-14 18:27:01 +00:00
harukin-expo-dev-env
acb1849544 FixedBoxを拡張可能に変更 2025-09-14 18:25:06 +00:00
harukin-expo-dev-env
3531a128ab テキストのサイズ調整 2025-09-14 10:02:06 +00:00
harukin-expo-dev-env
64de920dc6 keyErrorを追加で修正 2025-09-13 16:35:01 +00:00
harukin-expo-dev-env
a650a21669 keyErrorを修正 2025-09-13 15:14:46 +00:00
harukin-expo-dev-env
7dc3c324f9 reloadをinject経由からuseIntervalへ変更 2025-09-13 14:31:14 +00:00
harukin-expo-dev-env
4edfb951d4 細かい仕様調整 2025-09-13 14:02:56 +00:00
harukin-expo-dev-env
60e1dcd1a5 timeFilteringをリファクタリング 2025-09-13 14:02:06 +00:00
harukin-expo-dev-env
a8cf24e745 4時を日付変更線に設定 2025-09-13 12:07:28 +00:00
harukin-expo-dev-env
19103d9796 時刻フィルタリングのロジックをdayjsベースに調整 2025-09-13 12:04:13 +00:00
harukin-expo-dev-env
50b2cbb21c path修正 2025-09-12 19:05:18 +00:00
harukin-expo-dev-env
7bea2ac454 詳細な型設定の変更 2025-09-12 17:42:39 +00:00
harukin-expo-dev-env
2d0c7605f6 部分的にtsxへ移動 2025-09-11 17:10:44 +00:00
harukin-expo-dev-env
58df77ae49 tsxのFC宣言をProviderに追加 2025-09-11 16:55:05 +00:00
harukin-expo-dev-env
9ac36216b9 CustomTrainDataTypeを適用 2025-09-11 16:31:36 +00:00
harukin-expo-dev-env
338afb087a getCurrentTrainDataを移動 2025-09-11 16:25:03 +00:00
harukin-expo-dev-env
71ee79289a getTrainTypeの仕様更新 2025-09-11 16:11:36 +00:00
harukin-expo-dev-env
ad2d18e263 getTrainTypeの仕様変更に追従 2025-09-11 16:08:03 +00:00
harukin-expo-dev-env
9ab4c0a205 tsへファイル移動 2025-09-11 15:05:32 +00:00
harukin-expo-dev-env
0d9c1cdb18 Merge commit 'd419e90140d9d9dbaf6e4ec7afce0df5fa20239a' into patch/6.x 2025-09-11 05:55:20 +00:00
harukin-expo-dev-env
d419e90140 ios-beta-build-season 2025-09-11 05:55:13 +00:00
harukin-expo-dev-env
bc4cb450a3 Merge commit '6de39e53b6fae73e21c26727e83a4463f83b51f0' into patch/6.x 2025-09-09 16:16:46 +00:00
harukin-expo-dev-env
6de39e53b6 6.1.7 release 2025-09-09 16:16:33 +00:00
harukin-expo-dev-env
2fa4ea75ee 初歩的なミスを修正 2025-09-09 15:57:31 +00:00
harukin-expo-dev-env
ddb467e4c6 Merge commit 'a593958feb028b16052258756040079f5e90a2b0' into develop 2025-09-09 15:10:23 +00:00
harukin-expo-dev-env
a593958feb 休編を追加 2025-09-09 15:10:15 +00:00
harukin-expo-dev-env
ea2ae7037a Merge commit 'c7487d38dba1f34e3f4fbe4a2071c4e7b227fce5' into develop 2025-09-09 14:58:41 +00:00
harukin-expo-dev-env
c7487d38db 列車の現在地が追従するように変更 2025-09-09 14:28:34 +00:00
harukin-expo-dev-env
30c05bdee6 停車する列車以外を表示しないように変更、横モードを仮有効化 2025-09-08 18:46:54 +00:00
harukin-expo-dev-env
4674f46c82 種別表示機能を追加 2025-09-08 18:09:20 +00:00
harukin-expo-dev-env
b43604c7f1 時刻を4時で日付変更線として設定 2025-09-08 15:12:22 +00:00
harukin-expo-dev-env
4dba21ccdd 列車情報が正しく表示されるように更新 2025-09-08 14:50:36 +00:00
harukin-expo-dev-env
b0cf702620 とりあえず最低限の駅発車情報が動作がするように作成 2025-09-08 12:28:10 +00:00
harukin-expo-dev-env
b76f1adec1 レイアウト変更 2025-09-08 11:22:36 +00:00
harukin-expo-dev-env
869731eedf ファイル移動 2025-09-07 14:54:34 +00:00
harukin-expo-dev-env
5d9a7e185f 左側の情報一通り完成 2025-09-07 14:29:54 +00:00
harukin-expo-dev-env
7b9cbf963e コードの整理とデータの供給元の整理 2025-09-07 09:51:26 +00:00
harukin-expo-dev-env
74054b107d 列車位置のレイアウトを調整 2025-09-07 09:09:06 +00:00
harukin-expo-dev-env
0c2c733a59 Merge commit '291091a3ec8b8a4475646f21f59886c399a86495' into feature/position-tracking-system 2025-09-05 10:51:44 +00:00
harukin-expo-dev-env
291091a3ec Merge commit '405f91a7d8dc09a15eb70c60306049cfbd54c7c9' into develop 2025-09-05 10:30:21 +00:00
harukin-expo-dev-env
405f91a7d8 タブレット端末で運行情報ページの表示がイマイチだったバグを修正 2025-09-05 10:30:08 +00:00
harukin-expo-dev-env
3d3414fc1a Merge commit '8970eedbfbc871b6dd8107ddbfb9de8aac7e4720' into develop 2025-09-05 09:24:06 +00:00
harukin-expo-dev-env
8970eedbfb 全列車探索機能で上書き列番を検索対象に追加 2025-09-05 09:23:02 +00:00
harukin-expo-dev-env
b0a488868e Merge commit '01378c2f7e3004ecd500d6611117af4d343335c2' into feature/position-tracking-system 2025-09-04 21:03:59 +00:00
harukin-expo-dev-env
01378c2f7e Merge commit 'a5139aca63b53bee3c25c63386e3722a42a32a52' into develop 2025-09-04 21:03:50 +00:00
harukin-expo-dev-env
a5139aca63 updatePermission持ちのみ表示可能に変更 2025-09-04 21:03:25 +00:00
harukin-expo-dev-env
a0cfca7a41 Merge commit '63ae4e8c14576270b3678df7e6210099aadb627a' into develop 2025-09-04 20:56:25 +00:00
harukin-expo-dev-env
63ae4e8c14 小修整 2025-09-04 20:55:48 +00:00
harukin-expo-dev-env
b7d3dccd95 時刻表フィルタリング機能一通り完成 2025-09-04 20:52:18 +00:00
harukin-expo-dev-env
cafb5b04f5 列車種別フィルタリングを実装するための準備 2025-09-04 18:14:33 +00:00
harukin-expo-dev-env
92b5052f3b 駅名入力でフィルタリングする機能を追加 2025-09-03 13:52:56 +00:00
harukin-expo-dev-env
620be8b58e 画面表示全体的に作成 2025-09-01 15:28:05 +00:00
harukin-expo-dev-env
ac11117fd6 暫定的に動作するように変更 2025-09-01 11:55:40 +00:00
harukin-expo-dev-env
eda1d10c0c 変数の定義をミスしていたので修正 2025-08-31 16:15:32 +00:00
harukin-expo-dev-env
b37b40b6a8 変数の定義をミスしていたので修正 2025-08-31 16:15:12 +00:00
harukin-expo-dev-env
0c64f7af45 列車走行位置へのジャンプ機能をuseCurrentTrainへ移動 2025-08-31 15:43:25 +00:00
harukin-expo-dev-env
99dbada0c2 useIntervalを初期stopも可能なように更新 2025-08-31 13:28:49 +00:00
harukin-expo-dev-env
2967837dd5 スクロール位置を調整 2025-08-31 09:53:38 +00:00
harukin-expo-dev-env
8b74273fed 小規模なアニメーション調整 2025-08-28 15:08:39 +00:00
harukin-expo-dev-env
b38d8fe39d 全時間帯表示、種別フィルタリング機能を追加 2025-08-28 03:56:53 +00:00
harukin-expo-dev-env
92d37b7277 現在時刻が表示されたり走行位置から列車時刻を更新したりアニメーションを強化した 2025-08-27 17:12:34 +00:00
harukin-expo-dev-env
35f1860b03 駅名の完全一致をしていなかったので修正 2025-08-27 01:35:45 +00:00
harukin-expo-dev-env
c19d9f21d1 Merge commit '2711e0850e8d7183d6a9c73a26bae23c9442cfe2' into feature/station-diagram-view-make 2025-08-27 01:20:20 +00:00
harukin-expo-dev-env
2711e0850e Merge commit '9b4c0735b0475659aa7fe1f688b8daef13b714f1' into develop 2025-08-27 01:20:15 +00:00
harukin-expo-dev-env
9b4c0735b0 6.1.6.2 2025-08-27 01:19:59 +00:00
harukin-expo-dev-env
7f3ef067ca Merge commit '036a7ee914eac55099ca5cfed6930bd31d345348' into patch/6.x 2025-08-27 01:19:28 +00:00
harukin-expo-dev-env
036a7ee914 駅名検索に通過が表示されないように編集 2025-08-27 01:19:13 +00:00
harukin-expo-dev-env
d6100c99c7 LEDテキスト表示修正 2025-08-27 00:45:32 +00:00
harukin-expo-dev-env
9410925f70 駅名カラー設定 2025-08-27 00:19:39 +00:00
harukin-expo-dev-env
7edfa62673 背景設定を整理 2025-08-26 17:59:28 +00:00
harukin-expo-dev-env
c25050f344 スクロールの挙動総合見直し 2025-08-26 17:39:55 +00:00
harukin-expo-dev-env
7e0749a2f2 スクロールの大枠の最適化 2025-08-26 17:12:57 +00:00
harukin-expo-dev-env
edc1dc5b2d 横スクロールのサイズ変更をピンチでできるようにした 2025-08-26 14:38:11 +00:00
harukin-expo-dev-env
5f7c4d202d 暫定的GridViewの実装 2025-08-26 11:37:46 +00:00
harukin-expo-dev-env
a927a73c29 ListViewを修正 2025-08-25 19:37:56 +00:00
harukin-expo-dev-env
23cd316213 小整理 2025-08-25 18:40:15 +00:00
harukin-expo-dev-env
c00034a11b 駅時刻表のコア情報を作成 2025-08-25 15:54:40 +00:00
harukin-expo-dev-env
2f558cddb2 Merge commit '087f6c882968bdef782bfe2aa0005a67fe436c7c' into develop 2025-08-24 11:29:35 +00:00
harukin-expo-dev-env
087f6c8829 6.1.6.1 2025-08-24 11:29:29 +00:00
harukin-expo-dev-env
d9a61dae33 Merge commit '391674ae427c5b1c77e4253698bdca789ce560db' into patch/6.x 2025-08-24 11:29:20 +00:00
harukin-expo-dev-env
391674ae42 通編で通過表示ができなくなっていたバグを修正 2025-08-24 11:28:51 +00:00
harukin-expo-dev-env
c7d509b61a LEDに通過列車であることを明示するように変更 2025-08-24 11:18:36 +00:00
harukin-expo-dev-env
ddaad38ccc Merge commit '0eef74a799ae8df7765d39f3d807ce2adaff6ce7' into patch/6.x 2025-08-24 04:49:08 +00:00
harukin-expo-dev-env
0eef74a799 6.1.6 release 2025-08-24 04:44:58 +00:00
harukin-expo-dev-env
eb35cb8d56 Merge commit 'bcdde280a20dd88c02134aaea66d4b917c750ddc' into develop 2025-08-24 04:43:48 +00:00
harukin-expo-dev-env
bcdde280a2 undefinedによって機能していなかった部分を修正 2025-08-24 04:43:42 +00:00
harukin-expo-dev-env
172f5aa2c8 特定条件でActionSheetが開けなくなるバグを修正 2025-08-24 04:36:01 +00:00
harukin-expo-dev-env
56240b0614 key忘れを修正 2025-08-24 04:28:30 +00:00
harukin-expo-dev-env
8f49bdb64a Merge commit '8daffd3d3b7433f818f92757d268ef186d3f45f3' into develop 2025-08-24 04:21:03 +00:00
harukin-expo-dev-env
8daffd3d3b LEDに行先変更と噂が表示されるように変更 2025-08-24 04:20:55 +00:00
harukin-expo-dev-env
4c9270171c Merge commit 'fd699c81509ba767315f54a52a8ee68265a85381' into develop 2025-08-24 03:45:30 +00:00
harukin-expo-dev-env
fd699c8150 スタイルの微調整 2025-08-24 03:43:41 +00:00
harukin-expo-dev-env
8792d3a770 時刻が表示できないバグを修正 2025-08-24 03:32:41 +00:00
harukin-expo-dev-env
c2226eb49e typeの整備 2025-08-23 20:07:05 +00:00
harukin-expo-dev-env
7e46dcda2f Merge commit '8cc1fcf3de465f7518f818c900abdd5eb81f6faf' into develop 2025-08-23 17:37:55 +00:00
harukin-expo-dev-env
8cc1fcf3de 通過情報を追加 2025-08-23 17:37:44 +00:00
harukin-expo-dev-env
ebf72e35bc とりあえず実装、明日動作チェックして挙動確認 2025-08-23 16:34:29 +00:00
harukin-expo-dev-env
37e21be4c0 タイトル要素クリック可能な時のデザインを追加 2025-08-23 14:48:58 +00:00
harukin-expo-dev-env
4d167408f2 Merge commit 'b07521e4ef6bf126f2a7debd0432489ef5655ba8' into develop 2025-08-23 14:28:55 +00:00
harukin-expo-dev-env
b07521e4ef オリジナルダイヤ表示反映に対応 2025-08-23 14:26:24 +00:00
harukin-expo-dev-env
98d3b750de 不要な要素を削除 2025-08-23 09:00:12 +00:00
harukin-expo-dev-env
cbc572ee6f Merge commit '46cff473e670b95bb836e8ac70a4b46c8bfc2587' into develop 2025-08-23 08:59:30 +00:00
harukin-expo-dev-env
46cff473e6 JRFの削除 2025-08-22 11:36:31 +00:00
harukin-expo-dev-env
7814037d2a partyのbackgoundColorを追加 2025-08-21 18:59:22 +00:00
harukin-expo-dev-env
ed6dc3809e Partyを追加 2025-08-21 17:06:43 +00:00
harukin-expo-dev-env
fc44c55e3a Merge branch 'feature/button-position-move' into develop 2025-08-21 16:27:39 +00:00
harukin-expo-dev-env
6fbe47f527 長押しする位置を変更 2025-08-21 16:26:44 +00:00
harukin-expo-dev-env
eabb2499fa Merge commit '14c5800aa2e65aa0ee0c64b8ccfa8f21f8124331' into patch/6.x 2025-08-19 19:19:18 +00:00
harukin-expo-dev-env
14c5800aa2 6.1.5 2025-08-19 19:19:09 +00:00
harukin-expo-dev-env
e52b019803 Merge commit 'f16fe6c9948044debaf640aa25426fdaa2f27199' into develop 2025-08-19 19:17:17 +00:00
harukin-expo-dev-env
f16fe6c994 列番を並び替え、列車リンク表示機能等を実装 2025-08-19 15:32:39 +00:00
harukin-expo-dev-env
d15d7c74fb allTrainDiagramViewを列車名検索を追加 2025-08-19 14:32:30 +00:00
harukin-expo-dev-env
ba5da62736 TrainNumberOverride機能を追加 2025-08-19 09:57:38 +00:00
harukin-expo-dev-env
6567bab066 isWanmanを基本的に無効化(種別判定を有効化)、予土線の直通ラインカラーを実装、特定期間有効アイコンをコミュニティアイコンみたく実装 2025-08-19 09:20:55 +00:00
harukin-expo-dev-env
5defa845fe Merge commit '8edf26c9be55fea38623455c69bf9bafaee578f2' into develop 2025-08-15 13:41:03 +00:00
harukin-expo-dev-env
8edf26c9be 位置情報の投稿機能がrelativeになっているせいでおかしな位置情報が提供されていたバグを修正 2025-08-15 13:40:26 +00:00
harukin-expo-dev-env
7bbb5b972f Merge commit 'ac9d4afdd87f9cbaae1d2e38065aa4832032bc7d' into patch/6.x 2025-08-13 12:50:51 +00:00
harukin-expo-dev-env
ac9d4afdd8 Merge commit '911d6942f6a6c33f8e29247ed362cfa0e78acad2' into develop 2025-08-13 12:50:44 +00:00
harukin-expo-dev-env
911d6942f6 6.1.4 2025-08-13 12:50:37 +00:00
harukin-expo-dev-env
dc552aada4 alertに車両情報を追加 2025-08-13 12:40:17 +00:00
harukin-expo-dev-env
eaadf66eda Merge commit 'fdc8b95406c3c02f1d8a8b15e85a5b8a313a5151' into develop 2025-08-13 12:19:13 +00:00
harukin-expo-dev-env
fdc8b95406 テキストのサイズ修正 2025-08-13 12:19:04 +00:00
harukin-expo-dev-env
fe5baba037 項目の最適化 2025-08-13 11:33:07 +00:00
harukin-expo-dev-env
8102680ba7 段階調整 2025-08-12 18:27:06 +00:00
harukin-expo-dev-env
6518b53de9 positionBoxの移動 2025-08-12 17:14:47 +00:00
harukin-expo-dev-env
367a70170f 小整理 2025-08-12 16:51:42 +00:00
harukin-expo-dev-env
d412941635 暫定的に投稿機能新型を実装 2025-08-12 16:47:35 +00:00
harukin-expo-dev-env
ff4eb2c95f Merge commit '5d97ab2f875236845c8a9872f45fea30ac32f9ae' into patch/6.x 2025-08-08 10:53:54 +00:00
harukin-expo-dev-env
5d97ab2f87 6.1.3 release 2025-08-08 10:53:46 +00:00
harukin-expo-dev-env
a5b3db5676 Merge commit 'c822799637d8f9b195ab21579794a13c2b13ad91' into develop 2025-08-08 10:49:15 +00:00
harukin-expo-dev-env
c822799637 ページアドレスの変更 2025-08-08 10:49:05 +00:00
harukin-expo-dev-env
fa664a15bd 画像差し替え 2025-08-08 10:41:00 +00:00
harukin-expo-dev-env
00e43772a0 ヘッダーに追加 2025-08-08 10:31:33 +00:00
harukin-expo-dev-env
980b251d43 getStringConfigを移動 2025-08-08 09:25:40 +00:00
harukin-expo-dev-env
7216392c9b AllTrainDiagramViewの強化 2025-08-08 08:49:25 +00:00
harukin-expo-dev-env
913a198a93 ダイヤ改正情報を削除 2025-08-08 07:26:04 +00:00
harukin-expo-dev-env
a119b426db コミュニティノートみたいなアイコンを追加 2025-08-08 07:16:05 +00:00
harukin-expo-dev-env
c258dfad3d 不要になる要素を削除 2025-08-08 04:16:34 +00:00
harukin-expo-dev-env
3143f73396 areainfoの処理ベースを変更 2025-08-07 17:11:00 +00:00
harukin-expo-dev-env
9280fc77f6 injectのアップデート処理の変更 2025-08-07 17:10:38 +00:00
harukin-expo-dev-env
a2a6c7fdb9 useeffect関係の機能最適化 2025-08-03 08:22:51 +00:00
harukin-expo-dev-env
c0804d2ac7 列車データ取得機能を30秒毎に動くように変更 2025-08-02 15:33:35 +00:00
harukin-expo-dev-env
6b4606f2b5 各種独自データを毎分更新して自動取得するように変更 2025-08-02 15:20:13 +00:00
harukin-expo-dev-env
4c68d7d103 路線カラー変更 2025-08-02 14:42:50 +00:00
harukin-expo-dev-env
268c11111e レイアウト修正 2025-08-02 14:36:54 +00:00
harukin-expo-dev-env
3dbaa6bfbf Merge commit 'dec33e9c64086eb2aa4b56bc109b49ed3840edd0' into patch/6.x 2025-07-27 04:11:56 +00:00
harukin-expo-dev-env
dec33e9c64 751Dも追加 2025-07-27 04:11:49 +00:00
harukin-expo-dev-env
9b266c15f8 Merge commit '28a3df44ccdd5a460c7f933c5c21ffb3fd23dd80' into patch/6.x 2025-07-27 03:54:17 +00:00
harukin-expo-dev-env
28a3df44cc 6.1.2 release 2025-07-27 03:54:07 +00:00
harukin-expo-dev-env
d19efd0e68 変更 2025-07-27 03:52:43 +00:00
harukin-expo-dev-env
d4443c862e Merge commit 'c3646a97d4f2d6cb70de5b4c629bf99131cffe88' into develop 2025-07-27 03:52:34 +00:00
harukin-expo-dev-env
c3646a97d4 直通系統のデータ更新 2025-07-27 03:52:24 +00:00
harukin-expo-dev-env
99349c3200 修正 2025-07-27 03:32:16 +00:00
harukin-expo-dev-env
e8e9d709ee 貨物や回送などの行先タグを追加 2025-07-27 03:24:18 +00:00
harukin-expo-dev-env
e6204bf504 Merge commit 'dc7cc555c990fd4a2cd5cf47089339c887eecc75' into develop 2025-07-18 16:46:40 +00:00
harukin-expo-dev-env
dc7cc555c9 Merge commit '33435c004b8cbb78d29b199b7021e4551e819944' into patch/6.x 2025-07-18 15:42:05 +00:00
harukin-expo-dev-env
33435c004b 6.1.1 release 2025-07-18 15:41:48 +00:00
harukin-expo-dev-env
d18e0f71e3 Merge commit 'acd5d0bb882139379fe5e409f3b7f291a7a14dcf' into develop 2025-07-18 15:34:11 +00:00
harukin-expo-dev-env
acd5d0bb88 検索削除機能を追加 2025-07-18 15:34:00 +00:00
harukin-expo-dev-env
0c10bcc339 新型CSSの形態調整 2025-07-18 15:18:33 +00:00
harukin-expo-dev-env
326cd60733 css調整 2025-07-17 10:27:43 +00:00
harukin-expo-dev-env
f75582ee53 menuのレイアウト更新 2025-07-16 23:46:26 +00:00
harukin-expo-dev-env
8d10fbf998 整理 2025-07-15 15:15:04 +00:00
harukin-expo-dev-env
ca4b9e7c2d Merge commit '8a1b8c94f31dc1d359ecc1f380ca0c2393649fd8' into develop 2025-07-15 04:52:04 +00:00
harukin-expo-dev-env
8a1b8c94f3 GithubCopilotリファクタリング2 2025-07-15 04:51:50 +00:00
harukin-expo-dev-env
3ac0edd3ad GithubCopilotによるリファクタリング 2025-07-15 04:23:14 +00:00
harukin-expo-dev-env
fdd0c78adc 検索内容の重複管理を実装 2025-07-15 03:25:20 +00:00
harukin-expo-dev-env
fbd76a0cf6 ファクタリング 2025-07-15 02:58:57 +00:00
harukin-expo-dev-env
e6adf775bb 検索モードの追加 2025-07-15 02:56:29 +00:00
harukin-expo-dev-env
3dc5f52333 iOSでキーボード関係でクラッシュするバグを修正 2025-07-13 15:39:43 +00:00
harukin-expo-dev-env
282ba84832 試験的に遅延時分を端っこに設置 2025-07-09 16:37:40 +00:00
harukin-expo-dev-env
8a7285bb20 試験時のbuild設定更新を適用 2025-07-08 16:44:05 +00:00
harukin-expo-dev-env
efc1631a78 Merge commit 'b512efd3ec1f7d38a2d1a10cb159ad7f34f95818' into patch/6.x 2025-07-08 16:43:42 +00:00
harukin-expo-dev-env
b512efd3ec ver.6.1 release 2025-07-08 16:43:31 +00:00
harukin-expo-dev-env
54fba616b5 Merge commit '59d7d425e5f52f547ac569aa7874fbd5adbefca1' into develop 2025-07-08 16:27:33 +00:00
harukin-expo-dev-env
59d7d425e5 不要になったアイコンを削除 2025-07-08 14:33:19 +00:00
harukin-expo-dev-env
934f9ce2c2 走行位置のUIに種別や内子経由のラインを追加、寝台特急をピンクに変更 2025-07-08 13:28:00 +00:00
harukin-expo-dev-env
d586bc562f カルーセルの挙動を修正、バッジのサイズとスクロールの調整 2025-07-08 12:23:29 +00:00
harukin-expo-dev-env
72e7894725 様子のおかしい列車が正常に表示されていなかったバグを修正 2025-07-08 06:04:18 +00:00
harukin-expo-dev-env
3da4986a7c 地図表示の挙動変更、位置情報への移動ボタンを実装 2025-07-07 13:34:13 +00:00
harukin-expo-dev-env
249f09bbc7 瀬戸大橋線で表示できないバグを修正 2025-07-07 11:58:10 +00:00
harukin-expo-dev-env
9478f2df8d メニューの路線別リストアップ機能を追加 2025-07-07 11:48:46 +00:00
harukin-expo-dev-env
6b39a3f723 keyの入力不足を修正 2025-07-07 10:28:30 +00:00
harukin-expo-dev-env
caa4694c94 検索ボタン暫定実装 2025-07-06 11:14:24 +00:00
harukin-expo-dev-env
fdea8be0b4 徳島線の徳島駅、阿波池田駅の地点情報が無かった問題をデータソース側の改変で対処 2025-07-06 08:01:57 +00:00
harukin-expo-dev-env
36ac66df3e メニューにお気に入りが無い場合の要素を追加 2025-07-05 16:20:53 +00:00
harukin-expo-dev-env
156912302d Merge commit '67d2bf6c98f192e4a308383dd08032dbbb972cbf' into develop 2025-07-05 10:50:03 +00:00
harukin-expo-dev-env
67d2bf6c98 LEDの枠に位置情報ジャンプボタンを追加 2025-07-05 10:49:30 +00:00
harukin-expo-dev-env
19db27a378 Merge commit '012544beebf66d416d7a93f252e599ce201bcb47' into develop 2025-07-05 09:43:54 +00:00
harukin-expo-dev-env
012544beeb 駅の地図情報を全開放 2025-07-05 09:43:44 +00:00
harukin-expo-dev-env
218f9d5093 全駅地図表示に対応 2025-07-05 08:48:16 +00:00
harukin-expo-dev-env
65123424a3 駅への移動スクリプトをhooksに移動 2025-07-05 07:57:55 +00:00
harukin-expo-dev-env
28b23efc5e お気に入りリストからのジャンプを全ての駅で利用可能に 2025-07-05 07:47:44 +00:00
harukin-expo-dev-env
3488c5e8d5 アイコンが設定されていてもアドレスが設定されてなかったらクリックできないように変更 2025-07-05 05:33:55 +00:00
harukin-expo-dev-env
bb41118e39 数字の表示やリストの表示位置を修正 2025-07-05 05:19:06 +00:00
harukin-expo-dev-env
d8453608c9 列車情報の頭に記載する列車名をサーバーから動的に取得変更可能に 2025-07-03 15:09:35 +00:00
harukin-expo-dev-env
e6430c27a6 Merge commit '570a55f4307025eaad90d9bf617e82fa87cf24a1' into develop 2025-07-03 12:08:53 +00:00
harukin-expo-dev-env
570a55f430 pushtokenを送信してtrueじゃなかったらwebviewが開けれないように修正 2025-07-03 12:08:43 +00:00
harukin-expo-dev-env
c98407527b 行き先の裏に駅の路線カラーを設定 2025-06-15 16:35:39 +00:00
harukin-expo-dev-env
b143e4251d 行き先情報を独自サーバーベースにするように変更 2025-06-15 09:43:05 +00:00
harukin-expo-dev-env
c526055dda 貨物の表示を追加 2025-06-15 09:09:05 +00:00
harukin-expo-dev-env
61aca4c75e injectのデザイン修正 2025-06-15 05:20:47 +00:00
harukin-expo-dev-env
c92f02fa0e 投稿機能へのウィンドウを作成 2025-06-15 05:20:11 +00:00
harukin-expo-dev-env
8e7ccba5cc デザインを修正 2025-06-12 08:54:39 +00:00
harukin-expo-dev-env
ed6f00f3fd Merge commit '7500aaa66f2b4309e287fa67ca245b49f6367c9c' into feature/train-data-edit-system 2025-06-11 14:18:21 +00:00
harukin-expo-dev-env
7500aaa66f Merge commit 'b5b9558136f02741e7ba472e09b244bf055a294b' into develop 2025-06-11 14:18:15 +00:00
harukin-expo-dev-env
b5b9558136 設定機能を実装 2025-06-11 14:18:00 +00:00
harukin-expo-dev-env
7b4badb9b0 injectJavascriptに変化条件を追加 2025-06-11 13:47:37 +00:00
harukin-expo-dev-env
dfc2fa5c89 アイコンの取得がキャッシュ優先されちゃう状態になっていたので修正 2025-06-11 13:21:40 +00:00
harukin-expo-dev-env
f2d49cbbf2 Merge commit 'c8356fad2f691e23952de122b209fda3c39c0c9d' into develop 2025-06-11 12:53:34 +00:00
harukin-expo-dev-env
c8356fad2f データが保存されていなかった問題を修正 2025-06-11 12:52:37 +00:00
harukin-expo-dev-env
5c143779e2 Merge commit 'a7ccb0b41fa99f9173d582f6b89d33449e02ac3b' into develop 2025-06-11 12:48:07 +00:00
harukin-expo-dev-env
a7ccb0b41f threwの動作条件をおまけで変更 2025-06-11 12:47:57 +00:00
harukin-expo-dev-env
c0f7a9b931 テキストのレイアウト修正 2025-06-11 12:44:52 +00:00
harukin-expo-dev-env
a305aa7202 クリックアニメーションを追加、進行方向に合わせた配置の変更 2025-06-11 12:06:55 +00:00
harukin-expo-dev-env
45b41dcef0 新しいデザインを暫定的に作成 2025-06-11 09:58:06 +00:00
harukin-expo-dev-env
0ce2b70669 Merge commit '6ad46c0e632c6fd1448cf743b8eadab2e5d8b216' into develop 2025-06-10 16:19:52 +00:00
harukin-expo-dev-env
6ad46c0e63 お気に入り一覧のドラッグ並び替え機能を実装 2025-06-10 16:19:43 +00:00
harukin-expo-dev-env
c43778c3c5 不要な要素を削除 2025-06-10 14:36:50 +00:00
harukin-expo-dev-env
7395c7e8f4 Merge commit 'af30d1cbb0ffac53805f28107b3564535219e541' into develop 2025-06-10 14:27:26 +00:00
harukin-expo-dev-env
af30d1cbb0 cssを修正 2025-06-10 14:26:15 +00:00
harukin-expo-dev-env
aefbf68401 LEDを以前の仕様に戻す 2025-06-10 14:17:23 +00:00
harukin-expo-dev-env
c52cb1c91f 検索範囲を縮小 2025-06-10 14:08:41 +00:00
harukin-expo-dev-env
52ca9d03a8 路線を跨ぐ位置に居ると路線順に候補が並んでしまう問題を修正 2025-06-10 13:59:38 +00:00
harukin-expo-dev-env
0d595c7f67 小修整 2025-06-10 13:18:52 +00:00
harukin-expo-dev-env
d6b701bdb1 不要な要素削除 2025-06-03 13:37:04 +00:00
harukin-expo-dev-env
59082c7873 小さな変更 2025-05-24 06:29:17 +00:00
harukin-expo-dev-env
2f65cd6a6f 定義忘れバグを修正 2025-05-19 06:21:08 +00:00
harukin-expo-dev-env
73ed5480c1 wpを削除して配置を変更 2025-05-17 10:16:35 +00:00
harukin-expo-dev-env
6a58263e94 最後の駅リスト選択を維持するように変更 2025-05-06 16:27:42 +00:00
harukin-expo-dev-env
7ca4cf95e6 テキストの点滅を移動したときにキャンセルするように修正 2025-05-06 13:59:13 +00:00
harukin-expo-dev-env
c41c61bba7 宇多津に近づいたらクラッシュする問題、現在地のリストアップ機能がちゃんと整理されていなかった問題を修正 2025-05-06 11:53:45 +00:00
harukin-expo-dev-env
a0f1c64041 Merge commit '44e542c0f1870fed58b8223801a20ee22992fb01' into experiment/new-menu-style-with-maps 2025-05-04 12:58:25 +00:00
harukin-expo-dev-env
44e542c0f1 Merge commit '8212148fb298dc678b811aadf0344731b43e8cf7' into develop 2025-05-04 12:58:18 +00:00
harukin-expo-dev-env
8212148fb2 Merge commit '7500582165eea1a436e09b2015f820934ab93525' into patch/6.x 2025-05-04 12:56:30 +00:00
harukin-expo-dev-env
7500582165 行き先情報もサーバー経由で取得できるように変更 2025-05-04 12:56:18 +00:00
harukin-expo-dev-env
d5cfe06086 読み込み時に自動再読み込みをするように変更 2025-05-04 10:46:45 +00:00
harukin-expo-dev-env
1795ab274b trainDataListを追加し、アイコン設定のロジックを改善 2025-05-04 10:19:21 +00:00
harukin-expo-dev-env
0206bb4cf8 画像アイコン取得を動的に変更 2025-05-04 09:31:02 +00:00
harukin-expo-dev-env
e9f845f448 意味を成してなかった要素を削除 2025-05-01 14:29:20 +00:00
harukin-expo-dev-env
611f233361 Merge commit '31bf3a72286b24b829eff88f464a330721be1cc4' into experiment/new-menu-style-with-maps 2025-04-20 17:24:04 +00:00
harukin-expo-dev-env
31bf3a7228 Merge commit 'bd2248e1a943e574ccc44892122cd9da4df14b68' into develop 2025-04-20 17:23:58 +00:00
harukin-expo-dev-env
bd2248e1a9 マクロのパスを修正 2025-04-20 17:22:48 +00:00
harukin-expo-dev-env
8c17a5b3da 列車の表示条件の厳密化、および出発促進表示を追加 2025-04-20 05:31:30 +00:00
harukin-expo-dev-env
fbcded3d23 列車が出発してなかったらLEDから消えないように修正、出発してたら率先して消えるように修正 2025-04-18 15:39:58 +00:00
harukin-expo-dev-env
b3cc5b6ede 地図の下部内容をabsoluteにして機能切り替えをスクロールで発動しないように変更 2025-04-18 09:51:36 +00:00
harukin-expo-dev-env
85de99e32d LED発車標が正常に動いていなかった問題を修正 2025-04-15 07:37:14 +00:00
harukin-expo-dev-env
fa758c144f スクロールの挙動がおかしかったバグを修正 2025-04-14 18:52:21 +00:00
harukin-expo-dev-env
99ba90f324 マップの移動機能を追加 2025-04-13 19:46:15 +00:00
harukin-expo-dev-env
427e06967c LEDにkeyを付与してデータの整理 2025-04-13 19:16:58 +00:00
harukin-expo-dev-env
f26da93193 コードの整理とuseCurrentTrainの取得ルートの変更 2025-04-13 18:06:22 +00:00
harukin-expo-dev-env
015e4e54ed 現在地基準の当該駅を複数表示できるように修正 2025-04-13 17:24:35 +00:00
harukin-expo-dev-env
7232c40af1 menuの変数名を変更 2025-04-13 16:56:47 +00:00
harukin-expo-dev-env
35bb460b54 CarouselBoxコンポーネントのrenderItem関数を分離し、MenuコンポーネントでのcurrentStationの管理をnearPositionStationに変更 2025-04-13 16:54:02 +00:00
harukin-expo-dev-env
748350178d 小さなミスを修正 2025-04-13 16:31:11 +00:00
harukin-expo-dev-env
2c505c4b17 近くの駅の情報がとりあえず出るようになった 2025-04-13 16:17:15 +00:00
harukin-expo-dev-env
6d51db98fa 微調整 2025-04-13 15:48:25 +00:00
harukin-expo-dev-env
ac06ca6c75 SignをID管理ベースに置き換え 2025-04-13 15:43:10 +00:00
harukin-expo-dev-env
3b98882d80 お気に入り/現在地切り替え機能を仮作成 2025-04-13 14:42:59 +00:00
harukin-expo-dev-env
f922edb973 位置情報権限の取得場所を変更 2025-04-13 13:21:09 +00:00
harukin-expo-dev-env
97a6bbc619 Carouselと切り替えボタンを変更 2025-04-13 12:41:33 +00:00
harukin-expo-dev-env
934938287d メニューの地図機能の仮作成 2025-04-13 10:35:08 +00:00
harukin-expo-dev-env
44f8be994e 単発の変更 2025-04-13 10:32:30 +00:00
harukin-expo-dev-env
cf025d3add 現在地ベースのボタンとか追加 2025-04-11 15:35:25 +00:00
harukin-expo-dev-env
190be0fa67 地図が移動するように変更 2025-04-11 14:12:10 +00:00
harukin-expo-dev-env
5ef720f475 地図の機能が一通り動くようになった 2025-04-11 13:52:48 +00:00
harukin-expo-dev-env
fdacc00f93 menuに新しい概念を作成 2025-04-11 11:18:51 +00:00
harukin-expo-dev-env
49ed69d541 Merge commit 'bb0ae86f67c2dccf8df6e96f4fc825569fc45200' into develop 2025-04-11 10:43:41 +00:00
harukin-expo-dev-env
bb0ae86f67 TwitterをSocialMenuに移動 2025-04-11 10:42:50 +00:00
harukin-expo-dev-env
b108029868 SpecialTrainInfoをActionSheetに 2025-04-11 10:22:40 +00:00
harukin-expo-dev-env
27dde29010 Merge commit '38dc92ab378a2fa2f1528a49f9145635b373b884' into feature/special-train-info 2025-04-10 18:41:42 +00:00
harukin-expo-dev-env
38dc92ab37 Merge commit 'b64138178c4ca99bfcbb4f115403a18674ce8136' into develop 2025-04-10 18:41:31 +00:00
harukin-expo-dev-env
b64138178c Merge commit '577e793af9398c72bc06fb6e57e4a28c239b055f' into patch/6.x 2025-04-10 18:41:25 +00:00
harukin-expo-dev-env
577e793af9 getStationListの整理 2025-04-10 18:40:04 +00:00
harukin-expo-dev-env
423625c08a 小規模なコード整理 2025-04-10 18:29:56 +00:00
harukin-expo-dev-env
99831e8d39 ダイヤ情報の中央集権化に伴うtrainListの省力化 2025-04-10 18:14:33 +00:00
harukin-expo-dev-env
95bad60631 サーバーエラー時のキャッシュ読み取りへの対応 2025-04-10 17:59:38 +00:00
harukin-expo-dev-env
db2547028d 列車データの提供元を完全にサーバーサイドに移行 2025-04-10 17:51:16 +00:00
harukin-expo-dev-env
e6c0fe94c0 Merge commit '715c0ddf9461bc55185cb421a789e10df2079b7b' into feature/special-train-info 2025-04-10 16:36:25 +00:00
harukin-expo-dev-env
715c0ddf94 Merge commit '67f40b55c19ff2e94b1168865486bcde7d457cab' into develop 2025-04-10 16:36:20 +00:00
harukin-expo-dev-env
67f40b55c1 リファラのせいでクラッシュする致命的なバグを発見したので修正 2025-04-10 16:36:14 +00:00
harukin-expo-dev-env
d059798f85 Merge commit '62e9a43f2bd5d5fae16810281e60bc0e6018b6ba' into feature/special-train-info 2025-04-10 16:31:15 +00:00
harukin-expo-dev-env
62e9a43f2b Merge commit '7015d90ea957413ce4a6bad440968ebf48bc7abf' into develop 2025-04-10 16:31:10 +00:00
harukin-expo-dev-env
7015d90ea9 わらぐろ号・れんげ号の情報を追加、半定期臨時列車のダイヤをミスしていたので修正 2025-04-10 16:31:01 +00:00
harukin-expo-dev-env
9bf047bff0 Merge commit 'c5e76a9a7a501ba8c3f0c4806ab84cf13deeeaef' into feature/special-train-info 2025-04-10 15:54:26 +00:00
harukin-expo-dev-env
c5e76a9a7a Merge commit 'fdefbc82bd39c8cba29911273db2f96fa39c0e3f' into develop 2025-04-10 15:50:08 +00:00
harukin-expo-dev-env
fdefbc82bd 臨時列車データの更新 2025-04-10 15:49:54 +00:00
harukin-expo-dev-env
f4a9bf23ef アイコンの変更 2025-04-10 15:42:17 +00:00
harukin-expo-dev-env
df2d93c29d アンパンマン列車の対応強化 2025-04-10 15:39:16 +00:00
harukin-expo-dev-env
9ba1f5d50b SpecialTrainInfoBoxを作成 2025-04-10 10:24:23 +00:00
harukin-expo-dev-env
6fbaf2b8ff Merge commit '3b129eb2b52177d1bf78feee7013585066ee1c1f' into develop 2025-04-06 14:30:53 +00:00
harukin-expo-dev-env
3b129eb2b5 半定期臨時列車データとあんぱんあしずり対応 2025-04-06 14:21:47 +00:00
harukin-expo-dev-env
c90c2fa3db Merge commit '3ffd8daf03f5d0e82011a84f323f93230be7a652' into patch/6.x 2025-04-04 14:41:25 +00:00
harukin-expo-dev-env
3ffd8daf03 Merge commit 'c9af861e714d94168dc99850b5e95c48127303ca' into develop 2025-04-04 14:41:13 +00:00
harukin-expo-dev-env
c9af861e71 コード修正 2025-04-04 14:41:03 +00:00
harukin-expo-dev-env
1a2d678ef3 StationDeteilViewの項目分離 2025-04-03 09:15:42 +00:00
harukin-expo-dev-env
cd08fdc08b Merge commit 'af8f3333cd68ea507675ad02ec59ccf2f7959e00' into develop 2025-03-30 02:52:24 +00:00
harukin-expo-dev-env
af8f3333cd RIZIN.50 香川大会臨時情報を追加 2025-03-30 02:52:13 +00:00
harukin-expo-dev-env
0ae9d59758 本家モードで列車位置に移動した時に強制的にメニューが展開されていたバグを修正 2025-03-30 02:47:02 +00:00
harukin-expo-dev-env
3eb92564ef 本家メニューで予期しないタイミングでメニューが表示されていたバグを修正 2025-03-29 15:00:42 +00:00
harukin-expo-dev-env
2b9553a45b 停止中表示を改良 2025-03-29 14:55:59 +00:00
harukin-expo-dev-env
4744d5f4e0 走行を再開したら闇落ちを解除するように修正 2025-03-29 05:20:23 +00:00
harukin-expo-dev-env
52e4f577ea Merge commit '0a364021ce2fed98257e80cc780ac4020cecb9c1' into develop 2025-03-25 07:51:40 +00:00
harukin-expo-dev-env
0a364021ce 6.0.2 release 2025-03-25 07:26:58 +00:00
harukin-expo-dev-env
74087067ea Merge commit 'cab738fa34d9d34de06503567ecca275f47c68f9' into patch/6.x 2025-03-25 07:22:54 +00:00
harukin-expo-dev-env
cab738fa34 Merge commit '828a974070c74113b93bbf136e70e1128630cd54' into develop 2025-03-25 07:22:33 +00:00
harukin-expo-dev-env
828a974070 闇落ち機能を追加 2025-03-25 07:16:55 +00:00
harukin-expo-dev-env
eea6407196 テキストの微妙な修正 2025-03-25 06:12:10 +00:00
harukin-expo-dev-env
3ce1c6db67 TraInfoEXのボタンを移動 2025-03-25 06:10:37 +00:00
harukin-expo-dev-env
002c60baa1 Merge commit 'de2b94292dc97df6e290e91976d01cea24c98ced' into develop 2025-03-22 12:32:10 +00:00
harukin-expo-dev-env
de2b94292d アドレスを修正 2025-03-22 12:32:02 +00:00
harukin-expo-dev-env
ff41948f14 ごな線直通系の普通表記が消滅していたバグを修正 2025-03-22 12:27:21 +00:00
harukin-expo-dev-env
403466d4fa あしずりのアイコンが不足していたバグを修正 2025-03-22 12:24:56 +00:00
harukin-expo-dev-env
8c75e06ac1 Merge commit 'f0c5402050fef1c949b1b82a89a9df220cb24b9f' into patch/6.x 2025-03-22 11:34:19 +00:00
harukin-expo-dev-env
f0c5402050 6.0.1 2025-03-22 11:34:12 +00:00
harukin-expo-dev-env
1f0f1a0ed3 Merge commit '20ab13bcaa88ddfe972e731cbb71958725ab1c30' into develop 2025-03-22 11:32:38 +00:00
harukin-expo-dev-env
20ab13bcaa 徳島界隈の普通列車運用アイコンを登録 2025-03-22 11:32:31 +00:00
harukin-expo-dev-env
e16783ecfb Merge commit '9b1fee75c7cbaeb7c2aee665389da0cd905f1187' into develop 2025-03-22 11:22:00 +00:00
harukin-expo-dev-env
9b1fee75c7 trainListをスクロールして閉じようとしたらトップにスクロールを移動させるように変更 2025-03-22 11:18:20 +00:00
harukin-expo-dev-env
a2b37f4f35 iOSでタブがおかしくなっていたバグを修正 2025-03-22 11:02:19 +00:00
harukin-expo-dev-env
1ff2f234e8 Androidでキーボード表示時にタブが消えなかった問題を修正 2025-03-22 10:56:39 +00:00
harukin-expo-dev-env
842b724103 LED関連でデータの解析依存関係を修正 2025-03-22 10:29:44 +00:00
harukin-expo-dev-env
7f148c17e4 グリーン、寝台のアイコンを追加 2025-03-22 10:10:29 +00:00
harukin-expo-dev-env
e604df3e6a フォント追加 2025-03-22 09:28:14 +00:00
harukin-expo-dev-env
8bc048523e 変更に伴う臨時列車データ更新 2025-03-22 09:27:59 +00:00
harukin-expo-dev-env
ea39f00515 列車表示のロジックをrelativeなものからcustomTrainData経由のものに統一 2025-03-22 09:27:38 +00:00
harukin-expo-dev-env
3e12371b16 ワンマンサンポートを追加 2025-03-22 07:37:12 +00:00
harukin-expo-dev-env
f6a571bcfe サンポートのデータをcustom-train-dataに追加 2025-03-22 07:32:48 +00:00
harukin-expo-dev-env
3d75ab149f コードの配置変更 2025-03-21 17:02:10 +00:00
harukin-expo-dev-env
9fe53f55e9 importのミスを修正 2025-03-21 13:22:11 +00:00
harukin-expo-dev-env
db53878385 Merge commit '45500e7a4ae614debd93404339958465db88f71d' into develop 2025-03-19 15:47:47 +00:00
harukin-expo-dev-env
45500e7a4a Merge commit '740815704eb2a87ff8fd2a45c5f96d4dd793ddfb' into patch/6.x 2025-03-19 15:37:43 +00:00
harukin-expo-dev-env
740815704e WESTLIVE臨時を追加 2025-03-19 15:37:07 +00:00
harukin-expo-dev-env
795e535e23 Merge commit '6a888e6e1243f9067be193add69577f7ee624fb1' into patch/6.x 2025-03-19 12:19:42 +00:00
harukin-expo-dev-env
6a888e6e12 一部データの修正 2025-03-19 11:31:41 +00:00
harukin-expo-dev-env
b5b650695a 一部の普通列車が表示されてる問題を修正 2025-03-19 10:46:43 +00:00
harukin-expo-dev-env
5725e2645d Merge commit '2c5023568a0442679b476bd84651eca3fcc90ee1' into develop 2025-03-16 05:55:24 +00:00
harukin-expo-dev-env
2c5023568a Merge commit '88b1a892e44aee130745cc10f621e3e02f17f489' into patch/6.x 2025-03-16 05:54:57 +00:00
harukin-expo-dev-env
88b1a892e4 土佐くろ直通記入 2025-03-16 05:54:43 +00:00
harukin-expo-dev-env
7f364adde9 発動していなかったバグを修正 2025-03-16 05:35:54 +00:00
harukin-expo-dev-env
a9e9a5cb3b 牟岐線のダイヤ情報書き込み完了 2025-03-16 05:06:35 +00:00
harukin-expo-dev-env
15be3eaab2 位置情報への牟岐線対応修正 2025-03-16 02:31:25 +00:00
harukin-expo-dev-env
fa07287da0 パス表示修正 2025-03-16 00:55:09 +00:00
harukin-expo-dev-env
281a816673 牟岐線接続系列車修正 2025-03-16 00:54:04 +00:00
harukin-expo-dev-env
ff4a24e07a うずしおのデータ修正 2025-03-15 06:48:53 +00:00
harukin-expo-dev-env
2ed67389c0 Merge commit '8a48bc48e6eb82921fcda3a84e07db2eca51e614' into develop 2025-03-15 04:23:06 +00:00
harukin-expo-dev-env
8a48bc48e6 Merge commit '0a520309e2f181b0a1b1780577dfdad15139cded' into patch/6.x 2025-03-15 04:22:57 +00:00
harukin-expo-dev-env
0a520309e2 特急、快速列車のアイコンに対応 2025-03-15 04:22:35 +00:00
harukin-expo-dev-env
047848ed1a Merge commit '23fb2d715a461cb0ebfca1e1944757febd315fec' into develop 2025-03-14 18:22:02 +00:00
harukin-expo-dev-env
23fb2d715a Merge commit '1b87c2fc911145a8a3ef7610dda09301de07bf74' into patch/6.x 2025-03-14 18:21:54 +00:00
harukin-expo-dev-env
1b87c2fc91 新ダイヤ情報への書き換え 2025-03-14 18:21:34 +00:00
harukin-expo-dev-env
3cd835b1ba ダイヤ改正確認 2025-03-14 18:10:00 +00:00
harukin-expo-dev-env
c973111f13 ダイヤデータtmpファイル作成機能を追加 2025-03-14 16:33:12 +00:00
harukin-expo-dev-env
99efc0d651 ダイヤ改正情報ページを作成 2025-03-14 16:19:31 +00:00
harukin-expo-dev-env
bcc077ac0f 2025シーズン向けに準備 2025-03-14 15:56:50 +00:00
harukin-expo-dev-env
cd0caf3b84 一時的にアイコン表示機能を無効化 2025-03-14 15:34:51 +00:00
harukin-expo-dev-env
0ce16c2dc2 テキストの配置を新版に統合 2025-03-14 15:27:33 +00:00
harukin-expo-dev-env
c7e08bf013 微修正 2025-03-14 15:23:12 +00:00
harukin-expo-dev-env
d0c174b924 Merge commit '002070bafb219924e949fde1910ab19d5d710b49' into patch/6.x 2025-03-11 06:34:31 +00:00
harukin-expo-dev-env
002070bafb コミットコマンド変更 2025-03-11 06:34:25 +00:00
133 changed files with 11394 additions and 4952 deletions

View File

@@ -1,5 +1,5 @@
import React, { useEffect } from "react";
import { Platform, UIManager } from "react-native";
import { Platform, UIManager, Text } from "react-native";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { AppContainer } from "./Apps";
import { UpdateAsync } from "./UpdateAsync";
@@ -18,6 +18,7 @@ import { TrainMenuProvider } from "./stateBox/useTrainMenu";
import { buildProvidersTree } from "./lib/providerTreeProvider";
import { StationListProvider } from "./stateBox/useStationList";
import { NotificationProvider } from "./stateBox/useNotifications";
import { UserPositionProvider } from "./stateBox/useUserPosition";
LogBox.ignoreLogs([
"ViewPropTypes will be removed",
@@ -31,16 +32,22 @@ if (Platform.OS === "android") {
}
export default function App() {
useEffect(() => UpdateAsync(), []);
useEffect(() => {
UpdateAsync();
}, []);
if (Text.defaultProps == null) {
Text.defaultProps = {};
Text.defaultProps.allowFontScaling = false;
}
const ProviderTree = buildProvidersTree([
AllTrainDiagramProvider,
NotificationProvider,
UserPositionProvider,
StationListProvider,
FavoriteStationProvider,
TrainDelayDataProvider,
CurrentTrainProvider,
AreaInfoProvider,
AllTrainDiagramProvider,
BusAndTrainDataProvider,
TrainMenuProvider,
SheetProvider,

View File

@@ -27,15 +27,17 @@ export function AppContainer() {
const [fontLoaded, error] = useFonts({
"JR-Nishi": require("./assets/fonts/jr-nishi.otf"),
Zou: require("./assets/fonts/DelaGothicOne-Regular.ttf"),
"JNR-font": require("./assets/fonts/JNRfont_pict.ttf"),
"DiaPro": require("./assets/fonts/DiaPro-Regular.otf"),
});
return (
<NavigationContainer ref={navigationRef}>
<Tab.Navigator
tabBarOptions={{ keyboardHidesTabBar: Platform.OS === "android" }}
initialRouteName="topMenu"
screenOptions={{
lazy: false,
animation: "shift",
tabBarHideOnKeyboard: Platform.OS === "android",
}}
detachInactiveScreens={false}
lazy={false}

30
GeneralWebView.tsx Normal file
View File

@@ -0,0 +1,30 @@
import React, { CSSProperties } from "react";
import { View, ViewProps } from "react-native";
import { WebView } from "react-native-webview";
import { BigButton } from "./components/atom/BigButton";
import { useNavigation } from "@react-navigation/native";
export default ({ route }) => {
if (!route.params) {
return null;
}
const { uri, useExitButton = true } = route.params;
const { goBack } = useNavigation();
return (
<View style={styles}>
<WebView
useWebKit
source={{ uri }}
onMessage={(event) => {
const { data } = event.nativeEvent;
const {type} = JSON.parse(data);
if (type === "windowClose") return goBack();
}}
/>
{useExitButton && <BigButton onPress={goBack} string="閉じる" />}
</View>
);
};
const styles: ViewProps["style"] = {
height: "100%",
backgroundColor: "#0099CC",
};

View File

@@ -1,93 +0,0 @@
import React, { useEffect } from "react";
import { createStackNavigator } from "@react-navigation/stack";
import { SheetManager } from "react-native-actions-sheet";
import { AS } from "./storageControl";
import TrainBase from "./components/trainbaseview";
import HowTo from "./howto";
import Menu from "./menu";
import News from "./components/news";
import Setting from "./components/Settings/settings";
import { useFavoriteStation } from "./stateBox/useFavoriteStation";
import { optionData } from "./lib/stackOption";
import AllTrainDiagramView from "./components/AllTrainDiagramView";
import { useCurrentTrain } from "./stateBox/useCurrentTrain";
import { useNavigation } from "@react-navigation/native";
import { news } from "./config/newsUpdate";
const Stack = createStackNavigator();
export function MenuPage() {
const { favoriteStation, setFavoriteStation } = useFavoriteStation();
const { getCurrentTrain } = useCurrentTrain();
const navigation = useNavigation();
const { addListener } = navigation;
useEffect(() => {
AS.getItem("startPage")
.then((res) => {
if (res == "true") navigation.navigate("positions");
})
.catch((e) => {
//6.0以降false
AS.setItem("startPage", "false");
});
//ニュース表示
AS.getItem("status")
.then((d) => {
if (d != news) navigation.navigate("topMenu", { screen: "news" });
})
.catch(() => navigation.navigate("topMenu", { screen: "news" }));
AS.getItem("isSetIcon")
.then((isSetIcon) => {
if (isSetIcon == "true") SheetManager.show("TrainIconUpdate");
})
.catch((error) => console.error("Error fetching icon setting:", error));
}, []);
useEffect(() => {
const unsubscribe = addListener("tabPress", (e) => {
AS.getItem("favoriteStation")
.then((d) => {
const returnData = JSON.parse(d);
if (favoriteStation.toString() != d) {
setFavoriteStation(returnData);
}
})
.catch((d) => console.log(d));
});
return unsubscribe;
}, [navigation]);
return (
<Stack.Navigator>
<Stack.Screen
name="menu"
options={{
headerShown: false,
gestureEnabled: true,
headerTransparent: true,
}}
children={() => <Menu getCurrentTrain={getCurrentTrain} />}
/>
<Stack.Screen name="news" options={optionData} component={News} />
<Stack.Screen
name="setting"
options={{
...optionData,
gestureEnabled: false,
cardOverlayEnabled: true,
}}
component={Setting}
/>
<Stack.Screen
name="trainbase"
options={{ ...optionData }}
component={TrainBase}
/>
<Stack.Screen
name="AllTrainIDList"
options={{ ...optionData, gestureEnabled: false }}
component={AllTrainDiagramView}
/>
<Stack.Screen name="howto" options={optionData} component={HowTo} />
</Stack.Navigator>
);
}

149
MenuPage.tsx Normal file
View File

@@ -0,0 +1,149 @@
import React, { useEffect, useRef, useState } from "react";
import { createStackNavigator } from "@react-navigation/stack";
import { useWindowDimensions, Platform } from "react-native";
import Constants from "expo-constants";
import { Dimensions, StatusBar } from "react-native";
import { SheetManager } from "react-native-actions-sheet";
import { AS } from "@/storageControl";
import TrainBase from "@/components/trainbaseview";
import HowTo from "@/howto";
import { Menu } from "@/menu";
import News from "@/components/news";
import Setting from "@/components/Settings/settings";
import { useFavoriteStation } from "@/stateBox/useFavoriteStation";
import { optionData } from "@/lib/stackOption";
import AllTrainDiagramView from "@/components/AllTrainDiagramView";
import { useNavigation } from "@react-navigation/native";
import { news } from "@/config/newsUpdate";
import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs";
import GeneralWebView from "@/GeneralWebView";
import { StationDiagramView } from "@/components/StationDiagram/StationDiagramView";
const Stack = createStackNavigator();
export function MenuPage() {
const { favoriteStation, setFavoriteStation } = useFavoriteStation();
const { height, width } = useWindowDimensions();
const tabBarHeight = useBottomTabBarHeight();
const navigation = useNavigation();
const { addListener } = navigation;
useEffect(() => {
AS.getItem("startPage")
.then((res) => {
if (res == "true") navigation.navigate("positions");
})
.catch((e) => {
//6.0以降false
AS.setItem("startPage", "false");
});
//ニュース表示
AS.getItem("status")
.then((d) => {
if (d != news) navigation.navigate("topMenu", { screen: "news" });
})
.catch(() => navigation.navigate("topMenu", { screen: "news" }));
AS.getItem("isSetIcon")
.then((isSetIcon) => {
if (isSetIcon == "true") SheetManager.show("TrainIconUpdate");
})
.catch((error) => console.error("Error fetching icon setting:", error));
}, []);
const scrollRef = useRef(null);
const [mapMode, setMapMode] = useState(false);
const [mapHeight, setMapHeight] = useState(0);
useEffect(() => {
const MapHeight =
height -
tabBarHeight +
(Platform.OS == "android" ? Constants.statusBarHeight : 0) -
100 -
((((width / 100) * 80) / 20) * 9 + 10 + 30);
setMapHeight(MapHeight);
}, [height, tabBarHeight, width]);
const [MapFullHeight, setMapFullHeight] = useState(0);
useEffect(() => {
const MapFullHeight =
height -
tabBarHeight +
(Platform.OS == "android" ? Constants.statusBarHeight : 0);
setMapFullHeight(MapFullHeight);
}, [height, tabBarHeight, width]);
useEffect(() => {
const unsubscribe = addListener("tabPress", (e) => {
scrollRef.current.scrollTo({
y: mapHeight - 80,
animated: true,
});
setMapMode(false);
AS.getItem("favoriteStation")
.then((d) => {
const returnData = JSON.parse(d);
if (favoriteStation.toString() != d) {
setFavoriteStation(returnData);
}
})
.catch((error) => {
if (__DEV__) {
console.warn("お気に入り駅の読み込みに失敗しました:", error);
}
});
});
return unsubscribe;
}, [navigation, mapHeight, favoriteStation, setFavoriteStation]);
return (
<Stack.Navigator id={null}>
<Stack.Screen
name="menu"
options={{
headerShown: false,
gestureEnabled: true,
headerTransparent: true,
}}
children={() => (
<Menu
scrollRef={scrollRef}
mapHeight={mapHeight}
MapFullHeight={MapFullHeight}
mapMode={mapMode}
setMapMode={setMapMode}
/>
)}
/>
<Stack.Screen
name="stDiagram"
options={{ ...optionData, gestureEnabled: false }}
component={StationDiagramView}
/>
<Stack.Screen name="news" options={optionData} component={News} />
<Stack.Screen
name="setting"
options={{
...optionData,
gestureEnabled: false,
cardOverlayEnabled: true,
}}
component={Setting}
/>
<Stack.Screen
name="trainbase"
options={{ ...optionData }}
component={TrainBase}
/>
<Stack.Screen
name="AllTrainIDList"
options={{ ...optionData, gestureEnabled: false }}
component={AllTrainDiagramView}
/>
<Stack.Screen name="howto" options={optionData} component={HowTo} />
<Stack.Screen
name="generalWebView"
options={optionData}
component={GeneralWebView}
/>
</Stack.Navigator>
);
}

View File

@@ -6,20 +6,22 @@ import TrainBase from "./components/trainbaseview";
import HowTo from "./howto";
import News from "./components/news";
import TrainMenu from "./components/trainMenu";
import FavoriteList from "./components/FavoriteList";
import { FavoriteList } from "./components/FavoriteList";
import { optionData } from "./lib/stackOption";
import { useCurrentTrain } from "./stateBox/useCurrentTrain";
import { useTrainMenu } from "./stateBox/useTrainMenu";
import { AS } from "./storageControl";
import { news } from "./config/newsUpdate";
import { Linking, Platform } from "react-native";
import GeneralWebView from "./GeneralWebView";
import { StationDiagramView } from "@/components/StationDiagram/StationDiagramView";
const Stack = createStackNavigator();
export const Top = () => {
const { webview } = useCurrentTrain();
const { navigate, addListener, isFocused } = useNavigation();
//地図用
const { injectJavaScript, mapSwitch } = useTrainMenu();
const { mapSwitch } = useTrainMenu();
const goToFavoriteList = () =>
navigate("positions", { screen: "favoriteList" });
@@ -32,30 +34,23 @@ export const Top = () => {
const goToTrainMenu = () => {
if (Platform.OS === "web") {
Linking.openURL("https://train.jr-shikoku.co.jp/");
setTimeout(() => {
navigate("topMenu", { screen: "menu" });
}, 100);
setTimeout(() => navigate("topMenu", { screen: "menu" }), 100);
return;
}
if (!isFocused()) {
navigate("positions", { screen: "Apps" });
}
if (mapSwitch == "true") {
if (!isFocused()) navigate("positions", { screen: "Apps" });
else if (mapSwitch == "true")
navigate("positions", { screen: "trainMenu" });
} else {
webview.current?.injectJavaScript(`AccordionClassEvent()`);
}
else webview.current?.injectJavaScript(`AccordionClassEvent()`);
return;
};
useEffect(() => {
const unsubscribe = addListener("tabPress", goToTrainMenu);
return unsubscribe;
}, [addListener, mapSwitch, injectJavaScript]);
}, [addListener, mapSwitch]);
return (
<Stack.Navigator detachInactiveScreens={false}>
<Stack.Navigator id={null} detachInactiveScreens={false}>
<Stack.Screen
name="Apps"
options={{
@@ -71,7 +66,17 @@ export const Top = () => {
options={{ ...optionData }}
component={TrainBase}
/>
<Stack.Screen
name="stDiagram"
options={{ ...optionData, gestureEnabled: false }}
component={StationDiagramView}
/>
<Stack.Screen name="howto" options={optionData} component={HowTo} />
<Stack.Screen
name="generalWebView"
options={optionData}
component={GeneralWebView}
/>
<Stack.Screen name="news" options={optionData} component={News} />
<Stack.Screen
name="trainMenu"

View File

@@ -7,7 +7,7 @@
"android",
"web"
],
"version": "6.0.1",
"version": "6.0.4",
"orientation": "default",
"icon": "./assets/icons/s8600.png",
"splash": {
@@ -22,7 +22,7 @@
"**/*"
],
"ios": {
"buildNumber": "47",
"buildNumber": "50",
"supportsTablet": false,
"bundleIdentifier": "jrshikokuinfo.xprocess.hrkn",
"config": {

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,94 @@
◆国鉄っぽいフォントぽいフォントピクトfor Win(xp)
 かつて日本国有鉄道(国鉄)の吊り下げ式駅名標や駅の案内で使用されていたもピクトグラム
(プラスアルファ)を搭載したフォントです。
 東海地方~四国で広く使用されていたものを見本としています。
◆作成ソフト
TTEditにより作成しています。
◆インストールの方法
 「スタート」から設定、コントロールパネルを開き、さらに「フォント」フォルダを開きます。
ファイルメニューから「新しいフォントのインストール」で、フォントを選択のうえインストール
してください。
 また、フォントファイルを適宜の場所に解凍し、上記「フォント」フォルダを開いたうえで、
ドラッグアンドドロップする方法でもインストールできます。
◆収録文字・記号一覧
左側が入力文字、右側が表示されるピクト類です。
0…公衆電話
1…エスカレーター(のぼり)
2…エスカレーター(くだり)
3…階段(おり)
4…階段(のぼり)
B…国鉄バスつばめマーク(つばめ左向き)
C…国鉄バスつばめマーク(つばめ右向き)
G…グリーン車マーク
J…国鉄「JNR」ロゴ
L…L特急マーク
M…公衆便所(男性)
S…シルバーシート
W…公衆便所(女性)
い…手荷物一時預かり
お…大阪市内の駅マーク
き…京都市内の駅マーク
く…北九州市内の駅マーク
け…禁煙マーク
こ…神戸市内の駅マーク
さ…札幌市内の駅マーク
し…新幹線
せ…仙台市内の駅マーク
た…タクシー
つ…つばめマーク(つばめ左向き)
ツ…つばめマーク(つばめ右向き)
て…手荷物預かり
で…国電
と…東京都区内の駅マーク
な…名古屋市内の駅マーク
は…国鉄ハイウェイバス
ば…路線バス
ひ…広島市内の駅マーク
ふ…福岡市内の駅マーク
ぶ…寝台急行マーク
ブ…寝台特急マーク
や…東京山手線内の駅マーク
ゆ…温泉マーク
よ…横浜市内の駅マーク
れ…レール
ろ…コインロッカー
←…矢印(左向き)
→…矢印(右向き)
↑…矢印(上向き)
↓…矢印(下向き)
◆ご使用に当たってのお願い
 フォントは無料にて配布しています。商用利用には耐えられない出来だと思いますが、ご自身
の責任においてご自由にお使いください。
 インストール及び使用にあたっても、ご自身の責任においてご使用ください。インストールや
使用によって蒙る損害については、当方は一切責任を負いかねます。
◆Windows Vistaをお使いの方へ
 Windows Vistaをお使いの方で、フォントのエッジを滑らかにしたい方は、スクリーンフ
ォントの縁を滑らかにする方法を「標準」にしてください。Clear Typeだと滑らかに表示されない
場合があります。
 ・標準への変更方法
 1.ウィンドウ上で右クリックをします。
 2.現れたメニュー中の「個人設定」を選択。
 3.続いて「ウィンドウの色とデザイン」を選択。
 4.一番下の「「デザイン」プロパティを開きます」をクリックします。
 5.現れた別ウィンドウの「効果」ボタンをクリック。
 「次の方法でスクリーンフォントの縁を滑らかにする」のところを「Clear Type」から「標
   準」にします。
 ※これでこのフォントについてはより滑らかに表示されますが、他のフォントが滑らかに表示さ
れない場合が多くなります。
◆フォント自体についての若干のご説明
 このフォントは、前述のとおり、国鉄において東海地区から四国地区の吊り下げ式駅名標や各種
案内表示で使用されたものを見本としています。もともとは、「鉄道掲示基準規程」という通達に
定められているピクトグラムです。
--------------------------------------
作成者Yokochan
ホームページ「旅と鉄の盲腸」http://travelcecum.xsrv.jp/font.htm
連絡先travel_cecum@yahoo.co.jp

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,29 @@
{
"type": "FeatureCollection",
"features": [
{
"properties": {
"name": "阿波池田",
"uri": "https://uedayou.net/jrslod/四国旅客鉄道/土讃線/阿波池田",
"color": "E25885"
},
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[133.80429, 34.02714],
[133.80515, 34.02656]
]
}
},
{
"properties": {
"name": "阿波池田",
"uri": "https://uedayou.net/jrslod/四国旅客鉄道/土讃線/阿波池田"
},
"type": "Feature",
"geometry": { "type": "Point", "coordinates": [133.80429, 34.02714] }
},
{
"properties": {
"name": "佃",
@@ -561,6 +584,29 @@
"type": "Feature",
"geometry": { "type": "Point", "coordinates": [134.53819, 34.08082] }
},
{
"properties": {
"name": "徳島",
"uri": "https://uedayou.net/jrslod/四国旅客鉄道/高徳線/徳島",
"color": "9ACD32"
},
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[134.55251, 34.07404],
[134.55049, 34.07498]
]
}
},
{
"properties": {
"name": "徳島",
"uri": "https://uedayou.net/jrslod/四国旅客鉄道/高徳線/徳島"
},
"type": "Feature",
"geometry": { "type": "Point", "coordinates": [134.55251, 34.07404] }
},
{
"properties": {
"name": "徳島線",

1
check.sh Normal file
View File

@@ -0,0 +1 @@
curl 'https://train.jr-shikoku.co.jp/g?arg1=station&arg2=traintimeinfo&arg3=dia' -H 'accept: */*' -H 'accept-language: ja,en;q=0.9,en-GB;q=0.8,en-US;q=0.7' -b 'user_rule=true; _ga=GA1.1.1550729344.1720017125; _ga_FHL4XV32CY=GS1.1.1741964710.14.1.1741964733.0.0.0' -H 'priority: u=0, i' -H 'referer: https://train.jr-shikoku.co.jp/sp.html' -H 'sec-ch-ua: "Chromium";v="134", "Not:A-Brand";v="24", "Microsoft Edge";v="134"' -H 'sec-ch-ua-mobile: ?0' -H 'sec-ch-ua-platform: "Windows"' -H 'sec-fetch-dest: empty' -H 'sec-fetch-mode: cors' -H 'sec-fetch-site: same-origin' -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Edg/134.0.0.0' > current.txt

View File

@@ -1,157 +0,0 @@
import React from "react";
import { View, Text, TouchableWithoutFeedback } from "react-native";
import dayjs from "dayjs";
import lineColorList from "../../../assets/originData/lineColorList";
export const EachStopList = ({
i,
index,
stationList,
points,
currentTrainData,
openStationACFromEachTrainInfo,
showThrew,
}) => {
if (!showThrew && i.split(",")[1] == "通過") return null;
const [station, se, time] = i.split(","); // 阿波池田,発,6:21
const Stations = stationList
.map((a) => a.filter((d) => d.StationName == station))
.reduce((newArray, e) => newArray.concat(e), []);
/*Array [
Object {
"StationName": "佐古",
"StationNumber": "T01",
},
Object {
"StationName": "佐古",
"StationNumber": "B01",
},
] */
const StationNumbers =
Stations &&
Stations.filter((d) => d.StationNumber).map((d) => d.StationNumber);
// Array [ "T01", "B01",]
const lineIDs = [];
const EachIDs = [];
StationNumbers.forEach((d) => {
const textArray = d.split("");
lineIDs.push(textArray.filter((s) => "A" < s && s < "Z").join(""));
EachIDs.push(textArray.filter((s) => "0" <= s && s <= "9").join(""));
});
// Array [ "T", "B",]
// Array [ "01", "01",]
const dates = dayjs()
.set("hour", parseInt(time.split(":")[0]))
.set("minute", parseInt(time.split(":")[1]))
.add(isNaN(currentTrainData?.delay) ? 0 : currentTrainData.delay, "minute");
const timeString = se == "通過" ? "" : dates.format("HH:mm").split(":");
const onClickStateText = (string) => {
if (string != "通過") return;
alert("この駅は通過駅です");
};
return (
<TouchableWithoutFeedback
onPress={() =>
openStationACFromEachTrainInfo &&
openStationACFromEachTrainInfo(station)
}
key={station}
>
<View style={{ flexDirection: "row", backgroundColor: "white" }}>
<View
style={{
width: 35,
position: "relative",
marginHorizontal: 15,
flexDirection: "row",
height: "101%",
}}
>
{lineIDs.map((lineID, index) => (
<View
style={{
backgroundColor: `${lineColorList[lineID]}${
se == "通過" ? "80" : ""
}`,
flex: 1,
}}
key={lineID}
>
<View style={{ flex: 1 }} />
<Text
style={{
color: "white",
textAlign: "center",
fontSize: 10,
fontWeight: "bold",
}}
>
{lineIDs[index]}
{"\n"}
{EachIDs[index]}
</Text>
<View style={{ flex: 1 }} />
</View>
))}
</View>
<View
style={{
padding: 8,
flexDirection: "row",
borderBottomWidth: 1,
borderBottomColor: "#f0f0f0",
flex: 1,
}}
>
<Text
style={{ fontSize: 20, color: `#000${se == "通過" ? "5" : ""}` }}
>
{station}
</Text>
<View style={{ flex: 1 }} />
<View style={{ position: "relative", width: 0 }}>
{points ? (
<Text style={{ fontSize: 20, position: "absolute", left: -60 }}>
🚊
</Text>
) : null}
</View>
{!isNaN(currentTrainData?.delay) && currentTrainData?.delay != 0 && (
<Text
style={{
fontSize: 15,
color: "black",
width: 60,
position: "absolute",
right: 120,
textAlign: "right",
textDecorationLine: "line-through",
}}
>
{time}
</Text>
)}
<Text
style={{
fontSize: 20,
color: isNaN(currentTrainData?.delay)
? "black"
: currentTrainData?.delay == 0
? "black"
: "red",
width: 60,
}}
onPress={() => onClickStateText(se)}
>
{se == "通過" ? "レ" : `${timeString[0]}:${timeString[1]}`}
</Text>
<Text style={{ fontSize: 18, width: 50 }}>
{se?.replace("発", "出発").replace("着", "到着")}
</Text>
</View>
</View>
</TouchableWithoutFeedback>
);
};

View File

@@ -0,0 +1,237 @@
import React, { FC } from "react";
import { View, Text, TouchableWithoutFeedback } from "react-native";
import dayjs from "dayjs";
import lineColorList from "../../../assets/originData/lineColorList";
type seTypes =
| "発編"
| "着編"
| "通編"
| "頃編"
| "発"
| "着"
| "休編"
| "通休編"
| string;
type currentTrainDataType = {
Index: number;
num: string;
delay: "入線" | number | undefined;
Pos: string;
PosNum: number;
Direction: number;
Type: string;
Line: string;
};
type props = {
i: string;
index: number;
stationList: { StationName: string; StationNumber: string }[][];
points: boolean;
currentTrainData?: currentTrainDataType;
openStationACFromEachTrainInfo?: (station: string) => void;
showThrew: boolean;
};
export const EachStopList: FC<props> = ({
i,
index,
stationList,
points,
currentTrainData,
openStationACFromEachTrainInfo,
showThrew,
}) => {
const [station, se, time] = i.split(",") as [string, seTypes, string]; // 阿波池田,発,6:21
if (!showThrew) {
if (se == "通過") return null;
if (se == "通編") return null;
if (se == "通休編") return null;
}
const Stations = stationList
.map((a) => a.filter((d) => d.StationName == station))
.reduce((newArray, e) => newArray.concat(e), []);
/*Array [
Object {
"StationName": "佐古",
"StationNumber": "T01",
},
Object {
"StationName": "佐古",
"StationNumber": "B01",
},
] */
const StationNumbers =
Stations &&
Stations.filter((d) => d.StationNumber).map((d) => d.StationNumber);
const [seString, seType] = (() => {
switch (se) {
case "発":
return ["出発", "normal"];
case "着":
return ["到着", "normal"];
case "発編":
return ["出発", "community"];
case "着編":
return ["到着", "community"];
case "通編":
return ["通過", "community"];
case "頃編":
return ["頃", "community"];
case "休編":
case "通休編":
return ["運休", "community"];
default:
return [se, "normal"];
}
})();
// Array [ "T01", "B01",]
// Array [ "T", "B",]
// Array [ "01", "01",]
const textColor = `#${seType == "community" ? "44f" : "000"}${
se == "通過" || se == "通編" || se == "通休編" ? "5" : ""
}`;
return (
<TouchableWithoutFeedback
onPress={() =>
openStationACFromEachTrainInfo &&
openStationACFromEachTrainInfo(station)
}
key={station}
>
<View
style={{
flexDirection: "row",
backgroundColor: (se != "休編" && se != "通休編") ? "#ffffffc2" : "#474747c2",
}}
>
<View
style={{
width: 35,
position: "relative",
marginHorizontal: 15,
flexDirection: "row",
height: "101%",
}}
>
{StationNumbers.map((stn, index) => (
<StationNumbersBox stn={stn} se={se} key={index} />
))}
</View>
<View
style={{
padding: 8,
flexDirection: "row",
borderBottomWidth: 1,
borderBottomColor: "#f0f0f0",
flex: 1,
}}
>
<Text
style={{
fontSize: 20,
color: textColor,
fontStyle: seType == "community" ? "italic" : "normal",
}}
>
{station}
</Text>
<View style={{ flex: 1 }} />
<View style={{ position: "relative", width: 0 }}>
{points && (
<Text style={{ fontSize: 20, position: "absolute", left: -60 }}>
🚊
</Text>
)}
</View>
{!!currentTrainData?.delay &&
currentTrainData?.delay != "入線" &&
currentTrainData?.delay != 0 && (
<Text
style={{
fontSize: 15,
color: textColor,
width: 60,
position: "absolute",
right: 120,
textAlign: "right",
textDecorationLine: "line-through",
fontStyle: seType == "community" ? "italic" : "normal",
}}
>
{time}
</Text>
)}
<StationTimeBox
delay={currentTrainData?.delay}
textColor={textColor}
seType={seType}
se={se}
time={time}
/>
<Text style={{ fontSize: 18, width: 50, color: textColor }}>
{seString}
</Text>
</View>
</View>
</TouchableWithoutFeedback>
);
};
const StationNumbersBox: FC<{ stn: string; se: seTypes }> = (props) => {
const { stn, se } = props;
const lineColor = lineColorList[stn.charAt(0)];
const hasThrew = (se == "通過" || se == "通編" || se == "通休編") ? "80" : "";
const backgroundColor = `${lineColor}${hasThrew}`;
return (
<View style={{ backgroundColor, flex: 1 }} key={stn}>
<View style={{ flex: 1 }} />
<Text
style={{
color: "white",
textAlign: "center",
fontSize: 10,
fontWeight: "bold",
}}
>
{stn.charAt(0)}
{"\n"}
{stn.slice(1)}
</Text>
<View style={{ flex: 1 }} />
</View>
);
};
type StationTimeBoxType = {
delay: "入線" | number | undefined;
textColor: string;
seType: seTypes;
se: string;
time: string;
};
const StationTimeBox: FC<StationTimeBoxType> = (props) => {
const { delay, textColor, seType, se, time } = props;
const dates = dayjs()
.set("hour", parseInt(time.split(":")[0]))
.set("minute", parseInt(time.split(":")[1]))
.add(delay == "入線" || delay == undefined ? 0 : delay, "minute");
return (
<Text
style={{
fontSize: 20,
color:
delay != "入線" && delay != undefined
? delay != 0 && "red"
: textColor,
width: 60,
fontStyle: seType == "community" ? "italic" : "normal",
}}
>
{se.includes("通") && time == "" ? "レ" : dates.format("HH:mm")}
</Text>
);
};

View File

@@ -1,47 +0,0 @@
import React from "react";
import { View, Text, ScrollView, useWindowDimensions } from "react-native";
export const LandscapeTrainInfo = (props) => {
const { leftContent, topStickyContent, children, scrollHandlers } = props;
const { height, width } = useWindowDimensions();
return (
<View
style={{
flexDirection: "row",
backgroundColor: "blue",
width: width,
height: (height / 100) * 70,
marginBottom: 50,
}}
>
<View
style={{
flexDirection: "column",
height: (height / 100) * 70,
width: width / 2,
}}
>
<Text>{width / 2}</Text>
{leftContent}
</View>
<ScrollView
{...scrollHandlers}
style={{
width: width / 2,
height: "auto",
}}
stickyHeaderIndices={[1]}
scrollEventThrottle={16}
onScroll={(d) => {
console.log(d.nativeEvent.contentOffset.y);
}}
>
<View style={{ height: 0 }} />
<View style={{ flexDirection: "column" }} index={1}>
{topStickyContent}
</View>
{children}
</ScrollView>
</View>
);
};

View File

@@ -1,8 +1,15 @@
import React from "react";
import React, { FC } from "react";
import { ScrollView } from "react-native";
import { TrainDataView } from "./TrainDataView";
export const LongHeader = ({
import { trainDataType } from "@/lib/trainPositionTextArray";
type props = {
currentTrainData: trainDataType;
currentPosition: string[] | undefined;
nearTrainIDList: string[];
openTrainInfo: (f: string) => void;
navigate: (screen: string, data?: any) => void;
}
export const LongHeader:FC<props> = ({
currentTrainData,
currentPosition,
nearTrainIDList,
@@ -11,14 +18,8 @@ export const LongHeader = ({
}) => {
return (
<ScrollView
//onTouchStart={() => setActionSheetHorizonalScroll(true)}
//onScrollEndDrag={() => setActionSheetHorizonalScroll(false)}
//onScrollBeginDrag={() => console.log("onScrollBeginDrag")}
style={{
flexDirection: "row",
//width: widthPercentageToDP("200%"),
// minHeight: 200,
//height: heightPercentageToDP("20%"),
}}
horizontal
pagingEnabled

View File

@@ -0,0 +1,122 @@
import { trainPosition } from "@/lib/trainPositionTextArray";
import React, { FC } from "react";
import { View, Text, TextStyle, ViewStyle } from "react-native";
type stateBox = {
currentTrainData: any;
platformNumber: any;
title: string;
style?: ViewStyle;
mode?: number;
platformDescription: string;
lineNumber: string;
};
export const PositionBox: FC<stateBox> = (props) => {
const {
currentTrainData,
platformNumber,
title,
style,
mode,
platformDescription,
lineNumber,
} = props;
let firstText = "";
let secondText = "";
let marginText = "";
let externalText = "";
const { isBetween, Pos: PosData } = trainPosition(currentTrainData);
if (isBetween === true) {
const { from, to } = PosData;
firstText = from;
secondText = to;
marginText = mode == 2 ? "→" : "↓";
} else {
const { Pos } = PosData;
if (Pos !== "") {
firstText = Pos;
if (platformNumber) {
secondText = `${platformNumber}番乗り場`;
if (lineNumber) {
externalText = `${lineNumber}番線`;
}
} else if (lineNumber) {
secondText = `${lineNumber}番線`;
}
}
}
return (
<View style={{ ...(mode == 2 ? boxStyle2 : boxStyle), ...style }}>
<Text style={{ fontSize: 12, color: "#0099CC" }}>{title}</Text>
<View style={{ flex: 1 }} />
<View style={{ flexDirection: mode == 2 ? "row" : "column" }}>
{firstText && (
<Text style={mode == 2 ? boxTextStyle2 : (isBetween ? boxTextStyle : boxTextStyleBig)}>
{firstText}
</Text>
)}
{marginText && (
<Text style={{ color: "#0099CC", textAlign: "right" }}>
{marginText}
</Text>
)}
{secondText && (
<Text style={mode == 2 ? boxTextStyle2 :(isBetween ? boxTextStyle : boxTextStyleMini)}>
{secondText}
</Text>
)}
</View>
{(platformDescription || externalText) && (
<View style={{ flexDirection: mode == 2 ? "row" : "column" }}>
<Text
style={{
...{ ...(mode == 2 ? boxTextStyle2 : boxTextStyle) },
fontSize: 10,
}}
>
{" " + externalText}
{" " + platformDescription}
</Text>
</View>
)}
</View>
);
};
const boxStyle: ViewStyle = {
flex: 1,
backgroundColor: "white",
borderRadius: 10,
padding: 10,
margin: 10,
};
const boxStyle2: ViewStyle = {
flex: 1,
backgroundColor: "white",
borderRadius: 10,
padding: 5,
margin: 5,
};
const boxTextStyle2: TextStyle = {
fontSize: 18,
color: "#0099CC",
textAlign: "right",
};
const boxTextStyleBig: TextStyle = {
fontSize: 28,
color: "#0099CC",
textAlign: "right",
};
const boxTextStyleMini: TextStyle = {
fontSize: 16,
color: "#0099CC",
textAlign: "right",
};
const boxTextStyle: TextStyle = {
fontSize: 25,
color: "#0099CC",
textAlign: "right",
};

View File

@@ -7,7 +7,7 @@ export const ScrollStickyContent = (props) => {
<View
style={{
alignItems: "center",
backgroundColor: "white",
backgroundColor: "#ffffffc2",
flexDirection: "row",
}}
>
@@ -16,7 +16,7 @@ export const ScrollStickyContent = (props) => {
padding: 8,
flexDirection: "row",
borderBottomWidth: 1,
borderBottomColor: "#f0f0f0",
borderBottomColor: "#ffffffc2",
flex: 1,
}}
>

View File

@@ -1,8 +1,15 @@
import React from "react";
import React, { FC } from "react";
import { ScrollView } from "react-native";
import { TrainDataView } from "./TrainDataView";
export const ShortHeader = ({
import { trainDataType } from "@/lib/trainPositionTextArray";
type props = {
currentTrainData: trainDataType;
currentPosition: string[] | undefined;
nearTrainIDList: string[];
openTrainInfo: (f: string) => void;
navigate: (screen: string, data?: any) => void;
}
export const ShortHeader:FC<props> = ({
currentTrainData,
currentPosition,
nearTrainIDList,
@@ -11,15 +18,9 @@ export const ShortHeader = ({
}) => {
return (
<ScrollView
//onTouchStart={() => setActionSheetHorizonalScroll(true)}
//onScrollEndDrag={() => setActionSheetHorizonalScroll(false)}
//onScrollBeginDrag={() => console.log("onScrollBeginDrag")}
style={{
flexDirection: "row",
flex: 1,
//width: widthPercentageToDP("200%"),
// minHeight: 200,
//height: heightPercentageToDP("20%"),
}}
horizontal
pagingEnabled

View File

@@ -1,36 +1,42 @@
import { Text, TouchableOpacity } from "react-native";
import React, { useState } from "react";
import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram";
export const ShowSpecialTrain = ({
isTrainDataNothing,
setTrainData,
trainList,
trueTrainID,
}) => {
const { allTrainDiagram } = useAllTrainDiagram();
const replaceSpecialTrainDetail = (trainNum) => {
let TD = trainList[trainNum];
let TD = allTrainDiagram[trainNum];
if (!TD) return;
setTrainData(TD.split("#").filter((d) => d != ""));
};
return (
<>
{isTrainDataNothing && trueTrainID && (
<TouchableOpacity
onPress={() => replaceSpecialTrainDetail(trueTrainID)}
style={{
padding: 10,
flexDirection: "row",
borderColor: "blue",
borderWidth: 1,
margin: 10,
borderRadius: 5,
alignItems: "center",
}}
>
<Text style={{ fontSize: 18, fontWeight: "bold", color: "black" }}>
本来の列車情報を表示
</Text>
</TouchableOpacity>
)}
{isTrainDataNothing &&
trueTrainID?.map((ids) => {
return (
<TouchableOpacity
onPress={() => replaceSpecialTrainDetail(ids)}
style={{
padding: 10,
flexDirection: "row",
borderColor: "blue",
borderWidth: 1,
margin: 10,
borderRadius: 5,
alignItems: "center",
}}
>
<Text
style={{ fontSize: 18, fontWeight: "bold", color: "black" }}
>
本来の列車情報候補を表示:({ids})
</Text>
</TouchableOpacity>
);
})}
</>
);
};

View File

@@ -15,21 +15,7 @@ export const StateBox: FC<stateBox> = (props) => {
<Text style={{ fontSize: 12, color: "#0099CC" }}>{title}</Text>
<View style={{ flex: 1 }} />
<View style={{ flexDirection: mode == 2 ? "row" : "column" }}>
{text?.match("") ? (
<>
<Text style={mode == 2 ? boxTextStyle2 : boxTextStyle}>
{text.split("")[0]}
</Text>
<Text style={{ color: "#0099CC", textAlign: "right" }}>
{mode == 2 ? "→" : "↓"}
</Text>
<Text style={mode == 2 ? boxTextStyle2 : boxTextStyle}>
{text.split("")[1]}
</Text>
</>
) : (
<Text style={mode == 2 ? boxTextStyle2 : boxTextStyle}>{text}</Text>
)}
<Text style={mode == 2 ? boxTextStyle2 : boxTextStyle}>{text}</Text>
</View>
{endText && (
<View style={{ flexDirection: mode == 2 ? "row" : "column" }}>

View File

@@ -1,187 +0,0 @@
import React, { useState, useEffect } from "react";
import { View, TouchableOpacity, useWindowDimensions } from "react-native";
import { StateBox } from "./StateBox";
import { useDeviceOrientationChange } from "../../../stateBox/useDeviceOrientationChange";
import { getStationList2 } from "../../../lib/getStationList2";
import { useCurrentTrain } from "../../../stateBox/useCurrentTrain";
import { SheetManager } from "react-native-actions-sheet";
import { trainPosition } from "../../../lib/trainPositionTextArray";
import { TrainPositionDataPush } from "../../発車時刻表/LED_inside_Component/TrainPositionDataPush";
import { getStationID } from "../../../lib/eachTrainInfoCoreLib/getStationData";
import { useStationList } from "../../../stateBox/useStationList";
export const TrainDataView = ({
currentTrainData,
currentPosition,
nearTrainIDList,
openTrainInfo,
mode = 0,
navigate,
}) => {
const { stationList } = useStationList();
const { width, height } = useWindowDimensions();
const { isLandscape } = useDeviceOrientationChange();
const { inject } = useCurrentTrain();
const [mapsStationData, setMapsStationData] = useState(undefined);
const [platformNumber, setPlatformNumber] = useState();
const [platformDescription, setPlatformDescription] = useState();
useEffect(() => {
//currentTrainData.Pos = "鴨川~端岡"; //test
if (!currentTrainData) return;
fetch(
`https://n8n.haruk.in/webhook/JR-shikoku-PosID?PosNum=${currentTrainData?.PosNum}&Line=${currentTrainData?.Line}`
)
.then((res) => res.json())
.then((data) => {
setPlatformNumber(data?.type == "Station" ? data?.platform : undefined);
setPlatformDescription(
data?.type == "Station" ? data?.description : undefined
);
});
}, [currentTrainData]);
useEffect(() => {
getStationList2().then(setMapsStationData);
}, []);
const onLine = !!currentPosition?.toString().length;
const trainPositionText = (trainData) => {
const { isBetween, Pos: PosData } = trainPosition(trainData);
const { from, to, Pos } = PosData;
if (isBetween === true) return `${from}${to}`;
if (Pos == "") return "";
return `${Pos}${platformNumber ? ` ${platformNumber}番線` : ""}`;
};
const [dialog, setDialog] = useState(false);
const [deleteDialog, setDeleteDialog] = useState(false);
const [posInput, setPosInput] = useState("");
const [descInput, setDescInput] = useState("");
const [stationInput, setStationInput] = useState("");
const [stationNumberInput, setStationNumberInput] = useState("");
return (
<>
<TrainPositionDataPush
dialog={dialog}
setDialog={setDialog}
currentTrainData={currentTrainData}
stationInput={stationInput}
stationNumberInput={stationNumberInput}
posInput={posInput}
descInput={descInput}
setPosInput={setPosInput}
setDescInput={setDescInput}
station={{
Station_JP: trainPositionText(currentTrainData),
StationNumber: currentPosition[0],
}}
/>
<View
style={{
flexDirection: "row",
//minHeight: 200,
//height: heightPercentageToDP("20%"),
width: isLandscape ? (width / 100) * 40 : width,
flex: 1,
}}
>
<TouchableOpacity
style={{ flex: 1, flexDirection: "row" }}
//disabled={!onLine}
onLongPress={() => {
const { isBetween, Pos } = trainPosition(currentTrainData);
if (isBetween === true) {
if (
platformNumber == undefined &&
platformDescription == undefined
)
return;
setStationInput(`${Pos.from}${Pos.to}`);
setStationNumberInput(
getStationID(currentTrainData?.Pos, stationList)
);
setPosInput(platformNumber?.toString() || "");
setDeleteDialog(true);
} else {
setStationInput(Pos.Pos);
setStationNumberInput(
getStationID(currentTrainData?.Pos, stationList)
);
setDescInput(platformDescription || "");
setPosInput(platformNumber?.toString() || "");
setDialog(true);
}
}}
onPress={() => {
if (!onLine) return;
const test = [];
Object.keys(mapsStationData).forEach((d) => {
mapsStationData[d].forEach((x) => {
if (x.StationNumber == currentPosition[0])
test.push({ line: d, station: x });
});
if (currentPosition[0] == "M12") {
test.push({
line: "seto",
station: { Station_JP: "児島", MyStation: "0" },
});
}
});
if (!test.length) return;
navigate("positions", { screen: "Apps" });
inject(
`MoveDisplayStation('${test[0].line}_${test[0].station.MyStation}_${test[0].station.Station_JP}');document.getElementById("disp").insertAdjacentHTML("afterbegin", "<div />");`
);
SheetManager.hide("EachTrainInfo");
}}
>
<StateBox
mode={mode}
title={`現在地 ${currentPosition?.toString()}${onLine ? "▶️" : ""}`}
text={trainPositionText(currentTrainData)}
endText={platformDescription ? `${platformDescription}` : ""}
style={
onLine
? { borderWidth: 1, borderColor: "red", borderStyle: "solid" }
: {}
}
/>
</TouchableOpacity>
<View style={{ flex: 1, flexDirection: mode == 2 ? "row" : "column" }}>
<View style={{ flex: 1, flexDirection: "row" }}>
<StateBox
mode={mode}
title={isNaN(currentTrainData?.delay) ? "状態" : "遅延時分"}
text={`${currentTrainData?.delay}${
isNaN(currentTrainData?.delay) ? "" : "分"
}`}
/>
</View>
<TouchableOpacity
style={{ flex: 1, flexDirection: "row" }}
disabled={nearTrainIDList.length == 0}
onPress={() => {
if (nearTrainIDList.length == 0) return;
openTrainInfo(nearTrainIDList[0]);
}}
>
{nearTrainIDList.length == 0 ? (
<StateBox mode={mode} title="列番" text={currentTrainData?.num} />
) : (
<StateBox
mode={mode}
title="増解結相手を表示▶️"
text={`${nearTrainIDList}`}
style={{
borderWidth: 1,
borderColor: "red",
borderStyle: "solid",
}}
/>
)}
</TouchableOpacity>
</View>
</View>
</>
);
};

View File

@@ -0,0 +1,229 @@
import React, { useState, useEffect, FC } from "react";
import { View, TouchableOpacity, useWindowDimensions } from "react-native";
import { StateBox } from "./StateBox";
import { PositionBox } from "./PositionBox";
import { useDeviceOrientationChange } from "../../../stateBox/useDeviceOrientationChange";
import { getStationList2 } from "../../../lib/getStationList";
import { useCurrentTrain } from "../../../stateBox/useCurrentTrain";
import { SheetManager } from "react-native-actions-sheet";
import { trainDataType, trainPosition } from "@/lib/trainPositionTextArray";
import { StationPosPushDialog } from "../../発車時刻表/LED_inside_Component/TrainPositionDataPush";
import { getStationID } from "../../../lib/eachTrainInfoCoreLib/getStationData";
import { useStationList } from "../../../stateBox/useStationList";
import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram";
import { customTrainDataDetector } from "@/components/custom-train-data";
type props = {
currentTrainData: trainDataType;
currentPosition: string[] | undefined;
nearTrainIDList: string[];
openTrainInfo: (f: string) => void;
mode?: 0 | 1 | 2; //0:通常,1:コンパクト,2:横並び
navigate: (screen: string, data?: any) => void;
}
export const TrainDataView:FC<props> = ({
currentTrainData,
currentPosition,
nearTrainIDList,
openTrainInfo,
mode = 0,
navigate,
}) => {
const { stationList } = useStationList();
const { width, height } = useWindowDimensions();
const { isLandscape } = useDeviceOrientationChange();
const { setInjectData } = useCurrentTrain();
const { allCustomTrainData } = useAllTrainDiagram();
const [mapsStationData, setMapsStationData] = useState(undefined);
const [platformNumber, setPlatformNumber] = useState();
const [lineNumber, setLineNumber] = useState();
const [platformDescription, setPlatformDescription] = useState();
type data = {
type: string;
lineNumber: string;
platformNumber: string;
position: string;
stationName: string;
description: string;
};
const [database, setDatabase] = useState<data>(null);
useEffect(() => {
//currentTrainData.Pos = "鴨川~端岡"; //test
if (!currentTrainData) return;
fetch(
`https://n8n.haruk.in/webhook/JR-shikoku-PosID-v3?PosId=${currentTrainData?.PosNum}&lineName=${currentTrainData?.Line}&StationName=${currentTrainData?.Pos}`
)
.then((res) => res.json())
.then((data) => {
if (!data) return;
const {
type,
stationName,
lineNumber,
platformNumber,
position,
description,
} = data;
setDatabase(data);
if (type == "Station") {
setLineNumber(lineNumber);
setPlatformNumber(platformNumber);
setPlatformDescription(description);
} else {
setLineNumber(undefined);
setPlatformNumber(undefined);
setPlatformDescription(undefined);
}
});
}, [currentTrainData]);
useEffect(() => {
getStationList2().then(setMapsStationData);
}, []);
const onLine = !!currentPosition?.toString().length;
const [trainNumber, setTrainNumber] = useState(currentTrainData?.num);
useEffect(() => {
const { TrainNumberOverride } = customTrainDataDetector(
currentTrainData?.num,
allCustomTrainData
);
if (TrainNumberOverride) {
setTrainNumber(TrainNumberOverride);
}else{
setTrainNumber(currentTrainData?.num);
}
}, [currentTrainData?.num, allCustomTrainData]);
// 投稿システム関係
// Dialog表示関係
const [dialog, setDialog] = useState(false);
const [deleteDialog, setDeleteDialog] = useState(false);
//固定値
const [PosNum, setPosNum] = useState<number | undefined>();
const [Pos, setPos] = useState<string>("");
const [Line, setLine] = useState<string>("");
const [StationNum, setStationNum] = useState<string>("");
//編集情報
const [lineInput, setLineInput] = useState<string>("");
const [posInput, setPosInput] = useState<string>("");
const [descInput, setDescInput] = useState<string>("");
const openEditWindow = () => {
const { isBetween, Pos } = trainPosition(currentTrainData);
if (isBetween === true) return;
//固定値
setPosNum(currentTrainData?.PosNum);
setPos(currentTrainData?.Pos);
setLine(currentTrainData?.Line);
setStationNum(getStationID(currentTrainData?.Pos, stationList));
//入力欄
setPosInput(database?.platformNumber?.toString() || "");
setDescInput(database?.description || "");
setLineInput(database?.lineNumber?.toString() || "");
setDialog(true);
};
return (
<>
<StationPosPushDialog
// Dialog表示関係
dialog={dialog}
setDialog={setDialog}
// 固定情報
PosNum={PosNum}
Pos={Pos}
Line={Line}
StationNum={StationNum}
// 入力欄
lineInput={lineInput}
setLineInput={setLineInput}
posInput={posInput}
setPosInput={setPosInput}
descInput={descInput}
setDescInput={setDescInput}
/>
<View
style={{
flexDirection: "row",
//minHeight: 200,
//height: heightPercentageToDP("20%"),
width: isLandscape ? (width / 100) * 40 : width,
flex: 1,
}}
>
<TouchableOpacity
style={{ flex: 1, flexDirection: "row" }}
//disabled={!onLine}
//onLongPress={openEditWindow}
onLongPress={()=>{
if (!onLine) return;
setInjectData({ type:"train", value:currentTrainData?.num, fixed:true});
navigate("positions", { screen: "Apps" });
SheetManager.hide("EachTrainInfo");
}}
onPress={() => {
if (!onLine) return;
setInjectData({ type: "station", value: currentPosition[0], fixed: false });
navigate("positions", { screen: "Apps" });
SheetManager.hide("EachTrainInfo");
}}
>
<PositionBox
mode={mode}
title={`現在地 ${currentPosition?.toString()}${onLine ? "▶️" : ""}`}
currentTrainData={currentTrainData}
platformNumber={platformNumber}
lineNumber={lineNumber}
platformDescription={platformDescription || ""}
style={
onLine
? { borderWidth: 1, borderColor: "red", borderStyle: "solid" }
: {}
}
/>
</TouchableOpacity>
<View style={{ flex: 1, flexDirection: mode == 2 ? "row" : "column" }}>
<View style={{ flex: 1, flexDirection: "row" }}>
<StateBox
mode={mode}
title={isNaN(currentTrainData?.delay) ? "状態" : "遅延時分"}
text={`${currentTrainData?.delay}${
isNaN(currentTrainData?.delay) ? "" : "分"
}`}
/>
</View>
<TouchableOpacity
style={{ flex: 1, flexDirection: "row" }}
disabled={nearTrainIDList.length == 0}
onPress={() => {
if (nearTrainIDList.length == 0) return;
openTrainInfo(nearTrainIDList[0]);
}}
>
{nearTrainIDList.length == 0 ? (
<StateBox mode={mode} title="列番" text={trainNumber} />
) : (
<StateBox
mode={mode}
title="増解結相手を表示▶️"
text={`${nearTrainIDList}`}
style={{
borderWidth: 1,
borderColor: "red",
borderStyle: "solid",
}}
/>
)}
</TouchableOpacity>
</View>
</View>
</>
);
};

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useMemo, useRef, useState } from "react";
import React, { useEffect, useState } from "react";
import {
View,
Text,
@@ -12,8 +12,7 @@ import {
import { SheetManager } from "react-native-actions-sheet";
import { useScrollHandlers } from "react-native-actions-sheet";
import { AS } from "../../storageControl";
import trainList from "../../assets/originData/trainList";
import { lineListPair } from "../../lib/getStationList";
import { lineListPair, stationIDPair } from "../../lib/getStationList";
import { useCurrentTrain } from "../../stateBox/useCurrentTrain";
import { checkDuplicateTrainData } from "../../lib/checkDuplicateTrainData";
import { getTrainType } from "../../lib/getTrainType";
@@ -28,15 +27,13 @@ import { ShortHeader } from "./EachTrainInfo/ShortHeader";
import { ScrollStickyContent } from "./EachTrainInfo/ScrollStickyContent";
import { getStationID } from "../../lib/eachTrainInfoCoreLib/getStationData";
import { findReversalPoints } from "../../lib/eachTrainInfoCoreLib/findReversalPoints";
import { migrateTrainName } from "../../lib/eachTrainInfoCoreLib/migrateTrainName";
import { getType } from "../../lib/eachTrainInfoCoreLib/getType";
import { searchSpecialTrain } from "../../lib/eachTrainInfoCoreLib/searchSpecialTrain";
import { openBackTrainInfo } from "../../lib/eachTrainInfoCoreLib/openBackTrainInfo";
import { ShowSpecialTrain } from "./EachTrainInfo/ShowSpecialTrain";
import { useTrainMenu } from "../../stateBox/useTrainMenu";
import { HeaderText } from "./EachTrainInfoCore/HeaderText";
import { useStationList } from "../../stateBox/useStationList";
import { stationIDPair } from "../../lib/getStationList2";
import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram";
export const EachTrainInfoCore = ({
actionSheetRef,
@@ -45,22 +42,19 @@ export const EachTrainInfoCore = ({
from,
navigate,
}) => {
// const [actionSheetHorizonalScroll, setActionSheetHorizonalScroll] = useState(false);
const { currentTrain } = useCurrentTrain();
const { currentTrain, getCurrentStationData, getPosition } =
useCurrentTrain();
const { originalStationList, stationList } = useStationList();
const { allTrainDiagram: trainList, allCustomTrainData } =
useAllTrainDiagram();
const { setTrainInfo } = useTrainMenu();
const [currentTrainData, setCurrentTrainData] = useState();
// const [actionSheetHorizonalScroll, setActionSheetHorizonalScroll] = useState(false);
useEffect(() => {
if (!currentTrain.length) return;
setCurrentTrainData(
checkDuplicateTrainData(
currentTrain.filter((d) => d.num == data.trainNum),
stationList
)
);
const stationData = getCurrentStationData(data.trainNum);
if (stationData) {
setCurrentTrainData(stationData);
}
}, [currentTrain, data.trainNum]);
useEffect(() => {
@@ -89,27 +83,36 @@ export const EachTrainInfoCore = ({
const [haveThrough, setHaveThrough] = useState(false);
// 使用例
const stopStationIDList = trainDataWidhThrough.map((i) => {
const [station, se, time] = i.split(",");
const Stations = stationList.map((a) =>
a.filter((d) => d.StationName == station)
);
const StationNumbers =
Stations &&
Stations.reduce((newArray, e) => {
return newArray.concat(e);
}, []).map((d) => d.StationNumber);
return StationNumbers;
});
const [stopStationIDList, setStopStationList] = useState([]);
useEffect(() => {
const stopStationList = trainData.map((i) => {
const x = trainDataWidhThrough.map((i) => {
const [station, se, time] = i.split(",");
const Stations = stationList.map((a) =>
a.filter((d) => d.StationName == station)
);
const StationNumbers =
Stations &&
Stations.reduce((newArray, e) => {
return newArray.concat(e);
}, []).map((d) => d.StationNumber);
return StationNumbers;
});
setStopStationList(x);
}, [trainDataWidhThrough]);
useEffect(() => {
const isCancel = [];
const stopStationList = trainData.map((i, index, array) => {
const [station, se, time] = i.split(",");
const [nextStation, nextSe, nextTime] =
array[index + 1]?.split(",") || [];
isCancel.push(se.includes("休") && nextSe.includes("休"));
if (se == "通編") setHaveThrough(true);
return stationList.map((a) => a.filter((d) => d.StationName == station));
});
const allThroughStationList = stopStationList.map((i, index, array) => {
let allThroughStation = [];
if (index == array.length - 1) return;
const firstItem = array[index];
const secondItem = array[index + 1];
let betweenStationLine = "";
@@ -134,7 +137,9 @@ export const EachTrainInfoCore = ({
d.StationNumber > baseStationNumberFirst &&
d.StationNumber < baseStationNumberSecond
) {
allThroughStation.push(`${d.Station_JP},通過,`);
allThroughStation.push(
`${d.Station_JP},${isCancel[index] ? "通休編" : "通過"},`
);
setHaveThrough(true);
reverse = false;
} else {
@@ -142,7 +147,9 @@ export const EachTrainInfoCore = ({
d.StationNumber < baseStationNumberFirst &&
d.StationNumber > baseStationNumberSecond
) {
allThroughStation.push(`${d.Station_JP},通過,`);
allThroughStation.push(
`${d.Station_JP},${isCancel[index] ? "通休編" : "通過"},`
);
setHaveThrough(true);
reverse = true;
}
@@ -175,12 +182,12 @@ export const EachTrainInfoCore = ({
const position = points.findIndex((d) => d == true);
let isThrew = false;
if (position == -1) return () => {};
setShowThrew(true);
if (trainDataWidhThrough[position].split(",")[1] == "通過") {
LayoutAnimation.configureNext({
duration: 400,
update: { type: "easeInEaseOut", springDamping: 0.6 },
});
setShowThrew(true);
isThrew = true;
}
if (position < 5) {
@@ -189,49 +196,30 @@ export const EachTrainInfoCore = ({
const count = position * 44 - 50;
// 0.5秒待機してからスクロール
setTimeout(
() => scrollHandlers.ref.current?.scrollTo({ y: count, animated: true }),
() =>
scrollHandlers.ref.current?.scrollTo({ y: count, animated: true }),
400
);
}
setIsJumped(true);
}, [points]);
const trainName = useMemo(() => {
if (!data.limited) return "";
const limitedArray = data.limited.split(":");
const type = getType(limitedArray[0]);
switch (true) {
case !!limitedArray[1]:
// 特急の場合は、列車名を取得
return type + migrateTrainName(limitedArray[1]);
case trainData.length == 0:
// 特急以外の場合は、列車番号を取得
return type;
default:
// 行先がある場合は、行先を取得
return (
type +
migrateTrainName(
trainData[trainData.length - 1].split(",")[0] + "行き"
)
);
}
}, [data.limited, trainData]);
const { height } = useWindowDimensions();
const { isLandscape } = useDeviceOrientationChange();
const scrollHandlers = actionSheetRef
? useScrollHandlers("scrollview-1", actionSheetRef)
: null;
const [trueTrainID, setTrueTrainID] = useState();
const [trueTrainID, setTrueTrainID] = useState([]);
useEffect(() => {
if (!data.trainNum) return;
const TD = trainList[data.trainNum];
setHeadStation([]);
setTailStation([]);
if (!TD) {
const specialTrainActualID = searchSpecialTrain(data.trainNum, trainList);
setTrueTrainID(specialTrainActualID || undefined);
const specialTrainActualIDs = searchSpecialTrain(
data.trainNum,
trainList
);
setTrueTrainID(specialTrainActualIDs || []);
setTrainData([]);
return;
}
@@ -242,9 +230,8 @@ export const EachTrainInfoCore = ({
if (!data.trainNum) return;
const NearTrainList = getInfluencedTrainData(data.trainNum);
if (NearTrainList.length == 0) return;
const returnArray = NearTrainList.map((d) => d.id);
const TDArray = NearTrainList.map((d) => d.TrainData);
setNearTrainIDList(returnArray);
setNearTrainIDList(NearTrainList.map((d) => d.id));
if (trainData.length == 0) return;
if (TDArray.length == 0) return;
let head = [];
@@ -268,80 +255,42 @@ export const EachTrainInfoCore = ({
}
})
);
if (head) setHeadStation(head);
else setHeadStation([]);
if (tail) setTailStation(tail);
else setTailStation([]);
setHeadStation(head || []);
setTailStation(tail || []);
}, [trainData, data]);
useEffect(() => {
//currentTrainData.Pos = "鴨川~端岡"; //test
if (!currentTrainData) return;
if (!currentTrainData?.Pos) return;
if (currentTrainData?.Pos.match("")) {
const pos = currentTrainData?.Pos.replace("(下り)", "")
.replace("(上り)", "")
.replace("(徳島線)", "")
.replace("(高徳線)", "")
.split("");
const direction = parseInt(currentTrainData?.Direction) || 0;
if (pos[0] == "児島" && pos[1] == "宇多津") {
setCurrentPosition(["M12", "Y09"]);
return;
} else if (pos[1] == "児島" && pos[0] == "宇多津") {
setCurrentPosition(["Y09", "M12"]);
return;
}else if (pos[0] == "伊予若宮" && pos[1] == "伊予白滝") {
setCurrentPosition(["S18", "S14"]);
return;
} else if (pos[0] == "伊予白滝" && pos[1] == "伊予若宮") {
setCurrentPosition(["S14", "S18"]);
return;
} else if (pos[0] == "伊予大洲" && pos[1] == "伊予若宮") {
setCurrentPosition(["U14", "U14"]);
return;
} else if (pos[0] == "伊予若宮" && pos[1] == "伊予大洲") {
setCurrentPosition(["U14", "U14"]);
return;
const position = getPosition(currentTrainData);
if (stopStationIDList.length == 0) return;
if (position) {
if (position.length > 1) {
if (position[0] == "-Iyo") {
position[0] =
stopStationIDList[
stopStationIDList.findIndex((d) => d.includes("U14")) - 1
][0];
} else if (position[0] == "+Iyo") {
position[0] =
stopStationIDList[
stopStationIDList.findIndex((d) => d.includes("U14")) + 1
][0];
}
if (position[1] == "+Iyo") {
position[1] =
stopStationIDList[
stopStationIDList.findIndex((d) => d.includes("U14")) + 1
][0];
} else if (position[1] == "-Iyo") {
position[1] =
stopStationIDList[
stopStationIDList.findIndex((d) => d.includes("U14")) - 1
][0];
}
}
const currentPosID = Object.keys(originalStationList).map((key) => {
let firstStation = false;
let firstStationID = "";
let secondStation = false;
let secondStationID = "";
originalStationList[key].forEach((station) => {
if (station.Station_JP === pos[0]) {
firstStation = true;
firstStationID = station.StationNumber;
}
if (station.Station_JP === pos[1]) {
secondStation = true;
secondStationID = station.StationNumber;
}
});
if (firstStation && secondStation) {
return [firstStationID, secondStationID];
} else return false;
});
const currentPos = currentPosID.filter((d) => d != false)[0];
if (currentPos) {
if (direction == 0) setCurrentPosition(currentPos.reverse());
else setCurrentPosition(currentPos);
} else if (direction == 0) {
setCurrentPosition([
getStationID(pos[1], stationList),
getStationID(pos[0], stationList),
]);
} else {
setCurrentPosition([
getStationID(pos[0], stationList),
getStationID(pos[1], stationList),
]);
}
} else {
setCurrentPosition([getStationID(currentTrainData?.Pos, stationList)]);
setCurrentPosition(position);
}
}, [currentTrainData]);
}, [currentTrainData,stopStationIDList]);
useEffect(() => {
//列車現在地アイコン表示スイッチ
@@ -351,21 +300,23 @@ export const EachTrainInfoCore = ({
})
.catch(() => AS.setItem("trainPositionSwitch", "true"));
}, []);
const customTrainType = getTrainType({
type: customTrainDataDetector(data.trainNum, allCustomTrainData).type,
});
const openTrainInfo = (d) => {
const train = customTrainDataDetector(d);
const train = customTrainDataDetector(d, allCustomTrainData);
let TrainNumber = "";
if (train.trainNumDistance != undefined) {
const timeInfo =
parseInt(d.replace("M", "").replace("D", "")) - train.trainNumDistance;
TrainNumber = timeInfo + "号";
}
const limitedData = getTrainType({ type: train.type });
const payload = {
data: {
trainNum: d,
limited: `${getTrainType(train.type).data}:${
train.trainName
}${TrainNumber}`,
limited: `${limitedData.data}:${train.trainName}${TrainNumber}`,
},
navigate,
from: from == "LED" ? "LED2" : "NearTrainDiagramView",
@@ -380,13 +331,6 @@ export const EachTrainInfoCore = ({
}
};
const headerItem = {
currentTrainData,
currentPosition,
nearTrainIDList,
openTrainInfo,
navigate,
};
return (
<View
style={{
@@ -419,26 +363,53 @@ export const EachTrainInfoCore = ({
tailStation={tailStation}
navigate={navigate}
from={from}
scrollHandlers={scrollHandlers}
/>
<DynamicHeaderScrollView
from={from}
styles={styles}
actionSheetRef={actionSheetRef}
scrollHandlers={scrollHandlers}
containerProps={{
style: {
maxHeight: isLandscape ? height - 94 : (height / 100) * 70,
backgroundColor:
customTrainType.data === "notService" ? "#777777ff" : "white",
},
}}
shortHeader={<ShortHeader {...headerItem} />}
longHeader={<LongHeader {...headerItem} />}
shortHeader={
<ShortHeader
{...{
currentTrainData,
currentPosition,
nearTrainIDList,
openTrainInfo,
navigate,
}}
/>
}
longHeader={
<LongHeader
{...{
currentTrainData,
currentPosition,
nearTrainIDList,
openTrainInfo,
navigate,
}}
/>
}
topStickyContent={
<ScrollStickyContent
{...{ currentTrainData, showThrew, setShowThrew, haveThrough }}
/>
}
>
{customTrainType.data === "notService" && (
<Text style={{ backgroundColor: "#ffffffc2", fontWeight: "bold" }}>
この列車には乗車できません
</Text>
)}
{headStation.length != 0 &&
headStation.map((i, index) =>
showHeadStation.findIndex((d) => d == index) == -1 ? (
@@ -458,6 +429,7 @@ export const EachTrainInfoCore = ({
borderRadius: 5,
alignItems: "center",
}}
key={i.station + "-head"}
>
<Text
style={{ fontSize: 18, fontWeight: "bold", color: "black" }}
@@ -472,7 +444,6 @@ export const EachTrainInfoCore = ({
<ShowSpecialTrain
isTrainDataNothing={trainData.length == 0}
setTrainData={setTrainData}
trainList={trainList}
trueTrainID={trueTrainID}
/>
{!trainData.length && (
@@ -488,6 +459,7 @@ export const EachTrainInfoCore = ({
margin: 10,
borderRadius: 5,
alignItems: "center",
backgroundColor: "#ffffffc2",
}}
>
<Text style={{ fontSize: 18, fontWeight: "bold", color: "black" }}>
@@ -497,7 +469,7 @@ export const EachTrainInfoCore = ({
)}
{trainDataWidhThrough.map((i, index) =>
i.split(",")[1] == "提" ? (
<DataFromButton i={i} />
<DataFromButton i={i} key={i + "-data"} />
) : (
<EachStopList
{...{
@@ -509,9 +481,13 @@ export const EachTrainInfoCore = ({
openStationACFromEachTrainInfo,
showThrew,
}}
key={i + "-stop"}
/>
)
)}
<Text style={{ backgroundColor: "#ffffffc2" }}>
時刻が斜体,青色になっている時刻はコミュニティで追加されている独自データです
</Text>
{tailStation.length != 0 &&
tailStation.map(({ station, dia }, index) =>
showTailStation.findIndex((d) => d == index) == -1 ? (
@@ -552,6 +528,7 @@ export const EachTrainInfoCore = ({
flexDirection: "row",
borderBottomWidth: 1,
borderBottomColor: "#f0f0f0",
backgroundColor: "#ffffffc2",
flex: 1,
}}
>

View File

@@ -1,12 +1,18 @@
import React, { CSSProperties, FC, useEffect, useMemo, useState } from "react";
import { Text, View, LayoutAnimation, TextStyle } from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { Text, View, TextStyle, TouchableOpacity } from "react-native";
import { SheetManager } from "react-native-actions-sheet";
import { getType } from "../../../lib/eachTrainInfoCoreLib/getType";
import { migrateTrainName } from "../../../lib/eachTrainInfoCoreLib/migrateTrainName";
import { TrainIconStatus } from "./trainIconStatus";
import { TrainViewIcon } from "./trainViewIcon";
import { OneManText } from "./HeaderTextParts/OneManText";
import { customTrainDataDetector } from "@/components/custom-train-data";
import { InfogramText } from "@/components/ActionSheetComponents/EachTrainInfoCore/HeaderTextParts/InfogramText";
import { useTrainMenu } from "@/stateBox/useTrainMenu";
import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram";
import { useNotification } from "@/stateBox/useNotifications";
import { getStringConfig } from "@/lib/getStringConfig";
import { FontAwesome, MaterialCommunityIcons } from "@expo/vector-icons";
import { getPDFViewURL } from "@/lib/getPdfViewURL";
type Props = {
data: { trainNum: string; limited: string };
@@ -18,10 +24,11 @@ type Props = {
navigate: any;
from: string;
fontLoaded: boolean;
scrollHandlers: any;
};
const textConfig: TextStyle = {
fontSize: 18,
fontSize: 17,
fontWeight: "bold",
color: "white",
};
@@ -35,130 +42,174 @@ export const HeaderText: FC<Props> = ({
tailStation,
navigate,
from,
scrollHandlers,
}) => {
const { limited, trainNum } = data;
// 貨物の判定
const freightDetect = (num:string)=>{
switch(num){
case "71":
return "貨物 東京(タ)→高松(タ)";
case "73":
case "75":
return "貨物 大阪(タ)→高松(タ)";
case "3079":
return "貨物 高松(タ)→伊予三島";
case "3071":
case "3077":
return "貨物 高松(タ)→新居浜";
case "3073":
return "貨物 高松(タ)→松山貨物";
case "70":
return "貨物 高松(タ)→東京(タ)";
case "74":
case "76":
return "貨物 高松(タ)→大阪(タ)";
case "3078":
return "貨物 伊予三島→高松(タ)";
case "3070":
return "貨物 新居浜→高松(タ)";
case "3076":
return "貨物 新居浜→高松(タ)";
case "3072":
return "貨物 松山貨物→高松(タ)";
case "9070":
return "貨物 臨時";
default:
return false;
}
}
// 列車名、種別、フォントの取得
const [typeName, trainName, fontAvailable] = useMemo(() => {
if (!limited) return "";
const limitedArray = limited.split(":");
const [type, fontAvailable] = (() => {
const d = getType(limitedArray[0]);
switch (true) {
case !!d:
return [d, true];
case !!trainNum.includes("T"):
return ["単機回送", false];
case !!trainNum.includes("R"):
case !!trainNum.includes("E"):
case !!trainNum.includes("L"):
case !!trainNum.includes("A"):
case !!trainNum.includes("B"):
return ["回送", false];
case !!trainNum.includes("H"):
return ["試運転", false];
case !!trainNum.match("D"):
case !!trainNum.match("M"):
return ["普通", true];
case !!freightDetect(trainNum):
return [freightDetect(trainNum), false];
default:
return ["", false];
}
})();
switch (true) {
case !!limitedArray[1]:
// 特急の場合は、列車名を取得
return [type, migrateTrainName(limitedArray[1]), fontAvailable];
case trainData.length == 0:
// 特急以外の場合は、列車番号を取得
const { updatePermission } = useTrainMenu();
const { allCustomTrainData } = useAllTrainDiagram();
const { expoPushToken } = useNotification();
return [type, "", fontAvailable];
// 列車名、種別、フォントの取得
const [
typeName,
trainName,
fontAvailable,
isOneMan,
infogram,
isEdit,
uwasa,
vehicleFormation,
trainInfoUrl,
] = useMemo(() => {
const {
type,
trainName,
trainNumDistance,
infogram,
isEdit,
uwasa,
vehicleFormation,
trainInfoUrl,
} = customTrainDataDetector(trainNum, allCustomTrainData);
const [typeString, fontAvailable, isOneMan] = getStringConfig(
type,
trainNum
);
switch (true) {
case trainName !== "":
// 特急の場合は、列車名を取得
// 列番対称データがある場合はそれから列車番号を取得
return [
typeString,
trainName +
(trainNumDistance !== null
? ` ${parseInt(trainNum) - trainNumDistance}`
: ""),
fontAvailable,
isOneMan,
infogram,
isEdit,
uwasa,
vehicleFormation,
trainInfoUrl,
];
case trainData[trainData.length - 1] === undefined:
return [
typeString,
"",
fontAvailable,
isOneMan,
infogram,
isEdit,
uwasa,
vehicleFormation,
trainInfoUrl,
];
default:
// 行先がある場合は、行先を取得
return [
type,
typeString,
migrateTrainName(
trainData[trainData.length - 1].split(",")[0] + "行き"
),
fontAvailable,
isOneMan,
infogram,
isEdit,
uwasa,
vehicleFormation,
trainInfoUrl,
];
}
}, [limited, trainData]);
// 1人運転の判定
const isOneMan = useMemo(() => {
const OneManRegex = new RegExp(/^4[1-9]\d\d[DM]$/);
const OneManRegex2 = new RegExp(/^5[1-7]\d\d[DM]$/);
return !!(
OneManRegex.test(trainNum) ||
OneManRegex2.test(trainNum) ||
trainNum === "3621D"
);
}, [trainNum]);
}, [trainData]);
return (
<View style={{ padding: 10, flexDirection: "row", alignItems: "center" }}>
<View
style={{ padding: 10, flexDirection: "row", alignItems: "center" }}
onTouchStart={() =>
scrollHandlers.ref.current?.scrollTo({ y: 0, animated: true })
}
>
<TrainIconStatus {...{ data, navigate, from }} />
<View
style={{ borderRadius: 5, flexDirection: "row", alignItems: "center" }}
<TouchableOpacity
style={{
borderRadius: 5,
flexDirection: "row",
alignItems: "center",
...(trainInfoUrl
? {
borderWidth: 0,
borderBottomWidth: 1,
borderStyle: "solid",
borderColor: "white",
}
: {}),
}}
onPress={() => {
if (!trainInfoUrl) return;
const uri = trainInfoUrl.includes("pdf")
? getPDFViewURL(trainInfoUrl)
: trainInfoUrl;
navigate("generalWebView", { uri, useExitButton: true });
SheetManager.hide("EachTrainInfo");
}}
disabled={!trainInfoUrl}
>
<Text
style={{
fontSize: 20,
color: "white",
fontFamily: fontAvailable ? "JR-Nishi" : undefined,
fontWeight: !fontAvailable ?"bold":undefined,
fontWeight: !fontAvailable ? "bold" : undefined,
marginRight: 5,
}}
>
{typeName}
</Text>
{isOneMan && <OneManText />}
<Text style={textConfig}>{trainName}</Text>
</View>
<Text style={{...textConfig,...trainName.length >10 ?{fontSize:14}:{} }}>{trainName}</Text>
<InfogramText infogram={infogram} />
{/* {trainInfoUrl && (
<MaterialCommunityIcons
name={"open-in-new"}
color="white"
size={15}
/>
)} */}
</TouchableOpacity>
{isEdit && (
<FontAwesome
name="commenting-o"
size={20}
color="white"
style={{ marginLeft: 5 }}
onPress={() =>
alert(
`[このアイコン、列車データはコミュニティによってリアルタイム追加されています。]\n使用車両情報:\n${vehicleFormation}\n投稿者メモ:\n${
uwasa || "なし"
}`
)
}
/>
)}
<View style={{ flex: 1 }} />
<Text style={textConfig}>
{showHeadStation.map((d) => `${headStation[d].id} + `)}
{trainNum}
{showTailStation.map((d) => ` + ${tailStation[d].id}`)}
</Text>
<TouchableOpacity
onLongPress={() => {
if (!updatePermission) return;
const uri = `https://jr-shikoku-data-post-system.pages.dev?trainNum=${trainNum}&token=${expoPushToken}`;
navigate("generalWebView", { uri, useExitButton: false });
SheetManager.hide("EachTrainInfo");
}}
disabled={!updatePermission}
>
<Text style={textConfig}>
{showHeadStation.map((d) => `${headStation[d].id} + `)}
{trainNum}
{showTailStation.map((d) => ` + ${tailStation[d].id}`)}
</Text>
</TouchableOpacity>
<TrainViewIcon {...{ data, navigate, from }} />
</View>

View File

@@ -0,0 +1,18 @@
import React, { FC } from "react";
import { Text } from "react-native";
type props = {
infogram: string;
}
export const InfogramText: FC<props> = ({infogram}) => {
return (
<Text
style={{
fontSize: 20,
color: "white",
fontFamily: "JNR-font",
}}
>
{infogram}
</Text>
);
};

View File

@@ -6,6 +6,7 @@ import { useInterval } from "../../../lib/useInterval";
import { Icon } from "@expo/vector-icons/build/createIconSet";
import { SheetManager } from "react-native-actions-sheet";
import { customTrainDataDetector } from "../../custom-train-data";
import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram";
type GlyphNames = ComponentProps<typeof Ionicons>["name"];
@@ -22,11 +23,14 @@ export const TrainIconStatus: FC<Props> = ({ data, navigate, from }) => {
const [trainIcon, setTrainIcon] = useState(null);
const [anpanmanStatus, setAnpanmanStatus] = useState<apt>();
const [address, setAddress] = useState("");
const { allCustomTrainData } = useAllTrainDiagram();
useEffect(() => {
if (!data.trainNum) return;
const { trainIcon, infoUrl } = customTrainDataDetector(data.trainNum);
if (trainIcon) setTrainIcon(trainIcon);
const { img, infoUrl } = customTrainDataDetector(
data.trainNum,
allCustomTrainData
);
if (img) setTrainIcon(img);
if (infoUrl) setAddress(infoUrl);
switch (data.trainNum) {
@@ -47,7 +51,6 @@ export const TrainIconStatus: FC<Props> = ({ data, navigate, from }) => {
)
.then((d) => d.json())
.then((d) => {
console.log(d);
if (d.trainStatus == "") {
//setAnpanmanStatus({name:"checkmark-circle-outline",color:"blue"});
} else if (d.trainStatus == "▲") {
@@ -57,6 +60,30 @@ export const TrainIconStatus: FC<Props> = ({ data, navigate, from }) => {
}
});
break;
case "2074D":
case "2076D":
case "2080D":
case "2082D":
case "2071D":
case "2073D":
case "2079D":
case "2081D":
fetch(
`https://n8n.haruk.in/webhook/dosan-anpanman-first?trainNum=${
data.trainNum
}&month=${dayjs().format("M")}&day=${dayjs().format("D")}`
)
.then((d) => d.json())
.then((d) => {
if (d.trainStatus == "") {
//setAnpanmanStatus({name:"checkmark-circle-outline",color:"blue"});
} else if (d.trainStatus == "▲") {
setAnpanmanStatus({ name: "warning-outline", color: "yellow" });
} else if (d.trainStatus == "×") {
//setAnpanmanStatus({ name: "close-circle-outline", color: "red" });
}
});
break;
}
}, [data.trainNum]);
const [move, setMove] = useState(true);
@@ -79,17 +106,18 @@ export const TrainIconStatus: FC<Props> = ({ data, navigate, from }) => {
});
SheetManager.hide("EachTrainInfo");
}}
disabled={!address}
>
{move ? (
<Image
source={{ uri: trainIcon }}
style={{ height: 34, width: 30, marginRight: 5 }}
resizeMethod="scale"
style={{ height: 30, width: 24, marginRight: 5 }}
resizeMethod="resize"
/>
) : (
<Ionicons
{...anpanmanStatus}
size={30}
size={24}
style={{ marginRight: 5 }}
/>
)}

View File

@@ -10,6 +10,7 @@ import {
BackHandler,
} from "react-native";
import { Ionicons, MaterialCommunityIcons } from "@expo/vector-icons";
import dayjs from "dayjs";
import ActionSheet, {
SheetManager,
useScrollHandlers,
@@ -19,9 +20,11 @@ import { useSafeAreaInsets } from "react-native-safe-area-context";
import ViewShot from "react-native-view-shot";
import * as Sharing from "expo-sharing";
import { useTrainDelayData } from "../../stateBox/useTrainDelayData";
import { BottomButtons } from "./JRSTraInfo/BottomButtons";
export const JRSTraInfo = () => {
const { getTime, delayData, loadingDelayData, setLoadingDelayData } =
useTrainDelayData();
const timeData = dayjs(getTime).format("HH:mm");
const actionSheetRef = useRef(null);
const scrollHandlers = useScrollHandlers("scrollview-1", actionSheetRef);
const insets = useSafeAreaInsets();
@@ -46,11 +49,7 @@ export const JRSTraInfo = () => {
ref={actionSheetRef}
isModal={Platform.OS == "ios"}
containerStyle={
Platform.OS == "android"
? {
paddingBottom: insets.bottom,
}
: {}
Platform.OS == "android" ? { paddingBottom: insets.bottom } : {}
}
useBottomSafeAreaPadding={Platform.OS == "android"}
>
@@ -90,15 +89,8 @@ export const JRSTraInfo = () => {
列車遅延速報EX
</Text>
<View style={{ flex: 1 }} />
{/* <TouchableOpacity style={{padding:10,backgroundColor:"white",alignContent:"center"}} onPress={() => {doFetch()}}>
<Text style={{fontSize:20,fontWeight:"bold",color:"#0099CC"}}>最新の情報へ更新</Text>
</TouchableOpacity> */}
<Text style={{ fontSize: 30, fontWeight: "bold", color: "white" }}>
{getTime
? getTime.toLocaleTimeString("ja-JP").split(":")[0] +
":" +
getTime.toLocaleTimeString("ja-JP").split(":")[1]
: NaN}{" "}
{timeData}
</Text>
<Ionicons
name="reload"
@@ -156,57 +148,7 @@ export const JRSTraInfo = () => {
</View>
</ScrollView>
</ViewShot>
<View
style={{
padding: 10,
backgroundColor: "#0099CC",
flexDirection: "row",
justifyContent: "space-between",
}}
>
<TouchableOpacity
style={{
padding: 10,
flexDirection: "row",
borderColor: "white",
borderWidth: 1,
margin: 10,
borderRadius: 5,
alignItems: "center",
backgroundColor: "#0099CC",
flex: 1,
}}
onPress={() =>
Linking.openURL("https://mstdn.y-zu.org/@JRSTraInfoEX")
}
>
<MaterialCommunityIcons name="mastodon" color="white" size={30} />
<View style={{ flex: 1 }} />
<Text style={{ fontSize: 25, fontWeight: "bold", color: "white" }}>
MastodonBOT
</Text>
<View style={{ flex: 1 }} />
</TouchableOpacity>
<TouchableOpacity
style={{
padding: 10,
flexDirection: "row",
borderColor: "white",
borderWidth: 1,
margin: 10,
borderRadius: 5,
alignItems: "center",
backgroundColor: "#0099CC",
}}
onPress={onCapture}
>
<MaterialCommunityIcons
name="share-variant"
color="white"
size={30}
/>
</TouchableOpacity>
</View>
<BottomButtons onCapture={onCapture} />
</View>
</ActionSheet>
);

View File

@@ -0,0 +1,49 @@
import React, { CSSProperties, FC } from "react";
import {
View,
Text,
TouchableOpacity,
Linking,
StyleProp,
ViewStyle,
} from "react-native";
import { MaterialCommunityIcons } from "@expo/vector-icons";
const styles: StyleProp<ViewStyle> = {
padding: 10,
flexDirection: "row",
borderColor: "white",
borderWidth: 1,
margin: 10,
borderRadius: 5,
alignItems: "center",
backgroundColor: "#0099CC",
};
export const BottomButtons: FC<{ onCapture: () => void }> = ({ onCapture }) => {
return (
<View
style={{
padding: 10,
backgroundColor: "#0099CC",
flexDirection: "row",
justifyContent: "space-between",
}}
>
<TouchableOpacity
style={{ ...styles, flex: 1 }}
onPress={() => Linking.openURL("https://mstdn.y-zu.org/@JRSTraInfoEX")}
>
<MaterialCommunityIcons name="mastodon" color="white" size={30} />
<View style={{ flex: 1 }} />
<Text style={{ fontSize: 25, fontWeight: "bold", color: "white" }}>
MastodonBOT
</Text>
<View style={{ flex: 1 }} />
</TouchableOpacity>
<TouchableOpacity style={styles} onPress={onCapture}>
<MaterialCommunityIcons name="share-variant" color="white" size={30} />
</TouchableOpacity>
</View>
);
};

View File

@@ -0,0 +1,146 @@
import React, { useRef } from "react";
import { View, Platform, Text } from "react-native";
import ActionSheet ,{ ScrollView } from "react-native-actions-sheet";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { ListItem } from "@rneui/themed";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import { Linking } from "react-native";
import TouchableScale from "react-native-touchable-scale";
export const Social = () => {
const actionSheetRef = useRef(null);
const insets = useSafeAreaInsets();
return (
<ActionSheet
gestureEnabled
CustomHeaderComponent={<></>}
ref={actionSheetRef}
isModal={Platform.OS == "ios"}
containerStyle={
Platform.OS == "android"
? {
paddingBottom: insets.bottom,
}
: {}
}
useBottomSafeAreaPadding={Platform.OS == "android"}
>
<View
style={{
backgroundColor: "#0099CC",
borderTopRadius: 5,
borderColor: "dark",
borderWidth: 1,
height: "100%",
}}
>
<View style={{ height: 26, width: "100%", backgroundColor: "#0099CC" }}>
<View
style={{
height: 6,
width: 45,
borderRadius: 100,
backgroundColor: "#f0f0f0",
marginVertical: 10,
alignSelf: "center",
}}
/>
</View>
<View
style={{ padding: 10, flexDirection: "row", alignItems: "center" }}
>
<MaterialCommunityIcons
name="web"
style={{ padding: 5 }}
color="white"
size={30}
/>
<Text style={{ fontSize: 30, fontWeight: "bold", color: "white" }}>
JR四国公式SNS一族
</Text>
</View>
<ScrollView
style={{
padding: 10,
backgroundColor: "white",
borderBottomLeftRadius: 10,
borderBottomRightRadius: 10,
flex:1
}}
>
{[
{
url: "https://twitter.com/jr_shikoku_info",
name: "JR四国列車運行情報",
},
{
url: "https://twitter.com/JRshikoku_eigyo",
name: "JR四国営業部【公式】",
},
{
url: "https://twitter.com/JRshikoku_tokyo",
name: "JR四国 東京営業情報【公式】",
},
{
url: "https://twitter.com/JRshikoku_osaka",
name: "JR四国 大阪営業部【公式】",
},
{
url: "https://twitter.com/jrs_matsuyama",
name: "JR四国 松山駅 【公式】",
},
{
url: "https://twitter.com/jrshikoku_kochi",
name: "JR四国 高知駅【公式】",
},
{
url: "https://twitter.com/jr_tokust",
name: "JR四国 徳島駅【公式】",
},
{
url: "https://twitter.com/jrshikoku_uwjm",
name: "JR四国 宇和島駅【公式】",
},
{
url: "https://twitter.com/jrshikoku_wkama",
name: "JR四国 ワープ高松支店【公式】",
},
{
url: "https://twitter.com/JRshikoku_wkoch",
name: "JR四国 ワープ高知支店【公式】",
},
{
url: "https://twitter.com/Yoakemonogatari",
name: "志国土佐 時代の夜明けのものがたり【公式】",
},
{
url: "https://twitter.com/Smile_Eki_Chan",
name: "すまいるえきちゃん♡JR四国【公式】",
},
{
url: "https://twitter.com/sper_ponchan",
name: "しこくたぬきのぽんちゃん 【四国家サポーターズクラブ】",
},
].map((d) => (
<ListItem
bottomDivider
onPress={() => Linking.openURL(d.url)}
key={d.url}
friction={90} //
tension={100} // These props are passed to the parent component (here TouchableScale)
activeScale={0.95} //
Component={TouchableScale}
>
<ListItem.Content>
<ListItem.Title>{d.name}</ListItem.Title>
</ListItem.Content>
<ListItem.Chevron />
</ListItem>
))}
</ScrollView>
</View>
</ActionSheet>
);
};

View File

@@ -0,0 +1,55 @@
import React, { FC, useRef } from "react";
import { View, Platform } from "react-native";
import ActionSheet from "react-native-actions-sheet";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { SpecialTrainInfoBox } from "../Menu/SpecialTrainInfoBox";
type props = {
payload: { navigate: (screen: string, params?: object) => void };
};
export const SpecialTrainInfo: FC<props> = ({ payload }) => {
const { navigate } = payload;
const actionSheetRef = useRef(null);
const insets = useSafeAreaInsets();
return (
<ActionSheet
gestureEnabled
CustomHeaderComponent={<></>}
ref={actionSheetRef}
isModal={Platform.OS == "ios"}
containerStyle={
Platform.OS == "android"
? {
paddingBottom: insets.bottom,
}
: {}
}
useBottomSafeAreaPadding={Platform.OS == "android"}
>
<View
style={{
backgroundColor: "#0099CC",
borderTopRadius: 5,
borderColor: "dark",
borderWidth: 1,
}}
>
<View style={{ height: 26, width: "100%", backgroundColor: "#0099CC" }}>
<View
style={{
height: 6,
width: 45,
borderRadius: 100,
backgroundColor: "#f0f0f0",
marginVertical: 10,
alignSelf: "center",
}}
/>
</View>
<SpecialTrainInfoBox navigate={navigate} />
</View>
</ActionSheet>
);
};

View File

@@ -2,45 +2,44 @@ import React, { useState, useEffect } from "react";
import {
View,
Linking,
Text,
TouchableOpacity,
BackHandler,
Platform,
useWindowDimensions,
} from "react-native";
import AutoHeightImage from "react-native-auto-height-image";
import { FontAwesome, Foundation, Ionicons } from "@expo/vector-icons";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import ActionSheet, { SheetManager } from "react-native-actions-sheet";
import Sign from "../../components/駅名表/Sign";
import { TicketBox } from "../atom/TicketBox";
import { widthPercentageToDP as wp } from "react-native-responsive-screen";
import { getPDFViewURL } from "../../lib/getPdfViewURL";
import { useBusAndTrainData } from "../../stateBox/useBusAndTrainData";
import { AS } from "../../storageControl";
import { StationMapButton } from "./StationDeteilView/StationMapButton";
import { TrainBusButton } from "./StationDeteilView/TrainBusButton";
import { 駅構内図 } from "./StationDeteilView/StationInsideMapButton";
import { WebSiteButton } from "./StationDeteilView/WebSiteButton";
import { StationTimeTableButton } from "./StationDeteilView/StationTimeTableButton";
import { StationTrainPositionButton } from "./StationDeteilView/StationTrainPositionButton";
import { StationDiagramButton } from "./StationDeteilView/StationDiagramButton";
import { useTrainMenu } from "@/stateBox/useTrainMenu";
export const StationDeteilView = (props) => {
if (!props.payload) return <></>;
const {
currentStation,
navigate,
onExit,
goTo,
useShow,
} = props.payload;
const { currentStation, navigate, onExit, goTo, useShow } = props.payload;
const { width } = useWindowDimensions();
const { busAndTrainData } = useBusAndTrainData();
const [trainBus, setTrainBus] = useState();
const { updatePermission } = useTrainMenu();
useEffect(() => {
if (!currentStation) return () => {};
const data = busAndTrainData.filter((d) => {
return d.name === currentStation[0].Station_JP;
});
const data = busAndTrainData.filter(
(d) => d.name === currentStation[0].Station_JP
);
if (data.length == 0) {
setTrainBus();
}
setTrainBus(data[0]);
}, [currentStation]);
}, [currentStation, busAndTrainData]);
const [usePDFView, setUsePDFView] = useState(undefined);
useEffect(() => {
@@ -90,129 +89,89 @@ export const StationDeteilView = (props) => {
</View>
<View>
{currentStation && (
<View
style={{
margin: 10,
marginHorizontal: wp("10%"),
}}
>
<Sign
currentStation={currentStation}
oP={() => {
usePDFView == "true"
? Linking.openURL(currentStation[0].StationTimeTable)
: navigate("howto", {
info,
goTo,
useShow,
});
onExit();
}}
oLP={() => Linking.openURL(currentStation[0].StationTimeTable)}
/>
</View>
)}
{currentStation &&
currentStation[0].JrHpUrl &&
currentStation[0].StationNumber != "M12" && (
<駅構内図 //高松/阿波池田&後免&須崎kounai.png児島例外/
oP={() => {
navigate("howto", {
info:
currentStation[0].JrHpUrl.replace("/index.html", "/") +
"/kounai_map.html",
goTo,
useShow,
});
onExit();
}}
oLP={() => {
Linking.openURL(
currentStation[0].JrHpUrl.replace("/index.html", "/") +
"/kounai_map.html"
);
}}
uri={currentStation[0].JrHpUrl.replace("/index.html", "/")}
/>
)}
{currentStation && (
<View style={{ flexDirection: "row" }}>
{!currentStation[0].JrHpUrl || (
<TicketBox
backgroundColor={"#AD7FA8"}
icon={<Foundation name="web" color="white" size={50} />}
flex={1}
onPressButton={() => {
navigate("howto", {
info: currentStation[0].JrHpUrl,
goTo,
useShow,
});
onExit();
}}
onLongPressButton={() =>
Linking.openURL(currentStation[0].JrHpUrl)
}
>
web
</TicketBox>
)}
{!currentStation[0].StationTimeTable || (
<TicketBox
backgroundColor={"#8F5902"}
icon={<FontAwesome name="table" color="white" size={50} />}
flex={1}
onPressButton={() => {
<>
<View style={{ margin: 10, marginHorizontal: width * 0.1 }}>
<Sign
stationID={currentStation[0].StationNumber}
oP={() => {
usePDFView == "true"
? Linking.openURL(currentStation[0].StationTimeTable)
: navigate("howto", {
info,
goTo,
useShow,
});
onExit();
}}
onLongPressButton={() =>
oLP={() =>
Linking.openURL(currentStation[0].StationTimeTable)
}
>
時刻表
</TicketBox>
)}
{!currentStation[0].StationMap || (
<TicketBox
backgroundColor={"#888A85"}
icon={<Ionicons name="map" color="white" size={50} />}
flex={1}
onPressButton={() =>
Linking.openURL(currentStation[0].StationMap)
/>
</View>
<View style={{ flexDirection: "row" }}>
<StationTrainPositionButton
stationNumber={currentStation[0].StationNumber}
onExit={onExit}
navigate={navigate}
/>
{currentStation[0].JrHpUrl &&
currentStation[0].StationNumber != "M12" && (
<駅構内図 //児島例外/
navigate={navigate}
goTo={goTo}
useShow={useShow}
address={currentStation[0].JrHpUrl}
onExit={onExit}
/>
)}
</View>
<View style={{ flexDirection: "row" }}>
{!currentStation[0].JrHpUrl || (
<WebSiteButton
navigate={navigate}
info={currentStation[0].JrHpUrl}
goTo={goTo}
useShow={useShow}
onExit={onExit}
/>
)}
{updatePermission &&<StationDiagramButton
navigate={navigate}
onExit={onExit}
currentStation={currentStation}
/>}
{!currentStation[0].StationTimeTable || (
<StationTimeTableButton
info={info}
address={currentStation[0].StationTimeTable}
usePDFView={usePDFView}
navigate={navigate}
onExit={onExit}
goTo={goTo}
useShow={useShow}
/>
)}
<StationMapButton
stationMap={
currentStation[0].StationMap ||
`https://www.google.co.jp/maps/place/${currentStation[0].lat},${currentStation[0].lng}`
}
>
Map
</TicketBox>
)}
{!trainBus || (
<TicketBox
backgroundColor={"#CE5C00"}
icon={<Ionicons name="bus" color="white" size={50} />}
flex={1}
onPressButton={() => {
navigate("howto", {
info: trainBus.address,
goTo,
useShow,
});
onExit();
}}
onLongPressButton={() => Linking.openURL(trainBus.address)}
>
並行バス
</TicketBox>
)}
</View>
/>
{!trainBus || (
<TrainBusButton
address={trainBus.address}
press={() => {
navigate("howto", {
info: trainBus.address,
goTo,
useShow,
});
onExit();
}}
/>
)}
</View>
</>
)}
</View>
</View>
@@ -220,67 +179,6 @@ export const StationDeteilView = (props) => {
);
};
const 駅構内図 = (props) => {
const [open, setOpen] = useState(false);
return (
<>
<TouchableOpacity
style={{
height: 50,
backgroundColor: "#888A85",
flexDirection: "column",
alignContent: "center",
alignItems: "center",
margin: 2,
}}
onPress={props.oP}
onLongPress={props.oLP}
//onPress={() => setOpen(!open)}
>
<View style={{ flex: 1 }} />
<Text
style={{
color: "white",
textAlign: "center",
textAlignVertical: "center",
flex: 1,
}}
>
{open ? "駅構内図を非表示" : "駅構内図を表示"}
</Text>
<View style={{ flex: 1 }} />
</TouchableOpacity>
<View>
{open && (
<>
<AutoHeightImage
source={{ uri: props.uri + "images/kounai.gif" }}
resizeMode="contain"
width={wp("100%")}
/>
<AutoHeightImage
source={{ uri: props.uri + "images/kounai.png" }}
resizeMode="contain"
width={wp("100%")}
/>
<AutoHeightImage
source={{ uri: props.uri + "images/kounai_1f.gif" }}
resizeMode="contain"
width={wp("100%")}
/>
<AutoHeightImage
source={{ uri: props.uri + "images/kounai_2f.png" }}
resizeMode="contain"
width={wp("100%")}
/>
</>
)}
</View>
</>
);
};
const Handler = () => {
useEffect(() => {
const backAction = () => {
@@ -294,4 +192,4 @@ const Handler = () => {
return () => backHandler.remove();
}, []);
return <></>;
};
};

View File

@@ -0,0 +1,40 @@
import React, { FC } from "react";
import { Linking } from "react-native";
import { FontAwesome } from "@expo/vector-icons";
import { TicketBox } from "@/components/atom/TicketBox";
type Props = {
navigate: (screen: string, params?: object) => void;
onExit: () => void;
currentStation: {
Station_JP: string;
Station_EN: string;
StationName?: string;
MyStation?: string;
StationNumber: string;
DispNum?: string;
StationTimeTable: string;
StationMap?: string;
JrHpUrl?: string;
lat: number;
lng: number;
jslodApi: string;
}[];
};
export const StationDiagramButton: FC<Props> = (props) => {
const { navigate, onExit, currentStation } = props;
return (
<TicketBox
backgroundColor={"#8F5902"}
icon={<FontAwesome name="table" color="white" size={50} />}
flex={1}
onPressButton={() => {
navigate("stDiagram", {
currentStation,
});
onExit();
}}
>
v2
</TicketBox>
);
};

View File

@@ -0,0 +1,44 @@
import { FC } from "react";
import { TouchableOpacity, View, Text, Linking } from "react-native";
type Props = {
navigate: (screen: string, params: { info: string; goTo: string; useShow: boolean }) => void;
address: string;
goTo: string;
useShow: boolean;
onExit: () => void;
};
export const 駅構内図:FC<Props> = (props) => {
const { navigate, address, goTo, useShow, onExit } = props;
const info = address.replace("/index.html", "/") + "/kounai_map.html";
return (
<TouchableOpacity
style={{
height: 50,
backgroundColor: "#888A85",
flexDirection: "column",
alignContent: "center",
alignItems: "center",
margin: 2,
flex: 1,
}}
onPress={() => {
navigate("howto", { info, goTo, useShow });
onExit();
}}
onLongPress={() => Linking.openURL(info)}
>
<View style={{ flex: 1 }} />
<Text
style={{
color: "white",
textAlign: "center",
textAlignVertical: "center",
flex: 1,
}}
>
</Text>
<View style={{ flex: 1 }} />
</TouchableOpacity>
);
};

View File

@@ -0,0 +1,16 @@
import React from "react";
import { Linking } from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { TicketBox } from "@/components/atom/TicketBox";
export const StationMapButton = ({stationMap}) => {
return (
<TicketBox
backgroundColor={"#888A85"}
icon={<Ionicons name="map" color="white" size={50} />}
flex={1}
onPressButton={() => Linking.openURL(stationMap)}
>
Map
</TicketBox>
);
};

View File

@@ -0,0 +1,32 @@
import React, { FC } from "react";
import { Linking } from "react-native";
import { FontAwesome } from "@expo/vector-icons";
import { TicketBox } from "@/components/atom/TicketBox";
type Props = {
info: string;
address: string;
usePDFView: string;
navigate: (screen: string, params?: object) => void;
onExit: () => void;
goTo: string;
useShow: string;
};
export const StationTimeTableButton: FC<Props> = (props) => {
const { info, address, usePDFView, navigate, onExit, goTo, useShow } = props;
return (
<TicketBox
backgroundColor={"#8F5902"}
icon={<FontAwesome name="table" color="white" size={50} />}
flex={1}
onPressButton={() => {
usePDFView == "true"
? Linking.openURL(address)
: navigate("howto", { info, goTo, useShow });
onExit();
}}
onLongPressButton={() => Linking.openURL(address)}
>
</TicketBox>
);
};

View File

@@ -0,0 +1,54 @@
import { FC } from "react";
import { TouchableOpacity, View, Text, Linking } from "react-native";
import { useCurrentTrain } from "@/stateBox/useCurrentTrain";
import AntDesign from "react-native-vector-icons/AntDesign";
type Props = {
stationNumber: string;
onExit: () => void;
navigate?: (screen: string, params: { screen: string }) => void;
};
export const StationTrainPositionButton: FC<Props> = (props) => {
const { stationNumber, onExit, navigate } = props;
const { setInjectData } = useCurrentTrain();
return (
<TouchableOpacity
style={{
height: 50,
backgroundColor: "#0099CC",
flexDirection: "row",
alignContent: "center",
alignItems: "center",
margin: 2,
flex: 1,
}}
onLongPress={() => {
navigate("positions", { screen: "Apps" });
setInjectData({ type: "station", value:stationNumber, fixed: true });
onExit();
}}
onPress={() => {
navigate("positions", { screen: "Apps" });
setInjectData({ type: "station", value: stationNumber, fixed: false });
onExit();
}}
>
<View style={{ flex: 1 }} />
<AntDesign
name={"barchart"}
size={20}
color={"white"}
style={{ marginHorizontal: 5, marginVertical: 5 }}
/>
<Text
style={{
color: "white",
textAlign: "center",
textAlignVertical: "center",
}}
>
</Text>
<View style={{ flex: 1 }} />
</TouchableOpacity>
);
};

View File

@@ -0,0 +1,21 @@
import React, { FC } from "react";
import { Linking } from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { TicketBox } from "@/components/atom/TicketBox";
type Props = {
address: string;
press: () => void;
};
export const TrainBusButton: FC<Props> = ({ address, press }) => {
return (
<TicketBox
backgroundColor={"#CE5C00"}
icon={<Ionicons name="bus" color="white" size={50} />}
flex={1}
onPressButton={press}
onLongPressButton={() => Linking.openURL(address)}
>
</TicketBox>
);
};

View File

@@ -0,0 +1,28 @@
import React, { FC } from "react";
import { Linking } from "react-native";
import { Foundation } from "@expo/vector-icons";
import { TicketBox } from "@/components/atom/TicketBox";
type Props = {
navigate: (screen: string, params: any) => void;
info: string;
goTo: string;
useShow: string;
onExit: () => void;
};
export const WebSiteButton: FC<Props> = (Props) => {
const { navigate, info, goTo, useShow, onExit } = Props;
return (
<TicketBox
backgroundColor={"#AD7FA8"}
icon={<Foundation name="web" color="white" size={50} />}
flex={1}
onPressButton={() => {
navigate("howto", { info, goTo, useShow });
onExit();
}}
onLongPressButton={() => Linking.openURL(info)}
>
web
</TicketBox>
);
};

View File

@@ -11,8 +11,7 @@ import { useSafeAreaInsets } from "react-native-safe-area-context";
import { useTrainMenu } from "../../stateBox/useTrainMenu";
import { useCurrentTrain } from "../../stateBox/useCurrentTrain";
import lineColorList from "../../assets/originData/lineColorList";
import { stationIDPair } from "../../lib/getStationList2";
import { lineListPair } from "../../lib/getStationList";
import { stationIDPair, lineListPair } from "../../lib/getStationList";
export const TrainMenuLineSelector = () => {
const {
@@ -20,7 +19,7 @@ export const TrainMenuLineSelector = () => {
setSelectedLine,
mapsStationData: stationData,
} = useTrainMenu();
const { webview } = useCurrentTrain();
const { webview } = useCurrentTrain();
const actionSheetRef = useRef(null);
const insets = useSafeAreaInsets();
const platformIs = Platform.OS == "android";
@@ -55,7 +54,7 @@ export const TrainMenuLineSelector = () => {
onPress={() => {
SheetManager.hide("TrainMenuLineSelector");
const s = selectedLine == d ? undefined : d;
if(!s) return;
if (!s) return;
setSelectedLine(s);
Object.keys(stationData).forEach((data, indexBase) => {
stationData[data].forEach((D, index) => {
@@ -66,7 +65,7 @@ export const TrainMenuLineSelector = () => {
""
).split(",");
if (latlng.length == 0) return null;
if (index == 0 ) {
if (index == 0) {
webview.current
?.injectJavaScript(`MoveDisplayStation('${data}_${D.MyStation}_${D.Station_JP}');
document.getElementById("disp").insertAdjacentHTML("afterbegin", "<div />");`);
@@ -74,6 +73,7 @@ export const TrainMenuLineSelector = () => {
});
});
}}
key={d+"TrainMenuLineSelector"}
>
<View
style={{

View File

@@ -4,11 +4,15 @@ import { JRSTraInfo } from "./JRSTraInfo";
import { StationDeteilView } from "./StationDeteilView";
import { TrainMenuLineSelector } from "./TrainMenuLineSelector";
import { TrainIconUpdate } from "./TrainIconUpdate";
import { SpecialTrainInfo } from "./SpecialTrainInfo";
import { Social } from "./SocialMenu";
registerSheet("EachTrainInfo", EachTrainInfo);
registerSheet("JRSTraInfo", JRSTraInfo);
registerSheet("StationDetailView", StationDeteilView);
registerSheet("TrainMenuLineSelector", TrainMenuLineSelector);
registerSheet("TrainIconUpdate", TrainIconUpdate);
registerSheet("SpecialTrainInfo", SpecialTrainInfo);
registerSheet("Social", Social);
export {};

View File

@@ -10,6 +10,7 @@ import {
Keyboard,
ScrollView,
Linking,
Image,
} from "react-native";
import { useAllTrainDiagram } from "../stateBox/useAllTrainDiagram";
@@ -19,9 +20,12 @@ import { SheetManager } from "react-native-actions-sheet";
import { useNavigation } from "@react-navigation/native";
import { BigButton } from "./atom/BigButton";
import { Switch } from "react-native-elements";
import { migrateTrainName } from "@/lib/eachTrainInfoCoreLib/migrateTrainName";
import { OneManText } from "./ActionSheetComponents/EachTrainInfoCore/HeaderTextParts/OneManText";
import { getStringConfig } from "@/lib/getStringConfig";
export default function AllTrainDiagramView() {
const { goBack, navigate } = useNavigation();
const { keyList, allTrainDiagram } = useAllTrainDiagram();
const { keyList, allTrainDiagram, allCustomTrainData } = useAllTrainDiagram();
const [input, setInput] = useState(""); // 文字入力
const [keyBoardVisible, setKeyBoardVisible] = useState(false);
const [useStationName, setUseStationName] = useState(false);
@@ -53,14 +57,14 @@ export default function AllTrainDiagramView() {
}, []);
const openTrainInfo = (d) => {
const train = customTrainDataDetector(d);
const train = customTrainDataDetector(d, allCustomTrainData);
let TrainNumber = "";
if (train.trainNumDistance != undefined) {
const timeInfo =
parseInt(d.replace("M", "").replace("D", "")) - train.trainNumDistance;
TrainNumber = timeInfo + "号";
}
const type = getTrainType(train.type).data;
const type = getTrainType({type:train.type}).data;
const limited = `${type}:${train.trainName}${TrainNumber}`;
const payload = {
data: { trainNum: d, limited },
@@ -71,16 +75,96 @@ export default function AllTrainDiagramView() {
payload,
});
};
const Item = ({ id, openTrainInfo }) => {
const { img, trainName, type, trainNumDistance, infogram } =
customTrainDataDetector(id, allCustomTrainData);
const [typeString, fontAvailable, isOneMan] = getStringConfig(type, id);
const trainNameString = (() => {
switch (true) {
case trainName !== "":
// 特急の場合は、列車名を取得
// 列番対称データがある場合はそれから列車番号を取得
const distance = trainNumDistance;
const number =
distance !== null ? ` ${parseInt(id) - distance}` : "";
return trainName + number;
case allTrainDiagram[id] === undefined:
return "";
default:
// 行先がある場合は、行先を取得
const s = allTrainDiagram[id].split("#");
const hoge = s[s.length - 2].split(",")[0];
return migrateTrainName(hoge + "行き");
}
})();
return (
<TouchableOpacity
style={{
padding: 5,
flexDirection: "row",
borderColor: "white",
borderWidth: 1,
margin: 5,
borderRadius: 5,
alignItems: "center",
}}
onPress={() => openTrainInfo(id)}
>
{img && (
<Image
source={{ uri: img }}
style={{ width: 20, height: 20, marginLeft: 10, marginRight: 10 }}
/>
)}
{typeString && (
<Text
style={{
fontSize: 20,
color: "white",
fontFamily: fontAvailable ? "JR-Nishi" : undefined,
fontWeight: !fontAvailable ? "bold" : undefined,
marginRight: 5,
}}
>
{typeString}
</Text>
)}
{isOneMan && <OneManText />}
{trainNameString && (
<Text style={{ fontSize: 20, fontWeight: "bold", color: "white" }}>
{trainNameString}
</Text>
)}
<View style={{ flex: 1 }} />
<Text style={{ fontSize: 20, fontWeight: "bold", color: "white" }}>
{id}
</Text>
</TouchableOpacity>
);
};
return (
<View style={{ backgroundColor: "#0099CC", height: "100%" }}>
<FlatList
contentContainerStyle={{ justifyContent: "flex-end", flexGrow: 1 }}
style={{ flex: 1 }}
data={keyList?.filter((d) => {
if (useStationName) {
const ls = input.split(",").map((stationName) => {
return allTrainDiagram[d].includes(stationName);
const EachStopInfo = allTrainDiagram[d].split("#");
const ls = input.split(",").map((inputStationValue) => {
const isHit = EachStopInfo.find((dx) => {
if (!dx) return undefined;
const returnData = dx.split(",")[0] == inputStationValue;
if (returnData) {
const isThrew = dx.split(",")[1].includes("通");
if (isThrew) return undefined;
}
return returnData;
});
return isHit;
});
return !ls.includes(false);
return !ls.includes(undefined);
}
if (useRegex) {
try {
@@ -90,9 +174,17 @@ export default function AllTrainDiagramView() {
return false;
}
}
return d.includes(input);
const { img, trainName, type, trainNumDistance, infogram, TrainNumberOverride } = customTrainDataDetector(d, allCustomTrainData);
return d.includes(input) || trainName.includes(input) || (TrainNumberOverride && TrainNumberOverride.includes(input));
})}
renderItem={({ item }) => <Item {...{ openTrainInfo, id: item }} />}
ListEmptyComponent={
<View style={{ flex: 1, alignItems: "center", marginTop: 50 }}>
<Text style={{ color: "white", fontSize: 20 }}>
検索結果がありません
</Text>
</View>
}
keyExtractor={(item) => item}
//initialNumToRender={100}
/>
@@ -196,7 +288,7 @@ export default function AllTrainDiagramView() {
}}
>
<TextInput
placeholder="列番を入力してフィルタリングします。"
placeholder="列番・列車名を入力してフィルタリングします。"
onFocus={() => setKeyBoardVisible(true)}
onEndEditing={() => {}}
onChange={(ret) => setInput(ret.nativeEvent.text)}
@@ -216,25 +308,3 @@ export default function AllTrainDiagramView() {
</View>
);
}
const Item = ({ id, openTrainInfo }) => {
return (
<TouchableOpacity
style={{
padding: 5,
flexDirection: "row",
borderColor: "white",
borderWidth: 1,
margin: 5,
borderRadius: 5,
alignItems: "center",
}}
onPress={() => openTrainInfo(id)}
>
<View style={{ flex: 1 }} />
<Text style={{ fontSize: 25, fontWeight: "bold", color: "white" }}>
{id}
</Text>
<View style={{ flex: 1 }} />
</TouchableOpacity>
);
};

View File

@@ -11,7 +11,7 @@ export const getDelayData = async () => {
// Fetch data from the server
const time = dayjs().format("HH:mm");
const delayString = await fetch(
"https://script.google.com/macros/s/AKfycbyKxch7z7l8e07LXulRHqxjVoIiB13kcgvoToLE-rqlxLmLSKdlmqz0FI1F2EuA7Zfg/exec"
"https://script.google.com/macros/s/AKfycbw-0RDLAu8EQAEWA860tk4KVW6VOr3iIU900AcWEfqIP16gtNUG1XO_A3oBfAGiNeCf/exec"
)
.then((response) => response.text())
.then((data) => {

View File

@@ -4,6 +4,7 @@ import {
Platform,
useWindowDimensions,
LayoutAnimation,
Text,
} from "react-native";
import Constants from "expo-constants";
import * as Updates from "expo-updates";
@@ -23,6 +24,7 @@ import { MapsButton } from "./Apps/MapsButton";
import { ReloadButton } from "./Apps/ReloadButton";
import { LandscapeBackButton } from "./Apps/LandscapeBackButton";
import { useStationList } from "../stateBox/useStationList";
import { FixedPositionBox } from "./Apps/FixedPositionBox";
/*
import StatusbarDetect from '../StatusbarDetect';
var Status = StatusbarDetect(); */
@@ -30,14 +32,13 @@ var Status = StatusbarDetect(); */
const top = Platform.OS == "ios" ? Constants.statusBarHeight : 0;
export default function Apps() {
const { webview } = useCurrentTrain();
const { webview, fixedPosition, setFixedPosition } = useCurrentTrain();
const { height, width } = useWindowDimensions();
const { navigate } = useNavigation();
const { isLandscape } = useDeviceOrientationChange();
const handleLayout = () => {};
const { originalStationList } = useStationList();
const { setInjectJavaScript, mapSwitch, trainInfo, setTrainInfo } =
useTrainMenu();
const { mapSwitch, trainInfo, setTrainInfo } = useTrainMenu();
const openStationACFromEachTrainInfo = async (stationName) => {
await SheetManager.hide("EachTrainInfo");
@@ -60,7 +61,7 @@ export default function Apps() {
useShow: () => SheetManager.show("StationDetailView", { payload }),
onExit: () => SheetManager.hide("StationDetailView"),
};
setTimeout(()=>SheetManager.show("StationDetailView", { payload }),50);
setTimeout(() => SheetManager.show("StationDetailView", { payload }), 50);
} else {
SheetManager.hide("StationDetailView");
}
@@ -110,7 +111,6 @@ export default function Apps() {
{isLandscape || (
<MapsButton
onPress={() => {
setInjectJavaScript("");
navigate("trainMenu", { webview });
}}
/>
@@ -127,6 +127,10 @@ export default function Apps() {
}}
/>
)}
{fixedPosition.type && (
<FixedPositionBox />
)}
{mapSwitch == "true" ? (
<ReloadButton
onPress={() => Updates.reloadAsync()}

View File

@@ -0,0 +1,45 @@
import { useCurrentTrain } from "@/stateBox/useCurrentTrain";
import { View, Platform } from "react-native";
import { useKeepAwake } from "expo-keep-awake";
import Constants from "expo-constants";
import { FixedTrain } from "./FixedPositionBox/FixedTrainBox";
import { FixedStation } from "./FixedPositionBox/FixedStationBox";
import { useState } from "react";
import { useTrainMenu } from "@/stateBox/useTrainMenu";
export const FixedPositionBox = () => {
const { mapSwitch } = useTrainMenu();
const { fixedPosition } = useCurrentTrain();
const [displaySize, setDisplaySize] = useState(mapSwitch == "true" ? 76 : 80);
useKeepAwake();
return (
<View
style={{
position: "absolute",
top: Platform.OS == "ios" ? Constants.statusBarHeight : 0,
borderRadius: 5,
zIndex: 1500,
width: "100%",
height: displaySize,
flexDirection: "row",
}}
pointerEvents="box-none"
>
{fixedPosition.type === "station" && (
<FixedStation
stationID={fixedPosition.value}
displaySize={displaySize}
setDisplaySize={setDisplaySize}
/>
)}
{fixedPosition.type === "train" && (
<FixedTrain
trainID={fixedPosition.value}
displaySize={displaySize}
setDisplaySize={setDisplaySize}
/>
)}
</View>
);
};

View File

@@ -0,0 +1,381 @@
import lineColorList from "@/assets/originData/lineColorList";
import { StationNumberMaker } from "@/components/駅名表/StationNumberMaker";
import { checkDuplicateTrainData } from "@/lib/checkDuplicateTrainData";
import {
CustomTrainData,
eachTrainDiagramType,
StationProps,
} from "@/lib/CommonTypes";
import { getCurrentTrainData } from "@/lib/getCurrentTrainData";
import { getTrainDelayStatus } from "@/lib/getTrainDelayStatus";
import { getTrainType } from "@/lib/getTrainType";
import { objectIsEmpty } from "@/lib/objectIsEmpty";
import { getTime, trainTimeFiltering } from "@/lib/trainTimeFiltering";
import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram";
import { useAreaInfo } from "@/stateBox/useAreaInfo";
import { useCurrentTrain } from "@/stateBox/useCurrentTrain";
import { useStationList } from "@/stateBox/useStationList";
import { useTrainMenu } from "@/stateBox/useTrainMenu";
import { Ionicons } from "@expo/vector-icons";
import { useNavigation } from "@react-navigation/native";
import { FC, useEffect, useState } from "react";
import { LayoutAnimation, Text, TouchableOpacity, View } from "react-native";
import { SheetManager } from "react-native-actions-sheet";
type props = {
stationID: string;
displaySize: number;
setDisplaySize: (size: number) => void;
};
export const FixedStation: FC<props> = ({
stationID,
displaySize,
setDisplaySize,
}) => {
const { mapSwitch } = useTrainMenu();
const { currentTrain, setFixedPosition } = useCurrentTrain();
const { getStationDataFromId } = useStationList();
const { navigate } = useNavigation();
const [station, setStation] = useState<StationProps[]>([]);
useEffect(() => {
const data = getStationDataFromId(stationID);
setStation(data);
}, [stationID]);
const lineColor =
station.length > 0
? lineColorList[station[0]?.StationNumber.slice(0, 1)]
: "white";
////
const { allTrainDiagram } = useAllTrainDiagram();
const { areaStationID } = useAreaInfo();
const [stationDiagram, setStationDiagram] = useState({}); //当該駅の全時刻表
const [isInfoArea, setIsInfoArea] = useState(false);
useEffect(() => {
// 現在の駅に停車するダイヤを作成する副作用[列車ダイヤと現在駅情報]
if (!allTrainDiagram) {
setStationDiagram({});
return;
}
if (station.length == 0) {
setStationDiagram({});
return;
}
let returnData = {};
Object.keys(allTrainDiagram).forEach((key) => {
if (allTrainDiagram[key].match(station[0].Station_JP + ",")) {
returnData[key] = allTrainDiagram[key];
}
});
setStationDiagram(returnData);
setIsInfoArea(station.some((s) => areaStationID.includes(s.StationNumber)));
}, [allTrainDiagram, station]);
const [trainTimeAndNumber, setTrainTimeAndNumber] = useState<
eachTrainDiagramType[]
>([]);
useEffect(() => {
//現在の駅に停車する列車から時刻を切り出してLEDベースにフォーマット
if (objectIsEmpty(stationDiagram)) return () => {};
const getTimeData = getTime(stationDiagram, station[0]);
setTrainTimeAndNumber(getTimeData);
}, [stationDiagram]);
const [selectedTrain, setSelectedTrain] = useState<eachTrainDiagramType[]>(
[]
);
useEffect(() => {
if (!trainTimeAndNumber) return () => {};
if (!currentTrain) return () => {};
const data = trainTimeAndNumber
.filter((d) => currentTrain.map((m) => m.num).includes(d.train)) //現在の列車に絞る[ToDo]
.filter((d) => trainTimeFiltering({ d, currentTrain, station })) //時間フィルター
.filter((d) => !d.isThrough)
.filter((d) => d.lastStation != station[0].Station_JP); //最終列車表示設定
setSelectedTrain(data);
}, [trainTimeAndNumber, currentTrain /*finalSwitch*/]);
return (
<View
style={{ display: "flex", flexDirection: "column", flex: 1 }}
pointerEvents="box-none"
>
<TouchableOpacity
style={{
flex: 1,
flexDirection: "row",
borderBottomColor: lineColor,
borderBottomWidth: 2,
position: "relative",
}}
activeOpacity={1}
onPress={() => {
const payload = {
currentStation: station,
navigate,
goTo: "menu",
onExit: () => SheetManager.hide("StationDetailView"),
};
//@ts-ignore
SheetManager.show("StationDetailView", { payload });
}}
>
<View
style={{
flex: 3,
flexDirection: "column",
alignContent: "center",
alignSelf: "center",
alignItems: "center",
height: "100%",
backgroundColor: "white",
}}
>
<View
style={{
backgroundColor: lineColor,
flexDirection: "row",
width: "100%",
alignContent: "center",
alignItems: "center",
height: 22,
overflow: "hidden",
paddingLeft: 5,
}}
>
<StationNumberMaker
currentStation={station}
singleSize={18}
useEach={true}
/>
<Text
style={{
fontSize: 14,
textAlignVertical: "center",
margin: 0,
padding: 0,
paddingLeft: 5,
flex: 1,
color: "white",
}}
>
{station[0]?.Station_JP}
</Text>
<View
style={{
backgroundColor: "white",
width: 6,
borderLeftColor: lineColor,
borderTopColor: lineColor,
borderBottomColor: "white",
borderRightColor: "white",
borderBottomWidth: 18,
borderLeftWidth: 10,
borderRightWidth: 0,
borderTopWidth: 5,
height: 20,
}}
/>
</View>
<View
style={{
height: "100%",
backgroundColor: "white",
flex: 1,
}}
>
<Text style={{ fontSize: 18 }}></Text>
</View>
</View>
<View
style={{
flex: 5,
flexDirection: "column",
backgroundColor: "white",
borderTopWidth: 5,
borderTopColor: lineColor,
overflow: "hidden",
}}
>
{selectedTrain.length > 0 ? (
selectedTrain.map((d) => (
<FixedStationBoxEachTrain
d={d}
station={station[0]}
displaySize={displaySize}
key={d.train + "-fixedStationBox"}
/>
))
) : (
<View style={{ backgroundColor: "white", flex: 1 }}>
<Text style={{ fontSize: parseInt("11%") }}>
</Text>
</View>
)}
</View>
</TouchableOpacity>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
borderTopColor: lineColor,
borderTopWidth: 2,
}}
pointerEvents="box-none"
>
<TouchableOpacity
style={{
flexDirection: "row",
alignItems: "center",
}}
onPress={() => {
setFixedPosition({ type: null, value: null });
}}
>
<View
style={{
flexDirection: "row",
alignItems: "center",
backgroundColor: lineColor,
paddingHorizontal: 5,
height: 26,
}}
>
<Ionicons name="lock-closed" size={15} color="white" />
<Text
style={{
color: "white",
fontSize: 15,
paddingRight: 5,
}}
>
</Text>
<Ionicons name="close" size={15} color="white" />
</View>
<View
style={{
backgroundColor: "#0000",
width: 6,
borderLeftColor: lineColor,
borderTopColor: lineColor,
borderBottomColor: "#0000",
borderRightColor: "#0000",
borderBottomWidth: 26,
borderLeftWidth: 10,
borderRightWidth: 0,
borderTopWidth: 0,
height: 26,
}}
/>
</TouchableOpacity>
<TouchableOpacity
style={{
flexDirection: "row",
alignItems: "center",
}}
onPress={() => {
LayoutAnimation.configureNext({
duration: 500,
update: { type: "spring", springDamping: 0.7 },
});
if (displaySize === 226) {
setDisplaySize(mapSwitch == "true" ? 76 : 80);
} else {
setDisplaySize(226);
}
}}
>
<View
style={{
backgroundColor: "#0000",
width: 6,
borderLeftColor: "#0000",
borderTopColor: lineColor,
borderBottomColor: "#0000",
borderRightColor: lineColor,
borderBottomWidth: 26,
borderLeftWidth: 0,
borderRightWidth: 10,
borderTopWidth: 0,
height: 26,
}}
/>
<View
style={{
flexDirection: "row",
alignItems: "center",
backgroundColor: lineColor,
paddingHorizontal: 5,
height: 26,
}}
pointerEvents="none"
>
<Ionicons
name={displaySize == 226 ? "chevron-up" : "chevron-down"}
size={15}
color="white"
/>
<Text
style={{
color: "white",
paddingRight: 5,
backgroundColor: lineColor,
fontSize: 15,
}}
>
{displaySize == 226 ? "時刻表を縮小する" : "時刻表を展開する"}
</Text>
</View>
</TouchableOpacity>
</View>
</View>
);
};
const FixedStationBoxEachTrain = ({ d, station, displaySize }) => {
const { currentTrain } = useCurrentTrain();
const { stationList } = useStationList();
const { allCustomTrainData } = useAllTrainDiagram();
const currentTrainData = checkDuplicateTrainData(
currentTrain.filter((a) => a.num == d.train),
stationList
);
const trainDelayStatus = `${getTrainDelayStatus(
currentTrainData,
station.Station_JP
)}`;
const [train, setTrain] = useState<CustomTrainData>(
getCurrentTrainData(d.train, currentTrain, allCustomTrainData)
);
useEffect(() => {
setTrain(getCurrentTrainData(d.train, currentTrain, allCustomTrainData));
}, [currentTrain, d.train]);
const { name, color } = getTrainType({ type: train.type, whiteMode: true });
return (
<View
style={{
backgroundColor: "white",
flexDirection: "row",
height: displaySize == 226 ? "7.5%" : "33%",
overflow: "visible",
}}
>
<Text style={{ fontSize: parseInt("11%"), flex: 3 }}>{d.time}</Text>
<Text style={{ fontSize: parseInt("11%"), flex: 4, color }}>{name}</Text>
<Text style={{ fontSize: parseInt("11%"), flex: 4 }}>
{d.lastStation}
</Text>
<Text style={{ fontSize: parseInt("11%"), flex: 3 }}>
{trainDelayStatus}
</Text>
</View>
);
};

View File

@@ -0,0 +1,847 @@
import lineColorList from "@/assets/originData/lineColorList";
import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram";
import { useCurrentTrain } from "@/stateBox/useCurrentTrain";
import { useStationList } from "@/stateBox/useStationList";
import { StationProps } from "@/lib/CommonTypes";
import { FC, useEffect, useState } from "react";
import {
Text,
TouchableOpacity,
View,
Image,
LayoutAnimation,
ScrollView,
} from "react-native";
import { getTrainType } from "@/lib/getTrainType";
import { trainDataType, trainPosition } from "@/lib/trainPositionTextArray";
import { StationNumberMaker } from "@/components/駅名表/StationNumberMaker";
import { lineListPair, stationIDPair } from "@/lib/getStationList";
import { findReversalPoints } from "@/lib/eachTrainInfoCoreLib/findReversalPoints";
import { CustomTrainData, trainTypeID } from "@/lib/CommonTypes";
import { getCurrentTrainData } from "@/lib/getCurrentTrainData";
import { Ionicons } from "@expo/vector-icons";
import dayjs from "dayjs";
import { useTrainMenu } from "@/stateBox/useTrainMenu";
type props = {
trainID: string;
displaySize: number;
setDisplaySize: (e: number) => void;
};
export const FixedTrain: FC<props> = ({
trainID,
displaySize,
setDisplaySize,
}) => {
const {
fixedPosition,
setFixedPosition,
currentTrain,
getCurrentStationData,
getPosition,
} = useCurrentTrain();
const { mapSwitch } = useTrainMenu();
const { allCustomTrainData, allTrainDiagram } = useAllTrainDiagram();
const [train, setTrain] = useState<trainDataType>(null);
const [customData, setCustomData] = useState<CustomTrainData>(
getCurrentTrainData(trainID, currentTrain, allCustomTrainData)
);
useEffect(() => {
setCustomData(
getCurrentTrainData(trainID, currentTrain, allCustomTrainData)
);
}, [currentTrain, trainID]);
useEffect(() => {
const stationData = getCurrentStationData(trainID);
if (stationData) {
setTrain(stationData);
} else {
alert("追跡していた列車が消えました。追跡を終了します。");
setFixedPosition({ type: null, value: null });
}
}, [trainID, currentTrain]);
const { getStationDataFromName, stationList, originalStationList } =
useStationList();
const [trainDataWidhThrough, setTrainDataWithThrough] = useState<string[]>(
[]
);
useEffect(() => {
const trainData = allTrainDiagram[trainID]?.split("#");
if (!trainData) return;
//let haveThrough = false;
//
const stopStationList = trainData.map((i) => {
const [station, se, time] = i.split(",");
//if (se == "通編") setHaveThrough(true);
return stationList.map((a) => a.filter((d) => d.StationName == station));
});
const allThroughStationList = stopStationList.map((i, index, array) => {
let allThroughStation = [];
if (index == array.length - 1) return;
const firstItem = array[index];
const secondItem = array[index + 1];
let betweenStationLine = "";
let baseStationNumberFirst = "";
let baseStationNumberSecond = "";
Object.keys(stationIDPair).forEach((d, index2) => {
if (!d) return;
const haveFirst = firstItem[index2];
const haveSecond = secondItem[index2];
if (haveFirst.length && haveSecond.length) {
betweenStationLine = d;
baseStationNumberFirst = haveFirst[0].StationNumber;
baseStationNumberSecond = haveSecond[0].StationNumber;
}
});
if (!betweenStationLine) return;
let reverse = false;
originalStationList[
lineListPair[stationIDPair[betweenStationLine]]
].forEach((d) => {
if (
d.StationNumber > baseStationNumberFirst &&
d.StationNumber < baseStationNumberSecond
) {
allThroughStation.push(`${d.Station_JP},通過,`);
//setHaveThrough(true);
reverse = false;
} else {
if (
d.StationNumber < baseStationNumberFirst &&
d.StationNumber > baseStationNumberSecond
) {
allThroughStation.push(`${d.Station_JP},通過,`);
//setHaveThrough(true);
reverse = true;
}
}
});
if (reverse) allThroughStation.reverse();
return allThroughStation;
});
let mainArray = [...trainData];
let indexs = 0;
trainData.forEach((d, index) => {
indexs = indexs + 1;
if (!allThroughStationList[index]) return;
if (allThroughStationList[index].length == 0) return;
mainArray.splice(indexs, 0, ...allThroughStationList[index]);
indexs = indexs + allThroughStationList[index].length;
});
setTrainDataWithThrough(mainArray);
}, [allTrainDiagram, stationList, trainID]);
const [stopStationIDList, setStopStationList] = useState([]);
useEffect(() => {
const x = trainDataWidhThrough.map((i) => {
const [station, se, time] = i.split(",");
const Stations = stationList.map((a) =>
a.filter((d) => d.StationName == station)
);
const StationNumbers =
Stations &&
Stations.reduce((newArray, e) => {
return newArray.concat(e);
}, []).map((d) => d.StationNumber);
return StationNumbers;
});
setStopStationList(x);
}, [trainDataWidhThrough]);
const [currentPosition, setCurrentPosition] = useState<string[]>([]);
useEffect(() => {
let position = getPosition(train);
if (stopStationIDList.length == 0) return;
if (position) {
if (position.length > 1) {
if (position[0] == "-Iyo") {
position[0] =
stopStationIDList[
stopStationIDList.findIndex((d) => d.includes("U14")) - 1
][0];
} else if (position[0] == "+Iyo") {
position[0] =
stopStationIDList[
stopStationIDList.findIndex((d) => d.includes("U14")) + 1
][0];
}
if (position[1] == "+Iyo") {
position[1] =
stopStationIDList[
stopStationIDList.findIndex((d) => d.includes("U14")) + 1
][0];
} else if (position[1] == "-Iyo") {
position[1] =
stopStationIDList[
stopStationIDList.findIndex((d) => d.includes("U14")) - 1
][0];
}
}
setCurrentPosition(position);
}
}, [train,stopStationIDList]);
const [nextStationData, setNextStationData] = useState<StationProps[]>([]);
const [untilStationData, setUntilStationData] = useState<StationProps[]>([]);
const [probably, setProbably] = useState(false);
useEffect(() => {
//棒線駅判定を入れて、棒線駅なら時間を見て分数がマイナスならcontinue;
const points = findReversalPoints(currentPosition, stopStationIDList);
if (!points) return;
if (points.length == 0) return;
let searchCountFirst = points.findIndex((d) => d == true);
let searchCountLast = points.findLastIndex((d) => d == true);
const delayTime = train?.delay == "入線" ? 0 : train?.delay;
let additionalSkipCount = 0;
for (
let searchCount = searchCountFirst;
searchCount < points.length;
searchCount++
) {
const nextPos = trainDataWidhThrough[searchCount];
if (nextPos) {
const [station, se, time] = nextPos.split(",");
if (searchCountFirst == searchCountLast) {
if (se.includes("通")) {
continue;
}
setNextStationData(getStationDataFromName(station));
break;
}
//棒線駅判定
let distanceMinute = 0;
if (time != "") {
const now = dayjs();
const hour = parseInt(time.split(":")[0]);
const distanceTime = now
.hour(hour < 4 ? hour + 24 : hour)
.minute(parseInt(time.split(":")[1]));
distanceMinute = distanceTime.diff(now, "minute") + delayTime;
if (now.hour() < 4) {
if (hour < 4) {
distanceMinute = distanceMinute - 1440;
}
}
}
if (distanceMinute >= 0) {
if (se.includes("通")) {
continue;
} else {
setNextStationData(getStationDataFromName(station));
break;
}
} else {
additionalSkipCount++;
continue;
}
}
}
let trainList = [];
for (
let searchCount = searchCountFirst - 1;
searchCount < points.length;
searchCount++
) {
trainList.push(trainDataWidhThrough[searchCount]);
}
if (additionalSkipCount > 0) {
trainList = trainList.slice(additionalSkipCount);
setProbably(true);
} else {
setProbably(false);
}
setUntilStationData(trainList);
}, [currentPosition, trainDataWidhThrough]);
const [ToData, setToData] = useState("");
useEffect(() => {
if (customData.ToData && customData.ToData != "") {
setToData(customData.ToData);
} else {
if (trainDataWidhThrough.length == 0) return;
setToData(
trainDataWidhThrough[trainDataWidhThrough.length - 2].split(",")[0]
);
}
}, [customData, trainDataWidhThrough]);
const [station, setStation] = useState<StationProps[]>([]);
useEffect(() => {
const data = getStationDataFromName(ToData);
setStation(data);
}, [ToData]);
const lineColor =
station.length > 0
? lineColorList[station[0]?.StationNumber.slice(0, 1)]
: "black";
//const lineColor = "red";
const customTrainType = getTrainType({
type: customData.type,
whiteMode: true,
});
const trainNameText = `${customData.trainName}${
customData.trainNumDistance !== null
? ` ${parseInt(customData.TrainNumber) - customData.trainNumDistance}`
: ""
}`;
return (
<View
style={{ display: "flex", flexDirection: "column", flex: 1 }}
pointerEvents="box-none"
>
<View
style={{
flex: 1,
flexDirection: displaySize === 226 ? "column" : "row",
backgroundColor: "black",
//borderBottomColor: "black",
//borderBottomWidth: 2,
}}
>
<View
style={{
flexDirection: displaySize === 226 ? "row" : "column",
flex: 1,
backgroundColor: "white",
height: displaySize === 226 ? 200 : 50,
overflow: "hidden",
}}
>
<View
style={{ flex: displaySize === 226 ? 5 : 1, flexDirection: "row" }}
>
<View
style={{
backgroundColor: customTrainType.color,
flexDirection: "row",
alignContent: "center",
alignSelf: "center",
alignItems: "center",
height: "100%",
}}
>
<Image
source={{ uri: customData.img }}
width={displaySize === 226 ? 23 : 14}
height={displaySize === 226 ? 26 : 17}
style={{ margin: 5 }}
/>
<View
style={{
flexDirection: displaySize === 226 ? "column" : "row",
alignContent: "center",
alignSelf: "center",
alignItems: "center",
maxWidth: displaySize === 226 ? 80 : 100,
}}
>
<Text
style={{
fontSize: trainNameText.length > 4 ? 12 : 14,
fontFamily: customTrainType.fontAvailable
? "JR-Nishi"
: undefined,
fontWeight: !customTrainType.fontAvailable
? "bold"
: undefined,
marginTop: customTrainType.fontAvailable ? 3 : 0,
color: "white",
textAlignVertical: "center",
textAlign: "left",
}}
>
{customTrainType.shortName}
</Text>
{customData.trainName && (
<Text
style={{
fontSize: trainNameText.length > 4 ? 8 : 14,
color: "white",
maxWidth: displaySize === 226 ? 200 : 60,
textAlignVertical: "center",
}}
>
{trainNameText}
</Text>
)}
</View>
<View
style={{
backgroundColor: customTrainType.color,
width: 10,
borderLeftColor: customTrainType.color,
borderTopColor: lineColor,
borderBottomColor: lineColor,
borderTopWidth: displaySize === 226 ? 50 : 14,
borderBottomWidth: displaySize === 226 ? 50 : 14,
borderLeftWidth: displaySize === 226 ? 30 : 10,
borderRightWidth: 0,
//height: displaySize === 226 ? 20 : 100,
height: "100%",
}}
></View>
</View>
<View
style={{
flexDirection: "row",
alignContent: "center",
alignSelf: "center",
height: "100%",
backgroundColor: lineColor,
flex: 1,
}}
>
<View
style={{
flexDirection: "row",
alignContent: "center",
alignSelf: "center",
alignItems: "center",
}}
>
<StationNumberMaker
currentStation={station}
singleSize={18}
useEach={true}
/>
<Text
style={{
fontSize: customData?.ToData?.length > 4 ? 9 : 12,
color: "white",
fontWeight: "bold",
textAlignVertical: "center",
margin: 0,
padding: 0,
height: "100%",
}}
>
{ToData}
</Text>
</View>
</View>
</View>
{displaySize === 226 && (
<View
style={{
backgroundColor: "white",
width: 10,
borderLeftColor: "black",
borderTopColor: lineColor,
borderBottomColor: "white",
borderRightColor: "black",
borderTopWidth: 50,
borderBottomWidth: 0,
borderLeftWidth: 0,
borderRightWidth: 20,
}}
></View>
)}
<View
style={{
backgroundColor: "black",
flex: displaySize === 226 ? 4 : 1,
flexDirection: "row",
alignItems: "center",
}}
>
<View style={{ flexDirection: "column" }}>
<Text
style={{
fontSize: 10,
fontWeight: "bold",
color: "white",
marginHorizontal: 5,
paddingVertical: 0,
marginVertical: -1,
}}
>
{nextStationData[0]?.Station_JP == train?.Pos
? "ただいま"
: "次は"}
</Text>
{probably && (
<Text
style={{
fontSize: 5,
color: "white",
fontWeight: "bold",
marginHorizontal: 5,
paddingVertical: 0,
marginVertical: -1,
}}
>
()
</Text>
)}
</View>
<StationNumberMaker
currentStation={nextStationData}
singleSize={20}
useEach={true}
/>
<Text
style={{
fontSize: 18,
fontWeight: "bold",
color: "white",
flex: 1,
}}
>
{nextStationData[0]?.Station_JP || "不明"}
</Text>
{displaySize !== 226 && (
<View
style={{
backgroundColor: "white",
width: 10,
borderLeftColor: "black",
borderTopColor: "black",
borderBottomColor: "white",
borderRightColor: "white",
borderTopWidth: 21,
borderBottomWidth: 0,
borderLeftWidth: 0,
borderRightWidth: 7,
}}
></View>
)}
</View>
</View>
<CurrentPositionBox
train={train}
lineColor={lineColor}
trainDataWithThrough={untilStationData}
isSmall={displaySize !== 226}
/>
</View>
<View
style={{
flexDirection: "row",
justifyContent: "space-between",
borderTopColor: "black",
borderTopWidth: 2,
}}
pointerEvents="box-none"
>
<TouchableOpacity
style={{
flexDirection: "row",
alignItems: "center",
}}
onPress={() => {
setFixedPosition({ type: null, value: null });
}}
>
<View
style={{
flexDirection: "row",
alignItems: "center",
backgroundColor: "black",
paddingHorizontal: 5,
height: 26,
}}
>
<Ionicons name="lock-closed" size={15} color="white" />
<Text
style={{
color: "white",
fontSize: 15,
paddingRight: 5,
}}
>
</Text>
<Ionicons name="close" size={15} color="white" />
</View>
<View
style={{
backgroundColor: "#0000",
width: 6,
borderLeftColor: "black",
borderTopColor: "black",
borderBottomColor: "#0000",
borderRightColor: "#0000",
borderBottomWidth: 26,
borderLeftWidth: 10,
borderRightWidth: 0,
borderTopWidth: 0,
height: 26,
}}
/>
</TouchableOpacity>
<TouchableOpacity
style={{
flexDirection: "row",
alignItems: "center",
}}
onPress={() => {
LayoutAnimation.configureNext({
duration: 200,
update: { type: "easeInEaseOut", springDamping: 0.4 },
});
if (displaySize === 226) {
setDisplaySize(mapSwitch == "true" ? 76 : 80);
} else {
setDisplaySize(226);
}
}}
>
<View
style={{
backgroundColor: "#0000",
width: 6,
borderLeftColor: "#0000",
borderTopColor: "black",
borderBottomColor: "#0000",
borderRightColor: "black",
borderBottomWidth: 26,
borderLeftWidth: 0,
borderRightWidth: 10,
borderTopWidth: 0,
height: 26,
}}
/>
<View
style={{
flexDirection: "row",
alignItems: "center",
backgroundColor: "black",
paddingHorizontal: 5,
height: 26,
}}
>
<Ionicons
name={displaySize == 226 ? "chevron-up" : "chevron-down"}
size={15}
color="white"
/>
<Text
style={{
color: "white",
paddingRight: 5,
backgroundColor: "black",
fontSize: 15,
}}
>
{displaySize == 226 ? "列車情報縮小" : "列車情報展開"}
</Text>
</View>
</TouchableOpacity>
</View>
</View>
);
};
const CurrentPositionBox = ({
train,
lineColor,
trainDataWithThrough,
isSmall,
}) => {
let firstText = "";
let secondText = "";
let marginText = "";
const { isBetween, Pos: PosData } = trainPosition(train);
if (isBetween === true) {
const { from, to } = PosData;
firstText = from;
secondText = to;
marginText = "→";
} else {
const { Pos } = PosData;
if (Pos !== "") {
firstText = Pos;
}
}
const delayTime = train?.delay == "入線" ? 0 : parseInt(train?.delay);
return (
<View
style={{
flex: isSmall ? 1 : 3,
backgroundColor: "white",
flexDirection: "row",
}}
>
{isSmall && (
<View style={{ flexDirection: "column" }}>
<View
style={{
backgroundColor: "white",
width: 10,
borderLeftColor: lineColor,
borderTopColor: lineColor,
borderBottomColor: "white",
borderRightColor: "white",
borderTopWidth: 28,
borderBottomWidth: 0,
borderLeftWidth: 0,
borderRightWidth: 10,
}}
></View>
<View
style={{
backgroundColor: "white",
width: 10,
borderLeftColor: "white",
borderTopColor: "white",
borderBottomColor: "white",
borderRightColor: "white",
borderTopWidth: 18,
borderBottomWidth: 0,
borderLeftWidth: 0,
borderRightWidth: 10,
}}
></View>
</View>
)}
<ScrollView
style={{ flex: 1, flexDirection: "row" }}
horizontal
overScrollMode="always"
>
{trainDataWithThrough.length > 0 &&
trainDataWithThrough.map((d, index) => (
<EachStopData
d={d}
index={index}
key={d}
delayTime={delayTime}
isSmall={isSmall}
secondText={secondText}
/>
))}
</ScrollView>
</View>
);
};
type eachStopType = {
d: string;
delayTime: number;
isSmall: boolean;
index: number;
secondText: string;
};
const EachStopData: FC<eachStopType> = (props) => {
const { d, delayTime, isSmall, index, secondText } = props;
if (!d) return null;
if (d == "") return null;
const [station, se, time] = d.split(",");
let distanceMinute = 0;
if (time != "") {
const now = dayjs();
const hour = parseInt(time.split(":")[0]);
const distanceTime = now
.hour(hour < 4 ? hour + 24 : hour)
.minute(parseInt(time.split(":")[1]));
distanceMinute = distanceTime.diff(now, "minute") + delayTime;
if (now.hour() < 4) {
if (hour < 4) {
distanceMinute = distanceMinute - 1440;
}
}
}
return (
<>
<View
style={{
flexDirection: "column",
backgroundColor: se.includes("通") ? "#6e6e6e77" : "#6e6e6eff",
borderRadius: 30,
marginHorizontal: isSmall ? 2 : 4,
marginVertical: isSmall ? 0 : 2,
padding: isSmall ? 2 : 4,
justifyContent: "center",
alignItems: "center",
overflow: "hidden",
}}
key={d + "CurrentPositionBox"}
>
{station.split("").map((i, index, array) => {
return (
<Text
key={i + index}
style={{
fontSize:
array.length < 5 ? (isSmall ? 5 : 12) : isSmall ? 3 : 10,
color: "white",
margin: 0,
padding: 0,
fontWeight: "bold",
}}
>
{i}
</Text>
);
})}
<View style={{ flex: 1 }} />
{isSmall ||
(time != "" && (
<Text
style={{
fontSize: isSmall ? 8 : 12,
color: "black",
backgroundColor: "white",
fontWeight: "bold",
}}
>
{distanceMinute}
</Text>
))}
<Text
style={{
fontSize: isSmall ? 8 : 14,
color:
index == 1 && secondText == ""
? "#ffe852ff"
: se.includes("通")
? "#020202ff"
: "white",
marginTop: isSmall ? 0 : 3,
height: isSmall ? "auto" : 17,
fontWeight: "bold",
}}
>
{index == 1 && secondText == ""
? "→"
: se.includes("通")
? null
: "●"}
</Text>
</View>
{index == 0 && secondText != "" && (
<View
style={{
flexDirection: "column",
backgroundColor: "#0000",
borderRadius: 10,
marginHorizontal: isSmall ? 2 : 4,
padding: isSmall ? 2 : 4,
justifyContent: "center",
alignItems: "center",
overflow: "hidden",
}}
>
<View style={{ flex: 1 }} />
<Ionicons
name="arrow-forward"
size={isSmall ? 8 : 14}
color="black"
style={{ marginTop: isSmall ? 0 : 3 }}
/>
</View>
)}
</>
);
};

View File

@@ -37,6 +37,7 @@ export const MapsButton: FC<MapsButtonProps> = ({ onPress }) => {
alignSelf: "center",
alignItems: "center",
display: mapSwitch == "true" ? "flex" : "none",
zIndex: 1000,
},
text: {
textAlign: "center",

View File

@@ -38,6 +38,7 @@ export const ReloadButton:FC<ReloadButton> = ({ onPress, right }) => {
alignSelf: "center",
alignItems: "center",
display: mapSwitch,
zIndex: 1000,
},
text: {
textAlign: "center",

View File

@@ -2,7 +2,13 @@ import React from "react";
import { Platform, LayoutAnimation } from "react-native";
import { WebView } from "react-native-webview";
import { lineList } from "../../lib/getStationList";
import {
lineList,
lineList_LineWebID,
lineListPair,
stationIDPair,
stationNamePair,
} from "../../lib/getStationList";
import { checkDuplicateTrainData } from "../../lib/checkDuplicateTrainData";
import { useFavoriteStation } from "../../stateBox/useFavoriteStation";
import { useCurrentTrain } from "../../stateBox/useCurrentTrain";
@@ -11,14 +17,14 @@ import { SheetManager } from "react-native-actions-sheet";
import { useNavigation } from "@react-navigation/native";
import { useTrainMenu } from "../../stateBox/useTrainMenu";
import { stationNamePair } from "../../lib/getStationList2";
import { useStationList } from "../../stateBox/useStationList";
export const AppsWebView = ({ openStationACFromEachTrainInfo }) => {
const { webview, currentTrain } = useCurrentTrain();
const { navigate } = useNavigation();
const { favoriteStation } = useFavoriteStation();
const { isLandscape } = useDeviceOrientationChange();
const { originalStationList, stationList } = useStationList();
const { originalStationList, stationList, getInjectJavascriptAddress } =
useStationList();
const {
setSelectedLine,
mapsStationData: stationData,
@@ -46,9 +52,13 @@ export const AppsWebView = ({ openStationACFromEachTrainInfo }) => {
break;
}
};
const onMessage = (event) => {
const { data } = event.nativeEvent;
/**
* {type,trainNum,limited}
* {type,currentLines}
* {type,event,id,name,pdf,map,url,chk}
*/
if (data.includes("train.html")) {
navigate("trainbase", { info: data, from: "Train" });
return;
@@ -125,20 +135,13 @@ export const AppsWebView = ({ openStationACFromEachTrainInfo }) => {
const onLoadEnd = () => {
if (once) return () => {};
if (!stationData) return () => {};
if (!originalStationList) return () => {};
if (favoriteStation.length < 1) return () => {};
const getStationLine = (now) => {
const returnData = Object.keys(stationData).filter((d) => {
const cache = stationData[d].findIndex(
(data) => data.Station_JP == now.Station_JP
);
return cache != -1;
});
return returnData[0];
};
const lineName = getStationLine(favoriteStation[0][0]);
webview.current?.injectJavaScript(
`MoveDisplayStation('${lineName}_${favoriteStation[0][0].MyStation}_${favoriteStation[0][0].Station_JP}')`
const string = getInjectJavascriptAddress(
favoriteStation[0][0].StationNumber
);
if (!string) return () => {};
webview?.current.injectJavaScript(string);
once = true;
};

View File

@@ -6,7 +6,6 @@ import { AS } from "../storageControl";
export const DynamicHeaderScrollView = (props) => {
const {
children,
actionSheetRef = {},
containerProps = {},
shortHeader = <></>,
longHeader = <></>,
@@ -160,7 +159,7 @@ export const DynamicHeaderScrollView = (props) => {
ref={scrollHandlers.ref}
onLayout={scrollHandlers.onLayout}
scrollEventThrottle={scrollHandlers.scrollEventThrottle}
style={{ backgroundColor: "white", zIndex: 0 }}
style={{ zIndex: 0 }}
stickyHeaderIndices={[1]}
onScroll={onScroll}
>

View File

@@ -8,11 +8,13 @@ import { useNavigation } from "@react-navigation/native";
import { useTrainMenu } from "../stateBox/useTrainMenu";
import { FavoriteListItem } from "./atom/FavoriteListItem";
import { BigButton } from "./atom/BigButton";
import { useStationList } from "@/stateBox/useStationList";
export const FavoriteList: FC = () => {
const { favoriteStation } = useFavoriteStation();
const { webview } = useCurrentTrain();
const { navigate, addListener, goBack, canGoBack } = useNavigation();
const { mapsStationData: stationData } = useTrainMenu();
const { getInjectJavascriptAddress } = useStationList();
useEffect(() => {
const unsubscribe = addListener("tabPress", goToTrainMenu);
@@ -38,30 +40,20 @@ export const FavoriteList: FC = () => {
</Text>
<ScrollView style={{ height: "100%", backgroundColor: "white" }}>
{favoriteStation
.filter((d) => d[0].StationMap)
.map((currentStation) => {
return (
<FavoriteListItem
currentStation={currentStation}
onPress={() => {
const getStationLine = (now) => {
const returnData = Object.keys(stationData).filter((d) => {
const cache = stationData[d].findIndex(
(data) => data.Station_JP == now.Station_JP
);
return cache != -1;
});
return returnData[0];
};
const lineName = getStationLine(currentStation[0]);
webview.current?.injectJavaScript(
`MoveDisplayStation('${lineName}_${currentStation[0].MyStation}_${currentStation[0].Station_JP}');
document.getElementById("disp").insertAdjacentHTML("afterbegin", "<div />");`
const scriptString = getInjectJavascriptAddress(
currentStation[0].StationNumber
);
if (!scriptString) return;
webview.current?.injectJavaScript(scriptString);
goBack();
if (canGoBack()) goBack();
}}
key={currentStation[0].StationNumber + "FavoriteList"}
>
<View
style={{

View File

@@ -0,0 +1,186 @@
import Sign from "@/components/駅名表/Sign";
import React, { useEffect, useRef, useState } from "react";
import { AS } from "@/storageControl";
import {
useWindowDimensions,
View,
LayoutAnimation,
TouchableOpacity,
Text,
ScrollView,
} from "react-native";
import Carousel, { ICarouselInstance } from "react-native-reanimated-carousel";
import { SheetManager } from "react-native-actions-sheet";
import { StationNumber } from "../StationPagination";
import { SimpleDot } from "../SimpleDot";
export const CarouselBox = ({
originalStationList,
listUpStation,
nearPositionStation,
setListIndex,
listIndex,
navigate,
stationListMode,
isSearchMode
}) => {
const carouselRef = useRef<ICarouselInstance>(null);
const { height, width } = useWindowDimensions();
const [dotButton, setDotButton] = useState(false);
const carouselBadgeScrollViewRef = useRef<ScrollView>(null);
useEffect(() => {
if (!carouselBadgeScrollViewRef.current) return;
const dotSize = dotButton ? 28 : 24;
const scrollToIndex = dotSize * listIndex - width / 2 + dotSize - 5;
carouselBadgeScrollViewRef.current.scrollTo({
x: scrollToIndex,
animated: true,
});
}, [listIndex, dotButton, width, carouselBadgeScrollViewRef]);
const oPSign = () => {
const payload = {
currentStation: listUpStation[listIndex],
navigate,
goTo: "menu",
//@ts-ignore
useShow: () => SheetManager.show("StationDetailView", { payload }),
onExit: () => SheetManager.hide("StationDetailView"),
};
//@ts-ignore
SheetManager.show("StationDetailView", { payload });
};
const oLPSign = () => {
LayoutAnimation.configureNext({
duration: 600,
update: { type: "spring", springDamping: 0.5 },
});
AS.setItem(
"CarouselSettings/activeDotSettings",
!dotButton ? "true" : "false"
);
setDotButton(!dotButton);
};
useEffect(() => {
AS.getItem("CarouselSettings/activeDotSettings").then((data) => {
setDotButton(data === "true");
});
}, []);
const RenderItem = ({ item, index }) => {
return (
<View
style={{
backgroundColor: "#0000",
width,
flexDirection: "row",
marginLeft: 0,
marginRight: 0,
}}
key={item[0].StationNumber}
>
<View style={{ flex: 1 }} />
{item[0].StationNumber != "null" ? (
<Sign
stationID={item[0].StationNumber}
isCurrentStation={item == nearPositionStation}
oP={oPSign}
oLP={oLPSign}
/>
) : (
<TouchableOpacity
style={{
width: width * 0.8,
height: ((width * 0.8) / 20) * 9,
borderColor: "#0099CC",
borderWidth: 1,
backgroundColor: "white",
}}
>
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<Text style={{ color: "#0099CC", fontSize: 20 }}>
{!!isSearchMode ? "路線検索モードです。入力欄に駅名やナンバリングを入力したり、上に並んでいる路線を選んでみましょう!" :stationListMode == "position"
? "現在地の近くに駅がありません。"
: "お気に入りリストがありません。お気に入りの駅を追加しよう!"}
</Text>
</View>
</TouchableOpacity>
)}
<View style={{ flex: 1 }} />
</View>
);
};
return (
<View style={{ flex: 1, paddingTop: 10 }}>
<Carousel
ref={carouselRef}
data={
listUpStation.length > 0
? listUpStation
: [[{ StationNumber: "null" }]]
}
height={(((width / 100) * 80) / 20) * 9 + 10}
pagingEnabled={true}
snapEnabled={true}
loop={false}
width={width}
style={{ width: width, alignContent: "center" }}
mode="parallax"
modeConfig={{
parallaxScrollingScale: 1,
parallaxScrollingOffset: 100,
parallaxAdjacentItemScale: 0.8,
}}
scrollAnimationDuration={600}
onSnapToItem={setListIndex}
renderItem={RenderItem}
overscrollEnabled={false}
defaultIndex={listIndex >= listUpStation.length ? 0 : listIndex}
/>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={{
flexDirection: "row",
justifyContent: "center",
alignContent: "center",
alignItems: "center",
paddingVertical: 2,
paddingHorizontal: 10,
minWidth: width,
}}
ref={(scrollViewRef) => {
// ScrollViewのrefを保存
if (scrollViewRef) {
carouselBadgeScrollViewRef.current = scrollViewRef;
}
}}
>
{originalStationList &&
listUpStation.map((d, index) => {
const active = index == listIndex;
const numberKey = d[0].StationNumber + index;
return dotButton ? (
<StationNumber
onPress={() => setListIndex(index)}
currentStation={d}
active={active}
key={numberKey}
/>
) : (
<SimpleDot
onPress={() => setListIndex(index)}
active={active}
key={numberKey}
/>
);
})}
</ScrollView>
</View>
);
};

View File

@@ -0,0 +1,172 @@
import { AS } from "@/storageControl";
import React from "react";
import {
TouchableOpacity,
Text,
LayoutAnimation,
KeyboardAvoidingView,
Platform,
} from "react-native";
import Ionicons from "react-native-vector-icons/Ionicons";
import { SearchUnitBox } from "@/components/Menu/RailScope/SearchUnitBox";
export const CarouselTypeChanger = ({
locationStatus,
position,
stationListMode,
setStationListMode,
setSelectedCurrentStation,
mapMode,
setMapMode,
isSearchMode,
setisSearchMode,
input,
setInput,
}) => {
const returnToDefaultMode = () => {
LayoutAnimation.configureNext({
duration: 300,
create: {
type: LayoutAnimation.Types.easeInEaseOut,
property: LayoutAnimation.Properties.opacity,
},
update: {
type: LayoutAnimation.Types.easeInEaseOut,
property: LayoutAnimation.Properties.opacity,
},
});
setMapMode(false);
};
return (
<KeyboardAvoidingView
behavior="position"
contentContainerStyle={{ flex: 1, flexDirection: "row" }}
keyboardVerticalOffset={mapMode ? 0 : 45}
enabled={Platform.OS === "ios"}
style={{
width: "100%",
height: 40,
flexDirection: "row",
position: mapMode ? "absolute" : "relative",
bottom: mapMode ? 0 : undefined,
zIndex: 1000,
backgroundColor: "white",
}}
key={"carouselTypeChanger"}
>
<SearchUnitBox
isSearchMode={isSearchMode}
setisSearchMode={setisSearchMode}
input={input}
setInput={setInput}
/>
<TouchableOpacity
style={{
flex: 1,
backgroundColor:
stationListMode == "position" ? "#0099CC" : "#0099CC80",
padding: 5,
alignItems: "center",
flexDirection: "row",
marginHorizontal: 5,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
borderBottomLeftRadius: mapMode ? 0 : 20,
borderBottomRightRadius: mapMode ? 0 : 20,
}}
disabled={!locationStatus}
onPressIn={() => {
if (!position) return;
returnToDefaultMode();
setStationListMode("position");
AS.setItem("stationListMode", "position");
setSelectedCurrentStation(0);
}}
onPress={() => {
if (!position) return;
returnToDefaultMode();
setStationListMode("position");
AS.setItem("stationListMode", "position");
setSelectedCurrentStation(0);
}}
>
<Ionicons
name="locate-outline"
size={14}
color="white"
style={{ margin: 5 }}
/>
<Text
style={{
color: "white",
fontSize: 14,
fontWeight: "bold",
flex: 1,
textAlign: "center",
}}
>
</Text>
</TouchableOpacity>
<TouchableOpacity
style={{
padding: 5,
alignItems: "center",
flexDirection: "row",
marginHorizontal: 5,
borderRadius: 50,
}}
onPressIn={() => returnToDefaultMode()}
>
<Ionicons
name={!mapMode ? "menu" : "chevron-up-outline"}
size={30}
color="#0099CC"
style={{ marginHorizontal: 5 }}
/>
</TouchableOpacity>
<TouchableOpacity
style={{
flex: 1,
backgroundColor:
stationListMode == "favorite" ? "#0099CC" : "#0099CC80",
padding: 5,
alignItems: "center",
flexDirection: "row",
marginHorizontal: 5,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
borderBottomLeftRadius: mapMode ? 0 : 20,
borderBottomRightRadius: mapMode ? 0 : 20,
}}
onPressIn={() => {
returnToDefaultMode();
// お気に入りリスト更新
setStationListMode("favorite");
AS.setItem("stationListMode", "favorite");
setSelectedCurrentStation(0);
}}
onPress={() => {
returnToDefaultMode();
// お気に入りリスト更新
setStationListMode("favorite");
AS.setItem("stationListMode", "favorite");
setSelectedCurrentStation(0);
}}
>
<Ionicons name="star" size={14} color="white" style={{ margin: 5 }} />
<Text
style={{
color: "white",
fontSize: 14,
fontWeight: "bold",
flex: 1,
textAlign: "center",
}}
>
</Text>
</TouchableOpacity>
</KeyboardAvoidingView>
);
};

View File

@@ -6,10 +6,12 @@ import {
MaterialCommunityIcons,
} from "@expo/vector-icons";
import { ListItem } from "@rneui/themed";
import TouchableScale from 'react-native-touchable-scale';
import TouchableScale from "react-native-touchable-scale";
import Icon from "react-native-vector-icons/Entypo";
import { TextBox } from "../atom/TextBox";
import { TicketBox } from "../atom/TicketBox";
import { SpecialTrainInfoBox } from "./SpecialTrainInfoBox";
import { SheetManager } from "react-native-actions-sheet";
export const FixedContentBottom = (props) => {
return (
@@ -51,7 +53,7 @@ export const FixedContentBottom = (props) => {
</TicketBox>
</View>
<TextBox
backgroundColor="#0099CC"
backgroundColor="#ed86b5"
flex={1}
onPressButton={() =>
Linking.openURL("https://www.jr-eki.com/smart-eki/index.html")
@@ -68,7 +70,9 @@ export const FixedContentBottom = (props) => {
backgroundColor="#0099CC"
flex={1}
onPressButton={() =>
Linking.openURL("https://www.jr-shikoku.co.jp/sp/index.html#menu-box")
SheetManager.show("SpecialTrainInfo", {
payload: { navigate: props.navigate },
})
}
>
<Text style={{ color: "white", fontWeight: "bold", fontSize: 20 }}>
@@ -165,105 +169,20 @@ export const FixedContentBottom = (props) => {
<Text style={{ color: "white" }}>(通話料がかかります)</Text>
</TouchableOpacity>
</View>
<View
style={{
backgroundColor: "#0099CC",
borderRadius: 10,
margin: 10,
borderColor: "black",
borderWidth: 2,
}}
<TextBox
backgroundColor="#0099CC"
flex={1}
onPressButton={() =>
SheetManager.show("Social")
}
>
<View
style={{ padding: 10, flexDirection: "row", alignItems: "center" }}
>
<MaterialCommunityIcons
name="twitter"
style={{ padding: 5 }}
color="white"
size={30}
/>
<Text style={{ fontSize: 30, fontWeight: "bold", color: "white" }}>
JR四国公式Twitter一族
</Text>
</View>
<View
style={{
padding: 10,
backgroundColor: "white",
borderBottomLeftRadius: 10,
borderBottomRightRadius: 10,
}}
>
{[
{
url: "https://twitter.com/jr_shikoku_info",
name: "JR四国列車運行情報",
},
{
url: "https://twitter.com/JRshikoku_eigyo",
name: "JR四国営業部【公式】",
},
{
url: "https://twitter.com/JRshikoku_tokyo",
name: "JR四国 東京営業情報【公式】",
},
{
url: "https://twitter.com/JRshikoku_osaka",
name: "JR四国 大阪営業部【公式】",
},
{
url: "https://twitter.com/jrs_matsuyama",
name: "JR四国 松山駅 【公式】",
},
{
url: "https://twitter.com/jrshikoku_kochi",
name: "JR四国 高知駅【公式】",
},
{
url: "https://twitter.com/jr_tokust",
name: "JR四国 徳島駅【公式】",
},
{
url: "https://twitter.com/jrshikoku_uwjm",
name: "JR四国 宇和島駅【公式】",
},
{
url: "https://twitter.com/jrshikoku_wkama",
name: "JR四国 ワープ高松支店【公式】",
},
{
url: "https://twitter.com/JRshikoku_wkoch",
name: "JR四国 ワープ高知支店【公式】",
},
{
url: "https://twitter.com/Yoakemonogatari",
name: "志国土佐 時代の夜明けのものがたり【公式】",
},
{
url: "https://twitter.com/Smile_Eki_Chan",
name: "すまいるえきちゃん♡JR四国【公式】",
},
{
url: "https://twitter.com/sper_ponchan",
name: "しこくたぬきのぽんちゃん 【四国家サポーターズクラブ】",
},
].map((d) => (
<ListItem bottomDivider onPress={() => Linking.openURL(d.url)}
key={d.url}friction={90} //
tension={100} // These props are passed to the parent component (here TouchableScale)
activeScale={0.95} //
Component={TouchableScale}
>
<ListItem.Content>
<ListItem.Title>{d.name}</ListItem.Title>
</ListItem.Content>
<ListItem.Chevron />
</ListItem>
))}
</View>
</View>
<Text style={{ color: "white", fontWeight: "bold", fontSize: 20 }}>
ソーシャルメディア
</Text>
<Text style={{ color: "white", fontSize: 18 }}>
JR四国のSNS一覧です
</Text>
</TextBox>
<Text style={{ fontWeight: "bold", fontSize: 20 }}>上級者向け機能</Text>
<TextBox
backgroundColor="#8c00d6"
@@ -278,6 +197,19 @@ export const FixedContentBottom = (props) => {
</Text>
</TextBox>
<Text style={{ fontWeight: "bold", fontSize: 20 }}>その他</Text>
<TextBox
backgroundColor="rgb(88, 101, 242)"
flex={1}
onPressButton={() => Linking.openURL("https://twitter.com/Xprocess_main/status/1955242437817012300")}
>
<Text style={{ color: "white", fontWeight: "bold", fontSize: 20 }}>
公式Discordのご案内
</Text>
<Text style={{ color: "white", fontSize: 18 }}>
皆さんの目撃情報をアプリに反映しませんかDiscordに登録して運用を報告しましょう
</Text>
</TextBox>
<TextBox
backgroundColor="linear-gradient(120deg, rgba(247,135,54,0.208) 0%, rgba(54,125,247,0.208) 100%)"
flex={1}

View File

@@ -0,0 +1,111 @@
import React from "react";
import {
View,
Text,
TouchableOpacity,
ScrollView,
StyleProp,
ViewStyle,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { SheetManager } from "react-native-actions-sheet";
import LottieView from "lottie-react-native";
import { useTrainDelayData } from "@/stateBox/useTrainDelayData";
import dayjs from "dayjs";
export const JRSTraInfoBox = () => {
const { getTime, delayData, loadingDelayData, setLoadingDelayData } =
useTrainDelayData();
const styles: { [key: string]: StyleProp<ViewStyle> } = {
touch: {
backgroundColor: "#0099CC",
borderRadius: 5,
margin: 10,
borderColor: "black",
borderWidth: 2,
overflow: "hidden",
},
scroll: {
backgroundColor: "#0099CC",
borderRadius: 5,
maxHeight: 300,
},
bottom: {
position: "absolute",
top: 250,
alignItems: "center",
width: "100%",
height: 50,
backgroundColor: "#007FCC88",
},
box: {
padding: 10,
backgroundColor: "white",
borderBottomLeftRadius: 5,
borderBottomRightRadius: 5,
},
};
return (
<TouchableOpacity
onPress={() => SheetManager.show("JRSTraInfo")}
style={styles.touch}
>
<ScrollView scrollEnabled={false} style={styles.scroll}>
<View
style={{ padding: 10, flexDirection: "row", alignItems: "center" }}
>
<Text style={{ fontSize: 30, fontWeight: "bold", color: "white" }}>
EX
</Text>
<View style={{ flex: 1 }} />
<Text style={{ fontSize: 30, fontWeight: "bold", color: "white" }}>
{getTime ? dayjs(getTime).format("HH:mm") : NaN}
</Text>
<Ionicons
name="reload"
color="white"
size={30}
style={{ margin: 5 }}
onPress={() => setLoadingDelayData(true)}
/>
</View>
<View style={styles.box}>
{loadingDelayData ? (
<View style={{ alignItems: "center" }}>
<LottieView
autoPlay
loop
style={{ width: 150, height: 150, backgroundColor: "#fff" }}
source={require("@/assets/51690-loading-diamonds.json")}
/>
</View>
) : delayData ? (
delayData.map((d, index, array) => {
let data = d.split(" ");
return (
<View
style={{ flexDirection: "row" }}
key={data[1] + "key" + index}
>
<Text style={{ flex: 15, fontSize: 18 }}>
{data[0].replace("\n", "")}
</Text>
<Text style={{ flex: 5, fontSize: 18 }}>{data[1]}</Text>
<Text style={{ flex: 6, fontSize: 18 }}>{data[3]}</Text>
</View>
);
})
) : (
<Text>5</Text>
)}
</View>
</ScrollView>
<View style={styles.bottom}>
<View style={{ flex: 1 }} />
<Text style={{ color: "white", fontWeight: "bold", fontSize: 20 }}>
</Text>
<View style={{ flex: 1 }} />
</View>
</TouchableOpacity>
);
};

View File

@@ -0,0 +1,161 @@
import React from "react";
import {
TouchableOpacity,
Text,
View,
LayoutAnimation,
TextInput,
KeyboardAvoidingView,
Platform,
} from "react-native";
import Ionicons from "react-native-vector-icons/Ionicons";
import { useWindowDimensions } from "react-native";
import lineColorList from "@/assets/originData/lineColorList";
import { lineList_LineWebID, stationIDPair } from "@/lib/getStationList";
export const SearchUnitBox = ({
isSearchMode,
setisSearchMode,
input,
setInput,
}) => {
const { height, width } = useWindowDimensions();
return (
<>
<TouchableOpacity
style={{
position: "absolute",
bottom: !!isSearchMode ? 0 : 60,
right: 0,
padding: !!isSearchMode ? 5 : 10,
margin: !!isSearchMode ? 0 : 10,
backgroundColor: "#0099CC",
borderRadius: !!isSearchMode ? 5 : 50,
width: !!isSearchMode ? width : 50,
zIndex: 1000,
}}
disabled={!!isSearchMode}
onPress={() => {
LayoutAnimation.configureNext({
duration: 100,
update: { type: "easeInEaseOut", springDamping: 0.6 },
});
setisSearchMode(true);
}}
>
{!isSearchMode && <Ionicons name="search" size={30} color="white" />}
{!!isSearchMode && (
<View
style={{
backgroundColor: "#0099CC",
flexDirection: "column",
display: "flex",
flex: 1,
alignContent: "center",
justifyContent: "flex-end",
}}
>
<View style={{ flexDirection: "row", alignItems: "center" }}>
<TouchableOpacity
onPress={() => {
LayoutAnimation.configureNext({
duration: 100,
update: { type: "easeInEaseOut", springDamping: 0.6 },
});
setisSearchMode(false);
}}
>
<Ionicons
name="arrow-back"
size={20}
color="white"
style={{ marginRight: 10 }}
/>
</TouchableOpacity>
<View
style={{
backgroundColor: "white",
borderRadius: 25,
height: 30,
paddingRight: 10,
paddingLeft: 10,
flex: 1,
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
}}
>
<TextInput
placeholder="駅名や駅ナンバリングを入力してフィルタリングします。"
onEndEditing={() => {}}
onChange={(ret) => setInput(ret.nativeEvent.text)}
value={input}
style={{ flex: 1 }}
/>
{input && (
<TouchableOpacity
onPress={() => setInput("") }
style={{
padding: 3,
borderRadius: 15,
backgroundColor: "lightgray",
}}
>
<Ionicons
name="close"
size={20}
color="white"
/>
</TouchableOpacity>
)}
</View>
</View>
{!input && (
<View style={{ flexDirection: "row", alignItems: "center" }}>
{Object.keys(lineList_LineWebID).map((d) => (
<TouchableOpacity
style={{
flex: 1,
backgroundColor:
lineColorList[stationIDPair[lineList_LineWebID[d]]],
padding: 5,
marginHorizontal: 2,
borderRadius: 10,
borderColor: "white",
borderWidth: 1,
borderStyle: "solid",
alignItems: "center",
opacity:
isSearchMode == stationIDPair[lineList_LineWebID[d]]
? 1
: !isSearchMode
? 1
: 0.5,
zIndex: 10,
}}
onPress={() => {
const id = stationIDPair[lineList_LineWebID[d]];
const s = isSearchMode == id ? undefined : id;
if (!s) return;
setisSearchMode(s);
}}
key={stationIDPair[lineList_LineWebID[d]]}
>
<Text
style={{
color: "white",
fontWeight: "bold",
fontSize: 20,
}}
>
{stationIDPair[lineList_LineWebID[d]]}
</Text>
</TouchableOpacity>
))}
</View>
)}
</View>
)}
</TouchableOpacity>
</>
);
};

View File

@@ -0,0 +1,63 @@
import { FC, useLayoutEffect, useState } from "react";
import { View, Text, TouchableOpacity } from "react-native";
import { getPDFViewURL } from "@/lib/getPdfViewURL";
import { ScrollView, SheetManager } from "react-native-actions-sheet";
type props = {
navigate: (screen: string, params?: object) => void;
};
type specialDataType = { address: string; text: string; description: string };
export const SpecialTrainInfoBox: FC<props> = ({ navigate }) => {
const [specialData, setSpecialData] = useState<specialDataType[]>([]);
useLayoutEffect(() => {
fetch("https://n8n.haruk.in/webhook/sptrainfo")
.then((res) => res.json())
.then((data) => setSpecialData(data.data))
.catch((err) => console.log(err));
}, []);
const onPressItem: (d: specialDataType) => void = (d) => {
navigate("howto", {
info: getPDFViewURL("https://www.jr-shikoku.co.jp" + d.address),
goTo: "menu",
});
SheetManager.hide("SpecialTrainInfo");
};
return (
<View style={{ backgroundColor: "#0099CC" }}>
<View style={{ flexDirection: "row", alignItems: "center" }}>
<Text
style={{
fontSize: 30,
fontWeight: "bold",
color: "white",
paddingHorizontal: 10,
paddingVertical: 5,
}}
>
</Text>
</View>
<ScrollView style={{ backgroundColor: "white" }}>
{specialData.map((d) => (
<TouchableOpacity
onPress={() => onPressItem(d)}
onLongPress={() => alert(d.description)}
key={d.address}
style={{
padding: 10,
borderBottomWidth: 1,
borderBottomColor: "#ccc",
flexDirection: "row",
alignItems: "center",
}}
>
<Text style={{ color: "black", fontSize: 20 }}>{d.text}</Text>
</TouchableOpacity>
))}
</ScrollView>
</View>
);
};

View File

@@ -1,22 +1,9 @@
import React, { FC, useState } from "react";
import { View, Text, TouchableOpacity } from "react-native";
import { useInterval } from "../../lib/useInterval";
import { useInterval } from "@/lib/useInterval";
import lineColorList from "../../assets/originData/lineColorList";
type StationProps = {
DispNum: string;
JrHpUrl: string;
MyStation: string;
StationMap: string;
StationNumber: string | null;
StationTimeTable: string;
Station_EN: string;
Station_JP: string;
jslodApi: string;
lat: number;
lng: number;
};
import lineColorList from "@/assets/originData/lineColorList";
import { StationProps } from "@/lib/CommonTypes";
type StationNumberProps = {
currentStation: StationProps[];
active: boolean;
@@ -36,30 +23,32 @@ export const StationNumber: FC<StationNumberProps> = (props) => {
const size = active ? 24 : 18;
return (
<TouchableOpacity
onPress={onPress} style={{
width: 28,
height:24,
alignContent:"center",
alignItems:"center",
justifyContent:"center",
position:"relative",
}}>
onPress={onPress}
style={{
width: 28,
height: 24,
alignContent: "center",
alignItems: "center",
justifyContent: "center",
position: "relative",
}}
>
{active && (
<View
style={{
flex: 1,
position: "absolute",
width: 28,
height: 28,
marginHorizontal:1,
borderRadius: 22,
borderColor: "black",
borderWidth: 2,
left: -1,
top: -2,
zIndex:10
}}
/>
<View
style={{
flex: 1,
position: "absolute",
width: 28,
height: 28,
marginHorizontal: 1,
borderRadius: 22,
borderColor: "black",
borderWidth: 2,
left: -1,
top: -2,
zIndex: 10,
}}
/>
)}
<View
style={{

View File

@@ -1,18 +1,25 @@
import { View, TouchableOpacity, Linking } from "react-native";
import AutoHeightImage from "react-native-auto-height-image";
import { widthPercentageToDP as wp } from "react-native-responsive-screen";
import { View, TouchableOpacity, Linking,Platform, Image, useWindowDimensions } from "react-native";
import Constants from "expo-constants";
export const TitleBar = () => {
const { width } = useWindowDimensions();
return (
<View style={{ alignItems: "center" }}>
<View
style={{
alignItems: "center",
position: "absolute",
top: 0,
left: 0,
right: 0,
zIndex: 100,
paddingTop: Platform.OS == "ios" ? Constants.statusBarHeight : 0,
}}
>
<TouchableOpacity
onPress={() => Linking.openURL("https://www.jr-shikoku.co.jp")}
>
<AutoHeightImage
source={require("../../assets/Header.png")}
resizeMode="contain"
width={wp("100%")}
/>
<Image source={require("../../assets/Header.png")} style={{ width: width, resizeMode: "contain", backgroundColor: "white", height: 80 }} />
</TouchableOpacity>
</View>
);

View File

@@ -0,0 +1,52 @@
import React from "react";
import { Linking, View } from "react-native";
import { UsefulBox } from "@/components/TrainMenu/UsefulBox";
import MaterialCommunityIcons from "@expo/vector-icons/build/MaterialCommunityIcons";
export const TopMenuButton = () => {
const buttonList:{
backgroundColor: string;
icon: keyof typeof MaterialCommunityIcons.glyphMap;
onPress: () => void;
title: string;
}[] = [
{
backgroundColor: "#F89038",
icon: "train-car",
onPress: () =>
Linking.openURL("https://www.jr-shikoku.co.jp/01_trainbus/sp/"),
title: "駅・鉄道情報",
},
{
backgroundColor: "#EA4752",
icon: "google-spreadsheet",
onPress: () =>
Linking.openURL(
"https://www.jr-shikoku.co.jp/01_trainbus/jikoku/sp/#mainprice-box"
),
title: "運賃表",
},
{
backgroundColor: "#91C31F",
icon: "clipboard-list-outline",
onPress: () => Linking.openURL("https://www.jr-shikoku.co.jp/e5489/"),
title: "予約",
},
];
return (
<View style={{ flexDirection: "row" }}>
{buttonList.map((d, index) => (
<UsefulBox
backgroundColor={d.backgroundColor}
icon={d.icon}
flex={1}
onPressButton={d.onPress}
key={index + d.icon}
>
{d.title}
</UsefulBox>
))}
</View>
);
};

View File

@@ -2,44 +2,18 @@ import React, { useEffect, useState } from "react";
import Icon from "react-native-vector-icons/Entypo";
import { View, Text, TouchableOpacity, LayoutAnimation } from "react-native";
import lineColorList from "../../../assets/originData/lineColorList";
import Ionicons from "react-native-vector-icons/Ionicons";
import { AS } from "../../../storageControl";
export const FavoriteSettingsItem = ({
currentStation,
setFavoriteStation,
index,
array,
}) => {
export const FavoriteSettingsItem = ({ currentStation }) => {
const lineIDs = [];
const EachIDs = [];
console.log(currentStation);
currentStation.forEach((d) => {
if (!d.StationNumber) return;
const textArray = d.StationNumber.split("");
lineIDs.push(textArray.filter((s) => "A" < s && s < "Z").join(""));
EachIDs.push(textArray.filter((s) => "0" <= s && s <= "9").join(""));
});
const [head, setHead] = useState(false);
const [tail, setTail] = useState(false);
useEffect(() => {
switch (true) {
case array.length == 1:
setHead(true);
setTail(true);
break;
case index == 0:
setHead(true);
setTail(false);
break;
case index == array.length - 1:
setHead(false);
setTail(true);
break;
default:
setHead(false);
setTail(false);
}
}, [array]);
return (
<View style={{ flexDirection: "row", backgroundColor: "white" }}>
@@ -47,7 +21,7 @@ export const FavoriteSettingsItem = ({
style={{
width: 35,
position: "relative",
marginHorizontal: 15,
marginHorizontal: 10,
flexDirection: "row",
height: "101%",
}}
@@ -91,43 +65,15 @@ export const FavoriteSettingsItem = ({
>
<Text style={{ fontSize: 20 }}>{currentStation[0].Station_JP}</Text>
<View style={{ flex: 1 }} />
<TouchableOpacity
style={{ marginHorizontal: 10, marginVertical: 4, width: 30 }}
onPress={() => {
console.log("up");
LayoutAnimation.configureNext(
LayoutAnimation.Presets.easeInEaseOut
);
const removedStation = [...array].filter((d, i) => {
if (i == index) return false;
return true;
});
removedStation.splice(index - 1, 0, currentStation);
setFavoriteStation(removedStation);
AS.setItem("favoriteStation", JSON.stringify(removedStation));
}}
>
{head ? null : <Icon name="chevron-up" size={26} />}
</TouchableOpacity>
<TouchableOpacity
style={{ marginHorizontal: 10, marginVertical: 4, width: 30 }}
onPress={() => {
console.log("down");
LayoutAnimation.configureNext(
LayoutAnimation.Presets.easeInEaseOut
);
const removedStation = [...array].filter((d, i) => {
if (i == index) return false;
return true;
});
removedStation.splice(index + 1, 0, currentStation);
setFavoriteStation(removedStation);
AS.setItem("favoriteStation", JSON.stringify(removedStation));
}}
>
{tail ? null : <Icon name="chevron-down" size={26} />}
</TouchableOpacity>
</View>
<View
style={{
alignContent: "center",
alignItems: "center",
alignSelf: "center",
}}
>
<Ionicons name={"reorder-two"} size={20} style={{ marginHorizontal: 10 }} />
</View>
</View>
);

View File

@@ -1,31 +1,58 @@
import React from "react";
import { View, Text, TouchableOpacity, ScrollView } from "react-native";
import React, { useCallback } from "react";
import { View, Text, StyleSheet } from "react-native";
import Animated, { useAnimatedRef } from "react-native-reanimated";
import { useNavigation } from "@react-navigation/native";
import Sortable from "react-native-sortables";
import { useFavoriteStation } from "../../stateBox/useFavoriteStation";
import { CheckBox } from "react-native-elements";
import { FavoriteSettingsItem } from "./FavoliteSettings/FavoiliteSettingsItem";
import { SheetHeaderItem } from "@/components/atom/SheetHeaderItem";
import { AS } from "@/storageControl";
export const FavoriteSettings = () => {
const { favoriteStation, setFavoriteStation } = useFavoriteStation();
const scrollableRef = useAnimatedRef();
const { goBack } = useNavigation();
const renderItem = useCallback((props) => {
const { item, index } = props;
return (
<FavoriteSettingsItem currentStation={item} key={item[0].StationNumber} />
);
}, []);
return (
<View style={{ height: "100%", backgroundColor: "#0099CC" }}>
<SheetHeaderItem
title="お気に入り設定"
LeftItem={{ title: " 設定", onPress: goBack }}
/>
<ScrollView style={{ flex: 1, backgroundColor: "white" }}>
{favoriteStation.map((currentStation, index, array) => (
<FavoriteSettingsItem
currentStation={currentStation}
setFavoriteStation={setFavoriteStation}
index={index}
array={array}
key={currentStation[0].StationNumber}
/>
))}
</ScrollView>
<Animated.ScrollView
style={{ flex: 1, backgroundColor: "white" }}
contentContainerStyle={styles.contentContainer}
ref={scrollableRef}
>
<Sortable.Grid
columnGap={0}
columns={1}
data={favoriteStation}
renderItem={renderItem}
rowGap={0}
scrollableRef={scrollableRef} // required for auto scroll
snapOffsetY={0}
onDragEnd={(newOrder) => {
const newFavoriteStation = newOrder.indexToKey.map(
(item, index, array) => {
let returnData = [];
favoriteStation.forEach((station) => {
if (station[0].StationNumber === item) returnData = station;
});
return returnData;
}
);
setFavoriteStation(newFavoriteStation);
AS.setItem("favoriteStation", JSON.stringify(newFavoriteStation));
}}
keyExtractor={(item) => item[0].StationNumber}
/>
</Animated.ScrollView>
<Text
style={{
backgroundColor: "white",
@@ -39,20 +66,19 @@ export const FavoriteSettings = () => {
);
};
const SimpleSwitch = ({ bool, setBool, str }) => (
<View style={{ flexDirection: "row" }}>
<CheckBox
checked={bool == "true" ? true : false}
checkedColor="red"
onPress={() => setBool(bool == "true" ? "false" : "true")}
containerStyle={{
flex: 1,
backgroundColor: "#00000000",
borderColor: "white",
alignContent: "center",
}}
textStyle={{ fontSize: 20, fontWeight: "normal" }}
title={str}
/>
</View>
);
const styles = StyleSheet.create({
card: {
alignItems: "center",
backgroundColor: "#36877F",
borderRadius: 10,
height: 100,
justifyContent: "center",
},
contentContainer: {
padding: 10,
},
text: {
color: "white",
fontWeight: "bold",
},
});

View File

@@ -18,6 +18,8 @@ export const LayoutSettings = ({
setUsePDFView,
trainMenu,
setTrainMenu,
uiSetting,
setUiSetting,
trainPosition,
setTrainPosition,
headerSize,
@@ -38,6 +40,17 @@ export const LayoutSettings = ({
falseText={"本家\n(文字アイコン)"}
trueText={"オリジナル\n(車種アイコン)"}
/>
<SwitchArea
str="列車表示"
bool={uiSetting}
setBool={setUiSetting}
falseImage={require("../../assets/configuration/layout_default.jpg")}
trueImage={require("../../assets/configuration/layout_tokyo.jpg")}
falseText={"本家"}
trueText={"オリジナル"}
falseValue="default"
trueValue="tokyo"
/>
<SwitchArea
str="トップメニュー表示"
bool={mapSwitch}

View File

@@ -17,7 +17,7 @@ import { SwitchArea } from "../atom/SwitchArea";
import { useNotification } from "../../stateBox/useNotifications";
import { SheetHeaderItem } from "@/components/atom/SheetHeaderItem";
const versionCode = "6.0";
const versionCode = "6.1.8"; // Update this version code as needed
export const SettingTopPage = ({
testNFC,

View File

@@ -14,9 +14,7 @@ import { createStackNavigator } from "@react-navigation/stack";
import { TransitionPresets } from "@react-navigation/stack";
//import * as ExpoFelicaReader from "../../modules/expo-felica-reader/src";
import * as Updates from "expo-updates";
import StatusbarDetect from "../../StatusbarDetect";
import { AS } from "../../storageControl";
var Status = StatusbarDetect();
import { Switch } from "react-native-elements";
import AutoHeightImage from "react-native-auto-height-image";
import { SettingTopPage } from "./SettingTopPage";
@@ -39,6 +37,7 @@ export default function Setting(props) {
const [trainPosition, setTrainPosition] = useState(false);
const [headerSize, setHeaderSize] = useState("default");
const [startPage, setStartPage] = useState(false);
const [uiSetting, setUiSetting] = useState("tokyo");
useLayoutEffect(() => {
AS.getItem("iconSwitch").then(setIconSetting);
AS.getItem("mapSwitch").then(setMapSwitch);
@@ -48,6 +47,7 @@ export default function Setting(props) {
AS.getItem("trainPositionSwitch").then(setTrainPosition);
AS.getItem("headerSize").then(setHeaderSize);
AS.getItem("startPage").then(setStartPage);
AS.getItem("uiSetting").then(setUiSetting);
}, []);
const testNFC = async () => {
//const result = await ExpoFelicaReader.scan();
@@ -63,6 +63,7 @@ export default function Setting(props) {
AS.setItem("trainPositionSwitch", trainPosition.toString()),
AS.setItem("headerSize", headerSize),
AS.setItem("startPage", startPage.toString()),
AS.setItem("uiSetting", uiSetting),
]).then(() => Updates.reloadAsync());
};
return (
@@ -114,6 +115,8 @@ export default function Setting(props) {
setTrainMenu={setTrainMenu}
trainPosition={trainPosition}
setTrainPosition={setTrainPosition}
uiSetting={uiSetting}
setUiSetting={setUiSetting}
testNFC={testNFC}
updateAndReload={updateAndReload}
headerSize={headerSize}

View File

@@ -0,0 +1,355 @@
import { FC, useRef, useState, useCallback, useEffect } from "react";
import {
View,
Text,
ScrollView,
useWindowDimensions,
Vibration,
} from "react-native";
import { ExGridViewItem } from "./ExGridViewItem";
import Animated, {
useAnimatedStyle,
useSharedValue,
runOnJS,
useAnimatedScrollHandler,
withTiming,
Easing,
FadeIn,
FadeOut,
BounceInUp,
FadeInUp,
FadeOutUp,
} from "react-native-reanimated";
import { Gesture, GestureDetector } from "react-native-gesture-handler";
import { ExGridViewTimePositionItem } from "./ExGridViewTimePositionItem";
import { useCurrentTrain } from "@/stateBox/useCurrentTrain";
import dayjs from "dayjs";
type hoge = {
trainNumber: string;
array: string;
name: string;
timeType: string;
time: string;
}[];
export const ExGridView: FC<{
data: hoge;
}> = ({ data }) => {
const groupedData: {
[d: number]: {
trainNumber: string;
array: string;
name: string;
timeType: string;
time: string;
isOperating: boolean;
}[];
} = {
"4": [],
"5": [],
"6": [],
"7": [],
"8": [],
"9": [],
"10": [],
"11": [],
"12": [],
"13": [],
"14": [],
"15": [],
"16": [],
"17": [],
"18": [],
"19": [],
"20": [],
"21": [],
"22": [],
"23": [],
"0": [],
"1": [],
"2": [],
"3": [],
};
const groupKeys = [
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"11",
"12",
"13",
"14",
"15",
"16",
"17",
"18",
"19",
"20",
"21",
"22",
"23",
"0",
"1",
"2",
"3",
];
const { width } = useWindowDimensions();
const { currentTrain } = useCurrentTrain();
data.forEach((item) => {
let isOperating = false;
let [hour, minute] = dayjs()
.hour(parseInt(item.time.split(":")[0]))
.minute(parseInt(item.time.split(":")[1]))
.format("H:m")
.split(":");
if (currentTrain.findIndex((x) => x.num == item.trainNumber) != -1) {
const currentTrainTime = currentTrain.find(
(x) => x.num == item.trainNumber
)?.delay;
if (currentTrainTime != "入線") {
[hour, minute] = dayjs()
.hour(parseInt(hour))
.minute(parseInt(minute))
.add(parseInt(currentTrainTime), "minute")
.format("H:m")
.split(":");
}
isOperating = true;
}
groupedData[hour].push({ ...item, time: `${hour}:${minute}`, isOperating });
});
// ドラッグ位置を保持する共有値
const widthX = useSharedValue(width);
const savedWidthX = useSharedValue(width);
const isChanging = useSharedValue(false);
const [scrollEnabled, setScrollEnabled] = useState(true);
const scrollRef = useRef<Animated.ScrollView>(null);
const scrollRef2 = useRef<Animated.ScrollView>(null);
// ScrollViewの有効/無効を切り替える関数
const toggleScrollEnabled = useCallback((enabled: boolean) => {
setScrollEnabled(enabled);
}, []);
// パンジェスチャー(ドラッグ)のハンドラー
const pinchGesture = Gesture.Pinch()
.onUpdate((e) => {
const calc = savedWidthX.value * e.scale;
widthX.value = calc > width ? calc : width;
//runOnJS(scrollToRightEnd)();
})
.onEnd(() => {
savedWidthX.value = widthX.value;
});
const gesture = Gesture.Pan()
.minPointers(2) // 最低2本指
.maxPointers(2) // 最大2本指
.onStart(() => {
runOnJS(toggleScrollEnabled)(false);
})
.onEnd(() => {
runOnJS(toggleScrollEnabled)(true);
savedWidthX.value = widthX.value;
});
const longPressGesture = Gesture.Pan()
.minPointers(1)
.maxPointers(1)
.activateAfterLongPress(200)
.onStart(() => {
runOnJS(Vibration.vibrate)(30);
isChanging.value = true;
})
.onUpdate((e) => {
const calc = widthX.value + e.velocityY;
widthX.value = calc > width ? calc : width;
})
.onEnd(() => {
console.log("Long press ended");
isChanging.value = false;
});
// ジェスチャーを組み合わせる
const composed = Gesture.Simultaneous(
longPressGesture,
pinchGesture,
gesture
);
// アニメーションスタイル
const animatedStyle = useAnimatedStyle(() => ({
width: widthX.value,
backgroundColor: isChanging.value ? "#8adeffff" : "white",
}));
// 時ヘッダーを横にスクロールしたときの処理
const scrollX = useSharedValue(0);
const scrollHandler = useAnimatedScrollHandler({
onScroll: (event) => {
scrollX.value = event.contentOffset.x;
},
});
const stickyTextStyle = useAnimatedStyle(() => ({
transform: [{ translateX: scrollX.value }],
}));
const animatedLongPressStyle = useAnimatedStyle(() => ({
display: isChanging.value ? "flex" : "none",
}));
useEffect(() => {
const getCurrentTime = dayjs().hour();
setTimeout(() => {
const keyTime =
getCurrentTime - 4 <= 0 ? getCurrentTime + 24 : getCurrentTime;
const goTo = keyTime * 60;
if (goTo > 400) {
scrollRef2.current?.scrollTo({ y: goTo - 300, animated: true });
}
}, 400);
}, [scrollRef2]);
return (
<>
<Animated.View
style={[
{
position: "absolute",
width,
backgroundColor: "#26d1baff",
zIndex: 500,
top: 0,
},
animatedLongPressStyle,
]}
entering={FadeInUp}
exiting={FadeOutUp}
>
<Text style={{ fontSize: 30, textAlign: "center", flex: 1 }}>
  
</Text>
</Animated.View>
<GestureDetector gesture={composed}>
<Animated.ScrollView
horizontal
nestedScrollEnabled
pinchGestureEnabled={false}
scrollEnabled={scrollEnabled}
onScroll={scrollHandler}
onContentSizeChange={(contentWidth) => {
// 現在のスクロール位置を取得
const currentScrollX = scrollX.value;
const containerWidth = width - 50;
// コンテンツが画面からはみ出している場合のみ右端にスクロール
if (currentScrollX + containerWidth > contentWidth) {
const newScrollX = Math.max(0, contentWidth - containerWidth);
scrollRef.current?.scrollTo({ x: newScrollX, animated: true });
}
}}
ref={scrollRef}
contentContainerStyle={{
flexDirection: "column",
backgroundColor: "white",
}}
>
<Animated.View
style={[
{
width: width,
flexDirection: "row",
},
animatedStyle,
]}
>
{Array.from({ length: 60 }, (_, i) => i + 1).map((num) => {
if (num % 5 === 0) {
return (
<Text
key={num + "ExGridViewTimeLabel"}
style={{
flex: 1,
textAlign: "left",
borderRightWidth: 0.5,
borderColor: "#ccc",
flexWrap: "nowrap",
fontSize: 12,
}}
>
{num - 5}
</Text>
);
} else return <></>;
})}
<Text
style={{
textAlign: "right",
borderRightWidth: 0.5,
borderColor: "#ccc",
flexWrap: "nowrap",
fontSize: 12,
width: 50,
}}
>
()
</Text>
</Animated.View>
<Animated.ScrollView
style={[{ width: width }, animatedStyle]}
pinchGestureEnabled={false}
minimumZoomScale={0.5}
maximumZoomScale={3.0}
scrollEnabled={scrollEnabled}
stickyHeaderIndices={
groupKeys.at(0) ? groupKeys.map((_, i) => i * 2) : []
}
ref={scrollRef2}
>
{groupKeys.map((hour) => [
<View
style={{
padding: 5,
borderBottomWidth: 0.5,
borderTopWidth: 0.5,
borderBottomColor: "#ccc",
backgroundColor: "#f0f0f0",
}}
key={hour}
>
<Animated.Text
style={[
{
fontSize: 15,
zIndex: 1,
marginLeft: 0,
},
stickyTextStyle,
]}
>
{hour}
</Animated.Text>
</View>,
<View
style={{
flexDirection: "row",
position: "relative",
height: 50,
}}
>
{groupedData[hour].map((d, i, array) => (
<ExGridViewItem
key={d.trainNumber + i}
d={d}
index={i}
width={widthX}
array={array}
/>
))}
<ExGridViewTimePositionItem width={widthX} hour={hour} />
</View>,
])}
</Animated.ScrollView>
</Animated.ScrollView>
</GestureDetector>
</>
);
};

View File

@@ -0,0 +1,254 @@
import { migrateTrainName } from "@/lib/eachTrainInfoCoreLib/migrateTrainName";
import { getStringConfig } from "@/lib/getStringConfig";
import { getTrainType } from "@/lib/getTrainType";
import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram";
import { FC, useEffect, useLayoutEffect, useMemo, useState } from "react";
import {
View,
Text,
TouchableOpacity,
useWindowDimensions,
} from "react-native";
import { customTrainDataDetector } from "../custom-train-data";
import dayjs from "dayjs";
import { SheetManager } from "react-native-actions-sheet";
import { useNavigation } from "@react-navigation/native";
import { lineList } from "@/lib/getStationList";
import { useStationList } from "@/stateBox/useStationList";
import { SharedValue, useAnimatedStyle } from "react-native-reanimated";
import Animated from "react-native-reanimated";
import lineColorList from "@/assets/originData/lineColorList";
import { CustomTrainData, trainTypeID } from "@/lib/CommonTypes";
export const ExGridViewItem: FC<{
d: {
trainNumber: string;
array: string;
name: string;
timeType: string;
time: string;
isOperating: boolean;
};
index: number;
width: SharedValue<number>;
array: {
train: string;
lastStation: string;
time: string;
isThrough?: boolean;
}[];
}> = ({ d, index, width, array }) => {
const { allCustomTrainData } = useAllTrainDiagram();
const { originalStationList, stationList } = useStationList();
const { navigate, goBack } = useNavigation();
const [trainData, setTrainData] = useState<CustomTrainData>();
useEffect(() => {
if (allCustomTrainData) {
allCustomTrainData.forEach((x) => {
if (x.TrainNumber === d.trainNumber) {
setTrainData(x);
}
});
}
}, []);
const { color, name, data } = getTrainType({ type: trainData?.type, whiteMode: true });
// 列車名、種別、フォントの取得
const [
typeString,
trainName,
fontAvailable,
isOneMan,
infogram,
isEdit,
uwasa,
vehicleFormation,
trainInfoUrl,
] = useMemo(() => {
const {
type,
trainName,
trainNumDistance,
infogram,
isEdit,
uwasa,
vehicleFormation,
trainInfoUrl,
} = customTrainDataDetector(d.trainNumber, allCustomTrainData);
const [typeString, fontAvailable, isOneMan] = getStringConfig(
type,
d.trainNumber
);
const trainData = d.array.split("#").filter((d) => d !== "");
switch (true) {
case trainData[trainData.length - 1] === undefined:
return [
typeString,
"",
fontAvailable,
isOneMan,
infogram,
isEdit,
uwasa,
vehicleFormation,
trainInfoUrl,
];
default:
// 行先がある場合は、行先を取得
const trainName = (d.timeType == "着" || d.timeType == "着編") ? trainData[0].split(",")[0] : trainData[trainData.length - 1].split(",")[0]
return [
typeString,
migrateTrainName(trainName),
fontAvailable,
isOneMan,
infogram,
isEdit,
uwasa,
vehicleFormation,
trainInfoUrl,
];
}
}, [d.array]);
const timeArray = d.time.split(":").map((s) => parseInt(s));
const formattedTime = dayjs()
.set("hour", timeArray[0])
.set("minute", timeArray[1])
.format("m");
let isSameTimeBefore = false;
if (index > 0) {
const beforeItem = array[index - 1];
const beforeTimeArray = beforeItem.time.split(":").map((s) => parseInt(s));
const beforeFormattedTime = dayjs()
.set("hour", beforeTimeArray[0])
.set("minute", beforeTimeArray[1])
.format("m");
isSameTimeBefore = beforeFormattedTime === formattedTime;
}
const openStationACFromEachTrainInfo = async (stationName) => {
await SheetManager.hide("EachTrainInfo");
const findStationEachLine = (selectLine) => {
let NearStation = selectLine.filter((d) => d.Station_JP == stationName);
return NearStation;
};
let returnDataBase = lineList
.map((d) => findStationEachLine(originalStationList[d]))
.filter((d) => d.length > 0)
.reduce((pre, current) => {
pre.push(...current);
return pre;
}, []);
if (returnDataBase.length) {
const payload = {
currentStation: returnDataBase,
navigate,
//@ts-ignore
useShow: () => SheetManager.show("StationDetailView", { payload }),
onExit: () => SheetManager.hide("StationDetailView"),
}; //@ts-ignore
setTimeout(() => SheetManager.show("StationDetailView", { payload }), 50);
} else {
SheetManager.hide("StationDetailView");
}
};
const openTrainInfo = () => {
let TrainNumber = "";
if (trainData.trainNumDistance != undefined) {
const timeInfo =
parseInt(trainData.TrainNumber.replace("M", "").replace("D", "")) -
trainData.trainNumDistance;
TrainNumber = timeInfo + "号";
}
const payload = {
data: {
trainNum: trainData.TrainNumber,
limited: `${data}:${trainData.trainName}${TrainNumber}`,
},
navigate,
openStationACFromEachTrainInfo,
from: d.isOperating ? null :"AllTrainIDList",
};
SheetManager.show("EachTrainInfo", {
//@ts-ignore
payload,
onClose: (data) => {
//alert(data);
},
});
};
const [stationColor, setStationColor] = useState(["gray"]);
useEffect(() => {
const Stations = stationList
.map((a) => a.filter((d) => d.StationName == trainName))
.reduce((newArray, e) => newArray.concat(e), []);
const StationNumbers =
Stations &&
Stations.filter((d) => d.StationNumber).map((d) => d.StationNumber);
if (StationNumbers) {
const stationLineColor = StationNumbers.map(
(d) => lineColorList[d.charAt(0)]
);
setStationColor(stationLineColor || ["gray"]);
}
}, [stationList]);
// if(typeString == "回送"){
// return<></>;
// }
const animatedStyle = useAnimatedStyle(() => {
const leftPosition =
((((width.value - 50) / 100) * parseInt(formattedTime)) / 60) * 100;
return {
left: leftPosition,
};
}, [formattedTime]);
return (
<View style={{ left: 0, height: 50 }}>
<Animated.View
style={[
{
flexDirection: "column",
//borderTopWidth: 1,
//borderBottomWidth: 0.5,
borderStyle: "solid",
borderColor: "darkgray",
opacity: d.timeType.includes("通") ? 0.5 : 1,
position: "absolute",
height: "100%",
width: 28,
top: isSameTimeBefore ? 10 : 0,
},
animatedStyle,
]}
>
<TouchableOpacity style={{ flex: 1 }} onPress={() => openTrainInfo()}>
<View style={{ position: "relative" }}>
<Text style={{ fontSize: 20, color: color, opacity: isSameTimeBefore ? 0 : 1, fontWeight:d.isOperating ? "bold" : "thin", fontStyle:d.isOperating? "italic" :"normal" }}>{formattedTime}</Text>
<Text
style={{
fontSize: 10,
position: "absolute",
bottom: 0,
right: 0,
fontWeight: "bold",
}}
>
{d.timeType}
</Text>
</View>
<View style={{ flex: 1, flexDirection: "column" }}>
<Text
style={{
fontSize: 8,
flex: 1,
fontWeight: "bold",
color: stationColor[0],
}}
>
{trainName}
</Text>
</View>
</TouchableOpacity>
</Animated.View>
</View>
);
};

View File

@@ -0,0 +1,44 @@
import { FC } from "react";
import { View } from "react-native";
import dayjs from "dayjs";
import { SharedValue, useAnimatedStyle } from "react-native-reanimated";
import Animated from "react-native-reanimated";
export const ExGridViewTimePositionItem: FC<{
width: SharedValue<number>;
hour: string;
}> = ({ width, hour }) => {
const date = dayjs();
const formattedTime = date.format("m");
const formattedHour = date.format("H");
// if(typeString == "回送"){
// return<></>;
// }
const animatedStyle = useAnimatedStyle(() => {
const leftPosition =
((((width.value - 50) / 100) * parseInt(formattedTime)) / 60) * 100;
return {
left: leftPosition,
};
}, [formattedTime]);
if (formattedHour != hour) return <></>;
return (
<View style={{ left: 0, height: 50, width: 1 }}>
<Animated.View
style={[
{
flexDirection: "column",
borderLeftWidth: 2,
//borderBottomWidth: 0.5,
borderStyle: "solid",
borderColor: "red",
position: "absolute",
height: "100%",
},
animatedStyle,
]}
/>
</View>
);
};

View File

@@ -0,0 +1,43 @@
import { FC } from "react";
import { ListViewItem } from "@/components/StationDiagram/ListViewItem";
import { View, Text, ScrollView } from "react-native";
type hoge = {
trainNumber: string;
array: string;
name: string;
timeType: string;
time: string;
};
export const ListView: FC<{
data: hoge[];
}> = ({ data }) => {
const groupedData: Record<string, hoge[]> = {};
const groupKeys = [];
data.forEach((item) => {
const hour = item.time.split(":")[0];
if (!groupedData[hour]) {
groupedData[hour] = [];
groupKeys.push(hour);
}
groupedData[hour].push(item);
});
return (
<ScrollView
style={{ backgroundColor: "white" }}
stickyHeaderIndices={
groupKeys.at(0) ? groupKeys.map((_, i) => i * 2) : []
}
>
{groupKeys.map((hour) => [
<View style={{ backgroundColor: "white", padding: 5, borderBottomWidth: 0.5, borderTopWidth: 0.5, borderBottomColor: "#ccc" }} key={hour}>
<Text style={{ fontSize: 15 }}>{hour}</Text>
</View>,
<View>
{groupedData[hour].map((d, i) => (
<ListViewItem key={d.trainNumber + i} d={d} />
))}
</View>,
])}
</ScrollView>
);
};

View File

@@ -0,0 +1,247 @@
import { migrateTrainName } from "@/lib/eachTrainInfoCoreLib/migrateTrainName";
import { getStringConfig } from "@/lib/getStringConfig";
import { getTrainType } from "@/lib/getTrainType";
import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram";
import { FC, useEffect, useMemo, useState } from "react";
import { View, Text, TouchableOpacity } from "react-native";
import { customTrainDataDetector } from "../custom-train-data";
import dayjs from "dayjs";
import { SheetManager } from "react-native-actions-sheet";
import { useNavigation } from "@react-navigation/native";
import { lineList } from "@/lib/getStationList";
import { useStationList } from "@/stateBox/useStationList";
import { CustomTrainData, trainTypeID } from "@/lib/CommonTypes";
import { StationNumberMaker } from "../駅名表/StationNumberMaker";
import { getStationID } from "@/lib/eachTrainInfoCoreLib/getStationData";
import lineColorList from "@/assets/originData/lineColorList";
export const ListViewItem: FC<{
d: {
trainNumber: string;
array: string;
name: string;
timeType: string;
time: string;
};
}> = ({ d }) => {
const { allCustomTrainData } = useAllTrainDiagram();
const { navigate, goBack } = useNavigation();
const [trainData, setTrainData] = useState<CustomTrainData>();
useEffect(() => {
if (allCustomTrainData) {
allCustomTrainData.forEach((x) => {
if (x.TrainNumber === d.trainNumber) {
setTrainData(x);
}
});
}
}, []);
const { color, name, data } = getTrainType({
type: trainData?.type,
whiteMode: true,
});
// 列車名、種別、フォントの取得
const { getStationDataFromName, stationList, originalStationList } =
useStationList();
const [
typeString,
trainName,
fontAvailable,
isOneMan,
infogram,
isEdit,
uwasa,
vehicleFormation,
trainInfoUrl,lineColor
] = useMemo(() => {
const {
type,
trainName,
trainNumDistance,
infogram,
isEdit,
uwasa,
vehicleFormation,
trainInfoUrl,
} = customTrainDataDetector(d.trainNumber, allCustomTrainData);
const [typeString, fontAvailable, isOneMan] = getStringConfig(
type,
d.trainNumber
);
const trainData = d.array.split("#").filter((d) => d !== "");
const station = getStationDataFromName(trainData[trainData.length - 1].split(",")[0]);
const lineColor =
station.length > 0
? lineColorList[station[0]?.StationNumber.slice(0, 1)]
: "black";
switch (true) {
case trainData[trainData.length - 1] === undefined:
return [
typeString,
"",
fontAvailable,
isOneMan,
infogram,
isEdit,
uwasa,
vehicleFormation,
trainInfoUrl,lineColor
];
default:
// 行先がある場合は、行先を取得
return [
typeString,
migrateTrainName(
trainData[trainData.length - 1].split(",")[0] + "行き"
),
fontAvailable,
isOneMan,
infogram,
isEdit,
uwasa,
vehicleFormation,
trainInfoUrl,lineColor
];
}
}, [d.array]);
const timeArray = d.time.split(":").map((s) => parseInt(s));
const formattedTime = dayjs()
.set("hour", timeArray[0])
.set("minute", timeArray[1])
.format("HH:mm");
const openStationACFromEachTrainInfo = async (stationName) => {
await SheetManager.hide("EachTrainInfo");
const findStationEachLine = (selectLine) => {
let NearStation = selectLine.filter((d) => d.Station_JP == stationName);
return NearStation;
};
let returnDataBase = lineList
.map((d) => findStationEachLine(originalStationList[d]))
.filter((d) => d.length > 0)
.reduce((pre, current) => {
pre.push(...current);
return pre;
}, []);
if (returnDataBase.length) {
const payload = {
currentStation: returnDataBase,
navigate,
//@ts-ignore
useShow: () => SheetManager.show("StationDetailView", { payload }),
onExit: () => SheetManager.hide("StationDetailView"),
}; //@ts-ignore
setTimeout(() => SheetManager.show("StationDetailView", { payload }), 50);
} else {
SheetManager.hide("StationDetailView");
}
};
const openTrainInfo = () => {
let TrainNumber = "";
if (trainData.trainNumDistance != undefined) {
const timeInfo =
parseInt(trainData.TrainNumber.replace("M", "").replace("D", "")) -
trainData.trainNumDistance;
TrainNumber = timeInfo + "号";
}
const payload = {
data: {
trainNum: trainData.TrainNumber,
limited: `${data}:${trainData.trainName}${TrainNumber}`,
},
navigate,
openStationACFromEachTrainInfo,
from: "AllTrainIDList",
};
SheetManager.show("EachTrainInfo", {
//@ts-ignore
payload,
onClose: (data) => {
//alert(data);
},
});
};
return (
<TouchableOpacity
style={{
flexDirection: "row",
marginHorizontal: 10,
borderTopWidth: 1,
borderBottomWidth: 0.5,
borderStyle: "solid",
borderColor: "darkgray",
padding: 10,
opacity: d.timeType?.includes("通") ? 0.5 : 1,
}}
onPress={() => openTrainInfo()}
>
<View style={{ position: "relative", flex: 3 }}>
<Text style={{ fontSize: 30, fontFamily: "DiaPro" }}>
{formattedTime}
</Text>
<Text
style={{
fontSize: 10,
position: "absolute",
bottom: -3,
right: 0,
fontWeight: "bold",
}}
>
{d.timeType}
</Text>
</View>
<View style={{ flex: 10, flexDirection: "column" }}>
<View style={{ flexDirection: "row" }}>
<Text
style={{
fontSize: 15,
fontFamily: fontAvailable ? "JR-Nishi" : undefined,
fontWeight: !fontAvailable ? "bold" : undefined,
paddingTop: fontAvailable ? 2 : 0,
paddingLeft: 10,
color: color,
}}
>
{typeString}
</Text>
<Text
style={{
fontSize: 15,
fontWeight: "bold",
flex: 1,
paddingLeft: 2,
color: color,
}}
>
{trainData?.trainName +
(trainData?.trainNumDistance !== null
? ` ${parseInt(d.trainNumber) - trainData?.trainNumDistance}`
: "")}
</Text>
<Text
style={{
fontSize: 15,
fontWeight: "bold",
}}
>
{trainData?.TrainNumber}
</Text>
</View>
<View style={{ flexDirection: "row", alignItems: "center", flex: 1 }}>
<Text
style={{
fontSize: 15,
flex: 1,
paddingHorizontal: 10,
fontWeight: "bold",
color: lineColor
}}
>
{trainName}
</Text>
</View>
</View>
</TouchableOpacity>
);
};

View File

@@ -0,0 +1,164 @@
import lineColorList from "@/assets/originData/lineColorList";
import { useStationList } from "@/stateBox/useStationList";
import { FC, useEffect, useState } from "react";
import {
View,
Text,
ScrollView,
TouchableOpacity,
LayoutAnimation,
} from "react-native";
type hoge = {
trainNumber: string;
array: string;
name: string;
timeType: string;
time: string;
}[];
export const SearchInputSuggestBox: FC<{
input: string;
setInput: (f: string) => void;
currentStationDiagram: hoge;
}> = ({ input, setInput, currentStationDiagram }) => {
const { getStationDataFromName } = useStationList();
const [stationList, setStationList] = useState<
{
stationName: string;
number: string[];
}[]
>([]);
const [listFiltered, setListFiltered] = useState<string>("");
const [filteredStationLine, setFilteredStationLine] = useState<string[]>([]);
useEffect(() => {
const x: { stationName: string; number: string[] }[] = [];
currentStationDiagram.forEach((d) => {
d.array.split("#").forEach((s) => {
if (s == "") return;
const [stationName, type, time] = s.split(",");
if (!x.find((item) => item.stationName === stationName)) {
if (!type?.includes("通")) {
const stationData = getStationDataFromName(stationName);
if (listFiltered === "その他") {
if (stationData.length === 0) {
x.push({
stationName,
number: stationData.map((item) => item.StationNumber),
});
return;
}
}
const filter = stationData.filter((s) => {
if (listFiltered === "") return true;
if (listFiltered === "その他") {
return !(
s.StationNumber ? s.StationNumber.slice(0, 1) : ""
).match(/[A-Z]/);
}
return (
s.StationNumber ? s.StationNumber.slice(0, 1) : ""
).includes(listFiltered);
});
if (filter.length === 0) return;
x.push({
stationName,
number: stationData.map((item) => item.StationNumber),
});
}
}
});
});
setStationList(x);
}, [currentStationDiagram, listFiltered]);
useEffect(() => {
const filtered = stationList
.map((s) => s.number?.map((r) => (r ? r.slice(0, 1) : "")))
.flat();
const arrayB = Array.from(new Set(filtered));
setFilteredStationLine(arrayB.map((r) => (r !== "" ? r : "その他")));
}, [stationList]);
return (
<View
style={{
maxHeight: 200,
width: "100%",
backgroundColor: "#0099CC",
zIndex: 100,
}}
>
<Text>{input}</Text>
<ScrollView keyboardShouldPersistTaps="handled">
<View style={{ flexDirection: "row", flexWrap: "wrap" }}>
{stationList.map(({ stationName, number }) => (
<TouchableOpacity
style={{
margin: 5,
padding: 5,
backgroundColor: "#eee",
borderRadius: 20,
}}
key={stationName + number.join(",")}
onPress={() => setInput(stationName)}
>
<Text>{stationName}</Text>
</TouchableOpacity>
))}
</View>
</ScrollView>
<View
style={{
flexDirection: "row",
flexWrap: "wrap",
borderTopColor: "#ccc",
borderTopWidth: 0.5,
paddingTop: 0,
marginTop: 10,
}}
>
<TouchableOpacity
style={{
margin: 5,
padding: 5,
backgroundColor: "#eee",
borderRadius: 5,
}}
key={"empty"}
onPress={() => {
LayoutAnimation.configureNext({
duration: 400,
update: { type: "easeInEaseOut", springDamping: 0.6 },
});
setListFiltered("");
}}
>
<Text></Text>
</TouchableOpacity>
{filteredStationLine.map((line) => (
<TouchableOpacity
style={{
margin: 5,
padding: 5,
backgroundColor: lineColorList[line]
? `${lineColorList[line]}`
: "#eee",
borderRadius: 5,
}}
key={line}
onPress={() => {
LayoutAnimation.configureNext({
duration: 400,
update: { type: "easeInEaseOut", springDamping: 0.6 },
});
setListFiltered(line);
}}
>
<Text style={{ color: lineColorList[line] ? `white` : "black" }}>
{line}
</Text>
</TouchableOpacity>
))}
</View>
</View>
);
};

View File

@@ -0,0 +1,509 @@
import { FC, useEffect, useState } from "react";
import {
View,
Text,
ScrollView,
TextInput,
Keyboard,
KeyboardAvoidingView,
Platform,
TouchableOpacity,
LayoutAnimation,
} from "react-native";
import { useNavigation } from "@react-navigation/native";
import { BigButton } from "../atom/BigButton";
import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram";
import { ListView } from "@/components/StationDiagram/ListView";
import dayjs from "dayjs";
import { ExGridView } from "./ExGridView";
import { Switch } from "react-native-elements";
import { customTrainDataDetector } from "../custom-train-data";
import { getTrainType } from "@/lib/getTrainType";
import { trainTypeID } from "@/lib/CommonTypes";
import { SearchInputSuggestBox } from "./SearchBox/SearchInputSuggestBox";
type props = {
route: {
params: {
currentStation: {
Station_JP: string;
Station_EN: string;
StationName?: string;
MyStation?: string;
StationNumber: string;
DispNum?: string;
StationTimeTable: string;
StationMap?: string;
JrHpUrl?: string;
lat: number;
lng: number;
jslodApi: string;
}[];
};
};
};
export const StationDiagramView: FC<props> = ({ route }) => {
if (!route.params) {
return null;
}
const { currentStation } = route.params;
// 必要な情報:駅情報、全ダイヤ、カスタム列車情報
// 表示モード:縦並びリスト、横並びグリッド(時刻分割)、横並び単純左詰め
// フィルタリング:終点路線、種別、行先、関係停車駅
const { keyList, allTrainDiagram, allCustomTrainData } = useAllTrainDiagram();
const { navigate, addListener, goBack, canGoBack } = useNavigation();
const [keyBoardVisible, setKeyBoardVisible] = useState(false);
const [input, setInput] = useState("");
const [displayMode, setDisplayMode] = useState<"list" | "grid">("list");
const [selectedTypeList, setSelectedTypeList] = useState<trainTypeID[]>([
"Normal",
"OneMan",
"Rapid",
"OneManRapid",
"LTDEXP",
"NightLTDEXP",
]);
type hoge = {
trainNumber: string;
array: string;
name: string;
timeType: string;
time: string;
}[];
const [showTypeFiltering, setShowTypeFiltering] = useState(false);
const [showLastStop, setShowLastStop] = useState(false);
const [threw, setIsThrew] = useState(false);
const [currentStationDiagram, setCurrentStationDiagram] = useState<hoge>([]);
useEffect(() => {
if (allTrainDiagram && currentStation.length > 0) {
const stationName = currentStation[0].Station_JP;
let returnDataArray: hoge = [];
keyList
.filter((s) => {
const boolData = allTrainDiagram[s];
let isStop = false;
let isStopPos = -1;
let isInput = false;
let isInputPos = -1;
boolData.split("#").forEach((d, index, array) => {
const [station, type, time] = d.split(",");
if (station === stationName) {
isStop = true;
isStopPos = index;
}
if (station === input && type && !type.includes("通")) {
isInput = true;
isInputPos = index;
}
});
if (input && input.length > 0) {
if (isInput && isStop) {
return isInputPos > isStopPos;
}
return false;
}
return isStop;
})
.forEach((d) => {
allTrainDiagram[d]
.split("#")
.filter((d) => {
const [station, type, time] = d.split(",");
return station === stationName;
})
.forEach((x) => {
const [name, timeType, time] = x.split(",");
if (!name || !timeType || !time) return;
const { img, trainName, type, trainNumDistance, infogram } =
customTrainDataDetector(d, allCustomTrainData);
const arrayData = {
trainNumber: d,
array: allTrainDiagram[d],
name,
timeType,
time,
};
// //条件によってフィルタリング
if (!threw && timeType && timeType.includes("通")) return;
if (!showLastStop && timeType && timeType.includes("着")) return;
if (
selectedTypeList.findIndex((item) => item === "SPCL") === -1
) {
if (d.match(/9\d\d\d[D,M,S]/)) return;
}
if (
selectedTypeList.length > 0 &&
selectedTypeList.findIndex((item) => item === type) === -1
) {
if (
selectedTypeList.findIndex(
(item) => item === "Forwarding"
) !== -1
) {
if (!d.match(/[A,B,R,H,E,T,L]/)) return;
} else if (
selectedTypeList.findIndex((item) => item === "SPCL") !== -1
) {
if (!d.match(/9\d\d\d[D,M,S]/)) return;
} else {
return;
}
}
returnDataArray.push(arrayData);
});
});
setCurrentStationDiagram(
returnDataArray.sort((a, b) => {
const adjustTime = (t: string) => {
const [h, m] = t.split(":").map(Number);
// 4時未満は翌日の時刻とみなして+24時間
return h < 4
? dayjs().add(1, "day").hour(h).minute(m)
: dayjs().hour(h).minute(m);
};
const aa = adjustTime(a.time);
const bb = adjustTime(b.time);
const x = aa.isAfter(bb);
return x ? 1 : -1;
//return true;
})
);
}
}, [currentStation, showLastStop, threw, input, selectedTypeList]);
useEffect(() => {
const showSubscription = Keyboard.addListener("keyboardDidShow", () => {
LayoutAnimation.configureNext({
duration: 600,
update: { type: "spring", springDamping: 0.6 },
});
setKeyBoardVisible(true);
});
const hideSubscription = Keyboard.addListener("keyboardDidHide", () => {
LayoutAnimation.configureNext({
duration: 600,
update: { type: "spring", springDamping: 0.6 },
});
setKeyBoardVisible(false);
});
return () => {
showSubscription.remove();
hideSubscription.remove();
};
}, []);
return (
<View style={{ height: "100%", backgroundColor: "#0099CC" }}>
<Text
style={{
textAlign: "center",
fontSize: 20,
color: "white",
fontWeight: "bold",
paddingVertical: 10,
}}
>
{currentStation[0].Station_JP}
</Text>
{displayMode === "list" ? (
<ListView data={currentStationDiagram} />
) : (
<ExGridView data={currentStationDiagram} />
)}
{/* <Text
style={{
backgroundColor: "white",
borderWidth: 1,
borderStyle: "solid",
}}
>
お気に入り登録した駅のうち、位置情報システムで移動可能な駅が表示されています。タップすることで位置情報システムの当該の駅に移動します。
</Text> */}
<KeyboardAvoidingView
behavior="padding"
keyboardVerticalOffset={80}
enabled={Platform.OS === "ios"}
>
{!keyBoardVisible ? (
<ScrollView
horizontal
style={{
height: 35,
flexDirection: "row",
display: "flex",
}}
>
<TouchableOpacity
style={{
alignItems: "center",
marginHorizontal: 5,
backgroundColor: threw ? "white" : "#ffffff00",
alignSelf: "center",
borderColor: "white",
borderWidth: 1,
borderRadius: 100,
}}
onPress={() => {
setIsThrew(!threw);
}}
>
<Text
style={{
color: threw ? "#0099CC" : "white",
fontSize: 14,
margin: 5,
}}
>
</Text>
</TouchableOpacity>
<TouchableOpacity
style={{
alignItems: "center",
marginHorizontal: 5,
backgroundColor: showLastStop ? "white" : "#ffffff00",
alignSelf: "center",
borderColor: "white",
borderWidth: 1,
borderRadius: 100,
}}
onPress={() => {
setShowLastStop(!showLastStop);
}}
>
<Text
style={{
color: showLastStop ? "#0099CC" : "white",
fontSize: 14,
margin: 5,
}}
>
</Text>
</TouchableOpacity>
<View
style={{
height: "auto",
borderLeftWidth: 1,
margin: 5,
borderColor: "white",
}}
/>
{showTypeFiltering ? (
<>
<TypeSelectorBox
selectedTypeList={selectedTypeList}
setSelectedTypeList={setSelectedTypeList}
typeID="Normal"
relativeID={["OneMan"]}
/>
<TypeSelectorBox
selectedTypeList={selectedTypeList}
setSelectedTypeList={setSelectedTypeList}
typeID="Rapid"
relativeID={["OneManRapid"]}
/>
<TypeSelectorBox
selectedTypeList={selectedTypeList}
setSelectedTypeList={setSelectedTypeList}
typeID="LTDEXP"
relativeID={["NightLTDEXP"]}
/>
<TypeSelectorBox
selectedTypeList={selectedTypeList}
setSelectedTypeList={setSelectedTypeList}
typeID="SPCL"
relativeID={[
"SPCL_Normal",
"SPCL_Rapid",
"SPCL_EXP",
"Party",
]}
/>
<TypeSelectorBox
selectedTypeList={selectedTypeList}
setSelectedTypeList={setSelectedTypeList}
typeID="Freight"
/>
<TypeSelectorBox
selectedTypeList={selectedTypeList}
setSelectedTypeList={setSelectedTypeList}
typeID="Forwarding"
relativeID={["FreightForwarding"]}
/>
<TouchableOpacity
style={{
alignItems: "center",
marginHorizontal: 5,
backgroundColor: "#ffffff00",
alignSelf: "center",
borderColor: "white",
borderWidth: 1,
borderRadius: 100,
}}
onPress={() => {
LayoutAnimation.configureNext(
LayoutAnimation.Presets.easeInEaseOut
);
setShowTypeFiltering(false);
}}
>
<Text
style={{
color: "white",
fontSize: 14,
margin: 5,
}}
>
</Text>
</TouchableOpacity>
</>
) : (
<TouchableOpacity
style={{
alignItems: "center",
marginHorizontal: 5,
backgroundColor: "#ffffff00",
alignSelf: "center",
borderColor: "white",
borderWidth: 1,
borderRadius: 100,
}}
onPress={() => {
LayoutAnimation.configureNext(
LayoutAnimation.Presets.easeInEaseOut
);
setShowTypeFiltering(true);
}}
>
<Text
style={{
color: "white",
fontSize: 14,
margin: 5,
}}
>
</Text>
</TouchableOpacity>
)}
<TouchableOpacity
style={{
alignItems: "center",
marginHorizontal: 5,
backgroundColor: "#ffffff00",
alignSelf: "center",
borderColor: "white",
borderWidth: 1,
borderRadius: 100,
}}
onPress={() => {
setDisplayMode(displayMode === "list" ? "grid" : "list");
}}
>
<Text
style={{
color: "white",
fontSize: 14,
margin: 5,
}}
>
{displayMode === "list" ? "横並びモード" : "リストモード"}
</Text>
</TouchableOpacity>
</ScrollView>
) : (
<View style={{ position: "relative", display: "flex" }}>
<SearchInputSuggestBox
input={input}
setInput={setInput}
currentStationDiagram={currentStationDiagram}
/>
</View>
)}
<View
style={{
height: 35,
margin: 5,
alignItems: "center",
backgroundColor: "#F4F4F4",
flexDirection: "row",
paddingLeft: 10,
paddingRight: 10,
borderRadius: 25,
borderColor: "#F4F4F4",
}}
>
<TextInput
placeholder="駅名を入力して停車駅でフィルタリングします。"
onFocus={() => setKeyBoardVisible(true)}
onEndEditing={() => {}}
onChange={(ret) => setInput(ret.nativeEvent.text)}
value={input}
style={{ flex: 1 }}
/>
</View>
</KeyboardAvoidingView>
{keyBoardVisible || (
<BigButton onPress={() => goBack()} string="閉じる" />
)}
</View>
);
};
export const TypeSelectorBox: FC<{
selectedTypeList: trainTypeID[];
setSelectedTypeList: (list: trainTypeID[]) => void;
typeID: trainTypeID;
relativeID?: trainTypeID[];
}> = (props) => {
const { selectedTypeList, setSelectedTypeList, typeID, relativeID } = props;
const isSelected =
selectedTypeList.findIndex((item) => item === typeID) !== -1;
const { color, shortName } = getTrainType({ type: typeID, whiteMode: true });
return (
<TouchableOpacity
style={{
alignItems: "center",
marginHorizontal: 5,
opacity: isSelected ? 1 : 0.8,
backgroundColor: isSelected ? "white" : color,
alignSelf: "center",
borderColor: color,
borderWidth: 1,
borderRadius: 100,
}}
onPress={() => {
if (selectedTypeList.findIndex((item) => item === typeID) === -1) {
setSelectedTypeList([
...selectedTypeList,
typeID,
...(relativeID ?? []),
]);
} else {
setSelectedTypeList(
selectedTypeList.filter(
(item) => item !== typeID && !relativeID?.includes(item)
)
);
}
}}
>
<Text
style={{
color: isSelected ? color : "white",
fontSize: 14,
margin: 5,
}}
>
{shortName}
</Text>
</TouchableOpacity>
);
};

View File

@@ -1,6 +1,7 @@
import React, { FC } from "react";
import { Marker } from "react-native-maps";
import { useNavigation } from "@react-navigation/native";
import { useStationList } from "@/stateBox/useStationList";
type Props = {
index: number;
indexBase: number;
@@ -13,7 +14,8 @@ type Props = {
export const MapPin: FC<Props> = (props) => {
const { index, indexBase, latlng, D, d, navigate, webview } = props;
const {goBack} = useNavigation();
const { goBack } = useNavigation();
const { getInjectJavascriptAddress } = useStationList();
return (
<Marker
key={index + indexBase}
@@ -22,10 +24,9 @@ export const MapPin: FC<Props> = (props) => {
longitude: parseFloat(latlng[1]),
}}
onPress={() => {
webview.current?.injectJavaScript(
`MoveDisplayStation('${d}_${D.MyStation}_${D.Station_JP}');
document.getElementById("disp").insertAdjacentHTML("afterbegin", "<div />");`
);
const address = getInjectJavascriptAddress(D.StationNumber);
if (!address) return;
webview.current?.injectJavaScript(address);
if (navigate) goBack();
}}
image={require("../../assets/reccha-small.png")}

View File

@@ -8,6 +8,8 @@ export const SwitchArea = ({
trueImage,
falseText,
trueText,
falseValue = false,
trueValue = true,
children,
}) => {
return (
@@ -37,7 +39,7 @@ export const SwitchArea = ({
bool={bool}
setBool={setBool}
color="red"
value={false}
value={falseValue}
image={falseImage}
subText={falseText}
/>
@@ -45,7 +47,7 @@ export const SwitchArea = ({
bool={bool}
setBool={setBool}
color="red"
value={true}
value={trueValue}
image={trueImage}
subText={trueText}
/>

View File

@@ -1,22 +0,0 @@
import { TouchableOpacity, Text } from "react-native";
import { MaterialCommunityIcons } from "@expo/vector-icons";
export const UsefulBox = (props) => {
const { icon, backgroundColor, flex, onPressButton, children } = props;
return (
<TouchableOpacity
style={{
flex: flex,
backgroundColor: backgroundColor,
padding: 10,
alignItems: "center",
margin: 2,
}}
onPress={onPressButton}
>
<MaterialCommunityIcons name={icon} color="white" size={50} />
<Text style={{ color: "white", fontWeight: "bold", fontSize: 18 }}>
{children}
</Text>
</TouchableOpacity>
);
};

View File

@@ -1,5 +1,24 @@
import { CustomTrainData } from "@/lib/CommonTypes";
import dayjs from "dayjs";
export const customTrainDataDetector = (TrainNumber: string) => {
type CustomTrainDataDetector = (
TrainNumber: string,
allCustomTrainData?: any[]
) => CustomTrainData;
export const customTrainDataDetector: CustomTrainDataDetector = (
TrainNumber,
allCustomTrainData
) => {
if (allCustomTrainData && allCustomTrainData.length > 0) {
const customTrain = allCustomTrainData.find(
(train) => train.TrainNumber === TrainNumber
);
if (customTrain) {
return customTrain;
}
}
const trainGetText = `?trainNum=${TrainNumber}&month=${dayjs().format(
"M"
)}&day=${dayjs().format("D")}`;
switch (TrainNumber) {
//しおかぜメイン
//8000 ノーマル
@@ -23,21 +42,23 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "しおかぜ",
trainIcon: "https://storage.haruk.in/s8000nr.png",
img: "https://storage.haruk.in/s8000nr.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/shiokaze.html",
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/shiokaze.html",
trainNumDistance: 0,
info: "いしづちと併結 / 8000系で運転",
infogram: "",
};
case "2M":
return {
type: "LTDEXP",
trainName: "しおかぜ",
trainIcon: "https://storage.haruk.in/s8000nr.png",
img: "https://storage.haruk.in/s8000nr.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/shiokaze.html",
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/shiokaze.html",
trainNumDistance: 0,
info: "8000系で運転",
infogram: "",
};
//8000 アンパン
case "10M":
@@ -47,10 +68,11 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "しおかぜ",
trainIcon: "https://storage.haruk.in/s8000ap.png",
img: `https://n8n.haruk.in/webhook/anpanman-pictures.png${trainGetText}`,
infoUrl: "https://www.jr-eki.com/aptrain/naani/yosan/train.html",
trainNumDistance: 0,
info: "いしづちと併結 / アンパンマン列車で運転",
infogram: "",
};
//8600
case "8M":
@@ -64,11 +86,12 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "しおかぜ",
trainIcon: "https://storage.haruk.in/s8600.png",
img: "https://storage.haruk.in/s8600.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/shiokaze.html",
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/shiokaze.html",
trainNumDistance: 0,
info: "いしづちと併結 / 8600系で運転",
infogram: "",
};
//いしづちメイン
@@ -94,11 +117,12 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "いしづち",
trainIcon: "https://storage.haruk.in/s8000no.png",
img: "https://storage.haruk.in/s8000no.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/ishizuchi.html",
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/ishizuchi.html",
trainNumDistance: 1000,
info: "しおかぜと併結 / 8000系で運転",
infogram: "",
};
//8000 アンパン
@@ -109,10 +133,11 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "いしづち",
trainIcon: "https://storage.haruk.in/s8000ap.png",
img: `https://n8n.haruk.in/webhook/anpanman-pictures.png${trainGetText}`,
infoUrl: "https://www.jr-eki.com/aptrain/naani/yosan/train.html",
trainNumDistance: 1000,
info: "しおかぜと併結 / アンパンマン列車で運転",
infogram: "",
};
//8600
@@ -127,11 +152,12 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "いしづち",
trainIcon: "https://storage.haruk.in/s8600_isz.png",
img: "https://storage.haruk.in/s8600_isz.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/ishizuchi.html",
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/ishizuchi.html",
trainNumDistance: 1000,
info: "しおかぜと併結 / 8600系で運転",
infogram: "",
};
//MEXP
@@ -140,22 +166,24 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "モーニングEXP高松",
trainIcon: "https://storage.haruk.in/s8000nr.png",
img: "https://storage.haruk.in/s8000nr.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/morning.html",
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/morning.html",
trainNumDistance: null,
info: "8000系で運転",
infogram: "",
};
//8600
case "1091M":
return {
type: "LTDEXP",
trainName: "モーニングEXP松山",
trainIcon: "https://storage.haruk.in/s8600_isz.png",
img: "https://storage.haruk.in/s8600_isz.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/morning.html",
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/morning.html",
trainNumDistance: null,
info: "8600系で運転",
infogram: "",
};
//三桁いしづち
//8000 アンパン
@@ -164,82 +192,68 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "いしづち",
trainIcon: "https://storage.haruk.in/s8000ap.png",
img: `https://n8n.haruk.in/webhook/anpanman-pictures.png${trainGetText}`,
infoUrl: "https://www.jr-eki.com/aptrain/naani/yosan/train.html",
trainNumDistance: 940,
info: "アンパンマン列車で運転",
infogram: "",
};
//8600
case "1043M":
case "1042M":
return {
type: "LTDEXP",
trainName: "いしづち",
img: "https://storage.haruk.in/s8600_isz.png",
infoUrl:
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/ishizuchi.html",
trainNumDistance: 940,
info: "8600系で運転",
infogram: "",
};
case "1046M":
return {
type: "LTDEXP",
trainName: "いしづち",
trainIcon: "https://storage.haruk.in/s8600_isz.png",
img: "https://storage.haruk.in/s8600_isz.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/ishizuchi.html",
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/ishizuchi.html",
trainNumDistance: 940,
info: "8600系で運転",
infogram: "",
};
//南風 2700ーマル
case "34D":
case "58D":
case "31D":
case "51D":
return {
type: "LTDEXP",
trainName: "南風",
trainIcon: "https://storage.haruk.in/s2700.png",
infoUrl: "http://jr-shikoku.co.jp/01_trainbus/vehicle-info/nanpu.html",
trainNumDistance: 30,
info: "しまんとと併結 / 2700系で運転",
};
case "52D":
case "53D":
return {
type: "LTDEXP",
trainName: "南風",
trainIcon: "https://storage.haruk.in/s2700.png",
infoUrl: "http://jr-shikoku.co.jp/01_trainbus/vehicle-info/nanpu.html",
trainNumDistance: 30,
info: "うずしおと併結 / 2700系で運転",
};
case "38D":
case "40D":
case "42D":
case "46D":
case "50D":
case "52D":
case "54D":
case "58D":
case "31D":
case "35D":
case "39D":
case "41D":
case "43D":
case "47D":
case "51D":
case "53D":
case "55D":
return {
type: "LTDEXP",
trainName: "南風",
trainIcon: "https://storage.haruk.in/s2700.png",
infoUrl: "http://jr-shikoku.co.jp/01_trainbus/vehicle-info/nanpu.html",
img: "https://storage.haruk.in/s2700.png",
infoUrl:
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/nanpu.html",
trainNumDistance: 30,
info: "2700系で運転",
infogram: "",
};
//2700アンパン
case "36D":
case "37D":
return {
type: "LTDEXP",
trainName: "南風",
trainIcon: `https://n8n.haruk.in/webhook/dosan-anpanman-pictures.png?trainNum=${TrainNumber}&day=${dayjs().format(
"yyyy-MM-DD"
)}`,
infoUrl: "https://www.jr-eki.com/aptrain/naani/dosan/train.html",
trainNumDistance: 30,
info: "うずしおと連結 / アンパンマン列車で運転",
};
case "32D":
case "36D":
case "44D":
@@ -253,66 +267,59 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "南風",
trainIcon: `https://n8n.haruk.in/webhook/dosan-anpanman-pictures.png?trainNum=${TrainNumber}&day=${dayjs().format(
"yyyy-MM-DD"
)}`,
img: `https://n8n.haruk.in/webhook/anpanman-pictures.png${trainGetText}`,
infoUrl: "https://www.jr-eki.com/aptrain/naani/dosan/train.html",
trainNumDistance: 30,
info: "アンパンマン列車で運転",
infogram: "",
};
//うずしお
//2700
case "5006D":
case "5022D":
case "5013D":
case "5029D":
return {
type: "LTDEXP",
trainName: "うずしお",
trainIcon: "https://storage.haruk.in/s2700_uzu.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/uzushio.html",
trainNumDistance: 5000,
info: "南風と併結 / 高松-宇多津間進行方向逆転 / 2700系で運転",
};
case "3004D":
case "3006D":
case "3010D":
case "3014D":
case "3016D":
case "3022D":
case "3028D":
case "3003D":
case "3007D":
case "3013D":
case "3019D":
case "3025D":
case "3031D":
return {
type: "LTDEXP",
trainName: "うずしお",
trainIcon: "https://storage.haruk.in/s2700_uzu.png",
img: "https://storage.haruk.in/s2700_uzu.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/uzushio.html",
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/uzushio.html",
trainNumDistance: 3000,
info: "2700系で運転",
infogram: "",
};
//2700 二両編成
case "3008D":
case "3020D":
case "3026D":
case "3032D":
case "3001D":
case "3005D":
case "3011D":
case "3017D":
case "3019D":
case "3023D":
case "3029D":
return {
type: "LTDEXP",
trainName: "うずしお",
trainIcon: "https://storage.haruk.in/s2700_uzu.png",
img: "https://storage.haruk.in/s2700_uzu.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/uzushio.html",
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/uzushio.html",
trainNumDistance: 3000,
info: "2700系で運転",
infogram: "",
};
//2600
@@ -329,24 +336,12 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "うずしお",
trainIcon: "https://storage.haruk.in/s2600.png",
img: "https://storage.haruk.in/s2600.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/uzushio.html",
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/uzushio.html",
trainNumDistance: 3000,
info: "2600系で運転",
};
//キハ185
case "3001D":
case "3008D":
return {
type: "LTDEXP",
trainName: "うずしお",
trainIcon: "https://storage.haruk.in/s185tu_uzu.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/uzushio.html",
trainNumDistance: 3000,
info: "キハ185系で運転",
infogram: "",
};
//マリンライナー
@@ -421,10 +416,12 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "Rapid",
trainName: "マリンライナー",
trainIcon: "https://storage.haruk.in/s5001.png",
infoUrl: "http://jr-shikoku.co.jp/01_trainbus/vehicle-info/marine.html",
img: "https://storage.haruk.in/s5001.png",
infoUrl:
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/marine.html",
trainNumDistance: 3100,
info: "",
infogram: "",
};
case "3102M":
case "3101M":
@@ -434,10 +431,108 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "Rapid",
trainName: "マリンライナー",
trainIcon: "https://storage.haruk.in/s5001k.png",
infoUrl: "http://jr-shikoku.co.jp/01_trainbus/vehicle-info/marine.html",
img: "https://storage.haruk.in/s5001k.png",
infoUrl:
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/marine.html",
trainNumDistance: 3100,
info: "",
infogram: "",
};
//下りサンポート
case "1219M":
return {
type: "Normal",
trainName: "南風リレー",
img: "",
infoUrl: "",
trainNumDistance: null,
info: " 土曜・休日は多度津-琴平間運休",
infogram: "",
};
case "111M":
case "115M":
case "117M":
case "121M":
case "123M":
case "127M":
case "131M":
case "139M":
case "147M":
case "151M":
return {
type: "Rapid",
trainName: "サンポート南風リレー",
img: null,
infoUrl: null,
trainNumDistance: null,
info: null,
infogram: "",
};
case "5109M":
case "5135M":
case "5251M":
return {
type: "OneManRapid",
trainName: "サンポート南風リレー",
img: null,
infoUrl: null,
trainNumDistance: null,
info: null,
infogram: "",
};
case "137M":
return {
type: "Rapid",
trainName: "サンポート",
img: null,
infoUrl: null,
trainNumDistance: null,
info: "土曜・休日運休",
infogram: "",
};
//上りサンポート
case "116M":
return {
type: "Normal",
trainName: "南風リレー",
img: null,
infoUrl: null,
trainNumDistance: null,
info: null,
infogram: "",
};
case "130M":
case "132M":
case "136M":
case "140M":
case "144M":
case "146M":
case "150M":
case "156M":
return {
type: "Rapid",
trainName: "サンポート南風リレー",
img: "",
infoUrl: "",
trainNumDistance: null,
info: "",
infogram: "",
};
case "5118M":
case "5120M":
case "5124M":
case "5126M":
case "5252M":
return {
type: "OneManRapid",
trainName: "サンポート南風リレー",
img: null,
infoUrl: null,
trainNumDistance: null,
info: null,
infogram: "",
};
//サンライズ瀬戸
@@ -446,42 +541,45 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "NightLTDEXP",
trainName: "サンライズ瀬戸",
trainIcon: "https://storage.haruk.in/w285.png",
img: "https://storage.haruk.in/w285.png",
infoUrl:
"https://www.jr-odekake.net/train/sunriseseto_izumo/index.html",
trainNumDistance: null,
info: "",
infogram: "ブ",
};
case "8041M": //琴平延長高松迄
case "8031M": //琴平延長高松以降
return {
type: "NightLTDEXP",
trainName: "サンライズ瀬戸",
trainIcon: "https://storage.haruk.in/w285.png",
img: "https://storage.haruk.in/w285.png",
infoUrl:
"https://www.jr-odekake.net/train/sunriseseto_izumo/index.html",
trainNumDistance: null,
info: "琴平延長運転日",
infogram: "ブ",
};
//宇和海
//2000 ノーマル
case "1052D":
case "1054D":
case "1056D":
case "1058D":
case "1060D":
case "1062D":
case "1064D":
case "1068D":
case "1070D":
case "1074D":
case "1072D":
case "1076D":
case "1078D":
case "1080D":
case "1082D":
case "1051D":
case "1053D":
case "1055D":
case "1057D":
case "1059D":
case "1061D":
case "1063D":
case "1065D":
case "1069D":
@@ -490,57 +588,47 @@ export const customTrainDataDetector = (TrainNumber: string) => {
case "1075D":
case "1077D":
case "1079D":
return {
type: "LTDEXP",
trainName: "宇和海",
trainIcon: "https://storage.haruk.in/s2000_uwa.png",
infoUrl: "http://jr-shikoku.co.jp/01_trainbus/vehicle-info/uwakai.html",
trainNumDistance: 1050,
info: "2000系で運転",
};
//2000 アンパン込み
case "1054D":
case "1060D":
case "1066D":
case "1072D":
case "1055D":
case "1061D":
case "1067D":
case "1081D":
return {
type: "LTDEXP",
trainName: "宇和海",
trainIcon: "https://storage.haruk.in/s2002a.png",
img: "https://storage.haruk.in/s2000_uwa.png",
infoUrl:
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/uwakai.html",
trainNumDistance: 1050,
info: "2000系で運転",
infogram: "",
};
//2000 アンパン込み
case "1058D":
case "1066D":
case "1074D":
case "1053D":
case "1059D":
case "1067D":
return {
type: "LTDEXP",
trainName: "宇和海",
img: `https://n8n.haruk.in/webhook/anpanman-pictures.png${trainGetText}`,
infoUrl: "https://www.jr-eki.com/aptrain/naani/yosan/train.html",
trainNumDistance: 1050,
info: "アンパン列車で運転",
infogram: "",
};
//しまんと
case "2002D":
case "2008D":
case "2004D":
case "2001D":
case "2005D":
case "2003D":
return {
type: "LTDEXP",
trainName: "しまんと",
trainIcon: "https://storage.haruk.in/s2700_smn.png",
img: "https://storage.haruk.in/s2700_smn.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/shimanto.html",
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/shimanto.html",
trainNumDistance: 2000,
info: "2700系で運転",
};
case "2004D":
case "2006D":
case "2003D":
case "2007D":
return {
type: "LTDEXP",
trainName: "しまんと",
trainIcon: "https://storage.haruk.in/s2700_smn.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/shimanto.html",
trainNumDistance: 2000,
info: "南風と併結 / 2700系で運転",
infogram: "",
};
//あしずり 2000
@@ -555,63 +643,59 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "あしずり",
trainIcon: "https://storage.haruk.in/s2000_asi.png",
img: `https://n8n.haruk.in/webhook/anpanman-pictures.png${trainGetText}`,
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/ashizuri.html",
"https://www.jr-eki.com/aptrain/naani/first-generation/jikoku.html",
trainNumDistance: 2070,
info: "2000系で運転",
infogram: "",
};
//あしずり 2700
case "2078D":
case "2084D":
case "2088D":
case "2075D":
case "2077D":
return {
type: "LTDEXP",
trainName: "あしずり",
img: "https://storage.haruk.in/s2700_asi.png",
infoUrl:
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/ashizuri.html",
trainNumDistance: 2070,
info: "2700系で運転",
infogram: "",
};
case "2072D":
case "2083D":
return {
type: "LTDEXP",
trainName: "あしずり",
trainIcon: "https://storage.haruk.in/s2700_asi.png",
img: "https://storage.haruk.in/s2700_asi.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/ashizuri.html",
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/ashizuri.html",
trainNumDistance: 2070,
info: "2700系で運転",
infogram: "",
};
//剣山
case "4002D":
case "4004D":
case "4006D":
case "4008D":
case "4010D":
case "4001D":
case "4003D":
case "4005D":
case "4007D":
case "4009D":
case "4011D":
return {
type: "LTDEXP",
trainName: "剣山",
trainIcon: "https://storage.haruk.in/s185tu.png",
img: "https://storage.haruk.in/s185tu.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/vehicle-info/tsurugisan.html",
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/tsurugisan.html",
trainNumDistance: 4000,
info: "キハ185系で運転",
};
//むろと
case "8051D":
case "8052D":
return {
type: "LTDEXP",
trainName: "むろと",
trainIcon: "https://storage.haruk.in/s185_mrt.png",
infoUrl: "http://jr-shikoku.co.jp/01_trainbus/vehicle-info/muroto.html",
trainNumDistance: 5050,
info: "キハ185系で運転",
infogram: "",
};
//よしのがわトロッコ
@@ -620,11 +704,12 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "よしのがわトロッコ",
trainIcon: "https://storage.haruk.in/s185to_ai.png",
img: "https://storage.haruk.in/s185to_ai.png",
infoUrl:
"http://jr-shikoku.co.jp/01_trainbus/event_train/yoshino_torokko.html",
"https://www.jr-shikoku.co.jp/01_trainbus/event_train/yoshino_torokko.html",
trainNumDistance: null,
info: "",
infogram: "",
};
//岡山高松アントロ
@@ -636,11 +721,12 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "アンパンマントロッコ",
trainIcon: "https://storage.haruk.in/s32to4.png",
img: "https://storage.haruk.in/s32to4.png",
infoUrl:
"https://www.jr-eki.com/aptrain/naani/torokko_seto/jikoku.html",
trainNumDistance: null,
info: "",
infogram: "",
};
//伊予灘ものがたり
@@ -649,20 +735,22 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "伊予灘ものがたり",
trainIcon: "https://storage.haruk.in/s185iyor.png",
img: "https://storage.haruk.in/s185iyor.png",
infoUrl: "https://iyonadamonogatari.com/",
trainNumDistance: null,
info: "",
infogram: "",
};
case "8092D":
case "8094D":
return {
type: "LTDEXP",
trainName: "伊予灘ものがたり",
trainIcon: "https://storage.haruk.in/s185iyoy.png",
img: "https://storage.haruk.in/s185iyoy.png",
infoUrl: "https://iyonadamonogatari.com/",
trainNumDistance: null,
info: "",
infogram: "",
};
//千年ものがたり
@@ -671,10 +759,11 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "四国まんなか千年ものがたり",
trainIcon: "https://storage.haruk.in/s185mm1.png",
img: "https://storage.haruk.in/s185mm1.png",
infoUrl: "https://www.jr-shikoku.co.jp/sennenmonogatari/",
trainNumDistance: null,
info: "",
infogram: "",
};
//夜明けものがたり
@@ -685,67 +774,137 @@ export const customTrainDataDetector = (TrainNumber: string) => {
return {
type: "LTDEXP",
trainName: "時代の夜明けのものがたり",
trainIcon: "https://storage.haruk.in/s185ym1.png",
img: "https://storage.haruk.in/s185ym1.png",
infoUrl: "https://www.jr-shikoku.co.jp/yoakenomonogatari/index.html",
trainNumDistance: null,
info: "",
infogram: "",
};
case "9174M":
return {
type: "SPCL_Rapid",
trainName: "マリンライナー94号",
img: "https://storage.haruk.in/s5001.png",
infoUrl:
"https://www.jr-shikoku.co.jp/01_trainbus/vehicle-info/marine.html",
trainNumDistance: null,
info: "臨時列車 4/12,13,19のみ運転",
infogram: "",
};
case "9395D":
return {
type: "SPCL_Normal",
trainName: "",
img: "https://storage.haruk.in/s1500.png",
infoUrl: null,
trainNumDistance: null,
info: "臨時列車 4/12,13,19のみ運転",
infogram: "",
};
case "9662D":
case "9665D":
return {
type: "SPCL_Normal",
trainName: "れんげ号",
img: "",
infoUrl: null,
trainNumDistance: null,
info: "臨時列車 4/29のみ運転",
infogram: "",
};
case "9664D":
case "9663D":
return {
type: "SPCL_Normal",
trainName: "わらぐろ号",
img: "",
infoUrl: null,
trainNumDistance: null,
info: "臨時列車 4/29のみ運転",
infogram: "",
};
default:
if (
if (getJRF(TrainNumber) !== null) {
return {
type: "Freight",
trainName: getJRF(TrainNumber),
img: "https://storage.haruk.in/ef210a.png",
infoUrl: null,
trainNumDistance: null,
info: "",
infogram: "",
};
} else if (
new RegExp(/^4[1-9]\d\d[DM]$/).test(TrainNumber) ||
new RegExp(/^5[1-7]\d\d[DM]$/).test(TrainNumber) ||
TrainNumber === "3621D"
new RegExp(/^3[2-9]\d\d[DM]$/).test(TrainNumber)
)
return {
type: "OneMan",
trainName: "",
trainIcon: null,
img: null,
infoUrl: null,
trainNumDistance: null,
info: null,
infogram: "",
};
else
else if (
new RegExp(/^[1-9]\d\d[DM]$/).test(TrainNumber) ||
new RegExp(/^1[26]\d\d[DM]$/).test(TrainNumber) ||
new RegExp(/^58\d\d[DM]$/).test(TrainNumber) ||
new RegExp(/^6\d\d\d[DM]$/).test(TrainNumber)
) {
return {
type: "Normal",
trainName: "",
trainIcon: null,
img: null,
infoUrl: null,
trainNumDistance: null,
info: null,
infogram: "",
};
break;
} else {
return {
type: "Other",
trainName: "",
img: null,
infoUrl: null,
trainNumDistance: null,
info: null,
infogram: "",
};
}
}
};
export const getJRF = (num: string) => {
switch (num) {
case "71":
return "東京(タ)→高松(タ)\\n";
return "東京(タ)→高松(タ)";
case "73":
case "75":
return "大阪(タ)→高松(タ)\\n";
return "大阪(タ)→高松(タ)";
case "3079":
return "高松(タ)→伊予三島\\n";
return "高松(タ)→伊予三島";
case "3071":
case "3077":
return "高松(タ)→新居浜\\n";
return "高松(タ)→新居浜";
case "3073":
return "高松(タ)→松山貨物\\n";
return "高松(タ)→松山貨物";
case "70":
return "高松(タ)→東京(タ)\\n";
return "高松(タ)→東京(タ)";
case "74":
case "76":
return "高松(タ)→大阪(タ)\\n";
return "高松(タ)→大阪(タ)";
case "3078":
return "伊予三島→高松(タ)\\n";
return "伊予三島→高松(タ)";
case "3070":
return "新居浜→高松(タ)\\n";
return "新居浜→高松(タ)";
case "3076":
return "新居浜→高松(タ)\\n";
return "新居浜→高松(タ)";
case "3072":
return "松山貨物→高松(タ)\\n";
return "松山貨物→高松(タ)";
case "9070":
return "臨時貨物\\n";
return "臨時";
default:
return null;
}

View File

@@ -4,13 +4,13 @@ import MapView from "react-native-maps";
import { useCurrentTrain } from "../stateBox/useCurrentTrain";
import { useNavigation } from "@react-navigation/native";
import lineColorList from "../assets/originData/lineColorList";
import { stationIDPair } from "../lib/getStationList2";
import { lineListPair } from "../lib/getStationList";
import { lineList_LineWebID, lineListPair, stationIDPair } from "../lib/getStationList";
import { SheetManager } from "react-native-actions-sheet";
import { useTrainMenu } from "../stateBox/useTrainMenu";
import { MapPin } from "./TrainMenu/MapPin";
import { UsefulBox } from "./TrainMenu/UsefulBox";
import { MapsButton } from "./TrainMenu/MapsButton";
import { useStationList } from "@/stateBox/useStationList";
export default function TrainMenu({ style }) {
const { webview } = useCurrentTrain();
const mapRef = useRef();
@@ -19,35 +19,30 @@ export default function TrainMenu({ style }) {
const {
selectedLine,
setSelectedLine,
injectJavaScript,
setInjectJavaScript,
mapsStationData: stationData,
} = useTrainMenu();
const { originalStationList } = useStationList();
useEffect(() => {
const stationPinData = [];
Object.keys(stationData).forEach((d, indexBase) => {
stationData[d].forEach((D, index) => {
if (!D.StationMap) return null;
if (selectedLine && selectedLine != d) return;
const latlng = D.StationMap.replace(
"https://www.google.co.jp/maps/place/",
""
).split(",");
Object.keys(lineList_LineWebID).forEach((d, indexBase) => {
originalStationList[d].forEach((D, index) => {
if (selectedLine && selectedLine != lineList_LineWebID[d]) return;
const latlng = [D.lat,D.lng];
if (latlng.length == 0) return null;
stationPinData.push({ D, d, latlng, indexBase: 0, index });
});
});
setStationPin(stationPinData);
}, [stationData, selectedLine]);
}, [originalStationList, selectedLine]);
useLayoutEffect(() => {
mapRef.current.fitToCoordinates(
mapRef?.current.fitToCoordinates(
stationPin.map(({ latlng }) => ({
latitude: parseFloat(latlng[0]),
longitude: parseFloat(latlng[1]),
})),
{ edgePadding: { top: 80, bottom: 120, left: 50, right: 50 } } // Add margin values here
);
}, [stationPin]);
}, [stationPin,mapRef]);
return (
<View style={{ height: "100%", backgroundColor: "#0099CC", ...style }}>
<MapView
@@ -75,7 +70,7 @@ export default function TrainMenu({ style }) {
d={d}
navigate={navigate}
webview={webview}
key={D.StationNumber + d}
key={D.Station_JP + D.StationNumber + d}
/>
))}
</MapView>
@@ -166,6 +161,7 @@ export default function TrainMenu({ style }) {
});
});
}}
key={stationIDPair[d]}
>
<Text
style={{ color: "white", fontWeight: "bold", fontSize: 20 }}
@@ -184,11 +180,11 @@ export default function TrainMenu({ style }) {
flex={1}
onPressButton={() =>
navigate("howto", {
info: "https://train.jr-shikoku.co.jp/usage.htm",
info: "https://xprocess.haruk.in/JR-shikoku-Apps-Common/info/train-position",
})
}
>
使い
走行位置の見
</UsefulBox>
<UsefulBox
backgroundColor={"#EA4752"}
@@ -215,7 +211,6 @@ export default function TrainMenu({ style }) {
<MapsButton
onPress={() => {
goBack();
webview.current?.injectJavaScript(injectJavaScript);
}}
top={0}
mapSwitch={"flex"}

View File

@@ -4,8 +4,7 @@ import { View, Text, TouchableOpacity, Linking } from "react-native";
import { useCurrentTrain } from "../stateBox/useCurrentTrain";
import { useNavigation } from "@react-navigation/native";
import lineColorList from "../assets/originData/lineColorList";
import { stationIDPair } from "../lib/getStationList2";
import { lineListPair } from "../lib/getStationList";
import { lineListPair, stationIDPair } from "../lib/getStationList";
import { SheetManager } from "react-native-actions-sheet";
import { useTrainMenu } from "../stateBox/useTrainMenu";
//import { MapPin } from "./TrainMenu/MapPin";
@@ -20,8 +19,6 @@ export default function TrainMenu({ style }) {
const {
selectedLine,
setSelectedLine,
injectJavaScript,
setInjectJavaScript,
mapsStationData: stationData,
} = useTrainMenu();
useEffect(() => {
@@ -216,7 +213,6 @@ export default function TrainMenu({ style }) {
<MapsButton
onPress={() => {
goBack();
webview.current?.injectJavaScript(injectJavaScript);
}}
top={0}
mapSwitch={"flex"}

View File

@@ -29,7 +29,9 @@ export default function TrainBase({ route }) {
"https://train.jr-shikoku.co.jp",
"https://train.jr-shikoku.co.jp/sp.html",
]}
onMessage={(event) => {}}
onMessage={() => {
// 必要に応じてメッセージ処理を実装
}}
mixedContentMode={"compatibility"}
javaScriptEnabled
injectedJavaScript={jss}

View File

@@ -1,34 +1,35 @@
import React, { FC, useEffect, useState } from "react";
import { Linking, TouchableOpacity, Text } from "react-native";
import { Dialog, Button, Input } from "react-native-elements";
import { checkDuplicateTrainData } from "../../lib/checkDuplicateTrainData";
import { getTrainDelayStatus } from "../../lib/getTrainDelayStatus";
import { getTrainType } from "../../lib/getTrainType";
import { useCurrentTrain } from "../../stateBox/useCurrentTrain";
import { TouchableOpacity } from "react-native";
import { checkDuplicateTrainData } from "@/lib/checkDuplicateTrainData";
import { getTrainDelayStatus } from "@/lib/getTrainDelayStatus";
import { getTrainType } from "@/lib/getTrainType";
import { useCurrentTrain } from "@/stateBox/useCurrentTrain";
import { SheetManager } from "react-native-actions-sheet";
import { Description } from "./LED_inside_Component/Description";
import { DependTime } from "./LED_inside_Component/DependTime";
import { LastStation } from "./LED_inside_Component/LastStation";
import { StatusAndDelay } from "./LED_inside_Component/StatusAndDelay";
import { TrainName } from "./LED_inside_Component/TrainName";
import { customTrainDataDetector } from "../custom-train-data";
import { TrainPosition } from "./LED_inside_Component/TrainPosition";
import { TrainPositionDataPush } from "./LED_inside_Component/TrainPositionDataPush";
import { TrainPositionDataDelete } from "./LED_inside_Component/TrainPositionDataDelete";
import { useStationList } from "../../stateBox/useStationList";
import { Description } from "@/components/発車時刻表/LED_inside_Component/Description";
import { DependTime } from "@/components/発車時刻表/LED_inside_Component/DependTime";
import { LastStation } from "@/components/発車時刻表/LED_inside_Component/LastStation";
import { StatusAndDelay } from "@/components/発車時刻表/LED_inside_Component/StatusAndDelay";
import { TrainName } from "@/components/発車時刻表/LED_inside_Component/TrainName";
import { TrainPosition } from "@/components/発車時刻表/LED_inside_Component/TrainPosition";
import { StationPosPushDialog } from "@/components/発車時刻表/LED_inside_Component/TrainPositionDataPush";
import { StationPosDeleteDialog } from "@/components/発車時刻表/LED_inside_Component/TrainPositionDataDelete";
import { useStationList } from "@/stateBox/useStationList";
import useInterval from "@/lib/useInterval";
import dayjs from "dayjs";
import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram";
import { CustomTrainData, StationProps, trainTypeID } from "@/lib/CommonTypes";
import { getCurrentTrainData } from "@/lib/getCurrentTrainData";
type Props = {
d: {
train: string;
lastStation: string;
time: string;
isThrough?: boolean;
};
trainIDSwitch: boolean;
trainDescriptionSwitch: boolean;
station: {
Station_JP: string;
StationNumber: string;
};
station: StationProps;
navigate: (screen: string, data?: any) => void;
openStationACFromEachTrainInfo: (station: string) => void;
};
@@ -43,6 +44,7 @@ export const EachData: FC<Props> = (props) => {
} = props;
const { currentTrain } = useCurrentTrain();
const { stationList } = useStationList();
const { allCustomTrainData } = useAllTrainDiagram();
const openTrainInfo = (d: {
train: string;
lastStation: string;
@@ -58,7 +60,7 @@ export const EachData: FC<Props> = (props) => {
const payload = {
data: {
trainNum: d.train,
limited: `${getTrainType(train.type).data}:${
limited: `${getTrainType({type:train.type}).data}:${
train.trainName
}${TrainNumber}`,
},
@@ -71,32 +73,9 @@ export const EachData: FC<Props> = (props) => {
});
};
const getTrainDataFromCurrentTrain = (trainNum: string) => {
const customTrainData = customTrainDataDetector(d.train);
switch (customTrainData.type) {
case "Normal":
case "OneMan":
const currentTrainData = currentTrain.filter((a) => a.num == trainNum);
if (currentTrainData.length == 0) return customTrainData;
else if (currentTrainData[0].Type.includes("rapid:")) {
const typeText = currentTrainData[0].Type.split(":");
const returnData = {
type: "Rapid",
trainName: typeText[1].replace("\r", ""),
trainIcon: null,
trainNumDistance: null,
info: "",
};
return returnData;
}
return customTrainData;
default:
return customTrainData;
}
};
const [train, setTrain] = useState(getTrainDataFromCurrentTrain(d.train));
const [train, setTrain] = useState<CustomTrainData>(getCurrentTrainData(d.train,currentTrain,allCustomTrainData));
useEffect(() => {
setTrain(getTrainDataFromCurrentTrain(d.train));
setTrain(getCurrentTrainData(d.train,currentTrain,allCustomTrainData));
}, [currentTrain, d.train, trainDescriptionSwitch]);
// 土讃線複数存在対策
const currentTrainData = checkDuplicateTrainData(
@@ -108,35 +87,70 @@ export const EachData: FC<Props> = (props) => {
station.Station_JP
)}`;
const [platformNumber, setPlatformNumber] = useState<number>();
const [platformDescription, setPlatformDescription] = useState<string>();
// 投稿システム関係
// Dialog表示関係
const [dialog, setDialog] = useState(false);
const [deleteDialog, setDeleteDialog] = useState(false);
const [posInput, setPosInput] = useState("");
const [descInput, setDescInput] = useState("");
const [stationInput, setStationInput] = useState("");
const [stationNumberInput, setStationNumberInput] = useState("");
//固定値
const [PosNum, setPosNum] = useState<number | undefined>();
const [Pos, setPos] = useState<string>("");
const [Line, setLine] = useState<string>("");
const [StationNum, setStationNum] = useState<string>("");
//編集情報
const [lineInput, setLineInput] = useState<string>("");
const [posInput, setPosInput] = useState<string>("");
const [descInput, setDescInput] = useState<string>("");
const [isShow, setIsShow] = useState(true);
const [isDepartureNow, setIsDepartureNow] = useState(false);
useEffect(() => {
const [h, m] = d.time.split(":");
const IntH = parseInt(h);
const IntM = parseInt(m);
const currentTime = dayjs();
const trainTime = currentTime
.set("hour", IntH < 4 ? IntH + 24 : IntH)
.set("minute", IntM);
const diff = trainTime.diff(currentTime, "minute");
if (diff < 2) setIsDepartureNow(true);
else setIsDepartureNow(false);
return () => {
setIsDepartureNow(false);
setIsShow(true);
};
}, [d.time, currentTrainData]);
useInterval(() => {
if (isDepartureNow) {
setIsShow(!isShow);
}
}, 800);
return (
<>
<TrainPositionDataDelete
<StationPosDeleteDialog
dialog={deleteDialog}
setDialog={setDeleteDialog}
currentTrainData={currentTrainData}
stationInput={stationInput}
stationNumberInput={stationNumberInput}
Pos={Pos}
PosNum={PosNum}
Line={Line}
StationNum={StationNum}
/>
<TrainPositionDataPush
<StationPosPushDialog
// Dialog表示関係
dialog={dialog}
setDialog={setDialog}
currentTrainData={currentTrainData}
stationInput={stationInput}
stationNumberInput={stationNumberInput}
// 固定情報
PosNum={PosNum}
Pos={Pos}
Line={Line}
StationNum={StationNum}
// 入力欄
lineInput={lineInput}
setLineInput={setLineInput}
posInput={posInput}
descInput={descInput}
setPosInput={setPosInput}
descInput={descInput}
setDescInput={setDescInput}
station={station}
/>
<TouchableOpacity
style={{
@@ -147,8 +161,10 @@ export const EachData: FC<Props> = (props) => {
marginHorizontal: "3%",
backgroundColor: "#000",
flexDirection: "row",
opacity: isShow ? 1 : 0.5,
}}
onPress={() => openTrainInfo(d)}
key={d.train + "-eachData"}
>
<TrainName
trainName={train.trainName}
@@ -156,30 +172,49 @@ export const EachData: FC<Props> = (props) => {
trainIDSwitch={trainIDSwitch}
trainID={d.train}
type={train.type}
isThrew={d.isThrough}
/>
<LastStation lastStation={d.lastStation} />
<LastStation lastStation={d.lastStation} ToData={train.ToData} Station_JP={station.Station_JP} />
<DependTime time={d.time} />
<StatusAndDelay trainDelayStatus={trainDelayStatus} />
</TouchableOpacity>
{!!isDepartureNow && (
<Description
info={
d.isThrough
? "通過列車にご注意ください"
: d.lastStation == station.Station_JP
? "この列車は当駅止です。間もなく到着します。"
: "列車の出発時刻です。"
}
key={d.train + "-isDepartureNow"}
/>
)}
{trainDescriptionSwitch && (
<TrainPosition
// LED表示関係
trainIDSwitch={trainIDSwitch}
currentTrainData={currentTrainData}
setStationInput={setStationInput}
setStationNumberInput={setStationNumberInput}
setDescInput={setDescInput}
setPosInput={setPosInput}
// ポップアップ表示関係
setDialog={setDialog}
setDeleteDialog={setDeleteDialog}
setPlatformDescription={setPlatformDescription}
setPlatformNumber={setPlatformNumber}
platformDescription={platformDescription}
platformNumber={platformNumber}
// 固定情報
setPos={setPos}
setPosNum={setPosNum}
setLine={setLine}
setStationNum={setStationNum}
//編集機能関係
setLineInput={setLineInput}
setPosInput={setPosInput}
setDescInput={setDescInput}
key={d.train + "-trainPosition"}
/>
)}
{trainDescriptionSwitch && !!train.info && (
<Description info={train.info} />
<Description info={train.info} key={d.train + "-description"} />
)}
{trainDescriptionSwitch && !!train.uwasa && (
<Description info={train.uwasa} key={d.train + "-uwasa"} />
)}
</>
);

View File

@@ -1,48 +0,0 @@
import { View, Text } from "react-native";
import { useCurrentTrain } from "../../../stateBox/useCurrentTrain";
import LottieView from "lottie-react-native";
import { Ionicons } from "@expo/vector-icons";
export const Header = ({ getCurrentTrain }) => {
const { currentTrainLoading, setCurrentTrainLoading } = useCurrentTrain();
return (
<View
style={{
alignContent: "center",
alignItems: "center",
width: "100%",
marginVertical: 10,
flexDirection: "row",
}}
>
<View style={{ flex: 1 }}></View>
<View style={{}}>
<Text style={{ fontSize: 25, color: "white", fontWeight: "bold" }}>
次の列車
</Text>
<Text style={{ fontSize: 15, color: "white" }}>Next Train</Text>
</View>
<View style={{ flex: 1, flexDirection: "row-reverse" }}>
{currentTrainLoading == "loading" ? (
<LottieView
autoPlay
loop
style={{ width: 40, height: 40, marginRight: 30 }}
source={require("../../../assets/51690-loading-diamonds.json")}
/>
) : currentTrainLoading == "error" ? (
<Ionicons
name="reload"
color="white"
size={30}
style={{ marginRight: 30 }}
onPress={() => {
setCurrentTrainLoading("loading");
getCurrentTrain();
}}
/>
) : null}
</View>
</View>
);
};

View File

@@ -0,0 +1,58 @@
import { View, Text } from "react-native";
import { useCurrentTrain } from "../../../stateBox/useCurrentTrain";
import LottieView from "lottie-react-native";
import { Ionicons, AntDesign } from "@expo/vector-icons";
import { useStationList } from "@/stateBox/useStationList";
import { useNavigation } from "@react-navigation/native";
export const Header = ({ station }) => {
const {
currentTrainLoading,
setCurrentTrainLoading,
getCurrentTrain,
inject,
} = useCurrentTrain();
const { getInjectJavascriptAddress } = useStationList();
const { navigate } = useNavigation();
return (
<View
style={{
alignContent: "center",
alignItems: "center",
width: "100%",
marginVertical: 10,
flexDirection: "row",
}}
>
<View style={{ flex: 1, flexDirection: "column", alignItems: "center" }}>
</View>
<View style={{}}>
<Text style={{ fontSize: 25, color: "white", fontWeight: "bold" }}>
</Text>
<Text style={{ fontSize: 15, color: "white" }}>Next Train</Text>
</View>
<View style={{ flex: 1, flexDirection: "row-reverse" }}>
{currentTrainLoading == "loading" ? (
<LottieView
autoPlay
loop
style={{ width: 40, height: 40, marginRight: 30 }}
source={require("../../../assets/51690-loading-diamonds.json")}
/>
) : currentTrainLoading == "error" ? (
<Ionicons
name="reload"
color="white"
size={30}
style={{ marginRight: 30 }}
onPress={() => {
setCurrentTrainLoading("loading");
getCurrentTrain();
}}
/>
) : null}
</View>
</View>
);
};

View File

@@ -0,0 +1,79 @@
import React, { FC, useState, useEffect } from "react";
import { Text, TextStyle, View, TouchableOpacity } from "react-native";
import { useInterval } from "../../../lib/useInterval";
const descriptionStyle: TextStyle = {
fontSize: parseInt("16%"),
fontWeight: "bold",
};
type Props = {
areaInfo: string;
numberOfLines?: number;
onClick?: () => void;
onLongClick?: () => void;
};
export const AreaDescription:FC<Props> = ({ areaInfo, numberOfLines = 0, onClick, onLongClick }) => {
const [areaString, setAreaString] = useState("");
const [areaStringLength, setAreaStringLength] = useState(0);
const [move, setMove] = useState(0);
useInterval(
() => {
if (areaInfo != "") {
setMove(areaStringLength < move ? 0 : move + 1);
}
},
350,
true
);
useEffect(() => {
if (!areaInfo) {
setAreaString("");
return () => {};
}
setAreaString(
areaInfo.substring(move, areaInfo.length) + areaInfo.substring(0, move)
);
}, [move]);
useEffect(() => {
if (!areaInfo) {
setAreaStringLength(0);
return () => {};
}
setAreaStringLength(areaInfo.length);
}, [areaInfo]);
return(
<TouchableOpacity
style={{
alignContent: "center",
alignItems: "center",
width: "94%",
marginVertical: 5,
marginHorizontal: "3%",
backgroundColor: "#000",
flexDirection: "row",
overflow: "hidden",
}}
onPress={onClick}
onLongPress={onLongClick}
>
<View style={{ flex: 4, flexDirection: "row" }}>
{numberOfLines == 1 ? (
<Text style={{ ...descriptionStyle, color: "red" }}>
&gt;{" "}
</Text>
) : (
<Text style={{ ...descriptionStyle, color: "green" }}> &gt; </Text>
)}
<Text
style={{ ...descriptionStyle, color: "green" }}
numberOfLines={numberOfLines}
>
{areaString.replaceAll("\n", "").replaceAll("\r", "")}
</Text>
</View>
</TouchableOpacity>
);
};

View File

@@ -3,18 +3,22 @@ import { Text, View } from "react-native";
type Props = {
lastStation: string;
ToData: string;
Station_JP: string;
};
export const LastStation: FC<Props> = ({ lastStation }) => {
export const LastStation: FC<Props> = ({ lastStation, ToData, Station_JP }) => {
const isEdit = !ToData ? false : ToData !== lastStation;
const string = isEdit ? ToData : lastStation;
return (
<View style={{ flex: 4, flexDirection: "row" }}>
<Text
style={{
fontSize: lastStation.length > 4 ? parseInt("12%") : parseInt("16%"),
color: "white",
fontSize: lastStation?.length > 4 ? parseInt("12%") : parseInt("16%"),
color: isEdit ? "#ffd16fff" : "white",
fontWeight: "bold",
}}
>
{lastStation}
{string === Station_JP ? "当駅止" : string}
</Text>
</View>
);

View File

@@ -1,16 +1,18 @@
import React, { FC } from "react";
import { Text, View } from "react-native";
import { getTrainType } from "../../../lib/getTrainType";
import { trainTypeID } from "@/lib/CommonTypes";
type Props = {
trainName: string;
trainNumDistance?: number;
trainIDSwitch: boolean;
trainID: string;
type: string;
type: trainTypeID;
isThrew: boolean;
};
export const TrainName: FC<Props> = (props) => {
const { trainName, trainNumDistance, trainIDSwitch, trainID, type } = props;
const { name, color } = getTrainType(type);
const { trainName, trainNumDistance, trainIDSwitch, trainID, type, isThrew } = props;
const { name, color } = getTrainType({ type });
const TrainNumber =
trainNumDistance != undefined
? `${
@@ -26,7 +28,7 @@ export const TrainName: FC<Props> = (props) => {
fontWeight: "bold",
}}
>
{trainIDSwitch ? trainID : `${name} ${trainName}${TrainNumber}`}
{trainIDSwitch ? trainID : `${isThrew ? `★通過列車★` : `${name} ${trainName}${TrainNumber}`} `}
</Text>
</View>
);

View File

@@ -1,11 +1,10 @@
import React, { FC, useEffect } from "react";
import React, { FC, useEffect, useState } from "react";
import { Text, TextStyle, View, TouchableOpacity } from "react-native";
import { useStationList } from "../../../stateBox/useStationList";
import {
trainDataType,
trainPosition,
} from "../../../lib/trainPositionTextArray";
import { lineList } from "../../../lib/getStationList";
import { getStationID } from "../../../lib/eachTrainInfoCoreLib/getStationData";
import { useCurrentTrain } from "../../../stateBox/useCurrentTrain";
@@ -15,56 +14,118 @@ const descriptionStyle: TextStyle = {
};
type Props = {
// LED表示関係
numberOfLines?: number;
trainIDSwitch: boolean;
currentTrainData: trainDataType;
setStationInput: (station: string) => void;
setStationNumberInput: (station: string) => void;
setDescInput: (desc: string) => void;
setPosInput: (pos: string) => void;
//ポップアップ表示関係
setDialog: (dialog: boolean) => void;
setDeleteDialog: (dialog: boolean) => void;
platformDescription: string;
platformNumber: number;
setPlatformDescription: (desc: string) => void;
setPlatformNumber: (num: number) => void;
//固定値設定
setPos: React.Dispatch<React.SetStateAction<string>>
setPosNum: React.Dispatch<React.SetStateAction<number>>;
setLine: React.Dispatch<React.SetStateAction<string>>;
setStationNum: React.Dispatch<React.SetStateAction<string>>;
//編集機能関係
setLineInput: (line: string) => void;
setPosInput: (pos: string) => void;
setDescInput: (desc: string) => void;
};
export const TrainPosition: FC<Props> = ({
// LED表示関係
numberOfLines = 0,
trainIDSwitch,
currentTrainData,
setStationInput,
setStationNumberInput,
setDescInput,
setPosInput,
//ポップアップ表示関係
setDialog,
setDeleteDialog,
setPlatformDescription,
setPlatformNumber,
platformDescription,
platformNumber,
}) => {
const { currentTrain } = useCurrentTrain();
const { stationList } = useStationList();
//固定値設定
setPos,
setPosNum,
setLine,
setStationNum,
//編集機能関係
setLineInput,
setPosInput,
setDescInput,
}) => {
const { stationList } = useStationList();
type data = {
type: string;
lineNumber: string;
platformNumber: string;
position: string;
stationName: string;
description: string;
};
const [database, setDatabase] = useState<data>(null);
const [text, setText] = useState("");
const [masterText, setMasterText] = useState("");
useEffect(() => {
const text = `${currentTrainData?.PosNum} ${currentTrainData?.Line} ${currentTrainData?.Pos}`;
setText(trainIDSwitch ? text : masterText);
return () => {
setText("");
};
}, [masterText, trainIDSwitch]);
useEffect(() => {
fetch(
`https://n8n.haruk.in/webhook/JR-shikoku-PosID?PosNum=${currentTrainData?.PosNum}&Line=${currentTrainData?.Line}`
`https://n8n.haruk.in/webhook/JR-shikoku-PosID-v3?PosId=${currentTrainData?.PosNum}&lineName=${currentTrainData?.Line}&StationName=${currentTrainData?.Pos}`
)
.then((res) => res.json())
.then((data: { type: string; platform: number; description: string }) => {
setPlatformNumber(data?.type == "Station" ? data?.platform : undefined);
setPlatformDescription(
data?.type == "Station" ? data?.description : undefined
);
.then((data: data) => {
const { type, platformNumber, description, lineNumber } = data;
setDatabase(data);
const { isBetween, Pos } = trainPosition(currentTrainData);
if (isBetween === true) {
// 移動中
setMasterText(`現在地:${Pos.from}${Pos.to}間を走行中`);
} else {
if (Pos.Pos) {
let platform = platformNumber ? `${platformNumber}番乗り場` : "";
let line = lineNumber ? `${lineNumber}番線` : "";
setMasterText(
`現在地:${Pos.Pos} ${platform || line} ${description || ""}`
);
} else {
setMasterText("");
}
}
});
}, [currentTrainData, currentTrain]);
return () => {
setMasterText("");
};
}, [currentTrainData?.PosNum, currentTrainData?.Line, currentTrainData?.Pos]);
//editWindow向けにfixした情報を送信
const openEditWindow = () => {
const { isBetween, Pos } = trainPosition(currentTrainData);
const trainPositionText = (trainData: trainDataType) => {
const { isBetween, Pos } = trainPosition(trainData);
if (isBetween === true) return `現在地:${Pos.from}${Pos.to}間を走行中`;
else return Pos.Pos == "" ? "" : `現在地:${Pos.Pos}`;
//固定値
setPosNum(currentTrainData?.PosNum);
setPos(currentTrainData?.Pos);
setLine(currentTrainData?.Line);
setStationNum(getStationID(currentTrainData?.Pos, stationList));
//入力欄
if (isBetween === true) {
if (
database?.platformNumber == undefined &&
database?.description == undefined
)
return;
setDeleteDialog(true);
} else {
setPosInput(database?.platformNumber?.toString() || "");
setDescInput(database?.description || "");
setLineInput(database?.lineNumber?.toString() || "");
setDialog(true);
}
};
return (
@@ -79,40 +140,14 @@ export const TrainPosition: FC<Props> = ({
flexDirection: "row",
overflow: "hidden",
}}
onLongPress={() => {
const { isBetween, Pos } = trainPosition(currentTrainData);
if (isBetween === true) {
if (platformNumber == undefined && platformDescription == undefined)
return;
setStationInput(`${Pos.from}${Pos.to}`);
setStationNumberInput(
getStationID(currentTrainData?.Pos, stationList)
);
setPosInput(platformNumber?.toString() || "");
setDeleteDialog(true);
} else {
setStationInput(Pos.Pos);
setStationNumberInput(
getStationID(currentTrainData?.Pos, stationList)
);
setDescInput(platformDescription || "");
setPosInput(platformNumber?.toString() || "");
setDialog(true);
}
}}
onLongPress={openEditWindow}
>
<View style={{ flex: 4, flexDirection: "row" }}>
<Text
style={{ ...descriptionStyle, color: "green" }}
numberOfLines={numberOfLines}
>
{`${
trainIDSwitch
? currentTrainData?.PosNum + currentTrainData?.Line
: trainPositionText(currentTrainData)
} ${platformNumber ? platformNumber + "番線" : ""} ${
platformDescription ? "(" + platformDescription + ")" : ""
}`}
{text}
</Text>
</View>
</TouchableOpacity>

View File

@@ -1,28 +1,32 @@
import React, { FC } from "react";
import { Text } from "react-native";
import { Dialog, Button } from "react-native-elements";
import { trainDataType } from "../../../lib/trainPositionTextArray";
type Props = {
dialog: boolean;
setDialog: (dialog: boolean) => void;
currentTrainData: trainDataType;
stationInput: string;
stationNumberInput: string;
PosNum: number;
Line: string;
Pos: string;
StationNum: string;
};
export const TrainPositionDataDelete: FC<Props> = ({
export const StationPosDeleteDialog: FC<Props> = ({
dialog,
setDialog,
currentTrainData,
stationInput,
stationNumberInput,
PosNum,
Line,
Pos,
StationNum
}) => {
const sendPlatformData = () => {
fetch(`https://n8n.haruk.in/webhook/JR-shikoku-PosID`, {
fetch(`https://n8n.haruk.in/webhook/JR-shikoku-PosID-v3`, {
method: "DELETE",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
PosId: currentTrainData?.PosNum,
lineName: currentTrainData?.Line,
PosId: PosNum,
lineName: Line,
StationName: Pos, //自動:駅名、漢字
}),
})
.then(() => {
@@ -36,10 +40,10 @@ export const TrainPositionDataDelete: FC<Props> = ({
return (
<Dialog isVisible={dialog} onBackdropPress={() => setDialog(false)}>
<Text></Text>
<Text>: {currentTrainData?.Line}</Text>
<Text>ID: {currentTrainData?.PosNum}</Text>
<Text>: {stationInput}</Text>
<Text>: {stationNumberInput}</Text>
<Text>: {Line}</Text>
<Text>ID: {PosNum}</Text>
<Text>: {Pos}</Text>
<Text>: {StationNum}</Text>
<Button title="送信" onPress={sendPlatformData} />
</Dialog>
);

View File

@@ -1,46 +1,56 @@
import React, { FC, useState } from "react";
import React, { FC } from "react";
import { Text } from "react-native";
import { Dialog, Input, Button } from "react-native-elements";
import { trainDataType } from "../../../lib/trainPositionTextArray";
import { useCurrentTrain } from "../../../stateBox/useCurrentTrain";
import { getStationID } from "@/lib/eachTrainInfoCoreLib/getStationData";
import { useStationList } from "@/stateBox/useStationList";
type Props = {
dialog: boolean;
setDialog: (dialog: boolean) => void;
currentTrainData: trainDataType;
stationInput: string;
stationNumberInput: string;
PosNum:number;
Pos:string;
Line:string;
StationNum: string;
lineInput: string;
setLineInput: (line: string) => void;
posInput: string;
descInput: string;
setPosInput: (pos: string) => void;
descInput: string;
setDescInput: (desc: string) => void;
station: {
Station_JP: string;
StationNumber: string;
};
};
export const TrainPositionDataPush: FC<Props> = ({
export const StationPosPushDialog: FC<Props> = ({
// Dialog表示関係
dialog,
setDialog,
currentTrainData,
stationInput,
stationNumberInput,
//固定情報
PosNum,//地点ID
Pos,//駅名
Line,//路線名
StationNum,//駅ナンバリング
//入力欄
lineInput,
setLineInput,
posInput,
descInput,
setPosInput,
descInput,
setDescInput,
station,
}) => {
const { stationList } = useStationList();
const sendPlatformData = () => {
fetch(`https://n8n.haruk.in/webhook/JR-shikoku-PosID`, {
fetch(`https://n8n.haruk.in/webhook/JR-shikoku-PosID-v3`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
PosId: currentTrainData?.PosNum,
lineName: currentTrainData?.Line,
PlatformNum: parseInt(posInput),
Description: descInput,
StationName: station.Station_JP,
StationId: station.StationNumber,
PosId: PosNum, //自動位置情報ID
StationId: getStationID(Pos, stationList), //自動駅ID
StationName: Pos, //自動:駅名、漢字
lineName: Line, //自動位置情報路線ID(koutoku/yosan)
Description: descInput, //手動入力、参考情報
platformNumber: parseInt(posInput), //手動入力、乗り場表記
lineNumber: parseInt(lineInput), //手動入力、番線表記
}),
})
.then(() => {
@@ -55,22 +65,30 @@ export const TrainPositionDataPush: FC<Props> = ({
};
return (
<Dialog isVisible={dialog} onBackdropPress={() => setDialog(false)}>
<Text>: {currentTrainData?.Line}</Text>
<Text>ID: {currentTrainData?.PosNum}</Text>
<Text>: {stationInput}</Text>
<Text>: {stationNumberInput}</Text>
<Text style={{ fontSize: 20, fontWeight: "bold" }}>稿</Text>
<Text>: {Line}</Text>
<Text>ID: {PosNum}</Text>
<Text>: {Pos}</Text>
<Text>: {StationNum}</Text>
<Input
label="番線"
label="乗り場"
inputMode="numeric"
value={posInput}
onChangeText={setPosInput}
/>
<Input
label="番線"
inputMode="numeric"
value={lineInput}
onChangeText={setLineInput}
/>
<Input
label="参考情報"
inputMode="text"
value={descInput}
onChangeText={setDescInput}
/>
<Text style={{ fontSize: 12, fontWeight: "bold" }}>稿稿</Text>
<Button title="送信" onPress={sendPlatformData} />
</Dialog>
);

View File

@@ -1,234 +0,0 @@
import React, { useState, useEffect } from "react";
import { View } from "react-native";
import { widthPercentageToDP as wp } from "react-native-responsive-screen";
import { useInterval } from "../../lib/useInterval";
import { objectIsEmpty } from "../../lib/objectIsEmpty";
import { useCurrentTrain } from "../../stateBox/useCurrentTrain";
import { useAreaInfo } from "../../stateBox/useAreaInfo";
import { AS } from "../../storageControl";
import { Footer } from "./LED_Vision_Component/Footer";
import { Header } from "./LED_Vision_Component/Header";
import { Description } from "./LED_inside_Component/Description";
import { EachData } from "./EachData";
/**
*
* 1-30M しおかぜ
* 31-58D 南風
* 1001-1030M いしづち(併結)
* 1041-1046M いしづち(単独)
* 1051-1082D 宇和海
* 1091M MX松山
* 1092M MX高松
* 2001-2010D しまんと
* 2071-2086D あしずり
* 3001-3033D うずしお
* 3101-3177M マリンライナー
* 4001-4011D 剣山
* 5006,13,22,29 うずしお(岡山直通南風併結)
* 5831-5843D 土佐くろしお鉄道ごめん・なはり線直通快速
* 5853-5892D 土佐くろしお鉄道ごめん・なはり線直通普通
* 8011,8012D 四国まんなか千年ものがたり
* 8031,(8041) サンライズ瀬戸, 琴平(延長)
* 8053,8054D トキの夜明けのものがたり
* 8176,8179D アンパントロッコタカマツ
* 8277,8278D アンパントロッココトヒラ
* 8451,8452D よしの川トロッコ
* 8814,8819D しまんトロッコ
* 8911-8914D 伊予灘ものがたり
* 9001-9030* いしづち(リレー)
* 9031M サンライズ瀬戸琴平(延長)(臨時?)
* 9062D 四国まんなか千年ものがたり(臨時?)
*/
export default function LED_vision(props) {
const {
station,
trainDiagram,
getCurrentTrain,
navigate,
openStationACFromEachTrainInfo,
} = props;
const { currentTrain } = useCurrentTrain();
const [stationDiagram, setStationDiagram] = useState({}); //当該駅の全時刻表
const [finalSwitch, setFinalSwitch] = useState(false);
const [trainIDSwitch, setTrainIDSwitch] = useState(false);
const [trainDescriptionSwitch, setTrainDescriptionSwitch] = useState(false);
const [isInfoArea, setIsInfoArea] = useState(false);
const { areaInfo, areaStationID } = useAreaInfo();
useEffect(() => {
AS.getItem("LEDSettings/trainIDSwitch").then((data) => {
setTrainIDSwitch(data === "true");
});
AS.getItem("LEDSettings/trainDescriptionSwitch").then((data) => {
setTrainDescriptionSwitch(data == "true");
});
AS.getItem("LEDSettings/finalSwitch").then((data) => {
setFinalSwitch(data == "true");
});
}, []);
useEffect(() => {
// 現在の駅に停車するダイヤを作成する副作用[列車ダイヤと現在駅情報]
if (!trainDiagram) {
setStationDiagram({});
return;
}
let returnData = {};
Object.keys(trainDiagram).forEach((key) => {
if (trainDiagram[key].match(station[0].Station_JP + ",")) {
returnData[key] = trainDiagram[key];
}
});
setStationDiagram(returnData);
setIsInfoArea(station.some((s) => areaStationID.includes(s.StationNumber)));
}, [trainDiagram, station]);
const [trainTimeAndNumber, setTrainTimeAndNumber] = useState(null);
useEffect(() => {
//現在の駅に停車する列車から時刻を切り出してLEDベースにフォーマット
if (objectIsEmpty(stationDiagram)) return () => {};
const getTimeData = getTime(stationDiagram, station[0]);
setTrainTimeAndNumber(getTimeData);
}, [stationDiagram]);
const [selectedTrain, setSelectedTrain] = useState([]);
useEffect(() => {
if (!trainTimeAndNumber) return () => {};
if (!currentTrain) return () => {};
const data = trainTimeAndNumber
.filter((d) => currentTrain.map((m) => m.num).includes(d.train))
.filter(timeFiltering)
.filter((d) => !!finalSwitch || d.lastStation != "当駅止");
setSelectedTrain(data);
}, [trainTimeAndNumber, currentTrain, finalSwitch]);
const getTime = (stationDiagram, station) => {
const returnData = Object.keys(stationDiagram).map((trainNum) => {
let trainData = {};
stationDiagram[trainNum].split("#").forEach((data) => {
if (data.match("着")) {
trainData.lastStation = data.split(",着,")[0];
}
if (data.split(",")[0] === station.Station_JP) {
if (data.match(",発,")) {
trainData.time = data.split(",発,")[1];
} else if(data.match(",着,")){
trainData.time = data.split(",着,")[1];
trainData.lastStation = "当駅止";
}
}
});
return {
train: trainNum,
time: trainData.time,
lastStation: trainData.lastStation,
};
}).filter((d) => d.time);
return returnData.sort((a, b) => {
switch (true) {
case parseInt(a.time.split(":")[0]) < parseInt(b.time.split(":")[0]):
return -1;
case parseInt(a.time.split(":")[0]) > parseInt(b.time.split(":")[0]):
return 1;
case parseInt(a.time.split(":")[1]) < parseInt(b.time.split(":")[1]):
return -1;
case parseInt(a.time.split(":")[1]) > parseInt(b.time.split(":")[1]):
return 1;
default:
return 0;
}
});
};
const timeFiltering = (d) => {
const date = new Date();
const newDate = new Date();
let data = d.time.split(":");
let delay = isNaN(currentTrain.filter((t) => t.num == d.train)[0].delay)
? 0
: currentTrain.filter((t) => t.num == d.train)[0].delay;
date.setHours(parseInt(data[0]));
date.setMinutes(parseInt(data[1]) + parseInt(delay));
return !(newDate > date);
};
const [areaString, setAreaString] = useState("");
const [areaStringLength, setAreaStringLength] = useState(0);
const [move, setMove] = useState(0);
useInterval(
() => {
if (areaInfo != "") {
setMove(areaStringLength < move ? 0 : move + 1);
}
},
350,
true
);
useEffect(() => {
if (!areaInfo) {
setAreaString("");
return () => {};
}
setAreaString(
areaInfo.substring(move, areaInfo.length) + areaInfo.substring(0, move)
);
}, [move]);
useEffect(() => {
if (!areaInfo) {
setAreaStringLength(0);
return () => {};
}
setAreaStringLength(areaInfo.length);
}, [areaInfo]);
return (
<View
style={{
width: wp("98%"),
/* height: wp("98%")/10*9, */ backgroundColor: "#432",
borderWidth: 1,
margin: 10,
marginHorizontal: wp("1%"),
}}
>
<Header getCurrentTrain={getCurrentTrain} />
{selectedTrain.map((d) => (
<EachData
{...{
d,
trainIDSwitch,
trainDescriptionSwitch,
navigate,
openStationACFromEachTrainInfo,
}}
station={station[0]}
key={d.train}
/>
))}
{areaString != "" && isInfoArea && (
<Description
numberOfLines={1}
info={areaString.replaceAll("\n", "").replaceAll("\r", "")}
onClick={() => alert(areaInfo)}
/>
)}
<Footer
{...{
trainIDSwitch,
setTrainIDSwitch,
trainDescriptionSwitch,
setTrainDescriptionSwitch,
finalSwitch,
setFinalSwitch,
}}
/>
</View>
);
}

View File

@@ -0,0 +1,164 @@
import React, { useState, useEffect, FC } from "react";
import { View, useWindowDimensions } from "react-native";
import { objectIsEmpty } from "@/lib/objectIsEmpty";
import { useCurrentTrain } from "@/stateBox/useCurrentTrain";
import { useAreaInfo } from "@/stateBox/useAreaInfo";
import { AS } from "@/storageControl";
import { Footer } from "@/components/発車時刻表/LED_Vision_Component/Footer";
import { Header } from "@/components/発車時刻表/LED_Vision_Component/Header";
import { EachData } from "@/components/発車時刻表/EachData";
import { useAllTrainDiagram } from "@/stateBox/useAllTrainDiagram";
import { AreaDescription } from "@/components/発車時刻表/LED_inside_Component/AreaDescription";
import { getTime, trainTimeFiltering } from "@/lib/trainTimeFiltering";
import { eachTrainDiagramType, StationProps } from "@/lib/CommonTypes";
import { useNavigation } from "@react-navigation/native";
/**
*
* 1-30M しおかぜ
* 31-58D 南風
* 1001-1030M いしづち(併結)
* 1041-1046M いしづち(単独)
* 1051-1082D 宇和海
* 1091M MX松山
* 1092M MX高松
* 2001-2010D しまんと
* 2071-2086D あしずり
* 3001-3033D うずしお
* 3101-3177M マリンライナー
* 4001-4011D 剣山
* 5006,13,22,29 うずしお(岡山直通南風併結)
* 5831-5843D 土佐くろしお鉄道ごめん・なはり線直通快速
* 5853-5892D 土佐くろしお鉄道ごめん・なはり線直通普通
* 8011,8012D 四国まんなか千年ものがたり
* 8031,(8041) サンライズ瀬戸, 琴平(延長)
* 8053,8054D トキの夜明けのものがたり
* 8176,8179D アンパントロッコタカマツ
* 8277,8278D アンパントロッココトヒラ
* 8451,8452D よしの川トロッコ
* 8814,8819D しまんトロッコ
* 8911-8914D 伊予灘ものがたり
* 9001-9030* いしづち(リレー)
* 9031M サンライズ瀬戸琴平(延長)(臨時?)
* 9062D 四国まんなか千年ものがたり(臨時?)
*/
type props = {
station: StationProps[];
};
export const LED_vision: FC<props> = (props) => {
const { station } = props;
const { navigate, addListener, isFocused } = useNavigation();
const { currentTrain } = useCurrentTrain();
const [stationDiagram, setStationDiagram] = useState<{
[key: string]: string;
}>({}); //当該駅の全時刻表
const [finalSwitch, setFinalSwitch] = useState(false);
const [trainIDSwitch, setTrainIDSwitch] = useState(false);
const [trainDescriptionSwitch, setTrainDescriptionSwitch] = useState(false);
const [isInfoArea, setIsInfoArea] = useState(false);
const { areaInfo, areaStationID } = useAreaInfo();
const { allTrainDiagram } = useAllTrainDiagram();
useEffect(() => {
AS.getItem("LEDSettings/trainIDSwitch").then((data) => {
setTrainIDSwitch(data === "true");
});
AS.getItem("LEDSettings/trainDescriptionSwitch").then((data) => {
setTrainDescriptionSwitch(data === "true");
});
AS.getItem("LEDSettings/finalSwitch").then((data) => {
setFinalSwitch(data === "true");
});
}, []);
useEffect(() => {
// 現在の駅に停車するダイヤを作成する副作用[列車ダイヤと現在駅情報]
if (!allTrainDiagram) {
setStationDiagram({});
return;
}
let returnData = {};
Object.keys(allTrainDiagram).forEach((key) => {
if (allTrainDiagram[key].match(station[0].Station_JP + ",")) {
returnData[key] = allTrainDiagram[key];
}
});
setStationDiagram(returnData);
setIsInfoArea(station.some((s) => areaStationID.includes(s.StationNumber)));
}, [allTrainDiagram, station]);
/*
{lastStation: "当駅止", time: "12:34", train: "1234M"}
*/
const [trainTimeAndNumber, setTrainTimeAndNumber] = useState<
eachTrainDiagramType[]
>([]);
useEffect(() => {
//現在の駅に停車する列車から時刻を切り出してLEDベースにフォーマット
if (objectIsEmpty(stationDiagram)) return () => {};
const getTimeData = getTime(stationDiagram, station[0]);
setTrainTimeAndNumber(getTimeData);
}, [stationDiagram]);
const [selectedTrain, setSelectedTrain] = useState<eachTrainDiagramType[]>(
[]
);
useEffect(() => {
if (!trainTimeAndNumber) return () => {};
if (!currentTrain) return () => {};
const data = trainTimeAndNumber
.filter((d) => currentTrain.map((m) => m.num).includes(d.train)) //現在の列車に絞る[ToDo]
.filter((d) => trainTimeFiltering({ d, currentTrain, station })) //時間フィルター
.filter((d) => !!finalSwitch || d.lastStation != station[0].Station_JP); //最終列車表示設定
setSelectedTrain(data);
}, [trainTimeAndNumber, currentTrain, finalSwitch]);
const { width } = useWindowDimensions();
const adjustedWidth = width * 0.98;
return (
<View
style={{
width: adjustedWidth,
/* height: wp("98%")/10*9, */ backgroundColor: "#432",
borderWidth: 1,
margin: 10,
marginHorizontal: width * 0.01,
}}
>
<Header station={station[0]} />
{selectedTrain.map((d) => (
<EachData
{...{
d,
trainIDSwitch,
trainDescriptionSwitch,
navigate,
openStationACFromEachTrainInfo: () => {},
}}
station={station[0]}
key={d.train}
/>
))}
{areaInfo != "" && isInfoArea && (
<AreaDescription
numberOfLines={1}
areaInfo={areaInfo}
onClick={() => alert(areaInfo)}
/>
)}
<Footer
{...{
trainIDSwitch,
setTrainIDSwitch,
trainDescriptionSwitch,
setTrainDescriptionSwitch,
finalSwitch,
setFinalSwitch,
}}
/>
</View>
);
};

View File

@@ -1,9 +1,22 @@
import React, { CSSProperties, FC } from "react";
import { widthPercentageToDP as wp } from "react-native-responsive-screen";
import { Platform, Text, TextStyle, View, ViewStyle } from "react-native";
import {
Platform,
Text,
TextStyle,
useWindowDimensions,
View,
ViewStyle,
} from "react-native";
import { StationName } from "./StationName";
import lineColorList from "../../assets/originData/lineColorList";
export const NextPreStationLine = ({ nexStation, preStation, isMatsuyama }) => {
const 下枠フレーム: ViewStyle = {
flex: 1,
flexDirection: "row",
alignContent: "center",
alignItems: "center",
};
return (
<View style={}>
<View style={}>
@@ -49,12 +62,40 @@ type FCimport = {
children: string;
};
const BottomSideArrow: FC<FCimport> = ({ isMatsuyama, children }) => {
const 下枠左右マーク: TextStyle = {
fontWeight: "bold",
fontSize: parseInt("20%"),
color: "white",
paddingHorizontal: 5,
textAlignVertical: "center",
};
return !isMatsuyama && <Text style={}>{children}</Text>;
};
const BottomStationNumberView: FC<FCimport> = ({ isMatsuyama, children }) => {
const { width } = useWindowDimensions();
const lineID = children.slice(0, 1);
const lineName = children.slice(1);
const 下枠駅ナンバー: ViewStyle = {
alignContent: "center",
alignItems: "center",
width: width * 0.08,
height: width * 0.08,
margin: width * 0.01,
backgroundColor: "white",
borderWidth: parseInt("3%"),
borderRadius: parseInt("100%"),
};
const 下枠駅ナンバーB: ViewStyle = {
alignContent: "center",
alignItems: "center",
width: width * 0.07,
height: width * 0.07,
margin: width * 0.02,
backgroundColor: "white",
borderWidth: parseInt("3%"),
borderRadius: parseInt("100%"),
};
return (
<View
style={{
@@ -77,37 +118,3 @@ const BottomStationNumberView: FC<FCimport> = ({ isMatsuyama, children }) => {
</View>
);
};
const 下枠フレーム: ViewStyle = {
flex: 1,
flexDirection: "row",
alignContent: "center",
alignItems: "center",
};
const 下枠左右マーク: TextStyle = {
fontWeight: "bold",
fontSize: parseInt("20%"),
color: "white",
paddingHorizontal: 5,
textAlignVertical: "center",
};
const 下枠駅ナンバー: ViewStyle = {
alignContent: "center",
alignItems: "center",
width: wp("8%"),
height: wp("8%"),
margin: wp("1%"),
backgroundColor: "white",
borderWidth: parseInt("3%"),
borderRadius: parseInt("100%"),
};
const 下枠駅ナンバーB: ViewStyle = {
alignContent: "center",
alignItems: "center",
width: wp("7%"),
height: wp("7%"),
margin: wp("2%"),
backgroundColor: "white",
borderWidth: parseInt("3%"),
borderRadius: parseInt("100%"),
};

View File

@@ -1,6 +1,10 @@
import React, { useRef, useState, useEffect, useLayoutEffect } from "react";
import { View, Text, TouchableOpacity } from "react-native";
import { widthPercentageToDP as wp } from "react-native-responsive-screen";
import {
View,
Text,
TouchableOpacity,
useWindowDimensions,
} from "react-native";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import LottieView from "lottie-react-native";
import { useInterval } from "../../lib/useInterval";
@@ -15,7 +19,14 @@ import { AddressText } from "./AddressText";
import { useStationList } from "../../stateBox/useStationList";
export default function Sign(props) {
const { currentStation, oP, oLP, isCurrentStation = false } = props;
const { oP, oLP, isCurrentStation = false, stationID } = props;
const { width, height } = useWindowDimensions();
const { getStationDataFromId } = useStationList();
if (!stationID) {
return <></>;
}
const [currentStationData] = useState(getStationDataFromId(stationID));
const { favoriteStation, setFavoriteStation } = useFavoriteStation();
const [nexPrePosition, setNexPrePosition] = useState(0);
const { originalStationList } = useStationList();
@@ -26,48 +37,40 @@ export default function Sign(props) {
useLayoutEffect(() => {
const isFavorite = favoriteStation.filter((d) => {
const compare = JSON.stringify(d);
const current = JSON.stringify(currentStation);
if (compare === current) {
return true;
} else {
return false;
}
const current = JSON.stringify(currentStationData);
return compare === current;
});
setTestButtonStatus(isFavorite.length == 0 ? false : true);
}, [favoriteStation, currentStation]);
}, [favoriteStation, currentStationData]);
useEffect(() => {
const isFavorite = favoriteStation.filter((d) => {
const compare = JSON.stringify(d);
const current = JSON.stringify(currentStation);
if (compare === current) {
return true;
} else {
return false;
}
const current = JSON.stringify(currentStationData);
return compare === current;
});
setTestButtonStatus(isFavorite.length == 0 ? false : true);
}, [favoriteStation, currentStation]);
}, [favoriteStation, currentStationData]);
useInterval(() => {
if (currentStation.length == 1) {
if (currentStationData.length == 1) {
setNexPrePosition(0);
return () => {};
}
setNexPrePosition(
nexPrePosition + 1 == currentStation.length ? 0 : nexPrePosition + 1
nexPrePosition + 1 == currentStationData.length ? 0 : nexPrePosition + 1
);
}, 2000);
useEffect(() => {
setNexPrePosition(0);
getPreNextStation(currentStation[0]);
if (currentStation.length == 1) return () => {};
getPreNextStation(currentStation[1]);
}, [currentStation]);
getPreNextStation(currentStationData[0]);
if (currentStationData.length == 1) return () => {};
getPreNextStation(currentStationData[1]);
}, [currentStationData]);
useEffect(() => {
if (!currentStation[nexPrePosition]) return () => {};
getPreNextStation(currentStation[nexPrePosition]);
if (!currentStationData[nexPrePosition]) return () => {};
getPreNextStation(currentStationData[nexPrePosition]);
}, [nexPrePosition]);
const getPreNextStation = (now) => {
const lineList = [
@@ -101,25 +104,81 @@ export default function Sign(props) {
if (returnData[1]) setNexStation(returnData[1]);
}
};
const isMatsuyama = currentStation[0].StationNumber == "Y55";
const isMatsuyama = currentStationData[0].StationNumber == "Y55";
//const isMatsuyama = true;
const favoliteChanger = () => {
if (testButtonStatus) {
const otherData = favoriteStation.filter((d) => {
const compare = JSON.stringify(d);
const current = JSON.stringify(currentStation);
const current = JSON.stringify(currentStationData);
return compare !== current;
});
AS.setItem("favoriteStation", JSON.stringify(otherData));
setFavoriteStation(otherData);
} else {
let ret = favoriteStation;
ret.push(currentStation);
ret.push(currentStationData);
AS.setItem("favoriteStation", JSON.stringify(ret));
setFavoriteStation(ret);
}
setTestButtonStatus(!testButtonStatus);
};
const styleSheet = {
外枠: {
width: width * 0.8,
height: ((width * 0.8) / 20) * 9,
borderColor: "#0099CC",
borderWidth: 1,
backgroundColor: "white",
},
外枠B: {
width: width * 0.8,
height: ((width * 0.8) / 20) * 9,
borderWidth: 0,
},
下帯: {
position: "absolute",
bottom: "8%",
left: "0%",
width: "100%",
height: "27%",
backgroundColor: "#0099CC",
},
下帯B: {
position: "absolute",
bottom: "0%",
left: "0%",
width: "100%",
height: "26%",
backgroundColor: "#454545",
},
JRStyle: {
position: "absolute",
top: "2%",
left: "2%",
fontWeight: "bold",
fontSize: parseInt("25%"),
color: "#0099CC",
},
下帯内容: {
position: "absolute",
bottom: "8%",
height: "27%",
width: "100%",
alignItems: "center",
flexDirection: "column",
},
下帯内容B: {
position: "absolute",
bottom: "0%",
height: "26%",
width: "100%",
alignItems: "center",
flexDirection: "column",
},
};
return (
<TouchableOpacity
style={styleSheet[isMatsuyama ? "外枠B" : "外枠"]}
@@ -131,15 +190,17 @@ export default function Sign(props) {
autoPlay
loop
style={{
width: wp("80%"),
height: (wp("80%") / 20) * 9,
width: width * 0.8,
height: ((width * 0.8) / 20) * 9,
backgroundColor: "#fff",
}}
source={require("../../assets/StationSign.json")}
/>
)}
<StationNumberMaker {...{ currentStation, isMatsuyama }} />
<StationNameArea {...{ currentStation, isMatsuyama }} />
<StationNumberMaker {...{ currentStation: currentStationData }} />
<StationNameArea
{...{ currentStation: currentStationData, isMatsuyama }}
/>
{isCurrentStation ? (
<View style={{ position: "absolute", right: 0, top: 0 }}>
<MaterialCommunityIcons
@@ -163,62 +224,7 @@ export default function Sign(props) {
<View style={styleSheet[isMatsuyama ? "下帯内容B" : "下帯内容"]}>
<NextPreStationLine {...{ nexStation, preStation, isMatsuyama }} />
</View>
<AddressText {...{ currentStation, isMatsuyama }} />
<AddressText {...{ currentStation: currentStationData, isMatsuyama }} />
</TouchableOpacity>
);
}
const styleSheet = {
外枠: {
width: wp("80%"),
height: (wp("80%") / 20) * 9,
borderColor: "#0099CC",
borderWidth: 1,
backgroundColor: "white",
},
外枠B: {
width: wp("80%"),
height: (wp("80%") / 20) * 9,
borderWidth: 0,
},
下帯: {
position: "absolute",
bottom: "8%",
left: "0%",
width: "100%",
height: "27%",
backgroundColor: "#0099CC",
},
下帯B: {
position: "absolute",
bottom: "0%",
left: "0%",
width: "100%",
height: "26%",
backgroundColor: "#454545",
},
JRStyle: {
position: "absolute",
top: "2%",
left: "2%",
fontWeight: "bold",
fontSize: parseInt("25%"),
color: "#0099CC",
},
下帯内容: {
position: "absolute",
bottom: "8%",
height: "27%",
width: "100%",
alignItems: "center",
flexDirection: "column",
},
下帯内容B: {
position: "absolute",
bottom: "0%",
height: "26%",
width: "100%",
alignItems: "center",
flexDirection: "column",
},
};

View File

@@ -1,17 +1,24 @@
import React from "react";
import React, { FC } from "react";
import { Text, View } from "react-native";
import { widthPercentageToDP as wp } from "react-native-responsive-screen";
import lineColorList from "../../assets/originData/lineColorList";
import { useWindowDimensions } from "react-native";
import lineColorList from "@/assets/originData/lineColorList";
import { StationProps } from "@/lib/CommonTypes";
export const StationNumberMaker = (props) => {
const { currentStation, isMatsuyama } = props;
type props = {
currentStation: StationProps[];
useEach?: boolean;
singleSize?: number;
};
export const StationNumberMaker: FC<props> = (props) => {
const { currentStation, useEach = false, singleSize } = props;
const { width } = useWindowDimensions();
const getTop = (array: number[], index: number) => {
if (array.length == 1) return 20;
else if (index == 0) return 5;
else if (index == 1) return 35;
else return 20;
};
return currentStation
return <>{currentStation
.filter((d) => (d.StationNumber ? true : false))
.map((d, index, array) => {
const lineID = d.StationNumber.slice(0, 1);
@@ -19,29 +26,41 @@ export const StationNumberMaker = (props) => {
return (
<View
style={{
position: "absolute",
alignContent: "center",
alignItems: "center",
top: `${getTop(array, index)}%`,
right: "10%",
width: wp("10%"),
height: wp("10%"),
borderColor: lineColorList[lineID],
backgroundColor: "white",
...(useEach ? {
width: singleSize,
height: singleSize,
borderWidth: parseInt("1%"),
borderRadius: parseInt("100%"),
} : {
width: (width / 100) * 10,
height: (width / 100) * 10,
borderWidth: parseInt("3%"),
borderRadius: parseInt("100%"),
position: "absolute",
top: `${getTop(array, index)}%`,
right: "10%"
})
}}
key={array[index].StationNumber}
>
<View style={{ flex: 1 }} />
<Text
style={{
fontSize: parseInt("13%"),
margin: 0,
padding: 0,
textAlign: "center",
color: "black",
color: "black",
fontWeight: "bold",
...(useEach ? {
fontSize: 6,//singleSize * 0.03,
}:{
fontSize: parseInt("13%"),
})
}}
>
{lineID + "\n" + lineName}
@@ -49,5 +68,5 @@ export const StationNumberMaker = (props) => {
<View style={{ flex: 1 }} />
</View>
);
});
})}</>
};

View File

@@ -1 +1 @@
export const news = "2025-03-06";
export const news = "2025-07-09";

851
current.txt Normal file
View File

@@ -0,0 +1,851 @@
[
{"104M":"多度津,発,5:51#讃岐塩屋,発,5:55#丸亀,発,5:57#宇多津,発,6:04#坂出,発,6:09#八十場,発,6:12#鴨川,発,6:19#讃岐府中,発,6:22#国分,発,6:25#端岡,発,6:28#鬼無,発,6:32#香西,発,6:34#高松,着,6:39#"},
{"108M":"観音寺,発,6:26#本山,発,6:31#比地大,発,6:34#高瀬,発,6:38#みの,発,6:41#詫間,発,6:45#海岸寺,発,6:50#多度津,発,6:58#讃岐塩屋,発,7:01#丸亀,発,7:04#宇多津,発,7:08#坂出,発,7:13#八十場,発,7:16#鴨川,発,7:26#讃岐府中,発,7:30#国分,発,7:33#端岡,発,7:36#鬼無,発,7:40#香西,発,7:43#高松,着,7:47#"},
{"110M":"多度津,発,7:18#讃岐塩屋,発,7:21#丸亀,発,7:24#宇多津,発,7:28#坂出,発,7:32#八十場,発,7:36#鴨川,発,7:39#讃岐府中,発,7:42#国分,発,7:45#端岡,発,7:48#鬼無,発,7:52#香西,発,7:55#高松,着,7:59#"},
{"112M":"伊予西条,発,5:36#中萩,発,5:42#新居浜,発,5:47#多喜浜,発,5:51#関川,発,5:58#伊予土居,発,6:02#赤星,発,6:05#伊予寒川,発,6:09#伊予三島,発,6:25#川之江,発,6:38#箕浦,発,6:43#豊浜,発,6:50#観音寺,発,6:56#本山,発,7:00#比地大,発,7:03#高瀬,発,7:07#みの,発,7:10#詫間,発,7:14#海岸寺,発,7:19#多度津,発,7:24#讃岐塩屋,発,7:27#丸亀,発,7:30#宇多津,発,7:33#坂出,発,7:38#八十場,発,7:41#鴨川,発,7:44#讃岐府中,発,7:47#国分,発,7:50#端岡,発,7:53#鬼無,発,7:57#香西,発,8:00#高松,着,8:04#"},
{"116M":"伊予西条,発,6:13#中萩,発,6:19#新居浜,発,6:24#多喜浜,発,6:31#関川,発,6:38#伊予土居,発,6:44#赤星,発,6:48#伊予寒川,発,6:52#伊予三島,発,7:01#川之江,発,7:05#箕浦,発,7:11#豊浜,発,7:15#観音寺,発,7:21#本山,発,7:30#比地大,発,7:33#高瀬,発,7:38#みの,発,7:41#詫間,発,7:44#海岸寺,発,7:50#多度津,発,7:56#讃岐塩屋,発,7:59#丸亀,発,8:03#宇多津,発,8:07#坂出,発,8:12#八十場,発,8:15#鴨川,発,8:18#讃岐府中,発,8:22#国分,発,8:25#端岡,発,8:29#鬼無,発,8:33#香西,発,8:36#高松,着,8:41#"},
{"128M":"多度津,発,12:09#讃岐塩屋,発,12:12#丸亀,発,12:15#宇多津,発,12:18#坂出,発,12:24#八十場,発,12:28#鴨川,発,12:31#讃岐府中,発,12:34#国分,発,12:37#端岡,発,12:40#鬼無,発,12:44#香西,発,12:47#高松,着,12:51#"},
{"130M":"観音寺,発,12:13#本山,発,12:20#比地大,発,12:23#高瀬,発,12:32#みの,発,12:35#詫間,発,12:39#海岸寺,発,12:48#多度津,発,13:02#讃岐塩屋,発,13:05#丸亀,発,13:08#宇多津,発,13:11#坂出,発,13:16#端岡,発,13:25#高松,着,13:33#"},
{"132M":"多度津,発,14:02#讃岐塩屋,発,14:05#丸亀,発,14:08#宇多津,発,14:11#坂出,発,14:16#端岡,発,14:25#高松,着,14:33#"},
{"134M":"多度津,発,14:09#讃岐塩屋,発,14:12#丸亀,発,14:15#宇多津,発,14:18#坂出,発,14:24#八十場,発,14:27#鴨川,発,14:30#讃岐府中,発,14:33#国分,発,14:36#端岡,発,14:39#鬼無,発,14:42#香西,発,14:45#高松,着,14:49#"},
{"136M":"観音寺,発,14:14#本山,発,14:21#比地大,発,14:25#高瀬,発,14:33#みの,発,14:36#詫間,発,14:40#海岸寺,発,14:46#多度津,発,15:02#讃岐塩屋,発,15:05#丸亀,発,15:08#宇多津,発,15:11#坂出,発,15:16#端岡,発,15:25#高松,着,15:33#"},
{"140M":"観音寺,発,15:12#本山,発,15:17#比地大,発,15:20#高瀬,発,15:33#みの,発,15:37#詫間,発,15:44#海岸寺,発,15:50#多度津,発,16:02#讃岐塩屋,発,16:05#丸亀,発,16:08#宇多津,発,16:11#坂出,発,16:16#端岡,発,16:25#高松,着,16:33#"},
{"142M":"多度津,発,16:12#讃岐塩屋,発,16:15#丸亀,発,16:18#宇多津,発,16:22#坂出,発,16:27#八十場,発,16:30#鴨川,発,16:34#讃岐府中,発,16:37#国分,発,16:40#端岡,発,16:48#鬼無,発,16:52#香西,発,16:55#高松,着,16:59#"},
{"144M":"観音寺,発,16:12#本山,発,16:16#比地大,発,16:19#高瀬,発,16:23#みの,発,16:26#詫間,発,16:31#海岸寺,発,16:37#多度津,発,17:02#讃岐塩屋,発,17:05#丸亀,発,17:08#宇多津,発,17:11#坂出,発,17:16#端岡,発,17:25#高松,着,17:33#"},
{"146M":"観音寺,発,17:31#本山,発,17:38#比地大,発,17:41#高瀬,発,17:45#みの,発,17:48#詫間,発,17:52#海岸寺,発,17:57#多度津,発,18:02#讃岐塩屋,発,18:05#丸亀,発,18:08#宇多津,発,18:11#坂出,発,18:16#鴨川,発,18:20#国分,発,18:25#端岡,発,18:28#鬼無,発,18:31#高松,着,18:37#"},
{"150M":"観音寺,発,18:18#本山,発,18:24#比地大,発,18:28#高瀬,発,18:36#みの,発,18:39#詫間,発,18:42#海岸寺,発,18:47#多度津,発,19:02#讃岐塩屋,発,19:06#丸亀,発,19:09#宇多津,発,19:12#坂出,発,19:17#端岡,発,19:27#高松,着,19:35#"},
{"152M":"多度津,発,19:14#讃岐塩屋,発,19:17#丸亀,発,19:20#宇多津,発,19:23#坂出,発,19:27#八十場,発,19:31#鴨川,発,19:33#讃岐府中,発,19:36#国分,発,19:39#端岡,発,19:42#鬼無,発,19:46#香西,発,19:49#高松,着,19:53#"},
{"154M":"多度津,発,20:54#讃岐塩屋,発,20:58#丸亀,発,21:01#宇多津,発,21:04#坂出,発,21:09#八十場,発,21:13#鴨川,発,21:16#讃岐府中,発,21:19#国分,発,21:22#端岡,発,21:25#鬼無,発,21:29#香西,発,21:32#高松,着,21:36#"},
{"156M":"観音寺,発,20:48#本山,発,20:53#比地大,発,20:55#高瀬,発,20:59#みの,発,21:02#詫間,発,21:05#海岸寺,発,21:11#多度津,発,21:18#讃岐塩屋,発,21:22#丸亀,発,21:24#宇多津,発,21:28#坂出,発,21:33#鴨川,発,21:37#国分,発,21:42#端岡,発,21:45#鬼無,発,21:49#高松,着,21:55#"},
{"158M":"多度津,発,22:48#讃岐塩屋,発,22:52#丸亀,発,22:54#宇多津,発,22:57#坂出,発,23:02#八十場,発,23:05#鴨川,発,23:08#讃岐府中,発,23:11#国分,発,23:14#端岡,発,23:17#鬼無,発,23:21#香西,発,23:24#高松,着,23:28#"},
{"510M":"今治,発,5:50#伊予富田,発,5:54#伊予桜井,発,5:58#伊予三芳,発,6:06#壬生川,発,6:11#玉之江,発,6:14#伊予小松,発,6:18#伊予氷見,発,6:20#石鎚山,発,6:24#伊予西条,発,6:30#中萩,発,6:39#新居浜,着,6:43#"},
{"514M":"松山,発,5:53#三津浜,発,5:58#伊予和気,発,6:03#堀江,発,6:06#光洋台,発,6:10#粟井,発,6:13#柳原,発,6:15#伊予北条,発,6:19#大浦,発,6:30#浅海,発,6:34#菊間,発,6:39#伊予亀岡,発,6:54#大西,発,6:59#波方,発,7:06#波止浜,発,7:10#今治,発,7:20#伊予富田,発,7:24#伊予桜井,発,7:28#伊予三芳,発,7:35#壬生川,発,7:42#玉之江,発,7:45#伊予小松,発,7:49#伊予氷見,発,7:51#石鎚山,発,7:54#伊予西条,発,8:01#中萩,発,8:07#新居浜,発,8:12#多喜浜,発,8:16#関川,発,8:23#伊予土居,発,8:28#赤星,発,8:31#伊予寒川,発,8:35#伊予三島,発,8:48#川之江,発,8:53#箕浦,発,8:59#豊浜,発,9:04#観音寺,着,9:08#"},
{"520M":"松山,発,7:48#三津浜,発,7:54#伊予和気,発,8:02#堀江,発,8:05#光洋台,発,8:08#粟井,発,8:11#柳原,発,8:13#伊予北条,着,8:16#"},
{"550M":"伊予西条,発,18:24#中萩,発,18:30#新居浜,発,18:47#多喜浜,発,18:51#関川,発,18:59#伊予土居,発,19:05#赤星,発,19:09#伊予寒川,発,19:13#伊予三島,発,19:17#川之江,発,19:24#箕浦,発,19:30#豊浜,発,19:35#観音寺,着,19:40#"},
{"558M":"松山,発,19:07#三津浜,発,19:12#伊予和気,発,19:19#堀江,発,19:22#光洋台,発,19:25#粟井,発,19:28#柳原,発,19:31#伊予北条,発,19:51#大浦,発,19:56#浅海,発,20:00#菊間,発,20:08#伊予亀岡,発,20:13#大西,発,20:22#波方,発,20:27#波止浜,発,20:30#今治,発,20:40#伊予富田,発,20:44#伊予桜井,発,20:51#伊予三芳,発,20:59#壬生川,発,21:03#玉之江,発,21:06#伊予小松,発,21:10#伊予氷見,発,21:13#石鎚山,発,21:16#伊予西条,着,21:20#"},
{"560M":"松山,発,20:29#三津浜,発,20:33#伊予和気,発,20:37#堀江,発,20:47#光洋台,発,20:50#粟井,発,20:53#柳原,発,20:56#伊予北条,発,20:59#大浦,発,21:02#浅海,発,21:06#菊間,発,21:14#伊予亀岡,発,21:18#大西,発,21:24#波方,発,21:28#波止浜,発,21:31#今治,着,21:36#"},
{"622D":"八幡浜,発,6:02#千丈,発,6:06#伊予平野,発,6:15#西大洲,発,6:18#伊予大洲,発,6:22#新谷,発,6:31#喜多山,発,6:34#五十崎,発,6:39#内子,発,6:42#伊予立川,発,6:49#伊予中山,発,7:07#伊予大平,発,7:14#向井原,発,7:17#伊予市,発,7:22#鳥ノ木,発,7:25#伊予横田,発,7:28#南伊予,発,7:31#北伊予,発,7:34#市坪,発,7:38#松山,着,7:42#"},
{"628D":"宇和島,発,6:10#北宇和島,発,6:14#高光,発,6:18#伊予吉田,発,6:25#立間,発,6:29#下宇和,発,6:42#卯之町,発,6:49#上宇和,発,6:52#伊予石城,発,7:09#双岩,発,7:19#八幡浜,発,7:28#千丈,発,7:34#伊予平野,発,7:43#西大洲,発,7:47#伊予大洲,発,7:51#新谷,発,7:58#喜多山,発,8:00#五十崎,発,8:05#内子,発,8:08#伊予立川,発,8:16#伊予中山,発,8:28#伊予大平,発,8:35#向井原,発,8:39#伊予市,発,8:45#鳥ノ木,発,8:47#伊予横田,発,8:50#南伊予,発,8:53#北伊予,発,8:56#市坪,発,9:00#松山,着,9:04#"},
{"912D":"八幡浜,発,5:42#千丈,発,5:46#伊予平野,発,5:55#西大洲,発,5:58#伊予大洲,発,6:02#五郎,発,6:07#春賀,発,6:11#八多喜,発,6:14#伊予白滝,発,6:18#伊予出石,発,6:24#伊予長浜,発,6:29#喜多灘,発,6:36#串,発,6:41#下灘,発,6:45#伊予上灘,発,6:56#高野川,発,7:01#向井原,発,7:09#伊予市,発,7:33#鳥ノ木,発,7:36#伊予横田,発,7:39#南伊予,発,7:42#北伊予,発,7:45#市坪,発,7:50#松山,着,7:54#"},
{"1004M":"宇多津,発,7:14#坂出,発,7:21#高松,着,7:36#"},
{"1006M":"宇多津,発,8:26#坂出,発,8:31#高松,着,8:45#"},
{"1008M":"宇多津,発,9:25#坂出,発,9:32#高松,着,9:47#"},
{"1010M":"宇多津,発,10:19#坂出,発,10:24#高松,着,10:39#"},
{"1012M":"宇多津,発,11:33#坂出,発,11:39#高松,着,11:54#"},
{"1014M":"宇多津,発,12:33#坂出,発,12:39#高松,着,12:54#"},
{"1016M":"宇多津,発,13:34#坂出,発,13:39#高松,着,13:55#"},
{"1018M":"宇多津,発,14:34#坂出,発,14:39#高松,着,14:56#"},
{"1020M":"宇多津,発,15:34#坂出,発,15:39#高松,着,15:56#"},
{"1022M":"宇多津,発,16:34#坂出,発,16:39#高松,着,16:54#"},
{"1024M":"宇多津,発,17:35#坂出,発,17:41#高松,着,17:57#"},
{"1026M":"宇多津,発,18:36#坂出,発,18:41#高松,着,18:56#"},
{"1028M":"宇多津,発,19:38#坂出,発,19:43#高松,着,19:58#"},
{"1030M":"宇多津,発,20:52#坂出,発,20:57#高松,着,21:11#"},
{"1042M":"松山,発,19:32#伊予北条,発,19:44#今治,発,20:09#壬生川,発,20:23#伊予西条,発,20:33#新居浜,発,20:41#伊予三島,発,20:57#川之江,発,21:02#観音寺,発,21:12#高瀬,発,21:20#詫間,発,21:24#多度津,発,21:32#丸亀,発,21:36#坂出,発,21:42#高松,着,21:58#"},
{"1044M":"松山,発,20:38#伊予北条,発,20:50#今治,発,21:14#壬生川,発,21:27#伊予西条,発,21:36#新居浜,発,21:44#伊予三島,発,22:01#川之江,発,22:06#観音寺,発,22:16#多度津,発,22:32#丸亀,発,22:36#坂出,発,22:42#高松,着,22:56#"},
{"1046M":"松山,発,21:49#伊予北条,発,22:02#今治,発,22:30#壬生川,発,22:45#伊予西条,発,22:54#新居浜,着,23:02#"},
{"1052D":"宇和島,発,5:24#伊予吉田,発,5:32#卯之町,発,5:44#八幡浜,発,5:57#伊予大洲,発,6:10#内子,発,6:23#伊予中山,発,6:31#伊予市,発,6:41#松山,着,6:55#"},
{"1054D":"宇和島,発,6:37#伊予吉田,発,6:46#卯之町,発,6:58#八幡浜,発,7:11#伊予大洲,発,7:24#内子,発,7:34#伊予中山,発,7:43#伊予市,発,7:56#松山,着,8:04#"},
{"1056D":"宇和島,発,7:37#伊予吉田,発,7:46#卯之町,発,7:59#八幡浜,発,8:12#伊予大洲,発,8:25#内子,発,8:36#伊予中山,発,8:46#伊予市,発,8:57#松山,着,9:06#"},
{"1058D":"宇和島,発,8:47#伊予吉田,発,8:57#卯之町,発,9:11#八幡浜,発,9:26#伊予大洲,発,9:42#内子,発,9:53#伊予市,発,10:10#松山,着,10:18#"},
{"1060D":"宇和島,発,9:46#伊予吉田,発,9:55#卯之町,発,10:09#八幡浜,発,10:22#伊予大洲,発,10:35#内子,発,10:46#伊予市,発,11:10#松山,着,11:19#"},
{"1062D":"宇和島,発,10:46#伊予吉田,発,10:55#卯之町,発,11:07#八幡浜,発,11:20#伊予大洲,発,11:34#内子,発,11:46#伊予市,発,12:10#松山,着,12:19#"},
{"1064D":"宇和島,発,11:46#伊予吉田,発,11:55#卯之町,発,12:07#八幡浜,発,12:20#伊予大洲,発,12:34#内子,発,12:46#伊予市,発,13:10#松山,着,13:19#"},
{"1066D":"宇和島,発,12:46#伊予吉田,発,12:55#卯之町,発,13:07#八幡浜,発,13:20#伊予大洲,発,13:34#内子,発,13:46#伊予市,発,14:10#松山,着,14:19#"},
{"1068D":"宇和島,発,13:46#伊予吉田,発,13:55#卯之町,発,14:07#八幡浜,発,14:20#伊予大洲,発,14:34#内子,発,14:46#伊予市,発,15:10#松山,着,15:19#"},
{"1070D":"宇和島,発,14:46#伊予吉田,発,14:55#卯之町,発,15:07#八幡浜,発,15:20#伊予大洲,発,15:34#内子,発,15:46#伊予市,発,16:10#松山,着,16:19#"},
{"1072D":"宇和島,発,15:46#伊予吉田,発,15:55#卯之町,発,16:07#八幡浜,発,16:20#伊予大洲,発,16:34#内子,発,16:46#伊予市,発,17:08#松山,着,17:17#"},
{"1074D":"宇和島,発,16:46#伊予吉田,発,16:55#卯之町,発,17:07#八幡浜,発,17:20#伊予大洲,発,17:34#内子,発,17:46#伊予市,発,18:10#松山,着,18:18#"},
{"1076D":"宇和島,発,17:46#伊予吉田,発,17:55#卯之町,発,18:07#八幡浜,発,18:20#伊予大洲,発,18:34#内子,発,18:46#伊予市,発,19:08#松山,着,19:17#"},
{"1078D":"宇和島,発,18:46#伊予吉田,発,18:55#卯之町,発,19:07#八幡浜,発,19:20#伊予大洲,発,19:34#内子,発,19:46#伊予市,発,20:09#松山,着,20:18#"},
{"1080D":"宇和島,発,19:46#伊予吉田,発,19:55#卯之町,発,20:07#八幡浜,発,20:20#伊予大洲,発,20:34#内子,発,20:46#伊予市,発,21:10#松山,着,21:19#"},
{"1082D":"宇和島,発,21:25#伊予吉田,発,21:33#卯之町,発,21:45#八幡浜,発,21:58#伊予大洲,発,22:11#内子,発,22:20#伊予市,発,22:39#松山,着,22:47#"},
{"1092M":"伊予西条,発,6:43#新居浜,発,6:52#伊予三島,発,7:09#川之江,発,7:14#観音寺,発,7:24#高瀬,発,7:31#詫間,発,7:36#多度津,発,7:45#丸亀,発,7:50#宇多津,発,7:53#坂出,発,7:57#高松,着,8:11#"},
{"1602M":"観音寺,発,8:36#本山,発,8:40#比地大,発,8:43#高瀬,発,8:49#みの,発,8:52#詫間,発,8:56#海岸寺,発,9:01#多度津,着,9:04#"},
{"1606M":"観音寺,発,19:17#本山,発,19:21#比地大,発,19:25#高瀬,発,19:29#みの,発,19:32#詫間,発,19:37#海岸寺,発,19:46#多度津,着,19:49#"},
{"3648D":"宇和島,発,18:11#北宇和島,発,18:15#高光,発,18:19#伊予吉田,発,18:25#立間,発,18:29#下宇和,発,18:45#卯之町,発,18:55#上宇和,発,18:58#伊予石城,発,19:03#双岩,発,19:18#八幡浜,着,19:24#"},
{"3656D":"宇和島,発,20:18#北宇和島,発,20:21#高光,発,20:25#伊予吉田,発,20:31#立間,発,20:35#下宇和,発,20:48#卯之町,発,20:52#上宇和,発,20:55#伊予石城,発,21:00#双岩,発,21:08#八幡浜,発,21:26#千丈,発,21:30#伊予平野,発,21:39#西大洲,発,21:42#伊予大洲,着,21:45#"},
{"4106M":"観音寺,発,6:00#本山,発,6:04#比地大,発,6:07#高瀬,発,6:12#みの,発,6:16#詫間,発,6:19#海岸寺,発,6:29#多度津,着,6:33#"},
{"4126M":"伊予西条,発,9:47#中萩,発,9:54#新居浜,発,10:02#多喜浜,発,10:08#関川,発,10:16#伊予土居,発,10:20#赤星,発,10:24#伊予寒川,発,10:28#伊予三島,発,10:33#川之江,発,10:41#箕浦,発,10:47#豊浜,発,10:52#観音寺,着,10:56#"},
{"4132M":"観音寺,発,13:18#本山,発,13:23#比地大,発,13:26#高瀬,発,13:32#みの,発,13:36#詫間,発,13:40#海岸寺,発,13:45#多度津,着,13:49#"},
{"4152M":"観音寺,発,18:42#本山,発,18:46#比地大,発,18:49#高瀬,発,18:53#みの,発,18:56#詫間,発,19:01#海岸寺,発,19:06#多度津,着,19:10#"},
{"4158M":"伊予西条,発,20:45#中萩,発,20:54#新居浜,発,20:59#多喜浜,発,21:04#関川,発,21:16#伊予土居,発,21:20#赤星,発,21:23#伊予寒川,発,21:27#伊予三島,発,21:31#川之江,発,21:35#箕浦,発,21:43#豊浜,発,21:47#観音寺,発,21:54#本山,発,21:59#比地大,発,22:01#高瀬,発,22:05#みの,発,22:08#詫間,発,22:11#海岸寺,発,22:16#多度津,着,22:20#"},
{"4160M":"伊予西条,発,21:56#中萩,発,22:02#新居浜,発,22:06#多喜浜,発,22:10#関川,発,22:20#伊予土居,発,22:25#赤星,発,22:28#伊予寒川,発,22:32#伊予三島,発,22:36#川之江,発,22:41#箕浦,発,22:46#豊浜,発,22:51#観音寺,発,23:03#本山,発,23:09#比地大,発,23:13#高瀬,発,23:17#みの,発,23:21#詫間,発,23:25#海岸寺,発,23:30#多度津,着,23:34#"},
{"4520M":"伊予北条,発,8:26#大浦,発,8:30#浅海,発,8:34#菊間,発,8:40#伊予亀岡,発,8:45#大西,発,8:50#波方,発,8:55#波止浜,発,8:58#今治,発,9:03#伊予富田,発,9:07#伊予桜井,発,9:11#伊予三芳,発,9:21#壬生川,発,9:25#玉之江,発,9:28#伊予小松,発,9:32#伊予氷見,発,9:34#石鎚山,発,9:37#伊予西条,着,9:41#"},
{"4522M":"松山,発,8:40#三津浜,発,8:47#伊予和気,発,8:51#堀江,発,8:54#光洋台,発,8:58#粟井,発,9:01#柳原,発,9:04#伊予北条,発,9:07#大浦,発,9:11#浅海,発,9:15#菊間,発,9:21#伊予亀岡,発,9:26#大西,発,9:40#波方,発,9:44#波止浜,発,9:56#今治,発,10:06#伊予富田,発,10:10#伊予桜井,発,10:14#伊予三芳,発,10:22#壬生川,発,10:28#玉之江,発,10:31#伊予小松,発,10:35#伊予氷見,発,10:37#石鎚山,発,10:41#伊予西条,着,10:45#"},
{"4524M":"伊予西条,発,10:35#中萩,発,10:42#新居浜,発,10:49#多喜浜,発,11:00#関川,発,11:08#伊予土居,発,11:12#赤星,発,11:15#伊予寒川,発,11:19#伊予三島,発,11:29#川之江,発,11:35#箕浦,発,11:49#豊浜,発,11:54#観音寺,着,11:59#"},
{"4526M":"松山,発,9:36#三津浜,発,9:41#伊予和気,発,9:45#堀江,発,9:48#光洋台,発,9:52#粟井,発,9:57#柳原,発,9:59#伊予北条,発,10:04#大浦,発,10:08#浅海,発,10:12#菊間,発,10:17#伊予亀岡,発,10:25#大西,発,10:31#波方,発,10:36#波止浜,発,10:45#今治,発,11:02#伊予富田,発,11:06#伊予桜井,発,11:11#伊予三芳,発,11:26#壬生川,発,11:30#玉之江,発,11:33#伊予小松,発,11:36#伊予氷見,発,11:39#石鎚山,発,11:42#伊予西条,発,11:49#中萩,発,11:55#新居浜,発,11:59#多喜浜,発,12:06#関川,発,12:13#伊予土居,発,12:17#赤星,発,12:20#伊予寒川,発,12:25#伊予三島,発,12:31#川之江,発,12:36#箕浦,発,12:50#豊浜,発,12:54#観音寺,着,12:59#"},
{"4528M":"伊予西条,発,12:38#中萩,発,12:47#新居浜,発,13:01#多喜浜,発,13:07#関川,発,13:14#伊予土居,発,13:19#赤星,発,13:22#伊予寒川,発,13:27#伊予三島,発,13:31#川之江,発,13:37#箕浦,発,13:50#豊浜,発,13:55#観音寺,着,14:00#"},
{"4532M":"伊予西条,発,13:20#中萩,発,13:33#新居浜,発,13:42#多喜浜,発,13:46#関川,発,13:53#伊予土居,発,14:00#赤星,発,14:03#伊予寒川,発,14:08#伊予三島,発,14:12#川之江,発,14:17#箕浦,発,14:22#豊浜,発,14:27#観音寺,着,14:31#"},
{"4534M":"松山,発,11:58#三津浜,発,12:12#伊予和気,発,12:16#堀江,発,12:20#光洋台,発,12:23#粟井,発,12:32#柳原,発,12:35#伊予北条,発,12:38#大浦,発,12:42#浅海,発,12:46#菊間,発,12:57#伊予亀岡,発,13:01#大西,発,13:07#波方,発,13:14#波止浜,発,13:17#今治,発,13:25#伊予富田,発,13:29#伊予桜井,発,13:35#伊予三芳,発,13:43#壬生川,発,13:47#玉之江,発,13:50#伊予小松,発,13:55#伊予氷見,発,13:57#石鎚山,発,14:04#伊予西条,着,14:08#"},
{"4536M":"伊予西条,発,14:20#中萩,発,14:34#新居浜,発,14:42#多喜浜,発,14:46#関川,発,14:53#伊予土居,発,15:00#赤星,発,15:04#伊予寒川,発,15:08#伊予三島,発,15:12#川之江,発,15:17#箕浦,発,15:23#豊浜,発,15:29#観音寺,着,15:33#"},
{"4538M":"松山,発,12:58#三津浜,発,13:03#伊予和気,発,13:14#堀江,発,13:17#光洋台,発,13:20#粟井,発,13:23#柳原,発,13:26#伊予北条,発,13:29#大浦,発,13:34#浅海,発,13:38#菊間,発,13:55#伊予亀岡,発,13:59#大西,発,14:06#波方,発,14:14#波止浜,発,14:17#今治,発,14:25#伊予富田,発,14:29#伊予桜井,発,14:39#伊予三芳,発,14:47#壬生川,発,14:51#玉之江,発,14:54#伊予小松,発,14:58#伊予氷見,発,15:01#石鎚山,発,15:05#伊予西条,発,15:30#中萩,発,15:37#新居浜,発,15:41#多喜浜,発,15:45#関川,発,15:53#伊予土居,発,16:00#赤星,発,16:04#伊予寒川,発,16:07#伊予三島,発,16:14#川之江,発,16:19#箕浦,発,16:24#豊浜,発,16:29#観音寺,着,16:33#"},
{"4540M":"松山,発,13:29#三津浜,発,13:33#伊予和気,発,13:37#堀江,発,13:40#光洋台,発,13:43#粟井,発,13:46#柳原,発,13:49#伊予北条,着,13:52#"},
{"4542M":"松山,発,13:58#三津浜,発,14:02#伊予和気,発,14:11#堀江,発,14:14#光洋台,発,14:18#粟井,発,14:21#柳原,発,14:24#伊予北条,発,14:27#大浦,発,14:39#浅海,発,14:43#菊間,発,14:49#伊予亀岡,発,14:56#大西,発,15:02#波方,発,15:13#波止浜,発,15:16#今治,発,15:25#伊予富田,発,15:29#伊予桜井,発,15:36#伊予三芳,発,15:44#壬生川,発,15:48#玉之江,発,15:51#伊予小松,発,15:55#伊予氷見,発,15:58#石鎚山,発,16:04#伊予西条,着,16:08#"},
{"4562M":"松山,発,21:35#三津浜,発,21:39#伊予和気,発,21:43#堀江,発,21:46#光洋台,発,21:49#粟井,発,21:52#柳原,発,21:55#伊予北条,発,22:05#大浦,発,22:09#浅海,発,22:17#菊間,発,22:22#伊予亀岡,発,22:28#大西,発,22:33#波方,発,22:38#波止浜,発,22:41#今治,発,22:48#伊予富田,発,22:56#伊予桜井,発,23:01#伊予三芳,発,23:08#壬生川,発,23:13#玉之江,発,23:16#伊予小松,発,23:19#伊予氷見,発,23:22#石鎚山,発,23:25#伊予西条,着,23:29#"},
{"4564M":"松山,発,22:50#三津浜,発,22:55#伊予和気,発,22:59#堀江,発,23:03#光洋台,発,23:06#粟井,発,23:09#柳原,発,23:12#伊予北条,着,23:15#"},
{"4604M":"観音寺,発,16:46#本山,発,16:51#比地大,発,16:54#高瀬,発,17:00#みの,発,17:04#詫間,発,17:07#海岸寺,発,17:12#多度津,着,17:16#"},
{"4608M":"観音寺,発,19:52#本山,発,19:57#比地大,発,20:00#高瀬,発,20:05#みの,発,20:08#詫間,発,20:12#海岸寺,発,20:17#多度津,着,20:21#"},
{"4618D":"伊予市,発,6:11#鳥ノ木,発,6:14#伊予横田,発,6:17#南伊予,発,6:20#北伊予,発,6:23#市坪,発,6:27#松山,着,6:31#"},
{"4620D":"伊予市,発,6:58#鳥ノ木,発,7:00#伊予横田,発,7:03#南伊予,発,7:06#北伊予,発,7:09#市坪,発,7:12#松山,着,7:16#"},
{"4624D":"伊予市,発,8:02#鳥ノ木,発,8:05#伊予横田,発,8:08#南伊予,発,8:11#北伊予,発,8:19#市坪,発,8:23#松山,着,8:27#"},
{"4626D":"伊予市,発,8:20#鳥ノ木,発,8:22#伊予横田,発,8:25#南伊予,発,8:28#北伊予,発,8:31#市坪,発,8:34#松山,着,8:38#"},
{"4630M":"伊予市,発,9:16#鳥ノ木,発,9:18#伊予横田,発,9:21#南伊予,発,9:23#北伊予,発,9:26#市坪,発,9:30#松山,着,9:33#"},
{"4632D":"宇和島,発,6:47#北宇和島,発,6:51#高光,発,6:55#伊予吉田,発,7:15#立間,発,7:19#下宇和,発,7:30#卯之町,発,7:37#上宇和,発,7:40#伊予石城,発,7:47#双岩,発,7:54#八幡浜,着,8:00#"},
{"4634M":"伊予市,発,10:42#鳥ノ木,発,10:44#伊予横田,発,10:47#南伊予,発,10:49#北伊予,発,10:54#市坪,発,10:58#松山,発,11:32#三津浜,発,11:36#伊予和気,発,11:40#堀江,発,11:43#光洋台,発,11:46#粟井,発,11:52#柳原,発,11:54#伊予北条,着,11:57#"},
{"4636D":"伊予大洲,発,10:14#新谷,発,10:21#喜多山,発,10:23#五十崎,発,10:28#内子,発,10:31#伊予立川,発,10:38#伊予中山,発,10:49#伊予大平,発,10:56#向井原,発,10:59#伊予市,発,11:13#鳥ノ木,発,11:16#伊予横田,発,11:19#南伊予,発,11:21#北伊予,発,11:25#市坪,発,11:33#松山,着,11:38#"},
{"4638D":"伊予大洲,発,12:14#新谷,発,12:21#喜多山,発,12:23#五十崎,発,12:28#内子,発,12:31#伊予立川,発,12:38#伊予中山,発,12:49#伊予大平,発,12:56#向井原,発,12:59#伊予市,発,13:13#鳥ノ木,発,13:16#伊予横田,発,13:19#南伊予,発,13:21#北伊予,発,13:25#市坪,発,13:33#松山,着,13:37#"},
{"4640D":"伊予大洲,発,14:14#新谷,発,14:21#喜多山,発,14:23#五十崎,発,14:28#内子,発,14:31#伊予立川,発,14:38#伊予中山,発,14:49#伊予大平,発,14:56#向井原,発,14:59#伊予市,発,15:13#鳥ノ木,発,15:15#伊予横田,発,15:18#南伊予,発,15:21#北伊予,発,15:26#市坪,発,15:33#松山,着,15:37#"},
{"4642M":"伊予市,発,15:42#鳥ノ木,発,15:45#伊予横田,発,15:47#南伊予,発,15:49#北伊予,発,15:54#市坪,発,15:58#松山,発,16:31#三津浜,発,16:36#伊予和気,発,16:40#堀江,発,16:44#光洋台,発,16:47#粟井,発,17:00#柳原,発,17:02#伊予北条,着,17:05#"},
{"4644D":"伊予大洲,発,16:14#新谷,発,16:21#喜多山,発,16:23#五十崎,発,16:28#内子,発,16:31#伊予立川,発,16:38#伊予中山,発,16:49#伊予大平,発,16:56#向井原,発,16:59#伊予市,発,17:11#鳥ノ木,発,17:14#伊予横田,発,17:17#南伊予,発,17:19#北伊予,発,17:22#市坪,発,17:26#松山,着,17:30#"},
{"4646M":"伊予市,発,18:42#鳥ノ木,発,18:45#伊予横田,発,18:47#南伊予,発,18:49#北伊予,発,18:54#市坪,発,18:58#松山,着,19:01#"},
{"4650D":"伊予大洲,発,18:14#新谷,発,18:21#喜多山,発,18:23#五十崎,発,18:28#内子,発,18:31#伊予立川,発,18:38#伊予中山,発,18:49#伊予大平,発,18:56#向井原,発,18:59#伊予市,発,19:11#鳥ノ木,発,19:14#伊予横田,発,19:17#南伊予,発,19:19#北伊予,発,19:22#市坪,発,19:26#松山,着,19:30#"},
{"4652M":"伊予市,発,20:47#鳥ノ木,発,20:50#伊予横田,発,20:52#南伊予,発,20:55#北伊予,発,20:58#市坪,発,21:05#松山,着,21:08#"},
{"4654D":"伊予大洲,発,20:54#新谷,発,21:04#喜多山,発,21:06#五十崎,発,21:11#内子,発,21:16#伊予立川,発,21:23#伊予中山,発,21:32#伊予大平,発,21:39#向井原,発,21:43#伊予市,着,21:46#"},
{"4658M":"伊予市,発,22:09#鳥ノ木,発,22:12#伊予横田,発,22:14#南伊予,発,22:16#北伊予,発,22:19#市坪,発,22:22#松山,着,22:26#"},
{"4660D":"伊予市,発,23:25#鳥ノ木,発,23:28#伊予横田,発,23:31#南伊予,発,23:34#北伊予,発,23:37#市坪,発,23:41#松山,着,23:45#"},
{"4914D":"伊予大洲,発,6:52#五郎,発,6:57#春賀,発,7:00#八多喜,発,7:03#伊予白滝,発,7:07#伊予出石,発,7:12#伊予長浜,発,7:18#喜多灘,発,7:26#串,発,7:31#下灘,発,7:35#伊予上灘,発,7:42#高野川,発,7:47#向井原,発,7:55#伊予市,着,7:59#"},
{"4916D":"伊予大洲,発,7:57#五郎,発,8:03#春賀,発,8:07#八多喜,発,8:10#伊予白滝,発,8:14#伊予出石,発,8:19#伊予長浜,発,8:31#喜多灘,発,8:38#串,発,8:43#下灘,発,8:48#伊予上灘,発,9:15#高野川,発,9:20#向井原,発,9:28#伊予市,発,9:34#鳥ノ木,発,9:37#伊予横田,発,9:40#南伊予,発,9:42#北伊予,発,9:45#市坪,発,9:49#松山,着,9:53#"},
{"4918D":"八幡浜,発,9:44#千丈,発,9:53#伊予平野,発,10:03#西大洲,発,10:06#伊予大洲,発,10:29#五郎,発,10:34#春賀,発,10:38#八多喜,発,10:41#伊予白滝,発,10:45#伊予出石,発,10:51#伊予長浜,発,10:56#喜多灘,発,11:03#串,発,11:08#下灘,発,11:12#伊予上灘,発,11:18#高野川,発,11:23#向井原,発,11:31#伊予市,発,11:39#鳥ノ木,発,11:42#伊予横田,発,11:45#南伊予,発,11:49#北伊予,発,11:54#市坪,発,11:58#松山,着,12:02#"},
{"4920D":"八幡浜,発,11:44#千丈,発,11:50#伊予平野,発,11:59#西大洲,発,12:02#伊予大洲,発,12:23#五郎,発,12:28#春賀,発,12:32#八多喜,発,12:35#伊予白滝,発,12:38#伊予出石,発,12:43#伊予長浜,発,13:09#喜多灘,発,13:16#串,発,13:21#下灘,発,13:25#伊予上灘,発,13:32#高野川,発,13:37#向井原,発,13:44#伊予市,発,14:13#鳥ノ木,発,14:16#伊予横田,発,14:19#南伊予,発,14:21#北伊予,発,14:25#市坪,発,14:33#松山,着,14:37#"},
{"4922D":"宇和島,発,12:11#北宇和島,発,12:15#高光,発,12:19#伊予吉田,発,12:25#立間,発,12:29#下宇和,発,12:45#卯之町,発,12:56#上宇和,発,12:59#伊予石城,発,13:03#双岩,発,13:18#八幡浜,発,13:44#千丈,発,13:48#伊予平野,発,13:57#西大洲,発,14:00#伊予大洲,発,14:25#五郎,発,14:30#春賀,発,14:34#八多喜,発,14:37#伊予白滝,発,15:01#伊予出石,発,15:06#伊予長浜,発,15:14#喜多灘,発,15:22#串,発,15:27#下灘,発,15:31#伊予上灘,発,15:51#高野川,発,15:55#向井原,発,16:02#伊予市,発,16:13#鳥ノ木,発,16:16#伊予横田,発,16:19#南伊予,発,16:21#北伊予,発,16:25#市坪,発,16:33#松山,着,16:37#"},
{"4924D":"宇和島,発,14:11#北宇和島,発,14:15#高光,発,14:19#伊予吉田,発,14:25#立間,発,14:29#下宇和,発,14:45#卯之町,発,14:56#上宇和,発,14:59#伊予石城,発,15:03#双岩,発,15:18#八幡浜,発,15:44#千丈,発,15:48#伊予平野,発,15:57#西大洲,発,16:00#伊予大洲,発,16:21#五郎,発,16:27#春賀,発,16:31#八多喜,発,16:34#伊予白滝,発,16:39#伊予出石,発,16:44#伊予長浜,発,16:51#喜多灘,発,16:58#串,発,17:04#下灘,発,17:08#伊予上灘,発,17:15#高野川,発,17:20#向井原,発,17:28#伊予市,発,17:39#鳥ノ木,発,17:42#伊予横田,発,17:45#南伊予,発,17:49#北伊予,発,17:54#市坪,発,17:58#松山,着,18:02#"},
{"4926D":"宇和島,発,16:11#北宇和島,発,16:15#高光,発,16:19#伊予吉田,発,16:25#立間,発,16:29#下宇和,発,16:45#卯之町,発,17:18#上宇和,発,17:21#伊予石城,発,17:26#双岩,発,17:34#八幡浜,発,17:44#千丈,発,17:48#伊予平野,発,17:57#西大洲,発,18:00#伊予大洲,発,18:17#五郎,発,18:23#春賀,発,18:27#八多喜,発,18:30#伊予白滝,発,18:35#伊予出石,発,18:41#伊予長浜,発,19:20#喜多灘,発,19:27#串,発,19:33#下灘,発,19:38#伊予上灘,発,19:45#高野川,発,19:50#向井原,発,19:58#伊予市,発,20:13#鳥ノ木,発,20:15#伊予横田,発,20:18#南伊予,発,20:21#北伊予,発,20:26#市坪,発,20:32#松山,着,20:36#"},
{"4928D":"八幡浜,発,20:30#千丈,発,20:34#伊予平野,発,20:43#西大洲,発,20:46#伊予大洲,発,20:58#五郎,発,21:03#春賀,発,21:07#八多喜,発,21:10#伊予白滝,発,21:14#伊予出石,発,21:19#伊予長浜,発,21:24#喜多灘,発,21:31#串,発,21:36#下灘,発,21:40#伊予上灘,発,21:47#高野川,発,21:52#向井原,発,21:59#伊予市,着,22:03#"},
{"5102M":"多度津,発,5:09#讃岐塩屋,発,5:13#丸亀,発,5:15#宇多津,発,5:19#坂出,発,5:24#八十場,発,5:28#鴨川,発,5:31#讃岐府中,発,5:35#国分,発,5:38#端岡,発,5:41#鬼無,発,5:45#香西,発,5:48#高松,着,5:53#"},
{"5106M":"多度津,発,6:42#讃岐塩屋,発,6:45#丸亀,発,6:48#宇多津,発,6:52#坂出,発,6:57#八十場,発,7:00#鴨川,発,7:03#讃岐府中,発,7:07#国分,発,7:10#端岡,発,7:13#鬼無,発,7:17#香西,発,7:20#高松,着,7:24#"},
{"5118M":"新居浜,発,7:01#多喜浜,発,7:05#関川,発,7:15#伊予土居,発,7:22#赤星,発,7:25#伊予寒川,発,7:30#伊予三島,発,7:42#川之江,発,7:47#箕浦,発,7:53#豊浜,発,7:59#観音寺,発,8:07#本山,発,8:12#比地大,発,8:15#高瀬,発,8:21#みの,発,8:25#詫間,発,8:28#海岸寺,発,8:35#多度津,発,8:54#讃岐塩屋,発,8:57#丸亀,発,9:00#宇多津,発,9:04#坂出,発,9:09#端岡,発,9:18#高松,着,9:26#"},
{"5120M":"観音寺,発,9:18#本山,発,9:23#比地大,発,9:26#高瀬,発,9:32#みの,発,9:36#詫間,発,9:39#海岸寺,発,9:45#多度津,発,9:50#讃岐塩屋,発,9:54#丸亀,発,9:57#宇多津,発,10:01#坂出,発,10:06#端岡,発,10:15#高松,着,10:23#"},
{"5122M":"多度津,発,10:02#讃岐塩屋,発,10:05#丸亀,発,10:08#宇多津,発,10:12#坂出,発,10:17#八十場,発,10:20#鴨川,発,10:30#讃岐府中,発,10:33#国分,発,10:36#端岡,発,10:45#鬼無,発,10:49#香西,発,10:53#高松,着,10:57#"},
{"5124M":"伊予西条,発,8:48#中萩,発,8:54#新居浜,発,9:01#多喜浜,発,9:05#関川,発,9:12#伊予土居,発,9:17#赤星,発,9:20#伊予寒川,発,9:25#伊予三島,発,9:41#川之江,発,9:49#箕浦,発,9:55#豊浜,発,9:59#観音寺,発,10:21#本山,発,10:27#比地大,発,10:31#高瀬,発,10:34#みの,発,10:38#詫間,発,10:41#海岸寺,発,10:47#多度津,発,11:02#讃岐塩屋,発,11:06#丸亀,発,11:09#宇多津,発,11:12#坂出,発,11:17#端岡,発,11:27#高松,着,11:35#"},
{"5126M":"観音寺,発,11:16#本山,発,11:21#比地大,発,11:24#高瀬,発,11:31#みの,発,11:35#詫間,発,11:38#海岸寺,発,11:44#多度津,発,12:02#讃岐塩屋,発,12:05#丸亀,発,12:08#宇多津,発,12:12#坂出,発,12:17#端岡,発,12:26#高松,着,12:34#"},
{"5138M":"観音寺,発,14:38#本山,発,14:43#比地大,発,14:46#高瀬,発,14:50#みの,発,14:54#詫間,発,14:57#海岸寺,発,15:03#多度津,発,15:08#讃岐塩屋,発,15:12#丸亀,発,15:15#宇多津,発,15:19#坂出,発,15:24#八十場,発,15:28#鴨川,発,15:31#讃岐府中,発,15:34#国分,発,15:37#端岡,発,15:40#鬼無,発,15:44#香西,発,15:47#高松,着,15:51#"},
{"5148M":"多度津,発,18:38#讃岐塩屋,発,18:42#丸亀,発,18:45#宇多津,発,18:49#坂出,発,18:55#八十場,発,18:58#鴨川,発,19:01#讃岐府中,発,19:04#国分,発,19:08#端岡,発,19:11#鬼無,発,19:15#香西,発,19:18#高松,着,19:22#"},
{"5512M":"伊予西条,発,7:20#中萩,発,7:28#新居浜,発,7:33#多喜浜,発,7:38#関川,発,7:46#伊予土居,発,7:51#赤星,発,7:54#伊予寒川,発,7:59#伊予三島,発,8:04#川之江,発,8:10#箕浦,発,8:15#豊浜,発,8:20#観音寺,着,8:24#"},
{"5516M":"松山,発,6:32#三津浜,発,6:37#伊予和気,発,6:41#堀江,発,6:44#光洋台,発,6:48#粟井,発,7:00#柳原,発,7:03#伊予北条,発,7:14#大浦,発,7:18#浅海,発,7:25#菊間,発,7:32#伊予亀岡,発,7:38#大西,発,7:50#波方,発,7:55#波止浜,発,8:01#今治,発,8:06#伊予富田,発,8:10#伊予桜井,発,8:14#伊予三芳,発,8:22#壬生川,発,8:26#玉之江,発,8:30#伊予小松,発,8:34#伊予氷見,発,8:36#石鎚山,発,8:40#伊予西条,着,8:44#"},
{"5518M":"松山,発,7:23#三津浜,発,7:27#伊予和気,発,7:31#堀江,発,7:35#光洋台,発,7:39#粟井,発,7:52#柳原,発,7:55#伊予北条,発,7:58#大浦,発,8:03#浅海,発,8:07#菊間,発,8:14#伊予亀岡,発,8:19#大西,発,8:25#波方,発,8:30#波止浜,発,8:33#今治,着,8:38#"},
{"5530M":"松山,発,10:58#三津浜,発,11:03#伊予和気,発,11:13#堀江,発,11:16#光洋台,発,11:20#粟井,発,11:23#柳原,発,11:26#伊予北条,発,11:42#大浦,発,11:47#浅海,発,11:55#菊間,発,12:00#伊予亀岡,発,12:05#大西,発,12:11#波方,発,12:16#波止浜,発,12:19#今治,発,12:25#伊予富田,発,12:30#伊予桜井,発,12:37#伊予三芳,発,12:45#壬生川,発,12:49#玉之江,発,12:52#伊予小松,発,12:56#伊予氷見,発,12:59#石鎚山,発,13:03#伊予西条,着,13:07#"},
{"5544M":"伊予西条,発,16:34#中萩,発,16:41#新居浜,発,16:48#多喜浜,発,16:52#関川,発,17:04#伊予土居,発,17:09#赤星,発,17:12#伊予寒川,発,17:19#伊予三島,発,17:24#川之江,発,17:30#箕浦,発,17:36#豊浜,発,17:50#観音寺,着,17:55#"},
{"5546M":"松山,発,14:58#三津浜,発,15:03#伊予和気,発,15:15#堀江,発,15:18#光洋台,発,15:22#粟井,発,15:25#柳原,発,15:28#伊予北条,発,15:31#大浦,発,15:36#浅海,発,15:40#菊間,発,15:56#伊予亀岡,発,16:01#大西,発,16:07#波方,発,16:15#波止浜,発,16:18#今治,発,16:25#伊予富田,発,16:29#伊予桜井,発,16:40#伊予三芳,発,16:48#壬生川,発,16:52#玉之江,発,16:55#伊予小松,発,16:59#伊予氷見,発,17:02#石鎚山,発,17:05#伊予西条,着,17:09#"},
{"5548M":"伊予西条,発,17:23#中萩,発,17:36#新居浜,発,17:44#多喜浜,発,17:48#関川,発,17:56#伊予土居,発,18:02#赤星,発,18:06#伊予寒川,発,18:10#伊予三島,発,18:15#川之江,発,18:21#箕浦,発,18:27#豊浜,発,18:32#観音寺,着,18:37#"},
{"5550M":"松山,発,15:58#三津浜,発,16:03#伊予和気,発,16:14#堀江,発,16:17#光洋台,発,16:21#粟井,発,16:24#柳原,発,16:27#伊予北条,発,16:30#大浦,発,16:35#浅海,発,16:39#菊間,発,16:52#伊予亀岡,発,17:01#大西,発,17:07#波方,発,17:14#波止浜,発,17:17#今治,発,17:25#伊予富田,発,17:29#伊予桜井,発,17:41#伊予三芳,発,17:48#壬生川,発,17:53#玉之江,発,17:56#伊予小松,発,18:00#伊予氷見,発,18:03#石鎚山,発,18:07#伊予西条,着,18:11#"},
{"5552M":"松山,発,16:58#三津浜,発,17:03#伊予和気,発,17:10#堀江,発,17:17#光洋台,発,17:21#粟井,発,17:24#柳原,発,17:27#伊予北条,発,17:30#大浦,発,17:35#浅海,発,17:39#菊間,発,17:44#伊予亀岡,発,18:04#大西,発,18:10#波方,発,18:15#波止浜,発,18:19#今治,発,18:25#伊予富田,発,18:29#伊予桜井,発,18:42#伊予三芳,発,18:50#壬生川,発,18:54#玉之江,発,18:58#伊予小松,発,19:02#伊予氷見,発,19:05#石鎚山,発,19:08#伊予西条,発,19:23#中萩,発,19:30#新居浜,発,19:37#多喜浜,発,19:41#関川,発,19:48#伊予土居,発,19:53#赤星,発,19:56#伊予寒川,発,20:11#伊予三島,発,20:18#川之江,発,20:23#箕浦,発,20:28#豊浜,発,20:33#観音寺,着,20:38#"},
{"5554M":"松山,発,17:40#三津浜,発,17:44#伊予和気,発,17:49#堀江,発,17:52#光洋台,発,17:56#粟井,発,18:02#柳原,発,18:05#伊予北条,着,18:08#"},
{"5556M":"松山,発,18:10#三津浜,発,18:24#伊予和気,発,18:28#堀江,発,18:32#光洋台,発,18:36#粟井,発,18:39#柳原,発,18:42#伊予北条,発,18:55#大浦,発,18:59#浅海,発,19:08#菊間,発,19:14#伊予亀岡,発,19:19#大西,発,19:25#波方,発,19:30#波止浜,発,19:34#今治,発,19:39#伊予富田,発,19:45#伊予桜井,発,19:49#伊予三芳,発,19:57#壬生川,発,20:01#玉之江,発,20:05#伊予小松,発,20:09#伊予氷見,発,20:12#石鎚山,発,20:15#伊予西条,着,20:19#"},
{"8092D":"伊予大洲,発,10:57#伊予長浜,発,11:30#喜多灘,発,11:42#下灘,発,12:10#伊予上灘,発,12:34#北伊予,発,12:56#松山,着,13:03#"},
{"8094D":"八幡浜,発,16:27#伊予大洲,発,16:49#伊予長浜,発,17:15#下灘,発,17:40#伊予市,発,18:13#市坪,発,18:25#松山,着,18:30#"},
{"101M":"多度津,発,5:47#海岸寺,発,5:56#詫間,発,6:02#みの,発,6:05#高瀬,発,6:11#比地大,発,6:14#本山,発,6:18#観音寺,発,6:25#豊浜,発,6:30#箕浦,発,6:43#川之江,発,6:49#伊予三島,発,7:10#伊予寒川,発,7:14#赤星,発,7:18#伊予土居,発,7:22#関川,発,7:30#多喜浜,発,7:38#新居浜,発,7:42#中萩,発,7:48#伊予西条,着,7:53#"},
{"105M":"高松,発,6:53#香西,発,6:57#鬼無,発,7:00#端岡,発,7:04#国分,発,7:08#讃岐府中,発,7:11#鴨川,発,7:14#八十場,発,7:17#坂出,発,7:26#宇多津,発,7:31#丸亀,発,7:35#讃岐塩屋,発,7:37#多度津,発,7:43#海岸寺,発,7:49#詫間,発,7:55#みの,発,7:58#高瀬,発,8:03#比地大,発,8:06#本山,発,8:12#観音寺,着,8:16#"},
{"111M":"高松,発,10:13#端岡,発,10:21#坂出,発,10:30#宇多津,発,10:34#丸亀,発,10:38#讃岐塩屋,発,10:40#多度津,発,10:51#海岸寺,発,10:56#詫間,発,11:01#みの,発,11:05#高瀬,発,11:11#比地大,発,11:15#本山,発,11:21#観音寺,着,11:25#"},
{"115M":"高松,発,11:13#端岡,発,11:21#坂出,発,11:30#宇多津,発,11:34#丸亀,発,11:38#讃岐塩屋,発,11:40#多度津,発,11:54#海岸寺,発,11:59#詫間,発,12:04#みの,発,12:08#高瀬,発,12:13#比地大,発,12:17#本山,発,12:20#観音寺,着,12:24#"},
{"117M":"高松,発,12:13#端岡,発,12:21#坂出,発,12:30#宇多津,発,12:34#丸亀,発,12:38#讃岐塩屋,発,12:40#多度津,発,12:44#海岸寺,発,12:48#詫間,発,12:54#みの,発,12:58#高瀬,発,13:01#比地大,発,13:05#本山,発,13:11#観音寺,着,13:16#"},
{"119M":"高松,発,12:52#香西,発,12:56#鬼無,発,13:00#端岡,発,13:04#国分,発,13:07#讃岐府中,発,13:10#鴨川,発,13:13#八十場,発,13:16#坂出,発,13:20#宇多津,発,13:25#丸亀,発,13:28#讃岐塩屋,発,13:30#多度津,着,13:33#"},
{"121M":"高松,発,13:13#端岡,発,13:21#坂出,発,13:30#宇多津,発,13:34#丸亀,発,13:38#讃岐塩屋,発,13:40#多度津,発,13:53#海岸寺,発,13:57#詫間,発,14:03#みの,発,14:06#高瀬,発,14:14#比地大,発,14:18#本山,発,14:21#観音寺,着,14:25#"},
{"123M":"高松,発,14:13#端岡,発,14:21#坂出,発,14:30#宇多津,発,14:34#丸亀,発,14:38#讃岐塩屋,発,14:40#多度津,着,14:43#"},
{"125M":"高松,発,14:52#香西,発,14:56#鬼無,発,15:00#端岡,発,15:04#国分,発,15:07#讃岐府中,発,15:10#鴨川,発,15:13#八十場,発,15:16#坂出,発,15:20#宇多津,発,15:25#丸亀,発,15:28#讃岐塩屋,発,15:30#多度津,発,15:34#海岸寺,発,15:39#詫間,発,15:44#みの,発,15:48#高瀬,発,15:51#比地大,発,15:55#本山,発,15:58#観音寺,着,16:03#"},
{"127M":"高松,発,15:13#端岡,発,15:21#坂出,発,15:30#宇多津,発,15:34#丸亀,発,15:38#讃岐塩屋,発,15:40#多度津,発,15:54#海岸寺,発,15:59#詫間,発,16:05#みの,発,16:09#高瀬,発,16:23#比地大,発,16:27#本山,発,16:31#観音寺,着,16:35#"},
{"131M":"高松,発,16:13#端岡,発,16:21#坂出,発,16:30#宇多津,発,16:34#丸亀,発,16:38#讃岐塩屋,発,16:40#多度津,発,16:44#海岸寺,発,16:48#詫間,発,16:54#みの,発,16:57#高瀬,発,17:00#比地大,発,17:04#本山,発,17:14#観音寺,着,17:18#"},
{"133M":"高松,発,16:52#香西,発,16:56#鬼無,発,17:00#端岡,発,17:04#国分,発,17:07#讃岐府中,発,17:10#鴨川,発,17:13#八十場,発,17:16#坂出,発,17:20#宇多津,発,17:25#丸亀,発,17:28#讃岐塩屋,発,17:30#多度津,発,17:34#海岸寺,発,17:46#詫間,発,17:52#みの,発,17:55#高瀬,発,17:58#比地大,発,18:02#本山,発,18:05#観音寺,着,18:09#"},
{"137M":"高松,発,17:56#端岡,発,18:05#鴨川,発,18:11#坂出,発,18:15#宇多津,発,18:20#丸亀,発,18:24#讃岐塩屋,発,18:27#多度津,発,18:32#海岸寺,発,18:36#詫間,発,18:42#みの,発,18:46#高瀬,発,18:53#比地大,発,18:57#本山,発,19:00#観音寺,着,19:04#"},
{"139M":"高松,発,18:13#端岡,発,18:21#鴨川,発,18:27#坂出,発,18:32#宇多津,発,18:37#丸亀,発,18:41#讃岐塩屋,発,18:43#多度津,発,18:52#海岸寺,発,18:56#詫間,発,19:01#みの,発,19:05#高瀬,発,19:08#比地大,発,19:12#本山,発,19:21#観音寺,着,19:25#"},
{"141M":"高松,発,18:52#香西,発,18:56#鬼無,発,18:59#端岡,発,19:07#国分,発,19:10#讃岐府中,発,19:13#鴨川,発,19:16#八十場,発,19:18#坂出,発,19:27#宇多津,発,19:32#丸亀,発,19:35#讃岐塩屋,発,19:38#多度津,発,19:41#海岸寺,発,19:46#詫間,発,19:51#みの,発,19:54#高瀬,発,20:04#比地大,発,20:08#本山,発,20:12#観音寺,着,20:16#"},
{"143M":"観音寺,発,20:25#豊浜,発,20:33#箕浦,発,20:38#川之江,発,20:43#伊予三島,発,20:58#伊予寒川,発,21:02#赤星,発,21:06#伊予土居,発,21:20#関川,発,21:25#多喜浜,発,21:33#新居浜,発,21:44#中萩,発,21:49#伊予西条,着,21:55#"},
{"147M":"高松,発,20:13#端岡,発,20:21#鴨川,発,20:27#坂出,発,20:32#宇多津,発,20:37#丸亀,発,20:40#讃岐塩屋,発,20:42#多度津,発,20:55#海岸寺,発,20:59#詫間,発,21:05#みの,発,21:09#高瀬,発,21:20#比地大,発,21:23#本山,発,21:26#観音寺,着,21:30#"},
{"149M":"高松,発,20:52#香西,発,20:56#鬼無,発,21:00#端岡,発,21:07#国分,発,21:10#讃岐府中,発,21:14#鴨川,発,21:17#八十場,発,21:20#坂出,発,21:30#宇多津,発,21:35#丸亀,発,21:39#讃岐塩屋,発,21:41#多度津,発,21:48#海岸寺,発,21:57#詫間,発,22:11#みの,発,22:15#高瀬,発,22:23#比地大,発,22:26#本山,発,22:29#観音寺,発,22:34#豊浜,発,22:39#箕浦,発,22:46#川之江,発,22:52#伊予三島,発,23:03#伊予寒川,発,23:12#赤星,発,23:16#伊予土居,発,23:19#関川,発,23:23#多喜浜,発,23:30#新居浜,発,23:35#中萩,発,23:40#伊予西条,着,23:45#"},
{"151M":"高松,発,21:45#端岡,発,21:53#鴨川,発,21:59#坂出,発,22:04#宇多津,発,22:08#丸亀,発,22:12#讃岐塩屋,発,22:14#多度津,発,22:32#海岸寺,発,22:37#詫間,発,22:43#みの,発,22:46#高瀬,発,22:49#比地大,発,22:53#本山,発,22:56#観音寺,着,23:00#"},
{"153M":"高松,発,22:34#香西,発,22:38#鬼無,発,22:41#端岡,発,22:45#国分,発,22:48#讃岐府中,発,22:51#鴨川,発,22:54#八十場,発,22:57#坂出,発,23:00#宇多津,発,23:05#丸亀,発,23:08#讃岐塩屋,発,23:11#多度津,発,23:15#海岸寺,発,23:19#詫間,発,23:25#みの,発,23:29#高瀬,発,23:33#比地大,発,23:36#本山,発,23:42#観音寺,着,23:46#"},
{"155M":"高松,発,23:33#香西,発,23:37#鬼無,発,23:40#端岡,発,23:44#国分,発,23:47#讃岐府中,発,23:50#鴨川,発,23:53#八十場,発,23:56#坂出,発,23:59#宇多津,発,0:05#丸亀,発,0:09#讃岐塩屋,発,0:11#多度津,着,0:14#"},
{"515M":"伊予西条,発,5:37#石鎚山,発,5:41#伊予氷見,発,5:44#伊予小松,発,5:46#玉之江,発,5:50#壬生川,発,6:01#伊予三芳,発,6:06#伊予桜井,発,6:14#伊予富田,発,6:18#今治,発,6:33#波止浜,発,6:38#波方,発,6:43#大西,発,6:48#伊予亀岡,発,6:54#菊間,発,6:59#浅海,発,7:04#大浦,発,7:08#伊予北条,発,7:12#柳原,発,7:16#粟井,発,7:18#光洋台,発,7:21#堀江,発,7:27#伊予和気,発,7:31#三津浜,発,7:36#松山,着,7:40#"},
{"517M":"伊予西条,発,6:19#石鎚山,発,6:24#伊予氷見,発,6:27#伊予小松,発,6:29#玉之江,発,6:33#壬生川,発,6:36#伊予三芳,発,6:40#伊予桜井,発,6:47#伊予富田,発,6:53#今治,発,6:58#波止浜,発,7:02#波方,発,7:05#大西,発,7:10#伊予亀岡,発,7:15#菊間,発,7:20#浅海,発,7:25#大浦,発,7:35#伊予北条,発,7:46#柳原,発,7:49#粟井,発,7:51#光洋台,発,7:54#堀江,発,7:58#伊予和気,発,8:01#三津浜,発,8:05#松山,着,8:09#"},
{"523M":"新居浜,発,6:52#中萩,発,6:57#伊予西条,発,7:15#石鎚山,発,7:19#伊予氷見,発,7:22#伊予小松,発,7:24#玉之江,発,7:28#壬生川,発,7:31#伊予三芳,発,7:35#伊予桜井,発,7:44#伊予富田,発,7:48#今治,発,8:11#波止浜,発,8:16#波方,発,8:19#大西,発,8:25#伊予亀岡,発,8:35#菊間,発,8:40#浅海,発,8:45#大浦,発,8:49#伊予北条,発,8:53#柳原,発,8:57#粟井,発,9:01#光洋台,発,9:04#堀江,発,9:08#伊予和気,発,9:11#三津浜,発,9:19#松山,着,9:23#"},
{"559M":"伊予西条,発,18:00#石鎚山,発,18:06#伊予氷見,発,18:09#伊予小松,発,18:12#玉之江,発,18:16#壬生川,発,18:26#伊予三芳,発,18:30#伊予桜井,発,18:37#伊予富田,発,18:47#今治,発,19:04#波止浜,発,19:15#波方,発,19:19#大西,発,19:25#伊予亀岡,発,19:31#菊間,発,19:35#浅海,発,19:41#大浦,発,19:47#伊予北条,発,19:52#柳原,発,19:55#粟井,発,19:58#光洋台,発,20:01#堀江,発,20:05#伊予和気,発,20:08#三津浜,発,20:13#松山,着,20:16#"},
{"561M":"観音寺,発,17:44#豊浜,発,17:50#箕浦,発,17:54#川之江,発,18:00#伊予三島,発,18:06#伊予寒川,発,18:11#赤星,発,18:15#伊予土居,発,18:18#関川,発,18:26#多喜浜,発,18:33#新居浜,発,18:42#中萩,発,18:47#伊予西条,発,19:00#石鎚山,発,19:08#伊予氷見,発,19:11#伊予小松,発,19:14#玉之江,発,19:18#壬生川,発,19:22#伊予三芳,発,19:30#伊予桜井,発,19:49#伊予富田,発,19:54#今治,発,20:08#波止浜,発,20:14#波方,発,20:18#大西,発,20:22#伊予亀岡,発,20:28#菊間,発,20:33#浅海,発,20:38#大浦,発,20:42#伊予北条,発,20:59#柳原,発,21:02#粟井,発,21:04#光洋台,発,21:07#堀江,発,21:13#伊予和気,発,21:16#三津浜,発,21:20#松山,着,21:24#"},
{"911D":"松山,発,5:51#市坪,発,5:56#北伊予,発,5:59#南伊予,発,6:02#伊予横田,発,6:05#鳥ノ木,発,6:08#伊予市,発,6:18#向井原,発,6:23#高野川,発,6:31#伊予上灘,発,6:52#下灘,発,6:59#串,発,7:03#喜多灘,発,7:08#伊予長浜,発,7:17#伊予出石,発,7:22#伊予白滝,発,7:27#八多喜,発,7:31#春賀,発,7:34#五郎,発,7:38#伊予大洲,発,7:51#西大洲,発,7:55#伊予平野,発,7:58#千丈,発,8:08#八幡浜,発,8:20#双岩,発,8:29#伊予石城,発,8:39#上宇和,発,8:43#卯之町,発,8:46#下宇和,発,8:51#立間,発,9:01#伊予吉田,発,9:05#高光,発,9:12#北宇和島,発,9:16#宇和島,着,9:19#"},
{"923D":"松山,発,17:45#市坪,発,17:50#北伊予,発,17:54#南伊予,発,17:58#伊予横田,発,18:01#鳥ノ木,発,18:04#伊予市,発,18:11#向井原,発,18:15#高野川,発,18:23#伊予上灘,発,18:28#下灘,発,18:34#串,発,18:39#喜多灘,発,18:44#伊予長浜,発,18:52#伊予出石,発,18:57#伊予白滝,発,19:02#八多喜,発,19:06#春賀,発,19:09#五郎,発,19:13#伊予大洲,発,19:20#西大洲,発,19:23#伊予平野,発,19:29#千丈,発,19:39#八幡浜,着,19:43#"},
{"925D":"松山,発,19:45#市坪,発,19:50#北伊予,発,19:54#南伊予,発,19:58#伊予横田,発,20:01#鳥ノ木,発,20:04#伊予市,発,20:11#向井原,発,20:15#高野川,発,20:23#伊予上灘,発,20:28#下灘,発,20:34#串,発,20:39#喜多灘,発,20:44#伊予長浜,発,20:52#伊予出石,発,20:57#伊予白滝,発,21:14#八多喜,発,21:18#春賀,発,21:21#五郎,発,21:24#伊予大洲,発,21:30#西大洲,発,21:34#伊予平野,発,21:39#千丈,発,21:48#八幡浜,着,21:52#"},
{"1001M":"高松,発,7:37#坂出,発,7:51#宇多津,着,7:55#"},
{"1003M":"高松,発,8:45#坂出,発,9:02#宇多津,着,9:10#"},
{"1005M":"高松,発,9:42#坂出,発,9:56#宇多津,着,10:03#"},
{"1007M":"高松,発,10:47#坂出,発,11:04#宇多津,着,11:10#"},
{"1009M":"高松,発,11:50#坂出,発,12:04#宇多津,着,12:11#"},
{"1011M":"高松,発,12:50#坂出,発,13:04#宇多津,着,13:11#"},
{"1013M":"高松,発,13:50#坂出,発,14:04#宇多津,着,14:11#"},
{"1015M":"高松,発,14:50#坂出,発,15:04#宇多津,着,15:12#"},
{"1017M":"高松,発,15:50#坂出,発,16:04#宇多津,着,16:12#"},
{"1019M":"高松,発,16:50#坂出,発,17:04#宇多津,着,17:11#"},
{"1021M":"高松,発,17:53#坂出,発,18:08#宇多津,発,18:13#丸亀,発,18:17#多度津,着,18:22#"},
{"1023M":"高松,発,18:59#坂出,発,19:13#宇多津,発,19:17#丸亀,発,19:20#多度津,着,19:26#"},
{"1025M":"高松,発,19:51#坂出,発,20:07#宇多津,発,20:12#丸亀,発,20:16#多度津,着,20:22#"},
{"1027M":"高松,発,20:59#坂出,発,21:13#宇多津,発,21:18#丸亀,発,21:22#多度津,着,21:27#"},
{"1029M":"高松,発,22:20#坂出,発,22:34#宇多津,発,22:39#丸亀,発,22:43#多度津,着,22:48#"},
{"1041M":"高松,発,5:17#坂出,発,5:30#丸亀,発,5:36#多度津,発,5:41#詫間,発,5:49#高瀬,発,5:53#観音寺,発,6:00#川之江,発,6:10#伊予三島,発,6:15#新居浜,発,6:34#伊予西条,発,6:44#壬生川,発,6:54#今治,発,7:14#伊予北条,発,7:43#松山,着,7:57#"},
{"1043M":"高松,発,6:00#坂出,発,6:14#宇多津,発,6:18#丸亀,発,6:21#多度津,発,6:26#詫間,発,6:33#高瀬,発,6:38#観音寺,発,6:45#川之江,発,6:56#伊予三島,発,7:01#新居浜,発,7:24#伊予西条,発,7:33#壬生川,発,7:42#今治,発,7:57#伊予北条,発,8:23#松山,着,8:36#"},
{"1051D":"松山,発,5:48#伊予市,発,5:56#内子,発,6:12#伊予大洲,発,6:22#八幡浜,発,6:36#卯之町,発,6:49#伊予吉田,発,7:04#宇和島,着,7:12#"},
{"1053D":"松山,発,6:49#伊予市,発,6:58#内子,発,7:14#伊予大洲,発,7:24#八幡浜,発,7:38#卯之町,発,7:50#伊予吉田,発,8:05#宇和島,着,8:14#"},
{"1055D":"松山,発,8:11#伊予市,発,8:20#内子,発,8:36#伊予大洲,発,8:45#八幡浜,発,8:59#卯之町,発,9:12#伊予吉田,発,9:23#宇和島,着,9:31#"},
{"1057D":"松山,発,9:07#伊予市,発,9:16#内子,発,9:33#伊予大洲,発,9:43#八幡浜,発,9:57#卯之町,発,10:09#伊予吉田,発,10:21#宇和島,着,10:30#"},
{"1059D":"松山,発,10:30#伊予市,発,10:39#内子,発,10:58#伊予大洲,発,11:10#八幡浜,発,11:29#卯之町,発,11:41#伊予吉田,発,11:55#宇和島,着,12:03#"},
{"1061D":"松山,発,11:30#伊予市,発,11:39#内子,発,11:58#伊予大洲,発,12:10#八幡浜,発,12:29#卯之町,発,12:41#伊予吉田,発,12:55#宇和島,着,13:03#"},
{"1063D":"松山,発,12:30#伊予市,発,12:39#内子,発,12:58#伊予大洲,発,13:10#八幡浜,発,13:29#卯之町,発,13:41#伊予吉田,発,13:55#宇和島,着,14:03#"},
{"1065D":"松山,発,13:30#伊予市,発,13:39#内子,発,13:58#伊予大洲,発,14:10#八幡浜,発,14:29#卯之町,発,14:41#伊予吉田,発,14:55#宇和島,着,15:03#"},
{"1067D":"松山,発,14:30#伊予市,発,14:39#内子,発,14:58#伊予大洲,発,15:10#八幡浜,発,15:29#卯之町,発,15:41#伊予吉田,発,15:55#宇和島,着,16:03#"},
{"1069D":"松山,発,15:30#伊予市,発,15:39#内子,発,15:58#伊予大洲,発,16:10#八幡浜,発,16:29#卯之町,発,16:41#伊予吉田,発,16:55#宇和島,着,17:03#"},
{"1071D":"松山,発,16:30#伊予市,発,16:39#内子,発,16:58#伊予大洲,発,17:10#八幡浜,発,17:29#卯之町,発,17:41#伊予吉田,発,17:55#宇和島,着,18:03#"},
{"1073D":"松山,発,17:30#伊予市,発,17:39#伊予中山,発,17:48#内子,発,17:58#伊予大洲,発,18:10#八幡浜,発,18:29#卯之町,発,18:41#伊予吉田,発,18:55#宇和島,着,19:03#"},
{"1075D":"松山,発,18:30#伊予市,発,18:39#伊予中山,発,18:48#内子,発,18:58#伊予大洲,発,19:10#八幡浜,発,19:29#卯之町,発,19:41#伊予吉田,発,19:55#宇和島,着,20:03#"},
{"1077D":"松山,発,19:30#伊予市,発,19:39#伊予中山,発,19:48#内子,発,19:58#伊予大洲,発,20:10#八幡浜,発,20:29#卯之町,発,20:41#伊予吉田,発,20:58#宇和島,着,21:06#"},
{"1079D":"松山,発,20:30#伊予市,発,20:39#内子,発,20:58#伊予大洲,発,21:08#八幡浜,発,21:22#卯之町,発,21:36#伊予吉田,発,21:52#宇和島,着,22:00#"},
{"1081D":"松山,発,22:00#伊予市,発,22:09#伊予中山,発,22:19#内子,発,22:31#伊予大洲,発,22:40#八幡浜,発,22:54#卯之町,発,23:07#伊予吉田,発,23:18#宇和島,着,23:27#"},
{"1091M":"新居浜,発,5:54#伊予西条,発,6:03#壬生川,発,6:12#今治,発,6:29#伊予北条,発,6:57#松山,着,7:09#"},
{"3621D":"八幡浜,発,6:17#双岩,発,6:26#伊予石城,発,6:36#上宇和,発,6:40#卯之町,発,6:58#下宇和,発,7:02#立間,発,7:10#伊予吉田,発,7:15#高光,発,7:23#北宇和島,発,7:30#宇和島,着,7:33#"},
{"4109M":"多度津,発,9:49#海岸寺,発,9:54#詫間,発,10:03#みの,発,10:06#高瀬,発,10:09#比地大,発,10:13#本山,発,10:16#観音寺,着,10:20#"},
{"4123M":"多度津,発,14:54#海岸寺,発,15:03#詫間,発,15:18#みの,発,15:21#高瀬,発,15:25#比地大,発,15:28#本山,発,15:31#観音寺,着,15:35#"},
{"4511M":"伊予北条,発,5:47#柳原,発,5:50#粟井,発,5:53#光洋台,発,5:56#堀江,発,5:59#伊予和気,発,6:03#三津浜,発,6:07#松山,着,6:11#"},
{"4521M":"伊予北条,発,8:28#柳原,発,8:31#粟井,発,8:33#光洋台,発,8:36#堀江,発,8:40#伊予和気,発,8:43#三津浜,発,8:49#松山,着,8:56#"},
{"4527M":"今治,発,10:04#波止浜,発,10:09#波方,発,10:13#大西,発,10:18#伊予亀岡,発,10:25#菊間,発,10:30#浅海,発,10:38#大浦,発,10:42#伊予北条,発,10:52#柳原,発,10:55#粟井,発,10:58#光洋台,発,11:01#堀江,発,11:10#伊予和気,発,11:14#三津浜,発,11:18#松山,着,11:23#"},
{"4529M":"伊予西条,発,10:00#石鎚山,発,10:05#伊予氷見,発,10:08#伊予小松,発,10:14#玉之江,発,10:18#壬生川,発,10:32#伊予三芳,発,10:36#伊予桜井,発,10:44#伊予富田,発,10:49#今治,発,11:04#波止浜,発,11:08#波方,発,11:11#大西,発,11:16#伊予亀岡,発,11:22#菊間,発,11:26#浅海,発,11:31#大浦,発,11:37#伊予北条,発,11:46#柳原,発,11:49#粟井,発,11:52#光洋台,発,11:55#堀江,発,11:59#伊予和気,発,12:08#三津浜,発,12:12#松山,着,12:16#"},
{"4533M":"伊予北条,発,12:38#柳原,発,12:41#粟井,発,12:44#光洋台,発,12:47#堀江,発,12:51#伊予和気,発,12:54#三津浜,発,13:03#松山,着,13:07#"},
{"4535M":"伊予西条,発,10:54#石鎚山,発,10:58#伊予氷見,発,11:02#伊予小松,発,11:04#玉之江,発,11:08#壬生川,発,11:12#伊予三芳,発,11:19#伊予桜井,発,11:33#伊予富田,発,11:38#今治,発,12:04#波止浜,発,12:09#波方,発,12:16#大西,発,12:20#伊予亀岡,発,12:26#菊間,発,12:30#浅海,発,12:46#大浦,発,12:50#伊予北条,発,12:54#柳原,発,12:57#粟井,発,12:59#光洋台,発,13:02#堀江,発,13:11#伊予和気,発,13:14#三津浜,発,13:18#松山,着,13:25#"},
{"4537M":"観音寺,発,10:35#豊浜,発,10:40#箕浦,発,10:47#川之江,発,10:53#伊予三島,発,11:00#伊予寒川,発,11:04#赤星,発,11:08#伊予土居,発,11:12#関川,発,11:16#多喜浜,発,11:24#新居浜,発,11:32#中萩,発,11:37#伊予西条,発,12:00#石鎚山,発,12:05#伊予氷見,発,12:08#伊予小松,発,12:19#玉之江,発,12:23#壬生川,発,12:33#伊予三芳,発,12:45#伊予桜井,発,12:52#伊予富田,発,12:56#今治,発,13:04#波止浜,発,13:10#波方,発,13:14#大西,発,13:18#伊予亀岡,発,13:23#菊間,発,13:28#浅海,発,13:42#大浦,発,13:46#伊予北条,発,13:53#柳原,発,13:56#粟井,発,13:58#光洋台,発,14:01#堀江,発,14:08#伊予和気,発,14:11#三津浜,発,14:16#松山,着,14:21#"},
{"4539M":"観音寺,発,11:40#豊浜,発,11:45#箕浦,発,11:49#川之江,発,11:56#伊予三島,発,12:04#伊予寒川,発,12:08#赤星,発,12:12#伊予土居,発,12:17#関川,発,12:22#多喜浜,発,12:37#新居浜,発,12:41#中萩,発,12:46#伊予西条,着,12:52#"},
{"4541M":"伊予西条,発,13:00#石鎚山,発,13:04#伊予氷見,発,13:08#伊予小松,発,13:17#玉之江,発,13:21#壬生川,発,13:32#伊予三芳,発,13:43#伊予桜井,発,13:51#伊予富田,発,13:55#今治,発,14:05#波止浜,発,14:10#波方,発,14:14#大西,発,14:19#伊予亀岡,発,14:25#菊間,発,14:30#浅海,発,14:43#大浦,発,14:47#伊予北条,発,14:54#柳原,発,14:57#粟井,発,15:00#光洋台,発,15:03#堀江,発,15:12#伊予和気,発,15:16#三津浜,発,15:21#松山,着,15:25#"},
{"4543M":"観音寺,発,12:40#豊浜,発,12:46#箕浦,発,12:50#川之江,発,12:57#伊予三島,発,13:03#伊予寒川,発,13:08#赤星,発,13:12#伊予土居,発,13:18#関川,発,13:23#多喜浜,発,13:37#新居浜,発,13:42#中萩,発,13:47#伊予西条,着,13:53#"},
{"4547M":"観音寺,発,13:41#豊浜,発,13:46#箕浦,発,13:50#川之江,発,13:58#伊予三島,発,14:03#伊予寒川,発,14:08#赤星,発,14:12#伊予土居,発,14:16#関川,発,14:20#多喜浜,発,14:27#新居浜,発,14:41#中萩,発,14:46#伊予西条,発,15:00#石鎚山,発,15:05#伊予氷見,発,15:09#伊予小松,発,15:18#玉之江,発,15:22#壬生川,発,15:33#伊予三芳,発,15:44#伊予桜井,発,15:52#伊予富田,発,15:56#今治,発,16:06#波止浜,発,16:11#波方,発,16:15#大西,発,16:19#伊予亀岡,発,16:25#菊間,発,16:31#浅海,発,16:45#大浦,発,16:49#伊予北条,発,16:54#柳原,発,16:57#粟井,発,17:00#光洋台,発,17:03#堀江,発,17:07#伊予和気,発,17:10#三津浜,発,17:16#松山,着,17:20#"},
{"4549M":"観音寺,発,14:41#豊浜,発,14:46#箕浦,発,14:50#川之江,発,14:58#伊予三島,発,15:03#伊予寒川,発,15:08#赤星,発,15:12#伊予土居,発,15:16#関川,発,15:20#多喜浜,発,15:27#新居浜,発,15:41#中萩,発,15:46#伊予西条,発,16:00#石鎚山,発,16:04#伊予氷見,発,16:08#伊予小松,発,16:10#玉之江,発,16:14#壬生川,発,16:19#伊予三芳,発,16:23#伊予桜井,発,16:33#伊予富田,発,16:37#今治,発,17:04#波止浜,発,17:10#波方,発,17:14#大西,発,17:19#伊予亀岡,発,17:25#菊間,発,17:30#浅海,発,17:39#大浦,発,17:43#伊予北条,発,17:55#柳原,発,17:59#粟井,発,18:02#光洋台,発,18:05#堀江,発,18:09#伊予和気,発,18:12#三津浜,発,18:17#松山,着,18:21#"},
{"4555M":"伊予西条,発,17:00#石鎚山,発,17:05#伊予氷見,発,17:08#伊予小松,発,17:11#玉之江,発,17:15#壬生川,発,17:19#伊予三芳,発,17:23#伊予桜井,発,17:33#伊予富田,発,17:37#今治,発,18:02#波止浜,発,18:10#波方,発,18:15#大西,発,18:21#伊予亀岡,発,18:28#菊間,発,18:33#浅海,発,18:39#大浦,発,18:44#伊予北条,発,18:51#柳原,発,18:55#粟井,発,18:57#光洋台,発,19:00#堀江,発,19:04#伊予和気,発,19:08#三津浜,発,19:15#松山,着,19:19#"},
{"4563M":"観音寺,発,18:45#豊浜,発,18:51#箕浦,発,18:56#川之江,発,19:03#伊予三島,発,19:08#伊予寒川,発,19:13#赤星,発,19:17#伊予土居,発,19:21#関川,発,19:26#多喜浜,発,19:33#新居浜,発,19:39#中萩,発,19:48#伊予西条,着,19:54#"},
{"4565M":"観音寺,発,19:53#豊浜,発,19:58#箕浦,発,20:03#川之江,発,20:13#伊予三島,発,20:18#伊予寒川,発,20:22#赤星,発,20:26#伊予土居,発,20:30#関川,発,20:34#多喜浜,発,20:44#新居浜,発,20:49#中萩,発,20:54#伊予西条,発,21:00#石鎚山,発,21:04#伊予氷見,発,21:07#伊予小松,発,21:10#玉之江,発,21:14#壬生川,発,21:17#伊予三芳,発,21:25#伊予桜井,発,21:32#伊予富田,発,21:37#今治,発,21:45#波止浜,発,21:52#波方,発,21:55#大西,発,22:00#伊予亀岡,発,22:17#菊間,発,22:22#浅海,発,22:27#大浦,発,22:31#伊予北条,発,22:35#柳原,発,22:38#粟井,発,22:40#光洋台,発,22:43#堀江,発,22:47#伊予和気,発,22:50#三津浜,発,22:54#松山,着,22:58#"},
{"4567M":"伊予西条,発,22:00#石鎚山,発,22:04#伊予氷見,発,22:07#伊予小松,発,22:10#玉之江,発,22:14#壬生川,発,22:20#伊予三芳,発,22:24#伊予桜井,発,22:35#伊予富田,発,22:40#今治,着,22:44#"},
{"4569M":"観音寺,発,21:33#豊浜,発,21:38#箕浦,発,21:43#川之江,発,21:48#伊予三島,発,22:14#伊予寒川,発,22:18#赤星,発,22:22#伊予土居,発,22:25#関川,発,22:30#多喜浜,発,22:37#新居浜,発,22:50#中萩,発,22:59#伊予西条,着,23:05#"},
{"4571M":"伊予北条,発,23:27#柳原,発,23:31#粟井,発,23:33#光洋台,発,23:36#堀江,発,23:40#伊予和気,発,23:43#三津浜,発,23:47#松山,着,23:54#"},
{"4623D":"松山,発,5:23#市坪,発,5:28#北伊予,発,5:32#南伊予,発,5:35#伊予横田,発,5:37#鳥ノ木,発,5:40#伊予市,発,5:43#向井原,発,5:47#伊予大平,発,5:51#伊予中山,発,6:08#伊予立川,発,6:15#内子,発,6:23#五十崎,発,6:25#喜多山,発,6:29#新谷,発,6:31#伊予大洲,発,6:51#西大洲,発,6:55#伊予平野,発,6:58#千丈,発,7:07#八幡浜,発,7:12#双岩,発,7:19#伊予石城,発,7:26#上宇和,発,7:30#卯之町,発,7:35#下宇和,発,7:39#立間,発,7:49#伊予吉田,発,7:53#高光,発,7:59#北宇和島,発,8:02#宇和島,着,8:04#"},
{"4625D":"松山,発,6:13#市坪,発,6:17#北伊予,発,6:23#南伊予,発,6:27#伊予横田,発,6:29#鳥ノ木,発,6:32#伊予市,発,6:41#向井原,発,6:45#伊予大平,発,6:49#伊予中山,発,7:00#伊予立川,発,7:21#内子,発,7:33#五十崎,発,7:36#喜多山,発,7:40#新谷,発,7:42#伊予大洲,着,7:48#"},
{"4627D":"松山,発,7:31#市坪,発,7:38#北伊予,発,7:45#南伊予,発,7:48#伊予横田,発,7:50#鳥ノ木,発,7:53#伊予市,着,7:55#"},
{"4629M":"松山,発,8:18#市坪,発,8:23#北伊予,発,8:31#南伊予,発,8:33#伊予横田,発,8:35#鳥ノ木,発,8:38#伊予市,着,8:40#"},
{"4631D":"松山,発,8:45#市坪,発,8:49#北伊予,発,9:02#南伊予,発,9:04#伊予横田,発,9:07#鳥ノ木,発,9:10#伊予市,発,9:19#向井原,発,9:23#伊予大平,発,9:27#伊予中山,発,9:38#伊予立川,発,9:45#内子,発,9:53#五十崎,発,9:55#喜多山,発,9:59#新谷,発,10:01#伊予大洲,着,10:07#"},
{"4633M":"松山,発,10:19#市坪,発,10:23#北伊予,発,10:26#南伊予,発,10:28#伊予横田,発,10:30#鳥ノ木,発,10:33#伊予市,着,10:35#"},
{"4635D":"松山,発,10:45#市坪,発,10:50#北伊予,発,10:54#南伊予,発,10:58#伊予横田,発,11:01#鳥ノ木,発,11:04#伊予市,発,11:11#向井原,発,11:15#伊予大平,発,11:20#伊予中山,発,11:31#伊予立川,発,11:37#内子,発,11:46#五十崎,発,11:49#喜多山,発,11:52#新谷,発,11:55#伊予大洲,着,12:01#"},
{"4637D":"八幡浜,発,12:34#双岩,発,12:41#伊予石城,発,12:48#上宇和,発,12:52#卯之町,発,12:55#下宇和,発,13:04#立間,発,13:12#伊予吉田,発,13:16#高光,発,13:23#北宇和島,発,13:30#宇和島,着,13:33#"},
{"4639D":"松山,発,12:45#市坪,発,12:50#北伊予,発,12:56#南伊予,発,12:59#伊予横田,発,13:01#鳥ノ木,発,13:04#伊予市,発,13:11#向井原,発,13:15#伊予大平,発,13:20#伊予中山,発,13:31#伊予立川,発,13:37#内子,発,13:46#五十崎,発,13:49#喜多山,発,13:52#新谷,発,13:55#伊予大洲,着,14:01#"},
{"4641D":"八幡浜,発,14:34#双岩,発,14:41#伊予石城,発,14:48#上宇和,発,14:52#卯之町,発,14:55#下宇和,発,15:04#立間,発,15:12#伊予吉田,発,15:16#高光,発,15:23#北宇和島,発,15:30#宇和島,着,15:33#"},
{"4643D":"松山,発,14:45#市坪,発,14:50#北伊予,発,14:54#南伊予,発,14:58#伊予横田,発,15:01#鳥ノ木,発,15:04#伊予市,発,15:11#向井原,発,15:15#伊予大平,発,15:20#伊予中山,発,15:31#伊予立川,発,15:37#内子,発,15:46#五十崎,発,15:49#喜多山,発,15:52#新谷,発,15:55#伊予大洲,着,16:01#"},
{"4645M":"伊予北条,発,14:35#柳原,発,14:38#粟井,発,14:40#光洋台,発,14:43#堀江,発,14:47#伊予和気,発,14:50#三津浜,発,14:54#松山,発,15:19#市坪,発,15:23#北伊予,発,15:26#南伊予,発,15:29#伊予横田,発,15:31#鳥ノ木,発,15:34#伊予市,着,15:35#"},
{"4647D":"松山,発,16:45#市坪,発,16:50#北伊予,発,16:54#南伊予,発,16:57#伊予横田,発,16:59#鳥ノ木,発,17:02#伊予市,発,17:11#向井原,発,17:15#伊予大平,発,17:20#伊予中山,発,17:31#伊予立川,発,17:37#内子,発,17:46#五十崎,発,17:49#喜多山,発,17:52#新谷,発,17:55#伊予大洲,着,18:01#"},
{"4649M":"伊予北条,発,17:30#柳原,発,17:33#粟井,発,17:35#光洋台,発,17:38#堀江,発,17:44#伊予和気,発,17:49#三津浜,発,17:54#松山,発,18:19#市坪,発,18:23#北伊予,発,18:26#南伊予,発,18:28#伊予横田,発,18:31#鳥ノ木,発,18:33#伊予市,着,18:35#"},
{"4651D":"八幡浜,発,16:55#双岩,発,17:02#伊予石城,発,17:11#上宇和,発,17:15#卯之町,発,17:18#下宇和,発,17:22#立間,発,17:29#伊予吉田,発,17:33#高光,発,17:39#北宇和島,発,17:42#宇和島,着,17:45#"},
{"4653D":"八幡浜,発,18:34#双岩,発,18:41#伊予石城,発,18:48#上宇和,発,18:52#卯之町,発,18:55#下宇和,発,19:04#立間,発,19:12#伊予吉田,発,19:16#高光,発,19:23#北宇和島,発,19:30#宇和島,着,19:33#"},
{"4655D":"松山,発,18:45#市坪,発,18:50#北伊予,発,18:54#南伊予,発,18:57#伊予横田,発,18:59#鳥ノ木,発,19:02#伊予市,発,19:11#向井原,発,19:15#伊予大平,発,19:20#伊予中山,発,19:31#伊予立川,発,19:37#内子,発,19:46#五十崎,発,19:49#喜多山,発,19:52#新谷,発,19:55#伊予大洲,着,20:01#"},
{"4657M":"松山,発,20:19#市坪,発,20:23#北伊予,発,20:26#南伊予,発,20:28#伊予横田,発,20:30#鳥ノ木,発,20:33#伊予市,着,20:35#"},
{"4659D":"八幡浜,発,21:00#双岩,発,21:08#伊予石城,発,21:15#上宇和,発,21:19#卯之町,発,21:22#下宇和,発,21:26#立間,発,21:37#伊予吉田,発,21:41#高光,発,21:47#北宇和島,発,21:51#宇和島,着,21:54#"},
{"4661D":"松山,発,20:45#市坪,発,20:50#北伊予,発,20:57#南伊予,発,21:00#伊予横田,発,21:03#鳥ノ木,発,21:06#伊予市,発,21:11#向井原,発,21:15#伊予大平,発,21:19#伊予中山,発,21:32#伊予立川,発,21:38#内子,発,21:45#五十崎,発,21:48#喜多山,発,21:51#新谷,発,21:54#伊予大洲,発,22:11#西大洲,発,22:14#伊予平野,発,22:17#千丈,発,22:27#八幡浜,着,22:33#"},
{"4663M":"松山,発,21:45#市坪,発,21:48#北伊予,発,21:51#南伊予,発,21:54#伊予横田,発,21:56#鳥ノ木,発,21:59#伊予市,着,22:01#"},
{"4665D":"松山,発,22:59#市坪,発,23:04#北伊予,発,23:07#南伊予,発,23:10#伊予横田,発,23:13#鳥ノ木,発,23:16#伊予市,着,23:18#"},
{"4913D":"松山,発,6:56#市坪,発,7:01#北伊予,発,7:09#南伊予,発,7:12#伊予横田,発,7:14#鳥ノ木,発,7:17#伊予市,発,7:23#向井原,発,7:27#高野川,発,7:35#伊予上灘,発,7:43#下灘,発,7:50#串,発,7:55#喜多灘,発,8:00#伊予長浜,発,8:24#伊予出石,発,8:29#伊予白滝,発,8:34#八多喜,発,8:38#春賀,発,8:41#五郎,発,8:45#伊予大洲,発,8:51#西大洲,発,8:55#伊予平野,発,8:58#千丈,発,9:08#八幡浜,着,9:12#"},
{"4915D":"松山,発,9:45#市坪,発,9:50#北伊予,発,9:54#南伊予,発,9:57#伊予横田,発,10:00#鳥ノ木,発,10:04#伊予市,発,10:11#向井原,発,10:15#高野川,発,10:23#伊予上灘,発,10:28#下灘,発,10:34#串,発,10:39#喜多灘,発,10:44#伊予長浜,発,10:56#伊予出石,発,11:01#伊予白滝,発,11:11#八多喜,発,11:15#春賀,発,11:18#五郎,発,11:21#伊予大洲,発,11:34#西大洲,発,11:38#伊予平野,発,11:41#千丈,発,11:50#八幡浜,着,11:54#"},
{"4917D":"松山,発,11:45#市坪,発,11:50#北伊予,発,11:54#南伊予,発,11:58#伊予横田,発,12:01#鳥ノ木,発,12:04#伊予市,発,12:11#向井原,発,12:15#高野川,発,12:23#伊予上灘,発,12:28#下灘,発,12:34#串,発,12:39#喜多灘,発,12:44#伊予長浜,発,12:50#伊予出石,発,12:55#伊予白滝,発,13:01#八多喜,発,13:05#春賀,発,13:08#五郎,発,13:12#伊予大洲,発,13:20#西大洲,発,13:24#伊予平野,発,13:29#千丈,発,13:39#八幡浜,着,13:43#"},
{"4919D":"松山,発,13:45#市坪,発,13:50#北伊予,発,13:54#南伊予,発,13:58#伊予横田,発,14:01#鳥ノ木,発,14:04#伊予市,発,14:25#向井原,発,14:29#高野川,発,14:37#伊予上灘,発,14:52#下灘,発,14:59#串,発,15:03#喜多灘,発,15:08#伊予長浜,発,15:17#伊予出石,発,15:22#伊予白滝,発,15:27#八多喜,発,15:31#春賀,発,15:35#五郎,発,15:39#伊予大洲,発,15:46#西大洲,発,15:50#伊予平野,発,15:58#千丈,発,16:07#八幡浜,着,16:11#"},
{"4921D":"松山,発,15:45#市坪,発,15:50#北伊予,発,15:54#南伊予,発,15:58#伊予横田,発,16:01#鳥ノ木,発,16:04#伊予市,発,16:11#向井原,発,16:15#高野川,発,16:23#伊予上灘,発,16:28#下灘,発,16:34#串,発,16:39#喜多灘,発,16:44#伊予長浜,発,16:52#伊予出石,発,16:57#伊予白滝,発,17:04#八多喜,発,17:08#春賀,発,17:11#五郎,発,17:15#伊予大洲,発,17:20#西大洲,発,17:24#伊予平野,発,17:29#千丈,発,17:39#八幡浜,着,17:43#"},
{"4927D":"伊予市,発,22:05#向井原,発,22:09#高野川,発,22:17#伊予上灘,発,22:21#下灘,発,22:28#串,発,22:32#喜多灘,発,22:37#伊予長浜,発,22:43#伊予出石,発,22:48#伊予白滝,発,22:53#八多喜,発,22:57#春賀,発,23:00#五郎,発,23:04#伊予大洲,着,23:09#"},
{"5101M":"伊予西条,発,8:01#石鎚山,発,8:05#伊予氷見,発,8:08#伊予小松,発,8:13#玉之江,発,8:17#壬生川,発,8:26#伊予三芳,発,8:30#伊予桜井,発,8:38#伊予富田,発,8:43#今治,発,8:51#波止浜,発,8:58#波方,発,9:02#大西,発,9:07#伊予亀岡,発,9:14#菊間,発,9:20#浅海,発,9:26#大浦,発,9:32#伊予北条,発,9:36#柳原,発,9:39#粟井,発,9:42#光洋台,発,9:45#堀江,発,9:49#伊予和気,発,9:52#三津浜,発,9:57#松山,着,10:01#"},
{"5103M":"多度津,発,7:04#海岸寺,発,7:08#詫間,発,7:16#みの,発,7:19#高瀬,発,7:37#比地大,発,7:41#本山,発,7:44#観音寺,発,7:54#豊浜,発,7:59#箕浦,発,8:04#川之江,発,8:10#伊予三島,発,8:16#伊予寒川,発,8:20#赤星,発,8:24#伊予土居,発,8:28#関川,発,8:35#多喜浜,発,8:42#新居浜,発,8:47#中萩,発,8:54#伊予西条,着,9:00#"},
{"5107M":"高松,発,7:40#香西,発,7:44#鬼無,発,7:48#端岡,発,7:56#国分,発,7:59#讃岐府中,発,8:02#鴨川,発,8:06#八十場,発,8:09#坂出,発,8:12#宇多津,発,8:18#丸亀,発,8:21#讃岐塩屋,発,8:24#多度津,発,8:31#海岸寺,発,8:36#詫間,発,8:42#みの,発,8:45#高瀬,発,8:49#比地大,発,8:53#本山,発,9:03#観音寺,着,9:06#"},
{"5109M":"高松,発,9:04#端岡,発,9:12#坂出,発,9:22#宇多津,発,9:27#丸亀,発,9:31#讃岐塩屋,発,9:34#多度津,着,9:37#"},
{"5113M":"高松,発,10:52#香西,発,10:56#鬼無,発,11:00#端岡,発,11:04#国分,発,11:07#讃岐府中,発,11:10#鴨川,発,11:13#八十場,発,11:16#坂出,発,11:20#宇多津,発,11:26#丸亀,発,11:30#讃岐塩屋,発,11:32#多度津,着,11:35#"},
{"5129M":"高松,発,15:52#香西,発,15:56#鬼無,発,16:00#端岡,発,16:04#国分,発,16:07#讃岐府中,発,16:10#鴨川,発,16:13#八十場,発,16:16#坂出,発,16:20#宇多津,発,16:25#丸亀,発,16:29#讃岐塩屋,発,16:31#多度津,着,16:34#"},
{"5135M":"高松,発,17:13#端岡,発,17:21#鴨川,発,17:28#坂出,発,17:32#宇多津,発,17:38#丸亀,発,17:41#讃岐塩屋,発,17:44#多度津,発,17:51#海岸寺,発,17:57#詫間,発,18:03#みの,発,18:07#高瀬,発,18:17#比地大,発,18:21#本山,発,18:24#観音寺,着,18:28#"},
{"5145M":"高松,発,19:25#香西,発,19:31#鬼無,発,19:34#端岡,発,19:39#国分,発,19:42#讃岐府中,発,19:45#鴨川,発,19:53#八十場,発,19:56#坂出,発,20:00#宇多津,発,20:05#丸亀,発,20:08#讃岐塩屋,発,20:11#多度津,着,20:14#"},
{"5513M":"今治,発,5:58#波止浜,発,6:04#波方,発,6:08#大西,発,6:12#伊予亀岡,発,6:18#菊間,発,6:23#浅海,発,6:34#大浦,発,6:38#伊予北条,発,6:45#柳原,発,6:48#粟井,発,6:51#光洋台,発,6:54#堀江,発,6:58#伊予和気,発,7:06#三津浜,発,7:11#松山,着,7:15#"},
{"5519M":"観音寺,発,6:03#豊浜,発,6:08#箕浦,発,6:13#川之江,発,6:19#伊予三島,発,6:30#伊予寒川,発,6:34#赤星,発,6:39#伊予土居,発,6:43#関川,発,6:47#多喜浜,発,6:56#新居浜,発,7:01#中萩,発,7:06#伊予西条,着,7:12#"},
{"5525M":"観音寺,発,7:07#豊浜,発,7:21#箕浦,発,7:26#川之江,発,7:32#伊予三島,発,7:39#伊予寒川,発,7:43#赤星,発,7:47#伊予土居,発,7:51#関川,発,7:55#多喜浜,発,8:02#新居浜,発,8:15#中萩,発,8:24#伊予西条,着,8:29#"},
{"5531M":"観音寺,発,9:11#豊浜,発,9:16#箕浦,発,9:21#川之江,発,9:27#伊予三島,発,9:34#伊予寒川,発,9:38#赤星,発,9:42#伊予土居,発,9:46#関川,発,9:50#多喜浜,発,9:57#新居浜,発,10:02#中萩,発,10:07#伊予西条,着,10:12#"},
{"5545M":"伊予西条,発,14:00#石鎚山,発,14:04#伊予氷見,発,14:08#伊予小松,発,14:10#玉之江,発,14:14#壬生川,発,14:18#伊予三芳,発,14:22#伊予桜井,発,14:33#伊予富田,発,14:43#今治,発,15:04#波止浜,発,15:09#波方,発,15:13#大西,発,15:18#伊予亀岡,発,15:24#菊間,発,15:29#浅海,発,15:44#大浦,発,15:48#伊予北条,発,15:54#柳原,発,15:57#粟井,発,16:00#光洋台,発,16:03#堀江,発,16:11#伊予和気,発,16:15#三津浜,発,16:19#松山,着,16:24#"},
{"5551M":"伊予北条,発,18:18#柳原,発,18:22#粟井,発,18:25#光洋台,発,18:28#堀江,発,18:32#伊予和気,発,18:36#三津浜,発,18:43#松山,着,18:48#"},
{"5553M":"観音寺,発,15:49#豊浜,発,15:55#箕浦,発,16:03#川之江,発,16:08#伊予三島,発,16:14#伊予寒川,発,16:18#赤星,発,16:22#伊予土居,発,16:26#関川,発,16:30#多喜浜,発,16:40#新居浜,発,16:46#中萩,発,16:51#伊予西条,着,16:57#"},
{"5557M":"観音寺,発,16:51#豊浜,発,16:57#箕浦,発,17:03#川之江,発,17:09#伊予三島,発,17:15#伊予寒川,発,17:19#赤星,発,17:23#伊予土居,発,17:27#関川,発,17:31#多喜浜,発,17:40#新居浜,発,17:46#中萩,発,17:51#伊予西条,着,17:56#"},
{"6107M":"高松,発,7:40#香西,発,7:44#鬼無,発,7:48#端岡,発,7:56#国分,発,7:59#讃岐府中,発,8:02#鴨川,発,8:06#八十場,発,8:09#坂出,発,8:12#宇多津,発,8:21#丸亀,発,8:25#讃岐塩屋,発,8:28#多度津,発,8:31#海岸寺,発,8:36#詫間,発,8:42#みの,発,8:45#高瀬,発,8:49#比地大,発,8:53#本山,発,9:03#観音寺,着,9:06#"},
{"8091D":"松山,発,8:28#市坪,発,8:34#伊予市,発,8:45#下灘,発,9:25#喜多灘,発,9:42#伊予大洲,着,10:28#"},
{"8093D":"松山,発,13:38#下灘,発,14:23#喜多灘,発,14:40#伊予大洲,発,15:14#伊予平野,発,15:36#千丈,発,15:51#八幡浜,着,15:56#"},
{"3102M":"高松,発,4:35#鬼無,発,4:40#端岡,発,4:44#国分,発,4:47#鴨川,発,4:51#坂出,発,4:56#児島,発,5:15#上の町,発,5:18#木見,発,5:22#植松,発,5:25#茶屋町,発,5:28#早島,発,5:32#妹尾,発,5:35#備前西市,発,5:39#大元,発,5:42#岡山,着,5:45#"},
{"3104M":"高松,発,5:35#坂出,発,5:49#児島,発,6:05#茶屋町,発,6:14#妹尾,発,6:20#大元,発,6:25#岡山,着,6:28#"},
{"3106M":"高松,発,6:08#坂出,発,6:22#児島,発,6:38#茶屋町,発,6:47#早島,発,6:50#妹尾,発,6:54#大元,発,7:01#岡山,着,7:04#"},
{"3108M":"高松,発,6:46#坂出,発,7:01#児島,発,7:17#茶屋町,発,7:27#早島,発,7:30#妹尾,発,7:34#備前西市,発,7:39#大元,発,7:43#岡山,着,7:46#"},
{"3110M":"高松,発,7:08#坂出,発,7:23#児島,発,7:39#上の町,発,7:43#木見,発,7:47#植松,発,7:50#茶屋町,発,7:54#早島,発,7:58#妹尾,発,8:02#備前西市,発,8:08#大元,発,8:12#岡山,着,8:15#"},
{"3112M":"高松,発,7:48#坂出,発,8:03#児島,発,8:21#茶屋町,発,8:30#早島,発,8:34#妹尾,発,8:38#岡山,着,8:45#"},
{"3114M":"高松,発,8:22#坂出,発,8:36#児島,発,8:53#茶屋町,発,9:02#早島,発,9:06#妹尾,発,9:10#備前西市,発,9:14#岡山,着,9:19#"},
{"3116M":"高松,発,8:55#坂出,発,9:09#児島,発,9:25#茶屋町,発,9:33#早島,発,9:36#妹尾,発,9:40#岡山,着,9:47#"},
{"3118M":"高松,発,9:23#坂出,発,9:38#児島,発,9:54#茶屋町,発,10:03#妹尾,発,10:10#岡山,着,10:17#"},
{"3120M":"高松,発,9:52#坂出,発,10:07#児島,発,10:23#茶屋町,発,10:33#早島,発,10:37#岡山,着,10:48#"},
{"3122M":"高松,発,10:10#坂出,発,10:24#児島,発,10:40#茶屋町,発,10:49#妹尾,発,10:56#岡山,着,11:03#"},
{"3124M":"高松,発,10:40#坂出,発,10:54#児島,発,11:11#茶屋町,発,11:19#早島,発,11:23#岡山,着,11:32#"},
{"3126M":"高松,発,11:10#坂出,発,11:24#児島,発,11:40#茶屋町,発,11:49#妹尾,発,11:55#岡山,着,12:02#"},
{"3128M":"高松,発,11:40#坂出,発,11:54#児島,発,12:10#茶屋町,発,12:19#早島,発,12:23#岡山,着,12:32#"},
{"3130M":"高松,発,12:10#坂出,発,12:24#児島,発,12:40#茶屋町,発,12:49#妹尾,発,12:55#岡山,着,13:02#"},
{"3132M":"高松,発,12:40#坂出,発,12:54#児島,発,13:10#茶屋町,発,13:19#早島,発,13:23#岡山,着,13:32#"},
{"3134M":"高松,発,13:10#坂出,発,13:24#児島,発,13:40#茶屋町,発,13:49#妹尾,発,13:55#岡山,着,14:02#"},
{"3136M":"高松,発,13:40#坂出,発,13:54#児島,発,14:11#茶屋町,発,14:19#早島,発,14:23#岡山,着,14:34#"},
{"3138M":"高松,発,14:10#坂出,発,14:24#児島,発,14:40#茶屋町,発,14:49#妹尾,発,14:55#岡山,着,15:02#"},
{"3140M":"高松,発,14:40#坂出,発,14:54#児島,発,15:10#茶屋町,発,15:19#早島,発,15:23#岡山,着,15:32#"},
{"3142M":"高松,発,15:10#坂出,発,15:24#児島,発,15:40#茶屋町,発,15:49#妹尾,発,15:55#岡山,着,16:03#"},
{"3144M":"高松,発,15:40#坂出,発,15:54#児島,発,16:10#茶屋町,発,16:19#早島,発,16:23#岡山,着,16:32#"},
{"3146M":"高松,発,16:10#坂出,発,16:24#児島,発,16:40#茶屋町,発,16:49#妹尾,発,16:55#岡山,着,17:03#"},
{"3148M":"高松,発,16:40#坂出,発,16:54#児島,発,17:10#茶屋町,発,17:19#早島,発,17:23#岡山,着,17:32#"},
{"3150M":"高松,発,17:10#坂出,発,17:25#児島,発,17:41#茶屋町,発,17:49#妹尾,発,17:55#岡山,着,18:03#"},
{"3152M":"高松,発,17:40#坂出,発,17:55#児島,発,18:11#茶屋町,発,18:19#早島,発,18:23#岡山,着,18:32#"},
{"3154M":"高松,発,18:10#坂出,発,18:24#児島,発,18:40#茶屋町,発,18:49#妹尾,発,18:55#岡山,着,19:02#"},
{"3156M":"高松,発,18:40#坂出,発,18:55#児島,発,19:11#茶屋町,発,19:19#早島,発,19:23#岡山,着,19:33#"},
{"3158M":"高松,発,19:10#坂出,発,19:25#児島,発,19:41#茶屋町,発,19:49#妹尾,発,19:55#岡山,着,20:03#"},
{"3160M":"高松,発,19:40#坂出,発,19:54#児島,発,20:10#茶屋町,発,20:19#早島,発,20:23#岡山,着,20:35#"},
{"3162M":"高松,発,20:10#坂出,発,20:24#児島,発,20:40#茶屋町,発,20:51#妹尾,発,20:58#岡山,着,21:05#"},
{"3164M":"高松,発,20:43#坂出,発,20:57#児島,発,21:13#茶屋町,発,21:22#早島,発,21:25#岡山,着,21:36#"},
{"3166M":"高松,発,21:13#坂出,発,21:27#児島,発,21:44#茶屋町,発,21:52#妹尾,発,21:58#岡山,着,22:05#"},
{"3168M":"高松,発,21:43#坂出,発,21:57#児島,発,22:14#茶屋町,発,22:22#早島,発,22:26#妹尾,発,22:31#岡山,着,22:38#"},
{"3170M":"高松,発,22:27#端岡,発,22:35#鴨川,発,22:41#坂出,発,22:45#児島,発,23:01#上の町,発,23:04#木見,発,23:08#植松,発,23:11#茶屋町,発,23:15#早島,発,23:18#妹尾,発,23:21#大元,発,23:26#岡山,着,23:30#"},
{"5032M":"高松,発,21:26#坂出,発,21:44#児島,発,22:01#岡山,着,22:23#"},
{"8176D":"高松,発,9:13#端岡,発,9:24#鴨川,発,9:36#坂出,発,9:43#児島,発,10:15#岡山,着,10:44#"},
{"3101M":"岡山,発,5:27#大元,発,5:30#妹尾,発,5:35#早島,発,5:39#茶屋町,発,5:42#植松,発,5:45#木見,発,5:48#上の町,発,5:52#児島,発,5:57#坂出,発,6:13#高松,着,6:31#"},
{"3103M":"岡山,発,6:01#妹尾,発,6:08#茶屋町,発,6:14#児島,発,6:24#坂出,発,6:39#高松,着,6:56#"},
{"3105M":"岡山,発,6:37#妹尾,発,6:46#早島,発,6:49#茶屋町,発,6:53#児島,発,7:02#坂出,発,7:18#高松,着,7:33#"},
{"3107M":"岡山,発,7:10#大元,発,7:13#妹尾,発,7:19#早島,発,7:23#茶屋町,発,7:26#児島,発,7:35#坂出,発,7:52#高松,着,8:07#"},
{"3109M":"岡山,発,7:55#妹尾,発,8:03#早島,発,8:07#茶屋町,発,8:10#児島,発,8:19#坂出,発,8:35#高松,着,8:50#"},
{"3111M":"岡山,発,8:24#妹尾,発,8:31#早島,発,8:35#茶屋町,発,8:39#児島,発,8:48#坂出,発,9:04#高松,着,9:18#"},
{"3113M":"岡山,発,8:40#妹尾,発,8:53#茶屋町,発,8:59#児島,発,9:09#坂出,発,9:24#高松,着,9:39#"},
{"3115M":"岡山,発,9:05#早島,発,9:15#茶屋町,発,9:19#児島,発,9:28#坂出,発,9:43#高松,着,9:58#"},
{"3117M":"岡山,発,9:33#妹尾,発,9:40#茶屋町,発,9:46#児島,発,9:56#坂出,発,10:11#高松,着,10:26#"},
{"3119M":"岡山,発,9:54#早島,発,10:05#茶屋町,発,10:09#児島,発,10:20#坂出,発,10:36#高松,着,10:51#"},
{"3121M":"岡山,発,10:23#妹尾,発,10:33#茶屋町,発,10:39#児島,発,10:48#坂出,発,11:03#高松,着,11:18#"},
{"3123M":"岡山,発,10:53#早島,発,11:06#茶屋町,発,11:09#児島,発,11:19#坂出,発,11:35#高松,着,11:49#"},
{"3125M":"岡山,発,11:12#妹尾,発,11:20#茶屋町,発,11:26#児島,発,11:36#坂出,発,11:52#高松,着,12:07#"},
{"3127M":"岡山,発,11:42#早島,発,11:52#茶屋町,発,11:55#児島,発,12:05#坂出,発,12:20#高松,着,12:37#"},
{"3129M":"岡山,発,12:13#妹尾,発,12:20#茶屋町,発,12:26#児島,発,12:35#坂出,発,12:51#高松,着,13:05#"},
{"3131M":"岡山,発,12:42#早島,発,12:52#茶屋町,発,12:55#児島,発,13:05#坂出,発,13:20#高松,着,13:36#"},
{"3133M":"岡山,発,13:13#妹尾,発,13:20#茶屋町,発,13:26#児島,発,13:35#坂出,発,13:51#高松,着,14:05#"},
{"3135M":"岡山,発,13:42#早島,発,13:52#茶屋町,発,13:55#児島,発,14:05#坂出,発,14:20#高松,着,14:36#"},
{"3137M":"岡山,発,14:13#妹尾,発,14:20#茶屋町,発,14:26#児島,発,14:35#坂出,発,14:51#高松,着,15:05#"},
{"3139M":"岡山,発,14:42#早島,発,14:52#茶屋町,発,14:56#児島,発,15:05#坂出,発,15:20#高松,着,15:36#"},
{"3141M":"岡山,発,15:13#妹尾,発,15:20#茶屋町,発,15:26#児島,発,15:35#坂出,発,15:51#高松,着,16:05#"},
{"3143M":"岡山,発,15:42#妹尾,発,15:49#早島,発,15:53#茶屋町,発,15:57#児島,発,16:06#坂出,発,16:21#高松,着,16:36#"},
{"3145M":"岡山,発,16:13#妹尾,発,16:20#茶屋町,発,16:26#児島,発,16:35#坂出,発,16:51#高松,着,17:05#"},
{"3147M":"岡山,発,16:42#妹尾,発,16:49#早島,発,16:53#茶屋町,発,16:57#児島,発,17:06#坂出,発,17:21#高松,着,17:36#"},
{"3149M":"岡山,発,17:13#妹尾,発,17:20#茶屋町,発,17:26#児島,発,17:35#坂出,発,17:51#高松,着,18:06#"},
{"3151M":"岡山,発,17:42#妹尾,発,17:49#早島,発,17:53#茶屋町,発,17:57#児島,発,18:06#坂出,発,18:24#高松,着,18:40#"},
{"3153M":"岡山,発,18:13#妹尾,発,18:20#茶屋町,発,18:26#児島,発,18:36#坂出,発,18:51#高松,着,19:06#"},
{"3155M":"岡山,発,18:42#妹尾,発,18:49#早島,発,18:53#茶屋町,発,18:57#児島,発,19:06#坂出,発,19:22#高松,着,19:38#"},
{"3157M":"岡山,発,19:13#妹尾,発,19:20#早島,発,19:24#茶屋町,発,19:27#児島,発,19:37#坂出,発,19:53#高松,着,20:07#"},
{"3159M":"岡山,発,19:42#妹尾,発,19:49#早島,発,19:53#茶屋町,発,19:57#児島,発,20:06#坂出,発,20:21#高松,着,20:37#"},
{"3161M":"岡山,発,20:13#妹尾,発,20:21#茶屋町,発,20:27#児島,発,20:36#坂出,発,20:52#高松,着,21:07#"},
{"3163M":"岡山,発,20:42#妹尾,発,20:52#早島,発,20:56#茶屋町,発,20:59#児島,発,21:08#坂出,発,21:24#高松,着,21:39#"},
{"3165M":"岡山,発,21:13#妹尾,発,21:23#茶屋町,発,21:29#児島,発,21:38#坂出,発,21:53#高松,着,22:08#"},
{"3167M":"岡山,発,21:42#妹尾,発,21:52#早島,発,21:56#茶屋町,発,21:59#児島,発,22:09#坂出,発,22:24#高松,着,22:39#"},
{"3169M":"岡山,発,22:12#妹尾,発,22:23#早島,発,22:27#茶屋町,発,22:30#児島,発,22:40#坂出,発,22:55#高松,着,23:10#"},
{"3171M":"岡山,発,22:46#妹尾,発,22:53#早島,発,22:57#茶屋町,発,23:00#上の町,発,23:07#児島,発,23:11#坂出,発,23:27#鴨川,発,23:31#国分,発,23:36#端岡,発,23:39#鬼無,発,23:42#高松,着,23:48#"},
{"3173M":"岡山,発,23:12#大元,発,23:16#妹尾,発,23:22#早島,発,23:25#茶屋町,発,23:29#植松,発,23:32#木見,発,23:35#上の町,発,23:39#児島,発,23:43#坂出,発,23:59#鴨川,発,0:04#国分,発,0:08#端岡,発,0:11#鬼無,発,0:15#高松,着,0:20#"},
{"3175M":"岡山,発,23:47#大元,発,23:50#妹尾,発,23:55#早島,発,23:59#茶屋町,発,0:02#植松,発,0:05#木見,発,0:08#上の町,発,0:12#児島,発,0:16#坂出,発,0:35#鴨川,発,0:39#端岡,発,0:45#高松,着,0:53#"},
{"5031M":"岡山,発,6:31#児島,発,6:53#坂出,発,7:10#高松,着,7:27#"},
{"8041M":"岡山,発,6:31#児島,発,6:53#坂出,発,7:10#高松,着,7:27#"},
{"8179D":"岡山,発,15:21#児島,発,16:11#坂出,発,16:35#鴨川,発,16:44#端岡,発,16:53#高松,着,17:02#"},
{"2M":"伊予西条,発,4:59#新居浜,発,5:06#伊予三島,発,5:23#川之江,発,5:27#観音寺,発,5:38#高瀬,発,5:45#詫間,発,5:49#多度津,発,5:57#丸亀,発,6:00#宇多津,発,6:07#児島,発,6:22#岡山,着,6:43#"},
{"4M":"松山,発,5:05#伊予北条,発,5:17#今治,発,5:41#壬生川,発,5:54#伊予西条,発,6:03#新居浜,発,6:11#伊予三島,発,6:30#川之江,発,6:34#観音寺,発,6:45#高瀬,発,6:52#詫間,発,6:56#多度津,発,7:04#丸亀,発,7:08#宇多津,発,7:15#児島,発,7:29#岡山,着,7:51#"},
{"6M":"松山,発,6:13#伊予北条,発,6:25#今治,発,6:50#壬生川,発,7:03#伊予西条,発,7:12#新居浜,発,7:22#伊予三島,発,7:39#川之江,発,7:43#観音寺,発,7:54#高瀬,発,8:02#詫間,発,8:06#多度津,発,8:17#丸亀,発,8:21#宇多津,発,8:27#児島,発,8:40#岡山,着,9:00#"},
{"8M":"松山,発,7:20#伊予北条,発,7:32#今治,発,7:57#壬生川,発,8:09#伊予西条,発,8:19#新居浜,発,8:27#伊予三島,発,8:44#川之江,発,8:48#観音寺,発,8:59#詫間,発,9:08#多度津,発,9:16#丸亀,発,9:20#宇多津,発,9:26#児島,発,9:40#岡山,着,10:00#"},
{"10M":"松山,発,8:10#伊予北条,発,8:23#今治,発,8:47#壬生川,発,9:00#伊予西条,発,9:09#新居浜,発,9:17#伊予三島,発,9:34#川之江,発,9:39#観音寺,発,9:53#多度津,発,10:09#丸亀,発,10:14#宇多津,発,10:20#児島,発,10:34#岡山,着,10:58#"},
{"12M":"松山,発,9:15#伊予北条,発,9:28#今治,発,9:56#壬生川,発,10:10#伊予西条,発,10:19#新居浜,発,10:27#伊予三島,発,10:46#川之江,発,10:53#観音寺,発,11:04#多度津,発,11:21#丸亀,発,11:26#宇多津,発,11:34#児島,発,11:50#岡山,着,12:11#"},
{"14M":"松山,発,10:21#今治,発,10:59#壬生川,発,11:12#伊予西条,発,11:24#新居浜,発,11:32#伊予三島,発,11:52#川之江,発,11:56#観音寺,発,12:07#多度津,発,12:22#丸亀,発,12:27#宇多津,発,12:34#児島,発,12:49#岡山,着,13:11#"},
{"16M":"松山,発,11:23#今治,発,12:02#壬生川,発,12:15#伊予西条,発,12:26#新居浜,発,12:33#伊予三島,発,12:52#川之江,発,12:57#観音寺,発,13:07#多度津,発,13:23#丸亀,発,13:28#宇多津,発,13:35#児島,発,13:50#岡山,着,14:11#"},
{"18M":"松山,発,12:21#今治,発,13:00#壬生川,発,13:12#伊予西条,発,13:26#新居浜,発,13:34#伊予三島,発,13:53#川之江,発,13:57#観音寺,発,14:08#多度津,発,14:24#丸亀,発,14:28#宇多津,発,14:35#児島,発,14:50#岡山,着,15:11#"},
{"20M":"松山,発,13:26#今治,発,14:05#壬生川,発,14:18#伊予西条,発,14:26#新居浜,発,14:34#伊予三島,発,14:53#川之江,発,14:58#観音寺,発,15:08#多度津,発,15:24#丸亀,発,15:29#宇多津,発,15:35#児島,発,15:50#岡山,着,16:11#"},
{"22M":"松山,発,14:23#今治,発,15:01#壬生川,発,15:14#伊予西条,発,15:27#新居浜,発,15:35#伊予三島,発,15:54#川之江,発,15:58#観音寺,発,16:09#多度津,発,16:25#丸亀,発,16:29#宇多津,発,16:35#児島,発,16:50#岡山,着,17:11#"},
{"24M":"松山,発,15:28#今治,発,16:06#壬生川,発,16:19#伊予西条,発,16:28#新居浜,発,16:36#伊予三島,発,16:55#川之江,発,16:59#観音寺,発,17:10#多度津,発,17:26#丸亀,発,17:30#宇多津,発,17:36#児島,発,17:50#岡山,着,18:11#"},
{"26M":"松山,発,16:27#伊予北条,発,16:39#今治,発,17:04#壬生川,発,17:18#伊予西条,発,17:29#新居浜,発,17:37#伊予三島,発,17:55#川之江,発,18:00#観音寺,発,18:11#多度津,発,18:26#丸亀,発,18:31#宇多津,発,18:37#児島,発,18:51#岡山,着,19:11#"},
{"28M":"松山,発,17:37#伊予北条,発,17:49#今治,発,18:13#壬生川,発,18:25#伊予西条,発,18:34#新居浜,発,18:42#伊予三島,発,18:59#川之江,発,19:03#観音寺,発,19:14#多度津,発,19:29#丸亀,発,19:33#宇多津,発,19:39#児島,発,19:53#岡山,着,20:12#"},
{"30M":"松山,発,18:39#伊予北条,発,18:51#今治,発,19:19#壬生川,発,19:33#伊予西条,発,19:43#新居浜,発,19:51#伊予三島,発,20:08#川之江,発,20:13#観音寺,発,20:24#高瀬,発,20:31#詫間,発,20:36#多度津,発,20:43#丸亀,発,20:47#宇多津,発,20:53#児島,発,21:07#岡山,着,21:30#"},
{"32D":"高知,発,6:00#後免,発,6:07#土佐山田,発,6:12#大杉,発,6:31#大歩危,発,6:48#阿波池田,発,7:08#琴平,発,7:32#善通寺,発,7:37#多度津,発,7:49#丸亀,発,7:54#宇多津,発,7:58#児島,発,8:14#岡山,着,8:38#"},
{"34D":"高知,発,7:00#後免,発,7:07#土佐山田,発,7:12#大杉,発,7:32#大歩危,発,7:52#阿波池田,発,8:13#琴平,発,8:40#善通寺,発,8:45#多度津,発,8:51#丸亀,発,8:55#宇多津,発,9:00#児島,発,9:15#岡山,着,9:38#"},
{"36D":"高知,発,8:01#後免,発,8:09#土佐山田,発,8:14#大歩危,発,8:49#阿波池田,発,9:07#琴平,発,9:35#善通寺,発,9:39#多度津,発,9:46#丸亀,発,9:51#宇多津,発,9:58#児島,発,10:12#岡山,着,10:33#"},
{"38D":"高知,発,9:13#後免,発,9:20#土佐山田,発,9:27#大歩危,発,10:02#阿波池田,発,10:23#琴平,発,10:47#善通寺,発,10:54#多度津,発,10:59#丸亀,発,11:03#宇多津,発,11:07#児島,発,11:21#岡山,着,11:40#"},
{"40D":"高知,発,10:13#後免,発,10:20#土佐山田,発,10:25#大杉,発,10:44#大歩危,発,11:05#阿波池田,発,11:23#琴平,発,11:47#善通寺,発,11:53#多度津,発,11:59#丸亀,発,12:03#宇多津,発,12:06#児島,発,12:20#岡山,着,12:40#"},
{"42D":"高知,発,11:13#後免,発,11:22#土佐山田,発,11:27#大歩危,発,12:05#阿波池田,発,12:23#琴平,発,12:47#善通寺,発,12:53#多度津,発,12:59#丸亀,発,13:03#宇多津,発,13:06#児島,発,13:20#岡山,着,13:40#"},
{"44D":"高知,発,12:13#後免,発,12:21#土佐山田,発,12:26#大歩危,発,13:05#阿波池田,発,13:23#琴平,発,13:47#善通寺,発,13:53#多度津,発,13:59#丸亀,発,14:03#宇多津,発,14:06#児島,発,14:20#岡山,着,14:41#"},
{"46D":"高知,発,13:13#後免,発,13:20#土佐山田,発,13:25#大杉,発,13:46#大歩危,発,14:05#阿波池田,発,14:23#琴平,発,14:47#善通寺,発,14:53#多度津,発,14:59#丸亀,発,15:03#宇多津,発,15:06#児島,発,15:20#岡山,着,15:41#"},
{"48D":"高知,発,14:13#後免,発,14:20#土佐山田,発,14:25#大歩危,発,15:02#阿波池田,発,15:23#琴平,発,15:47#善通寺,発,15:53#多度津,発,15:59#丸亀,発,16:03#宇多津,発,16:06#児島,発,16:20#岡山,着,16:41#"},
{"50D":"高知,発,15:13#後免,発,15:20#土佐山田,発,15:25#大杉,発,15:45#大歩危,発,16:02#阿波池田,発,16:23#琴平,発,16:47#善通寺,発,16:53#多度津,発,16:59#丸亀,発,17:03#宇多津,発,17:06#児島,発,17:20#岡山,着,17:41#"},
{"52D":"高知,発,16:13#後免,発,16:20#土佐山田,発,16:25#大杉,発,16:45#大歩危,発,17:02#阿波池田,発,17:23#琴平,発,17:46#善通寺,発,17:50#多度津,発,17:57#丸亀,発,18:02#宇多津,発,18:06#児島,発,18:20#岡山,着,18:41#"},
{"54D":"高知,発,17:13#後免,発,17:20#土佐山田,発,17:25#大杉,発,17:46#大歩危,発,18:05#阿波池田,発,18:23#琴平,発,18:46#善通寺,発,18:52#多度津,発,18:59#丸亀,発,19:03#宇多津,発,19:07#児島,発,19:21#岡山,着,19:41#"},
{"56D":"高知,発,18:38#後免,発,18:46#土佐山田,発,18:51#大杉,発,19:11#大歩危,発,19:30#阿波池田,発,19:48#琴平,発,20:14#善通寺,発,20:19#多度津,発,20:25#丸亀,発,20:29#宇多津,発,20:33#児島,発,20:48#岡山,着,21:12#"},
{"58D":"高知,発,19:31#後免,発,19:42#土佐山田,発,19:46#大杉,発,20:06#大歩危,発,20:23#阿波池田,発,20:42#琴平,発,21:05#善通寺,発,21:09#多度津,発,21:15#丸亀,発,21:19#宇多津,発,21:23#児島,発,21:38#岡山,着,21:57#"},
{"8278D":"琴平,発,13:16#多度津,発,13:34#宇多津,発,13:45#児島,発,14:23#岡山,着,14:54#"},
{"1M":"岡山,発,7:22#児島,発,7:42#宇多津,発,8:01#丸亀,発,8:04#多度津,発,8:09#詫間,発,8:17#観音寺,発,8:27#川之江,発,8:37#伊予三島,発,8:44#新居浜,発,9:01#伊予西条,発,9:09#壬生川,発,9:18#今治,発,9:31#伊予北条,発,9:54#松山,着,10:06#"},
{"3M":"岡山,発,8:32#児島,発,8:54#宇多津,発,9:13#丸亀,発,9:16#多度津,発,9:21#詫間,発,9:28#観音寺,発,9:38#川之江,発,9:49#伊予三島,発,9:54#新居浜,発,10:11#伊予西条,発,10:19#壬生川,発,10:28#今治,発,10:41#松山,着,11:15#"},
{"5M":"岡山,発,9:25#児島,発,9:47#宇多津,発,10:06#丸亀,発,10:10#多度津,発,10:15#観音寺,発,10:31#川之江,発,10:41#伊予三島,発,10:46#新居浜,発,11:03#伊予西条,発,11:12#壬生川,発,11:22#今治,発,11:36#松山,着,12:10#"},
{"7M":"岡山,発,10:35#児島,発,10:55#宇多津,発,11:13#丸亀,発,11:17#多度津,発,11:21#観音寺,発,11:37#川之江,発,11:47#伊予三島,発,11:52#新居浜,発,12:09#伊予西条,発,12:17#壬生川,発,12:29#今治,発,12:42#松山,着,13:16#"},
{"9M":"岡山,発,11:35#児島,発,11:55#宇多津,発,12:14#丸亀,発,12:17#多度津,発,12:22#観音寺,発,12:37#川之江,発,12:48#伊予三島,発,12:52#新居浜,発,13:10#伊予西条,発,13:18#壬生川,発,13:27#今治,発,13:39#松山,着,14:13#"},
{"11M":"岡山,発,12:35#児島,発,12:55#宇多津,発,13:14#丸亀,発,13:18#多度津,発,13:23#観音寺,発,13:38#川之江,発,13:48#伊予三島,発,13:53#新居浜,発,14:10#伊予西条,発,14:18#壬生川,発,14:31#今治,発,14:43#松山,着,15:17#"},
{"13M":"岡山,発,13:35#児島,発,13:55#宇多津,発,14:14#丸亀,発,14:18#多度津,発,14:23#観音寺,発,14:38#川之江,発,14:49#伊予三島,発,14:53#新居浜,発,15:10#伊予西条,発,15:19#壬生川,発,15:28#今治,発,15:41#伊予北条,発,16:04#松山,着,16:16#"},
{"15M":"岡山,発,14:35#児島,発,14:56#宇多津,発,15:15#丸亀,発,15:19#多度津,発,15:24#観音寺,発,15:39#川之江,発,15:49#伊予三島,発,15:54#新居浜,発,16:11#伊予西条,発,16:19#壬生川,発,16:32#今治,発,16:45#伊予北条,発,17:12#松山,着,17:24#"},
{"17M":"岡山,発,15:35#児島,発,15:55#宇多津,発,16:15#丸亀,発,16:19#多度津,発,16:24#観音寺,発,16:39#川之江,発,16:50#伊予三島,発,16:55#新居浜,発,17:12#伊予西条,発,17:20#壬生川,発,17:32#今治,発,17:45#伊予北条,発,18:13#松山,着,18:26#"},
{"19M":"岡山,発,16:35#児島,発,16:55#宇多津,発,17:15#丸亀,発,17:18#多度津,発,17:25#観音寺,発,17:40#川之江,発,17:51#伊予三島,発,17:55#新居浜,発,18:13#伊予西条,発,18:21#壬生川,発,18:34#今治,発,18:47#伊予北条,発,19:11#松山,着,19:23#"},
{"21M":"岡山,発,17:35#児島,発,17:55#宇多津,発,18:09#丸亀,発,18:13#多度津,発,18:26#観音寺,発,18:42#川之江,発,18:52#伊予三島,発,18:58#新居浜,発,19:15#伊予西条,発,19:24#壬生川,発,19:33#今治,発,19:48#伊予北条,発,20:16#松山,着,20:28#"},
{"23M":"岡山,発,18:35#児島,発,18:55#宇多津,発,19:10#丸亀,発,19:14#多度津,発,19:29#詫間,発,19:37#高瀬,発,19:41#観音寺,発,19:49#川之江,発,20:01#伊予三島,発,20:08#新居浜,発,20:25#伊予西条,発,20:33#壬生川,発,20:42#今治,発,20:55#伊予北条,発,21:22#松山,着,21:34#"},
{"25M":"岡山,発,19:35#児島,発,19:55#宇多津,発,20:09#丸亀,発,20:12#多度津,発,20:26#詫間,発,20:36#高瀬,発,20:40#観音寺,発,20:48#川之江,発,21:02#伊予三島,発,21:07#新居浜,発,21:25#伊予西条,発,21:36#壬生川,発,21:45#今治,発,21:58#伊予北条,発,22:22#松山,着,22:35#"},
{"27M":"岡山,発,20:39#児島,発,21:01#宇多津,発,21:15#丸亀,発,21:18#多度津,発,21:31#詫間,発,21:40#高瀬,発,21:46#観音寺,発,21:55#川之江,発,22:06#伊予三島,発,22:11#新居浜,発,22:28#伊予西条,発,22:36#壬生川,発,22:45#今治,発,22:58#伊予北条,発,23:22#松山,着,23:34#"},
{"29M":"岡山,発,22:00#児島,発,22:22#宇多津,発,22:36#丸亀,発,22:39#多度津,発,22:52#詫間,発,23:00#高瀬,発,23:05#観音寺,発,23:13#川之江,発,23:30#伊予三島,発,23:35#新居浜,発,23:52#伊予西条,着,23:59#"},
{"31D":"岡山,発,7:08#児島,発,7:29#宇多津,発,7:46#丸亀,発,7:50#多度津,発,7:56#善通寺,発,8:01#琴平,発,8:06#阿波池田,発,8:29#大歩危,発,8:49#大杉,発,9:07#土佐山田,発,9:27#後免,発,9:32#高知,着,9:39#"},
{"33D":"岡山,発,8:52#児島,発,9:17#宇多津,発,9:33#丸亀,発,9:36#多度津,発,9:44#善通寺,発,9:51#琴平,発,9:59#阿波池田,発,10:24#大歩危,発,10:41#大杉,発,10:58#土佐山田,発,11:18#後免,発,11:23#高知,着,11:30#"},
{"35D":"岡山,発,10:05#児島,発,10:26#宇多津,発,10:39#丸亀,発,10:43#多度津,発,10:48#善通寺,発,10:54#琴平,発,10:59#阿波池田,発,11:24#大歩危,発,11:41#土佐山田,発,12:16#後免,発,12:21#高知,着,12:29#"},
{"37D":"岡山,発,11:05#児島,発,11:25#宇多津,発,11:39#丸亀,発,11:42#多度津,発,11:47#善通寺,発,11:53#琴平,発,11:59#阿波池田,発,12:24#大歩危,発,12:46#土佐山田,発,13:26#後免,発,13:31#高知,着,13:39#"},
{"39D":"岡山,発,12:05#児島,発,12:25#宇多津,発,12:39#丸亀,発,12:42#多度津,発,12:47#善通寺,発,12:53#琴平,発,12:59#阿波池田,発,13:24#大歩危,発,13:44#土佐山田,発,14:26#後免,発,14:31#高知,着,14:38#"},
{"41D":"岡山,発,13:05#児島,発,13:25#宇多津,発,13:39#丸亀,発,13:42#多度津,発,13:47#善通寺,発,13:53#琴平,発,13:59#阿波池田,発,14:24#大歩危,発,14:42#土佐山田,発,15:26#後免,発,15:31#高知,着,15:38#"},
{"43D":"岡山,発,14:05#児島,発,14:25#宇多津,発,14:39#丸亀,発,14:42#多度津,発,14:47#善通寺,発,14:53#琴平,発,14:59#阿波池田,発,15:24#大歩危,発,15:42#土佐山田,発,16:26#後免,発,16:31#高知,着,16:39#"},
{"45D":"岡山,発,15:05#児島,発,15:25#宇多津,発,15:39#丸亀,発,15:42#多度津,発,15:47#善通寺,発,15:53#琴平,発,15:59#阿波池田,発,16:24#大歩危,発,16:42#土佐山田,発,17:26#後免,発,17:31#高知,着,17:41#"},
{"47D":"岡山,発,16:05#児島,発,16:25#宇多津,発,16:39#丸亀,発,16:42#多度津,発,16:47#善通寺,発,16:53#琴平,発,16:59#阿波池田,発,17:24#大歩危,発,17:42#大杉,発,18:05#土佐山田,発,18:26#後免,発,18:31#高知,着,18:44#"},
{"49D":"岡山,発,17:05#児島,発,17:26#宇多津,発,17:41#丸亀,発,17:45#多度津,発,17:55#善通寺,発,18:01#琴平,発,18:06#阿波池田,発,18:34#大歩危,発,18:52#大杉,発,19:11#土佐山田,発,19:30#後免,発,19:34#高知,着,19:44#"},
{"51D":"岡山,発,18:05#児島,発,18:26#宇多津,発,18:41#丸亀,発,18:45#多度津,発,18:51#善通寺,発,18:58#琴平,発,19:03#阿波池田,発,19:26#大歩危,発,19:48#大杉,発,20:06#土佐山田,発,20:26#後免,発,20:34#高知,着,20:42#"},
{"53D":"岡山,発,19:05#児島,発,19:27#宇多津,発,19:42#丸亀,発,19:46#多度津,発,19:51#善通寺,発,19:56#琴平,発,20:01#阿波池田,発,20:31#大歩危,発,20:52#大杉,発,21:10#土佐山田,発,21:31#後免,発,21:36#高知,着,21:44#"},
{"55D":"岡山,発,20:05#児島,発,20:29#宇多津,発,20:45#丸亀,発,20:49#多度津,発,20:59#善通寺,発,21:10#琴平,発,21:15#阿波池田,発,21:39#大歩危,発,21:58#大杉,発,22:15#土佐山田,発,22:34#後免,発,22:39#高知,着,22:47#"},
{"57D":"岡山,発,21:38#児島,発,21:59#宇多津,発,22:14#丸亀,発,22:18#多度津,発,22:23#善通寺,発,22:29#琴平,発,22:34#阿波池田,発,22:58#大歩危,発,23:16#大杉,発,23:34#土佐山田,発,23:54#後免,発,23:59#高知,着,0:06#"},
{"8277D":"岡山,発,11:17#児島,発,12:10#宇多津,発,12:30#多度津,発,12:41#琴平,着,13:04#"},
{"3810D":"宇和島,発,5:46#北宇和島,発,5:49#務田,発,6:01#伊予宮野下,発,6:04#二名,発,6:07#大内,発,6:11#深田,発,6:16#近永,発,6:20#出目,発,6:23#松丸,発,6:29#吉野生,発,6:34#真土,発,6:37#西ケ方,発,6:46#江川崎,着,6:50#"},
{"4812D":"江川崎,発,7:10#半家,発,7:19#十川,発,7:27#土佐昭和,発,7:32#土佐大正,発,7:42#打井川,発,7:50#家地川,発,7:56#若井,発,8:04#窪川,着,8:09#"},
{"4814D":"宇和島,発,7:27#北宇和島,発,7:30#務田,発,7:43#伊予宮野下,発,7:48#二名,発,7:52#大内,発,7:55#深田,発,8:01#近永,発,8:06#出目,発,8:09#松丸,発,8:15#吉野生,発,8:20#真土,発,8:23#西ケ方,発,8:32#江川崎,着,8:36#"},
{"4818D":"宇和島,発,11:27#北宇和島,発,11:30#務田,発,11:43#伊予宮野下,発,11:48#二名,発,11:52#大内,発,11:55#深田,発,12:01#近永,発,12:05#出目,発,12:08#松丸,発,12:14#吉野生,発,12:19#真土,発,12:22#西ケ方,発,12:31#江川崎,着,12:35#"},
{"4820D":"宇和島,発,13:27#北宇和島,発,13:30#務田,発,13:43#伊予宮野下,発,13:48#二名,発,13:52#大内,発,13:55#深田,発,14:01#近永,発,14:05#出目,発,14:08#松丸,発,14:14#吉野生,発,14:19#真土,発,14:22#西ケ方,発,14:31#江川崎,発,14:35#半家,発,14:44#十川,発,14:52#土佐昭和,発,14:57#土佐大正,発,15:07#打井川,発,15:15#家地川,発,15:21#若井,発,15:29#窪川,着,15:34#"},
{"4822D":"宇和島,発,15:27#北宇和島,発,15:30#務田,発,15:43#伊予宮野下,発,15:49#二名,発,15:53#大内,発,15:56#深田,発,16:02#近永,発,16:06#出目,発,16:09#松丸,発,16:15#吉野生,発,16:20#真土,発,16:23#西ケ方,発,16:32#江川崎,着,16:36#"},
{"4824D":"宇和島,発,17:27#北宇和島,発,17:30#務田,発,17:43#伊予宮野下,発,17:48#二名,発,17:52#大内,発,17:55#深田,発,18:01#近永,発,18:05#出目,発,18:08#松丸,発,18:14#吉野生,発,18:19#真土,発,18:22#西ケ方,発,18:31#江川崎,発,18:41#半家,発,18:49#十川,発,18:57#土佐昭和,発,19:02#土佐大正,発,19:15#打井川,発,19:23#家地川,発,19:29#若井,発,19:38#窪川,着,19:44#"},
{"4826D":"宇和島,発,19:27#北宇和島,発,19:30#務田,発,19:43#伊予宮野下,発,19:48#二名,発,19:52#大内,発,19:55#深田,発,20:01#近永,発,20:05#出目,発,20:08#松丸,発,20:14#吉野生,発,20:19#真土,発,20:22#西ケ方,発,20:31#江川崎,着,20:35#"},
{"4828D":"宇和島,発,21:11#北宇和島,発,21:14#務田,発,21:27#伊予宮野下,発,21:31#二名,発,21:35#大内,発,21:38#深田,発,21:44#近永,着,21:47#"},
{"8816D":"宇和島,発,9:34#北宇和島,発,9:37#務田,発,9:50#伊予宮野下,発,9:52#二名,発,9:57#大内,発,10:00#深田,発,10:06#近永,発,10:10#出目,発,10:13#松丸,発,10:19#吉野生,発,10:24#真土,発,10:27#西ケ方,発,10:37#江川崎,発,10:45#半家,発,10:54#十川,発,11:02#土佐昭和,発,11:08#土佐大正,発,11:42#打井川,発,11:50#家地川,発,11:57#若井,発,12:05#窪川,着,12:11#"},
{"3813D":"江川崎,発,7:00#西ケ方,発,7:04#真土,発,7:13#吉野生,発,7:16#松丸,発,7:21#出目,発,7:27#近永,発,7:31#深田,発,7:35#大内,発,7:41#二名,発,7:44#伊予宮野下,発,7:49#務田,発,7:51#北宇和島,発,8:05#宇和島,着,8:07#"},
{"4811D":"窪川,発,5:50#若井,発,5:55#家地川,発,6:02#打井川,発,6:08#土佐大正,発,6:15#土佐昭和,発,6:24#十川,発,6:29#半家,発,6:37#江川崎,着,6:45#"},
{"4815D":"江川崎,発,9:00#西ケ方,発,9:04#真土,発,9:13#吉野生,発,9:16#松丸,発,9:21#出目,発,9:27#近永,発,9:31#深田,発,9:35#大内,発,9:41#二名,発,9:44#伊予宮野下,発,9:53#務田,発,9:55#北宇和島,発,10:08#宇和島,着,10:11#"},
{"4817D":"窪川,発,9:39#若井,発,9:45#家地川,発,9:53#打井川,発,9:59#土佐大正,発,10:10#土佐昭和,発,10:18#十川,発,10:23#半家,発,10:31#江川崎,発,11:00#西ケ方,発,11:04#真土,発,11:13#吉野生,発,11:16#松丸,発,11:21#出目,発,11:27#近永,発,11:31#深田,発,11:35#大内,発,11:41#二名,発,11:44#伊予宮野下,発,11:49#務田,発,11:51#北宇和島,発,12:04#宇和島,着,12:07#"},
{"4819D":"江川崎,発,13:00#西ケ方,発,13:04#真土,発,13:13#吉野生,発,13:16#松丸,発,13:21#出目,発,13:27#近永,発,13:31#深田,発,13:35#大内,発,13:41#二名,発,13:44#伊予宮野下,発,13:49#務田,発,13:51#北宇和島,発,14:04#宇和島,着,14:07#"},
{"4823D":"江川崎,発,17:00#西ケ方,発,17:04#真土,発,17:13#吉野生,発,17:16#松丸,発,17:21#出目,発,17:27#近永,発,17:31#深田,発,17:35#大内,発,17:41#二名,発,17:44#伊予宮野下,発,17:49#務田,発,17:51#北宇和島,発,18:04#宇和島,着,18:07#"},
{"4825D":"窪川,発,17:41#若井,発,17:47#家地川,発,17:55#打井川,発,18:01#土佐大正,発,18:10#土佐昭和,発,18:19#十川,発,18:25#半家,発,18:33#江川崎,発,19:00#西ケ方,発,19:04#真土,発,19:13#吉野生,発,19:16#松丸,発,19:21#出目,発,19:27#近永,発,19:31#深田,発,19:35#大内,発,19:41#二名,発,19:44#伊予宮野下,発,19:49#務田,発,19:51#北宇和島,発,20:04#宇和島,着,20:07#"},
{"4827D":"江川崎,発,20:44#西ケ方,発,20:48#真土,発,20:57#吉野生,発,21:00#松丸,発,21:05#出目,発,21:11#近永,発,21:14#深田,発,21:18#大内,発,21:24#二名,発,21:27#伊予宮野下,発,21:31#務田,発,21:34#北宇和島,発,21:47#宇和島,着,21:49#"},
{"8821D":"窪川,発,13:15#若井,発,13:21#家地川,発,13:29#打井川,発,13:35#土佐大正,発,13:46#土佐昭和,発,13:56#十川,発,14:02#半家,発,14:10#江川崎,発,15:00#西ケ方,発,15:04#真土,発,15:14#吉野生,発,15:17#松丸,発,15:22#出目,発,15:28#近永,発,15:32#深田,発,15:36#大内,発,15:41#二名,発,15:45#伊予宮野下,発,15:49#務田,発,15:52#北宇和島,発,16:05#宇和島,着,16:08#"},
{"216D":"高知,発,6:27#薊野,発,6:30#土佐一宮,発,6:33#布師田,発,6:36#土佐大津,発,6:39#後免,発,6:44#土佐長岡,発,6:48#山田西町,発,6:51#土佐山田,着,6:52#"},
{"238D":"高知,発,12:45#薊野,発,12:48#土佐一宮,発,12:53#布師田,発,12:56#土佐大津,発,12:59#後免,発,13:05#土佐長岡,発,13:08#山田西町,発,13:12#土佐山田,着,13:14#"},
{"248D":"高知,発,16:15#薊野,発,16:19#土佐一宮,発,16:22#布師田,発,16:24#土佐大津,発,16:27#後免,発,16:38#土佐長岡,発,16:41#山田西町,発,16:45#土佐山田,着,16:47#"},
{"250D":"高知,発,17:29#薊野,発,17:32#土佐一宮,発,17:38#布師田,発,17:41#土佐大津,発,17:45#後免,発,17:54#土佐長岡,発,17:58#山田西町,発,18:02#土佐山田,着,18:04#"},
{"710D":"高知,発,6:03#薊野,発,6:06#土佐一宮,発,6:09#布師田,発,6:12#土佐大津,発,6:15#後免,発,6:19#土佐長岡,発,6:22#山田西町,発,6:26#土佐山田,着,6:27#"},
{"714D":"須崎,発,6:07#大間,発,6:10#多ノ郷,発,6:13#吾桑,発,6:17#斗賀野,発,6:24#襟野々,発,6:27#佐川,発,6:31#西佐川,発,6:34#土佐加茂,発,6:39#岡花,発,6:43#日下,発,6:46#小村神社前,発,6:50#波川,発,6:53#伊野,発,6:58#枝川,発,7:01#朝倉,発,7:07#高知商業前,発,7:11#旭,発,7:16#円行寺口,発,7:20#入明,発,7:25#高知,発,7:32#薊野,発,7:36#土佐一宮,発,7:40#布師田,発,7:42#土佐大津,発,7:47#後免,発,7:52#土佐長岡,発,7:55#山田西町,発,7:59#土佐山田,着,8:00#"},
{"716D":"窪川,発,5:54#仁井田,発,5:59#六反地,発,6:02#影野,発,6:05#土佐久礼,発,6:16#安和,発,6:23#土佐新荘,発,6:27#須崎,発,6:31#大間,発,6:34#多ノ郷,発,6:36#吾桑,発,6:39#斗賀野,発,6:47#襟野々,発,6:50#佐川,発,6:53#西佐川,発,6:56#土佐加茂,発,7:00#岡花,発,7:04#日下,発,7:07#小村神社前,発,7:11#波川,発,7:14#伊野,発,7:17#枝川,発,7:20#朝倉,発,7:25#高知商業前,発,7:28#旭,発,7:33#円行寺口,発,7:36#入明,発,7:40#高知,着,7:42#"},
{"718D":"須崎,発,6:58#大間,発,7:01#多ノ郷,発,7:03#吾桑,発,7:07#斗賀野,発,7:15#襟野々,発,7:18#佐川,発,7:21#西佐川,発,7:32#土佐加茂,発,7:37#岡花,発,7:41#日下,発,7:44#小村神社前,発,7:47#波川,発,7:50#伊野,発,7:53#枝川,発,7:56#朝倉,発,8:03#高知商業前,発,8:07#旭,発,8:10#円行寺口,発,8:12#入明,発,8:15#高知,着,8:17#"},
{"720D":"伊野,発,8:18#枝川,発,8:21#朝倉,発,8:29#高知商業前,発,8:32#旭,発,8:35#円行寺口,発,8:38#入明,発,8:40#高知,着,8:42#"},
{"732D":"須崎,発,11:21#大間,発,11:24#多ノ郷,発,11:27#吾桑,発,11:31#斗賀野,発,11:38#襟野々,発,11:42#佐川,発,11:45#西佐川,発,11:54#土佐加茂,発,11:58#岡花,発,12:02#日下,発,12:07#小村神社前,発,12:11#波川,発,12:14#伊野,発,12:17#枝川,発,12:20#朝倉,発,12:25#高知商業前,発,12:28#旭,発,12:34#円行寺口,発,12:37#入明,発,12:39#高知,着,12:41#"},
{"744D":"須崎,発,15:12#大間,発,15:15#多ノ郷,発,15:18#吾桑,発,15:24#斗賀野,発,15:31#襟野々,発,15:34#佐川,発,15:37#西佐川,発,15:41#土佐加茂,発,15:49#岡花,発,15:53#日下,発,16:07#小村神社前,発,16:11#波川,発,16:14#伊野,発,16:19#枝川,発,16:22#朝倉,発,16:27#高知商業前,発,16:30#旭,発,16:34#円行寺口,発,16:37#入明,発,16:39#高知,発,16:45#薊野,発,16:48#土佐一宮,発,16:53#布師田,発,16:56#土佐大津,発,16:59#後免,発,17:06#土佐長岡,発,17:09#山田西町,発,17:13#土佐山田,着,17:15#"},
{"746D":"須崎,発,15:50#大間,発,15:53#多ノ郷,発,15:55#吾桑,発,15:59#斗賀野,発,16:06#襟野々,発,16:09#佐川,発,16:16#西佐川,発,16:19#土佐加茂,発,16:24#岡花,発,16:28#日下,発,16:32#小村神社前,発,16:35#波川,発,16:39#伊野,発,16:57#枝川,発,17:00#朝倉,発,17:06#高知商業前,発,17:09#旭,発,17:16#円行寺口,発,17:18#入明,発,17:20#高知,着,17:22#"},
{"750D":"須崎,発,16:51#大間,発,16:55#多ノ郷,発,16:57#吾桑,発,17:03#斗賀野,発,17:10#襟野々,発,17:13#佐川,発,17:16#西佐川,発,17:19#土佐加茂,発,17:34#岡花,発,17:37#日下,発,17:40#小村神社前,発,17:44#波川,発,17:47#伊野,発,17:52#枝川,発,17:54#朝倉,発,17:59#高知商業前,発,18:02#旭,発,18:04#円行寺口,発,18:07#入明,発,18:09#高知,発,18:18#薊野,発,18:22#土佐一宮,発,18:26#布師田,発,18:29#土佐大津,発,18:34#後免,発,18:38#土佐長岡,発,18:41#山田西町,発,18:45#土佐山田,着,18:46#"},
{"754D":"須崎,発,17:22#大間,発,17:25#多ノ郷,発,17:28#吾桑,発,17:34#斗賀野,発,17:44#襟野々,発,17:47#佐川,発,17:50#西佐川,発,18:07#土佐加茂,発,18:11#岡花,発,18:15#日下,発,18:18#小村神社前,発,18:22#波川,発,18:25#伊野,発,18:28#枝川,発,18:31#朝倉,発,18:36#高知商業前,発,18:38#旭,発,18:43#円行寺口,発,18:46#入明,発,18:48#高知,発,18:52#薊野,発,18:56#土佐一宮,発,18:59#布師田,発,19:01#土佐大津,発,19:04#後免,発,19:08#土佐長岡,発,19:12#山田西町,発,19:15#土佐山田,着,19:16#"},
{"756D":"須崎,発,18:09#大間,発,18:12#多ノ郷,発,18:14#吾桑,発,18:18#斗賀野,発,18:25#襟野々,発,18:28#佐川,発,18:34#西佐川,発,18:37#土佐加茂,発,18:43#岡花,発,18:46#日下,発,18:53#小村神社前,発,18:56#波川,発,18:59#伊野,発,19:02#枝川,発,19:05#朝倉,発,19:12#高知商業前,発,19:15#旭,発,19:17#円行寺口,発,19:20#入明,発,19:22#高知,発,19:36#薊野,発,19:42#土佐一宮,発,19:45#布師田,発,19:48#土佐大津,発,19:51#後免,発,19:55#土佐長岡,発,19:58#山田西町,発,20:01#土佐山田,着,20:03#"},
{"764D":"須崎,発,21:22#大間,発,21:25#多ノ郷,発,21:27#吾桑,発,21:31#斗賀野,発,21:38#襟野々,発,21:41#佐川,発,21:46#西佐川,発,21:49#土佐加茂,発,21:54#岡花,発,21:58#日下,発,22:01#小村神社前,発,22:04#波川,発,22:07#伊野,発,22:10#枝川,発,22:13#朝倉,発,22:20#高知商業前,発,22:23#旭,発,22:25#円行寺口,発,22:28#入明,発,22:30#高知,着,22:32#"},
{"1214M":"琴平,発,7:00#善通寺,発,7:06#金蔵寺,発,7:09#多度津,発,7:14#讃岐塩屋,発,7:17#丸亀,発,7:20#宇多津,発,7:23#坂出,発,7:28#八十場,発,7:31#鴨川,発,7:34#讃岐府中,発,7:37#国分,発,7:40#端岡,発,7:43#鬼無,発,7:47#香西,発,7:50#高松,着,7:54#"},
{"1222M":"琴平,発,8:43#善通寺,発,8:56#金蔵寺,発,9:00#多度津,着,9:04#"},
{"1224M":"琴平,発,9:05#善通寺,発,9:10#金蔵寺,発,9:14#多度津,発,9:20#讃岐塩屋,発,9:24#丸亀,発,9:27#宇多津,発,9:30#坂出,発,9:36#八十場,発,9:39#鴨川,発,9:48#讃岐府中,発,9:51#国分,発,9:54#端岡,発,9:58#鬼無,発,10:01#香西,発,10:04#高松,着,10:08#"},
{"1230M":"琴平,発,11:05#善通寺,発,11:11#金蔵寺,発,11:14#多度津,発,11:30#讃岐塩屋,発,11:33#丸亀,発,11:36#宇多津,発,11:40#坂出,発,11:55#八十場,発,11:58#鴨川,発,12:01#讃岐府中,発,12:04#国分,発,12:07#端岡,発,12:10#鬼無,発,12:13#香西,発,12:17#高松,着,12:22#"},
{"1246M":"琴平,発,17:25#善通寺,発,17:31#金蔵寺,発,17:34#多度津,発,17:39#讃岐塩屋,発,17:42#丸亀,発,17:45#宇多津,発,17:49#坂出,発,17:55#八十場,発,17:58#鴨川,発,18:01#讃岐府中,発,18:04#国分,発,18:07#端岡,発,18:10#鬼無,発,18:13#香西,発,18:17#高松,着,18:21#"},
{"1248M":"琴平,発,18:23#善通寺,発,18:29#金蔵寺,発,18:32#多度津,着,18:36#"},
{"1250M":"琴平,発,19:34#善通寺,発,19:40#金蔵寺,発,19:44#多度津,発,19:53#讃岐塩屋,発,19:56#丸亀,発,19:59#宇多津,発,20:03#坂出,発,20:07#八十場,発,20:11#鴨川,発,20:14#讃岐府中,発,20:17#国分,発,20:20#端岡,発,20:23#鬼無,発,20:27#香西,発,20:30#高松,着,20:34#"},
{"2002D":"高知,発,4:51#後免,発,4:58#土佐山田,発,5:03#大杉,発,5:22#大歩危,発,5:40#阿波池田,発,6:00#琴平,発,6:23#善通寺,発,6:28#多度津,発,6:38#丸亀,発,6:42#坂出,発,6:48#高松,着,7:02#"},
{"2004D":"中村,発,18:47#土佐入野,発,18:54#土佐佐賀,発,19:05#窪川,発,19:24#土佐久礼,発,19:39#須崎,発,19:49#佐川,発,20:02#伊野,発,20:15#朝倉,発,20:21#旭,発,20:25#高知,発,20:32#後免,発,20:45#土佐山田,発,20:50#大杉,発,21:10#大歩危,発,21:28#阿波池田,発,21:49#琴平,発,22:12#善通寺,発,22:17#多度津,発,22:22#丸亀,発,22:27#坂出,発,22:33#高松,着,22:46#"},
{"2072D":"中村,発,6:08#土佐入野,発,6:15#土佐佐賀,発,6:26#窪川,発,6:46#土佐久礼,発,7:01#須崎,発,7:12#多ノ郷,発,7:16#佐川,発,7:27#伊野,発,7:40#朝倉,発,7:46#旭,発,7:54#高知,着,7:58#"},
{"2074D":"中村,発,7:00#土佐入野,発,7:07#土佐佐賀,発,7:20#窪川,発,7:41#土佐久礼,発,7:56#須崎,発,8:10#多ノ郷,発,8:14#佐川,発,8:26#伊野,発,8:51#朝倉,発,8:56#旭,発,9:00#高知,着,9:04#"},
{"2076D":"中村,発,9:24#土佐入野,発,9:31#土佐佐賀,発,9:45#窪川,発,10:04#土佐久礼,発,10:19#須崎,発,10:29#佐川,発,10:42#伊野,発,10:55#高知,着,11:05#"},
{"2078D":"中村,発,11:13#土佐入野,発,11:20#土佐上川口,発,11:28#土佐佐賀,発,11:36#窪川,発,11:56#土佐久礼,発,12:11#須崎,発,12:21#佐川,発,12:38#伊野,発,12:52#朝倉,発,12:57#旭,発,13:01#高知,着,13:05#"},
{"2080D":"中村,発,13:13#土佐入野,発,13:20#土佐佐賀,発,13:35#窪川,発,13:56#土佐久礼,発,14:12#須崎,発,14:22#佐川,発,14:39#伊野,発,14:52#朝倉,発,14:58#旭,発,15:01#高知,着,15:05#"},
{"2082D":"中村,発,15:13#土佐入野,発,15:20#土佐佐賀,発,15:36#窪川,発,15:56#土佐久礼,発,16:11#須崎,発,16:21#佐川,発,16:38#伊野,発,16:51#朝倉,発,16:57#旭,発,17:00#高知,着,17:04#"},
{"2084D":"中村,発,16:42#土佐入野,発,16:49#土佐佐賀,発,17:00#窪川,発,17:19#土佐久礼,発,17:35#須崎,発,17:45#佐川,発,18:02#伊野,発,18:15#朝倉,発,18:21#旭,発,18:25#高知,着,18:29#"},
{"3210D":"高知,発,5:41#薊野,発,5:45#土佐一宮,発,5:48#布師田,発,5:51#土佐大津,発,5:54#後免,発,5:59#土佐長岡,発,6:03#山田西町,発,6:06#土佐山田,着,6:08#"},
{"3258D":"高知,発,20:42#薊野,発,20:46#土佐一宮,発,20:49#布師田,発,20:51#土佐大津,発,20:54#後免,発,20:59#土佐長岡,発,21:02#山田西町,発,21:05#土佐山田,着,21:07#"},
{"3710D":"伊野,発,5:36#枝川,発,5:39#朝倉,発,5:44#高知商業前,発,5:47#旭,発,5:50#円行寺口,発,5:53#入明,発,5:55#高知,着,5:57#"},
{"3712D":"須崎,発,5:36#大間,発,5:39#多ノ郷,発,5:41#吾桑,発,5:45#斗賀野,発,5:52#襟野々,発,5:55#佐川,発,5:58#西佐川,発,6:02#土佐加茂,発,6:07#岡花,発,6:11#日下,発,6:14#小村神社前,発,6:17#波川,発,6:20#伊野,発,6:23#枝川,発,6:27#朝倉,発,6:31#高知商業前,発,6:35#旭,発,6:41#円行寺口,発,6:43#入明,発,6:46#高知,発,7:02#土佐一宮,発,7:07#土佐大津,発,7:12#後免,発,7:20#土佐山田,着,7:25#"},
{"3722D":"窪川,発,7:02#仁井田,発,7:07#六反地,発,7:10#影野,発,7:13#土佐久礼,発,7:26#安和,発,7:33#土佐新荘,発,7:37#須崎,発,7:41#大間,発,7:45#多ノ郷,発,7:48#吾桑,発,7:52#斗賀野,発,7:59#襟野々,発,8:02#佐川,発,8:05#西佐川,発,8:09#土佐加茂,発,8:14#岡花,発,8:18#日下,発,8:21#小村神社前,発,8:25#波川,発,8:28#伊野,発,8:35#枝川,発,8:38#朝倉,発,8:43#高知商業前,発,8:46#旭,発,8:49#円行寺口,発,8:52#入明,発,8:54#高知,着,8:57#"},
{"3726D":"須崎,発,9:12#大間,発,9:15#多ノ郷,発,9:18#吾桑,発,9:21#斗賀野,発,9:29#襟野々,発,9:32#佐川,発,9:35#西佐川,発,9:38#土佐加茂,発,9:42#岡花,発,9:46#日下,発,9:49#小村神社前,発,9:53#波川,発,9:56#伊野,発,10:02#枝川,発,10:06#朝倉,発,10:11#高知商業前,発,10:13#旭,発,10:18#円行寺口,発,10:21#入明,発,10:24#高知,着,10:26#"},
{"3730D":"須崎,発,10:13#大間,発,10:16#多ノ郷,発,10:18#吾桑,発,10:24#斗賀野,発,10:31#襟野々,発,10:34#佐川,発,10:37#西佐川,発,10:48#土佐加茂,発,11:00#岡花,発,11:04#日下,発,11:07#小村神社前,発,11:10#波川,発,11:13#伊野,発,11:17#枝川,発,11:20#朝倉,発,11:25#高知商業前,発,11:28#旭,発,11:34#円行寺口,発,11:37#入明,発,11:39#高知,着,11:41#"},
{"4212D":"阿波池田,発,6:12#佃,発,6:17#箸蔵,発,6:22#讃岐財田,発,6:34#黒川,発,6:38#塩入,発,6:45#琴平,着,6:51#"},
{"4214D":"大歩危,発,6:02#小歩危,発,6:10#阿波川口,発,6:15#祖谷口,発,6:19#三縄,発,6:24#阿波池田,着,6:28#"},
{"4218D":"阿波池田,発,6:38#佃,発,6:43#箸蔵,発,6:48#坪尻,発,6:56#讃岐財田,発,7:14#黒川,発,7:17#塩入,発,7:22#琴平,着,7:28#"},
{"4220D":"大歩危,発,7:09#小歩危,発,7:19#阿波川口,発,7:24#祖谷口,発,7:28#三縄,発,7:33#阿波池田,着,7:38#"},
{"4222D":"琴平,発,7:44#善通寺,発,7:53#金蔵寺,発,7:59#多度津,着,8:04#"},
{"4224D":"阿波池田,発,7:58#佃,発,8:05#箸蔵,発,8:10#坪尻,発,8:29#讃岐財田,発,8:42#黒川,発,8:46#塩入,発,8:52#琴平,着,8:58#"},
{"4226D":"土佐山田,発,7:04#新改,発,7:22#繁藤,発,7:35#角茂谷,発,7:39#土佐北川,発,7:50#大杉,発,7:56#土佐穴内,発,8:01#大田口,発,8:05#豊永,発,8:10#土佐岩原,発,8:23#大歩危,発,8:30#小歩危,発,8:42#阿波川口,発,8:47#祖谷口,発,8:51#三縄,発,8:56#阿波池田,着,9:01#"},
{"4228D":"高知,発,8:10#薊野,発,8:19#土佐一宮,発,8:22#布師田,発,8:25#土佐大津,発,8:28#後免,発,8:41#土佐長岡,発,8:44#山田西町,発,8:48#土佐山田,着,8:50#"},
{"4230D":"琴平,発,9:42#善通寺,発,9:51#金蔵寺,発,9:55#多度津,着,10:00#"},
{"4232D":"高知,発,10:45#薊野,発,10:48#土佐一宮,発,10:53#布師田,発,10:55#土佐大津,発,10:59#後免,発,11:05#土佐長岡,発,11:08#山田西町,発,11:12#土佐山田,着,11:14#"},
{"4234D":"大歩危,発,12:58#小歩危,発,13:13#阿波川口,発,13:18#祖谷口,発,13:22#三縄,発,13:29#阿波池田,着,13:34#"},
{"4236D":"阿波池田,発,13:36#佃,発,13:42#箸蔵,発,13:47#坪尻,発,13:53#讃岐財田,発,14:14#黒川,発,14:18#塩入,発,14:23#琴平,発,14:32#善通寺,発,14:38#金蔵寺,発,14:41#多度津,着,14:46#"},
{"4238D":"土佐山田,発,13:36#新改,発,13:46#繁藤,発,14:00#角茂谷,発,14:03#土佐北川,発,14:09#大杉,発,14:23#土佐穴内,発,14:28#大田口,発,14:32#豊永,発,14:37#土佐岩原,発,14:48#大歩危,発,15:17#小歩危,発,15:25#阿波川口,発,15:34#祖谷口,発,15:38#三縄,発,15:43#阿波池田,着,15:48#"},
{"4240D":"高知,発,13:45#薊野,発,13:48#土佐一宮,発,13:53#布師田,発,13:56#土佐大津,発,13:59#後免,発,14:05#土佐長岡,発,14:08#山田西町,発,14:12#土佐山田,着,14:14#"},
{"4242D":"阿波池田,発,16:35#佃,発,16:43#箸蔵,発,16:48#讃岐財田,発,17:08#黒川,発,17:12#塩入,発,17:17#琴平,着,17:23#"},
{"4244D":"高知,発,15:45#薊野,発,15:48#土佐一宮,発,15:53#布師田,発,15:56#土佐大津,発,16:03#後免,発,16:11#土佐長岡,発,16:15#山田西町,発,16:19#土佐山田,着,16:20#"},
{"4246D":"大歩危,発,17:42#小歩危,発,17:50#阿波川口,発,18:02#祖谷口,発,18:06#三縄,発,18:11#阿波池田,発,18:38#佃,発,18:44#箸蔵,発,18:51#讃岐財田,発,19:12#黒川,発,19:16#塩入,発,19:22#琴平,着,19:28#"},
{"4248D":"土佐山田,発,16:53#繁藤,発,17:12#角茂谷,発,17:16#土佐北川,発,17:19#大杉,発,17:25#土佐穴内,発,17:30#大田口,発,17:34#豊永,発,17:39#土佐岩原,発,17:48#大歩危,発,18:19#小歩危,発,18:26#阿波川口,発,18:43#祖谷口,発,18:47#三縄,発,18:52#阿波池田,着,18:57#"},
{"4252D":"高知,発,17:49#薊野,発,17:53#土佐一宮,発,17:57#布師田,発,17:59#土佐大津,発,18:03#後免,発,18:07#土佐長岡,発,18:11#山田西町,発,18:15#土佐山田,着,18:16#"},
{"4254D":"大歩危,発,19:50#小歩危,発,19:57#阿波川口,発,20:03#祖谷口,発,20:06#三縄,発,20:12#阿波池田,着,20:17#"},
{"4256D":"土佐山田,発,19:30#新改,発,19:40#繁藤,発,20:01#角茂谷,発,20:05#土佐北川,発,20:11#大杉,発,20:17#土佐穴内,発,20:22#大田口,発,20:26#豊永,発,20:32#土佐岩原,発,20:37#大歩危,発,20:52#小歩危,発,20:59#阿波川口,発,21:04#祖谷口,発,21:08#三縄,発,21:13#阿波池田,着,21:18#"},
{"4724D":"須崎,発,8:16#大間,発,8:19#多ノ郷,発,8:22#吾桑,発,8:26#斗賀野,発,8:34#襟野々,発,8:38#佐川,発,8:47#西佐川,発,8:50#土佐加茂,発,8:55#岡花,発,9:00#日下,発,9:03#小村神社前,発,9:06#波川,発,9:09#伊野,発,9:12#枝川,発,9:15#朝倉,発,9:20#高知商業前,発,9:23#旭,発,9:26#円行寺口,発,9:29#入明,発,9:31#高知,発,9:45#薊野,発,9:48#土佐一宮,発,9:53#布師田,発,9:55#土佐大津,発,9:59#後免,発,10:05#土佐長岡,発,10:08#山田西町,発,10:12#土佐山田,着,10:14#"},
{"4728D":"伊野,発,11:02#枝川,発,11:06#朝倉,発,11:11#高知商業前,発,11:13#旭,発,11:18#円行寺口,発,11:21#入明,発,11:24#高知,発,11:45#薊野,発,11:48#土佐一宮,発,11:53#布師田,発,11:56#土佐大津,発,11:59#後免,発,12:05#土佐長岡,発,12:08#山田西町,発,12:12#土佐山田,着,12:14#"},
{"4734D":"伊野,発,13:02#枝川,発,13:05#朝倉,発,13:10#高知商業前,発,13:13#旭,発,13:15#円行寺口,発,13:18#入明,発,13:20#高知,着,13:22#"},
{"4736D":"須崎,発,12:30#大間,発,12:33#多ノ郷,発,12:35#吾桑,発,12:39#斗賀野,発,12:46#襟野々,発,12:49#佐川,発,12:52#西佐川,発,12:55#土佐加茂,発,13:00#岡花,発,13:04#日下,発,13:07#小村神社前,発,13:10#波川,発,13:13#伊野,発,13:17#枝川,発,13:20#朝倉,発,13:25#高知商業前,発,13:28#旭,発,13:34#円行寺口,発,13:37#入明,発,13:39#高知,着,13:41#"},
{"4738D":"窪川,発,12:33#仁井田,発,12:38#六反地,発,12:42#影野,発,12:51#土佐久礼,発,13:02#安和,発,13:09#土佐新荘,発,13:13#須崎,発,13:17#大間,発,13:20#多ノ郷,発,13:25#吾桑,発,13:29#斗賀野,発,13:36#襟野々,発,13:39#佐川,発,13:43#西佐川,発,13:46#土佐加茂,発,13:51#岡花,発,13:55#日下,発,14:07#小村神社前,発,14:11#波川,発,14:14#伊野,発,14:17#枝川,発,14:20#朝倉,発,14:25#高知商業前,発,14:28#旭,発,14:34#円行寺口,発,14:37#入明,発,14:39#高知,発,14:45#薊野,発,14:48#土佐一宮,発,14:53#布師田,発,14:56#土佐大津,発,14:59#後免,発,15:05#土佐長岡,発,15:08#山田西町,発,15:12#土佐山田,着,15:14#"},
{"4740D":"須崎,発,14:00#大間,発,14:03#多ノ郷,発,14:05#吾桑,発,14:11#斗賀野,発,14:21#襟野々,発,14:24#佐川,発,14:28#西佐川,発,14:44#土佐加茂,発,14:49#岡花,発,14:53#日下,発,14:56#小村神社前,発,15:00#波川,発,15:04#伊野,発,15:17#枝川,発,15:20#朝倉,発,15:25#高知商業前,発,15:28#旭,発,15:34#円行寺口,発,15:37#入明,発,15:40#高知,着,15:42#"},
{"4742D":"伊野,発,16:02#枝川,発,16:05#朝倉,発,16:13#高知商業前,発,16:16#旭,発,16:18#円行寺口,発,16:21#入明,発,16:23#高知,着,16:25#"},
{"4748D":"伊野,発,17:26#枝川,発,17:29#朝倉,発,17:33#高知商業前,発,17:36#旭,発,17:39#円行寺口,発,17:41#入明,発,17:43#高知,着,17:45#"},
{"4752D":"窪川,発,16:37#仁井田,発,16:42#六反地,発,16:45#影野,発,16:51#土佐久礼,発,17:02#安和,発,17:09#土佐新荘,発,17:13#須崎,着,17:15#"},
{"4758D":"伊野,発,19:22#枝川,発,19:25#朝倉,発,19:30#高知商業前,発,19:33#旭,発,19:36#円行寺口,発,19:39#入明,発,19:42#高知,着,19:44#"},
{"4760D":"窪川,発,18:45#仁井田,発,18:51#六反地,発,18:54#影野,発,18:57#土佐久礼,発,19:10#安和,発,19:17#土佐新荘,発,19:20#須崎,発,19:30#大間,発,19:33#多ノ郷,発,19:35#吾桑,発,19:41#斗賀野,発,19:48#襟野々,発,19:51#佐川,発,19:54#西佐川,発,20:07#土佐加茂,発,20:12#岡花,発,20:15#日下,発,20:18#小村神社前,発,20:22#波川,発,20:25#伊野,発,20:30#枝川,発,20:33#朝倉,発,20:38#高知商業前,発,20:40#旭,発,20:44#円行寺口,発,20:47#入明,発,20:49#高知,着,20:51#"},
{"4762D":"伊野,発,21:33#枝川,発,21:36#朝倉,発,21:40#高知商業前,発,21:43#旭,発,21:46#円行寺口,発,21:48#入明,発,21:50#高知,発,22:01#薊野,発,22:04#土佐一宮,発,22:07#布師田,発,22:10#土佐大津,発,22:16#後免,発,22:20#土佐長岡,発,22:24#山田西町,発,22:27#土佐山田,着,22:28#"},
{"5210M":"琴平,発,6:05#善通寺,発,6:11#金蔵寺,発,6:14#多度津,発,6:20#讃岐塩屋,発,6:24#丸亀,発,6:27#宇多津,発,6:31#坂出,発,6:42#八十場,発,6:46#鴨川,発,6:53#讃岐府中,発,6:57#国分,発,7:00#端岡,発,7:03#鬼無,発,7:07#香西,発,7:10#高松,着,7:15#"},
{"5212M":"琴平,発,6:42#善通寺,発,6:48#金蔵寺,発,6:52#多度津,着,6:56#"},
{"5216M":"琴平,発,7:17#善通寺,発,7:24#金蔵寺,発,7:27#多度津,発,7:33#讃岐塩屋,発,7:37#丸亀,発,7:40#宇多津,発,7:44#坂出,発,8:00#八十場,発,8:04#鴨川,発,8:07#讃岐府中,発,8:10#国分,発,8:14#端岡,発,8:17#鬼無,発,8:21#香西,発,8:25#高松,着,8:29#"},
{"5218M":"琴平,発,7:38#善通寺,発,7:45#金蔵寺,発,7:49#多度津,発,8:05#讃岐塩屋,発,8:09#丸亀,発,8:13#宇多津,発,8:17#坂出,発,8:38#八十場,発,8:41#鴨川,発,8:44#讃岐府中,発,8:48#国分,発,8:51#端岡,発,8:54#鬼無,発,8:58#香西,発,9:01#高松,着,9:06#"},
{"5220M":"琴平,発,8:06#善通寺,発,8:12#金蔵寺,発,8:15#多度津,着,8:19#"},
{"5226M":"琴平,発,10:05#善通寺,発,10:11#金蔵寺,発,10:14#多度津,発,10:24#讃岐塩屋,発,10:27#丸亀,発,10:30#宇多津,発,10:34#坂出,発,10:39#八十場,発,10:43#鴨川,発,10:46#讃岐府中,発,10:49#国分,発,10:52#端岡,発,10:55#鬼無,発,10:59#香西,発,11:02#高松,着,11:07#"},
{"5228M":"琴平,発,10:18#善通寺,発,10:27#金蔵寺,発,10:32#多度津,着,10:37#"},
{"5232M":"琴平,発,12:13#善通寺,発,12:19#金蔵寺,発,12:22#多度津,発,12:30#讃岐塩屋,発,12:33#丸亀,発,12:36#宇多津,発,12:40#坂出,発,12:53#八十場,発,12:57#鴨川,発,13:00#讃岐府中,発,13:03#国分,発,13:06#端岡,発,13:09#鬼無,発,13:13#香西,発,13:17#高松,着,13:21#"},
{"5234M":"琴平,発,13:13#善通寺,発,13:19#金蔵寺,発,13:22#多度津,発,13:30#讃岐塩屋,発,13:33#丸亀,発,13:36#宇多津,発,13:40#坂出,発,13:53#八十場,発,13:57#鴨川,発,14:00#讃岐府中,発,14:03#国分,発,14:06#端岡,発,14:09#鬼無,発,14:13#香西,発,14:17#高松,着,14:21#"},
{"5236M":"琴平,発,14:13#善通寺,発,14:19#金蔵寺,発,14:22#多度津,発,14:30#讃岐塩屋,発,14:33#丸亀,発,14:36#宇多津,発,14:40#坂出,発,14:53#八十場,発,14:57#鴨川,発,15:00#讃岐府中,発,15:03#国分,発,15:06#端岡,発,15:09#鬼無,発,15:13#香西,発,15:17#高松,着,15:21#"},
{"5238M":"琴平,発,15:13#善通寺,発,15:19#金蔵寺,発,15:22#多度津,発,15:30#讃岐塩屋,発,15:33#丸亀,発,15:36#宇多津,発,15:40#坂出,発,15:53#八十場,発,15:57#鴨川,発,16:00#讃岐府中,発,16:03#国分,発,16:06#端岡,発,16:09#鬼無,発,16:13#香西,発,16:17#高松,着,16:21#"},
{"5240M":"琴平,発,15:32#善通寺,発,15:37#金蔵寺,発,15:41#多度津,発,15:47#讃岐塩屋,発,15:50#丸亀,発,15:53#宇多津,発,15:57#坂出,発,16:02#八十場,発,16:05#鴨川,発,16:09#讃岐府中,発,16:12#国分,発,16:15#端岡,発,16:18#鬼無,発,16:22#香西,発,16:26#高松,着,16:30#"},
{"5242M":"琴平,発,16:13#善通寺,発,16:19#金蔵寺,発,16:22#多度津,発,16:30#讃岐塩屋,発,16:33#丸亀,発,16:36#宇多津,発,16:40#坂出,発,16:53#八十場,発,16:57#鴨川,発,17:00#讃岐府中,発,17:03#国分,発,17:06#端岡,発,17:09#鬼無,発,17:13#香西,発,17:17#高松,着,17:21#"},
{"5244M":"琴平,発,16:41#善通寺,発,16:56#金蔵寺,発,16:59#多度津,発,17:09#讃岐塩屋,発,17:12#丸亀,発,17:15#宇多津,発,17:19#坂出,発,17:25#八十場,発,17:29#鴨川,発,17:32#讃岐府中,発,17:35#国分,発,17:38#端岡,発,17:41#鬼無,発,17:45#香西,発,17:48#高松,着,17:53#"},
{"5252M":"琴平,発,20:17#善通寺,発,20:23#金蔵寺,発,20:27#多度津,発,20:33#讃岐塩屋,発,20:36#丸亀,発,20:39#宇多津,発,20:42#坂出,発,20:47#端岡,発,20:57#高松,着,21:04#"},
{"5254M":"琴平,発,21:15#善通寺,発,21:21#金蔵寺,発,21:24#多度津,発,21:35#讃岐塩屋,発,21:38#丸亀,発,21:41#宇多津,発,21:45#坂出,発,21:57#八十場,発,22:01#鴨川,発,22:04#讃岐府中,発,22:08#国分,発,22:11#端岡,発,22:15#鬼無,発,22:19#香西,発,22:22#高松,着,22:27#"},
{"5260M":"琴平,発,22:34#善通寺,発,22:39#金蔵寺,発,22:42#多度津,着,22:46#"},
{"5812D":"高知,発,7:46#薊野,発,7:49#土佐一宮,発,7:54#布師田,発,7:57#土佐大津,発,8:00#後免,着,8:04#"},
{"5814D":"高知,発,8:30#薊野,発,8:33#土佐一宮,発,8:36#布師田,発,8:39#土佐大津,発,8:42#後免,着,8:46#"},
{"5816D":"高知,発,15:15#薊野,発,15:20#土佐一宮,発,15:24#布師田,発,15:27#土佐大津,発,15:34#後免,着,15:37#"},
{"5852D":"高知,発,9:15#薊野,発,9:19#土佐一宮,発,9:24#布師田,発,9:26#土佐大津,発,9:35#後免,着,9:39#"},
{"5854D":"高知,発,10:15#薊野,発,10:20#土佐一宮,発,10:24#布師田,発,10:27#土佐大津,発,10:34#後免,着,10:39#"},
{"5856D":"高知,発,11:15#薊野,発,11:20#土佐一宮,発,11:28#布師田,発,11:30#土佐大津,発,11:34#後免,着,11:39#"},
{"5858D":"高知,発,12:15#薊野,発,12:20#土佐一宮,発,12:27#布師田,発,12:30#土佐大津,発,12:34#後免,着,12:39#"},
{"5860D":"高知,発,13:15#薊野,発,13:20#土佐一宮,発,13:24#布師田,発,13:27#土佐大津,発,13:34#後免,着,13:38#"},
{"5862D":"高知,発,14:15#薊野,発,14:20#土佐一宮,発,14:24#布師田,発,14:27#土佐大津,発,14:34#後免,着,14:38#"},
{"5872D":"高知,発,19:05#薊野,発,19:09#土佐一宮,発,19:12#布師田,発,19:14#土佐大津,発,19:17#後免,着,19:21#"},
{"5874D":"高知,発,19:47#薊野,発,19:51#土佐一宮,発,19:56#布師田,発,19:59#土佐大津,発,20:02#後免,着,20:05#"},
{"5876D":"高知,発,20:15#薊野,発,20:18#土佐一宮,発,20:21#布師田,発,20:24#土佐大津,発,20:29#後免,着,20:33#"},
{"5880D":"高知,発,21:25#薊野,発,21:28#土佐一宮,発,21:31#布師田,発,21:34#土佐大津,発,21:43#後免,着,21:46#"},
{"5882D":"高知,発,22:36#薊野,発,22:40#土佐一宮,発,22:45#布師田,発,22:47#土佐大津,発,22:50#後免,着,22:54#"},
{"6222D":"琴平,発,8:43#善通寺,発,8:56#金蔵寺,発,9:00#多度津,着,9:04#"},
{"8022D":"大歩危,発,14:19#小歩危,発,14:38#阿波川口,発,15:01#阿波池田,発,15:25#坪尻,発,15:51#讃岐財田,発,16:15#琴平,発,16:59#善通寺,発,17:13#多度津,着,17:21#"},
{"8074D":"窪川,発,13:10#土佐久礼,発,13:50#安和,発,14:03#須崎,発,14:31#佐川,発,15:00#西佐川,発,15:09#伊野,発,15:32#朝倉,発,15:43#旭,発,16:02#高知,着,16:09#"},
{"8082D":"高知,発,12:00#土佐大津,発,12:09#後免,着,12:14#"},
{"213D":"土佐山田,発,7:27#山田西町,発,7:29#土佐長岡,発,7:32#後免,発,7:43#土佐大津,発,7:48#布師田,発,7:51#土佐一宮,発,7:54#薊野,発,7:58#高知,着,8:00#"},
{"217D":"土佐山田,発,8:15#山田西町,発,8:17#土佐長岡,発,8:20#後免,発,8:24#土佐大津,発,8:28#布師田,発,8:31#土佐一宮,発,8:36#薊野,発,8:39#高知,着,8:42#"},
{"219D":"土佐山田,発,8:57#山田西町,発,8:59#土佐長岡,発,9:02#後免,発,9:12#土佐大津,発,9:18#布師田,発,9:21#土佐一宮,発,9:24#薊野,発,9:27#高知,着,9:30#"},
{"231D":"土佐山田,発,13:33#山田西町,発,13:35#土佐長岡,発,13:38#後免,発,13:43#土佐大津,発,13:47#布師田,発,13:50#土佐一宮,発,13:53#薊野,発,13:56#高知,着,13:59#"},
{"715D":"土佐山田,発,6:35#山田西町,発,6:37#土佐長岡,発,6:40#後免,発,6:43#土佐大津,発,6:47#布師田,発,6:50#土佐一宮,発,6:53#薊野,発,6:56#高知,発,7:07#入明,発,7:10#円行寺口,発,7:12#旭,発,7:17#高知商業前,発,7:20#朝倉,発,7:29#枝川,発,7:34#伊野,発,7:53#波川,発,7:56#小村神社前,発,8:00#日下,発,8:03#岡花,発,8:06#土佐加茂,発,8:14#西佐川,発,8:20#佐川,発,8:26#襟野々,発,8:29#斗賀野,発,8:34#吾桑,発,8:40#多ノ郷,発,8:44#大間,発,8:46#須崎,着,8:49#"},
{"717D":"土佐山田,発,7:12#山田西町,発,7:14#土佐長岡,発,7:17#後免,発,7:21#土佐大津,発,7:26#布師田,発,7:29#土佐一宮,発,7:32#薊野,発,7:36#高知,発,7:45#入明,発,7:49#円行寺口,発,7:51#旭,発,7:57#高知商業前,発,8:00#朝倉,発,8:03#枝川,発,8:08#伊野,着,8:11#"},
{"719D":"高知,発,8:25#入明,発,8:28#円行寺口,発,8:30#旭,発,8:35#高知商業前,発,8:38#朝倉,発,8:42#枝川,発,8:47#伊野,発,8:51#波川,発,8:54#小村神社前,発,8:57#日下,発,9:03#岡花,発,9:06#土佐加茂,発,9:11#西佐川,発,9:17#佐川,発,9:21#襟野々,発,9:23#斗賀野,発,9:28#吾桑,発,9:35#多ノ郷,発,9:39#大間,発,9:41#須崎,着,9:44#"},
{"731D":"高知,発,13:06#入明,発,13:09#円行寺口,発,13:11#旭,発,13:15#高知商業前,発,13:18#朝倉,発,13:25#枝川,発,13:29#伊野,発,13:32#波川,発,13:35#小村神社前,発,13:38#日下,発,13:42#岡花,発,13:45#土佐加茂,発,13:51#西佐川,発,13:56#佐川,発,13:59#襟野々,発,14:02#斗賀野,発,14:05#吾桑,発,14:11#多ノ郷,発,14:15#大間,発,14:17#須崎,着,14:20#"},
{"733D":"高知,発,14:06#入明,発,14:09#円行寺口,発,14:11#旭,発,14:15#高知商業前,発,14:18#朝倉,発,14:25#枝川,発,14:29#伊野,発,14:32#波川,発,14:35#小村神社前,発,14:38#日下,発,14:56#岡花,発,14:59#土佐加茂,発,15:03#西佐川,発,15:09#佐川,発,15:12#襟野々,発,15:15#斗賀野,発,15:18#吾桑,発,15:24#多ノ郷,発,15:28#大間,発,15:30#須崎,着,15:32#"},
{"735D":"高知,発,15:06#入明,発,15:09#円行寺口,発,15:11#旭,発,15:15#高知商業前,発,15:18#朝倉,発,15:25#枝川,発,15:29#伊野,発,15:32#波川,発,15:35#小村神社前,発,15:38#日下,発,15:42#岡花,発,15:45#土佐加茂,発,15:49#西佐川,発,15:54#佐川,発,15:57#襟野々,発,16:00#斗賀野,発,16:06#吾桑,発,16:12#多ノ郷,発,16:16#大間,発,16:18#須崎,着,16:20#"},
{"739D":"高知,発,15:55#入明,発,15:58#円行寺口,発,16:00#旭,発,16:06#高知商業前,発,16:09#朝倉,発,16:12#枝川,発,16:16#伊野,発,16:19#波川,発,16:22#小村神社前,発,16:25#日下,発,16:32#岡花,発,16:35#土佐加茂,発,16:43#西佐川,発,16:48#佐川,発,16:51#襟野々,発,16:54#斗賀野,発,16:57#吾桑,発,17:03#多ノ郷,発,17:07#大間,発,17:09#須崎,着,17:12#"},
{"741D":"高知,発,16:27#入明,発,16:29#円行寺口,発,16:31#旭,発,16:34#高知商業前,発,16:36#朝倉,発,16:39#枝川,発,16:43#伊野,発,16:51#波川,発,16:54#小村神社前,発,16:57#日下,発,17:01#岡花,発,17:04#土佐加茂,発,17:07#西佐川,発,17:19#佐川,発,17:22#襟野々,発,17:25#斗賀野,発,17:28#吾桑,発,17:34#多ノ郷,発,17:38#大間,発,17:40#須崎,着,17:42#"},
{"745D":"高知,発,17:27#入明,発,17:31#円行寺口,発,17:33#旭,発,17:39#高知商業前,発,17:41#朝倉,発,17:44#枝川,発,17:48#伊野,発,17:54#波川,発,17:57#小村神社前,発,18:01#日下,発,18:18#岡花,発,18:22#土佐加茂,発,18:25#西佐川,発,18:31#佐川,発,18:34#襟野々,発,18:37#斗賀野,発,18:40#吾桑,発,18:46#多ノ郷,発,18:50#大間,発,18:52#須崎,発,18:55#土佐新荘,発,18:58#安和,発,19:02#土佐久礼,発,19:10#影野,発,19:31#六反地,発,19:33#仁井田,発,19:36#窪川,着,19:41#"},
{"747D":"土佐山田,発,17:33#山田西町,発,17:35#土佐長岡,発,17:38#後免,発,17:41#土佐大津,発,17:48#布師田,発,17:51#土佐一宮,発,17:56#薊野,発,18:00#高知,発,18:15#入明,発,18:18#円行寺口,発,18:20#旭,発,18:25#高知商業前,発,18:27#朝倉,発,18:36#枝川,発,18:40#伊野,発,18:44#波川,発,18:47#小村神社前,発,18:50#日下,発,18:53#岡花,発,18:56#土佐加茂,発,19:00#西佐川,発,19:05#佐川,発,19:09#襟野々,発,19:11#斗賀野,発,19:14#吾桑,発,19:20#多ノ郷,発,19:24#大間,発,19:26#須崎,着,19:29#"},
{"751D":"土佐山田,発,18:30#山田西町,発,18:32#土佐長岡,発,18:35#後免,発,18:38#土佐大津,発,18:44#布師田,発,18:47#土佐一宮,発,18:50#薊野,発,18:56#高知,発,19:06#入明,発,19:09#円行寺口,発,19:12#旭,発,19:17#高知商業前,発,19:20#朝倉,発,19:30#枝川,発,19:35#伊野,発,19:39#波川,発,19:42#小村神社前,発,19:45#日下,発,19:48#岡花,発,19:51#土佐加茂,発,19:55#西佐川,発,20:05#佐川,発,20:08#襟野々,発,20:11#斗賀野,発,20:14#吾桑,発,20:20#多ノ郷,発,20:24#大間,発,20:26#須崎,着,20:29#"},
{"753D":"土佐山田,発,19:23#山田西町,発,19:25#土佐長岡,発,19:28#後免,発,19:43#土佐大津,発,19:51#布師田,発,19:54#土佐一宮,発,19:56#薊野,発,19:59#高知,発,20:06#入明,発,20:08#円行寺口,発,20:11#旭,発,20:14#高知商業前,発,20:16#朝倉,発,20:21#枝川,発,20:26#伊野,発,20:30#波川,発,20:33#小村神社前,発,20:36#日下,発,20:39#岡花,発,20:42#土佐加茂,発,20:46#西佐川,発,20:51#佐川,発,20:54#襟野々,発,20:57#斗賀野,発,21:00#吾桑,発,21:06#多ノ郷,発,21:10#大間,発,21:12#須崎,着,21:15#"},
{"1213M":"高松,発,5:42#香西,発,5:46#鬼無,発,5:50#端岡,発,5:54#国分,発,5:57#讃岐府中,発,6:00#鴨川,発,6:04#八十場,発,6:07#坂出,発,6:25#宇多津,発,6:30#丸亀,発,6:33#讃岐塩屋,発,6:36#多度津,発,6:40#金蔵寺,発,6:45#善通寺,発,6:48#琴平,着,6:54#"},
{"1219M":"高松,発,7:10#香西,発,7:15#鬼無,発,7:19#端岡,発,7:23#国分,発,7:26#讃岐府中,発,7:30#鴨川,発,7:33#八十場,発,7:36#坂出,発,7:39#宇多津,発,7:51#丸亀,発,7:55#讃岐塩屋,発,7:58#多度津,発,8:10#金蔵寺,発,8:15#善通寺,発,8:18#琴平,着,8:24#"},
{"1221M":"高松,発,7:55#香西,発,8:00#鬼無,発,8:03#端岡,発,8:10#国分,発,8:14#讃岐府中,発,8:17#鴨川,発,8:20#八十場,発,8:23#坂出,発,8:26#宇多津,発,8:31#丸亀,発,8:34#讃岐塩屋,発,8:37#多度津,発,8:41#金蔵寺,発,8:48#善通寺,発,8:51#琴平,着,8:56#"},
{"1227M":"高松,発,9:25#香西,発,9:30#鬼無,発,9:34#端岡,発,9:50#国分,発,9:53#讃岐府中,発,9:56#鴨川,発,10:05#八十場,発,10:08#坂出,発,10:12#宇多津,発,10:17#丸亀,発,10:20#讃岐塩屋,発,10:23#多度津,発,10:28#金蔵寺,発,10:32#善通寺,発,10:35#琴平,着,10:41#"},
{"1243M":"高松,発,16:25#香西,発,16:29#鬼無,発,16:32#端岡,発,16:36#国分,発,16:39#讃岐府中,発,16:42#鴨川,発,16:45#八十場,発,16:47#坂出,発,16:51#宇多津,発,16:56#丸亀,発,16:59#讃岐塩屋,発,17:01#多度津,発,17:05#金蔵寺,発,17:10#善通寺,発,17:14#琴平,着,17:19#"},
{"1245M":"高松,発,17:25#香西,発,17:29#鬼無,発,17:32#端岡,発,17:36#国分,発,17:39#讃岐府中,発,17:42#鴨川,発,17:45#八十場,発,17:47#坂出,発,17:51#宇多津,発,17:56#丸亀,発,17:59#讃岐塩屋,発,18:02#多度津,発,18:05#金蔵寺,発,18:10#善通寺,発,18:13#琴平,着,18:18#"},
{"1247M":"高松,発,17:58#香西,発,18:03#鬼無,発,18:06#端岡,発,18:10#国分,発,18:13#讃岐府中,発,18:16#鴨川,発,18:23#八十場,発,18:25#坂出,発,18:29#宇多津,発,18:34#丸亀,発,18:37#讃岐塩屋,発,18:39#多度津,発,18:43#金蔵寺,発,18:48#善通寺,発,18:52#琴平,着,18:57#"},
{"1263M":"高松,発,22:08#香西,発,22:13#鬼無,発,22:16#端岡,発,22:20#国分,発,22:23#讃岐府中,発,22:26#鴨川,発,22:33#八十場,発,22:36#坂出,発,22:39#宇多津,発,22:45#丸亀,発,22:48#讃岐塩屋,発,22:51#多度津,着,22:55#"},
{"2001D":"高松,発,6:04#坂出,発,6:18#丸亀,発,6:25#多度津,発,6:30#善通寺,発,6:35#琴平,発,6:40#阿波池田,発,7:06#大歩危,発,7:24#大杉,発,7:44#土佐山田,発,8:04#後免,発,8:10#高知,発,8:20#旭,発,8:24#朝倉,発,8:28#伊野,発,8:33#佐川,発,8:47#須崎,発,9:01#土佐久礼,発,9:11#窪川,発,9:27#土佐佐賀,発,9:45#土佐上川口,発,9:53#土佐入野,発,9:57#中村,着,10:04#"},
{"2003D":"高松,発,8:25#坂出,発,8:40#丸亀,発,8:46#多度津,発,8:50#善通寺,発,8:55#琴平,発,9:01#阿波池田,発,9:24#大歩危,発,9:42#大杉,発,10:04#土佐山田,発,10:25#後免,発,10:30#高知,着,10:37#"},
{"2071D":"高知,発,9:51#伊野,発,10:02#佐川,発,10:15#須崎,発,10:29#土佐久礼,発,10:40#窪川,発,10:58#土佐佐賀,発,11:16#土佐入野,発,11:27#中村,着,11:33#"},
{"2073D":"高知,発,11:49#旭,発,11:53#朝倉,発,11:57#伊野,発,12:02#佐川,発,12:16#須崎,発,12:30#土佐久礼,発,12:41#窪川,発,12:58#土佐佐賀,発,13:16#土佐入野,発,13:27#中村,着,13:34#"},
{"2075D":"高知,発,13:49#旭,発,13:53#朝倉,発,13:57#伊野,発,14:02#佐川,発,14:17#須崎,発,14:31#土佐久礼,発,14:41#窪川,発,14:58#土佐佐賀,発,15:16#土佐上川口,発,15:24#土佐入野,発,15:29#中村,着,15:35#"},
{"2077D":"高知,発,15:49#旭,発,15:53#朝倉,発,15:57#伊野,発,16:02#佐川,発,16:16#須崎,発,16:30#土佐久礼,発,16:41#窪川,発,17:01#土佐佐賀,発,17:24#土佐入野,発,17:35#中村,着,17:41#"},
{"2079D":"高知,発,17:11#旭,発,17:16#朝倉,発,17:20#伊野,発,17:25#佐川,発,17:39#多ノ郷,発,17:51#須崎,発,17:55#土佐久礼,発,18:06#窪川,発,18:27#土佐佐賀,発,18:45#土佐入野,発,19:00#中村,着,19:06#"},
{"2081D":"高知,発,19:01#旭,発,19:07#朝倉,発,19:12#伊野,発,19:18#佐川,発,19:32#多ノ郷,発,19:44#須崎,発,19:49#土佐久礼,発,20:00#窪川,発,20:19#土佐佐賀,発,20:42#土佐入野,発,20:53#中村,着,20:59#"},
{"2083D":"高知,発,21:18#旭,発,21:23#朝倉,発,21:27#伊野,発,21:33#佐川,発,21:46#多ノ郷,発,21:58#須崎,発,22:02#土佐久礼,発,22:12#窪川,発,22:28#土佐佐賀,発,22:46#土佐入野,発,22:57#中村,着,23:04#"},
{"3215D":"土佐山田,発,7:42#山田西町,発,7:44#土佐長岡,発,7:47#後免,発,7:54#土佐大津,発,8:07#布師田,発,8:10#土佐一宮,発,8:16#薊野,発,8:20#高知,着,8:23#"},
{"3247D":"土佐山田,発,19:00#山田西町,発,19:02#土佐長岡,発,19:05#後免,発,19:08#土佐大津,発,19:17#布師田,発,19:20#土佐一宮,発,19:23#薊野,発,19:27#高知,着,19:29#"},
{"3259D":"土佐山田,発,20:50#山田西町,発,20:52#土佐長岡,発,20:55#後免,発,20:59#土佐大津,発,21:03#布師田,発,21:06#土佐一宮,発,21:08#薊野,発,21:12#高知,着,21:14#"},
{"3721D":"高知,発,9:34#入明,発,9:37#円行寺口,発,9:39#旭,発,9:42#高知商業前,発,9:44#朝倉,発,9:47#枝川,発,9:52#伊野,発,10:08#波川,発,10:11#小村神社前,発,10:15#日下,発,10:18#岡花,発,10:21#土佐加茂,発,10:25#西佐川,発,10:31#佐川,発,10:43#襟野々,発,10:45#斗賀野,発,10:49#吾桑,発,10:55#多ノ郷,発,10:59#大間,発,11:02#須崎,着,11:05#"},
{"3751D":"須崎,発,20:37#土佐新荘,発,20:40#安和,発,20:44#土佐久礼,発,20:52#影野,発,21:06#六反地,発,21:08#仁井田,発,21:11#窪川,着,21:16#"},
{"3757D":"土佐山田,発,21:23#山田西町,発,21:25#土佐長岡,発,21:28#後免,発,21:39#土佐大津,発,21:43#布師田,発,21:46#土佐一宮,発,21:49#薊野,発,21:51#高知,発,22:06#入明,発,22:09#円行寺口,発,22:12#旭,発,22:14#高知商業前,発,22:17#朝倉,発,22:20#枝川,発,22:24#伊野,発,22:28#波川,発,22:31#小村神社前,発,22:34#日下,発,22:37#岡花,発,22:40#土佐加茂,発,22:44#西佐川,発,22:50#佐川,発,22:53#襟野々,発,22:56#斗賀野,発,22:59#吾桑,発,23:05#多ノ郷,発,23:09#大間,発,23:11#須崎,着,23:13#"},
{"3759D":"高知,発,22:52#入明,発,22:55#円行寺口,発,22:57#旭,発,23:00#高知商業前,発,23:02#朝倉,発,23:05#枝川,発,23:10#伊野,着,23:12#"},
{"4211D":"阿波池田,発,5:33#三縄,発,5:38#祖谷口,発,5:43#阿波川口,発,5:49#小歩危,発,5:55#大歩危,発,6:02#土佐岩原,発,6:10#豊永,発,6:15#大田口,発,6:20#土佐穴内,発,6:24#大杉,発,6:31#土佐北川,発,6:38#角茂谷,発,6:41#繁藤,発,6:45#土佐山田,着,6:57#"},
{"4221D":"阿波池田,発,7:45#三縄,発,7:50#祖谷口,発,7:55#阿波川口,発,8:02#小歩危,発,8:08#大歩危,発,8:15#土佐岩原,発,8:23#豊永,発,8:28#大田口,発,8:38#土佐穴内,発,8:42#大杉,発,8:47#土佐北川,発,8:54#角茂谷,発,8:58#繁藤,発,9:01#新改,発,9:13#土佐山田,発,9:33#山田西町,発,9:35#土佐長岡,発,9:38#後免,発,9:43#土佐大津,発,9:47#布師田,発,9:50#土佐一宮,発,9:53#薊野,発,9:56#高知,着,9:59#"},
{"4223D":"琴平,発,6:58#塩入,発,7:05#黒川,発,7:10#讃岐財田,発,7:26#箸蔵,発,7:38#佃,発,7:43#阿波池田,着,7:48#"},
{"4225D":"阿波池田,発,12:11#三縄,発,12:19#祖谷口,発,12:24#阿波川口,発,12:28#小歩危,発,12:44#大歩危,着,12:50#"},
{"4227D":"多度津,発,11:39#金蔵寺,発,11:44#善通寺,発,11:57#琴平,発,12:03#塩入,発,12:10#黒川,発,12:14#讃岐財田,発,12:18#坪尻,発,12:34#箸蔵,発,12:38#佃,発,12:43#阿波池田,着,12:48#"},
{"4229D":"土佐山田,発,12:33#山田西町,発,12:35#土佐長岡,発,12:38#後免,発,12:43#土佐大津,発,12:47#布師田,発,12:50#土佐一宮,発,12:53#薊野,発,12:56#高知,着,12:59#"},
{"4233D":"土佐山田,発,14:33#山田西町,発,14:35#土佐長岡,発,14:38#後免,発,14:43#土佐大津,発,14:47#布師田,発,14:50#土佐一宮,発,14:53#薊野,発,14:56#高知,着,14:59#"},
{"4235D":"土佐山田,発,15:33#山田西町,発,15:35#土佐長岡,発,15:38#後免,発,15:43#土佐大津,発,15:47#布師田,発,15:50#土佐一宮,発,15:53#薊野,発,15:56#高知,着,15:59#"},
{"4237D":"阿波池田,発,13:49#三縄,発,13:54#祖谷口,発,13:59#阿波川口,発,14:03#小歩危,発,14:11#大歩危,発,14:22#土佐岩原,発,14:29#豊永,発,14:37#大田口,発,14:51#土佐穴内,発,14:54#大杉,発,15:19#土佐北川,発,15:26#角茂谷,発,15:30#繁藤,発,15:37#新改,発,15:48#土佐山田,発,16:03#山田西町,発,16:05#土佐長岡,発,16:08#後免,発,16:21#土佐大津,発,16:27#布師田,発,16:30#土佐一宮,発,16:38#薊野,発,16:41#高知,着,16:44#"},
{"4239D":"多度津,発,13:58#金蔵寺,発,14:03#善通寺,発,14:07#琴平,発,14:13#塩入,発,14:23#黒川,発,14:28#讃岐財田,発,14:39#坪尻,発,14:53#箸蔵,発,14:57#佃,発,15:02#阿波池田,着,15:07#"},
{"4241D":"土佐山田,発,16:30#山田西町,発,16:32#土佐長岡,発,16:35#後免,発,16:43#土佐大津,発,16:47#布師田,発,16:50#土佐一宮,発,16:53#薊野,発,16:56#高知,着,16:59#"},
{"4243D":"阿波池田,発,16:54#三縄,発,16:59#祖谷口,発,17:05#阿波川口,発,17:11#小歩危,発,17:17#大歩危,着,17:23#"},
{"4245D":"多度津,発,15:58#金蔵寺,発,16:03#善通寺,発,16:07#琴平,発,16:14#塩入,発,16:24#黒川,発,16:29#讃岐財田,発,16:37#坪尻,発,16:53#箸蔵,発,16:57#佃,発,17:02#阿波池田,着,17:07#"},
{"4249D":"阿波池田,発,17:48#三縄,発,17:53#祖谷口,発,17:58#阿波川口,発,18:02#小歩危,発,18:11#大歩危,発,18:19#土佐岩原,発,18:26#豊永,発,18:31#大田口,発,18:36#土佐穴内,発,18:40#大杉,発,18:45#土佐北川,発,18:52#角茂谷,発,18:56#繁藤,発,19:02#新改,発,19:14#土佐山田,着,19:21#"},
{"4251D":"琴平,発,18:20#塩入,発,18:27#黒川,発,18:32#讃岐財田,発,18:38#箸蔵,発,18:51#佃,発,18:56#阿波池田,着,19:01#"},
{"4253D":"阿波池田,発,19:10#三縄,発,19:15#祖谷口,発,19:20#阿波川口,発,19:24#小歩危,発,19:35#大歩危,着,19:42#"},
{"4255D":"琴平,発,19:46#塩入,発,19:54#黒川,発,19:58#讃岐財田,発,20:04#箸蔵,発,20:16#佃,発,20:21#阿波池田,着,20:26#"},
{"4257D":"土佐山田,発,19:47#山田西町,発,19:49#土佐長岡,発,19:52#後免,発,19:55#土佐大津,発,20:02#布師田,発,20:05#土佐一宮,発,20:08#薊野,発,20:11#高知,着,20:13#"},
{"4261D":"土佐山田,発,22:43#山田西町,発,22:45#土佐長岡,発,22:48#後免,発,22:54#土佐大津,発,22:58#布師田,発,23:01#土佐一宮,発,23:04#薊野,発,23:07#高知,着,23:10#"},
{"4263M":"多度津,発,23:03#金蔵寺,発,23:07#善通寺,発,23:11#琴平,着,23:16#"},
{"4711D":"高知,発,5:39#入明,発,5:42#円行寺口,発,5:45#旭,発,5:50#高知商業前,発,5:52#朝倉,発,5:55#枝川,発,5:59#伊野,発,6:02#波川,発,6:05#小村神社前,発,6:08#日下,発,6:18#岡花,発,6:21#土佐加茂,発,6:25#西佐川,発,6:34#佐川,発,6:38#襟野々,発,6:41#斗賀野,発,6:50#吾桑,発,6:56#多ノ郷,発,7:03#大間,発,7:05#須崎,発,7:12#土佐新荘,発,7:15#安和,発,7:19#土佐久礼,発,7:30#影野,発,7:48#六反地,発,7:51#仁井田,発,7:54#窪川,着,7:59#"},
{"4713D":"土佐山田,発,5:50#山田西町,発,5:52#土佐長岡,発,5:55#後免,発,6:08#土佐大津,発,6:15#布師田,発,6:18#土佐一宮,発,6:20#薊野,発,6:23#高知,発,6:31#入明,発,6:35#円行寺口,発,6:37#旭,発,6:40#高知商業前,発,6:43#朝倉,発,6:45#枝川,発,6:50#伊野,発,6:56#波川,発,6:59#小村神社前,発,7:02#日下,発,7:13#岡花,発,7:17#土佐加茂,発,7:21#西佐川,発,7:32#佐川,発,7:35#襟野々,発,7:39#斗賀野,発,7:42#吾桑,発,7:52#多ノ郷,発,7:57#大間,発,8:00#須崎,着,8:03#"},
{"4723D":"高知,発,10:27#入明,発,10:30#円行寺口,発,10:33#旭,発,10:36#高知商業前,発,10:38#朝倉,発,10:41#枝川,発,10:45#伊野,着,10:48#"},
{"4725D":"土佐山田,発,10:33#山田西町,発,10:35#土佐長岡,発,10:38#後免,発,10:43#土佐大津,発,10:47#布師田,発,10:50#土佐一宮,発,10:53#薊野,発,10:56#高知,発,11:06#入明,発,11:09#円行寺口,発,11:11#旭,発,11:16#高知商業前,発,11:18#朝倉,発,11:25#枝川,発,11:29#伊野,発,11:32#波川,発,11:35#小村神社前,発,11:39#日下,発,11:42#岡花,発,11:45#土佐加茂,発,11:49#西佐川,発,11:54#佐川,発,11:57#襟野々,発,12:00#斗賀野,発,12:03#吾桑,発,12:09#多ノ郷,発,12:13#大間,発,12:15#須崎,着,12:18#"},
{"4727D":"土佐山田,発,11:33#山田西町,発,11:35#土佐長岡,発,11:38#後免,発,11:43#土佐大津,発,11:47#布師田,発,11:50#土佐一宮,発,11:53#薊野,発,11:56#高知,発,12:06#入明,発,12:09#円行寺口,発,12:11#旭,発,12:15#高知商業前,発,12:18#朝倉,発,12:25#枝川,発,12:29#伊野,発,12:32#波川,発,12:35#小村神社前,発,12:38#日下,発,12:47#岡花,発,12:50#土佐加茂,発,13:00#西佐川,発,13:05#佐川,発,13:08#襟野々,発,13:11#斗賀野,発,13:14#吾桑,発,13:20#多ノ郷,発,13:24#大間,発,13:26#須崎,発,13:32#土佐新荘,発,13:35#安和,発,13:39#土佐久礼,発,13:47#影野,発,14:02#六反地,発,14:05#仁井田,発,14:08#窪川,着,14:12#"},
{"4729D":"高知,発,12:27#入明,発,12:29#円行寺口,発,12:31#旭,発,12:36#高知商業前,発,12:38#朝倉,発,12:41#枝川,発,12:45#伊野,着,12:48#"},
{"4735D":"須崎,発,16:43#土佐新荘,発,16:46#安和,発,16:50#土佐久礼,発,17:02#影野,発,17:26#六反地,発,17:29#仁井田,発,17:31#窪川,着,17:36#"},
{"4737D":"高知,発,15:27#入明,発,15:29#円行寺口,発,15:31#旭,発,15:36#高知商業前,発,15:38#朝倉,発,15:41#枝川,発,15:45#伊野,着,15:48#"},
{"4743D":"高知,発,16:50#入明,発,16:53#円行寺口,発,16:55#旭,発,17:01#高知商業前,発,17:03#朝倉,発,17:06#枝川,発,17:11#伊野,着,17:13#"},
{"4749D":"高知,発,18:36#入明,発,18:39#円行寺口,発,18:41#旭,発,18:44#高知商業前,発,18:46#朝倉,発,18:49#枝川,発,18:54#伊野,着,18:56#"},
{"4755D":"高知,発,21:06#入明,発,21:09#円行寺口,発,21:11#旭,発,21:14#高知商業前,発,21:16#朝倉,発,21:19#枝川,発,21:23#伊野,着,21:26#"},
{"5211M":"多度津,発,5:42#金蔵寺,発,5:47#善通寺,発,5:51#琴平,着,5:57#"},
{"5215M":"高松,発,6:12#香西,発,6:16#鬼無,発,6:20#端岡,発,6:24#国分,発,6:28#讃岐府中,発,6:31#鴨川,発,6:34#八十場,発,6:37#坂出,発,6:41#宇多津,発,6:46#丸亀,発,6:50#讃岐塩屋,発,6:53#多度津,発,6:58#金蔵寺,発,7:03#善通寺,発,7:06#琴平,着,7:12#"},
{"5217M":"多度津,発,7:42#金蔵寺,発,7:48#善通寺,発,7:52#琴平,着,7:57#"},
{"5223M":"高松,発,8:15#香西,発,8:20#鬼無,発,8:23#端岡,発,8:33#国分,発,8:37#讃岐府中,発,8:40#鴨川,発,8:43#八十場,発,8:46#坂出,発,8:50#宇多津,発,8:56#丸亀,発,8:59#讃岐塩屋,発,9:02#多度津,発,9:09#金蔵寺,発,9:14#善通寺,発,9:18#琴平,着,9:23#"},
{"5225M":"高松,発,8:57#香西,発,9:02#鬼無,発,9:05#端岡,発,9:14#国分,発,9:18#讃岐府中,発,9:21#鴨川,発,9:24#八十場,発,9:28#坂出,発,9:32#宇多津,発,9:37#丸亀,発,9:41#讃岐塩屋,発,9:44#多度津,発,9:50#金蔵寺,発,9:55#善通寺,発,9:59#琴平,着,10:04#"},
{"5229M":"高松,発,10:25#香西,発,10:31#鬼無,発,10:34#端岡,発,10:39#国分,発,10:42#讃岐府中,発,10:45#鴨川,発,10:53#八十場,発,10:56#坂出,発,11:00#宇多津,発,11:05#丸亀,発,11:08#讃岐塩屋,発,11:11#多度津,発,11:23#金蔵寺,発,11:28#善通寺,発,11:32#琴平,着,11:37#"},
{"5231M":"高松,発,11:25#香西,発,11:31#鬼無,発,11:34#端岡,発,11:39#国分,発,11:42#讃岐府中,発,11:45#鴨川,発,11:53#八十場,発,11:56#坂出,発,12:00#宇多津,発,12:05#丸亀,発,12:08#讃岐塩屋,発,12:11#多度津,発,12:17#金蔵寺,発,12:22#善通寺,発,12:26#琴平,着,12:32#"},
{"5233M":"高松,発,12:25#香西,発,12:31#鬼無,発,12:34#端岡,発,12:39#国分,発,12:42#讃岐府中,発,12:45#鴨川,発,12:53#八十場,発,12:56#坂出,発,13:00#宇多津,発,13:05#丸亀,発,13:08#讃岐塩屋,発,13:11#多度津,発,13:17#金蔵寺,発,13:22#善通寺,発,13:26#琴平,着,13:31#"},
{"5235M":"高松,発,13:25#香西,発,13:31#鬼無,発,13:34#端岡,発,13:39#国分,発,13:42#讃岐府中,発,13:45#鴨川,発,13:53#八十場,発,13:56#坂出,発,14:00#宇多津,発,14:05#丸亀,発,14:08#讃岐塩屋,発,14:11#多度津,発,14:17#金蔵寺,発,14:22#善通寺,発,14:26#琴平,着,14:32#"},
{"5237M":"多度津,発,14:58#金蔵寺,発,15:03#善通寺,発,15:07#琴平,着,15:12#"},
{"5239M":"高松,発,14:25#香西,発,14:31#鬼無,発,14:34#端岡,発,14:39#国分,発,14:42#讃岐府中,発,14:45#鴨川,発,14:53#八十場,発,14:56#坂出,発,15:00#宇多津,発,15:05#丸亀,発,15:08#讃岐塩屋,発,15:11#多度津,発,15:17#金蔵寺,発,15:22#善通寺,発,15:26#琴平,着,15:31#"},
{"5241M":"高松,発,15:25#香西,発,15:31#鬼無,発,15:34#端岡,発,15:39#国分,発,15:42#讃岐府中,発,15:45#鴨川,発,15:53#八十場,発,15:56#坂出,発,16:00#宇多津,発,16:05#丸亀,発,16:08#讃岐塩屋,発,16:11#多度津,発,16:17#金蔵寺,発,16:22#善通寺,発,16:26#琴平,着,16:33#"},
{"5249M":"高松,発,18:25#香西,発,18:31#鬼無,発,18:34#端岡,発,18:39#国分,発,18:42#讃岐府中,発,18:45#鴨川,発,18:53#八十場,発,18:56#坂出,発,19:00#宇多津,発,19:05#丸亀,発,19:08#讃岐塩屋,発,19:11#多度津,発,19:32#金蔵寺,発,19:36#善通寺,発,19:40#琴平,着,19:45#"},
{"5251M":"高松,発,19:13#端岡,発,19:21#鴨川,発,19:28#坂出,発,19:33#宇多津,発,19:38#丸亀,発,19:42#讃岐塩屋,発,19:44#多度津,発,19:54#金蔵寺,発,19:59#善通寺,発,20:03#琴平,着,20:09#"},
{"5253M":"高松,発,19:53#香西,発,19:58#鬼無,発,20:02#端岡,発,20:06#国分,発,20:09#讃岐府中,発,20:12#鴨川,発,20:15#八十場,発,20:18#坂出,発,20:27#宇多津,発,20:32#丸亀,発,20:35#讃岐塩屋,発,20:38#多度津,発,20:47#金蔵寺,発,20:52#善通寺,発,20:56#琴平,着,21:01#"},
{"5255M":"高松,発,20:25#香西,発,20:29#鬼無,発,20:33#端岡,発,20:37#国分,発,20:40#讃岐府中,発,20:43#鴨川,発,20:47#八十場,発,20:50#坂出,発,21:00#宇多津,発,21:06#丸亀,発,21:10#讃岐塩屋,発,21:13#多度津,発,21:18#金蔵寺,発,21:24#善通寺,発,21:28#琴平,着,21:33#"},
{"5257M":"高松,発,21:20#香西,発,21:25#鬼無,発,21:28#端岡,発,21:36#国分,発,21:39#讃岐府中,発,21:42#鴨川,発,21:45#八十場,発,21:48#坂出,発,21:52#宇多津,発,21:57#丸亀,発,22:01#讃岐塩屋,発,22:03#多度津,発,22:08#金蔵寺,発,22:13#善通寺,発,22:17#琴平,着,22:23#"},
{"5811D":"後免,発,8:39#土佐大津,発,8:43#布師田,発,8:46#土佐一宮,発,8:49#薊野,発,8:52#高知,着,8:55#"},
{"5813D":"後免,発,15:59#土佐大津,発,16:03#布師田,発,16:06#土佐一宮,発,16:09#薊野,発,16:19#高知,着,16:22#"},
{"5815D":"後免,発,17:05#土佐大津,発,17:09#布師田,発,17:12#土佐一宮,発,17:17#薊野,発,17:21#高知,着,17:24#"},
{"5817D":"後免,発,18:17#土佐大津,発,18:21#布師田,発,18:24#土佐一宮,発,18:26#薊野,発,18:30#高知,着,18:32#"},
{"5843D":"後免,発,7:08#土佐大津,発,7:13#布師田,発,7:16#土佐一宮,発,7:19#薊野,発,7:22#高知,着,7:25#"},
{"5853D":"後免,発,10:03#土佐大津,発,10:07#布師田,発,10:11#土佐一宮,発,10:17#薊野,発,10:20#高知,着,10:24#"},
{"5855D":"後免,発,11:03#土佐大津,発,11:07#布師田,発,11:11#土佐一宮,発,11:17#薊野,発,11:20#高知,着,11:24#"},
{"5859D":"後免,発,12:03#土佐大津,発,12:07#布師田,発,12:11#土佐一宮,発,12:17#薊野,発,12:20#高知,着,12:24#"},
{"5861D":"後免,発,13:03#土佐大津,発,13:07#布師田,発,13:11#土佐一宮,発,13:17#薊野,発,13:20#高知,着,13:24#"},
{"5865D":"後免,発,14:03#土佐大津,発,14:07#布師田,発,14:11#土佐一宮,発,14:17#薊野,発,14:20#高知,着,14:24#"},
{"5869D":"後免,発,15:03#土佐大津,発,15:07#布師田,発,15:11#土佐一宮,発,15:17#薊野,発,15:20#高知,着,15:23#"},
{"5881D":"後免,発,18:59#土佐大津,発,19:04#布師田,発,19:07#土佐一宮,発,19:12#薊野,発,19:15#高知,着,19:17#"},
{"5885D":"後免,発,20:25#土佐大津,発,20:29#布師田,発,20:32#土佐一宮,発,20:42#薊野,発,20:46#高知,着,20:49#"},
{"5889D":"後免,発,22:12#土佐大津,発,22:16#布師田,発,22:19#土佐一宮,発,22:22#薊野,発,22:25#高知,着,22:28#"},
{"6219D":"多度津,発,8:20#金蔵寺,発,8:24#善通寺,発,8:28#琴平,着,8:33#"},
{"8021D":"多度津,発,10:19#善通寺,発,10:26#琴平,発,10:48#讃岐財田,発,11:11#坪尻,発,11:34#阿波池田,発,11:55#阿波川口,発,12:14#大歩危,着,12:34#"},
{"8031M":"高松,発,8:02#多度津,発,8:26#善通寺,発,8:33#琴平,着,8:39#"},
{"8073D":"高知,発,10:02#旭,発,10:16#伊野,発,10:31#日下,発,10:50#土佐加茂,発,11:08#吾桑,発,11:31#安和,発,11:56#土佐久礼,発,12:11#窪川,着,12:32#"},
{"8083D":"後免,発,17:25#土佐一宮,発,17:43#薊野,発,17:53#高知,着,17:57#"},
{"310D":"徳島,発,5:51#佐古,発,5:54#吉成,発,6:00#勝瑞,発,6:03#池谷,発,6:07#板東,発,6:10#阿波川端,発,6:14#板野,発,6:18#阿波大宮,発,6:24#讃岐相生,発,6:31#引田,発,6:35#讃岐白鳥,発,6:40#三本松,発,6:47#丹生,発,6:51#鶴羽,発,6:55#讃岐津田,発,6:59#神前,発,7:04#造田,発,7:10#オレンジタウン,発,7:14#志度,発,7:22#讃岐牟礼,発,7:25#八栗口,発,7:28#古高松南,発,7:31#屋島,発,7:34#木太町,発,7:38#栗林,発,7:41#栗林公園北口,発,7:44#昭和町,発,7:47#高松,着,7:50#"},
{"312D":"徳島,発,6:09#佐古,発,6:12#吉成,発,6:18#勝瑞,発,6:20#池谷,発,6:24#板東,発,6:28#阿波川端,発,6:32#板野,発,6:36#阿波大宮,発,6:42#讃岐相生,発,6:48#引田,発,6:53#讃岐白鳥,発,6:58#三本松,発,7:03#丹生,発,7:07#鶴羽,発,7:12#讃岐津田,発,7:16#神前,発,7:21#造田,発,7:27#オレンジタウン,発,7:33#志度,発,7:37#讃岐牟礼,発,7:41#八栗口,発,7:44#古高松南,発,7:47#屋島,発,7:51#木太町,発,7:55#栗林,発,8:00#栗林公園北口,発,8:03#昭和町,発,8:06#高松,着,8:09#"},
{"316D":"引田,発,7:09#讃岐白鳥,発,7:15#三本松,発,7:20#丹生,発,7:26#鶴羽,発,7:35#讃岐津田,発,7:52#神前,発,7:59#造田,発,8:05#オレンジタウン,発,8:10#志度,発,8:16#讃岐牟礼,発,8:21#八栗口,発,8:24#古高松南,発,8:27#屋島,発,8:33#木太町,発,8:38#栗林,発,8:43#栗林公園北口,発,8:46#昭和町,発,8:49#高松,着,8:53#"},
{"356D":"徳島,発,16:26#佐古,発,16:29#吉成,発,16:35#勝瑞,発,16:38#池谷,発,16:43#板東,発,16:47#阿波川端,発,16:51#板野,発,17:01#阿波大宮,発,17:08#讃岐相生,発,17:14#引田,発,17:25#讃岐白鳥,発,17:30#三本松,発,17:35#丹生,発,17:46#鶴羽,発,17:51#讃岐津田,発,17:56#神前,発,18:01#造田,発,18:12#オレンジタウン,発,18:17#志度,発,18:26#讃岐牟礼,発,18:31#八栗口,発,18:37#古高松南,発,18:40#屋島,発,18:44#木太町,発,18:48#栗林,発,18:52#栗林公園北口,発,18:54#昭和町,発,18:58#高松,着,19:01#"},
{"358D":"徳島,発,17:26#佐古,発,17:29#吉成,発,17:35#勝瑞,発,17:38#池谷,発,17:43#板東,発,17:47#阿波川端,発,17:51#板野,着,17:53#"},
{"362D":"徳島,発,18:26#佐古,発,18:29#吉成,発,18:35#勝瑞,発,18:38#池谷,発,18:43#板東,発,18:47#阿波川端,発,18:51#板野,発,19:02#阿波大宮,発,19:11#讃岐相生,発,19:22#引田,着,19:26#"},
{"364D":"徳島,発,19:27#佐古,発,19:30#吉成,発,19:36#勝瑞,発,19:39#池谷,発,19:43#板東,発,19:47#阿波川端,発,19:51#板野,着,19:54#"},
{"366D":"引田,発,19:35#讃岐白鳥,発,19:39#三本松,発,19:45#丹生,発,19:50#鶴羽,発,19:54#讃岐津田,発,20:13#神前,発,20:18#造田,発,20:21#オレンジタウン,発,20:25#志度,発,20:29#讃岐牟礼,発,20:33#八栗口,発,20:40#古高松南,発,20:42#屋島,発,20:45#木太町,発,20:49#栗林,発,20:53#栗林公園北口,発,20:55#昭和町,発,20:58#高松,着,21:01#"},
{"372D":"引田,発,20:35#讃岐白鳥,発,20:40#三本松,発,20:47#丹生,発,20:56#鶴羽,発,21:00#讃岐津田,発,21:13#神前,発,21:18#造田,発,21:21#オレンジタウン,発,21:24#志度,発,21:32#讃岐牟礼,発,21:35#八栗口,発,21:38#古高松南,発,21:40#屋島,発,21:43#木太町,発,21:47#栗林,発,21:51#栗林公園北口,発,21:53#昭和町,発,21:56#高松,着,21:59#"},
{"3002D":"徳島,発,5:41#勝瑞,発,5:48#池谷,発,5:52#板野,発,5:59#引田,発,6:10#讃岐白鳥,発,6:14#三本松,発,6:17#讃岐津田,発,6:26#オレンジタウン,発,6:33#志度,発,6:38#屋島,発,6:45#栗林,発,6:50#高松,着,6:55#"},
{"3004D":"徳島,発,6:58#勝瑞,発,7:09#池谷,発,7:13#板野,発,7:20#引田,発,7:31#讃岐白鳥,発,7:35#三本松,発,7:39#讃岐津田,発,7:47#オレンジタウン,発,7:54#志度,発,7:58#屋島,発,8:04#栗林,発,8:08#高松,着,8:13#"},
{"3006D":"徳島,発,8:24#勝瑞,発,8:32#池谷,発,8:36#板野,発,8:42#讃岐白鳥,発,8:55#三本松,発,8:59#志度,発,9:14#屋島,発,9:20#栗林,発,9:25#高松,着,9:31#"},
{"3008D":"徳島,発,9:24#池谷,発,9:33#板野,発,9:39#引田,発,9:51#三本松,発,9:58#志度,発,10:14#屋島,発,10:20#栗林,発,10:25#高松,着,10:30#"},
{"3010D":"徳島,発,10:24#池谷,発,10:33#板野,発,10:39#引田,発,10:51#三本松,発,10:58#志度,発,11:14#屋島,発,11:20#栗林,発,11:25#高松,着,11:30#"},
{"3012D":"徳島,発,11:24#池谷,発,11:33#板野,発,11:39#引田,発,11:51#三本松,発,11:58#志度,発,12:14#屋島,発,12:20#栗林,発,12:25#高松,着,12:30#"},
{"3014D":"徳島,発,12:24#池谷,発,12:33#板野,発,12:39#引田,発,12:51#三本松,発,12:58#志度,発,13:14#屋島,発,13:20#栗林,発,13:25#高松,着,13:30#"},
{"3016D":"徳島,発,13:24#池谷,発,13:33#板野,発,13:39#引田,発,13:51#三本松,発,13:58#志度,発,14:14#屋島,発,14:20#栗林,発,14:25#高松,着,14:30#"},
{"3018D":"徳島,発,14:24#池谷,発,14:33#板野,発,14:39#引田,発,14:51#三本松,発,14:58#志度,発,15:14#屋島,発,15:20#栗林,発,15:25#高松,着,15:30#"},
{"3020D":"徳島,発,15:24#池谷,発,15:33#板野,発,15:39#引田,発,15:51#三本松,発,15:58#志度,発,16:14#屋島,発,16:20#栗林,発,16:25#高松,着,16:30#"},
{"3022D":"徳島,発,16:24#池谷,発,16:33#板野,発,16:39#引田,発,16:51#三本松,発,16:58#志度,発,17:14#屋島,発,17:20#栗林,発,17:25#高松,着,17:30#"},
{"3024D":"徳島,発,17:24#池谷,発,17:33#板野,発,17:39#引田,発,17:51#三本松,発,17:58#志度,発,18:14#屋島,発,18:20#栗林,発,18:25#高松,着,18:30#"},
{"3026D":"徳島,発,18:24#池谷,発,18:33#板野,発,18:39#引田,発,18:51#三本松,発,18:58#オレンジタウン,発,19:11#志度,発,19:14#屋島,発,19:20#栗林,発,19:25#高松,着,19:30#"},
{"3028D":"徳島,発,19:24#勝瑞,発,19:31#板野,発,19:40#引田,発,19:52#讃岐白鳥,発,19:56#三本松,発,20:00#讃岐津田,発,20:08#志度,発,20:17#屋島,発,20:23#栗林,発,20:27#高松,着,20:33#"},
{"3030D":"徳島,発,20:27#勝瑞,発,20:34#板野,発,20:42#引田,発,20:54#三本松,発,21:01#志度,発,21:17#屋島,発,21:25#栗林,発,21:30#高松,着,21:35#"},
{"4302D":"オレンジタウン,発,5:26#志度,発,5:30#讃岐牟礼,発,5:33#八栗口,発,5:36#古高松南,発,5:38#屋島,発,5:41#木太町,発,5:45#栗林,発,5:48#栗林公園北口,発,5:51#昭和町,発,5:53#高松,着,5:56#"},
{"4304D":"オレンジタウン,発,6:04#志度,発,6:08#讃岐牟礼,発,6:12#八栗口,発,6:15#古高松南,発,6:18#屋島,発,6:22#木太町,発,6:26#栗林,発,6:30#栗林公園北口,発,6:32#昭和町,発,6:35#高松,着,6:38#"},
{"4314D":"徳島,発,6:45#佐古,発,6:49#吉成,発,6:55#勝瑞,発,7:00#池谷,発,7:19#板東,発,7:27#阿波川端,発,7:30#板野,着,7:33#"},
{"4318D":"引田,発,7:50#讃岐白鳥,発,7:56#三本松,発,8:00#丹生,発,8:05#鶴羽,発,8:11#讃岐津田,発,8:16#神前,発,8:22#造田,発,8:25#オレンジタウン,発,8:29#志度,発,8:39#讃岐牟礼,発,8:44#八栗口,発,8:47#古高松南,発,8:50#屋島,発,8:52#木太町,発,8:56#栗林,発,9:00#栗林公園北口,発,9:03#昭和町,発,9:06#高松,着,9:09#"},
{"4322D":"徳島,発,8:45#佐古,発,8:51#吉成,発,8:56#勝瑞,発,8:59#池谷,発,9:03#板東,発,9:07#阿波川端,発,9:11#板野,着,9:14#"},
{"4324D":"引田,発,9:25#讃岐白鳥,発,9:30#三本松,発,9:35#丹生,発,9:46#鶴羽,発,9:51#讃岐津田,発,9:56#神前,発,10:01#造田,発,10:12#オレンジタウン,発,10:17#志度,発,10:26#讃岐牟礼,発,10:31#八栗口,発,10:37#古高松南,発,10:40#屋島,発,10:44#木太町,発,10:48#栗林,発,10:52#栗林公園北口,発,10:54#昭和町,発,10:58#高松,着,11:01#"},
{"4326D":"徳島,発,10:26#佐古,発,10:29#吉成,発,10:35#勝瑞,発,10:38#池谷,発,10:43#板東,発,10:47#阿波川端,発,10:51#板野,着,10:53#"},
{"4328D":"オレンジタウン,発,10:56#志度,発,11:00#讃岐牟礼,発,11:04#八栗口,発,11:07#古高松南,発,11:10#屋島,発,11:22#木太町,発,11:26#栗林,発,11:29#栗林公園北口,発,11:31#昭和町,発,11:34#高松,着,11:37#"},
{"4330D":"引田,発,10:25#讃岐白鳥,発,10:30#三本松,発,10:35#丹生,発,10:46#鶴羽,発,10:51#讃岐津田,発,10:56#神前,発,11:01#造田,発,11:12#オレンジタウン,発,11:17#志度,発,11:26#讃岐牟礼,発,11:31#八栗口,発,11:37#古高松南,発,11:40#屋島,発,11:44#木太町,発,11:48#栗林,発,11:52#栗林公園北口,発,11:54#昭和町,発,11:58#高松,着,12:01#"},
{"4332D":"引田,発,11:25#讃岐白鳥,発,11:30#三本松,発,11:35#丹生,発,11:46#鶴羽,発,11:51#讃岐津田,発,11:56#神前,発,12:01#造田,発,12:12#オレンジタウン,発,12:17#志度,発,12:26#讃岐牟礼,発,12:31#八栗口,発,12:37#古高松南,発,12:40#屋島,発,12:44#木太町,発,12:48#栗林,発,12:52#栗林公園北口,発,12:54#昭和町,発,12:58#高松,着,13:01#"},
{"4334D":"徳島,発,11:26#佐古,発,11:29#吉成,発,11:35#勝瑞,発,11:38#池谷,発,11:43#板東,発,11:47#阿波川端,発,11:51#板野,着,11:53#"},
{"4336D":"オレンジタウン,発,12:56#志度,発,13:00#讃岐牟礼,発,13:04#八栗口,発,13:07#古高松南,発,13:10#屋島,発,13:22#木太町,発,13:26#栗林,発,13:29#栗林公園北口,発,13:31#昭和町,発,13:34#高松,着,13:37#"},
{"4338D":"引田,発,12:25#讃岐白鳥,発,12:30#三本松,発,12:35#丹生,発,12:46#鶴羽,発,12:51#讃岐津田,発,12:56#神前,発,13:01#造田,発,13:12#オレンジタウン,発,13:17#志度,発,13:26#讃岐牟礼,発,13:31#八栗口,発,13:37#古高松南,発,13:40#屋島,発,13:44#木太町,発,13:48#栗林,発,13:52#栗林公園北口,発,13:54#昭和町,発,13:58#高松,着,14:01#"},
{"4340D":"徳島,発,12:26#佐古,発,12:29#吉成,発,12:35#勝瑞,発,12:38#池谷,発,12:43#板東,発,12:47#阿波川端,発,12:51#板野,発,13:01#阿波大宮,発,13:08#讃岐相生,発,13:14#引田,発,13:25#讃岐白鳥,発,13:30#三本松,発,13:35#丹生,発,13:46#鶴羽,発,13:51#讃岐津田,発,13:56#神前,発,14:01#造田,発,14:12#オレンジタウン,発,14:17#志度,発,14:26#讃岐牟礼,発,14:31#八栗口,発,14:37#古高松南,発,14:40#屋島,発,14:44#木太町,発,14:48#栗林,発,14:52#栗林公園北口,発,14:54#昭和町,発,14:58#高松,着,15:01#"},
{"4342D":"徳島,発,14:26#佐古,発,14:29#吉成,発,14:35#勝瑞,発,14:38#池谷,発,14:43#板東,発,14:47#阿波川端,発,14:51#板野,着,14:53#"},
{"4344D":"オレンジタウン,発,14:56#志度,発,15:00#讃岐牟礼,発,15:04#八栗口,発,15:07#古高松南,発,15:10#屋島,発,15:22#木太町,発,15:26#栗林,発,15:29#栗林公園北口,発,15:31#昭和町,発,15:34#高松,着,15:37#"},
{"4346D":"三本松,発,14:35#丹生,発,14:46#鶴羽,発,14:51#讃岐津田,発,14:56#神前,発,15:01#造田,発,15:12#オレンジタウン,発,15:17#志度,発,15:26#讃岐牟礼,発,15:31#八栗口,発,15:37#古高松南,発,15:40#屋島,発,15:44#木太町,発,15:48#栗林,発,15:52#栗林公園北口,発,15:54#昭和町,発,15:58#高松,着,16:01#"},
{"4348D":"引田,発,15:25#讃岐白鳥,発,15:30#三本松,発,15:35#丹生,発,15:46#鶴羽,発,15:51#讃岐津田,発,15:56#神前,発,16:01#造田,発,16:12#オレンジタウン,発,16:17#志度,発,16:26#讃岐牟礼,発,16:31#八栗口,発,16:37#古高松南,発,16:40#屋島,発,16:44#木太町,発,16:48#栗林,発,16:52#栗林公園北口,発,16:54#昭和町,発,16:58#高松,着,17:01#"},
{"4350D":"徳島,発,15:26#佐古,発,15:29#吉成,発,15:35#勝瑞,発,15:38#池谷,発,15:43#板東,発,15:47#阿波川端,発,15:51#板野,着,15:53#"},
{"4352D":"オレンジタウン,発,16:56#志度,発,17:00#讃岐牟礼,発,17:04#八栗口,発,17:07#古高松南,発,17:10#屋島,発,17:22#木太町,発,17:26#栗林,発,17:29#栗林公園北口,発,17:31#昭和町,発,17:34#高松,着,17:37#"},
{"4354D":"引田,発,16:25#讃岐白鳥,発,16:30#三本松,発,16:35#丹生,発,16:46#鶴羽,発,16:51#讃岐津田,発,16:56#神前,発,17:01#造田,発,17:12#オレンジタウン,発,17:17#志度,発,17:26#讃岐牟礼,発,17:31#八栗口,発,17:37#古高松南,発,17:40#屋島,発,17:44#木太町,発,17:48#栗林,発,17:52#栗林公園北口,発,17:54#昭和町,発,17:58#高松,着,18:01#"},
{"4360D":"引田,発,18:25#讃岐白鳥,発,18:30#三本松,発,18:35#丹生,発,18:46#鶴羽,発,18:51#讃岐津田,発,19:09#神前,発,19:14#造田,発,19:22#オレンジタウン,発,19:30#志度,発,19:34#讃岐牟礼,発,19:37#八栗口,発,19:40#古高松南,発,19:42#屋島,発,19:45#木太町,発,19:49#栗林,発,19:53#栗林公園北口,発,19:55#昭和町,発,19:58#高松,着,20:01#"},
{"4368D":"徳島,発,20:58#佐古,発,21:05#吉成,発,21:11#勝瑞,発,21:15#池谷,発,21:19#板東,発,21:23#阿波川端,発,21:26#板野,着,21:29#"},
{"4370D":"オレンジタウン,発,20:59#志度,発,21:02#讃岐牟礼,発,21:06#八栗口,発,21:08#古高松南,発,21:11#屋島,発,21:14#木太町,発,21:17#栗林,発,21:21#栗林公園北口,発,21:23#昭和町,発,21:26#高松,着,21:29#"},
{"4374D":"引田,発,21:25#讃岐白鳥,発,21:30#三本松,発,21:35#丹生,発,21:47#鶴羽,発,21:55#讃岐津田,発,21:59#神前,発,22:05#造田,発,22:08#オレンジタウン,発,22:16#志度,発,22:19#讃岐牟礼,発,22:23#八栗口,発,22:26#古高松南,発,22:29#屋島,発,22:32#木太町,発,22:36#栗林,発,22:40#栗林公園北口,発,22:43#昭和町,発,22:46#高松,着,22:49#"},
{"4376D":"徳島,発,22:26#佐古,発,22:29#吉成,発,22:35#勝瑞,発,22:38#池谷,発,22:44#板東,発,22:48#阿波川端,発,22:52#板野,着,22:56#"},
{"5306D":"引田,発,5:43#讃岐白鳥,発,5:49#三本松,発,5:53#丹生,発,5:58#鶴羽,発,6:03#讃岐津田,発,6:08#神前,発,6:13#造田,発,6:18#オレンジタウン,発,6:22#志度,発,6:27#讃岐牟礼,発,6:31#八栗口,発,6:34#古高松南,発,6:37#屋島,発,6:47#木太町,発,6:51#栗林,発,6:55#栗林公園北口,発,6:58#昭和町,発,7:01#高松,着,7:05#"},
{"5308D":"三本松,発,6:21#丹生,発,6:26#鶴羽,発,6:33#讃岐津田,発,6:40#神前,発,6:45#造田,発,6:48#オレンジタウン,発,6:53#志度,発,6:58#讃岐牟礼,発,7:02#八栗口,発,7:08#古高松南,発,7:11#屋島,発,7:15#木太町,発,7:19#栗林,発,7:25#栗林公園北口,発,7:28#昭和町,発,7:31#高松,着,7:34#"},
{"5320D":"オレンジタウン,発,9:17#志度,発,9:26#讃岐牟礼,発,9:31#八栗口,発,9:37#古高松南,発,9:40#屋島,発,9:44#木太町,発,9:48#栗林,発,9:52#栗林公園北口,発,9:54#昭和町,発,9:58#高松,着,10:01#"},
{"305D":"高松,発,5:39#昭和町,発,5:42#栗林公園北口,発,5:45#栗林,発,5:48#木太町,発,5:52#屋島,発,5:55#古高松南,発,5:58#八栗口,発,6:02#讃岐牟礼,発,6:05#志度,発,6:09#オレンジタウン,発,6:13#造田,発,6:17#神前,発,6:20#讃岐津田,発,6:29#鶴羽,発,6:32#丹生,発,6:37#三本松,発,6:53#讃岐白鳥,発,6:58#引田,発,7:04#讃岐相生,発,7:07#阿波大宮,発,7:15#板野,発,7:20#阿波川端,発,7:23#板東,発,7:27#池谷,発,7:31#勝瑞,発,7:36#吉成,発,7:39#佐古,発,7:45#徳島,着,7:47#"},
{"353D":"板野,発,18:39#阿波川端,発,18:42#板東,発,18:47#池谷,発,18:50#勝瑞,発,18:55#吉成,発,18:58#佐古,発,19:04#徳島,着,19:07#"},
{"355D":"高松,発,17:42#昭和町,発,17:45#栗林公園北口,発,17:48#栗林,発,17:51#木太町,発,17:55#屋島,発,17:59#古高松南,発,18:02#八栗口,発,18:08#讃岐牟礼,発,18:10#志度,発,18:14#オレンジタウン,発,18:18#造田,発,18:22#神前,発,18:25#讃岐津田,発,18:31#鶴羽,発,18:41#丹生,発,18:46#三本松,発,18:58#讃岐白鳥,発,19:01#引田,発,19:18#讃岐相生,発,19:22#阿波大宮,発,19:29#板野,発,19:40#阿波川端,発,19:43#板東,発,19:47#池谷,発,19:50#勝瑞,発,19:55#吉成,発,19:58#佐古,発,20:04#徳島,着,20:07#"},
{"357D":"高松,発,18:14#昭和町,発,18:17#栗林公園北口,発,18:21#栗林,発,18:25#木太町,発,18:28#屋島,発,18:32#古高松南,発,18:34#八栗口,発,18:38#讃岐牟礼,発,18:40#志度,発,18:44#オレンジタウン,発,18:48#造田,発,18:51#神前,発,18:54#讃岐津田,発,19:05#鶴羽,発,19:09#丹生,発,19:14#三本松,発,19:18#讃岐白鳥,発,19:22#引田,着,19:27#"},
{"361D":"高松,発,19:14#昭和町,発,19:17#栗林公園北口,発,19:21#栗林,発,19:25#木太町,発,19:28#屋島,発,19:32#古高松南,発,19:34#八栗口,発,19:41#讃岐牟礼,発,19:43#志度,発,19:47#オレンジタウン,発,19:50#造田,発,19:54#神前,発,19:57#讃岐津田,発,20:08#鶴羽,発,20:11#丹生,発,20:16#三本松,発,20:21#讃岐白鳥,発,20:25#引田,着,20:29#"},
{"363D":"高松,発,19:42#昭和町,発,19:45#栗林公園北口,発,19:48#栗林,発,19:52#木太町,発,19:56#屋島,発,20:00#古高松南,発,20:03#八栗口,発,20:08#讃岐牟礼,発,20:10#志度,発,20:17#オレンジタウン,発,20:25#造田,発,20:38#神前,発,20:42#讃岐津田,発,20:47#鶴羽,発,20:51#丹生,発,20:56#三本松,発,21:01#讃岐白鳥,発,21:05#引田,着,21:10#"},
{"367D":"板野,発,20:42#阿波川端,発,20:46#板東,発,20:49#池谷,発,20:53#勝瑞,発,20:57#吉成,発,20:59#佐古,発,21:05#徳島,着,21:08#"},
{"371D":"高松,発,20:42#昭和町,発,20:45#栗林公園北口,発,20:49#栗林,発,20:52#木太町,発,20:56#屋島,発,21:00#古高松南,発,21:03#八栗口,発,21:10#讃岐牟礼,発,21:13#志度,発,21:17#オレンジタウン,発,21:24#造田,発,21:41#神前,発,21:44#讃岐津田,発,21:50#鶴羽,発,21:54#丹生,発,22:01#三本松,発,22:06#讃岐白鳥,発,22:10#引田,発,22:16#讃岐相生,発,22:20#阿波大宮,発,22:32#板野,発,22:38#阿波川端,発,22:42#板東,発,22:48#池谷,発,22:52#勝瑞,発,22:57#吉成,発,22:59#佐古,発,23:06#徳島,着,23:09#"},
{"3001D":"高松,発,6:10#栗林,発,6:16#屋島,発,6:21#志度,発,6:29#オレンジタウン,発,6:33#三本松,発,6:47#引田,発,6:53#板野,発,7:06#池谷,発,7:19#勝瑞,発,7:23#徳島,着,7:29#"},
{"3003D":"高松,発,7:05#栗林,発,7:10#屋島,発,7:15#志度,発,7:21#オレンジタウン,発,7:24#讃岐津田,発,7:31#三本松,発,7:40#讃岐白鳥,発,7:43#引田,発,7:47#板野,発,7:58#池谷,発,8:05#勝瑞,発,8:09#徳島,着,8:15#"},
{"3005D":"高松,発,8:24#栗林,発,8:29#屋島,発,8:33#志度,発,8:39#三本松,発,8:59#讃岐白鳥,発,9:02#引田,発,9:07#板野,発,9:18#池谷,発,9:24#勝瑞,発,9:30#徳島,着,9:36#"},
{"3007D":"高松,発,9:10#栗林,発,9:15#屋島,発,9:20#志度,発,9:27#三本松,発,9:43#引田,発,9:50#板野,発,10:01#池谷,発,10:08#徳島,着,10:16#"},
{"3009D":"高松,発,10:10#栗林,発,10:15#屋島,発,10:20#志度,発,10:27#三本松,発,10:43#引田,発,10:50#板野,発,11:01#池谷,発,11:08#徳島,着,11:16#"},
{"3011D":"高松,発,11:10#栗林,発,11:15#屋島,発,11:20#志度,発,11:27#三本松,発,11:43#引田,発,11:50#板野,発,12:01#池谷,発,12:08#徳島,着,12:16#"},
{"3013D":"高松,発,12:10#栗林,発,12:15#屋島,発,12:20#志度,発,12:27#三本松,発,12:43#引田,発,12:50#板野,発,13:01#池谷,発,13:08#徳島,着,13:16#"},
{"3015D":"高松,発,13:10#栗林,発,13:15#屋島,発,13:20#志度,発,13:27#三本松,発,13:43#引田,発,13:50#板野,発,14:01#池谷,発,14:08#徳島,着,14:16#"},
{"3017D":"高松,発,14:10#栗林,発,14:15#屋島,発,14:20#志度,発,14:27#三本松,発,14:43#引田,発,14:50#板野,発,15:01#池谷,発,15:08#徳島,着,15:16#"},
{"3019D":"高松,発,15:10#栗林,発,15:15#屋島,発,15:20#志度,発,15:27#三本松,発,15:43#引田,発,15:50#板野,発,16:01#池谷,発,16:08#徳島,着,16:16#"},
{"3021D":"高松,発,16:10#栗林,発,16:15#屋島,発,16:20#志度,発,16:27#三本松,発,16:43#引田,発,16:50#板野,発,17:01#池谷,発,17:08#徳島,着,17:17#"},
{"3023D":"高松,発,17:10#栗林,発,17:15#屋島,発,17:20#志度,発,17:27#三本松,発,17:43#引田,発,17:50#板野,発,18:01#池谷,発,18:08#徳島,着,18:17#"},
{"3025D":"高松,発,18:10#栗林,発,18:15#屋島,発,18:20#志度,発,18:27#オレンジタウン,発,18:30#三本松,発,18:43#讃岐白鳥,発,18:47#引田,発,18:51#板野,発,19:02#勝瑞,発,19:11#徳島,着,19:17#"},
{"3027D":"高松,発,19:10#栗林,発,19:15#屋島,発,19:20#志度,発,19:27#オレンジタウン,発,19:30#讃岐津田,発,19:37#三本松,発,19:46#引田,発,19:52#板野,発,20:03#池谷,発,20:09#勝瑞,発,20:13#徳島,着,20:20#"},
{"3029D":"高松,発,20:10#栗林,発,20:15#屋島,発,20:23#志度,発,20:29#讃岐津田,発,20:38#三本松,発,20:47#讃岐白鳥,発,20:50#引田,発,20:55#板野,発,21:06#池谷,発,21:12#徳島,着,21:20#"},
{"3031D":"高松,発,21:14#栗林,発,21:21#屋島,発,21:25#志度,発,21:32#讃岐津田,発,21:41#三本松,発,21:49#讃岐白鳥,発,21:53#引田,発,21:57#板野,発,22:08#池谷,発,22:14#勝瑞,発,22:18#徳島,着,22:24#"},
{"3033D":"高松,発,22:22#栗林,発,22:27#屋島,発,22:32#志度,発,22:39#オレンジタウン,発,22:43#讃岐津田,発,22:51#三本松,発,22:59#讃岐白鳥,発,23:03#引田,発,23:07#板野,発,23:19#勝瑞,発,23:27#徳島,着,23:34#"},
{"4301D":"板野,発,5:37#阿波川端,発,5:41#板東,発,5:45#池谷,発,5:53#勝瑞,発,5:57#吉成,発,6:00#佐古,発,6:06#徳島,着,6:08#"},
{"4303D":"板野,発,6:49#阿波川端,発,6:53#板東,発,6:58#池谷,発,7:04#勝瑞,発,7:10#吉成,発,7:13#佐古,発,7:20#徳島,着,7:23#"},
{"4307D":"高松,発,6:21#昭和町,発,6:24#栗林公園北口,発,6:27#栗林,発,6:33#木太町,発,6:36#屋島,発,6:45#古高松南,発,6:48#八栗口,発,6:52#讃岐牟礼,発,6:54#志度,発,6:59#オレンジタウン,発,7:03#造田,発,7:07#神前,発,7:11#讃岐津田,発,7:16#鶴羽,発,7:20#丹生,発,7:26#三本松,発,7:30#讃岐白鳥,発,7:35#引田,着,7:40#"},
{"4309D":"板野,発,8:11#阿波川端,発,8:14#板東,発,8:18#池谷,発,8:22#勝瑞,発,8:32#吉成,発,8:36#佐古,発,8:42#徳島,着,8:44#"},
{"4311D":"高松,発,6:41#昭和町,発,6:44#栗林公園北口,発,6:47#栗林,発,6:54#木太町,発,6:58#屋島,発,7:02#古高松南,発,7:05#八栗口,発,7:08#讃岐牟礼,発,7:11#志度,発,7:25#オレンジタウン,発,7:30#造田,発,7:34#神前,発,7:38#讃岐津田,発,7:47#鶴羽,発,7:51#丹生,発,7:56#三本松,発,8:02#讃岐白鳥,発,8:06#引田,発,8:19#讃岐相生,発,8:23#阿波大宮,発,8:31#板野,発,8:42#阿波川端,発,8:45#板東,発,8:49#池谷,発,8:52#勝瑞,発,8:59#吉成,発,9:01#佐古,発,9:09#徳島,着,9:11#"},
{"4313D":"高松,発,7:17#昭和町,発,7:20#栗林公園北口,発,7:23#栗林,発,7:26#木太町,発,7:29#屋島,発,7:36#古高松南,発,7:39#八栗口,発,7:48#讃岐牟礼,発,7:50#志度,発,7:57#オレンジタウン,発,8:01#造田,発,8:05#神前,発,8:09#讃岐津田,発,8:16#鶴羽,発,8:19#丹生,発,8:24#三本松,発,8:29#讃岐白鳥,発,8:33#引田,着,8:37#"},
{"4317D":"板野,発,9:39#阿波川端,発,9:42#板東,発,9:47#池谷,発,9:50#勝瑞,発,9:55#吉成,発,9:58#佐古,発,10:04#徳島,着,10:08#"},
{"4319D":"高松,発,8:33#昭和町,発,8:36#栗林公園北口,発,8:39#栗林,発,8:42#木太町,発,8:46#屋島,発,8:52#古高松南,発,8:55#八栗口,発,8:59#讃岐牟礼,発,9:01#志度,発,9:14#オレンジタウン,発,9:18#造田,発,9:22#神前,発,9:25#讃岐津田,発,9:31#鶴羽,発,9:41#丹生,発,9:46#三本松,発,9:58#讃岐白鳥,発,10:01#引田,着,10:06#"},
{"4321D":"高松,発,9:42#昭和町,発,9:45#栗林公園北口,発,9:48#栗林,発,9:51#木太町,発,9:55#屋島,発,9:59#古高松南,発,10:02#八栗口,発,10:08#讃岐牟礼,発,10:10#志度,発,10:14#オレンジタウン,発,10:18#造田,発,10:22#神前,発,10:25#讃岐津田,発,10:31#鶴羽,発,10:41#丹生,発,10:46#三本松,発,10:58#讃岐白鳥,発,11:01#引田,着,11:06#"},
{"4323D":"高松,発,10:14#昭和町,発,10:17#栗林公園北口,発,10:21#栗林,発,10:25#木太町,発,10:28#屋島,発,10:32#古高松南,発,10:34#八栗口,発,10:38#讃岐牟礼,発,10:40#志度,発,10:44#オレンジタウン,着,10:47#"},
{"4325D":"高松,発,10:42#昭和町,発,10:45#栗林公園北口,発,10:48#栗林,発,10:51#木太町,発,10:55#屋島,発,10:59#古高松南,発,11:02#八栗口,発,11:08#讃岐牟礼,発,11:10#志度,発,11:14#オレンジタウン,発,11:18#造田,発,11:22#神前,発,11:25#讃岐津田,発,11:31#鶴羽,発,11:41#丹生,発,11:46#三本松,発,11:58#讃岐白鳥,発,12:01#引田,着,12:06#"},
{"4327D":"板野,発,11:39#阿波川端,発,11:42#板東,発,11:47#池谷,発,11:50#勝瑞,発,11:55#吉成,発,11:59#佐古,発,12:05#徳島,着,12:08#"},
{"4329D":"板野,発,12:39#阿波川端,発,12:42#板東,発,12:47#池谷,発,12:50#勝瑞,発,12:55#吉成,発,12:58#佐古,発,13:04#徳島,着,13:07#"},
{"4331D":"高松,発,11:42#昭和町,発,11:45#栗林公園北口,発,11:48#栗林,発,11:51#木太町,発,11:55#屋島,発,11:59#古高松南,発,12:02#八栗口,発,12:08#讃岐牟礼,発,12:10#志度,発,12:14#オレンジタウン,発,12:18#造田,発,12:22#神前,発,12:25#讃岐津田,発,12:31#鶴羽,発,12:41#丹生,発,12:46#三本松,発,12:58#讃岐白鳥,発,13:01#引田,発,13:18#讃岐相生,発,13:22#阿波大宮,発,13:30#板野,発,13:39#阿波川端,発,13:42#板東,発,13:47#池谷,発,13:50#勝瑞,発,13:55#吉成,発,13:58#佐古,発,14:04#徳島,着,14:08#"},
{"4333D":"高松,発,12:14#昭和町,発,12:17#栗林公園北口,発,12:21#栗林,発,12:25#木太町,発,12:28#屋島,発,12:32#古高松南,発,12:34#八栗口,発,12:38#讃岐牟礼,発,12:40#志度,発,12:44#オレンジタウン,着,12:47#"},
{"4335D":"高松,発,12:42#昭和町,発,12:45#栗林公園北口,発,12:48#栗林,発,12:51#木太町,発,12:55#屋島,発,12:59#古高松南,発,13:02#八栗口,発,13:08#讃岐牟礼,発,13:10#志度,発,13:14#オレンジタウン,発,13:18#造田,発,13:22#神前,発,13:25#讃岐津田,発,13:31#鶴羽,発,13:41#丹生,発,13:46#三本松,着,13:50#"},
{"4337D":"高松,発,13:42#昭和町,発,13:45#栗林公園北口,発,13:48#栗林,発,13:51#木太町,発,13:55#屋島,発,13:59#古高松南,発,14:02#八栗口,発,14:08#讃岐牟礼,発,14:10#志度,発,14:14#オレンジタウン,発,14:18#造田,発,14:22#神前,発,14:25#讃岐津田,発,14:31#鶴羽,発,14:41#丹生,発,14:46#三本松,発,14:58#讃岐白鳥,発,15:01#引田,着,15:06#"},
{"4339D":"高松,発,14:14#昭和町,発,14:17#栗林公園北口,発,14:21#栗林,発,14:25#木太町,発,14:28#屋島,発,14:32#古高松南,発,14:34#八栗口,発,14:38#讃岐牟礼,発,14:40#志度,発,14:44#オレンジタウン,着,14:47#"},
{"4341D":"高松,発,14:42#昭和町,発,14:45#栗林公園北口,発,14:48#栗林,発,14:51#木太町,発,14:55#屋島,発,14:59#古高松南,発,15:02#八栗口,発,15:08#讃岐牟礼,発,15:10#志度,発,15:14#オレンジタウン,発,15:18#造田,発,15:22#神前,発,15:25#讃岐津田,発,15:31#鶴羽,発,15:41#丹生,発,15:46#三本松,発,15:58#讃岐白鳥,発,16:01#引田,着,16:06#"},
{"4343D":"板野,発,15:39#阿波川端,発,15:42#板東,発,15:47#池谷,発,15:50#勝瑞,発,15:55#吉成,発,15:58#佐古,発,16:04#徳島,着,16:08#"},
{"4345D":"板野,発,16:39#阿波川端,発,16:42#板東,発,16:47#池谷,発,16:50#勝瑞,発,16:55#吉成,発,16:58#佐古,発,17:05#徳島,着,17:08#"},
{"4347D":"引田,発,17:18#讃岐相生,発,17:22#阿波大宮,発,17:30#板野,発,17:39#阿波川端,発,17:42#板東,発,17:47#池谷,発,17:50#勝瑞,発,17:55#吉成,発,17:58#佐古,発,18:05#徳島,着,18:08#"},
{"4349D":"高松,発,16:14#昭和町,発,16:17#栗林公園北口,発,16:21#栗林,発,16:25#木太町,発,16:28#屋島,発,16:32#古高松南,発,16:34#八栗口,発,16:38#讃岐牟礼,発,16:40#志度,発,16:44#オレンジタウン,着,16:47#"},
{"4369D":"板野,発,21:39#阿波川端,発,21:42#板東,発,21:47#池谷,発,21:50#勝瑞,発,21:55#吉成,発,21:58#佐古,発,22:04#徳島,着,22:07#"},
{"4375D":"高松,発,22:50#昭和町,発,22:53#栗林公園北口,発,22:56#栗林,発,22:59#木太町,発,23:03#屋島,発,23:07#古高松南,発,23:10#八栗口,発,23:14#讃岐牟礼,発,23:16#志度,発,23:20#オレンジタウン,着,23:23#"},
{"5315D":"高松,発,7:51#昭和町,発,7:54#栗林公園北口,発,7:57#栗林,発,8:09#木太町,発,8:12#屋島,発,8:16#古高松南,発,8:19#八栗口,発,8:25#讃岐牟礼,発,8:28#志度,発,8:33#オレンジタウン,着,8:36#"},
{"5347D":"高松,発,15:42#昭和町,発,15:45#栗林公園北口,発,15:48#栗林,発,15:51#木太町,発,15:55#屋島,発,15:59#古高松南,発,16:02#八栗口,発,16:08#讃岐牟礼,発,16:10#志度,発,16:14#オレンジタウン,発,16:18#造田,発,16:22#神前,発,16:25#讃岐津田,発,16:31#鶴羽,発,16:41#丹生,発,16:46#三本松,発,16:58#讃岐白鳥,発,17:01#引田,着,17:06#"},
{"5351D":"高松,発,16:42#昭和町,発,16:45#栗林公園北口,発,16:48#栗林,発,16:51#木太町,発,16:55#屋島,発,16:59#古高松南,発,17:02#八栗口,発,17:08#讃岐牟礼,発,17:10#志度,発,17:14#オレンジタウン,発,17:18#造田,発,17:22#神前,発,17:25#讃岐津田,発,17:31#鶴羽,発,17:41#丹生,発,17:46#三本松,発,17:58#讃岐白鳥,発,18:01#引田,着,18:06#"},
{"5359D":"高松,発,18:42#昭和町,発,18:45#栗林公園北口,発,18:48#栗林,発,18:51#木太町,発,18:55#屋島,発,18:59#古高松南,発,19:02#八栗口,発,19:08#讃岐牟礼,発,19:10#志度,発,19:14#オレンジタウン,発,19:18#造田,発,19:22#神前,発,19:25#讃岐津田,発,19:31#鶴羽,発,19:43#丹生,発,19:50#三本松,着,19:53#"},
{"5365D":"高松,発,20:14#昭和町,発,20:17#栗林公園北口,発,20:21#栗林,発,20:27#木太町,発,20:31#屋島,発,20:34#古高松南,発,20:37#八栗口,発,20:41#讃岐牟礼,発,20:43#志度,発,20:47#オレンジタウン,着,20:50#"},
{"5373D":"高松,発,21:42#昭和町,発,21:45#栗林公園北口,発,21:48#栗林,発,21:51#木太町,発,21:55#屋島,発,21:59#古高松南,発,22:02#八栗口,発,22:06#讃岐牟礼,発,22:08#志度,発,22:12#オレンジタウン,発,22:16#造田,発,22:20#神前,発,22:23#讃岐津田,発,22:30#鶴羽,発,22:34#丹生,発,22:39#三本松,発,22:44#讃岐白鳥,発,22:47#引田,着,22:52#"},
{"950D":"池谷,発,7:08#阿波大谷,発,7:11#立道,発,7:14#教会前,発,7:18#金比羅前,発,7:20#撫養,発,7:24#鳴門,着,7:27#"},
{"952D":"徳島,発,7:30#佐古,発,7:33#吉成,発,7:39#勝瑞,発,7:45#池谷,発,7:51#阿波大谷,発,7:54#立道,発,7:57#教会前,発,8:00#金比羅前,発,8:03#撫養,発,8:06#鳴門,着,8:09#"},
{"968D":"徳島,発,14:58#佐古,発,15:03#吉成,発,15:12#勝瑞,発,15:15#池谷,発,15:20#阿波大谷,発,15:23#立道,発,15:26#教会前,発,15:29#金比羅前,発,15:32#撫養,発,15:35#鳴門,着,15:37#"},
{"970D":"徳島,発,15:58#佐古,発,16:03#吉成,発,16:12#勝瑞,発,16:15#池谷,発,16:20#阿波大谷,発,16:23#立道,発,16:26#教会前,発,16:29#金比羅前,発,16:32#撫養,発,16:35#鳴門,着,16:37#"},
{"972D":"徳島,発,16:58#佐古,発,17:04#吉成,発,17:12#勝瑞,発,17:15#池谷,発,17:20#阿波大谷,発,17:23#立道,発,17:26#教会前,発,17:29#金比羅前,発,17:32#撫養,発,17:35#鳴門,着,17:37#"},
{"974D":"徳島,発,17:58#佐古,発,18:04#吉成,発,18:12#勝瑞,発,18:15#池谷,発,18:20#阿波大谷,発,18:23#立道,発,18:26#教会前,発,18:29#金比羅前,発,18:32#撫養,発,18:35#鳴門,着,18:37#"},
{"976D":"徳島,発,18:58#佐古,発,19:03#吉成,発,19:13#勝瑞,発,19:16#池谷,発,19:20#阿波大谷,発,19:23#立道,発,19:26#教会前,発,19:30#金比羅前,発,19:32#撫養,発,19:35#鳴門,着,19:38#"},
{"980D":"徳島,発,21:26#佐古,発,21:32#吉成,発,21:39#勝瑞,発,21:42#池谷,発,21:52#阿波大谷,発,21:55#立道,発,21:58#教会前,発,22:02#金比羅前,発,22:04#撫養,発,22:07#鳴門,着,22:10#"},
{"982D":"徳島,発,22:58#佐古,発,23:05#吉成,発,23:12#勝瑞,発,23:15#池谷,発,23:20#阿波大谷,発,23:23#立道,発,23:26#教会前,発,23:29#金比羅前,発,23:32#撫養,発,23:35#鳴門,着,23:37#"},
{"4954D":"徳島,発,8:27#佐古,発,8:30#吉成,発,8:36#勝瑞,発,8:40#池谷,発,8:44#阿波大谷,発,8:46#立道,発,8:49#教会前,発,8:53#金比羅前,発,8:55#撫養,発,8:58#鳴門,着,9:01#"},
{"4956D":"徳島,発,9:05#佐古,発,9:09#吉成,発,9:15#勝瑞,発,9:17#池谷,発,9:26#阿波大谷,発,9:29#立道,発,9:32#教会前,発,9:35#金比羅前,発,9:37#撫養,発,9:40#鳴門,着,9:43#"},
{"4958D":"徳島,発,9:58#佐古,発,10:03#吉成,発,10:12#勝瑞,発,10:15#池谷,発,10:20#阿波大谷,発,10:23#立道,発,10:26#教会前,発,10:29#金比羅前,発,10:32#撫養,発,10:35#鳴門,着,10:37#"},
{"4960D":"徳島,発,10:58#佐古,発,11:03#吉成,発,11:12#勝瑞,発,11:15#池谷,発,11:20#阿波大谷,発,11:23#立道,発,11:26#教会前,発,11:29#金比羅前,発,11:32#撫養,発,11:35#鳴門,着,11:37#"},
{"4962D":"徳島,発,11:58#佐古,発,12:04#吉成,発,12:12#勝瑞,発,12:15#池谷,発,12:20#阿波大谷,発,12:23#立道,発,12:26#教会前,発,12:29#金比羅前,発,12:32#撫養,発,12:35#鳴門,着,12:37#"},
{"4964D":"徳島,発,12:58#佐古,発,13:03#吉成,発,13:12#勝瑞,発,13:15#池谷,発,13:20#阿波大谷,発,13:23#立道,発,13:26#教会前,発,13:29#金比羅前,発,13:32#撫養,発,13:35#鳴門,着,13:37#"},
{"4966D":"徳島,発,13:58#佐古,発,14:03#吉成,発,14:12#勝瑞,発,14:15#池谷,発,14:20#阿波大谷,発,14:23#立道,発,14:26#教会前,発,14:29#金比羅前,発,14:32#撫養,発,14:35#鳴門,着,14:37#"},
{"4978D":"徳島,発,19:58#佐古,発,20:03#吉成,発,20:15#勝瑞,発,20:18#池谷,発,20:23#阿波大谷,発,20:26#立道,発,20:29#教会前,発,20:32#金比羅前,発,20:34#撫養,発,20:38#鳴門,着,20:40#"},
{"951D":"鳴門,発,6:32#撫養,発,6:35#金比羅前,発,6:38#教会前,発,6:41#立道,発,6:44#阿波大谷,発,6:48#池谷,発,6:51#勝瑞,発,6:59#吉成,発,7:04#佐古,発,7:11#徳島,着,7:14#"},
{"953D":"鳴門,発,6:51#池谷,着,7:02#"},
{"955D":"鳴門,発,7:32#撫養,発,7:35#金比羅前,発,7:38#教会前,発,7:40#立道,発,7:44#阿波大谷,発,7:47#池谷,発,7:51#勝瑞,発,7:57#吉成,発,8:00#佐古,発,8:07#徳島,着,8:10#"},
{"957D":"鳴門,発,8:14#撫養,発,8:17#金比羅前,発,8:20#教会前,発,8:22#立道,発,8:26#阿波大谷,発,8:29#池谷,発,8:44#勝瑞,発,8:48#吉成,発,8:56#佐古,発,9:02#徳島,着,9:04#"},
{"973D":"鳴門,発,16:00#撫養,発,16:02#金比羅前,発,16:05#教会前,発,16:08#立道,発,16:11#阿波大谷,発,16:14#池谷,発,16:20#勝瑞,発,16:30#吉成,発,16:35#佐古,発,16:42#徳島,着,16:45#"},
{"975D":"鳴門,発,17:00#撫養,発,17:02#金比羅前,発,17:05#教会前,発,17:08#立道,発,17:11#阿波大谷,発,17:14#池谷,発,17:20#勝瑞,発,17:30#吉成,発,17:35#佐古,発,17:42#徳島,着,17:45#"},
{"977D":"鳴門,発,18:00#撫養,発,18:02#金比羅前,発,18:05#教会前,発,18:08#立道,発,18:11#阿波大谷,発,18:14#池谷,発,18:20#勝瑞,発,18:30#吉成,発,18:35#佐古,発,18:42#徳島,着,18:45#"},
{"979D":"鳴門,発,19:00#撫養,発,19:02#金比羅前,発,19:05#教会前,発,19:08#立道,発,19:11#阿波大谷,発,19:14#池谷,発,19:20#勝瑞,発,19:31#吉成,発,19:36#佐古,発,19:42#徳島,着,19:45#"},
{"981D":"鳴門,発,20:00#撫養,発,20:02#金比羅前,発,20:05#教会前,発,20:08#立道,発,20:11#阿波大谷,発,20:14#池谷,発,20:23#勝瑞,発,20:33#吉成,発,20:36#佐古,発,20:42#徳島,着,20:45#"},
{"4959D":"鳴門,発,9:08#撫養,発,9:10#金比羅前,発,9:13#教会前,発,9:16#立道,発,9:19#阿波大谷,発,9:22#池谷,発,9:33#勝瑞,発,9:37#吉成,発,9:39#佐古,発,9:46#徳島,着,9:48#"},
{"4961D":"鳴門,発,10:00#撫養,発,10:02#金比羅前,発,10:05#教会前,発,10:08#立道,発,10:11#阿波大谷,発,10:14#池谷,発,10:20#勝瑞,発,10:30#吉成,発,10:35#佐古,発,10:42#徳島,着,10:44#"},
{"4963D":"鳴門,発,11:00#撫養,発,11:02#金比羅前,発,11:05#教会前,発,11:08#立道,発,11:11#阿波大谷,発,11:14#池谷,発,11:20#勝瑞,発,11:30#吉成,発,11:35#佐古,発,11:42#徳島,着,11:45#"},
{"4965D":"鳴門,発,12:00#撫養,発,12:02#金比羅前,発,12:05#教会前,発,12:08#立道,発,12:11#阿波大谷,発,12:14#池谷,発,12:20#勝瑞,発,12:30#吉成,発,12:35#佐古,発,12:42#徳島,着,12:44#"},
{"4967D":"鳴門,発,13:00#撫養,発,13:02#金比羅前,発,13:05#教会前,発,13:08#立道,発,13:11#阿波大谷,発,13:14#池谷,発,13:20#勝瑞,発,13:30#吉成,発,13:35#佐古,発,13:42#徳島,着,13:45#"},
{"4969D":"鳴門,発,14:00#撫養,発,14:02#金比羅前,発,14:05#教会前,発,14:08#立道,発,14:11#阿波大谷,発,14:14#池谷,発,14:20#勝瑞,発,14:30#吉成,発,14:35#佐古,発,14:42#徳島,着,14:45#"},
{"4971D":"鳴門,発,15:00#撫養,発,15:02#金比羅前,発,15:05#教会前,発,15:08#立道,発,15:11#阿波大谷,発,15:14#池谷,発,15:20#勝瑞,発,15:30#吉成,発,15:35#佐古,発,15:42#徳島,着,15:44#"},
{"4983D":"鳴門,発,21:00#撫養,発,21:02#金比羅前,発,21:05#教会前,発,21:08#立道,発,21:11#阿波大谷,発,21:14#池谷,発,21:20#勝瑞,発,21:24#吉成,発,21:27#佐古,発,21:33#徳島,着,21:36#"},
{"434D":"阿波池田,発,5:43#佃,発,5:48#辻,発,5:51#阿波加茂,発,5:56#三加茂,発,5:59#江口,発,6:03#阿波半田,発,6:09#貞光,発,6:13#小島,発,6:18#穴吹,発,6:25#川田,発,6:30#阿波山川,発,6:34#山瀬,発,6:37#学,発,6:41#阿波川島,発,6:45#西麻植,発,6:48#鴨島,発,6:56#麻植塚,発,6:59#牛島,発,7:02#下浦,発,7:06#石井,発,7:12#府中,発,7:18#鮎喰,発,7:21#蔵本,発,7:25#佐古,発,7:31#徳島,着,7:34#"},
{"436D":"穴吹,発,6:45#川田,発,6:51#阿波山川,発,6:55#山瀬,発,6:58#学,発,7:05#阿波川島,発,7:09#西麻植,発,7:12#鴨島,発,7:15#麻植塚,発,7:18#牛島,発,7:21#下浦,発,7:25#石井,発,7:29#府中,発,7:34#鮎喰,発,7:37#蔵本,発,7:42#佐古,発,7:46#徳島,着,7:48#"},
{"438D":"阿波池田,発,6:25#佃,発,6:31#辻,発,6:34#阿波加茂,発,6:39#三加茂,発,6:42#江口,発,6:46#阿波半田,発,6:52#貞光,発,6:55#小島,発,7:01#穴吹,発,7:09#川田,発,7:16#阿波山川,発,7:20#山瀬,発,7:24#学,発,7:29#阿波川島,発,7:44#西麻植,発,7:47#鴨島,発,7:50#麻植塚,発,7:53#牛島,発,8:01#下浦,発,8:04#石井,発,8:09#府中,発,8:15#鮎喰,発,8:18#蔵本,発,8:23#佐古,発,8:27#徳島,着,8:30#"},
{"446D":"穴吹,発,9:42#川田,発,9:48#阿波山川,発,9:52#山瀬,発,9:56#学,発,10:00#阿波川島,発,10:05#西麻植,発,10:09#鴨島,発,10:12#麻植塚,発,10:16#牛島,発,10:21#下浦,発,10:25#石井,発,10:28#府中,発,10:36#鮎喰,発,10:40#蔵本,発,10:43#佐古,発,10:46#徳島,着,10:49#"},
{"450D":"阿波池田,発,9:34#佃,発,9:40#辻,発,9:43#阿波加茂,発,9:49#三加茂,発,9:53#江口,発,10:01#阿波半田,発,10:08#貞光,発,10:12#小島,発,10:18#穴吹,発,10:32#川田,発,10:38#阿波山川,発,10:42#山瀬,発,10:49#学,発,10:53#阿波川島,発,11:05#西麻植,発,11:08#鴨島,発,11:12#麻植塚,発,11:14#牛島,発,11:21#下浦,発,11:24#石井,発,11:36#府中,発,11:40#鮎喰,発,11:43#蔵本,発,11:46#佐古,発,11:49#徳島,着,11:51#"},
{"468D":"阿波川島,発,15:35#西麻植,発,15:39#鴨島,発,15:42#麻植塚,発,15:46#牛島,発,15:51#下浦,発,15:55#石井,発,15:59#府中,発,16:07#鮎喰,発,16:10#蔵本,発,16:13#佐古,発,16:17#徳島,着,16:20#"},
{"474D":"阿波池田,発,15:40#佃,発,15:45#辻,発,15:49#阿波加茂,発,15:55#三加茂,発,15:58#江口,発,16:02#阿波半田,発,16:09#貞光,発,16:15#小島,発,16:21#穴吹,発,16:32#川田,発,16:38#阿波山川,発,16:42#山瀬,発,16:47#学,発,16:52#阿波川島,発,17:05#西麻植,発,17:08#鴨島,発,17:12#麻植塚,発,17:15#牛島,発,17:21#下浦,発,17:25#石井,発,17:28#府中,発,17:37#鮎喰,発,17:40#蔵本,発,17:43#佐古,発,17:46#徳島,着,17:49#"},
{"476D":"阿波川島,発,17:35#西麻植,発,17:38#鴨島,発,17:42#麻植塚,発,17:45#牛島,発,17:51#下浦,発,17:55#石井,発,17:59#府中,発,18:10#鮎喰,発,18:13#蔵本,発,18:16#佐古,発,18:19#徳島,着,18:22#"},
{"478D":"阿波池田,発,16:56#佃,発,17:03#辻,発,17:06#阿波加茂,発,17:12#三加茂,発,17:15#江口,発,17:24#阿波半田,発,17:30#貞光,発,17:34#小島,発,17:40#穴吹,発,17:47#川田,発,17:55#阿波山川,発,17:59#山瀬,発,18:03#学,発,18:09#阿波川島,発,18:13#西麻植,発,18:17#鴨島,発,18:22#麻植塚,発,18:25#牛島,発,18:28#下浦,発,18:32#石井,発,18:35#府中,発,18:40#鮎喰,発,18:43#蔵本,発,18:46#佐古,発,18:49#徳島,着,18:52#"},
{"480D":"穴吹,発,18:32#川田,発,18:41#阿波山川,発,18:45#山瀬,発,18:51#学,発,18:55#阿波川島,発,19:05#西麻植,発,19:09#鴨島,発,19:12#麻植塚,発,19:16#牛島,発,19:21#下浦,発,19:25#石井,発,19:28#府中,発,19:37#鮎喰,発,19:40#蔵本,発,19:43#佐古,発,19:46#徳島,着,19:50#"},
{"484D":"穴吹,発,19:51#川田,発,19:59#阿波山川,発,20:03#山瀬,発,20:07#学,発,20:11#阿波川島,発,20:15#西麻植,発,20:19#鴨島,発,20:24#麻植塚,発,20:27#牛島,発,20:33#下浦,発,20:36#石井,発,20:40#府中,発,20:45#鮎喰,発,20:48#蔵本,発,20:58#佐古,発,21:02#徳島,着,21:04#"},
{"488D":"阿波池田,発,21:19#佃,発,21:25#辻,発,21:30#阿波加茂,発,21:36#三加茂,発,21:39#江口,発,21:44#阿波半田,発,21:54#貞光,発,21:57#小島,発,22:06#穴吹,発,22:13#川田,発,22:21#阿波山川,発,22:25#山瀬,発,22:29#学,発,22:33#阿波川島,発,22:37#西麻植,発,22:41#鴨島,発,22:44#麻植塚,発,22:48#牛島,発,22:51#下浦,発,22:55#石井,発,22:59#府中,発,23:05#鮎喰,発,23:08#蔵本,発,23:11#佐古,発,23:15#徳島,着,23:17#"},
{"4002D":"阿波池田,発,6:46#阿波加茂,発,6:57#貞光,発,7:09#穴吹,発,7:22#阿波山川,発,7:30#阿波川島,発,7:39#鴨島,発,7:43#石井,発,7:52#蔵本,発,7:59#徳島,着,8:03#"},
{"4004D":"阿波池田,発,10:30#阿波加茂,発,10:41#貞光,発,10:53#穴吹,発,11:04#阿波山川,発,11:12#阿波川島,発,11:22#鴨島,発,11:26#蔵本,発,11:39#徳島,着,11:43#"},
{"4006D":"阿波池田,発,14:30#阿波加茂,発,14:41#貞光,発,14:53#穴吹,発,15:06#阿波山川,発,15:15#阿波川島,発,15:24#鴨島,発,15:29#蔵本,発,15:47#徳島,着,15:51#"},
{"4430D":"阿波川島,発,5:55#西麻植,発,5:59#鴨島,発,6:02#麻植塚,発,6:06#牛島,発,6:09#下浦,発,6:13#石井,発,6:17#府中,発,6:21#鮎喰,発,6:25#蔵本,発,6:29#佐古,発,6:33#徳島,着,6:36#"},
{"4448D":"阿波川島,発,10:35#西麻植,発,10:38#鴨島,発,10:41#麻植塚,発,10:44#牛島,発,10:47#下浦,発,10:51#石井,発,10:55#府中,発,11:03#鮎喰,発,11:07#蔵本,発,11:09#佐古,発,11:12#徳島,着,11:15#"},
{"4452D":"阿波川島,発,11:35#西麻植,発,11:38#鴨島,発,11:42#麻植塚,発,11:45#牛島,発,11:52#下浦,発,11:55#石井,発,11:59#府中,発,12:03#鮎喰,発,12:07#蔵本,発,12:13#佐古,発,12:17#徳島,着,12:19#"},
{"4454D":"穴吹,発,11:32#川田,発,11:42#阿波山川,発,11:46#山瀬,発,11:49#学,発,11:54#阿波川島,発,12:05#西麻植,発,12:08#鴨島,発,12:11#麻植塚,発,12:15#牛島,発,12:27#下浦,発,12:30#石井,発,12:34#府中,発,12:38#鮎喰,発,12:42#蔵本,発,12:45#佐古,発,12:48#徳島,着,12:51#"},
{"4456D":"阿波川島,発,12:39#西麻植,発,12:43#鴨島,発,12:46#麻植塚,発,12:49#牛島,発,12:53#下浦,発,12:56#石井,発,13:00#府中,発,13:07#鮎喰,発,13:10#蔵本,発,13:13#佐古,発,13:17#徳島,着,13:20#"},
{"4458D":"穴吹,発,12:32#川田,発,12:42#阿波山川,発,12:46#山瀬,発,12:50#学,発,12:54#阿波川島,発,13:05#西麻植,発,13:09#鴨島,発,13:12#麻植塚,発,13:16#牛島,発,13:21#下浦,発,13:25#石井,発,13:28#府中,発,13:37#鮎喰,発,13:40#蔵本,発,13:43#佐古,発,13:46#徳島,着,13:49#"},
{"4460D":"阿波川島,発,13:35#西麻植,発,13:38#鴨島,発,13:42#麻植塚,発,13:45#牛島,発,13:51#下浦,発,13:55#石井,発,13:59#府中,発,14:07#鮎喰,発,14:10#蔵本,発,14:13#佐古,発,14:17#徳島,着,14:19#"},
{"4464D":"阿波川島,発,14:35#西麻植,発,14:38#鴨島,発,14:42#麻植塚,発,14:45#牛島,発,14:51#下浦,発,14:55#石井,発,14:59#府中,発,15:07#鮎喰,発,15:10#蔵本,発,15:13#佐古,発,15:17#徳島,着,15:19#"},
{"4466D":"穴吹,発,14:32#川田,発,14:38#阿波山川,発,14:42#山瀬,発,14:48#学,発,14:52#阿波川島,発,15:05#西麻植,発,15:08#鴨島,発,15:12#麻植塚,発,15:15#牛島,発,15:21#下浦,発,15:25#石井,発,15:28#府中,発,15:35#鮎喰,発,15:39#蔵本,発,15:42#佐古,発,15:45#徳島,着,15:47#"},
{"4470D":"穴吹,発,15:32#川田,発,15:38#阿波山川,発,15:42#山瀬,発,15:48#学,発,15:52#阿波川島,発,16:05#西麻植,発,16:08#鴨島,発,16:12#麻植塚,発,16:15#牛島,発,16:21#下浦,発,16:25#石井,発,16:28#府中,発,16:37#鮎喰,発,16:40#蔵本,発,16:43#佐古,発,16:46#徳島,着,16:49#"},
{"4472D":"阿波川島,発,16:35#西麻植,発,16:38#鴨島,発,16:42#麻植塚,発,16:45#牛島,発,16:51#下浦,発,16:55#石井,発,16:59#府中,発,17:07#鮎喰,発,17:10#蔵本,発,17:13#佐古,発,17:17#徳島,着,17:20#"},
{"4482D":"阿波池田,発,18:17#佃,発,18:22#辻,発,18:26#阿波加茂,発,18:34#三加茂,発,18:37#江口,発,18:41#阿波半田,発,18:48#貞光,発,18:56#小島,発,19:02#穴吹,発,19:09#川田,発,19:15#阿波山川,発,19:19#山瀬,発,19:22#学,発,19:27#阿波川島,発,19:35#西麻植,発,19:38#鴨島,発,19:42#麻植塚,発,19:45#牛島,発,19:51#下浦,発,19:55#石井,発,19:59#府中,発,20:04#鮎喰,発,20:08#蔵本,発,20:10#佐古,発,20:13#徳島,着,20:16#"},
{"5432D":"穴吹,発,5:57#川田,発,6:03#阿波山川,発,6:07#山瀬,発,6:10#学,発,6:14#阿波川島,発,6:19#西麻植,発,6:22#鴨島,発,6:26#麻植塚,発,6:29#牛島,発,6:32#下浦,発,6:36#石井,発,6:46#府中,発,6:52#鮎喰,発,6:56#蔵本,発,7:00#佐古,発,7:04#徳島,着,7:07#"},
{"5440D":"阿波池田,発,6:52#佃,発,7:00#辻,発,7:04#阿波加茂,発,7:10#三加茂,発,7:13#江口,発,7:20#阿波半田,発,7:26#貞光,発,7:36#小島,発,7:42#穴吹,発,7:51#川田,発,7:59#阿波山川,発,8:03#山瀬,発,8:07#学,発,8:11#阿波川島,発,8:16#西麻植,発,8:19#鴨島,発,8:22#麻植塚,発,8:26#牛島,発,8:29#下浦,発,8:33#石井,発,8:36#府中,発,8:41#鮎喰,発,8:44#蔵本,発,8:47#佐古,発,8:50#徳島,着,8:53#"},
{"5442D":"穴吹,発,8:12#川田,発,8:18#阿波山川,発,8:22#山瀬,発,8:26#学,発,8:30#阿波川島,発,8:35#西麻植,発,8:39#鴨島,発,8:42#麻植塚,発,8:45#牛島,発,8:51#下浦,発,8:56#石井,発,9:00#府中,発,9:08#鮎喰,発,9:11#蔵本,発,9:14#佐古,発,9:17#徳島,着,9:20#"},
{"5444D":"阿波池田,発,7:52#佃,発,7:58#辻,発,8:04#阿波加茂,発,8:10#三加茂,発,8:14#江口,発,8:18#阿波半田,発,8:25#貞光,発,8:29#小島,発,8:35#穴吹,発,8:43#川田,発,8:49#阿波山川,発,8:53#山瀬,発,8:57#学,発,9:01#阿波川島,発,9:05#西麻植,発,9:09#鴨島,発,9:19#麻植塚,発,9:22#牛島,発,9:26#下浦,発,9:30#石井,発,9:33#府中,発,9:38#鮎喰,発,9:42#蔵本,発,9:45#佐古,発,9:48#徳島,着,9:51#"},
{"5462D":"阿波池田,発,12:37#佃,発,12:43#辻,発,12:48#阿波加茂,発,12:54#三加茂,発,12:57#江口,発,13:03#阿波半田,発,13:10#貞光,発,13:16#小島,発,13:22#穴吹,発,13:32#川田,発,13:38#阿波山川,発,13:42#山瀬,発,13:48#学,発,13:52#阿波川島,発,14:05#西麻植,発,14:08#鴨島,発,14:12#麻植塚,発,14:15#牛島,発,14:21#下浦,発,14:25#石井,発,14:28#府中,発,14:37#鮎喰,発,14:40#蔵本,発,14:43#佐古,発,14:46#徳島,着,14:49#"},
{"5486D":"阿波池田,発,19:51#佃,発,19:57#辻,発,20:00#阿波加茂,発,20:06#三加茂,発,20:09#江口,発,20:14#阿波半田,発,20:24#貞光,発,20:27#小島,発,20:34#穴吹,発,20:42#川田,発,20:52#阿波山川,発,20:56#山瀬,発,21:00#学,発,21:04#阿波川島,発,21:08#西麻植,発,21:12#鴨島,発,21:15#麻植塚,発,21:18#牛島,発,21:22#下浦,発,21:25#石井,発,21:29#府中,発,21:34#鮎喰,発,21:37#蔵本,発,21:40#佐古,発,21:44#徳島,着,21:46#"},
{"8452D":"阿波池田,発,14:33#阿波加茂,発,14:52#貞光,発,15:24#穴吹,発,15:43#川田,発,15:58#学,発,16:12#鴨島,発,16:29#石井,発,16:49#蔵本,発,16:58#徳島,着,17:04#"},
{"433D":"徳島,発,6:23#佐古,発,6:26#蔵本,発,6:29#鮎喰,発,6:32#府中,発,6:35#石井,発,6:40#下浦,発,6:43#牛島,発,6:47#麻植塚,発,6:50#鴨島,発,6:54#西麻植,発,6:57#阿波川島,発,7:00#学,発,7:05#山瀬,発,7:09#阿波山川,発,7:12#川田,発,7:16#穴吹,発,7:23#小島,発,7:29#貞光,発,7:37#阿波半田,発,7:40#江口,発,7:46#三加茂,発,7:50#阿波加茂,発,7:53#辻,発,8:01#佃,発,8:04#阿波池田,着,8:09#"},
{"439D":"徳島,発,8:12#佐古,発,8:15#蔵本,発,8:21#鮎喰,発,8:24#府中,発,8:28#石井,発,8:37#下浦,発,8:41#牛島,発,8:50#麻植塚,発,8:53#鴨島,発,8:56#西麻植,発,9:00#阿波川島,発,9:09#学,発,9:13#山瀬,発,9:17#阿波山川,発,9:21#川田,発,9:25#穴吹,着,9:30#"},
{"451D":"徳島,発,11:52#佐古,発,11:55#蔵本,発,11:58#鮎喰,発,12:00#府中,発,12:07#石井,発,12:20#下浦,発,12:23#牛島,発,12:27#麻植塚,発,12:30#鴨島,発,12:33#西麻植,発,12:36#阿波川島,発,12:39#学,発,12:44#山瀬,発,12:50#阿波山川,発,12:53#川田,発,12:57#穴吹,発,13:03#小島,発,13:09#貞光,発,13:16#阿波半田,発,13:19#江口,発,13:25#三加茂,発,13:29#阿波加茂,発,13:32#辻,発,13:37#佃,発,13:41#阿波池田,着,13:47#"},
{"461D":"徳島,発,14:22#佐古,発,14:26#蔵本,発,14:30#鮎喰,発,14:33#府中,発,14:37#石井,発,14:43#下浦,発,14:47#牛島,発,14:51#麻植塚,発,14:54#鴨島,発,14:57#西麻植,発,15:00#阿波川島,着,15:03#"},
{"463D":"徳島,発,14:52#佐古,発,14:56#蔵本,発,14:59#鮎喰,発,15:02#府中,発,15:07#石井,発,15:13#下浦,発,15:17#牛島,発,15:21#麻植塚,発,15:24#鴨島,発,15:29#西麻植,発,15:32#阿波川島,発,15:39#学,発,15:43#山瀬,発,15:47#阿波山川,発,15:51#川田,発,15:56#穴吹,発,16:03#小島,発,16:09#貞光,発,16:15#阿波半田,発,16:19#江口,発,16:25#三加茂,発,16:29#阿波加茂,発,16:33#辻,発,16:39#佃,発,16:42#阿波池田,着,16:48#"},
{"469D":"徳島,発,16:22#佐古,発,16:26#蔵本,発,16:30#鮎喰,発,16:33#府中,発,16:37#石井,発,16:43#下浦,発,16:47#牛島,発,16:51#麻植塚,発,16:54#鴨島,発,16:58#西麻植,発,17:01#阿波川島,着,17:03#"},
{"473D":"徳島,発,17:22#佐古,発,17:26#蔵本,発,17:30#鮎喰,発,17:33#府中,発,17:37#石井,発,17:43#下浦,発,17:47#牛島,発,17:51#麻植塚,発,17:54#鴨島,発,17:57#西麻植,発,18:00#阿波川島,発,18:04#学,発,18:09#山瀬,発,18:13#阿波山川,発,18:17#川田,発,18:21#穴吹,着,18:26#"},
{"475D":"徳島,発,17:52#佐古,発,17:55#蔵本,発,17:58#鮎喰,発,18:00#府中,発,18:04#石井,発,18:19#下浦,発,18:22#牛島,発,18:29#麻植塚,発,18:32#鴨島,発,18:36#西麻植,発,18:39#阿波川島,発,18:42#学,発,18:46#山瀬,発,18:51#阿波山川,発,18:54#川田,発,18:58#穴吹,発,19:09#小島,発,19:16#貞光,発,19:23#阿波半田,発,19:27#江口,発,19:37#三加茂,発,19:42#阿波加茂,発,19:46#辻,発,19:52#佃,発,19:56#阿波池田,着,20:02#"},
{"477D":"徳島,発,18:22#佐古,発,18:26#蔵本,発,18:30#鮎喰,発,18:33#府中,発,18:40#石井,発,18:45#下浦,発,18:49#牛島,発,18:53#麻植塚,発,18:56#鴨島,発,18:59#西麻植,発,19:02#阿波川島,発,19:09#学,発,19:13#山瀬,発,19:23#阿波山川,発,19:27#川田,発,19:31#穴吹,着,19:38#"},
{"485D":"徳島,発,20:52#佐古,発,20:55#蔵本,発,20:59#鮎喰,発,21:02#府中,発,21:07#石井,発,21:12#下浦,発,21:16#牛島,発,21:21#麻植塚,発,21:25#鴨島,発,21:28#西麻植,発,21:31#阿波川島,発,21:35#学,発,21:39#山瀬,発,21:43#阿波山川,発,21:47#川田,発,21:52#穴吹,発,22:00#小島,発,22:07#貞光,発,22:14#阿波半田,発,22:17#江口,発,22:27#三加茂,発,22:32#阿波加茂,発,22:36#辻,発,22:42#佃,発,22:45#阿波池田,着,22:50#"},
{"487D":"徳島,発,21:52#佐古,発,21:56#蔵本,発,21:59#鮎喰,発,22:02#府中,発,22:07#石井,発,22:13#下浦,発,22:17#牛島,発,22:21#麻植塚,発,22:24#鴨島,発,22:27#西麻植,発,22:31#阿波川島,発,22:37#学,発,22:42#山瀬,発,22:46#阿波山川,発,22:50#川田,発,22:54#穴吹,着,23:01#"},
{"4001D":"徳島,発,9:00#蔵本,発,9:04#石井,発,9:11#鴨島,発,9:19#阿波川島,発,9:24#阿波山川,発,9:33#穴吹,発,9:41#貞光,発,9:52#阿波加茂,発,10:04#阿波池田,着,10:15#"},
{"4003D":"徳島,発,12:00#蔵本,発,12:09#鴨島,発,12:23#阿波川島,発,12:27#阿波山川,発,12:36#穴吹,発,12:44#貞光,発,12:55#阿波加茂,発,13:07#阿波池田,着,13:18#"},
{"4005D":"徳島,発,18:00#蔵本,発,18:07#鴨島,発,18:22#阿波川島,発,18:28#阿波山川,発,18:37#穴吹,発,18:45#貞光,発,18:56#阿波加茂,発,19:08#阿波池田,着,19:19#"},
{"4007D":"徳島,発,20:17#蔵本,発,20:21#石井,発,20:28#鴨島,発,20:35#阿波川島,発,20:40#阿波山川,発,20:49#穴吹,発,20:58#貞光,発,21:10#阿波加茂,発,21:24#阿波池田,着,21:35#"},
{"4441D":"徳島,発,9:22#佐古,発,9:26#蔵本,発,9:30#鮎喰,発,9:33#府中,発,9:38#石井,発,9:43#下浦,発,9:47#牛島,発,9:50#麻植塚,発,9:54#鴨島,発,9:57#西麻植,発,10:00#阿波川島,着,10:03#"},
{"4443D":"徳島,発,9:52#佐古,発,9:56#蔵本,発,9:59#鮎喰,発,10:02#府中,発,10:07#石井,発,10:13#下浦,発,10:17#牛島,発,10:21#麻植塚,発,10:24#鴨島,発,10:27#西麻植,発,10:31#阿波川島,発,10:39#学,発,10:43#山瀬,発,10:47#阿波山川,発,10:51#川田,発,10:56#穴吹,着,11:01#"},
{"4445D":"徳島,発,10:22#佐古,発,10:25#蔵本,発,10:28#鮎喰,発,10:30#府中,発,10:34#石井,発,10:38#下浦,発,10:42#牛島,発,10:51#麻植塚,発,10:54#鴨島,発,10:57#西麻植,発,11:00#阿波川島,着,11:03#"},
{"4447D":"徳島,発,10:52#佐古,発,10:55#蔵本,発,10:58#鮎喰,発,11:00#府中,発,11:04#石井,発,11:08#下浦,発,11:12#牛島,発,11:18#麻植塚,発,11:21#鴨島,発,11:27#西麻植,発,11:31#阿波川島,発,11:39#学,発,11:43#山瀬,発,11:49#阿波山川,発,11:53#川田,発,11:58#穴吹,着,12:03#"},
{"4449D":"徳島,発,11:22#佐古,発,11:25#蔵本,発,11:28#鮎喰,発,11:30#府中,発,11:40#石井,発,11:45#下浦,発,11:48#牛島,発,11:52#麻植塚,発,11:55#鴨島,発,11:58#西麻植,発,12:01#阿波川島,着,12:04#"},
{"4453D":"徳島,発,12:22#佐古,発,12:26#蔵本,発,12:30#鮎喰,発,12:33#府中,発,12:38#石井,発,12:43#下浦,発,12:47#牛島,発,12:53#麻植塚,発,12:56#鴨島,発,12:59#西麻植,発,13:02#阿波川島,着,13:05#"},
{"4455D":"徳島,発,12:52#佐古,発,12:56#蔵本,発,12:59#鮎喰,発,13:02#府中,発,13:07#石井,発,13:13#下浦,発,13:17#牛島,発,13:21#麻植塚,発,13:24#鴨島,発,13:27#西麻植,発,13:31#阿波川島,発,13:39#学,発,13:43#山瀬,発,13:47#阿波山川,発,13:51#川田,発,13:56#穴吹,着,14:01#"},
{"4457D":"徳島,発,13:22#佐古,発,13:26#蔵本,発,13:30#鮎喰,発,13:33#府中,発,13:37#石井,発,13:43#下浦,発,13:47#牛島,発,13:51#麻植塚,発,13:54#鴨島,発,13:57#西麻植,発,14:00#阿波川島,着,14:03#"},
{"4459D":"徳島,発,13:52#佐古,発,13:56#蔵本,発,13:59#鮎喰,発,14:02#府中,発,14:07#石井,発,14:13#下浦,発,14:17#牛島,発,14:21#麻植塚,発,14:24#鴨島,発,14:27#西麻植,発,14:31#阿波川島,発,14:39#学,発,14:43#山瀬,発,14:47#阿波山川,発,14:51#川田,発,14:56#穴吹,着,15:01#"},
{"4465D":"徳島,発,15:22#佐古,発,15:26#蔵本,発,15:30#鮎喰,発,15:32#府中,発,15:35#石井,発,15:43#下浦,発,15:47#牛島,発,15:51#麻植塚,発,15:54#鴨島,発,15:57#西麻植,発,16:01#阿波川島,着,16:03#"},
{"5431D":"穴吹,発,6:53#小島,発,7:01#貞光,発,7:09#阿波半田,発,7:13#江口,発,7:20#三加茂,発,7:24#阿波加茂,発,7:28#辻,発,7:34#佃,発,7:37#阿波池田,着,7:43#"},
{"5435D":"徳島,発,6:54#佐古,発,6:57#蔵本,発,7:01#鮎喰,発,7:03#府中,発,7:07#石井,発,7:12#下浦,発,7:16#牛島,発,7:22#麻植塚,発,7:26#鴨島,発,7:29#西麻植,発,7:33#阿波川島,発,7:40#学,発,7:45#山瀬,発,7:49#阿波山川,発,7:54#川田,発,7:58#穴吹,着,8:04#"},
{"5437D":"徳島,発,7:35#佐古,発,7:38#蔵本,発,7:42#鮎喰,発,7:45#府中,発,7:48#石井,発,7:53#下浦,発,7:57#牛島,発,8:01#麻植塚,発,8:04#鴨島,発,8:07#西麻植,発,8:10#阿波川島,発,8:15#学,発,8:20#山瀬,発,8:26#阿波山川,発,8:30#川田,発,8:34#穴吹,発,8:53#小島,発,9:00#貞光,発,9:06#阿波半田,発,9:10#江口,発,9:17#三加茂,発,9:21#阿波加茂,発,9:25#辻,発,9:31#佃,発,9:40#阿波池田,着,9:45#"},
{"5467D":"徳島,発,15:52#佐古,発,15:56#蔵本,発,15:59#鮎喰,発,16:02#府中,発,16:07#石井,発,16:13#下浦,発,16:17#牛島,発,16:21#麻植塚,発,16:24#鴨島,発,16:27#西麻植,発,16:31#阿波川島,発,16:39#学,発,16:43#山瀬,発,16:47#阿波山川,発,16:51#川田,発,16:56#穴吹,発,17:01#小島,発,17:08#貞光,発,17:14#阿波半田,発,17:17#江口,発,17:24#三加茂,発,17:28#阿波加茂,発,17:32#辻,発,17:38#佃,発,17:41#阿波池田,着,17:47#"},
{"5471D":"徳島,発,16:52#佐古,発,16:55#蔵本,発,16:59#鮎喰,発,17:02#府中,発,17:07#石井,発,17:13#下浦,発,17:17#牛島,発,17:21#麻植塚,発,17:24#鴨島,発,17:27#西麻植,発,17:31#阿波川島,発,17:39#学,発,17:43#山瀬,発,17:47#阿波山川,発,17:51#川田,発,17:56#穴吹,発,18:03#小島,発,18:09#貞光,発,18:15#阿波半田,発,18:19#江口,発,18:26#三加茂,発,18:30#阿波加茂,発,18:34#辻,発,18:40#佃,発,18:44#阿波池田,着,18:49#"},
{"5479D":"徳島,発,18:52#佐古,発,18:56#蔵本,発,18:59#鮎喰,発,19:02#府中,発,19:07#石井,発,19:13#下浦,発,19:17#牛島,発,19:21#麻植塚,発,19:24#鴨島,発,19:27#西麻植,発,19:31#阿波川島,発,19:39#学,発,19:43#山瀬,発,19:47#阿波山川,発,19:51#川田,発,19:59#穴吹,発,20:09#小島,発,20:16#貞光,発,20:27#阿波半田,発,20:31#江口,発,20:41#三加茂,発,20:46#阿波加茂,発,20:50#辻,発,20:56#佃,発,21:00#阿波池田,着,21:05#"},
{"5481D":"徳島,発,19:22#佐古,発,19:26#蔵本,発,19:30#鮎喰,発,19:33#府中,発,19:37#石井,発,19:43#下浦,発,19:47#牛島,発,19:51#麻植塚,発,19:54#鴨島,発,19:57#西麻植,発,20:00#阿波川島,発,20:04#学,発,20:13#山瀬,発,20:18#阿波山川,発,20:22#川田,発,20:26#穴吹,着,20:34#"},
{"5483D":"徳島,発,19:52#佐古,発,19:55#蔵本,発,19:58#鮎喰,発,20:01#府中,発,20:05#石井,発,20:09#下浦,発,20:13#牛島,発,20:17#麻植塚,発,20:21#鴨島,発,20:27#西麻植,発,20:31#阿波川島,発,20:44#学,発,20:48#山瀬,発,21:00#阿波山川,発,21:04#川田,発,21:08#穴吹,着,21:18#"},
{"5489D":"徳島,発,22:52#佐古,発,22:55#蔵本,発,22:58#鮎喰,発,23:01#府中,発,23:05#石井,発,23:09#下浦,発,23:13#牛島,発,23:17#麻植塚,発,23:21#鴨島,発,23:24#西麻植,発,23:27#阿波川島,発,23:30#学,発,23:35#山瀬,発,23:39#阿波山川,発,23:43#川田,発,23:47#穴吹,着,23:54#"},
{"8451D":"徳島,発,10:35#蔵本,発,10:42#石井,発,10:54#鴨島,発,11:11#阿波川島,発,11:22#穴吹,発,11:50#貞光,発,12:18#阿波加茂,発,12:39#阿波池田,着,12:59#"}
]

View File

@@ -1,4 +1,3 @@
import 'babel-polyfill';
import { registerRootComponent } from "expo";
import { registerWidgetTaskHandler } from "react-native-android-widget";
import { Platform } from "react-native";

Some files were not shown because too many files have changed in this diff Show More