No Regrets in Bathing

カレーを週に一度食っていく

気が散らない作業BGMサービス「#作業してくる」

普段のコーディング中のBGM、基本的にSoundCloudなんだけど、下記が不満だったりする。

  • まず最初に曲を見繕う作業で時間を10分とか使ってしまう
  • ずっと聞いてると気が散るイベントが発生する
    • 全然違うジャンルに飛ばされる
    • 今ひとつ音の合ってないマッシュアップが流れたりする
    • 探し方次第だけど、レーベルの宣伝用ラジオとかも入ってきてしまう事がある
  • DJMIXは気が散りにくくていいけど、なんか気分じゃない時がある
    • 多分踊るにはいいけど、長時間聞くには疲れる

こういう感じで、曲を飛ばす作業が発生してコーディングが中断してしまうということがよくあった。

環境音は猫が最強

で、環境音が良さそうということで、色々試していた。

www.noisli.com

ここがそれなりに良いのだけど、環境音でもイライラしたりすると気が散ることがあった。「何このせせらぎ、オフィスに川なんてねえぞ!イライラしてきた!!!!」みたいな感じで。

で、環境音系で一番使ってたのはここ。

purrli.com

こっちのほうが良いです。猫がゴロゴロ言ってるのを延々と聞ける。youtubeにも似たコンセプトの動画が上がってるけどそれもリアリティがあって良いです。なんか、膝上に猫が来て思う存分くつろいでて、 自分もなんか西日とかで温くなってしまって、やることあるんだけど動けなくて一緒に寝ちゃうみたいな、最高なやつをVR体験出来ます。今思ったけど、膝に何か重いものを置くといいだろうな。

でもこれでリラックス出来るのは猫ユーザーだけだと思う。

「作業してくる」の認知負荷の低さ

しかしメロディが欲しいし、昔のMIDIが恋しいなと思っていた所で、「#作業してくる」というサービスが公開された。(曲提供したのでダイマ気味だけど)

f:id:hashrock:20171211010543p:plain

sitekuru.net

ここ数日使ってるけど良いです。

何が良いかというと、とにかく聞いていて認知負荷が低い。作業してくる自体のことを意識することがほとんどない。

  • 曲数が多くて100曲くらいある
  • 曲の雰囲気やテンポが揃っている
    • 時間帯ごとにテーマが決まっている
    • 激しい曲は深夜など、特定の時間帯に流れるようにまとめられている
  • 全体的に打ち込みっぽくて、ボーカルがない
  • ループがシームレス(WebAudioでループさせているらしい)

特に、曲間の空白が気にならないというのは本当に良い!

全体的にどうぶつの森みたいな、ほっとする感じのゲームBGMっぽいのが多くて、自分は好きな感じの曲が多いかな。 1曲気に入ったらだいたい全部気に入るだろうし、1曲合わなかったらほとんど合わないと思う。 これは、企画時にリファレンス楽曲が提示されていて、雰囲気合わせが上手く行ったということだと思う。

サイトの企画者は「cagpie」さんという人で、わずか1ヶ月の間に100人以上の作曲者を集めて、かなりの曲数が集まった。おそらくその多くが書き下ろしだと思う。 下記の募集告知からどういう企画だったかが窺い知れる。

作業用BGM垂れ流しサイト「#作業してくる」の楽曲募集! - TwiPla

技術的なことに関しては下記に書いてある。

qiita.com

cagpieさんは、picotuneの作者でもあったりと、多才だしこれからが楽しみ。

ちなみに、曲一覧は右下の「配信楽曲一覧」で出せて、そこから曲名直接クリックでも聞ける。

f:id:hashrock:20171211015834p:plain

f:id:hashrock:20171211015916p:plain

今のところ考えた作業BGMの流れ

