タイマーを複数クライアントで共有できるWebアプリケーションを
PHP,JavaScript,MySQL等で作りたいと考えています。
イメージとしては、ある1つのWebクライアントがタイマーのスタートボタンを押すと
そのサーバーにアクセスしている他のWebクライアントのタイマーもカウントダウンが始まる、
というものです。
例えば、サーバーでタイマーを動かし、Ajaxで残り時間を受け取ることができれば
実現は可能なのでしょうか。
システム構成についてイメージがつかめておらず、
アドバイス等ありましたらご教授いただけますと幸いです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答2件
0
ベストアンサー
ふんわり原始的な方法で書いてみました。
MySQLではなく、ファイル./time.txt
を作成してそこに保存してます。
ajaxでは残り時間ではなく、タイムアウトする時刻のようなもの(0と負値は意味が違う)を返しています。
ご参考までに。
※100msに1回APIを呼び出すので、実行するならローカル環境だけにしてください
ファイル: ./timer.html
html
1<!DOCTYPE html> 2<html lang="ja"> 3 4<head> 5 <meta charset="utf8"> 6 <title>timer</title> 7</head> 8<div> 9 <button id="toggle_button">toggle</button><span id="time"></span> 10</div> 11<script> 12 document.addEventListener('DOMContentLoaded', (ev) => { 13 async function update(toggle) { 14 const timeout = ( 15 await fetch(`./timer_api.php?toggle=${toggle}`) 16 .then(res => res.json()) 17 ).utcms_from1970; 18 const current = Date.now().valueOf(); 19 document.querySelector('#time').textContent = timeout !== 0 20 ? (timeout < 0 21 ? ((-timeout) / 1000).toFixed(2) 22 : (timeout > current 23 ? ((timeout - current) / 1000).toFixed(2) 24 : 'timeout!')) 25 : '-'; 26 } 27 document.querySelector('#toggle_button') 28 .addEventListener('click', (ev) => { 29 update(1); 30 }); 31 const intervalId = setInterval(() => { 32 update(0); 33 }, 100); 34 document.addEventListener('unload', (ev) => { 35 clearInterval(intervalId); 36 }); 37 }); 38</script> 39 40</html>
ファイル: ./timer_api.php
php
1<?php 2header("Content-Type: application/json; charset=UTF-8"); 3$FILENAME = "./time.txt"; 4$TIMER_IN_MS = 10000; 5 6function unixtime_in_ms() 7{ 8 return round(microtime(true) * 1000); 9} 10 11$toggle = filter_input(INPUT_GET, "toggle"); 12 13if (file_exists($FILENAME)) { 14 $time = intval(file_get_contents($FILENAME)); 15} else { 16 $time = 0; 17} 18 19if ($toggle) { 20 if ($time > 0) { 21 $time = $time - unixtime_in_ms(); 22 if ($time > 0) { 23 $time = -$time; 24 } else { 25 $time = 0; 26 } 27 } else if ($time < 0) { 28 $time = unixtime_in_ms() - $time; 29 } else { 30 $time = unixtime_in_ms() + $TIMER_IN_MS; 31 } 32 file_put_contents($FILENAME, $time, LOCK_EX); 33} 34 35echo json_encode(["utcms_from1970" => $time]);
(追記1)
状態遷移図書いてみました。
teratailではsvg使えないみたいなので、↑はPNGですが、元は↓のSVGです。
svg
1<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="151px" preserveAspectRatio="none" style="width:1173px;height:151px;background:#FFFFFF;" version="1.1" viewBox="0 0 1173 151" width="1173px" zoomAndPan="magnify"><defs><filter height="300%" id="flbkmc7f8q21n" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><ellipse cx="74" cy="16" fill="#000000" filter="url(#flbkmc7f8q21n)" rx="10" ry="10" style="stroke:none;stroke-width:1.0;"/><g id="初期状態"><rect fill="#FEFECE" filter="url(#flbkmc7f8q21n)" height="50.2656" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="134" x="7" y="87"/><line style="stroke:#A80036;stroke-width:1.5;" x1="7" x2="141" y1="113.2969" y2="113.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="56" x="46" y="104.9951">初期状態</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="114" x="12" y="129.4355">(0)タイマ動いてない</text></g><g id="タイマ動作中"><rect fill="#FEFECE" filter="url(#flbkmc7f8q21n)" height="50.2656" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="226" x="381" y="87"/><line style="stroke:#A80036;stroke-width:1.5;" x1="381" x2="607" y1="113.2969" y2="113.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="84" x="452" y="104.9951">タイマ動作中</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="206" x="386" y="129.4355">(正の整数)タイムアウトするUTC[ms]</text></g><g id="タイマ一時停止中"><rect fill="#FEFECE" filter="url(#flbkmc7f8q21n)" height="50.2656" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="322" x="837" y="87"/><line style="stroke:#A80036;stroke-width:1.5;" x1="837" x2="1159" y1="113.2969" y2="113.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="112" x="942" y="104.9951">タイマ一時停止中</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="302" x="842" y="129.4355">(負の整数)タイムアウトまでの残り時間を符号反転[ms]</text></g><!--MD5=[deaffe79b3ee21e90318abb8f74e4bd6] 2link *start to 初期状態--><path d="M74,26.013 C74,38.698 74,62.4093 74,81.5698 " fill="none" id="*start-to-初期状態" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="74,86.8404,78,77.8404,74,81.8404,70,77.8404,74,86.8404" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[d30e3980f9843bd17f71c4a10a4dad22] 3link 初期状態 to タイマ動作中--><path d="M141.32,124.398 C161.265,127.5283 183.199,130.4416 203.5,132 C260.143,136.3482 323.034,133.0252 375.773,127.9279 " fill="none" id="初期状態-to-タイマ動作中" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="380.844,127.4292,371.4953,124.3305,375.8681,127.9192,372.2793,132.292,380.844,127.4292" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="113" x="204.5" y="128.0669">update(toggle=1)</text><!--MD5=[f4aff1e9f12684eed04a722415600c46] 4link タイマ動作中 to 初期状態--><path d="M380.961,112 C306.382,112 210.899,112 146.381,112 " fill="none" id="タイマ動作中-to-初期状態" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="141.015,112,150.015,116,146.015,112,150.015,108,141.015,112" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="203" x="159.5" y="105.0669">update(toggle=1)[残り時間<=0]</text><!--MD5=[528ec752e90b9c75408ab4ceb4f5b690] 5link タイマ動作中 to タイマ一時停止中--><path d="M607.107,112 C673.145,112 757.689,112 831.248,112 " fill="none" id="タイマ動作中-to-タイマ一時停止中" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="836.525,112,827.525,108,831.525,112,827.525,116,836.525,112" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="193" x="625.5" y="105.0669">update(toggle=1)[残り時間>0]</text><!--MD5=[824f9ec85e989e5fe711c3d4bd431b3b] 6link タイマ一時停止中 to タイマ動作中--><path d="M836.858,129.3611 C782.151,133.2067 720.667,135.283 664.5,132 C647.648,131.015 629.906,129.4868 612.494,127.704 " fill="none" id="タイマ一時停止中-to-タイマ動作中" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="607.102,127.1429,615.6386,132.0547,612.075,127.6614,616.4683,124.0978,607.102,127.1429" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="113" x="665.5" y="128.0669">update(toggle=1)</text><!--MD5=[7650aa9408f90a6e04a087846f450031] 7@startuml 8[*] - -> 初期状態 9初期状態 : (0)タイマ動いてない 10初期状態-> タイマ動作中:update(toggle=1) 11タイマ動作中 : (正の整数)タイムアウトするUTC[ms] 12タイマ動作中->タイマ一時停止中:update(toggle=1)[残り時間>0] 13タイマ一時停止中 : (負の整数)タイムアウトまでの残り時間を符号反転[ms] 14タイマ一時停止中->タイマ動作中:update(toggle=1) 15タイマ動作中->初期状態:update(toggle=1)[残り時間<=0] 16@enduml 17 18PlantUML version 1.2021.11beta1(Unknown compile time) 19(GPL source distribution) 20Java Runtime: Java(TM) SE Runtime Environment 21JVM: Java HotSpot(TM) 64-Bit Server VM 22Default Encoding: UTF-8 23Language: en 24Country: US 25--></g></svg>
投稿2021/09/12 23:26
編集2021/09/13 21:07退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/09/13 12:56
退会済みユーザー
2021/09/13 20:37
2021/09/14 01:17
退会済みユーザー
2021/09/14 01:19
2021/09/16 15:44 編集
退会済みユーザー
2021/09/16 16:34
2021/09/18 05:04
0
要件がふわっとしていて(たとえばどの程度の精度を求めるのかなど)答えにくい質問な気がするのですが、あえて答えてみます。
例えば、サーバーでタイマーを動かし、Ajaxで残り時間を受け取ることができれば
実現は可能なのでしょうか。
おそらく可能だと思います。まずは非同期通信を用いて簡単なエコーサーバやリアルタイムチャットみたいな簡単なものから学習するといいと思います。その辺の知識が深まれば、タイマーを共有する方法のイメージも自ずとつかめてくると思いますよ。イメージがつかめないと言うことは、まだそれに手を付けるのが早いと言うことです。もう少し身近な目標地点を定めるといいと思います。
投稿2021/09/11 17:09
総合スコア4853
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。