yuw27b’s blog

技術メモと雑記

カレンダーUIを実装する依存なしのJavaScriptライブラリ

カレンダーUIを実装するJavaScriptライブラリの紹介です。
Webアプリ上の入力フォームに、日付を選択する項目を実装したときのこと。

input type="date" を使いたいのだけど・・・

HTMLのinputタグに、「type="date"」を指定すると、一部のブラウザではカレンダーUIを表示してくれますが、主要ブラウザすべてにサポートされるのはまだまだ先のようで、案件で使うのは難しそうでした(2016年1月現在)。
参考:Can I use... Support tables for HTML5, CSS3, etc
※この仕様自体が、WHATWGのLiving Standardsであり、HTML5の仕様として勧告されているわけではないので、ブラウザのサポートはなかなか進まないのかもしれません。

jQueryjQuery UIに依存したくない

カレンダー方式で日付を入力するUIとなると、まずjQuery UIのDatepickerが思い浮かびました。デザインも色々なパターンがあり、jQuery製ということで各種のブラウザ対応や安定性も保証できて良いのですが、最近はjQueryを使わないWebアプリの案件もあり、カレンダーのためだけにjQueryjQuery UIを読み込む、というのはあまり良い方法には思えませんでした。

「Kalendae」

それで、ピュアJavaScriptで動作するライブラリを探したところ、「Kalendae」というものに行き当たりました。
GitHubにコードとドキュメントがあります:GitHub - ChiperSoft/Kalendae: A javascript date picker that just works.

GitHubのスター数は1,700を超えており(2016年1月現在)、開発も止まっていないようなので、良さそう!ということで、使ってみることにしました。

特徴としては、

  • 依存ライブラリなし(※)
  • 単一の日付選択と、期間選択の両方が可能。他にもオプションはいろいろある。
  • click、changeなどのイベント取得や、リセットなど、必要になりそうなAPIはきちんと揃っている印象
  • 見た目はCSSでカスタマイズ可能
  • モダンブラウザとIE8に対応

※ドキュメントにも「依存はないよ」というようなニュアンスのことが書いてあるのですが、実際にはmoment.jsを使っています。ですがKalendaeにはstand alone版があり、こちらはkalendae.jsのコードにmoment.jsを含めて配布しているものなので、読み込むファイルはこれ1つで済みます。
(どちらもMITライセンスなので、ソースコードに丸ごと含めてしまっても問題ないわけですね。)
つまり、

  • 基本的には・・・stand alone版のkalendae.js
  • すでにmoment.jsを読み込んでいるよ、という場合は・・・moment.jsを含まないkalendae.js

を使えば良い、と思います。

ファイルサイズ

  • kalendae.js 34KB
  • kalendae.min.js 17KB
  • kalendae.standalone.js 132KB
  • kalendae.standalone.min.js 51KB

上記の他に、

  • kalendae.css 7KB
  • ボタン用のpng画像が1KB×2ファイル

(バージョン0.5.5で確認)

実装例

kalendae.cssとkalendae.standalone.min.jsを読み込んで、ボタン用の画像はCSSと同じ階層に置いておきます。
そこで以下のように書くと、

<input type="text" class="auto-kal">

こうなります
f:id:yuw27b:20160108230952p:plain

オプション指定例:

<input type="text" class="auto-kal" data-kal="format: 'YYYY/MM/DD', months: 2, mode: 'range', direction: 'future'">

f:id:yuw27b:20160108231824p:plain
(フォーマットを年/月/日、2ヶ月分表示、期間選択、未来の日付のみ選択可能)



jQueryなプロジェクトでカレンダーが必要なときは、しばらくはこのKalendarにお世話になろうと思います!

新潟へIターンしてWEBエンジニアをしている話

この記事は、地方在住ITエンジニア(元・地方在住も可) Advent Calendar 2015 - Adventarの19日目の記事です。

私が住んでいるのは新潟県新潟市で、政令指定都市ですので、カレンダーの「地方」の趣旨からするとちょっとぎりぎりですが、

ということで、多目にに見てもらえたら幸いです。

アラサーWEBエンジニア。
最近は、JavaScript4割、CSS3割、Ruby2割、PHP1割くらいの感じで書いてます。

東京から新潟へ

3年前まで東京でECサイトの制作をやっていましたが、結婚を機に新潟へ引っ越すことになりました。
引っ越すこと自体に不満はなかったのですが、「仕事どうしよう・・・?」というのは頭に浮かんでいました。