やっぱり気分に応じて色々使い分けられるようにするのが良さそう。

  • とりあえずやる気が無いときは、SoundCloudのお気に入りとかハードコアテクノとかを流して気付けをする
  • 猫のゴロゴロを徐々にミックスし、落ち着いて資料などを眺めて計画を練る
  • 作業内容が決まったら、作業してくるを立ち上げ、slackの分報チャンネルに作業開始宣言

って感じですかね。あとはamazon musicとかのストリーミングサービスもいいと思う。みんなのおすすめがあればtwitterにリプしてください。

グリグリ動くUIをVueとSVGでサクッと書く

これは Vue.js #3 Advent Calendar 2017 – Qiita 4日目の記事です。

こんにちは。SVGで色々なコンポーネントを作っているものです。最近の作品は下記のような感じです。

f:id:hashrock:20171204200705g:plain

f:id:hashrock:20171204200933g:plain

Webでグリグリ動くUIを作りたい!!という一心でやっています。

これらはほとんどSVGとVueの組み合わせのみで作っています。依存が少ないというのは大事で、ライブラリ間の相性でハマったり、いろんなドキュメント間を往復することがなくなります。

Webでグリグリ動くUIを作るのは基本的にめんどくさいです。jQuery pluginを駆使して作るのも闇が多いですし、divやcanvasをゴリゴリするのも結構手間がかかります。

ですが、最近はSVGで高度なUI実装されることが増えてきた気がします。特に自分が衝撃を受けたのは、CacooがFlashからSVGにスイッチしたことです。

nulab-inc.com

SVGに遅いイメージを持っていた自分にとってこのニュースは衝撃的で、SVGやれば出来るじゃん!と勇気づけられました。というわけで、VueがSVGを標準で扱えることもあって、最近はSVGのポテンシャルを試していたわけです。他にもMSのSarahさんのVueConfでの発表もきっかけの一つでした。

SVGcanvasに比べて出来ることが多いわけではないのですが、だいぶ実装の手数が削減できます。サクッと実装できるかどうかの差は大きく、僕はこれでグラフィカルなUIを書こうというモチベーションが湧いてくるようになりました。 ※個人の感想です

SVGの基本的な使い方&バインディング

で、どのくらいサクッとなのかというと、例えば線を引きたければ、下記のように書くだけです。

<svg viewbox="0 0 300 300" width="300" height="300">
  <line x1=100 y1=100 x2=200 y2=200 stroke="black"></line>
</svg>

f:id:hashrock:20171204203229p:plain

で、canvasとは違って、この線はDOM要素なので、Vue.jsを使うとバインディングが効きます。すなわちこういうことが出来ます。

f:id:hashrock:20171204203728g:plain

コードはこれだけです。

<div id="app">
  <svg viewbox="0 0 300 300" width="300" height="300">
    <line :x1="x1" y1=100 x2=200 y2=200 stroke="black"></line>
  </svg>
  <div>
    <input type="range" v-model="x1">
  </div>
</div>
<script>
  new Vue({
    el: "#app",
    data: {
      x1: 100
    }
  })
</script>

バインディングが出来るフレームワークであれば、VueでなくてもReactでもRiotでもElmでもいいのですが、とにかくSVGバインディングとの相性が良いです。バインディングだらけになるとスパゲッティになる懸念がありますが、コンポーネントに切り分けることである程度防ぐことが出来ます。

SVG要素にイベントリスナをつける

また、SVG要素はイベントリスナをひっつけられます。例えば円をクリックした時にmethodを呼びたければ、これだけで良いです。

<circle @click="myMethod" cx=100 cy=100 r=50></circle>

これを利用して、クリックした時にトグルする何かを作りました。

f:id:hashrock:20171204211409g:plain

<svg viewbox="0 0 300 300" width="300" height="300">
  <circle r=50 cx=150 cy=150 @click="active = !active" :class="{'active': active}"></circle>
