著者アーカイブ 杉浦

著者:杉浦

Vue.jsの配列監視

 Vue.jsはJavaScriptのフレームワークで、目玉の機能として変数の値の変化に同期して画面上の描画を変更する機能があります。変数の変化は変数の監視機能で実現されていますが、オブジェクトや配列のプロパティをどこまで監視するかという問題があります。JavaScriptである以上prototypeと付き合っていく必要があり、再帰的にプロパティを見ることはprototypeを大量に見ることにつながり計算量的な問題が発生します。
 Vue.jsではいくつかの配列用のメソッドを上書きすることによって監視を実現しています。

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

リストレンダリング — Vue.js#配列の変化を検出より引用

 このため

a[a.length + 1] = 1;

 の様にするよりも

a.push(1);

の様に配列操作メソッドを使うことが推奨されます。
 上記のリストには配列中のある値を変更するためのメソッドが存在しません。加えてVue.jsはプロパティの変更を検知しません。

a[0] = 1;// Vue.jsは変数aが変化したことに気づかない

 このような時には

vm.$set(/** 変更対象元の配列やオブジェクト */vm.items, /** インデックスやプロパティ名 */indexOfItem, /** 変更後の値 */newValue)

 の様にvm.$set()なるVue.jsにこの変数は変更したと通知するメソッドで値を変更することになります。
 原因はわかりませんでしたが、これでもなお画面が変化しないことがありました。このような時には

vm.$forceUpdate();

なる強制再描画メソッドを呼び出します。このメソッドの再描画は特徴的で、呼び出したコンポーネントとその子コンポーネントでのみ再描画をします。とにかく更新したい時には、大本の親コンポーネントにvm.$forceUpdate()を実行するイベントを設定して子コンポーネントから発火させる方法が望ましいでしょう。

著者:杉浦

Google ChromeにService Workerを無視させる方法

 PWAはアプリそのもののようにwebページをふるまわせる仕組みです。PWAを実現するためにService Workerなる仕組みが必須になります。Service Workerは主にアプリとしてふるまうための設定とネットワークとキャッシュを司ります。オフラインで動かすためかキャッシュの保存が頑強で、ネットワークよりもキャッシュを優先することがよくあります。この仕組みは頻繁にデータソースが変更される開発の際、邪魔になることがしばしばあります。Google Chromeは開発者ツールからService Workerを自在に操作でき、これを使うことでストレスフリーに開発ができます。

 開発者ツールのApplicationタブからServuce Workerを操作します。特に使うのはチェックボックスのBypass for networkです。Bypass for networkはService Workerを無視して常にネットワークからデータを取得するようにします。これをチェックした状態ならばService Workerの管理を無視して通常のwebページ同様に開発ができるようになります。
 次のリンクはService Workerに関する開発全体のデバッグ手引書です。困ったらリンク先の記事に書いてある方法で大体解決します。
Service Worker のデバッグ | Web | Google Developers

著者:杉浦

scssの変数、制御構文とhsl表記色

Sass: Syntactically Awesome Style Sheets
 scssはCSSのメタ言語Sassの記法一つです。どのあたりが上位言語かというと、CSSをより便利に記述できるような記法と組み込み関数を増やして、scssファイルをコンパイルすることでcssファイルを作成するあたりが、上位言語です。
 CSSは元から大して変数、制御構文などがなくとも十分使えるものでscssならではのコードはなかなか思いつきません(色を変数化してパレット風にするのは便利なくらい)。この記事ではhsl表記の色と組み合わせることによってscssならではのコードを紹介します。

 上のJSFiddleのCSSを構成しているscssコードが次です。16行目からが特にscssです。変数としての色$baseの色相を組み込み関数adjust-hue()でイテレータに合わせて動かし、イテレータの番号を名前に含むクラス名のdivの高さを変更しています。10行少々のコードで生のCSSでは長大になりそうな離散的グラデーションを実現できました。また、変数$base, $diffの変更だけで色相の起点、刻み幅を変更可能で多少のデザイン変更ならすぐに対応できます。

.flex-row {
  display: flex;
  height: 8em;
  width: 30em;
}