当時の会社から、リモートで続けるか、みたいな話もあったのですが、

  • 業務内容がちょっと希望の方向とずれてきていたこと
  • 家族以外に友人・知人のいない土地でいきなり在宅勤務では、完全に引きこもりになりそうなこと

から、きっぱり退職させてもらうことにしました。(今思えば少しもったいなかった気もしますが・・・)

新潟の求人

当時勤務していた会社は、採用したいときにはFind Job!を利用していたので、自分もここで新潟県の求人を検索してみましたが・・・
検索条件の「勤務地」のところに新潟県はないんですね。北陸と東北がありますが、その中に新潟県の求人は0件です。当時、約半年にわたってときどきチェックしてましたが、いつ見ても0件でした。
引っ越してから分かりましたが、こっちの求人は何と言ってもハローワークなのでした。

WEBエンジニアで探した求人の印象は、

  • 新潟県の平均給与額は東京都の7割くらいなので、IT関連でも同じくらいの感覚。
  • ただし、最先端の技術を求める求人が少ないので、高給なエンジニア職は見つけにくそう。
  • 車がないと通えないところに会社があるのは普通のこと
  • 自動車免許必須のところが多い(会社には電車で通えたとしても、客先には車で行く)
  • WEB制作専門で規模の大きな会社は少ない(10人以下が多かったと思う)
  • もう少し規模の大きなところだと、WEB以外の事もやっていてWEB部門もあるよ、っていう会社

東京に比べると数が圧倒的に少ないので、希望に合う求人が出るまで待てるかどうかが重要かもしれません。

今の働きかた

パートタイムのエンジニア(WEB専門の会社ではない)+フリーランス に落ち着きました。
ハローワークのIT関係の相談員さんに「パートでもいいんですけど」って言ったら、「そんな人は初めてです」って言われた記憶があります(笑)。ですが「事務職のカテゴリのほうにも、プログラミングが活かせる仕事がありますよ」っていうアドバイスは的中しました。そういえば、当時ハローワーク自体が車がないとかなり行きにくい場所にありました。

フリーランスのほうは、東京のWEB制作会社さんや、新潟のセミナー・勉強会で知り合った方から発注いただけている状態です。

現状には満足&感謝してますが、将来的には東京の会社に雇用してもらって新潟でリモートワーク、が理想かなあ・・・などと考えたりもしています。
これは新潟が、とかではなくて、私がそこまでフリーランス向きではない気がするからです。

東京に比べて困ること

だいたい他の方々が書いていたことと同じですが、

  • 技術書を売っている本屋さんが少ない
  • 勉強会などが少ない(でも、あることはありますよ!)
  • もし転職するとなると選択肢が少ない

といったあたりです。
また、私はある程度東京でエンジニア経験ができていて、情報収集の仕方とか、自分の目指したい方向とか、多少なりとも分かっているから地方でやれている部分もあると思います。新米エンジニアだったらどうだろう・・・、というか、新潟で生まれ育っていたらエンジニアにすらなっていなかったのでは?という気がします。


新潟FAQ

※他のかたのブログでおもしろかったので、僭越ながら東京でよく聞かれる質問集を(3年しか住んでないけど)。

  • お米とお酒でしょ?

まあそうです。お米は本当においしいです!それ以外にもたいていの野菜と果物、肉、魚、卵と県内産のものが手に入ります。

  • 雪がすごいんでしょ?

新潟市内はそうでもないです。屋根の雪を降ろすなんてことはあり得ません。積もっても備えがあるので、そこまで困ることは(今のところ)ないです。

  • 生活費は安い?

家賃や駐車場などは安いです。食費も、野菜、魚などをよくもらうので安いと思います。ですが、上にも書きましたがその分給与水準が低いので、余計にお金が貯まったりということはないです。

  • 車がないと生活できないの?

新潟市内だと、車なしでも生活はできると思います。が、車がないと行かれないレストランとかお店とかたくさんあるので、そのあたりの選択肢はだいぶ減ります。
あと、冬はスタッドレスタイヤ必須です。

  • 新潟弁てあるの?

あります。しかも地域によってけっこう違うようです。
私の場合、おばあちゃんと会話するのがけっこう大変で、最初の頃は半分くらいしか理解できませんでした。
逆に若い人は共通語に近い話し方をしている印象です。

  • 東京に戻ってこないの?

今のところ戻るつもりはないです。
仕事も、どうにもならなくなったらIT関連じゃなくても仕方ないかなあ、くらいに思っています。
もちろんエンジニアを続けられたら理想的ですけどね!



明日は@takushinoharaさんです。よろしくお願いします!

