まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

タグ:javascript

Chart.js は棒グラフや折れ線グラフなどの各種グラフやチャートを描画するための JavaScript ライブラリです。グラフを描くだけならかなり簡単に使うことができて便利です。また MIT ライセンスが採用されており、商用を含めた柔軟な利用が可能になっています。

今回はこの Chart.js を使って円グラフを作る例を紹介します:
2018030900


<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.3/Chart.min.js"></script>

  :
  :

<canvas id="myChart"></canvas>

  :
  :

<script>
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart( ctx, {
  type: 'pie',
  data: {
    labels: [ "Red", "Green", "Blue" ],
    datasets: [{
      backgroundColor: [
        "#ff0000",
        "#00ff00",
        "#0000ff"
      ],
      data: [ 150, 100, 20 ]
    }]
  }
});
</script>

  :
  :

キャンバスの 2D コンテキストを取得し、グラフ種類、ラベル、色、そして数値データを指定して描画しています。上記コードの "pie" という部分が円グラフを指定しており、ここを変更することで円グラフ以外のチャートを作ることもできます。

この内容を実際にこのページ内に埋め込むと以下のようになります: 




なんとなく直感的にというか、 ウェブで簡単に使えるグラフ描画ライブラリだと思ってます。

JavaScript で JSON 配列をソートする、意外と簡単な方法があります。具体例として、例えば以下のような JSON 配列: myArray があったときに、
var myArray = [
 { id: 1, name: "鈴木", age: 30 },
 { id: 2, name: "田中", age: 29 },
 { id: 3, name: "佐藤", age: 35 },
   :
];

この JSON 配列を age 要素の小さい順にソートしたいという場合にどうやるか、というケースを紹介します。


まず、JavaScript の配列には sort 関数が標準で用意されています。直感的にこんな感じで使えます:
var array1 = [ 30, 29, 35 ];
array1.sort();                  //. => array1 = [ 29, 30, 35 ];

注意点として sort() 実行後の返り値がソート結果になるのではなく、実行すると array1 そのものが書き換えられる、という点に注意が必要です。

sort() 関数には比較関数をパラメータで指定して、比較方法を指定することもできます。例えば以下の例では比較関数 compare を「小さい順に並べる」ような内容にしているので、sort() 実行後に小さい順にソートされます(要するに普通の sort() と同じ結果になります):
//. 比較関数
function compare( a, b ){ var r = 0; if( a < b ){ r = -1; } else if( a > b ){ r = 1; } return r; }
var array2 = [ 30, 29, 35 ]; array2.sort( compare ); //. => array2 = [ 29, 30, 35 ];

比較関数はパラメータ a と b の大小関係をその返り値によって定義します:
・返り値が 0 より小さい場合、a < b(aはbよりも前に来る)
・返り値が 0 より大きい場合、a > b(aはbよりも後ろに来る)
・返り値が 0 の場合、a = b(aとbの位置関係は変わらない)

したがって、compare 関数の返り値の符号を逆にすると「大きい順に並べる」という比較関数を指定したことになり、sort() 実行後に大きい順にソートされます:
//. 比較関数
function compare( a, b ){ var r = 0; if( a < b ){ r = -1; } else if( a > b ){ r = 1; } return ( -1 * r ); } var array3 = [ 30, 29, 35 ]; array3.sort( compare ); //. => array3 = [ 35, 30, 29 ];

上記 JSON 配列のソートもこの比較関数を使った sort() の応用で可能になります。具体的には以下のように age 要素で大小比較するような比較関数を用意します:
//. 比較関数
function compare( a, b ){ var r = 0; if( a.age < b.age ){ r = -1; } else if( a.age > b.age ){ r = 1; } return r; }
var myArray = [ { id: 1, name: "鈴木", age: 30 }, { id: 2, name: "田中", age: 29 }, { id: 3, name: "佐藤", age: 35 }, : ]; myArray.sort( compare );

これだけ。応用も簡単にできそうで超便利。


Node.js / Express を使って API を作成する場合は、こんな感じの記述で実装することになります(3000 番ポートで listen する POST /mypost を実装する場合の例):
var express = require( 'express' );
var app = express();

  :

app.post( '/mypost', function( req, res ){
   :
   :
});

  :