.col-box {
  display: flex;
  flex-direction: column;
}

.box {
  width: 2.25em;
  border: solid darken(#fff, 20%);
}

$base: hsl(0, 100%, 50%);
$diff: 30;
@for $i from 1 through 7 {
  .box-l-#{$i} {
    @extend .box;
    background: adjust-hue($base, ($i - 1) * $diff);
    height: #{$i}em;
  }
  .box-r-#{$i} {
    @extend .box;
    background: adjust-hue($base, -($i - 1) * $diff);
    height: calc(100% - #{$i}em);
  }
}
著者:杉浦

HTMLとCSSの重ね合わせコンテキスト

 重ね合わせコンテキストはstacking contextの訳でHTMLの描画のZ軸(奥行)に関する概念です。positionやz-indexによってスタッキングコンテキストが定義され、これに沿ってHTML要素の重なり方が決定されます。
 重ね合わせコンテキスト – CSS: カスケーディングスタイルシート | MDN
 スタッキングコンテキストは木の様な階層構造になっており、親のノードの要素の上に子のノードの要素が描画されます。スタッキングコンテキストは次のルールに従います。

  • 重ね合わせコンテキストは他の重ね合わせコンテキストに含めることができ、その結果重ね合わせコンテキストの階層構造ができます。
  • 重ね合わせコンテキストはすべて、その兄弟要素と完全に独立しています。重ね合わせ処理では、子孫要素だけが考慮されます。
  • 重ね合わせコンテキストははめ込み式です。要素の中身が重ねられた後、その要素がまるごと、今度は親の重ね合わせコンテキストの重ね合わせ順の中にあるとみなされます。

重ね合わせコンテキスト – CSS: カスケーディングスタイルシート | MDNより引用

 この親の上に子を描画するルールはけっこう強力で、直感的でないz-indexの動作を引き起こします。

 z-index:4の要素の上にz-index:3やz-index:1の要素が描画され、z-index:5の要素がz-index:6を差し置いて最前面に描画されています。これが親の上に子のルールによるものです。z-indexもまた階層構造になっており、描画順はz-index-levelの記述の様に親子を考慮した辞書順で考えるのがわかりやすいです。地図をwebページ上で描画するLeafletなどはこれを特に利用しています。下図の様にとんでもない勢いで位置の上下に合わせてz-indexを変更していますが、地図ノードコンテキストの上でのみのz-index操作なのでバグの原因になることは滅多にないです。

 重ね合わせコンテキストを生の開発者ツールで読み取るのは正直しんどいです。(見方を知らないだけかもしれないけど)Chromeの拡張にはこれを開発者ツールに追記するものがあります。
z-context – Chrome ウェブストア
 z-contextは下図の様に開発者ツールに、この要素はどのコンテキストに属しているか、コンテキストを作るか、親コンテキストは何か、z-index何番であるかを示します。

著者:杉浦

コーディング原則の一つSLAP

Single Level of Abstraction (SLA) [Principles Wiki]
 SLAPとはSingle Level of Abstraction Principleの略で直訳して単一レベルの抽象化原則です。上記リンクはSLAですが、SLAPの方が検索結果が多いです。この原則をもっとかみ砕いていうと、プログラムの構造化の段階を揃えましょう、となります。これが為されていると読みやすくまとまったコードが出来ます。例えば次のようなコードです。

function 高水準(){// レベル1の目次
  中水準1();
  中水準2();
}
function 中水準1(){// レベル2の目次-1
  低水準1();
  低水準2();
}
function 低水準1(){// 本文内容
  // 処理
}
function 低水準2(){// 本文内容
  // 処理
}
function 中水準2(){// レベル2の目次-2
  低水準3();
}
function 低水準3(){// 本文内容
  // 処理
}

上田勲. プリンシプル オブ プログラミング 3年目までに身につけたい 一生役立つ101の原理原則 (Kindle の位置No.946-956). 株式会社秀和システム. Kindle 版.

 例は書籍の内容に沿って処理を行うコードになっています。書籍で言う目次、章、節がそれぞれ高水準、中水準、低水準に従う形です。こうなっていると、どこで何のために何をしているか分かりやすくなります。

