入社してた

4月になってしばらくしてから新卒として内定が決まって、5月中旬頃から今の会社で働いている。
就職が決まった時期としてはかなり遅い。ギリのタイミングまで自分のレベル上げをしたかったというのと、最悪就職できないはずもないだろうと社会をなめていたことが原因だった。
でも結果オーライというか、あのときだらだら悩んでたおかげで今のいい感じの環境で働けるようになってラッキーだったなという感想。ついでに言うと、他人の言葉を無視して、自分だけを信じろという考え方が功を奏した感じはある。

入社した会社は、広告のサイトとか作ってる、いわゆる制作会社。10人に満たないくらいの規模でやってる。
加えて、Web制作以外にもイベントの設営とかアプリ開発とかやってたり。
なにより、おもろそうだなー、こいつら、おもろそうだなーと思ったのでここに決めた。

人間関係は良好で、自分の発言も尊重されるし、かなり自由に働ける。
フロントエンドな人は僕だけで、その辺の道は自分で切り開くしかないんだけど、そんでもやってやんぜという心意気はある。
この世界でやっていくために申し分ない土俵に上がったという感触があって、これからはこの場所から世界を変えていく予定です。

BrowserSyncでサーバーのパスのbasenameを指定する

BrowserSyncでサーバーを立ち上げると、http://localhost:3000/とかルートのURLで指定したディレクトリが開くようになっている。
でもたまにパスの指定の関係で、ルートでなくて下層のディレクトリでファイルを開きたいというときがある。http://localhost:3000/dir-name/みたいに。
jekyllとかルーティングライブラリとかだと、basenameみたいな感じのオプションで設定できるので、BrowserSyncでもできるのかなーと思ってたらそういうのはなさそうだった。
ただ、別のオプションで同じようなことが実現できた。

module.exports = {
  files: 'dist',
  server: {
    baseDir: './',
    routes: {
      '/dir-name': 'dist'
    }
  },
  startPath: '/dir-name/'
};

こんな感じの設定ファイルを作って、以下のようなコマンドで実行できる。

$ browser-sync start --config "bs-config.js"

普通のウェブサイトのためのJSボイラープレートを作った

JSバリバリじゃない、いわゆる普通のウェブサイトでもモダンなJSを書くためのボイラープレートを作った。

最近のJSの文脈的には、browserifyでモジュール分割してes2015で書きたい。

でも、browserifyは全部のモジュールをひとつのファイルにまとめるというのが基本的な使い方で、モジュールごとにファイルを分割して、ページによって読み込むファイルを変えるみたいなのは結構やりにくい。

これを解決するために、ページごとに1ファイルにバンドルするという手があるけど、それだと、ページ遷移時に共通部分をもつファイルを丸々ダウンロードしないといけないのが無駄になる。
es6 modulesがブラウザに実装されればこの問題はなくなるけど、かなり先の未来だと思う。

ところが、全部のファイルを1ファイルにまとめるという方法を採ると、ページで実行する機能ごとの切り分けが難しくなる。

なので、URLごとに実行する処理を分けるURLディスパッチャーを作った。
yuheiy/simple-url-dispatcher

この記事から着想を得た。
そこそこ規模が大きくても何とかなるjavascriptの設計(URL dispatcherの薦め)

jQueryプラグインやCreateJSとかのbrowserifyしにくいファイルは、バンドルするファイルの前に普通にscriptタグで読み込めば使える。

モジュールシステムとes2015、そしてURLディスパッチャーを採用しつつ、jadeとscssも加えて、そこそこ現実的なフロントエンドのスタックができたと思う。
yuheiy/js-boilerplate-for-normal-websites

PhantomJSでサムネイルの取得を自動化する

前に作ったウェブサイトギャラリーで使ってるサムネイル画像の取得を自動化した。
それまでは、URLを渡すとサムネイル画像を提供してくれる外部のAPIを使ってたけど、Node.jsでフォルダ内の全HTMLをキャプチャし画像化という記事を見て、おもしろそうだったのでやってみた。
実際にはこの記事のサンプルより少し複雑になってしまった。