SVGを描くJavaScriptライブラリ

この記事は、SVG Advent Calendar 2015 - Adventarの15日目の記事です。

チャートやグラフ用のJavaScriptライブラリはどれがいいんだろう?

2015年は「Ajaxで取ってきたデータを、SVGのチャートやグラフにして表示する」という作業をわりとたくさんやりました。
実装方法もいろいろやっていて、

などなど・・・。
小規模サイトだったり、公開範囲の限定されたサイトだったり、という事情に甘えて、色々なものに手を出した感じですね(笑)。

ピュアJavaScriptは、まさに13日のこちらの記事(気づいて築く: パイチャートのSVG仕立て 〜アニメーションを添えて〜)みたいなことを四苦八苦しながらやってました。

どれがベストかは、ケースバイケース、だとは思いますが、
「普段使ってるようなWebサービスはどうやって実装されてるんだろう?」と思って、いくつかソースコードを見てみた、というのがこの記事です。

GitHub

f:id:yuw27b:20151215232116j:plain
※各リポジトリの「Graphs」タブのところ

Google Analytics

d3.jsも使っているというのがちょっと意外でした。

StatCounter

このライブラリは有料のよう。

SimilarWeb

Lazy Line Painterというのは、線のアニメーション用みたいですね。

Qiita

f:id:yuw27b:20151215232124j:plain
※ユーザーの「投稿タイプ」のパイチャートのところ


2016/1/26追記:
UIがリニューアルされましたね!
f:id:yuw27b:20160126211924j:plain
新しいチャートは、d3.jsのラッパーライブラリc3.jsを使用しているようです。
ちょうどIE8のサポートも切れたので、Raphaëlである必要がなくなった、ということかもしれません。




RaphaëlはIE8でも表示できるので重宝してました。
最近はIE8対応不要なケースが増えて、私はあまり使わなくなってしまいましたが、
Raphaëlの作者さんがSnap.svgを作っているので、今度はそちらでお世話になろうと思います。

d3.jsは一番よく見かけるし、サンプルも多くて便利だな、と思います。
反面、サンプルそのままで事足りてしまうケースも多くて、そうすると「いかにもd3.js」な見た目になるので、
ゼロベースで実装できるように勉強したい・・・というのを来年の目標にしようと思います。


また見つけたら追記します!
普段、いろいろなところでSVGのチャートを見ている気がしていましたが、いざ探そうとすると思い出せないものですね><




12/16追記:
SVG Advent Calendar、翌日16日は空きだった・・・と思いきや、
カレンダーの作成者でもあるrikuoさんがSVGでFizzBuzz(XSLT版) - 週刊SVGという記事をアップされていました。XSLTでプログラミングしていてすごい・・・!
もしかして簡単なチャートならJavaScript使わなくても書けちゃったりするんでしょうか。画像でもありテキストでもあるSVGって本当におもしろいですね。

writing-modeがFirefoxでも使えるようになっていた

CSSで縦書きテキスト

CSSのみで縦書きテキストを実現するには、writing-modeプロパティを使いますが、Firefoxだけが長いあいだ未対応でした。
Can I use... Support tables for HTML5, CSS3, etc

2015年11月現在、この仕様は勧告候補の段階なので、ブラウザによってベンダープレフィックスが必要だったり、指定する値の記述方法がばらばらだったりもします。
そして、未対応だったFirefoxは、バージョン41からは標準で対応するようになったとのこと(ベンダープレフィックスもなし!)。
Firefox 41 for developers - Mozilla | MDN

ほぼ全てのブラウザが対応したことに

IEは(値の記述方法は独自仕様ですが)6から使えますし、ChromeSafariはベンダープレフィックス付きで対応しているので、Firefoxが対応したことでほぼ足並みが揃ったことになります。

現時点で各ブラウザに対応させるには、こんな感じになります。

writing-mode: tb-rl; /*IE*/
-o-writing-mode: vertical-rl; /*Opera*/
-webkit-writing-mode: vertical-rl; /*Chrome, Safari*/
writing-mode: vertical-rl; /*Firefox, Edge*/

※縦書きで、行が右から左へ進む場合の指定方法です

まだフォールバックが必要?

writing-modeに対応したFirefox41のリリースは2015年9月22日と(これを書いている時点からすると)かなり最近なので、基本的に自動アップデートがかかるとはいえ、まだ40以前のバージョンのユーザーもいるかも?という不安もあります。
さらに、FirefoxにはESRという法人向けの延長サポート版が存在していて、こちらはまだバージョン38です。これが2016年5月末までのサポート予定とのことなので、やはりそれまでは何かしらフォールバックを用意したほうが良さそうです。