高水準─┬─中水準1─┬─低水準1
        │           └─低水準2
        └─中水準2───低水準3

 少々極端ですが、もし共通する部分をまとめて扱うことを優先し次の様になっていた場合、どこからどこまでが何のための処理なのかわかりにくくなります。

// 低水準1,2,3で使う変数の宣言
// 低水準1と3の共通前処理
// 低水準1の処理
// 低水準2の処理
// 低水準2と3の共通処理
// 低水準3の処理
// 低水準1と3の共通後処理

 最初の例では本の内容をコードに落とし込むため幾分か楽に構造化レベルを整えられましたが、実際は処理の長さの差がまちまちでなかなかまとめるのが難しくSLAPを完全に守ることができないこともあります。そういった時、SLAPの上で最低限守るべきなのは呼び出し時のレベルの統一です。次の様にすると何もしない時よりか幾分楽に読めるようになります。

function 高水準(){// 目次
  中水準1();
  中水準2();
  中水準3();
}
function 中水準1(){// 章-1
  低水準1();
  低水準2();
}
function 低水準1(){// 節-1
  極低水準1();
  極低水準2();
  極低水準3();
}
function 極低水準1(){// 本文内容
  // 処理
}
function 極低水準2(){// 本文内容
  // 処理
}
function 極低水準3(){// 本文内容
  // 処理
}
function 中水準2(){// 章-2 本文内容
  // 処理
}
function 中水準3(){// 章-3
  低水準3();
}
function 低水準3(){// 節-2 本文内容
  // 処理
}

 上記例が読み難い原因はいずれも同レベルfunctionで宣言されているためです。例えばJavaScriptの関数内関数でレベル分けをするならば次の様になります。

function 高水準(){// 目次
  中水準1();
  中水準2();
  中水準3();
}

function 中水準1(){// 章-1
  低水準1();
  低水準2();
  function 低水準1(){// 節-1
    極低水準1();
    極低水準2();
    極低水準3();
    function 極低水準1(){// 本文内容
      // 処理
    }
    function 極低水準2(){// 本文内容
      // 処理
    }
    function 極低水準3(){// 本文内容
      // 処理
    }
  }
  function 低水準2(){// 節-2 本文内容
    // 処理
  }
}

function 中水準2(){// 章-2 本文内容
  // 処理
}

function 中水準3(){// 章-3
  低水準3();
  function 低水準3(){// 節-3 本文内容
    // 処理
  }
}

 読みやすくなりました。この書き方そのままではネストが深くなってしまいますが実際にはフォルダ、ファイル、クラス、プロパティ、アクセス修飾子などによる分類も用いて構造化を行うことで、深いネストの回避とレベルの統一された階層化を実現します。

高水準─┬─中水準1─┬─低水準1─┬─極低水準1
        │           │           ├─極低水準2
        │           │           └─極低水準3
        │           └─低水準2
        ├─中水準2
        └─中水準3───低水準3
著者:杉浦

LeafletのアイコンオプションiconAnchorの意味

 Leafletは地図をJavaScriptで描画、操作するためのライブラリです。地図上に何かを置きたい時、それはアイコンオブジェクトを用いて実現することが多いです。アイコンを定義する際にはicon関数を用いて次の様に定義します。次のコードはMarkers With Custom Icons – Leaflet – a JavaScript library for interactive mapsからの引用です。

var greenIcon = L.icon({
    iconUrl: 'leaf-green.png',
    shadowUrl: 'leaf-shadow.png',

    iconSize:     [38, 95], // size of the icon
    shadowSize:   [50, 64], // size of the shadow
    iconAnchor:   [22, 94], // point of the icon which will correspond to marker's location
    shadowAnchor: [4, 62],  // the same for the shadow
    popupAnchor:  [-3, -76] // point from which the popup should open relative to the iconAnchor
});

 このオプションの中にiconAnchorというものがあります。直訳してマーカーの位置に対応するアイコンの点です。Leafletはこの緯度経度に、このアイコンを用いてマーカ―を、この地図上に置く、という様にマーカーを地図上に置きます。