</svg>
new Vue({
  el: "#app",
  data: {
    active: false
  }
})
circle{
  fill: #333;
  transition: all 0.4s cubic-bezier(.96,.04,.04,.96);
  stroke: rgb(119, 0, 255);
  stroke-width: 1px;
}
.active{
  fill: white;
  stroke-width: 50px;
}

クリックした時に、active変数をトグルし、連動してclassもトグルさせています。で、切り替わる時にCSSアニメーションさせています。楽しいですね。

2017-12-05追記:IE11ではSVG要素のCSS Transitionは動かないそうなので、プロダクションで使う方はご注意下さい。

更に複雑なUIを作るには

以前書いた記事の中で、ヒントになりそうなものをピックアップしました。どれもVue + SVGでの実装です。

また、SVG要素に精通するのが大事です。MDNのSVG要素リファレンスを熟読しましょう。

  • コンポーネントとしてSVG要素をまとめる際は、groupという要素でラップします。groupにxやyという属性はなく、transform属性で変形する必要があります。
  • SVG子要素でクリック位置を取得する場合は、offsetX / offsetYの解釈がIE+Chrome / Firefoxで異なることに注意する必要があります。offsetX / offsetYは使わないほうが無難です。

終わりに

さて、高度なUIといえばドラッグ&ドロップですが、ざっくり言うとmousedown, mousemove, mouseupを各要素に付けてよしなにします。これに関しては紹介すると長くなるので、またいつかやり方を書こうと思います。

ドラッガブルな要素の実装についてはまだ研究中で、シンプルに書く方法を見いだせていません。ただカスタムディレクティブでさっくり行けるんじゃないかという手応えは感じています。一緒に研究してくれる仲間を募集しています。

おまけ

最後に、この記事を読んでSVGをやってみたくなった人に向けて、雛形HTMLを作ったので置いていきます。

svg-sandbox.html · GitHub

よく使うSVG要素を幾つか表示させているので、属性をいじるなり、Vueとバインドさせるなりさせてみてください。

f:id:hashrock:20171204214411p:plain

上記に表示されている基本図形の組み合わせで表現できるUIを考えて、実装してみるのがおすすめです。

ボツネタ

この記事を書くにあたって、無駄に作りかけてしまったSVGエディタです。何も使ってないじゃん。人間は愚かだ…

f:id:hashrock:20171204214737g:plain

Vue.js + SVG練習8 : 付箋を作った&vuexに入門した

f:id:hashrock:20171120010012g:plain

ふつーのドラッグ出来たりリサイズ出来たりする付箋。 SVGで作る必要があったのかは謎。

DEMO

コードはこちら。

github.com

ポイント

  • SVGで複数行のテキストを表示するには、foreignObject + divを使うのが定番らしい。
  • ただしその場合、IE11は見捨てなければならない。
    • cacooなんかもIEは非対応にしている。
  • エディタに関してはSVG外でやっている。cacooをみると、absoluteでiframeとcontenteditableを乗っけている。
    • iframeを介す理由は謎だけど、IE対応のためかも?という話を教えてもらった
  • 今回はプレーンテキストでいいので、textareaをabsoluteで単に乗っける形とした。

詰まったとこ

下記のエラーが出てしまう。computedにしたselectedItemが、参照するときに関数として取れてきてしまう。

(30,34): error TS2339: Property 'y' does not exist on type '() => FusenItem'.

一旦代入するとうまくいく。

https://github.com/hashrock-sandbox/study-vue-touch-ui-svg/blob/master/src/App.vue#L28

computedってこんな感じだったっけ?多分、TypeScript力が足りないだけなんだと思う。

vuexに入門した

  • 実はvuexをまだ使ったことがなかったので、これを期にえいやした
  • 公式のドキュメント読みながらなんとか形にした。結構型を書く必要がある箇所が多い。まだ初心者なので言えることは何もない
  • 整理されてるんだろうか?ちょっとまだわからないけど、不用意な代入が防がれるのは良いかもしれない。

Vue.js + SVG練習7: 文字がにょろっと出てくるやつ