app.listen( 3000, function(){
  console.log( 'server running on port 3000...' );
});

これで POST /mypost を 3000 番ポートで待ち受ける API ができました。同一アプリケーション内の HTML などからであれば、こんな感じでリクエストを受けることができるようになります:
(jQuery を使って AJAX でポストする例)
  :
$.ajax({
  type: 'POST',
  url: '/mypost',
  data: { a: 1, b: 2, c: 3 }
}).done( function( result ){
  console.log( result );
});
  :

さて、ではこの POST /mypost を外部アプリケーションの HTML からリクエストするにはどうすればいいでしょうか?深く考えずに URL にサーバー名やポート番号も指定して、
(jQuery を使って AJAX でポストする例)
  :
$.ajax({
  type: 'POST',
  url: 'http://servername:3000/mypost',
  data: { a: 1, b: 2, c: 3 }
}).done( function( result ){
  console.log( result );
});
  :

こんな感じ↑にすればいいかというと、たしかに AJAX 部分はこれでいいのですが、結論としてはまだ不充分です。これを実行すると、ブラウザのコンソールには以下のようなメッセージが表示され、期待通りの挙動にはなりません:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://servername:3000/mypost. (Reason: CORS header 'Access-Control-Allow-Origin' missing).

CORS(Cross Origin Resource Sharing) というメカニズムによって、このリクエストはブロックされている、というエラーメッセージです。つまり「 servername:3000 上で動いている POST /mypost という API を外部から呼ぶことはポリシーに反しているのでできない」ということになります。

この外部リクエストを許可する方法はないでしょうか? CORS の設定の問題なので理論上はできるはずですが、その中でも比較的簡単な方法が cors ライブラリを使う方法です:
2017112401


この cors ライブラリを使うと CORS のデフォルトポリシーを変更して、柔軟に API のクロスオリジン対応が可能になります。以下に例を紹介しますが、まずは cors をインストールしておきます:
$ npm install cors

実際にクロスオリジンリクエストを許可するには以下のようにします。まずは全ての API をクロスオリジンで許可する場合です。API の定義を行う前に app.use() で cors を指定します:
var express = require( 'express' );
var app = express();
var cors = require( 'cors' );

app.use( cors() );   //. ここから下に定義する全ての API にクロスオリジン実行を許可する

  :

app.post( '/mypost', function( req, res ){  //. クロスオリジン実行が許可される
   :
   :
});

  :

app.listen( 3000, function(){
  console.log( 'server running on port 3000...' );
});

また、特定の API に対して個別にクロスオリジン実行を許可する場合は、以下のように指定します:
var express = require( 'express' );
var app = express();
var cors = require( 'cors' );

  :

app.post( '/mypost', cors(), function( req, res ){  //. POST /mypost のクロスオリジン実行は許可される
   :
   :
});

  :

app.listen( 3000, function(){
  console.log( 'server running on port 3000...' );
});




 

今更感もありますが、久しぶりにウェブでクッキー(cookie)を使う機会があったのでまとめておきました。

普通の JavaScript だけで扱う場合と、jQuery Cookie を使って便利にする場合と、2通りで記載しています。



【JavaScript でクッキーを書き込む】
document.cookie に '名前=値' のペアを書き込む:

(例)
document.cookie = 'name1=value1';


名前にはセミコロン、カンマ、空白文字は利用できない。
値は UTF-8 で記載し、encodeURIComponent() でエンコードする。


複数の '名前=値' を書き込む場合は繰り返し実行する:

(例)
document.cookie = 'name1=value1';
document.cookie = 'name2=value2';  //. 最新の実行結果だけでなく、2つとも記憶される



パラメータで属性を指定することも可能:

(例)
document.cookie = 'name1=value1;path=/path1';   //. /path1/** 以下のパスにアクセスした場合だけ有効なクッキーを設定
document.cookie = 'name2=value2;max-age=3600';  //. クッキーの有効期限を秒数で設定(指定しないとブラウザ終了時に無効になる)
document.cookie = 'name3=value3;expires=Sun, 17 Dec 2017 01:27:14 GMT';  //. クッキーの有効期限をGMTで設定(指定しないとブラウザ終了時に無効になる)



【JavaScript でクッキーを取り出す】
document.cookie の値をそのまま参照して取り出す:

(例)
var cookies = document.cookie;  //. 有効な '名前=値' のペアが、セミコロン区切りで取得できる



【JavaScript でクッキーを削除する】
「クッキーを削除する」関数は用意されていないので、「強制的に無効にする」方法を使います:

(例)
document.cookie = 'name1=value1;expires=Sat, 1 Jan 2000 00:00:00 GMT';



【jQuery Cookie とは?】
jQuery を使ってクッキーを便利・簡単に扱えるようにしたライブラリです。このライブラリを使う前に jQuery ライブラリを読み込んで置く必要があります:

(例)
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>


【jQuery Cookie でクッキーを書き込む】
$.cookie を使って名前と値を書き込みます:

(例)
$.cookie( 'name1', 'value1' );



オプションを指定することも可能です:

(例)
$.cookie( 'name1', 'value1', { expires: 7, path: '/path1' } ); //. /path1 以下のパスを指定して7日間保持



【jQuery Cookie でクッキーを取り出す】
$.cookie を使って、名前を指定してクッキーを取り出します:

(例)
var cookie = $.cookie( 'name1' );




【jQuery Cookie でクッキーを削除する】
$.removeCookie() を使って削除します:

(例)
$.removeCookie( 'name1' );


マンホールマップなど、地図や位置情報を使ったアプリを何度か作ったことがあります。地図を扱うためのライブラリはいくつかありますが、leaflet.js というオープンソースのマップクライアントライブラリを使う機会がありました:
2017110901


leaflet.js 自体はオープンソースで提供された JavaScript によるマップ操作クライアントライブラリです。ここで扱うマップは OpenStreetMap だったり、国土地理院のものだったり、(プラグインを使えば)Google MAPs だったりを選ぶことができます。

使い方も簡単で、まずは(CDN などから)leaflet の css と javascript をロードしておきます(以下の例では leaflet 1.2.0 を使っています。また後で使うので jQuery もロードしています):
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.2.0/leaflet.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.2.0/leaflet.js"></script>

HTML 内にマップを表示する部分を定義します。この例ではブラウザ画面全体に広がる <div id="demoMap"></div> を定義しています:
<style>
html, body  {
	width: 100%;
	height: 100%;
	padding: 0px;
	margin: 0px;
}
#demoMap {
	width: 100%;
	height: 100%;
}
</style>
  :
  :
<body>
<div id="demoMap"></div>
</body>

そしてメイン部分。上記の demoMap 内に地図を表示します。以下の例では OpenStreetMap を使って千葉県船橋市役所周辺の地図を表示し、市役所の位置にマーカーを置いて、2秒おきにマーカーをランダムウォークさせる、というものです:
<script>
//. 船橋市役所の緯度経度(初期位置)
var lat = 35.69471100;
var lng = 139.98262100;

var map = null;
var marker = null;

$(function(){
  //. 船橋市役所を中心とした地図を OpenStreetMap データで表示
  map = L.map('demoMap').setView( [ lat, lng ], 15 );
  L.tileLayer(
    'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: 'Map data © <a href="http://openstreetmap.org/">OpenStreetMap</a>',
      maxZoom: 18
    }
  ).addTo( map );
  
  //. 初期状態で市役所にマーカーを設置
  marker = L.marker( [ lat, lng ] ).addTo( map );

  //. マーカーを2秒おきにランダムウォークさせる
  setInterval( randomWalk, 2000 );
});

function randomWalk(){
  //. マーカー位置をランダムに移動
  lat += Math.random() / 100.0 - 0.005;
  lng += Math.random() / 100.0 - 0.005;
  var latlng = new L.LatLng( lat, lng );
  marker.setLatLng( latlng );
}
</script>


完成品の HTML はこちらに用意しました。全体を確認したい方はこちらから HTML ファイルをダウンロードしてください:
https://raw.githubusercontent.com/dotnsf/samples/master/leafletjs.html


ダウンロードした HTML をウェブブラウザで表示すると、以下のように船橋市役所を中心としたマップが表示され、青いマーカーが2秒おきにその場所を少しずつ変えて移動する様子が確認できると思います:
2017110901


こういったライブラリを使って地図アプリを作っておくと、利用する地図を変える(例えば OpenStreetMap だったり、Google MAPs だったりに変える)のが楽になりますね。

このページのトップヘ