L.marker([51.5, -0.09], {icon: greenIcon}).addTo(map);

 マーカーという以上、地図を見るものにその印を示すために絵を用います。iconAnchorはこの絵のどの部分に指定した緯度経度がくるかを指定するオプションです。もしiconAnchorを間違えた場合、矢印の根元のような直感的でない部分が位置を指すことになってしまいます。
 Explanation of Leaflet Custom Icon LatLng vs XY Coordinates – Stack Overflow
 このStack Overflowの図説が完結にまとまっていました。

 左上を(0,0)とし、用いるimgに合わせてpx単位で合わせることが基本になります。割合を用いないのはアンチパターンに見えますが、アイコンを定義する際の単位はいずれもピクセル単位となっているためこのやり方が推奨のやり方となっています。

著者:杉浦

HSL表記によって色を自然に変化させる

 色の表記の定義である色空間には様々なものがありますよく聞くものに赤青緑の三原色を用いたRGB、それに加えて透明度を足したRGBAがあります。他にも印刷で使われるCMYK(Cyan, Magenta, Yellow, Key plate)やLab色空間、XYZ表色系など目的に合わせて多くのものが作られています。HSLはその中の一つでHLSとも呼ばれ色相(Hue)、輝度(Lightness)、彩度(Saturation)の3値から定義される色空間です。HLSの値の大雑把な意味は次です。

  • 色相:色味を0~360度の範囲の角度で表す。0度は赤で、その反対側に位置する180度は赤の反対色にあたる青緑。すなわち、反対色を見つけるのも容易。色相についてはHSVと同じ。
  • 彩度:HSVとは違い、純色から彩度が落ちるということは、すなわち灰色になっていくという考え方に基づいている。
  • 輝度:明度100%を純色とし、そこからどれだけ明るさが失われるかを示すHSVとは違い、輝度0%を黒、100%を白とし、その中間(50%)を純色とする。50%以下はHSVの明度を示し、50%以上はHSVの彩度を示すと考えると分かりやすいだろう。

HLS色空間 – Wikipediaより引用

 紹介するHSLの主な利点は二つです。まず第一にCSSのオプションとして直接指定できます。次の様にhsl(hue, ssaturation, lightness)を指定するのみで大変楽です。

style="background-color: hsl(90deg, 100%, 50%);

CSS を使った HTML の要素への色の適用 – HTML: HyperText Markup Language | MDN #HSL_functional_notation
– CSS: カスケーディングスタイルシート | MDN #HSL_colors
 わざわざ変換式を実装してRGBに変える必要も、RGB上でややこしい計算をする必要もありません。
 第二は自然で多彩な色の変化を簡単に表せることです。次のJSFiddleはHSL方式とRGB方式それぞれで箱の中の色を変えるコードの実装です。

 色相の下に彩度、輝度が引っ付いているイメージで簡単に色を決定することができると思います。RGBでは赤緑青から離れる程どうやって思いついた色を作るのかてこずるでしょう。
 HSLがRGBに比べて特に便利なのがある色からある色への変化です。同時刻にある色になる様に三値をそれぞれ一次関数的に変化させるのみできれいな色の変化を実現できます。

著者:杉浦

Vue.jsでVue.js向けに開発されていないライブラリを用いる

 Vue.jsはwebページを部品化してコーディングすることを目的としたJavaScriptのフレームワークです。単一コンポーネントの仕組みを用いたVue.jsのコード例の多くは(少なくとも私の読んだコードでは)次の様になっています。

// コンポーネント定義用Vue.jsコード
<template>
  // Vue.jsと連携するHTMLコード
</template>

<script>
export default {
  name: 'hoge',
  // prop:{}とかdeta(){return {hogehoge}}とかmethods:{}とかVue.jsと連携するためのプロパティ
};
</script>

<style scoped>
  // このコンポーネント内でのみ適用されるcss
</style>
// コンポーネント読み込み用JavaScriptコード
window.$ = window.jQuery = require('jquery');
// 色々グローバルで使うライブラリ