動いてるところは下記ツイートから見れる(gifがでかくなりすぎてはてなにアップロードできなかった)

デモサイトは下記。文字を入力したり、文字サイズや太さを変えて遊べる。

https://hashrock.github.io/canvas-lff/

ソースは下記。

github.com

リポジトリについて

  • もともとは昔に作ったリポジトリで、LFFというラインフォントフォーマットの存在を知って作ったやつ
  • canvas上に描くようにして、光らせたりアニメーションさせたりはしていた
  • 今回はVue + SVGに移植した
  • ついでにES5 -> ES2015 -> TypeScriptに段階移行した
    • まずlebabでarrowやletを変換し、その後にSFC + 外部tsファイルのリンクの形にしてVSCodeの支援を得ながら移植し、最後にtsをSFCにがっちゃんこした。結構大変だった。

フォントについて

  • LFFはCAD用のフォーマットらしく、プロッターとかで描画したり、物理的に掘ったりしてたんじゃないかなぁと思う。
  • ここにあるKST32Bというフォントがレトロでかっこよかったので使わせて頂いた。GPL2。
  • 内容としては、0-10までの範囲の点列をテキストで記述しているだけ
  • なので、JSでゴリゴリパースした

SVG周りについて

  • もともとcanvas向けに処理を書いていたので、楽をするためにd3-pathを利用した
  • d3-pathを使うと、canvas互換のAPIで引いた線をpath要素にシリアライズすることが出来る
  • (なんかy軸反転してたり、座標が細かい小数点になっている気がする。自分のバグかもしれんが)

アニメーションについて

  • animejsを利用
  • animejsとmo.jsは2大Exampleかっこいいけど全く使いこなせないライブラリと勝手にみなしている
  • よくあるパスアニメーションを利用。点線ハックするやつ。SVGの仕様決めた人こういう使われ方想定してなかっただろうな
  • 文字を重ねて3色で描き、それぞれずらしながら線を描画していけば色がついてかっこよくなる(mo.jsのexampleにあったテクニック)

Vueについて

  • 今回は1行と1文字、それぞれをSFCにしてある
  • 最初はフォントデータの検索が遅く、データ構造変えたりキャッシュを期待してcomputedにもたせてみたり、設計をがちゃがちゃ変えた
  • 文字の太さ変更については、CSSプロパティとinput: rangeを紐付ける必要があったので、下記の知見を使った(CSS VariablesはJSから変更したときに再評価される)

思い

  • これが何なのかはわからないけど、今までの中では結構遊んでて楽しいやつができた。
  • すっごいアクセシビリティの荒廃したサイト作れそう

Vue.js + SVG練習6: ズーム&パンできる折れ線グラフを書く

f:id:hashrock:20171116025148g:plain

ズーム&パンできる折れ線グラフを書いた。グリッドライン付き。

こういったグラフや、ズーム・パンはd3の得意技なのだけれど、あえてSVGを組み上げる部分をd3でやらずVueのテンプレート側でやっている。 スケーリングや、グリッドラインの位置決めなんかは、d3のコア部分の「d3-scale」というライブラリを利用した。

実際描画部分は全く苦労していなくて、グリッドラインも含めてたったのこれだけ。

<template>
  <svg :width="w" :height="h" @wheel="wheel" @pointerdown="startDrag" @pointermove="onDrag" @pointerup="stopDrag">
    <polyline fill="none" stroke="#793" :points="points"></polyline>
    <line class="grid" v-for="(tick, index) in ticks" :key="index" :x1="scaleTick(tick)" :y1="0" :x2="scaleTick(tick)" :y2="h"></line>
  </svg>
</template>

マウスホイールとか、ドラッグの挙動なんかはmixinとかで切り出せないかな、とかは思っている。 コードは以下。

github.com

DEMO