PhantomJSコマンドラインから実行できるブラウザで、これを利用してサイトのスクリーンショットを取得した。
そのスクリーンショットを、EasyImageというモジュールを使って縮小してる。
最初からスクリーンショットのサイズを指定して生成することもできるけど、大きめの画面でスクリーンショットを撮影して縮小したほうがきれいに撮れる。

PhantomJSの操作を非同期で行ってるんだけど、並行タスクの数が増えてくるとかなりマシンの負荷が増えてくるので、とりあえずタスクを10ずつに分割して、その10のタスクが終了したら次の10のタスクを実行するようにした。
本当は並行タスクの数を10までに制限するというような形にするべきだけど、あんまりきれいな実装が思いつかなかったのでひとまずこれにした。
bluebirdにそんなAPIがあるらしいので後で調べる。

既存のものを使えばだいたいなんでもできるんだなあと少し感動した。

Velocityのイージングを拡張する

Velocityっていうアニメーション用のライブラリがある。
最初からいろんなイージングが使えて、jQuery UIのイージングの一部が入ってるんだけど、Back系、Elastic系、Bounce系のやつは入ってない。
Velocityは独自にイージングを拡張することもできるので、jQuery UIで使えるイージングは全部使えるようにしてみた。

'use strict';
import Velocity from 'velocity-animate';

let baseEasings = {};

baseEasings.Elastic = p => {
  return p === 0 || p === 1
    ? p
    : -Math.pow(2, 8 * (p - 1)) *
        Math.sin (((p - 1) * 80 - 7.5) * Math.PI / 15);
};

baseEasings.Back = p => p * p * (3 * p - 2);

baseEasings.Bounce = p => {
  let pow2;
  let bounce = 4;
  while (p < ((pow2 = Math.pow(2, --bounce)) - 1) / 11) {}

  return 1 / Math.pow(4, 3 - bounce) - 7.5625 *
    Math.pow((pow2 * 3 - 2) / 22 - p, 2);
};

Object.keys(baseEasings).forEach(name => {
  Velocity.Easings[`easeIn${name}`] = baseEasings[name];

  Velocity.Easings[`easeOut${name}`] = p => 1 - baseEasings[name](1 - p);

  Velocity.Easings[`easeInOut${name}`] = p => {
    return p < 0.5
      ? baseEasings[name](p * 2) / 2
      : 1 - baseEasings[name](p * -2 + 2) / 2;
  }
});

export default Velocity;

以上のコードで、

  • easeInElastic
  • easeOutElastic
  • easeInOutElastic
  • easeInBack
  • easeOutBack
  • easeInOutBack
  • easeInBounce
  • easeOutBounce
  • easeInOutBounce

を拡張できた。
これをimportしたらイージングを拡張したVelocityが使える。

2016/8/15 追記

ソースはこの辺参考
あと、イージングは一度拡張すれば、ファイルを分けてrequireする必要はない。
つまり以下のようにして利用できる。

main.js

const Velocity = require('velocity-animate');

// イージングを拡張
Velocity.Easings.anyEasing = () => {};

require('./animation');

animation.js

const Velocity = require('velocity-animate');

Velocity(document.getElementById('el'), {opacity: 0}, 'anyEasing');

ウェブサイトギャラリーを作り直した

気に入ったサイトを集めるだけのページが欲しくて前に作ったものがある。
けどそれがあんまり使いやすくないので作り直した。

前のやつは、管理用のページを用意して、そこにURLとパスワード入力したらデータベースに登録して、実際のリストに反映されるという形にしてた。
でも、そのデータベースを置いてたサーバーの契約更新時期が来たのをきっかけに、これくらいのことで自分でデータベースを使うのは大袈裟なような気がして、もっと簡易的な仕組みにしたいと思った。

ということでまず、自分のタイミングで更新できるページなので、サーバーサイドとかAjaxでデータ取ってきてレンダリングするというのはやめて、ローカルでテンプレートエンジンを使って静的なページにすることに決めた。
それで、ローカルでビルドするときに基になるデータが必要なので、その管理をどうするかで悩んだ。BaaS使おうかなと思ったけどそれでは前と同じ手間だし、登録しやすくするにはどうしたらいいか考えて、いつもページをブックマークするときに使ってるPocketを使うのがよさそうだと思った。chrome拡張機能を使ってページをすぐに登録できるので便利。