フォールバックも書いてみた

縦書きのテキストが横書きになってしまった場合、コンテンツのレイアウトにかなり影響が出るので、それを回避するべく以下のような方法をとりました。

  • writing-modeが使えない場合、横書きのテキストを90度回転させる
  • 回転はCSSのtransformプロパティで行う(これはFirefox16から対応している)
  • ブラウザがFirefox40以前かどうか、という点はJavaScriptで判別する

日本語の場合はテキストが横倒しになるので、writing-modeが適用された状態と全く同じにはなりませんが、フォールバックということで、そこまでの対応としました。

Chrome(writing-modeに対応)
f:id:yuw27b:20151110231711j:plain

Firefox38(writing-modeに非対応)
f:id:yuw27b:20151110231718j:plain

HTML

<div class="box">
    <p class="text">日本語のテキスト<br />改行</p>
</div>


CSS

.box {
	margin: 20px;
	border: solid 1px #E00;
        line-height: 0;
}

.text {
	display: inline-block;
	margin: 0;
	font-size: 18px;
	line-height: 1.5;
	color: #000;
	background: #CCC;
	writing-mode: tb-rl;
	-o-writing-mode: vertical-rl;
	-webkit-writing-mode: vertical-rl;
	writing-mode: vertical-rl;
}

.text-rotate { /*writing-mode fallback*/
	transform-origin: 0 0;
	transform: rotate(90deg) translateY(-100%);
}