ポイント

  • d3-scaleはめちゃくちゃ便利で、scale.scaleLinear().domain([min, max]).range([distmin, distmax])とかやると、domain範囲の値をrange範囲にマッピングしてくれる。
  • さらに、上記から取れるfunctionにtickというメソッドが生えていて、これは何かというとdistminからdistmaxまでの範囲で、ここに縦線引いたらいい感じになるよ、という座標の配列を返してくれる。
  • ので、これをそのままグリッドラインに変換してしまえば終わり。
  • 折れ線グラフを塗りつぶすには、pathの端っこを一旦y座標0に落としてから閉じてあげる必要がある。
  • マウスホイールの挙動はd3-zoomからパクった。d3は参考になる箇所が無限にある
  • マウスドラッグの挙動は、この前作ったスライダーからの流用。
  • あといい機会なので全部TypeScriptに移行した。d3使うときは型があると涙がでるほどありがたい。
  • 算数むずかし~~~ってなったときは、computedに切り出して変換後の変数をVue devtoolで見れるようにしてしまうと、どういう変化をするのかが分かりやすい。とにかくVueでロジックを簡単にするにはcomputedを使いこなすこと。
  • 計算量については全く何も考えてないので、データ量が多くなったら万事休すかもしれない。そのあたりはおいおい勉強していきたい。

気持ち

そもそも、このSVGの練習を始めたのも色々理由があって、

  • VueconfのSarah Drasnerさんの発表が良かったため
  • anydownで使うSVGのUIの完成度を上げたかったため
  • Vue.js meetupの時だったか、あまり覚えてないけど、「Vue + D3の連携をするより、VueとSVGで直接描画したほうがいい」と誰かが言っていたのを小耳に挟んだ為

この最後の理由も結構大きくて、検証のために今回の練習に至っている。 d3は便利なんだけどSVGの生成部分が辛く、メソッドチェーンをゴリゴリ書いてるうちに自分が一体何を書いているのかわからなくなりがちなのと、 既成のグラフコンポーネントを使ったら使ったで、カスタマイズが全くできなくなりがちというのが結構困るポイントだったりする。 Vueのテンプレートは大変書きやすいので、カスタマイズしやすいグラフが作れるのではないかな。

d3もやっていることはDOMのバインディングと生成で、Vueの出来ることとおんなじなので、Vue + D3の糊付けを頑張るよりは、Vueでやれる範囲を広げたほうがいいんじゃないかという感じに思っている。 無論、d3のutilは便利だし、再発明を防ぐためにd3の考え方の流用はやったほうが良いと思う。

あとは、すべてをVueのバインディングでやることで、複数のグラフのズーム位置やフィルタ状態などの同期が簡単に出来るんじゃないかともくろんでいる。 実際、Webアプリ上でグラフを単体で見たいということは少なく、複数グラフの比較やいろんな切り口でも分析に使うわけで、双方向バインディングが役に立つのでは。

Vue + TypeScript + poiで小さいプロジェクトを作る時の手順

TypeScriptを使いたい、型に守られたいという気持ちが定期的に生まれるのだけど、 ただwebpack.config.jsとtsconfig.jsonが上手く書けなくてしんどいみたいなことがままある。

お仕事的に、TypeScript + Vueでやっていくぞというのは下記のダーシノさんのスライドが良い。

www.slideshare.net

上記の内容と、webpack-simpleという自分が愛用しているテンプレートと、vue-class-componentのexampleを見ながら書いた雛形が下記に置いてある。

github.com

それはそれとして、今日はpoiを調べた。

poi + TypeScript

poiは設定より規約感のあるツールで、書捨てのプロジェクトにはwebpack直で使うよりpoiが楽だったりする。 .vueファイルへの対応も最初から組み込まれている。 デフォルトではbabelが使われる設定なのだけど、TypeScriptやる場合は、もう下記のことを順にやってけば良い。

github.com

で、それなりにボイラープレートも必要だったので、自分なりにやった手順を書いておく。

まずはセットアップ。