ということで、気に入ったサイトはPocketに専用のタグをつけて登録して、ページを更新するときはPocketのAPIからそのタグのついたデータを取ってきてビルドするという形にした。API使うのに最初だけOAuth認証しないといけないのがめんどくさかった。

Website Gallery

サムネイルはHeartRails Captureってやつがあったので使わせてもらった。
毎回手作業で作るのは手間すぎるし、それを自動化するのもなかなか大変そうだったので既存のもので対応。

GitHub Pagesに置いた。
yuheiy/gallery.yhey.me

図形による画像のクリップをクロスブラウザで実現する

この記事の内容は全体的に古いので、クロスブラウザ周りの情報はあまりあてにしないでください。

Webサイト上で、画像を六角形にクリップしたいということがあった。
やり方はいろいろあるけど、クロスブラウザで動作するようにと考えるとSVGのclipPathを使った方法がよさそうだった。
ただ、ブラウザによる解釈の違いではまるところもあったので備忘録として書いておく。

まず、clipPathを定義するSVGをHTML内にインラインで書く。
外部ファイルに記述することもできるけど、クロスブラウザでは動作しない。
以下のコードは六角形にくり抜くclipPath。

<svg width="0" height="0" style="position: absolute;">
  <defs>
    <clipPath id="hexagon" clipPathUnits="objectBoundingBox">
      <polygon points=".5,0 .933,.25 .933,.75 .5,1 .067,.75 .067,.25"/>
    </clipPath>
  </defs>
</svg>

clipPathUnits="objectBoundingBox"という属性をつけると、要素に対して相対的にクリップできる。
これを使わない場合だと、クリップするためのSVG要素をpxで指定することになって、伸縮する要素に対応できない。
インラインスタイルでposition: absolute;を指定しているのは、これがないとこのSVG要素分の空間ができてしまうので、この指定で高さを無くしている。
あと、このclipPathを参照できるようにIDをつけておく。
この記述を、HTML内のどこに書いても問題なさそうだけど、bodyの終了直前に書くのが多いっぽい。

次に、実際にクリップされた要素を配置する場所にSVGを記述する。

<svg width="500" height="500">
  <image class="clipped" xlink:href="./img/photo.jpg" width="100%" height="100%"/>
</svg>

クリップする要素にCSSから参照する用のクラスをつけておく。 複数の要素をクリップするときはg要素とかで囲ってやるといい。

<svg width="500" height="500">
  <g class="clipped">
    <image xlink:href="./img/photo.jpg" width="100%" height="100%"/>
    <rect width="100%" height="100%" style="fill: rgba(0,0,0,.8);"/>
  </g>
</svg>

そして、次のようなCSSを書く。

.clipped {
  clip-path: url("#hexagon");
}

-webkit-をつけるとSafariで動作しないので外しておく。
Autoprefixerとかを使ってると勝手につけてくれるのでそれも考慮しておかないといけない。
PostCSSの設定で特定のプロパティだけ無視するみたいなことができるかもしれないけど、やり方がわからないので、僕はAutoprefixerの実行後に不要なベンダープリフィックスを削除するようにしてる。

あと、Firefoxではまるところがあって、clipPathのurlとして指定するIDの前に、CSSファイルの位置から見たHTMLファイルまでのパスを書く必要がある。

css/
- style.css

index.html

みたいな階層だと、

.clip-path {
  clip-path: url("..#hexagon");
}

という風に書いたりする。ルートまでの指定だったら

.clip-path {
  clip-path: url("/#hexagon");
}

とか。
この辺で複数ファイルがあったときの挙動とかは調べてないけど、どうしても問題があればHTML内にインラインCSSで書いてやれば動くはず。

デモ作った

で、実際に作ったものとソース)はもうちょっと複雑だったけど、CSSのpositionを駆使すれば実現できるレベルだった。
とはいえ若干手間でわかりにくいので、IEとかもclipPathの実装はがんばってほしいとしか言いようがない。