window.Vue = require('vue');

Vue.component('hoge', require('./hoge.vue').default);

const app = new Vue({
  el: '#app',
});

 自分はVue.jsで使うことを前提にしていないライブラリはJavaScript側2、3行目の様に色々読み込むものだと思っていました。一方でこのようなやり方はグローバル汚染がひどく、重要なごく一部のライブラリ以外を読み込んだ場合あっという間にバグが生まれるとも思っていました。実際はそのようなことをせずともよく、次の様に記述することで管理しやすくライブラリを用いることができました。

<template>
  // Vue.jsと連携するHTMLコード
</template>

<script>
import 'fuga';
import foo from 'foo';

// Vue.jsに依らない静的処理
const bar = foo.bar();

export default {
  name: 'hoge',
  // importしたライブラリや変数barを用いたVue.jsと連携するコード
};
</script>

<style scoped>
  // このコンポーネント内でのみ適用されるcss
</style>

 <script>タグの先頭に記述するだけです。<script>タグの内部ならばVue.jsがいい感じにスコープを作ってくれるのでグローバル汚染を気にせず好き勝手できます。
 <script>export default {で始めて、}</script>で終わらなければならないという風に思い込んでいましたがVue.jsにその様な縛りはなく、実際はかなり自由に記述できました。

著者:杉浦

HTMLの検証を行ってくれるwebサービスNu Html Checker

Ready to check – Nu Html Checker
 Nu Html CheckerはHTMLのバリデーターです。HTMLソースを読ませるとそれがW3C準拠なのかを始めとして様々な警告をしてくれます。読ませ方は様々です。上記リンクからはwebページのアドレス、HTMLファイル、HTMLソースコードそのものを読み込むことでHTMLバリデーションを実行するページへ飛べます。
 バリデーションの結果よく報告されるのは既に非推奨、不要な属性である、そこにそのタグを置くべきでない(label中にdivなど)の様なものから文法エラーまで多岐に渡ります。いくつかのページで試しましたが、エラーが一斉なかったのはNu Html Checkerのみでした。
 Ready to check – Nu Html Checker中のAbout this checkerにはより詳細な使い方が載っています。主にローカルで動かす手法とブックマークレットで動かす手法の二種類です。ブラウザのセキュリティ機能で動かない時がままありますが、HTMLが動的に生成される場合でも簡単に対応できるブックマークレットは特に便利です。

著者:杉浦

Leaflet関連のライブラリを用いる際たまに起こるライブラリのバグ

Leaflet – a JavaScript library for interactive maps
 LeafletはJavaScript上で地図を描画、操作できる様にするライブラリです。地図の需要は多くLeafletを拡張するライブラリもまた多くあります。紹介するのはこのLeafletに何かを付け足すようなライブラリにありがちなバグです。
 Leaflet関連のライブラリはLeafletに様々なものを載せます。例えばフルスクリーン化、google map、ミニマップ、サイドバー。重要なのはこれらのいずれもまずLeafletありきだということです。このためライブラリの中には単独で動くようにライブラリ内でLeafletを読み込んでくれるものがいます。これ自体はありがたいしそのライブラリ単独ではむしろ良いことです。ですがこの動作を既にLeafletが読み込まれているにも関わらず行った場合、問題が起きます。既に読み込まれていたLeafletを壊すことがあるのです。このLeafletを壊すような問答無用な読み込み動作を行うライブラリが稀にあります。
 Leaflet読み込み動作付きライブラリと他のライブラリを混ぜ合わせて使うと、他のライブラリを上書きして、存在するはずの関数が存在しない、引数の型が期待したものと異なるといった混乱が引き起こされバグが発生します。対処法はライブラリの中を見て

import L from 'leaflet'

の様な変数Lにleafletを出力している様な記述があるかチェックして消し、プロジェクト内に移動しパスを変更するだけです。
 ライブラリの中をいじること自体はバージョン管理が面倒になるアンチパターンもいい所なのであまり褒められたやり方ではありませんが、幸いLeaflet拡張機能系統のライブラリは小さなものが多く個人でもすぐに読み解け管理できます。