JavaScript(※DOMを読み込み終わってから実行)

  var ua = window.navigator.userAgent;
  if (!('indexOf' in Array.prototype) || ua.indexOf('Firefox') === -1) {
    return;
  }
  var browser_str = ua.match(/Firefox\/.*$/);
  var version = parseFloat(browser_str[0].replace(/^Firefox\//, ''), 10);
  if (version < 41) {
    document.querySelector('.text').classList.add('text-rotate');
  }

包含ブロック(.box)に赤い枠線を、テキストの要素(.text)にはグレーの背景をつけました。
テキストの要素(.text)に「display: inline-block」を指定しているのは、rotateを使用した(フォールバックの)場合に、.textの高さが.boxの横幅100%になってしまうからです。

また、画像で分かるように、rotateを使用した場合は包含ブロックの高さは伸びません。
包含ブロックがテキストの要素(.text)よりも縦に長い場合は問題ありませんが、必要に応じてmin-heightを指定するなどすると良さそうです。

CADDYで手軽にHTTP/2サーバを立てる

CADDYとは

公式サイト
Caddy - The HTTP/2 Web Server with Fully Managed TLS

GitHub
GitHub - mholt/caddy: Fast, cross-platform HTTP/2 web server with automatic HTTPS

公式サイトから抜粋:

  • Windows, Mac, Linuxと、Androidで動く
  • Apacheやnginxのような細かな設定はできないかわりに、設定に関する専門知識は不要
  • 静的なファイルのサーブを主目的にしていて、環境の移行も簡単

ローカルでちょっとテストするのに使えるかなー、と思って興味を持ったのですが、
もう少し本格的なサーバなのかも?という印象。
HTTP/2で動かすのは本当に簡単で、PHPもHTTP/2でサービスさせることができました。


以下、Macでの設定〜起動までの手順です。
※他のOSでは試していませんが、サーバ自体が実行ファイル形式になっているので、基本的には同じような方法で動かせるのではないかと思います。

ダウンロードとインストール

Download Caddy
本体の「Caddy Core」をダウンロードします。

f:id:yuw27b:20151108212649p:plain

ダウンロードしたフォルダ直下にある「caddy」が実行ファイルです。
好きな場所に置いて、シェルからコマンドを実行できるようにパスを通しておきます。

ターミナルから、サーバのドキュメントルートにしたいディレクトリに移動して、

$ caddy

でサーバが起動します。
デフォルトでは「2015」番ポートを使うようになっているので(来年になったら変わるとか?)、ブラウザで「http://localhost:2015/」にアクセスしてみます。
「index.html」があればその内容が表示されるはずです。なくても「404 Not Found」が出ていればサーバは動いています。
f:id:yuw27b:20151108212725p:plain
↑デフォルトの404画面はすごくシンプル。

HTTP/2でサービスさせるために、SSLの設定をする

HTTP/2に対応させるにはSSLの設定をして、HTTPSを使用する必要があります。

2017年2月追記:
CADDYに、自動的に自己証明書を生成するオプションが追加されましたので、テスト用途であれば以下の証明書の準備は不要になりました。便利です!
公式ページ:tls - Caddy Directives (追記ここまで)

今回は、ローカルのテストサーバということでセキュリティは考えずに、opensslで自己証明書を用意します。

※証明書について詳しいことは省きますが、以下が参考になりました:
オレオレ証明書をopensslで作る(詳細版) - ろば電子が詰まっている
OpenSSLコマンドによる公開鍵暗号、電子署名の方法 - Qiita

鍵ファイルを置きたいディレクトリに移動してopensslのコマンドを実行します。

$ openssl genrsa -aes128 -out server.key 2048
$ openssl req -new -key server.key -sha256 -out server.csr
$ openssl x509 -in server.csr -days 365 -req -signkey server.key -sha256 -out server.crt

※openssl reqのところで、いろいろ入力項目が出てきますが、パスワード以外はすべて空欄のままで問題ありませんでした。

これで鍵セットは完成ですが、暗号化されたままだとうまく動かなかったので、キーを復号したものも作りました。

$ openssl rsa -in server.key -out server.noencrypt.key

これでSSLの準備は完了です。
(※復号化しないと動かなかったのは、何かミスっているような気もするのですが、ローカルサーバなので追求していません。)

とりあえず、サーバもSSL keyもコンテンツもこんな感じで一ヶ所にまとめました。

f:id:yuw27b:20151108213106p:plain

もちろんどこに何を置いてもいいのですが、まとめておいたほうがパスの指定などがやりやすいかな、という印象です。

caddyfileを用意して細かな設定をする

CADDYでは「caddyfile」というテキストファイルに様々な設定を記述することができます。
設定可能な項目は公式サイトの以下のページにまとまっています。かなりたくさんあります。
The Caddyfile - Caddy

シンプルなHTTP/2(HTTPS)のローカルサーバの場合:

localhost:2015 {
  tls ./sslkey/server.crt ./sslkey/server.noencrypt.key
  root ./public/
}

毎回ドキュメントルートに移動してサーバを起動するのも面倒なので、「root」をcaddyfileに記述しました。
※caddyfile内に記述するパスは、カレントディレクトリからのパスです。上の例では相対パスになっていますが、もちろん絶対パスでも大丈夫です。

2017年2月追記:
CADDYに自己証明書を自動生成させる場合は、

  tls self_signed

と記述します。(追記ここまで)

caddyfileを保存したら、ファイルの内容をcaddyに渡して実行します:

$ caddy -conf="/path/to/Caddyfile"

もしくは、

$ cat Caddyfile | caddy

ブラウザから、今度は「https://localhost:2015」にアクセスしてみます。(証明書の警告が出ると思いますが、無視して接続を選択します。)
f:id:yuw27b:20151108213220p:plain

ブラウザが対応していれば、HTTP/2での接続になっているはずです。
ChromeのDevToolsで見てみると、「Protocol」のところが「h2」となっているのが確認できます。
f:id:yuw27b:20151108213238p:plain


HTTP/1.1 vs HTTP/2

簡単なテストとして、画像を10枚配置したHTMLを作ってアクセスしてみました。
上がHTTP/1.1で下がHTTP/2です。HTTP/2では10枚が並列に読み込まれています。

f:id:yuw27b:20151108213259p:plain
(ローカルサーバにしては時間がかかっていますが、差が分かりにくいのでブラウザのほうでわざと速度を落としています。)

FastCGIを使う

CADDYでは、そのままでは静的なファイルのサーブしかできませんが、リクエストをFastCGIにプロキシすることで、PHPの実行が可能になります。
fastcgi - Caddy Directives

まず、PHPFastCGIマネージャであるphp-fpmを起動しておきます。
php-fpmが9000番ポートでサービスしている場合、caddyfileを以下のように記述します。

localhost:2015 {
  tls ./sslkey/server.crt ./sslkey/server.noencrypt.key
  root ./public/
  fastcgi /api 127.0.0.1:9000
}

この設定では、「/api」以下のリクエストを、FastCGIにプロキシします。

phpinfo()を呼び出すと以下のようになりました。
f:id:yuw27b:20151108213315p:plain


おわりに

テストサーバとしてやりたかったことはこれで全部できたので、ひとまずここまで。

処理速度やどのくらいのトラフィックをさばけるのか、というパフォーマンス面と、まだいろいろなことができそう、という機能面を、もう少し調査できたらまた続編を書いてみたいと思います。