最近読んだ漫画 (と CSS で感想の表示・非表示を切り替えてみるテスト)
あまり人に漫画を勧める時に感想って言いたくない。 けど自分はしょっちゅうブログのデザインを変えるので、単純に背景色と同じにするだけだとテーマを変えた場合に隠したはずの文章が見えてしまう。 それはあまりにもあんまりなので、CSS で感想の表示・非表示を切り替えられるようにしてみた。
案1:シンプルにチェックボックスで切替え
※チェックボックスをオンにしてみてください。
はてなブログの場合、設定画面の「デザイン」→「デザインCSS」から追加の CSS を定義できるのでそこに以下の記述を追加。 あと Markdown じゃないと HTML は書けないかも (たぶん)。
label.toggle-opacity > span { opacity: 0; } label.toggle-opacity > input[type=checkbox]:checked + span { opacity: 1; }
でブログ本文に書くときはこう。
<label class='toggle-opacity'><input type='checkbox'><span>テスト</span></label>
ちょっと書くのが面倒だけどそう使わないだろうし、コピペするなり辞書登録するなりしてしまえばいい。
案2:<details>
+ <summary>
…でさらにちょっとリッチなボタン形式で表示させてみるかーといろいろ HTML5 のタグを調べてたら、
こういう場合(?)に便利な <details>
タグ + <summary>
タグというものを発見。こう使う。
<details> <summary>(感想は省略されました。読むにはここをクリックしてください)</summary> 主人公がかっこよかった(小並) </details>
で、こうなる。
(感想は省略されました。読むにはここをクリックしてください)
主人公がかっこよかった(小並)
HTML5 のタグなので CSS は一切使ってない。 感想部分の文章にインデントを加えたい場合とかは CSS でごにょごにょすればいいだろうけど、自分はもうこれでいいや。
案3:リッチなボタン風
…と思ってたんだけど、自分が考えてた「リッチなボタン形式」のデザイン案もそれなりに実現してみたかったのでちょっとやってみた (完全にやりたいだけ)。
正直デザインより機能性を求めてしまう自分はもう <summary>
タグでいいやって気分になってたけど、
せっかく作ったのでこの記事で使ってみたら結構いい感じだったので良かった。
案としてはこんな感じ。
- チェックボックスじゃなく代わりに自由なテキストを表示させる
- テキストは表示時/非表示時で切り替えられる
- ちょっとリッチなボタン形式で表示
そのデモがこちら。
HTML はこう (長い)。
<label class='toggle-opacity-text'> <input type='checkbox'> <span class='tot-enable'>感想を読むにはクリック</span> <span class='tot-disable'>感想を非表示にする</span> <span class='tot-body'>ねーねー本の感想は?</span> </label>
CSS はこう (長い)。 クラス名はさっきのと変えてます。
label.toggle-opacity-text > .tot-disable, label.toggle-opacity-text > .tot-body, label.toggle-opacity-text > input[type=checkbox] { display: none; } label.toggle-opacity-text > input[type=checkbox]:checked ~ .tot-enable { display: none; } label.toggle-opacity-text > input[type=checkbox]:checked ~ .tot-disable { display: inline; } label.toggle-opacity-text > input[type=checkbox]:checked ~ .tot-body { display: block; } /* ちょっとリッチなボタン風 */ label.toggle-opacity-text > .tot-enable, label.toggle-opacity-text > .tot-disable { color: #fff; font-weight: bold; background-color: aqua; padding: 5px 10px; border-radius: 1em; } /* ついでに枠もつけてみた */ label.toggle-opacity-text { padding: 10px; display: inline-block; border: 1px solid white; }
- (2016/07/18 23:42 追記) 「ボタンのテキストの選択を無効」を追加。
- (2016/07/19 23:15 追記) スマホで感想が丸見えになっていたのでブログをレスポンシブ化した。
- (2016/07/19 23:23 追記) Android Chrome でテキスト部分のタップが認識されなくなっていたので、やはり「ボタンのテキストの選択を無効」を削除。削除したコードは以下の通り。
/* ボタンのテキストの選択を無効 */ label.toggle-opacity-text > .tot-disable, label.toggle-opacity-text > .tot-enable { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }
結局 HTML が <span>
タグの嵐になってしまった。
さすがにブログの記事で気軽に使えない *1 ので、
それを避けるために適切な HTML タグを探していて偶然 <summary>
タグに行き当たった訳だけど、
目的は叶えられたのでとりあえずこれはこれでよしとする。
漫画の感想
という訳でおまけみたいな感じになりつつある漫画の紹介。横道ばかりの人生。
感想だけだと非表示にしてしまったらジャンルも分からなくなるので、 せめてジャンルだけ1行で紹介するようにしてみようかなーと思ったけど、 ジャンルというくくりも微妙にしっくり来ない… ジャンルで興ざめされたり敬遠されてしまうのは悲しいし、 個人的に作品に感じるジャンルやテーマは人それぞれだと思うので、いっそジャンルも隠すようにしてみた。
あとジャンルも各成分の % で表記するようにしたので、「それは違う」ってジャンルが含まれてるのもあるかも。 あと % って言っても適当なのであまり気にしないでください。
なのは洋菓子店のいい仕事
- 作者: 若木民喜
- 出版社/メーカー: 小学館
- 発売日: 2015/08/14
- メディア: Kindle版
- この商品を含むブログを見る
ジャンル
ファンタジー(10%) 青春(20%) ラブ(25%) コメ(25%) 菓子(20%)
ねじの人々
- 作者: 若木民喜
- 出版社/メーカー: 小学館
- 発売日: 2015/10/16
- メディア: Kindle版
- この商品を含むブログを見る
ジャンル
青春(10%) ラブ(10%) コメ(30%) 哲学(50%)
いかづち遠く海が鳴る
- 作者: 野田彩子
- 出版社/メーカー: 小学館
- 発売日: 2015/09/11
- メディア: Kindle版
- この商品を含むブログを見る
ジャンル
ファンタジー(70%) 恋愛(30%)
ノラガミ
Kindle 版が今0円だった。
- 作者: あだちとか
- 出版社/メーカー: 講談社
- 発売日: 2014/01/17
- メディア: Kindle版
- この商品を含むブログを見る
ジャンル
ファンタジー(40%) 恋愛(30%) 友情(20%)
キレる私をやめたい
キレる私をやめたい ?夫をグーで殴る妻をやめるまで? (バンブーコミックス エッセイセレクション)
- 作者: 田房永子
- 出版社/メーカー: 竹書房
- 発売日: 2016/06/30
- メディア: Kindle版
- この商品を含むブログを見る
ジャンル
ノンフィクション(50%) メンタルヘルス(50%)
※ノンフィクション 50% は嘘という訳ではない
さびしすぎてレズ風俗に行きましたレポ
- 作者: 永田カビ
- 出版社/メーカー: イースト・プレス
- 発売日: 2016/06/30
- メディア: Kindle版
- この商品を含むブログ (2件) を見る
ジャンル
ノンフィクション(40%) メンタルヘルス(30%) 性(30%)
※ノンフィクション 40% は嘘という訳では(ry
僕が私になるために
- 作者: 平沢ゆうな
- 出版社/メーカー: 講談社
- 発売日: 2016/06/23
- メディア: Kindle版
- この商品を含むブログを見る
ジャンル
ノンフィクション(50%) 性(50%)
MAJOR 2nd
MAJOR 2nd(メジャーセカンド)(1) (少年サンデーコミックス)
- 作者: 満田拓也
- 出版社/メーカー: 小学館
- 発売日: 2015/07/10
- メディア: Kindle版
- この商品を含むブログを見る
ジャンル
青春(50%) 野球(50%)
週刊少年ガール
- 作者: 中村ゆうひ
- 出版社/メーカー: 講談社
- 発売日: 2014/05/16
- メディア: Kindle版
- この商品を含むブログを見る
ジャンル
ファンタジー(34%) 青春(33%) 恋愛(33%)
スペシャル
- 作者: 平方イコルスン
- 出版社/メーカー: リイド社
- 発売日: 2016/04/11
- メディア: Kindle版
- この商品を含むブログ (1件) を見る
ジャンル
ギャグ(50%) 青春(50%)
彼とカレット。
- 作者: tugeneko
- 出版社/メーカー: KADOKAWA / アスキー・メディアワークス
- 発売日: 2013/09/21
- メディア: Kindle版
- この商品を含むブログを見る
ジャンル
ギャグ(40%) エロ(ネタ)(30%) かわいい(30%)
ぱら☆いぞ
- 作者: 道満晴明
- 出版社/メーカー: ワニマガジン社
- 発売日: 2013/09/12
- メディア: Kindle版
- この商品を含むブログを見る
ジャンル
エロ(100%) 頭おかしい(100%) 天才(100%)
AIの遺電子
- 作者: 山田胡瓜
- 出版社/メーカー: 秋田書店
- 発売日: 2016/04/08
- メディア: Kindle版
- この商品を含むブログ (1件) を見る
ジャンル
SF(50%) 未来(25%) 友情とか恋愛とか(25%)
木根さんの1人でキネマ
- 作者: アサイ
- 出版社/メーカー: 白泉社
- 発売日: 2015/12/25
- メディア: Kindle版
- この商品を含むブログ (8件) を見る
ジャンル
ギャグ(40%) 映画(40%) 友情(10%) シェアルーム(10%)
服を着るならこんな風に
服を着るならこんなふうに(1)<服を着るならこんなふうに> (カドカワデジタルコミックス)
- 作者: 縞野やえ,MB
- 出版社/メーカー: KADOKAWA / 角川書店
- 発売日: 2015/12/10
- メディア: Kindle版
- この商品を含むブログを見る
ジャンル
ファッション(70%) 妹かわいい(20%) こんな妹いるか(10%)
setInterval() を requestAnimationFrame() に変えてもカクカクさせない方法
前提知識
まず requestAnimationFrame() は setInterval() と同じで定期的にコールバックを実行する API。
- アニメーションを実装するなら知っておきたい「requestAnimationFrame」の使い方 | 株式会社LIG
- HTML5 で、コンピューター ハードウェアをより効率的に使用する: 新しい Web パフォーマンス API – パート 1 – Internet Explorer ブログ (日本語版)
- パフォーマンスの基本 - Mozilla | MDN
requestAnimationFrame() を使うことによるメリットは以下の通り。
- タブがバックグラウンドになった時に fps を落として実行される
- ブラウザの描画更新単位と同じ単位で呼び出される
よって
- 低メモリ消費
- 省電力
しかし setInterval() で書いていた処理を requestAnimationFrame() に書き換えるに当たって一つ問題がある。 それは実行する間隔を指定できないこと。 setInterval() は第2引数でミリ秒でコールバックが呼ばれる間隔を指定できる。 しかし requestAnimationFrame() が受け付けるのはコールバックのみ。 ブラウザの描画更新単位と同じ単位で呼び出されるため効率の良い API だが、呼ばれる間隔はまちまちになってしまう問題がある (大体 60 fps と言われているが、バックグラウンドになった際にはもっと低 fps になるらしい)。
コールバックを実行するタイミング指定できない問題をどうにかする
自分は今回糸通しのゲームで requestAnimationFrame() 対応したかった。 このゲームはPCとスマホ両対応といいつつ自分が暇な時に触りたいので圧倒的にスマホの需要のほうが大きい。 しかし FPS を制御できないのはアクションゲームにとっては致命的。 だけど冒頭に挙げたメリットはスマホにとってうれしいことばかりだったのでそれなりに対応したい問題だった。
そこで検索したら以下の記事がヒットした。
requestAnimationFrame のタイミングにたよって値を変えるするというのではなく、経過時間を管理し再描画のタイミングで「経過時間に合わせたフレーム」を表示してやればよさそうです。
上記の記事では「経過時間に合わせたフレーム」を表示するために描画の対象を「コマ割り」し、フレームごとのコマを描画している。 ただ、自分の場合はゲームのメインループをカクつかせずに回す方法が知りたかった。 ゲームはユーザの入力が絡むシーンが大半なので単純にコマ割できず、 毎フレームごとにじりじり座標を更新していかなければならない場合が大半なのでどうすべきか考えた結果、 その方法が割と上手くいったので共有してみる。
解決策
やりたいことは以下のような感じです。
setInterval() を使うなどして FPS を固定させた場合のそれぞれのオブジェクトの移動量を100%とした時、 前回との経過時間から「実際の FPS」を計算し、「想定している FPS」と比較して割合を出します (70%とか120%とか)。 そしてその割合を移動量に掛けることで描画のタイミングがバラついても移動量は FPS 固定の時と同じ移動量になる(はず)なので、 カクつくことなく描画できます。
より分かりやすく実際のアルゴリズムで書いてみると以下の通りです。
- 1回の移動量に対する割合を計算する
- 描画した時の時間を覚えておく
- その計算量に応じてオブジェクトを移動させる
実際のコードはこんな感じです (色々省略してます)。
ito-to-shi/app.js at 65634edaa427a53649f8ac825e71c97b05c36097 · tyru/ito-to-shi · GitHub
update() { // 1. 1回の移動量に対する割合を計算する // 注意:この関数では経過時間しか計算していないので嘘コメントです。 // 実際はそれぞれのオブジェクトで経過時間から割合を計算しています。 const now = Date.now(); const elapsedMs = now - this._prevUpdatedTime; // 2. 描画した時の時間を覚えておく this._prevUpdatedTime = now; // 3. その計算量に応じてオブジェクトを移動させる // (計算量である elapsedMs をそれぞれの画面のオブジェクトに渡して座標を移動して描画してもらっている) screen.update(elapsedMs); }
で呼ばれた update() メソッドの冒頭で割合を出しています。
ito-to-shi/running.js at 65634edaa427a53649f8ac825e71c97b05c36097 · tyru/ito-to-shi · GitHub
update(elapsedMs) { const movePercent = elapsedMs / constant.THE_FPS; // (省略) }
ちなみに 30 FPS の想定ですが、constant.THE_FPS = 1000.0 / 30.0
となっていて非常に紛らわしい変数名になってました… *1
なので上の処理は movePercent = 経過時間(ミリ秒) / 1フレームにかかるミリ秒
になります。
100 ms かかる想定が 200 ms かかったら 2.0 (=200%) です。
その場合は2フレーム分オブジェクトを移動させればいいですね。
失敗例
逆に失敗した方法は、想定している FPS 分の経過時間が経っていなかったら座表計算や描画をスキップする方法です。 これだとスキップした時には当然描画は行われないため、カクついてしまいます (この件で描画全体をスキップするのではなく毎回描画は行う方法でないとカクつくんじゃないかと思って冒頭の方法に変えた)。
ito-to-shi/app.js at f29fae827b02d238ca753ff20f60ad69cbfb3a6e · tyru/ito-to-shi · GitHub
update() { // Skip if main loop was called too early. const now = Date.now(); const stepFrames = Math.floor((now - this._prevUpdatedTime) / constant.THE_FPS); if (stepFrames > 0) { this._prevUpdatedTime = now; } // Update screen. const dispatcher = this._screenDispatcher; const screen = dispatcher.screens[dispatcher.screenId]; if (screen && screen.update) { screen.update(stepFrames); } }
stepFrames > 0
の時のみ「描画した時の時間を保存&呼ばれた update() メソッドで描画」しているため、小数点以下が考慮されていません。
呼ばれた update() メソッドは以下の通り。
ito-to-shi/running.js at f29fae827b02d238ca753ff20f60ad69cbfb3a6e · tyru/ito-to-shi · GitHub
update(stepFrames) { for (let i = 0; i < stepFrames; ++i) if (!this._doUpdate()) break; }
前回の経過時間から描画するフレーム数ごとに描画関数を呼ぶようにしただけ。 名前は変わってますが movePercent と stepFrames は同じ値ですね。 この方法だとstepFrames=0.7(70%)とかの場合、ループは1回も回りません。
実際のデモ
(この記事のデモのつもりじゃないけど) 実際に以下のリンクから遊べます。
一応前のバージョンと比較してプレイしてみたかったので、前のバージョンもプレイ可能にしてみた。
前のバージョンと比べると普段の操作はむしろ前よりもヌルヌルになった気がします (ブラウザからすると setInterval() の方が非効率な API なんでしょうね…)。 ちなみに前のバージョンは色々バグっていたのでそこはあまりツッコまないでください。
*1:今は修正済み。あとついでに movePercent もダサい名前で変えたい…けど良い名前が思いつかない
現代的な React の書き方へのリンク
React 初心者を対象とした記事です。昨日の記事からの続き。
- React、Redux、D3を用いたアニメーション | プログラミング | POSTD
class App extends Component { ... }
ってなんだろ- React v0.13.0 Beta1でclassでComponentが作れるようになった - blog.koba04.com
- React が ES6 classes 使ってカッコよく書けるようになったらしい
this.refs.svg
ってなんだろ- 今からはじめるReact.js〜propsとstate、それからrefs〜 - Qiita
- ReactDOM.findDOMNode() というのと refs というのを使って DOM を参照できるらしい
- getDOMNode() というのもあったが Ver0.14 で非推奨となった
- 用途としては HTML の name 属性みたいな感じ?
App.propTypes = { ... }
ってなんだろ- React.jsのProp - Qiita
- (簡易的な) 型チェック?
import
そういや最近見るようになったけどよくわからない…- 【古い記事】Babelで理解するEcmaScript6の import / export - Qiita
- 記事では MDN 見た方が良いと書かれてるけど
require()
使った書き方との比較が分かりやすかったので
ES6版React.jsチュートリアル - Qiita もオススメ。
差分で見る現代化のようす
Rewrite in ES6 style · tyru/hello-react@22d4e7e · GitHub
-const React = require('react'); -const ReactDOM = require('react-dom'); +import React from 'react' +import ReactDOM from 'react-dom' -const Hello = React.createClass({ - render: function() { +class App extends React.Component { + render() { return ( - <div className="container">Hello {this.props.name}</div> + <div className="container">Hello React in ES6 style</div> ); } -}) +} -ReactDOM.render(<Hello name="React" />, document.getElementById("app")); +ReactDOM.render( + <App />, + document.getElementById("app") +);