mkdir my-project
cd $_
yarn init
yarn add poi typescript poi-preset-typescript --dev

そして、下記のファイルを作る。

index.ts

import Vue from 'vue'
import App from "./App.vue"

new Vue({
  el: '#app',
  render: h => h(App)
})

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "strict": true,
    "module": "es2015",
    "moduleResolution": "node",
    "experimentalDecorators": true
  }
}

App.vue

<template>
  <div id="main">
    <h1>Hello World!</h1>
    <input v-model="text">
    <p>input: {{text}}</p>
  </div>
</template>
<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";

@Component({})
export default class App extends Vue {
  text: string = "Hello There";
  mounted() {}
}
</script>

poi.config.js

module.exports = {
  presets: [
    require('poi-preset-typescript')(/* options */)
  ],
  "homepage": "./"
}

sfc.d.ts

declare module "*.vue" {
  import Vue from 'vue'
  export default Vue
}

その後、package.json内に下記を追記。

  "scripts": {
    "dev": "poi index.ts",
    "build": "poi build index.ts"
  }

もし、ビルド後のプロジェクトをGitHub Pagesにデプロイしたい場合は…

yarn add gh-pages

しつつ、package.jsonに以下も追加

  "scripts": {
    "deploy": "gh-pages -d dist"
  }

という感じで、意外とボイラープレート作らなきゃいけなくて、 まだ楽とは言い切れない感じではある。

ただこれさえ済ませてしまえば、Vueファイルの中でもTypeScriptが使えてバイブス上がる感じになる。

f:id:hashrock:20171111031211p:plain

という風に、補完もバッチリ効く。ただ、LSP実装もなかなか大変なようで、リネームやリファクタリングには未対応の様子だった。veturのロードマップ

VSCodeのリファクタ機能をフルに使いたい場合は、ロジックはなるべくモデルに切り出して、普通のTSにしてからリファクタするのが良さそう。

これで作ったプロジェクトの雛形が以下。流石に素のwebpackより大分シンプル。

github.com

気持ち

自分がコード書くときはとにかく設計も何もなく適当にぐちゃぐちゃ書き進めることが大半で、しかも意識が朦朧としていることが多かったりする。JSは集中してないと書けないので大変難しい。

自分がアホだからこそ役立つのがTypeScriptなんだけど、アホにとってtsconfig.jsonやwebpack.config.jsはパズルじみていて、書くのが難しいという問題がある。もうちょっと楽になったらいいなぁとは思う。

追記 : vue-class-componentを使わないバージョンのブランチを作った

vue-class-componentを使わなくとも、TypeScriptの恩恵を受けられるそうで、 お手軽用途にそっちのバージョンも作った。

github.com

data内のプロパティにもちゃんと型がついてる。すごい。

f:id:hashrock:20171111142359p:plain

最初はbabelで書いて、TSに段階移行というやり方が取れると思う。

babelからの移行手順で必要なのは

これによる利点は、下記を参考。

やって来る Vue 2.5 での TypeScript の変更 — Vue.js

Vue.js + SVG練習5: クリックすると頑張るスピナー

ただし、やりすぎると爆発する。

f:id:hashrock:20171110011101g:plain

動作確認は以下より。

hashrock-sandbox.github.io

ソースはこちら。

github.com

ポイント

  • 小ネタなので特にないかな…
  • 早めに寝たいので、短い時間で実装できる題材を結構考えた
  • 小ジャンプは、2次関数でやるパターンと、y変位と速度でやるパターンがあったような気がするけど、頭回ってなくて後者でやった
    • とにかく加速度は常に下にかけて、y変位は0を超えないようにすればジャンプになる。現実と同じ

日記

  • egoistさんからプルリクもらった
  • poiからgh-pagesへのデプロイ時に、アセットの参照フォルダがルートになってしまっていて、これまで手でパスを修正していたんだけど、package.jsonのpoi/homepageに./を指定することで修正出来るよー、というもの
  • すごく助かった!