- 投稿日:2019-02-27T23:53:20+09:00
payjp.jsの導入方法<Rails>
Payjp.jsを導入するにあたって、理解するのに時間がかかってしまったので(なにせ記事が少ない!)今後導入される方の時間短縮のために、ここに残しておきます。
Pay.jpとは
Pay.jpのサービスを利用することでクレジットカード決済機能を簡単に導入することができます。
gem'payjp'をインストールすることで使用可能に。
利用方法については大きく2通りあります。「チェックアウト」
公式で用意されたスクリプトタグをHTMLに記述すれば、デザインされた決済フォーム、カード情報のバリデーション、カード情報のトークン化を行うフォームを生成することができます。こちらを使用すれば、ささっとすぐに実装可能です。
ビューについてこだわりがないという方であればこちらで十分だと思います。「カスタムフォーム(payjp.js)」
payjp.jsを使うことで、好きなデザインや挙動でトークン化を行うフォームを組み込めます。
ここで注意をしたいのが、payjp.jsはトークン化に特化したライブラリであり、これを使用したからといって決済ができる訳ではありません。
クレジットカード情報入力ページは自分の好みのビューにしたい!という方はこちらです。
今回はこのpayjp.jsで実装していくための説明となります。トークンとは
クレジットカード情報を自身のデータベース上で管理するのはセキュリティの観点で好ましくないので、顧客が入力したカード情報をトークン化しなくてはいけません。
顧客情報を持った情報の塊のことをトークンを呼びます。IDを使用することで顧客情報を呼び出すことができます。トークン化については公式を参考にしてください。
https://pay.jp/docs/cardtokenまたトークンは1度のみの使用しか出来ないので、2度以上使いたい場合は顧客カードを作成してカード情報をそこに紐付けることが必要です。顧客カードへの紐付けというのは後ほど説明します。
いざ導入!
ここからは実際のコードを交えて説明します。
まずは、顧客がカード情報を入力するためのフォームを作成します。qiita.html.haml%h2 クレジットカード情報入力 = form_tag("/users/purchase", method: "PATCH", id: "charge-form") do %label カード番号 %input{maxlength: "16", type: "text", class: "number", id: "payment_card_no" name: "number", placeholder: "カード番号"} %label CVC %input{type: "text", class: "cvc", id: "payment_card_security_code", name: "cvc", maxlength: "3", placeholder: "CVC"} %label 有効期限 %input{type: "text", class: "exp_month", id: "payment_card_expire_mm", name: "exp_month", maxlength: "2", placeholder: "月"} %input{type: "text", class: "exp_year", name: "exp_year", maxlength: "4", placeholder: "年"}Pay.jpにトークンを作成してもらうには、公式で用意されているフォームを活用しましょう。
(本記事では所々書き換えています。)qiita.js$(document).on('turbolinks:load', function() { var form = $("#charge-form"); Payjp.setPublicKey('pk_test_0383a1b8f91e8a6e3ea0e2a9'); $("#charge-form").on("click", "#submit-button", function(e) { e.preventDefault(); form.find("input[type=submit]").prop("disabled", true); var card = { number: parseInt($("#payment_card_no").val()), cvc: parseInt($("#payment_card_security_code").val()), exp_month: parseInt($("#payment_card_expire_mm").val()), exp_year: parseInt($("#payment_card_expire_yy").val()) }; Payjp.createToken(card, function(s, response) { if (response.error) { alert("error") form.find('button').prop('disabled', false); } else { $(".number").removeAttr("name"); $(".cvc").removeAttr("name"); $(".exp_month").removeAttr("name"); $(".exp_year").removeAttr("name"); var token = response.id; $("#charge-form").append($('<input type="hidden" name="payjp_token" class="payjp-token" />').val(token)); $("#charge-form").get(0).submit(); } }); }); });顧客がsubmitボタンを押した瞬間にこのjsファイルが反応するようにしてあげます。
このフォームの中のPayjp.createTokenで作成されたトークンIDがresponse.idに返ってきます。
後はif文で分岐をさせてあげて、最後にe.preventDefault();によって停止させていたsubmitを実行させます。setPublicKeyにはpay.jpにログインした際の管理画面で確認できるAPIキーを入れてください。
APIキーはconfig/initializers/setting.rbを作成してその中に変数を定義して入れてあげるとrbファイル間で共有できるので、利便性・セキュア面で良いですね!
(記載しているAPIキーは公式のものなのでご心配なく)qiita.html.haml%input.payjp-token{ type: "hidden", name: "payjpToken", value: "" }そしてHTML上で上記の記述をして、jsファイルで作成したトークンIDが空のvalueに入ることで、paramsとしてコントローラーへ投げることができます。
inputタグをhiddenにすることでビュー上には反映されていません。
以上でトークン作成と、トークンIDをparamsとしてコントローラーへ渡せるようになりました。顧客カードとの紐付け
カード情報非通過対応により2018年6月頃からサーバーサイドからのカード情報のPOSTリクエストができなくなりました。
そのためトークン化はビュー上で行いましたが、顧客作成はコントローラーで行います。users.controller.rbPayjp.api_key = PAYJP_SECRET_KEY customer = Payjp::Customer.create(card: params[:payjp_token])Payjp::Customer.createで顧客カードが作成されたので、その中のcardキーのバリューとしてトークンIDを指定してあげます。
カード情報を取り出す際にもこのIDは使用するので、私はUserテーブルのカラムに入れてあげました。他にも支払い等の詳しいやり方は公式のリファレンスを参照ください。
https://pay.jp/docs/api/#introduction終わりに
私自身まだエンジニアとしてプログラミングを学んで3ヶ月満たないので、ツッコミどころがあるかもしれません。
こういったやり方もあるんだな〜という、一つの実装方法として参考程度に見てください。
他に効率の良いやり方があるよ!この記述無駄じゃない?と気づいた方がいらしたらご指摘ください(_ _)
- 投稿日:2019-02-27T23:33:53+09:00
Node.jsとExpressでローカルサーバーを構築する(3) ―JSONを返すスタブAPI―
※ 本記事は、Node.jsとExpressでローカルサーバーを構築する(2) ―Expressでルーティング―の続きです。
最近は、Jsonデータを送りつけたり受け取ったりしてなんやかやするケースが増えてきました。私の極狭い認識の範囲では、フロント側の製作期間中にAPIが完成していないことが多いです。
その為、ローカルサーバーにJSONを返すスタブAPIの機能を実装したいと思います。概要
この記事の概要
- 目的
- Node.jsとExpressを利用して、PC上にローカルサーバーを立ち上げる
- 本記事のゴール
- GETでリクエストを送ると、JSONデータが返ってくる
- POSTでJSONデータを送ると、200 OK のレスポンスコードが返ってくる
- 対象者
- WEBフロント担当者
- HTML,CSS,JavaScript(es2015含む)の基本的な構文を理解している人
- HTTP通信、GET、POSTなどについて、ある程度理解している人(ざっくりで良いです)
- 黒い画面にコマンドを打ち込むことに抵抗がない方
- 環境・バージョン
- Windows10
- Node.js(推奨版) 10.15.01
- npm 6.4.1
- Express 4.16.4
- Advanced REST client 10.0.12
Chrome拡張ツール:Advanced REST client
GETやPOSTの動作確認を簡単に行うために、Chrome拡張ツールの「Advanced REST client」を利用します。
Advanced REST client
導入方法や利用方法は、下記サイトが詳しいです。分かりやすいUIですので、本記事内でも都度説明します。
「Advanced REST client」の使い方まとめ ~GoogleChromeの拡張ツールexpressでのルーティングの実装
前回のおさらい
Expressを使ったサーバーで、静的コンテンツのルーティングのためにuse
メソッドやexpress.static
メソッドを利用しました。const express = require('express'); const app = express(); app.listen(8080); app.use(express.static(path.join(__dirname, 'public')));
use
は、全てのタイプのリクエストで実行されます。ルーティングの基本
GETリクエストを受け取る
GETリクエストを受け取りたい場合は、
get
メソッドを利用します。// サイトルートへのGETリクエストの場合 app.get('/', (req, res, next)=>{ res.send('ルートだよ!'); }); // /hoge/fugaへのGETリクエストを受け取りたい場合 app.get('/hoge/fuga', (req, res, next)=>{ res.send('ほげふが'); });POSTリクエストを受け取る
POSTリクエストを受け取りたい場合は、
post
メソッドを利用します。// サイトルートへのPOSTリクエストの場合 app.post('/', (req, res, next)=>{ res.send('ルートだよ!全員集合!'); }); // /hoge/fugaへのPOSTリクエストを受け取りたい場合 app.post('/hoge/fuga', (req, res, next)=>{ res.send('ほげふが'); });パスの指定
get
とpost
いずれの場合も、第一引数にはピックアップしたいサイト上のパスを指定します。この指定は、ワイルドカードや正規表現などを組み合わせることも可能です。app.get(/^book/, ()=>{});上記の例では、
/book
、/books
にはマッチしますが、/boo
、/ibook
とはマッチしません。
公式ガイド:Expressでのルーティングミドルウェアの基本
get
とpost
いずれの場合も、第二引数はリクエストを受け取った際のコールバック関数を渡します。このコールバック関数は、ミドルウェア(中間処理を行う関数)と呼ばれます。
ミドルウェアは、リクエストreq
・レスポンスres
を表すオブジェクトと、後続のミドルウェアへのバトンの役割を果たす関数next
を受け取ります。
このミドルウェア内でクライアントにレスポンスをするか、明示的にプロセスを終了させるかnext()
を実行して他へ制御を渡すかしないと、応答なしの状態に陥ってしまいます。app.get(/^book/, (req, res, next)=>{ if(req.query.id){ res.send('OK.'); }else{ next(); } });res.send
クライアントへHTTPレスポンスを返すためのメソッドです。
文字列だけでなく、配列やオブジェクトも送信できます。事前に指定しなかった場合、ヘッダーのContentTypeは送信データに応じて自動的に割り当てられます。res.end
データ送信をせずにレスポンスのプロセスを終了させるためのメソッドです。
実体はNode.jsのコアモジュールhttp
のresponse.end
です。引数にデータを渡せば送信されますが、res.send
などの専用メソッドを利用する方が望ましいです。送信されたデータを受け取る
GETで送信されたURLパラメータ
GETで送信されたURLパラメータを受け取るには、ミドルウェアに渡された
req
オブジェクトのquery
プロパティにアクセスします。/** * /search?color=red&size=small へのリクエスト */ app.get('/search', (req, res, next)=>{ console.log(req.query.color); // "red" console.log(req.query.size); // "small" });POSTで送信されたJOSNデータ
POSTでJSONデータを受け取るには、予めパース処理を行うミドルウェアを設定しておく必要があります。このミドルウェアは、Expressに予め用意されています。
const express = require('express'); const app = express(); app.use(express.json()); //パース用ミドルウェアを設定 app.post((req, res)=>{ console.log(req.body); //パースされたデータを参照 });Expressの静的メソッド
json
の実行結果をuse
メソッドに渡しています。渡すのはあくまでjson
の実行結果として返されるミドルウェアで、json
メソッドそのものではありません。パースされたデータは、request
オブジェクトのbody
プロパティに格納されます。JSONデータを送る
オブジェクトをパースして送る
オブジェクトをJSONにパースした上で送信したい場合は、
res.json
メソッドを使います。app.get('/', (req, res, next)=>{ res.json({ message: `This is a pen.`}); });JSONファイルを送る
予め用意したJSONファイルを送信したい場合、
res.sendFile
メソッドが便利です。このメソッドは、Expressのバージョン4.8.0以降からサポートされています。app.get('/', (req, res, next)=>{ res.sendFile(__dirname + '/data.json', (err) => { if (err) { res.sendStatus(400); } else { console.log('sending completed'); } }); });第一引数に送信したいファイルの絶対パスを指定します。
第二引数には、送信完了もしくはエラー発生時に呼び出されるコールバック関数を指定します。
エラー発生時はエラー情報を引数で受け取ります。成功時はundefined
です。route()でミドルウェアをまとめる
route
メソッドを利用すると、同一パスに対するタイプ別のリクエストに対し、ミドルウェアを見通し良くまとめられます。app.route('/moimoi') .get((req, res)=>{ // GET }) .post((req, res)=>{ // POST }) .put((req, res)=>{ // PUT }) .delete((req, res)=>{ // DELETE });Routerでルーティング処理を外部モジュール化する
ルーティング処理を他ファイルで定義して、メインの処理にミドルウェアとして組み込むことが出来ます。
ミドルウェアを定義して公開する
Expressの静的メソッド
express.Router
を実行してルーティング用のミドルウェアの骨格を生成します。
この骨格に対して、「このパスへのリクエストはこれ返せ」といったルーティング処理を肉付けしていきます。肉付けの方法は、通常のexpress()で取得したオブジェクトと同様に、use、get、post等を利用します。
そして、完成したミドルウェアをエクスポートして公開します。/** * /api/index.js */ const express = require('express'); const router = express.Router(); //ミドルウェアの準備 router.get('/items', (req, res) => { res.json({ items: [] }); }); router.post('/registration', (req, res) => { res.end('Completed'); }); module.exports = router; //エクスポートして公開公開されたミドルウェアを利用する
公開されたミドルウェアをインポートしてルーティングに適用します。
/** * /app.js */ const express = require('express'); const app = express(); const api = require('./api/'); //ミドルウェア読み込み app.use('/api', api);
/api
へのリクエストの対応を、/api/index.js
で定義したミドルウェアへ渡しています。
この際、ミドルウェア内のルートパスは/api
です。ミドルウェア内で指定した/items
は、実際は/app/items
へのリクエストです。ミドルウェア内で/app/items
としてしまうと、実際には/app/app/items
を指定したことになってしまいます。ガイド:express.Router(日本語)
リファレンス:express.Router(英語)API機能の実装
上記を踏まえて、API機能を実装していきます。
ファイルとフォルダの準備
API関連のファイルを格納するフォルダ
api
を追加します。
このフォルダの配下に、クライアントに送りつけるjsonデータと、ルーティング処理を記述するjsファイルを作成します。sample/ ├ public/ │ ├ css/ │ │ └ sample.css │ ├ js/ │ │ └ sample.js │ ├ img/ │ │ └ sample.png │ └ index.html ├ api/ │ ├ index.js │ └ data.json └ app.js/** * /app.js */ const express = require('express'); const app = express(); const path = require('path'); // /api/index.js で定義されたミドルウェア const api = require('./api/'); app.listen(8080, () => { console.log('Running at Port 8080...'); }); // APIルーティング用ミドルウェアを/apiに設定 app.use('/api', api); app.use(express.static(path.join(__dirname, 'public'))); app.use((req, res) => { res.sendStatus(404); }); /** * /api/index.js */ const express = require('express'); const router = express.Router(); // JSONパース router.use(express.json()); // /api/foo へのGETリクエスト router.get('/foo', (req, res) => { // ファイルを転送 res.sendFile(__dirname + '/data.json', (err) => { if (err) { res.sendStatus(400); } else { console.log('sending completed'); } }); }); // /api/bar へのGET・POSTリクエスト router.route('/bar') .get((req, res) => { // 受け取ったパラメータをそのままJSONにして送り返している res.json(req.query); }) .post((req, res) => { // 必須のデータ項目を、id,name,address として、受信データをチェックしている const nameAry = ['id', 'name', 'address'], failed = nameAry.some(v => !req.body[v]); if (failed) { res.sendStatus(400); } else { res.sendStatus(200); } }); module.exports = router;
/api/data.json
に適当な内容を記述します。{ "id": "W0001", "title": "I Love Cats and Dogs", "price": 3000000000000 }準備が出来たら、サーバーを起動します。
$ node app.js「Advanced REST client(ARC)」で送受信テスト
送受信のテストを、Chromeの拡張ツールの「Advanced REST client」で行いたいと思います。
こちらから取得できます。
ホーム > アプリ > Advanced REST clientARCを起動して、まずはTOPページにアクセスしてみます。
- Methodを「GET」
- RequestURLに「
http://localhost:8080/
」- 「SEND」をクリック
「200 OK」とHTMLデータが取得できました。
では、続けてAPIのデータを取得します。
GETで「http://localhost:8080/api/foo
」へリクエストを送ると、/api/data.json
が取得できます。次は、GETで「
http://localhost:8080/api/bar?name=pee&address=poo&age=17
」へリクエストを送ります。
URLパラメータの値をJSONで取得で取得できます。次は、POSTで「
http://localhost:8080/api/bar
」へリクエストを送ります。
- 「Parameters>Body>Body content type」を「application/jdon」
- 「Parameters>Body>Editor view」を「JSON visual editer」
- id, name, address の三つのプロパティを含むJSONデータを定義
「200 OK」が返ってきました。
次は、項目を一つ減らして送信してみると、「400 Bad Request」が返ってきます。これで、APIの開発が間に合っていなくても何とかなりそうですね!
初心者の拙い記事を読んでいただき、ありがとうございました。
お役に立てていたら幸いです。JSON Server
この記事を書いている途中で、JSONを返すAPIを簡単に実現する「JSON Server」なるものの存在を知りました。。。
JSON Server使いこなし - モックサーバーの起動とリソース処理 | CodeGrid
公式:GitHub - typicode/json-serverリンク一覧
- Node.jsとExpressでローカルサーバーを構築する(1) ―Node.jsとnpmの導入―
- Node.jsとExpressでローカルサーバーを構築する(2) ―Expressでルーティング―
- Node.jsとExpressでローカルサーバーを構築する(3) ―JSONを返すスタブAPI―(本記事)
- Node.jsとExpressでローカルサーバーを構築する(4) ―他サーバーから画像を取得する―(準備中)
参考情報
- 投稿日:2019-02-27T18:07:28+09:00
JQueryでhtmlをincludeする
いまさらJQuery。
概要
html内でフッターやヘッダーなどの共通部分のhtmlをincludeするコード。
htmlを記述する際に同じ部分をたくさん書かずに済む。メンテも楽!コード
共通部分を呼び出したいhtmlファイルの一部。共通部分は
<div class="target"></div>
の中に展開されます。index.htmlの一部<script type="text/javascript" src="includeTemplateHTML.js"> IncludeTemplateHTML("div.target","/Path/Of/templateHTML.html"); </script> <div class="target"></div>共通部分を呼び出すためのJS関数。
includeTemplateHTML.jsfunction IncludeTemplateHTML(selector,filepath){ $(function (){ $.ajaxSetup({cache:false}); $(selector).load(filepath); }); }補足
template自体が共通部分なのでさらにその中の一部分を呼びたい、ということはほとんどないと思いますが、
引数のfilepathをfilepath="/Path/Of/templateHTML.html div#hogehoge"にかえてやればtemplateHTML.htmlのdivタグのid="hogehoge"の内容だけをselectorにインクルードさせることができます。
参考
- 投稿日:2019-02-27T18:02:45+09:00
JavaScriptについての個人的まとめ
この記事について
自分の備忘録として、JavaScript全般についての自分の考えや調べたことを記載していきます。
ほぼリンク集として使用。
経験が浅いので、間違っていることもあると思いますがご容赦ください。小技
事項 説明 参照 イベント処理 イベント、イベントハンドラについて イベント処理/JavaScript イベントリスナー一覧 イベントリスナーについて イベントリスナー一覧/JavaScript JQuery-入力チェック jQuery Validation Engine
を使った入力チェックjQueryで簡単!フォームをリアルタイムで入力チェック
サンプルコードブレークポイントによるデバッグ - ChromeのデベロッパーツールでJSをデバッグする方法(2018年版) 要素に紐づくイベント確認 ボタンを押したらどのイベントが動くかを確認 JavaScript,jQueryの爆速コーディング、デバッグ方法論の勧め エラー対応
事象 説明 参照 資源が読み込めない Failed to load resource: the server responded with a status of 404 (Not Found) Jqueryがテストサーバーで動いていたけど、本番環境で動かない場合
- 投稿日:2019-02-27T16:51:56+09:00
TWAの挙動をPWAに寄せていく(起動編)
先日、TWAサポートライブラリを使用してPWAをAndroidアプリ化してPlayストアから配信する方法を紹介しました。
【実践】Google Play Store でPWA配信 (TWA)
PWAをPlayストアから配信するという目的は達成しましたが、起動時の見栄えがあまり良くないなぁ・・・という状態だったので、少しのコード追加で起動時挙動をPWAに寄せる方法を紹介したいと思います。
PWAとTWAの起動時挙動はどう違うか
PWAとTWAの起動時挙動を比較してみます。
PWAの挙動
TWAの挙動
差分
- 起動時のスプラッシュページがない
- 起動時の画面でActionBarが表示されている(QRとだけ表示されているヘッダー)
- Webページがフェードインじゃなくスライドインで表示される
- Webページ表示中のステータスバーが白くて浮いている
PWAに寄せていく
GitHubのcommitログと共に変更箇所を説明します。
ActionBarを消す
アプリのテーマをDarkActionBarからNoActionBarに変更することで、ActivityのActionBarを消しています。
https://github.com/zprodev/QR-TWA/commit/6d8732fb94840b89792f3b33836fc3f17cad4601
TWAのステータスバーにテーマカラーを反映
元はTWAサポートライブラリで提供されているLauncherActivityをそのまま使用していましたが、LauncherActivityを継承した自前のActivityを使用するよう変更し、ChromeCustomTabのIntentを生成しているメソッドをオーバーライドします。
https://github.com/zprodev/QR-TWA/commit/fb93ee7b87827627f03e7258904333003f3cec7bその上で、リソースとして定義済みのcolorPrimaryDarkをsetToolbarColorでTWAに設定しています。
https://github.com/zprodev/QR-TWA/commit/3944385ce235c405788a0879ef23b13e23dfce3cTWA起動時のトランジションを変更
ステータスバーの色変更と同様に起動時アニメーションを設定することができるので、Alpha変更アニメーションを定義してsetStartAnimationsでTWAに設定しています。
https://github.com/zprodev/QR-TWA/commit/b0ba980f52a8a028ed23ecc8f814662cd0404579結果
変更後の起動時挙動は以下ようになります
スプラッシュページに関しては若干面倒なので省きましたが、デフォルトの状態よりかなりPWAに近づき違和感がなくなったかなと思います。
実機で見てみたい方は↓から試してみてください
PWA: https://qr.zpro.app
アプリ: https://play.google.com/store/apps/details?id=app.zpro.qr
- 投稿日:2019-02-27T15:51:46+09:00
jsオフでも変にならないように年を自動更新
hogehoge.html<span id="copyright-year">2019</span>hogehoge.jsvar date = new Date(); var y = String(date.getFullYear()); var getCopy = $('#copyright-year'); var tx = getCopy.text(); var t = tx + ' - ' + y; if (tx !== y) { getCopy.text(t); }htmlには公開年、もといjs無効の時に見せたい年を書いておく。
jsが動けば、公開から現在までを2018 - 20XX
といったように表示。兼投稿テストでした。
- 投稿日:2019-02-27T13:42:11+09:00
Google Apps Scriptで使えるJSのバージョンについて調査
はじめに
未来になると拡張されてると思うので 2019/02/27 時点での話です。
対応しているバージョン
- https://developers.google.com/apps-script/guides/services/#basic_javascript_features
- 公式にはJavaScript 1.6をベースにしていて1.7と1.8のfeatureも少し入ってるよ、というアナウンス
- 何が入ってて何が入ってないは書いていないので読者の想像に任せられている...
- の記事から各バージョンへのリンクはMDNに向けて貼られているのでMDNでのスペックで調べてます
1.6
feature 対応状況 E4X Arrayの拡張 Array および String の汎用化 1.7
feature 対応状況 ジェネレータ (yield) イテレータ 配列内包 let 分割代入 1.8
まとめ
- 意外と対応していたのでGASがんばってる
- polyfillが使えないんでES7で入った仕様とかはGASだと現状は動きません
- たとえば
Array.prototype.includes
- strictモードのサポートが になっているのはちゃんとエラーになるケースならないケースがあったので部分的に対応してるようだったからです
- 投稿日:2019-02-27T13:02:28+09:00
ml5jsで特徴抽出を用いた回帰を試す
Daniel Shiffmanさんのcodingtrainのチュートリアルを参考に
特徴抽出を用いた回帰(Regression with Feature Extractor)を試してみました。
featureExtractor()メソッドを用いて実装できます。
ml5.js: Feature Extractor Regression
https://www.youtube.com/watch?v=aKgq0m1YjvQ&feature=youtu.befeatureExtractor()
https://ml5js.org/docs/FeatureExtractorファイルは以下にアップしています。
https://www.dropbox.com/s/3cgr99lwuocugwo/03_2_featureExtractorRegression-demo.zip?dl=0コードは以下です。
試す場合は、プロジェクトフォルダに「images」フォルダを設置し、配下に「happy.png」「sad.png」を置いてください。
ライブラリはCDNを読み込んでますのでローカルサーバー上で実行してください。<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Feature Extractor Regression</title> <style> body { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } #inputContainer { position: absolute; top: 10px; left: 10px; } input, button { display: block; margin: 0 10px 10px 0; } </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/p5.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/addons/p5.dom.min.js"></script> <script src="https://unpkg.com/ml5@0.1.1/dist/ml5.min.js"></script> <script src="sketch.js"></script> </head> <body> <div id="inputContainer"></div> </body> </html>let mobilenet; let predictor; let video; let happyIco; let sadIco; let value = 0; let slider; let addButton; let trainButton; // MobileNetモデルの準備が完了したときコールバック関数として呼ばれる function modelReady() { console.log('モデルが準備できた!'); } // ビデオ入力したクラス分類機の準備が完了したときコールバック関数として呼ばれる function videoReady() { console.log('ビデオが準備できた!!!'); } // トレーニング完了時に1度だけ実行される関数 function whileTraining(loss) { if (loss == null) { console.log('トレーニングが完了した!'); // 画像の予測を取得する predictor.predict(gotResults); } else { console.log(loss); } } // トレーニング完了時に再帰的に実行される関数 function gotResults(error, result) { if (error) { console.error(error); } else { // 画像の予測の値を代入する value = result; // 画像の予測を取得する // 再帰的に実行 predictor.predict(gotResults); } } function setup() { // キャンバスを生成する createCanvas(windowWidth, windowHeight); // ウェブカメラから映像をキャプチャし、Video要素を生成 video = createCapture(VIDEO); // Video要素を非表示にする video.hide(); happyIco = loadImage('images/happy.png'); sadIco = loadImage('images/sad.png'); // 背景を黒で塗りつぶす background(0); // MobileNetで事前学習された特徴を展開 mobilenet = ml5.featureExtractor('MobileNet', modelReady); // ビデオを入力にして、回帰のカスタム予測子を生成する predictor = mobilenet.regression(video, videoReady); // スライダーを生成(0 ~ 1) slider = createSlider(0, 1, 0.5, 0.01); slider.parent('inputContainer'); // 「サンプル画像追加」ボタンンを生成する addButton = createButton('サンプル画像を追加する'); addButton.parent('inputContainer'); addButton.mousePressed(function() { // 0 ~ 1の値に画像を紐づける predictor.addImage(slider.value()); }); // 「トレーニング開始」ボタンを生成する trainButton = createButton('トレーニング開始'); trainButton.parent('inputContainer'); // 「トレーニング開始」ボタンが押された時の処理 trainButton.mousePressed(function() { // クラス分類機を再トレーニングする(Transfer Learning 転移学習) predictor.train(whileTraining); }); } function draw() { // 背景を黒で塗りつぶし background(0); // ウェブカメラからの映像をキャンバスに描画 // ミラー表示 imageMode(CORNER) push(); translate(width,0); scale(-1.0,1.0); image(video, 0, 0, width, height); pop(); // 画像の直径は横幅の1/10 let diameter = width / 10; // 円を描画 imageMode(CENTER); // 上下左右に画像を配置 for ( let x = 0; x < width; x += diameter) { for ( let y = 0; y < height; y += diameter) { if (value == 0) { break; // value = 0(初期値)のときは表示しない } else if (value < 0.5) { // 楽しい顔のアイコンを表示 image(happyIco, x + diameter/2, y + diameter/2, diameter*Math.cos(value * Math.PI), diameter); } else { // 悲しい顔のアイコンを表示 image(sadIco, x + diameter/2, y + diameter/2, diameter*Math.cos(value * Math.PI), diameter); } } } // 線を描画しない noStroke(); // 塗りを黒へ fill(0); // 矩形の描画モードを左上へ rectMode(CORNER); rect(0, height - 50, width, 50); // 矩形の描画モードを中央へ rectMode(CENTER); // 塗りつぶしを赤へ fill(255, 0, 0); rect(value * width, height - 25, 50, 50); // 塗りつぶしを白に設定 fill(255); // テキストのサイズを設定 textSize(25); // テキストを描画 text(value, 10, height - 10); } function windowResized() { resizeCanvas(windowWidth, windowHeight); }ローカルサーバーを立ち上げ、ブラウザでindex.htmlを開いたら、
以下の手順でテストしてみてください。
- スライダーを左端までドラッグし、ウェブカメラの前で前でポーズをとって、[楽しい]ボタンをクリックします。約15枚の画像を追加してみてください。
- スライダーを右端までドラッグし、ウェブカメラの前でポーズを変えて、[悲しい]ボタンをクリックします。約15枚の画像を追加してみてください。
- [トレーニング開始]をクリックして、トレーニングプロセスが完了するまで待ちます。 (コンソールログにプロセスが表示されます。)
- トレーニングが完了したら、モデルをトレーニングした2つのポーズを切り替えます。
※カメラのいろんな位置で、ポーズ画像を追加した方が精度が上がるかと思います。
- 投稿日:2019-02-27T12:44:03+09:00
ml5jsで特徴抽出を用いた分類器を試す
Daniel Shiffmanさんのcodingtrainのチュートリアルを参考に
特徴抽出を用いた分類器(Classifier with Feature Extractor)を試してみました。
featureExtractor()メソッドを用いて実装できます。
ml5.js: Feature Extractor Classification
https://www.youtube.com/watch?v=eeO-rWYFuG0&&feature=youtu.befeatureExtractor()
https://ml5js.org/docs/FeatureExtractorファイルは以下にアップしています。
https://www.dropbox.com/s/i7f8fs6wiznzxs6/02_2_featureExtractorClassification-demo.zip?dl=0コードは以下です。
試す場合は、プロジェクトフォルダに「images」フォルダを設置し、配下に「happy.png」「sad.png」を置いてください。
ライブラリはCDNを読み込んでますのでローカルサーバー上で実行してください。<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Feature Extractor Classification</title> <style> body { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } #inputContainer { position: absolute; top: 10px; left: 10px; } input, button { display: block; margin: 0 10px 10px 0; } </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/p5.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/addons/p5.dom.min.js"></script> <script src="https://unpkg.com/ml5@0.1.1/dist/ml5.min.js"></script> <script src="sketch.js"></script> </head> <body> <div id="inputContainer"></div> </body> </html>let mobilenet; let classifier; let video; let happyIco; let sadIco; let label = ''; let preLabel = ''; let happyButton; let sadButton; let trainButton; let count = 0; // MobileNetモデルの準備が完了したときコールバック関数として呼ばれる function modelReady() { console.log('モデルが準備できた!!!'); } // ビデオ入力したクラス分類機の準備が完了したときコールバック関数として呼ばれる function videoReady() { console.log('ビデオが準備できた!!!'); } // トレーニング完了時に1度だけ実行される関数 function whileTraining(loss) { if (loss == null) { console.log('トレーニングが完了した!'); // 画像の予測を取得する classifier.classify(gotResults); } else { console.log(loss); } } // トレーニング完了時に再帰的に実行される関数 function gotResults(error, result) { if (error) { console.error(error); } else { // ラベルに結果を代入 label = result; // 画像の予測を取得する // 再帰的に実行 classifier.classify(gotResults); } } function setup() { // キャンバスを生成する createCanvas(windowWidth, windowHeight); // ウェブカメラから映像をキャプチャし、Video要素を生成 video = createCapture(VIDEO); // Video要素を非表示にする video.hide(); happyIco = loadImage('images/happy.png'); sadIco = loadImage('images/sad.png'); // 背景を黒で塗りつぶす background(0); // MobileNetで事前学習された特徴を展開 mobilenet = ml5.featureExtractor('MobileNet', modelReady); // ビデオを入力にして、既に展開させた特徴抽出でクラス分類機を生成する classifier = mobilenet.classification(video, videoReady); // 「楽しい」ボタンを生成する happyButton = createButton('楽しい'); happyButton.parent('inputContainer'); // 「楽しい」ボタンが押された時の処理 happyButton.mousePressed(function() { // クラス分類機に「楽しい」ラベルを付与して画像を追加 classifier.addImage('happy'); }); // 「悲しい」ボタンを生成する sadButton = createButton('悲しい'); sadButton.parent('inputContainer'); // 「悲しい」ボタンが押された時の処理 sadButton.mousePressed(function() { // クラス分類機に「悲しい」ラベルを付与して画像を追加 classifier.addImage('sad'); }); // 「トレーニング開始」ボタンを生成する trainButton = createButton('トレーニング開始'); trainButton.parent('inputContainer'); // 「トレーニング開始」ボタンが押された時の処理 trainButton.mousePressed(function() { // クラス分類機を再トレーニングする(Transfer Learning 転移学習) classifier.train(whileTraining); }); } function draw() { // 背景を黒で塗りつぶし background(0); // ウェブカメラからの映像をキャンバスに描画 // ミラー表示 imageMode(CORNER) push(); translate(width,0); scale(-1.0,1.0); image(video, 0, 0, width, height); pop(); // 画像の直径は横幅の1/10 let diameter = width / 10; // 円を描画 imageMode(CENTER); // 状態が変更(happy <-> sad)されたらカウンターをリセット if (label !== preLabel) count = 0; // 上下左右に画像を配置 for ( let x = 0; x < width; x += diameter) { for ( let y = 0; y < height; y += diameter) { // 回転のタイミングをずらす let delay = (x / diameter + y / diameter) * 0.2; // 画像のサイズ let scale = Math.min(1, count/90); if (label == 'happy') { // 楽しい顔のアイコンを表示 image(happyIco, x + diameter/2, y + diameter/2, diameter*Math.sin(count * Math.PI / 180 - delay) * scale, diameter * scale); } else if (label == 'sad') { // 悲しい顔のアイコンを表示 image(sadIco, x + diameter/2, y + diameter/2, diameter*Math.sin(count * Math.PI / 180 - delay) * scale, diameter * scale); } } } count+=4; // 前フレームのlabelをキャッシュしておく preLabel = label; } function windowResized() { resizeCanvas(windowWidth, windowHeight); }ローカルサーバーを立ち上げ、ブラウザでindex.htmlを開いたら、
以下の手順でテストしてみてください。
- ウェブカメラの前で前でポーズをとって、[楽しい]ボタンをクリックします。約15枚の画像を追加してみてください。
- ウェブカメラの前でポーズを変えて、[悲しい]ボタンをクリックします。約15枚の画像を追加してみてください。
- [トレーニング開始]をクリックして、トレーニングプロセスが完了するまで待ちます。 (コンソールログにプロセスが表示されます。)
- トレーニングが完了したら、モデルをトレーニングした2つのポーズを切り替えます。
※カメラのいろんな位置で、ポーズ画像を追加した方が精度が上がるかと思います。
- 投稿日:2019-02-27T12:42:24+09:00
JavaScriptでカウントダウンを作る
業務でカウントダウン機能を作る機会があったので備忘録的に。
完成物
html側の設定
index.html<!DOCTYPE html> <html> <head> </head> <body> <p>東京オリンピックまであと</p> <div id="result"></div> <script src="countdown.js"></script> </body> </html>これだけ。
bodyの最後でjsを読み込んでいるのは、後述するが、getElementByIdでresultを読み込むため。JavaScript側の設定
countdown.jsvar endDate = new Date('2020/07/24 00:00:00'); var interval = 1000; function countdownTimer(){ var nowDate = new Date(); var period = endDate - nowDate ; var addZero = function(n){return('0'+n).slice(-2);} var addZeroDay = function(n){return('0'+n).slice(-3);} if(period >= 0) { var day = Math.floor(period / (1000 * 60 * 60 * 24)); period -= (day *(1000 * 60 * 60 * 24)); var hour = Math.floor(period / (1000 * 60 * 60)); period -= (hour *(1000 * 60 * 60)); var minutes = Math.floor(period / (1000 * 60)); period -= (minutes * (1000 * 60)); var second = Math.floor(period / 1000); var insert = ""; insert += '<span class="h">' + addZeroDay(day) +'日' + '</span>'; insert += '<span class="h">' + addZero(hour) + '時'+'</span>'; insert += '<span class="m">' + addZero(minutes) +'分' + '</span>'; insert += '<span class="s">' + addZero(second)+ '秒'+ '</span>'; document.getElementById('result').innerHTML = insert; setTimeout(countdownTimer,10); } else{ var insert = ""; var number = 0; insert += '<span class="h">' + number + number + '</span>'; insert += '<span class="m">' + number + number + '</span>'; insert += '<span class="s">' + number + number + '</span>'; document.getElementById('result').innerHTML = insert; } } countdownTimer();少し解説。
endDateに目標となる日付を与え、それをnowDateと引き算してあげることで目標の日付までの差分を出す。しかしこれだけじゃうまく日や時間、分などに別れていないため、それぞれ分けてあげる。
countdown.jsvar day = Math.floor(period / (1000 * 60 * 60 * 24)); period -= (day *(1000 * 60 * 60 * 24)); var hour = Math.floor(period / (1000 * 60 * 60)); period -= (hour *(1000 * 60 * 60)); var minutes = Math.floor(period / (1000 * 60)); period -= (minutes * (1000 * 60)); var second = Math.floor(period / 1000);ここらへんは、periodをそれぞれの単位に合わせている。
countdown.jsvar insert = ""; insert += '<span class="h">' + addZeroDay(day) +'日' + '</span>'; insert += '<span class="h">' + addZero(hour) + '時'+'</span>'; insert += '<span class="m">' + addZero(minutes) +'分' + '</span>'; insert += '<span class="s">' + addZero(second)+ '秒'+ '</span>'; document.getElementById('result').innerHTML = insert;変数にそれぞれの単位を格納した後は、実際に表示させるためにinsertに入れていく。
spanにそれぞれの値を挟むことで、数字の装飾が出来るようになっている。しかし、そのままの変数で表示しようとすると、1桁の数字の時にサイズが変わって、レイアウトが崩れてしまう。そこでaddZeroを使っている。
countdown.jsvar addZero = function(n){return('0'+n).slice(-2);} var addZeroDay = function(n){return('0'+n).slice(-3);}addZeroDayは、addZeroだけだと3桁の表示の時にレイアウトが崩れてしまうと思ったので、3桁を表示することがあるdayだけに適用している。
書きなぐっただけなので、適宜わかりやすく書き直します....
- 投稿日:2019-02-27T11:57:18+09:00
グローバルインストールなしで nodemon を使用する
はじめに
Node.jsで開発中、修正が終わるたびに再起動するはなかなかの手間になり、
ストレスがたまります。そこでソース修正後に自動再起動してくれるnodemon
の登場です。
nodemon
はグローバルにインストールして使われることが多いようですが、
今回はnodemon
をローカルインストールで動かす方法を調べてみました。インストール
$ npm install --save-dev nodemonこの例では開発依存としてインストールしました。
--save-dev
の代わりに--save
を使用して、通常の依存としてインストールしても問題ありません。package.jsonを編集
その後、
package.json
を以下のようにを編集します。package.json"scripts": { "start": "nodemon index.js" },
index.js
は適宜実行したいファイル名に置き換えてください。サーバーを起動
$ npm start
以上で、ファイル修正後に
nodemon
が自動で再起動してくれるようになりました。
- 投稿日:2019-02-27T11:24:15+09:00
[Vue.js] IME入力時にEnterキーイベントを発火しない様にする
Vue.js ^2.5.16 においてIME-ON時にも
keydown.enter
が発火する様になったらしいので
それを制御するお話
備忘録程度に対策
compositionstart
compositionend
を使いましょうSource
https://forum.vuejs.org/t/how-does-vue-handle-real-enter-event/2169/4See the Pen YgPBye by ?あんじぇあーと? (@shinomiya_ag) on CodePen.
- 投稿日:2019-02-27T10:27:55+09:00
JavaScriptのコーディング面接した際の出題問題(Sort)
JavaScriptのコーディング面談で下記のような問題がでました。
緊張すると頭が真っ白になって、実装できなかったです。
帰りの電車で考えたらあっさりできました。。問題
時間は5〜10分ぐらいです。
const data = `pineapple,160 apple,80 watermelon,160 grape,160 melon,80 mango,170 banana,80 strawberry,170 peach,160 orange,170 kiwi,80 ` // printSortedDataに処理を記載して、shoud print以下の内容が表示されるようにする // 要件はdataの金額でソートする。同一金額はdataの記載順で表示する。 // dataは改行区切りの文字列である const printSortedData = (items) => { } printSortedData(data) // should print // apple,80 // melon,80 // banana,80 // kiwi,80 // pineapple,160 // watermelon,160 // grape,160 // peach,160 // mango,170 // strawberry,170 // orange,170実装例
もっと良い方法や書き方があれば、コメントや編集リクエストを頂けると幸いです。
paizaさんのオンラインエディタとかですぐ確認できて便利でした。
https://paiza.io/ja/projects/new
実装例
const printSortedData = items => { const array_data = items.split("\n").slice(0, -1); const sort_data = array_data.slice().sort(function(a, b) { const a_price = Number(a.split(",")[1]); const b_price = Number(b.split(",")[1]); if (a_price < b_price) return -1; if (a_price > b_price) return 1; return 0; }); // console.log(array_data) // console.log(sort_data) result = sort_data.join("\n"); console.log(result); };所感
初めてのコーディング面談でしたが、日頃から手を動かしてプログラミングしているかが重要であると感じました。
悔しいので、アルゴリズム問題をちょくちょく解いていこうと思います。追記
つとむ( @TsutomuNakamura )さんがbashで書いてくれました!!
bashだと一行で書けるらしいです。スゴイです。
なおとさんの「コーディング面接した際の出題問題(Sort)」をbash で解いてみた
- 投稿日:2019-02-27T10:02:05+09:00
最近知った JavaScript のメソッドや記法の話
概要
こんにちは TOMMY です。
タイトルのとおりですが今日は JavaScript の話です。ぶっちゃけ別に大した内容じゃないんですが、最近こんなメソッドや記法を知って地味に便利で感動しているっていう話を書きたいと思います。String.prototype.padStart()
String.prototype.padStart() - JavaScript | MDN
基本形"1".padStart(2, 0); //=> "01" "12".padStart(2, 0); //=> "12"↓パッと思いつく使い方としては、日付などの 0 埋めなどでしょうか。
月を0埋めしてみる例const date = new Date(); console.log( (date.getMonth() + 1).toString().padStart(2, 0) ); //=> "02"ちなみに 0 埋めだけなら slice を使う手もあります。わりとこっちも好きです。
String.prototype.slice() - JavaScript | MDNsliceを使った例const date = new Date(); console.log( ("0" + (date.getMonth() + 1)).slice(-2) ); //=> "02"ただ、前者のほうが英単語的に何をやっているかが直感的でわかりやすいかと思います。ん?直感的か?と思った方は、詰め物の pad (パッド) って考えればピンと来るんじゃないでしょうか。肩パッドとか、胸パッドとか(ぁ
Template literals (Template strings)
Template literals (Template strings) - JavaScript | MDN
こんなかんじでバッククオートを使うと文字列に式を埋め込むことができます。
使用例1-メソッド呼び出しconsole.log(`現在は${new Date().getFullYear()}年です。`); //=> 現在は2019年です。使用例2-変数const nowYear = new Date().getFullYear(); console.log(`現在は${nowYear}年です。`); //=> 現在は2019年です。使用例3-演算などconsole.log(`現在は${2017 + 1 + 1}年です。`); //=> 現在は2019年です。下記はES5以前でよくやっていた文字列を連結する方法です。
ES6以前からある文字列連結const nowYear = new Date().getFullYear(); console.log("現在は" + nowYear + "年です。"); //=> 現在は2019年です。数が少なければこれでもいいんですが数が増えたり、区切りが細かくなってくると差は歴然としてくるとおもいます。
百聞は一見に如かずということでこちらをご覧ください。
テンプレートリテラルと従来の文字列連結の比較//テンプレートリテラル const template = `現在は${nowYear}年${month}月${date}日(${day})です。` //従来の文字列連結 const concat = "現在は" + nowYear + "年" + month + "月" + date + "日" + day + "です。"明らかにテンプレートリテラルのほうが読みやすいかと思います。ついでに後者は書くのも面倒ですし、油断すると文字列の閉じクオート忘れたりもして余計面倒です(僕だけか
Support
今日紹介したものはどちらもIEはダメです。IEでどうしても使いたい場合は Babel 等によるトランスパイル必須です。IEはほんとWEB開発者泣かせですね
それにしても ES6 にさわりはじめたころは Babel が手放せなかったんですが、近頃は最新版の Chrome や Firefox なら軒並み素で動くようになってきましたね。
もしご存知なかったという方がいらっしゃいましたら、けっこう便利なので機会があればぜひ使ってみてください。
それでは。
- 投稿日:2019-02-27T03:26:14+09:00
Googleスプレッドシート - ボタンを押すだけでメールを送信する機能
今回はタイトル通り、
GASの記述ルールやお作法、変数、定数、型、配列や演算子など様々な基本を複数回に分けて書いていきます!以下様々なGASの記事を紹介してます!
https://bzbot.work/紹介記事
今回紹介している記事は以下です!
https://bzbot.work/2019/02/01/spreadsheet-email-1/GASfunction goGoGmail() { var sheet = SpreadsheetApp.openById('****************'); var add = sheet.getSheetByName('メールテンプレ').getRange(1,2).getValue(); var popUp = Browser.msgBox("送信確認!", add + "へ送信しますか?", Browser.Buttons.OK_CANCEL); if (popUp == 'ok') { var mailSubject = sheet.getSheetByName('メールテンプレ').getRange(2,2).getValue(); var mailBody = sheet.getSheetByName('メールテンプレ').getRange(3,2).getValue(); GmailApp.sendEmail(add, mailSubject, mailBody); Browser.msgBox("送信しました"); } else { Browser.msgBox("キャンセルしました"); } }var sheet = SpreadsheetApp.openById('****************');
にはスプレッドシートのID部分を指定することができます。
それ以外にもActiveのシートとして別の記述をする方法もあります!Toには送信先アドレスをセットします。
Subjectには送りたい件名をセットします。
Bodyには送信したい内容をセットします。送信用シート
送信確認は誤送信を防ぐ意味でもポップアップで通知をしています。
送信確認
最後に送信の完了確認が取れました。
送信完了
どういった場面でManualで送信をする方法でやりたいか?ですが、
これは結構現場によりけりですが、メールフォーマットでスクレイピングをする様なビジネスだったり、メールの文面から判断する様なシステムがあったときに、一度セットしておけばフォーマット変更がない限りずっと使えます。私も仕事でそういった場面があったときに都度送ったりしてましたがどこかに向き先とか指定できるツールがあればなってことでつくってみました。
- 投稿日:2019-02-27T00:49:56+09:00
ワイプスライダーに機能を追加し、プラグイン化してみた
こちらの記事で作ったスライダーに機能を追加し、プラグインとして使えるように拡張しました。
サンプル使い方
ファイルはGithubから一式ダウンロードできます。
https://github.com/Kackie/wipeSlider
※test.htmlは旧バージョン。HTML
外部ファイル読み込み
<link rel="stylesheet" href="css/wipeSlider.css"> <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script> <script src="script/jquery.wipeSlider.js"></script>スライド用のCSSとjQuery、プラグインのJSを読み込みます。
CSSは開いてみればわかりますがすごくシンプルです。必須なのはこれだけです。
ページャー等の見た目の調整はサンプルのHTMLに直書きしています。参考にしてもらっても、自由にスタイルを書くのもよいと思います。スライド部分
<div class="slidesWrap js_wiper"> <ul class="slides"> <li class="slide"> <img src="https://dummyimage.com/980x500/ccc/fff&text=1" alt=""> </li> <li class="slide"> <img src="https://dummyimage.com/980x500/ccc/fff&text=2" alt=""> </li> <li class="slide"> <img src="https://dummyimage.com/980x500/ccc/fff&text=3" alt=""> </li> </ul><!-- / .slides --> </div><!-- / .js_wiper -->一番シンプルな形です。
階層が守られていればulタグ以外でも構いません。jQuery
$('.js_wiper').wipeSlider();最低限これだけ書けば動きます。
$('.js_wiper').wipeSlider({ transition : 1000, auto : true });オプションを設定するとこんな感じです。
オプション設定
ラベル 機能 transition スライドが切り替わるときの速度を設定します。
初期値は500。auto 自動再生を設定します。
初期値はfalse。duration 自動再生時、スライドの表示時間を設定します。
初期値は4000。pager ページャーを生成します。
初期値はtrue。controls 前後のスライドに切り替えるコントローラーを生成します。
初期値はtrue。その他の仕様
表示中のスライドにはactiveクラスが付きます。
これを使用して、スライド内のインタラクション作成に役立ててもらえればと思います。前回のバージョンでは、別タブでページを閲覧してから戻ってくると、アニメーションがおかしくなってしまうことがありました(setIntervalの仕様ですが)。
タブが非アクティブ時にはclearIntervalがかかり、戻ってくるとsetIntervalが再発動するようになっています。感想と反省
プラグイン自作初挑戦です。意外と簡単ですね。
前回作った元のスライダーがシンプル過ぎたので、最低限スライダーのプラグインに必要になるであろう機能を追加しておきました。
表示中のものより前のスライドに移動したときは逆方向にアニメーションさせたりとか、ユーザー設定でアニメーション方向を自由に帰らるようにしたかったのですが、アニメーションをCSSのtransitionでやっているがためにclipの再設定ができないという問題に直面し断念。。
backFlag
という変数をつくり、戻る動作のときはbackFlag = true;
となるようにしたもののそのままうまく扱えていないです。
keyframesを動的生成はできなさそうだし、やるとしたらanimateメソッドのstepを使うことになるのだろうか・・?
時間がかかりそうだったのでひとまず公開してしまいましたが、これはなんとか作ってみたいのでじっくり考えてみることにします。せっかくなのでクレジットを入れようと思ったのですが書き方がわかりませんでした(恥)。
- 投稿日:2019-02-27T00:40:00+09:00
ANGULAR.JS公式チュートリアルのPhoneCat Tutorial Appはじめました。
ANGULAR.JS公式チュートリアルのPhoneCat Tutorial Appはじめました。
なぜ始めたのか?
業務でJavascriptのwindowオブジェクトの操作とJasmineのUTをやる機会が
あったので、これを機会にJavaScriptの知識を深めたいと思い、テーマを探していました。目に留まったのがGoogleなどが開発を手掛けたAngularJSが有名!などという情報が入ってきたので、公式ページにあったチュートリアルを試してみることにしました。
電話のカタログページを使ったチュートリアルみたいですね。参考:https://docs.angularjs.org/tutorial
ひとまず、今回は環境構築から始めたいと思いまっす。
前提
・Gitがインストールされていることを前提として進めます。
環境構築
繰り返しになりますが、今回は環境構築がメインです。
まずはangular-phoncatのリポジトリをクローンして
クローンしたフォルダをカレントディレクトリにします。git clone --depth=16 https://github.com/angular/angular-phonecat.git cd angular-phonecat--depth=16のオプションは最新16件分のコミットのみ抽出するらしいです。
ダウンロード速度を考慮して設定してるみたいですね。次に依存関係を解決するためにNode.jsをインストールします。
これは事前設定されているローカルWEBサーバの実施に使うみたいです。インストーラはOS毎に分かれているので公式ページから適切なものをダウンロードしてインストールしてください。
参考:https://nodejs.org/en/download/
Node.JSについてよくわからなかったので調べてみたところ、サーバでJavaScriptを実行できるようにするための
プラットフォームらしいです。
まずは使ってみて雰囲気つかんでみて、気になるとこがあったら詳細に調べてみたいと思います。インストールが完了したらコマンドラインで次のコマンドを叩いて正常にインストールされた事を確認します。
ちなみに、2019年2月26日現在ではv10.15.1が推奨される最新のNode.jsです。
11.10.0も公開されていましたが、安定している方を選びます。node --versionNode.jsをインストールしたらnpmも取得されます。
npmはパッケージ管理ツールでNode.jsのパッケージを管理するのに使用します。
まずは依存関係をインストールしてみます。npm install完了したら実際にWEBサーバを起動してみましょう!
デフォルトの設定ではポート8000をリスナーとするlocalhostが作成されるはずです。npm start起動に成功したらhttp://localhost:8000/index.htmlにアクセスしてみましょう。
こ、これがAngular.jsを使ったページか!めっちゃカッコいい画面やんけ!って画面が表示されれば成功です。さて、まだ環境構築は終わりではありません。
次は単体テストの機能が正常に動作するか確認します。angular.jsはKarmaを使って単体テストするように構築されています。
さっそくKarmaを起動してみます。
起動はnpmの以下コマンドでできます。npm testChromeのブラウザが起動してKarmaの画面が表示されます。
今回はKarumaの勉強に焦点を当てるわけではないので、いったん此処まで。次にテストツールのE2E(エンドツーエンド)の確認です。
このプロダクトはユーザとブラウザの対話をシュミレートすることでテストします。WEBサーバが起動した状態で、別のコマンドラインを起動して、次のコマンドを実行します。
npm run protractorすると、ブラウザが起動してアプリケーションを自動でテストし始めます。
検索用テキストボックスに勝手に文字が入力されて検索されたりと少し驚きますが、これによりE2Eのテストが自動化できる仕組みっぽいです。
たぶん別途specを用意する必要があるんだと思いますが、これは別の機会に勉強します。今回はここまで!
参考:https://docs.angularjs.org/tutorial/step_01
マークダウンは後程なおします。
おやすみなさい。
- 投稿日:2019-02-27T00:12:54+09:00
ランダムな文脈表示
100分de名著の太宰治「斜陽」(高橋源一郎著)に感銘を受けた。
そして、そのノリのまま、webアプリを一つ作成した。http://world-l-word.com/dazai/index.html
特徴:小説「人間失格」から、文脈をランダムに表示するもの。
データ:青空文庫から適当に。
- 投稿日:2019-02-27T00:08:10+09:00
JavaScriptのvar、let、constの違いを恋愛に置き換えて説明してみる。
JavaScriptの変数宣言Var,let,constについて恋愛に置き換えて説明してみました。
主人公は花子ちゃんです。
varの場合
花子ちゃんは同じクラスの太郎くんが好きだと宣言するとします。
var my_crush = "太郎くん"; console.log(my_crush); // 太郎くん;しかし、二郎くんを好きになってしまった場合、後から宣言し直すことができます。
var my_crush = "二郎くん"; console.log(my_crush); // 二郎くんletの場合
同じく花子ちゃんは同じクラスの太郎くんが好きだと宣言するとします。
let my_crush = "太郎くん"; console.log(my_crush); // 太郎くん;次に二郎くんを好きになってしまったとしても、宣言し直すことができません。
let my_crush = "二郎くん" ; console.log(my_crush); // エラーしかし、ひっそりと好きな人を二郎くんにすることは可能です。
my_crush = "二郎くん"; console.log(my_crush); // 二郎くんconstの場合
上記同様、花子ちゃんは同じクラスの太郎くんが好きだと宣言するとします。
const my_crush = "太郎くん"; console.log(my_crush); // 太郎くん;次に二郎くんを好きになってしまったとしても、let同様宣言し直すことができません。
const my_crush = "二郎くん"; console.log(my_crush); // エラーさらにひっそりと好きな人を変えることもできません。
my_crush = "二郎くん"; console.log(my_crush); // エラーまとめ
constは最も一途
letは見かけ上一途
varは一途ではないが、いさぎが良い