- 投稿日:2019-02-03T22:33:51+09:00
JavaScriptでストップウォッチ作ってみる
参考
javascriptでストップウォッチを作ってみる。忘備録
https://qiita.com/ryomaDsakamoto/items/c49a9d4cd2017405af1b
完成形
シンプルなストップウォッチです.
HTML
最低限必要な表示する領域とボタンを配置します.
stopwatch.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <title>StopWatch</title> </head> <body> <div id="timer">00:00:000</div> <button id="start">start</button> <button id="stop">stop</button> <button id="reset">reset</button> <script src="js/main.js"></script> </body> </html>JavaScript(ES6)でロジックを書く
main.jsconst timer = document.getElementById("timer"); const start = document.getElementById("start"); const stop = document.getElementById("stop"); const reset = document.getElementById("reset"); // 経過時間を保存する変数(単位:ミリ秒) let elapsedTime; // スタートボタンを押したときのUnix Epoch let startTime; // タイマーのID let timerId; // 以前 stop したタイミングまでの計測時間 let timeToAdd = 0; // 表示される内容をアップデートする関数 const updateTimeText = () => { // 1分 = 1000 ミリ秒 * 60秒 let m = Math.floor(elapsedTime / (1000 * 60)); // 1分に満たなかったミリ秒のうち,秒となったもの let s = Math.floor((elapsedTime % (1000 * 60)) / 1000); // 1秒になれなかったもの let ms = elapsedTime % 1000; // ゼロパディング m = `0${m}`.slice(-2); s = `0${s}`.slice(-2); ms = `00${ms}`.slice(-3); timer.textContent = `${m}:${s}:${ms}`; }; // 経過時間の管理と計算を行う関数 const countUp = () => { timerId = setTimeout(() => { elapsedTime = Date.now() - startTime + timeToAdd; updateTimeText(); countUp(); }, 10); }; start.addEventListener("click", () => { startTime = Date.now(); countUp(); }); stop.addEventListener("click", () => { clearTimeout(timerId); timeToAdd += Date.now() - startTime; }); reset.addEventListener("click", () => { elapsedTime = 0; timeToAdd = 0; // 00:00:000 を表示 updateTimeText(); });ポイント
const,let
定数は
const,変数はletを使います.変数の意図しない変更を防ぐことができます.また,スコープが自身が定義されたブロックとなります.
アロー関数
毎度
functionと書くのは面倒です.() => {}というように書くと見た目がすっきりします.今回は関係ありませんが,
thisの扱いが少し違うので注意が必要です.https://azu.github.io/what-is-this/
テンプレート文字列
"string text " + expression + " string text"は,`string text ${expression} string text`というように書くことができます.テンプレート文字列を使うことによってダブルクオートやシングルクオートを使う回数を減らすことができ,可読性が上がります.デバッグ
上のコードにはバグがあるので修正します.
スタートボタンの連続クリック
このアプリケーションでは,連続で2回クリックをしたとき2つのタイマーイベント(
countUp)が発生してしまいます.この問題を解決する方法としていくつかのアプローチがあります.
- スタートボタンとストップボタンを統合する
- 連続で押せないように無効化する
一般的な(物理)ストップウォッチでは,1の選択肢が取られています.
ただ,手法としては2もあるのでどちらも紹介します.
スタートボタンとストップボタンを統合する
HTML
HTMLはスタートボタンとストップボタンが統合されたことにより,buttonタグが一つ減ります.
stopwatch.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <title>StopWatch</title> </head> <body> <div id="timer">00:00:000</div> <button id="start-stop">start</button> <button id="reset">reset</button> <script src="js/main.js"></script> </body> </html>JavaScript
現在の状態が動作中か停止中かを条件分けして,ボタンの処理を変える必要があります.
main.jsconst timer = document.getElementById("timer"); const startStop = document.getElementById("start-stop"); const reset = document.getElementById("reset"); // 経過時間を保存する変数(単位:ミリ秒) let elapsedTime; // スタートボタンを押したときのUnix Epoch let startTime; // タイマーのID let timerId = null; // 以前 stop したタイミングまでの計測時間 let timeToAdd = 0; // 表示される内容をアップデートする関数 const updateTimeText = () => { // 1分 = 1000 ミリ秒 * 60秒 let m = Math.floor(elapsedTime / (1000 * 60)); // 1分に満たなかったミリ秒のうち,秒となったもの let s = Math.floor((elapsedTime % (1000 * 60)) / 1000); // 1秒になれなかったもの let ms = elapsedTime % 1000; // ゼロパディング m = `0${m}`.slice(-2); s = `0${s}`.slice(-2); ms = `00${ms}`.slice(-3); timer.textContent = `${m}:${s}:${ms}`; }; // 経過時間の管理と計算を行う関数 const countUp = () => { timerId = setTimeout(() => { elapsedTime = Date.now() - startTime + timeToAdd; updateTimeText(); countUp(); }, 10); }; startStop.addEventListener("click", () => { // タイマーIDが停止中 if (timerId === null) { startTime = Date.now(); countUp(); // ボタンのテキストをstartからstopに更新 startStop.textContent = "stop"; } else { // タイマーが動作中 clearTimeout(timerId); timerId = null; timeToAdd += Date.now() - startTime; // ボタンのテキストをstopからstartに更新 startStop.textContent = "start"; } }); reset.addEventListener("click", () => { elapsedTime = 0; timeToAdd = 0; // 00:00:000 を表示 updateTimeText(); });連続で押せないように無効化する
button タグには,disabled という属性を付けることができます.
JavaScript から disabled 属性をコントロールすることによってボタンを無効化します.HTML
はじめのHTMLと同じコードですが,初期状態としてstopボタンを無効化しておきます.
stopwatch.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <title>StopWatch</title> </head> <body> <div id="timer">00:00:000</div> <button id="start">start</button> <button id="stop" disabled>stop</button> <button id="reset">reset</button> <script src="js/main.js"></script> </body> </html>JavaScript
はじめのコードに ボタンを有効化/無効化するコードを追加します.
main.jsconst timer = document.getElementById("timer"); const start = document.getElementById("start"); const stop = document.getElementById("stop"); const reset = document.getElementById("reset"); // 経過時間を保存する変数(単位:ミリ秒) let elapsedTime; // スタートボタンを押したときのUnix Epoch let startTime; // タイマーのID let timerId; // 以前 stop したタイミングまでの計測時間 let timeToAdd = 0; // 表示される内容をアップデートする関数 const updateTimeText = () => { // 1分 = 1000 ミリ秒 * 60秒 let m = Math.floor(elapsedTime / (1000 * 60)); // 1分に満たなかったミリ秒のうち,秒となったもの let s = Math.floor((elapsedTime % (1000 * 60)) / 1000); // 1秒になれなかったもの let ms = elapsedTime % 1000; // ゼロパディング m = `0${m}`.slice(-2); s = `0${s}`.slice(-2); ms = `00${ms}`.slice(-3); timer.textContent = `${m}:${s}:${ms}`; }; // 経過時間の管理と計算を行う関数 const countUp = () => { timerId = setTimeout(() => { elapsedTime = Date.now() - startTime + timeToAdd; updateTimeText(); countUp(); }, 10); }; start.addEventListener("click", () => { startTime = Date.now(); countUp(); // スタートボタンを無効化 start.disabled = true; // ストップボタンを有効化 stop.disabled = false; }); stop.addEventListener("click", () => { clearTimeout(timerId); timeToAdd += Date.now() - startTime; // スタートボタンを有効化 start.disabled = false; // ストップボタンを無効化 stop.disabled = true; }); reset.addEventListener("click", () => { elapsedTime = 0; timeToAdd = 0; // 00:00:000 を表示 updateTimeText(); });まとめ
プログラムは自分の書いたようにしか動きません.
プログラムを書くにはまず必要な機能を考え言語化し,そのとおりにプログラムを書くと動きます.
- 投稿日:2019-02-03T12:46:47+09:00
lxmlメモ
はじめに
今回の内容はスクレイピングする上で用いたとあるライブラリについての個人的感想です。
どんなことができるのか、使ってみた感想をつらつらと書いていきます。スクレイピングとは
Web上のページから情報を引き抜くこと。機械学習など大量のデータが欲しい時に、データの取得をプログラミングで自動化できるのでとても便利なものである。
lxmlとは
スクレイピングを実現するためのPythonモジュールのひとつ。他にもhtmllibやBeautiful Soupなどがある。
特徴
- とにかく高速、おそらくモジュールがCを使って書かれたため?
- HTMLの要素をDOM(Document Object Model)構造に変換する
- XPath(次で説明)というものを使って抜き取る要素を指定
使い方
lxmlで要素を抜き取りたいときは、XPathというもので要素の場所を指定する必要がある。
XPathの使い方はこちらのものを引用しつつ説明する。XPath(XML Path Language)とは、XML形式の文書から、特定の部分を指定して抽出するための簡潔な構文(言語)です。HTML形式の文書にも対応します。
CSSではセレクタを使ってHTML文書内の特定の部分を抽出しますが、XPathはより簡潔かつ柔軟に指定ができるとされています。例としてbody以下のリンク要素(hogeクラス)を取り出す書き方を挙げる。
- CSSセレクタ:
html > body a.hoge- XPath:
/html/body//a[@class="hoge"]または//a[@class="hoge"]このようにXPathは要素を階層的に指定できる。
さらにXPathでは絶対パス形式と相対パス形式で要素を指定できるので柔軟に要素を抜き取ることができる。具体例として以下のようなHTMLファイルから要素を抜き取るとする。
sample.html<html> <head> <title>sample page</title> </head> <body> <div class="test1"> <h1>Hello World!!</h1> </div> <div class="table"> <table border="1"> <tr> <th>名前</th> <th>一言</th> </tr> <tr> <td>サンプル1</td> <td>よろしく</td> </tr> <tr> <td>サンプル2</td> <td>はじめまして</td> </tr> <tr> <td>サンプル3</td> <td>これはテストです</td> </tr> </table> </div> </body> </html>このとき、テーブル内の一言を抽出したい場合は、次のようにXPathを指定する。
//table/tr/td[2]もしサンプル2が発している「はじめまして」を抽出するなら
//td[4]と指定しても良い。
ただし、tdの数の変動を考慮するならば次のように指定する。//table//td[contains(*,'サンプル2')]/following-sibling::td[1]こうすることで中身がサンプル2であるtdの後ろにある要素(今回はtd)を抽出することができる。
XPathにはこうした細かい条件を指定できる関数もあるので、非常に便利である。
ここまでをコードとしてまとめる。import lxml.html import requests # Webページのソースを取得するのに用いる。今回はこれについての説明は省く url = 'http://example.com/' # URLの一例、今回は上のsample.htmlを指すものとする r = requests.get(url) # URLにあるページのソースを取得 html = lxml.html.fromstring(r.text) # 取得したソースをHtmlElementオブジェクトに変換 td = html.xpath("//table//td[contains(*,'サンプル2')]/following-sibling::td[1]") # >>> print(td) # '<td>はじめまして</td>'指定された要素の中身(ex.文字列やURL)を抽出するには以下の文を最後に追加する。
text = td.text()ただし、もしtdの中身が
はじめまして<br />僕はサンプル2ですの場合、text()ははじめましてしか抽出できない。そういったときは次のようなメソッドを使う。text = td.text_content()こうするとtextには
はじめまして僕の名前はサンプル2ですが代入され、要素内の全文字列を取得することができる。
その他様々なデータの抽出方法はこちらを参考に感想
大量のデータをとるときでもわずか数分で取得できたのは神だった。
スクレイピングする際は「とりあえずlxml」の気持ちで生きていきたい。参考文献
- 投稿日:2019-02-03T04:13:35+09:00
loadしたhtmlにjsを適用させる
loadしたhtmlにjsを適用させる
前提:フォルダ階層
階層┣ static ┃ ┣ css ┃ ┃ ┗ menu.css ┃ ┣ js ┃ ┃ ┣common.js ┃ ┃ ┗menu.js ┃ ┣ html ┃ ┃ ┗ menu.html ┗ templates ┗ main.htmlやりたかったこと
機能
現在いるページと対応するメニューの色を変更させたい。
コード
htmlで複数ページを作る時に、メニューのところのhtmlが長いのでmenu.htmlとして外部ファイルを作った。
それをcommon.jsで読み込み、main.htmlにmenu.htmlを適用させた。
更に今いるページと対応するメニューの色を変更するために
特定のタグをactiveにする処理を書いたmenu.jsをmenu.htmlに適応させたい。main.html<body> <div id="menu"></div> <!--jQueryの読み込みとか--> <script type="text/javascript" src="/webjars/jquery/3.3.1/jquery.min.js" charset="utf-8"> </script> <!--javaScriptの読み込み--> <script type="text/javascript" src="/js/common.js"></script> <script type="text/javascript" src="/js/menu.js"></script> </body>menu.html<ul id="nav"> <li><a href="/menu1">MENU1</a></li> <li><a href="/menu2">MENU2</a></li> <li><a href="/menu3">MENU3</a></li> <li><a href="/menu4">MENU4</a></li> </ul>common.js$(window).on('load', function() { //main.htmlのmenu要素についてmenu.htmlを適用させる $("#menu").load('/html/menu.html'); });menu.js//現在のページのurlとメニューのurlが同じだったら、そこのタグをactiveにする $(function() { $('#nav li a').each(function() { var $href = $(this).attr('href'); if (location.href.match($href)) { $(this).addClass('active'); } else { $(this).removeClass('active'); } }); });menu.css/*activeになってる要素navの[li a]タグの文字を赤にする*/ #nav li a.active { color: red; }問題1
menu.jsはちゃんと読み込まれているっぽいけど、activeにならない。
コンソール上のエラーは発生してないが、なんかうまく適用されていない気がする実際にやってみたこと
menu.html上で直接jsを呼んでみる
menu.html<!--変更したところ↓--> <script type="text/javascript" src="/js/menu.js"></script> <!--変更したところ↑--> <ul id="nav"> <li><a href="/menu1">MENU1</a></li> <li><a href="/menu2">MENU2</a></li> <li><a href="/menu3">MENU3</a></li> <li><a href="/menu4">MENU4</a></li> </ul>問題2
とりあえず、jsは読み込まれて適用された。が、
コンソールに以下のエラーerror[[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.よくわらかないけどエラーが出るってことはダメな気がする。気持ち悪いし
あと、ググったらエンドユーザーに影響がどうのって書いてたらかダメなんだと思う解決方法
menu.htmlをロードする時に一緒にjsもロードしてあげる!
common.js$(window).on('load', function() { //main.htmlのmenu要素についてmenu.htmlを適用させる $("#menu").load('/html/menu.html'); //変更したところ↓ $.getScript("/js/menu.js", function() { }); //変更したところ↑ });これでエラーなくちゃんとactiveにすることができた
参考にしたサイト
