ラベル JavaScript の投稿を表示しています。 すべての投稿を表示
ラベル JavaScript の投稿を表示しています。 すべての投稿を表示

2015年5月24日日曜日

テーブルデータのグラフ表示

さてCouchDBを使って、テーブルデータを扱うhtmlはできましたが、まだ表だけです。やはりここはグラフ表示できないと使い物になりません。そこでjCanvasを使ってグラフ表示できるようにしてみました。 まずデータの読込です。

ここで1つデータを追加します。
とまあ、順調にできました。
いつもならここでコードを参考に載せるところですが、機能的にまだあまりに不足している部分があるので、今回はパスします。こういう汎用的なものなら、以下の機能が欲しいところです。
・グラフを描画するcanvas要素のサイズに応じて描画。
・グラフ描画の際の上下左右のマージンをパラメータ化。
・あと、グラフの軸に目盛りが欲しい!
はっきりいって「とりあえず描画できるのを確認した」というレベルのコードしかまだできていません。( ;´Д`)まだ使い物になるかわかりませんが、少し様子をみて使い物になりそうなら、コードを作り込んでからまたブログに載せます。



2015年5月5日火曜日

CouchDB テーブルデータを表示/更新

さて単純なデータの表示/更新はできました。続いてテーブルデータです。例としては高度による静圧を取り上げます。とりあえず、出来た結果の表示例を以下に示します。(注:うっかり例には「標準大気圧テーブル」と書いてしまいましたが、正確には標準大気圧を元にした静圧のテーブルです。後で気づきました。(^_^;))


これの元になったCouchDBのドキュメントは以下です。

{ "_id": "StaticPressure", 
 "_rev": "16-482692fb61559cf3ad7224021b093d63", 
 "name": "StaticPressure", 
 "value": { "StaticPressure": [ { "Alt": 0, "P": 10332 }, { "Alt": 1, "P": 9167 }, { "Alt": 2, "P": 8106 } ] }, 
 "unit": "Alt[km],P[kgf/m2]" }

取り扱いたいデータは、"value"項にあるObjectのArrayです。(後にデータの追加を説明しますが、最初はこれもjson形式だと勘違いしていましたが、正確には違うんですね。そのためjsonのデータハンドリングが使えず、JavaScriptのObjectのデータとして取り扱います。つまりObjectのArrayがjsonの一つのデータとして格納されている形になっています)

「読込」ボタンで動くJacaScriptを以下に示します。


   var url = 'http://localhost:5984/environment/StaticPressure';
   var json;
   var json_part; // 静圧テーブルデータ部分(正確に言うと狭義のJSONとは違う)


   function exec() {
    // データの読み込み
    $.ajax({
     type: "GET",
     url: url,
     dataType:'json',
    }).done(function(data) {
     json = data;
     json_part = data.value;

     for (var i=0; i<json_part.StaticPressure.length; i++) {
      // 表(table)の最後の行に追加
      $('#table1 > tbody:last').append('<tr><td>'+ json_part.StaticPressure[i].Alt +'</td><td>'+ json_part.StaticPressure[i].P +'</td></tr>');     
     }

    }).fail(function(xhr, textStatus, errorThrown){
     alert('error!!');
     console.log("NG:" + xhr.status);
     console.log("NG:" + textStatus.status);
     $('#msg').append("失敗しました");
    });

   }


#table1というidのtableタグがhtml側に用意してあり、そこに読み込んだ静圧テーブルのデータを1行づつ追加していくだけです。

次に「追加」を実装します。最初の例に既に「読込」の右横に2個の入力フィールドとともに準備してあります。ここに、「0.5」「1000」という 値を入れて「追加」してみます。
無事データが一行追加されました。「追加」ボタンの実装を以下に示します。
function add() {
 var newAlt = parseFloat( $('#inputAlt').val() );
 var newPressure = parseFloat( $('#inputPressure').val() );

 // 入力データを追加する(単純に検索する)
 for (var i=0; i<json_part.StaticPressure.length; i++) {

  if (json_part.StaticPressure[i].Alt <= newAlt) {
   continue;
  }

  var newdata = {};
  newdata.Alt = newAlt;
  newdata.P = newPressure;

  // 表(table)のi行に追加
  $('#table1 tr').eq(i).after('<tr><td>'+ newdata.Alt +'</td><td>'+ newdata.P +'</td></tr>');

  // 静圧テーブルデータにも追加
  // 第1引数:変更を加えるindex
  // 第2引数:第1引数から難行のObjectを削除するか指定
  // 第3引数:変更として追懐したいObject
  json_part.StaticPressure.splice(i, 0, newdata);

  break;    
}

今回は注意点が2箇所あります。
①17行目でtableに値を追加しています。前回はappend( )を使いましたが、今回はafter( )を使いました。理由がわかりませんが、append( )だとテーブルの形が崩れたからです。(右横に1列追加される感じになってしまいました)この辺はもう少し勉強が必要です。
②23行目で実際のメモリ中のデータにも挿入しています。最初にも書きましたが、てっきりこれがjson形式のデータと思い込んでいたので、pushやなんか使おうとしたんですが、エラーばかり返されてきました。JavaScriptのObjectというデータ形式の中で、特にハンドリングしやすいようにフォーマットを決められたのがjsonとのことで、JavaScript内部のメモリでの持ち方はどちらも同じですが、使う関数が違います。splice( )と呼ばれるArrayに対する操作を行う関数を使っています。

ところで最初に「読込」時、テーブルデーを扱いやすくするため、json内部のvalueの部分だけjson_partという変数に代入してました。これまさしくポインタの代入で、「追加」の方でjsn_partにデータを追加したら、しっかしjsonの方にも反映されていました。(この辺りはjavaと同じで、変数は基本ポインタで値を保持しているようです)
後はこの新しいデータをCouchDBに戻してやるのと、せっかくテーブルデータなのでグラフが欲しいところですが、それはまた次回に。



2015年4月30日木曜日

CouchDB データを表示/更新するサンプル

ずいぶん前回から時間が空いてしまいました。余裕がなかったのもありますが、一番大きいのがこのBloggerでHTMLのソースを表示する方法が中々わからなかったのが一番大きい理由です。prettyprint使っても、どうしても内部のhtmlを本物のタグと解釈してしまうんです。結局そのままブログにペーストするのは諦めて、「偽の」HTMLに変換してからprettyprintすることにしました。(一手間増えるのと、ブログ編集中に確認がしづらいのでこの方法はどうしても嫌だったんですが、どうもこれしかなさそうです。あと変換ツールの問題なのか、シングルクオート、ダブルクオートの前にバックスラッシュが入ってしまいます。手作業で少しは削除しましたが、途中でめげました。) さて以下がサンプルで作成したHTMLの表示例です。
地球半径をCouchDBに登録したものです。「読み込み」ボタンでCouchDBからデータを読み込み表示し、「変更」でvalueに入力されている値をCouchDBに書き込みます。デバッグ用に、一番下に読み込んだり、書き込んだりするjson形式のデータを表示しています。
以下がそのサンプルです。(注:クオートの前にバックスラッシュが入ってしまっているのは無視してください。)

<!DOCTYPE html>
<html lang="ja">
 <head>
  <meta charset="UTF-8">
  <title>HTML5</title>
  <script src="jquery-1.11.2.min.js"></script>
  <script src="stringify.js"></script>
 </head>
 <body>
  <p>Hello Ajax, couchdb データ更新をします</p>
  <input type="button" value="読み込み" onclick="readCouch('msg');">
  <input type="button" value="変更" onclick="change()">
  <!-- <TEXTAREA cols="40" rows="6" id="texts" wrap="on"></TEXTAREA> -->
  <script>
   var url;
   url = 'http://localhost:5984/environment/Radius';
   var json;

   function readCouch(id) {
    var target = document.getElementById(id);

    $('#texts').text("これから読みます:");
    $('#msg').append("これから読みます:</br>");

    $.ajax({
     type: "GET",
     url: url,
     dataType:'json',
    }).done(function(data) {
     // alert('読み込み');
     json = data;
     $(\'#id_text\').val(data._id);
     $(\'#name_text\').val(data.name);
     $(\'#value_text\').val(data.value.toString());
     $(\'#unit_text\').val(data.unit);

     var str = $.stringify(data);
     $(\'#msg\').append(str);
    }).fail(function(xhr, textStatus, errorThrown){
     alert(\'error!!\');
     console.log(\"NG:\" + xhr.status);
     console.log(\"NG:\" + textStatus.status);
     $(\'#msg\').append(\"失敗しました</br>\");
    });

    $(\'#msg\').empty();
    $(\'#msg\').append(\"うまくいった?</br>\");

   }

   function change() {
    json.value = parseFloat($(\'#value_text\').val());
    var jsonStr = JSON.stringify(json);

    $.ajax({
     type: \"PUT\",
     url: url,
     data: jsonStr,
     dataType:\'json\',
    }).done(function(data) {

     var str = $.stringify(data);
     $(\'#msg\').append(str);
    }).fail(function(xhr, textStatus, errorThrown){
     alert(\'error!!\');
     console.log(\"NG:\" + xhr.status);
     console.log(\"NG:\" + textStatus.status);
     $(\'#msg\').append(\"失敗しました</br>\");
    });
   }
  </script>
  <br>
  <table border=\"0\">
   <tr>
    <td align=\"right\"><label>id : </label></td>
    <td><input type=\"text\" id=\"id_text\"></td>
   </tr>
   <tr>
    <td align=\"right\"><label>name : </label></td>
    <td><input type=\"text\" id=\"name_text\"></td>
   </tr>
   <tr>
    <td align=\"right\"><label>value : </label></td>
    <td><input type=\"text\" id=\"value_text\"></td>
   </tr>
   <tr>
    <td align=\"right\"><label>unit : </label></td>
    <td><input type=\"text\" id=\"unit_text\"></td>
   </tr>
  </table>
  <br>
  <p id=\"msg\"></p>
 </body>
</html>

これまでGUIでのデータ入出力画面をMotifやらViduslaStuioで組んできましたが、こっちの方がOSを選ばないので汎用性が高いです。(ただ2次元のグラフも表示したい、3次元のグラフィックが欲しい、とか言われるとHTML5のCanvsタグが必要になってくるので、現時点ではブラウザを選んでしまうのが悩ましいところです。)

追記:
ところで上記サンプルでは更新したいのは"value"だけなのに、ドキュメント全体のjsonデータをCouchDBに送信しています。これって無駄が多くない?と思い調べてみると、jsonStrを作るstringify( )で第2引数に特定のjsonデータだけを指定してやればjsonStrもそれだけが作れることがわかりました。
これはいい!と思って早速試してみたんですが、CouchDBのデータを管理するのがドキュメント単位で、さらにそれにrev番号まで付いています。つまり変更したい部分だけのjsonStrを送信してしまうと、残りの部分がなくなったドキュメントになってしまいます。ちょっとこれではうまくありません。あきらめるしかないようです。(あまりでかいドキュメントが必要になるようなデータベース構成にすると処理時間が問題になってきます)

2015年2月14日土曜日

JSON形式のハンドリング

couchdbとアクセスするためJSONを扱えるよう、JavaScript/jQueryによるJSONの処理方法を調べてます。

$.ajax()でGETすると、JSON形式でcouchdbからの応答をObjectの型式で読み込みます。データにアクセスするのは楽なのですが、デバッグ用に文字列で全体を表示しようと思うとすごいめんどくさい。調べてみると、stringify()という関数がよくでてきます。以下の様なスプクリプトをstringify.jsとか保存しておいてjQueryを拡張して使います。

(function($) {
 $.extend({
  stringify: function stringify(obj) {
   
   var t = typeof (obj);
   if (t != "object" || obj === null) {
    // simple data type
    if (t == "string") {
     obj = '"' + obj + '"';
    }
    return String(obj);
   }
   else {
    var n, v, json = [];
    var arr = (obj && $.isArray(obj));
     
    for (n in obj) {
     v = obj[n];
     t = typeof(v);
     if (obj.hasOwnProperty(n)) {
      if (t == "string") {
       v = '"' + v + '"';
      }
      else if (t == "object" && v !== null) {
       v = jQuery.stringify(v);
      }
      json.push((arr ? "" : '"' + n + '":') + String(v));
     }
    }
    return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
   }
  }
 });
})(jQuery);

皆んな困ってるようで、ググってると結構いろんな所ででてきます。今度は、$.ajax()でPUTしようとすると、送信データの形式がObjectではなくJSON形式の文字列で渡さないといけません。 これではjQueryにstringify()がなぜ実装されていないのか訳がわかりません。 さらにググると、JavaScript1.7からJSON.stringify()というのが実装されているのがわかり、納得しました。結局、ライブラリとして作ったファイルは一瞬で必要なくなったかの様に思えたのですが、話はこれで終わりませんでした。

ところがどっこい、IE8だとこのJSONというオブジェクトが実装されてません。ブラウザに実装されているJavaScriptのバージョンをチェックするスクリプトがあったので、調べてみると1.3です!(IEだと正確にはJScriptですが)会社関係だとシステムが対応してるのがまだIE8というところが多いと聞いています。(XPがダメになった時に、IE6からやっとあがったばっかりという所が多いと思います) 結局、当面はstringify.jsを使うようにしたほうがいいようです。
ちなみに以下に、そのスクリプトを示します。


<SCRIPT Language="JavaScript">
// Java Script 1.0以降で動作する関数
function funcGetVer() { return "1.0" ; }
</SCRIPT>

<SCRIPT Language="JavaScript1.1">
// Java Script 1.1以降で動作する関数
function funcGetVer() { return "1.1" ; }
</SCRIPT>

<SCRIPT Language="JavaScript1.2">
// Java Script 1.2以降で動作する関数
function funcGetVer() { return "1.2" ; }
</SCRIPT>

<SCRIPT Language="JavaScript1.3">
// Java Script 1.3以降で動作する関数
function funcGetVer() { return "1.3" ; }
</SCRIPT>

<SCRIPT Language="JavaScript1.4">
// Java Script 1.3以降で動作する関数
function funcGetVer() { return "1.4" ; }
</SCRIPT>

<SCRIPT Language="JavaScript1.5">
// Java Script 1.3以降で動作する関数
function funcGetVer() { return "1.5" ; }
</SCRIPT>

<SCRIPT Language="JavaScript1.6">
// Java Script 1.3以降で動作する関数
function funcGetVer() { return "1.6" ; }
</SCRIPT>

<SCRIPT Language="JavaScript1.7">
// Java Script 1.3以降で動作する関数
function funcGetVer() { return "1.7" ; }
</SCRIPT>

<SCRIPT Language="JavaScript1.8">
// Java Script 1.3以降で動作する関数
function funcGetVer() { return "1.8" ; }
</SCRIPT>

<SCRIPT Language="JavaScript1.9">
// Java Script 1.3以降で動作する関数
function funcGetVer() { return "1.9" ; }
</SCRIPT>

<SCRIPT Language="JavaScript2.0">
// Java Script 1.3以降で動作する関数
function funcGetVer() { return "2.0" ; }
</SCRIPT>

<SCRIPT Language="JavaScript">
// Java Script のバージョンを取得して表示する関数
  function funcVerDisp()
{
var strVersion = funcGetVer() ;
alert( 'このブラウザーの Java Scriptのバージョンは\n\t' + strVersion + ' です。\n' ) ;
}
</SCRIPT>

なんか同じ関数を何度も定義してますが、SCRIPTでのlanguage指定がキモです。ここで対応するバージョンを指定していますが、同じ関数定義をすると最後のものが有効になります。そこでhtml内のbuttonからonclickでfuncVerDisp()をCallしてやるようにすれば、バージョン名をダイアログで表示してくれます。ちなみに私が普段使いしているchromeは1.7でした。(最初にこのテクニックを紹介していたサイトでは、SCRIPTの中で、Type="javascript"というtype属性をつけていましたが、それではうまく動きませんでした。調べてみるとtype属性はスクリプトバージョンには関係しないので、返ってそれ以降の指定が無効になってしまうようです。)

結局、stringify()の使い方ですが、以下のように使います。

var jsonStr = '{"message":"success", "returnCode":0}';
json = $.parseJSON(jsonStr);

var str = $.stringify(json);

最初にJSON形式の文字列をjQueryの関数でObject形式にしていますが、JavaScript1.7だと、JSON.parse()という同様のものがあります。しかしこれもIE8では使えないので、色んな環境で動かしたいならjQueryにまかせた方がいいようです。

2015年1月31日土曜日

CouchDB JavaScriptからの読み込みについて

CouchDBのUIを作ってみたくなり、htmlを書いてみます。せっかくなのでjQueryを使って、Ajaxを試して見たいと思ったのですが、ここからが苦難の始まりでした。

簡単なサンプルを書いてみたんですが、どうしてもNo 'Access-Control-Allow-Origin' header is present on the requested resource.というエラーがコンソールに出てきて失敗します。(ChromeのJavaScriptコンソールで確認しています)色々、調べてみたんですが、エラーの意味はXSSを防ぐため、ドメインが異なるJavaScriptを実行したり、読み込もうとするとでるエラーのようです。(数年前、これおを悪用したサイトの改竄が流行った記憶があります)しかし自分はローカル環境、あるいは家庭内の別PCで動かしているcouchdbから読もうとしているんですが、このエラーから逃げれません。
そこで、jQueryの問題なのかcouchdbの問題なのか区別するため、素に戻って単純にJavaScriptでローカルPCに置いたjsonデータを読むプログラムを書いてみました。

   function loadJson(id) {
    $('#msg').append("これから読みます:");

    var url = "http://localhost/~hogehoge/test1.json";
    var xmlHttp;

    xmlHttp = new XMLHttpRequest();
    xmlHttp.open("GET", url, false);
    xmlHttp.send(null);

    $('#msg').append(xmlHttp.responseText);

    $('#msg').append("うまくいった?");

   }

(これをやるために前回「ウェブ共有」の設定を調べました)
ところがMac上のchromeからでは相変わらず同じエラーが出ます。幾ら何でもこれはおかしいだろうと、調べてみるとchromeではセキュリティを厳しくしていて、ローカルPC上のファイルをhttp経由で読もうが、同じチェックをしていてエラーを出すそうです。ちなみに同じものをSafariで実行してみたら、あっさり動きました。(ちなみに同様のスクリプトをjQueryで書くと、Safariでもエラーがでます。どうもjQuery内部で同様のチェックをしているようで、簡単に自分のとこだけで試してみようと思っているのに難儀なことです)

さてCouchDBのUIを作ろうと思ったらなんとかcouchdbの設定で'Access-Control-Allow-Origin' のヘッダをつけるようにしないといけません。
現状、使用しているcouchdbは1.6ですが、1.4のドキュメントには以下の設定があるのがわかりました。

local.iniに以下の設定を追加。

[httpd]
enable_cors = true

[cors]
origins = *

特に[cors]の項目はデフォルトの設定ファイルには存在しておらず大丈夫かと思いましたが、うまくいきました。(ただこの設定は「全て許可する」という意味なんで、あまり推奨できませんが…本当は単にローカルPC上だけで動かしたいだけなら、origins=http://localhostとかするのがいいと思います。でもこれだと、http://127.0.0.1でアクセスすると拒否されてしまい、難しいところです。)
さて実際にcouchDBからデータを読み込んでみます。以下のプログラムで試してみました。(htmlにはボタンをつけて、以下のスクリプトを実行するようにしています)

   function readCouch(id) {
    $('#msg').append("これから読みます:");
    var url;
    url = 'http://localhost:5984/kakeibo';
    $.ajax({
     type: "GET",
     url: url,
     dataType:'json',
    }).done(function(data) {
     alert('読み込み');
     var str = parseJson(data);
     $('#msg').append(str);
    }).fail(function(xhr, textStatus, errorThrown){
     alert('error!!');
     console.log("NG:" + xhr.status);
     console.log("NG:" + textStatus.status);
     $('#msg').append("失敗しました");
    });

    $('#msg').append("うまくいった?");
   }

   function parseJson(json) {
    var ret = 'db_name : ' + json.db_name + '';
    ret = ret + 'doc_count : ' + json.doc_count;
    return ret;
   }

chromeで実行すると以下のようになります。(html上に、<p id=msg>が付けてあり、そこに追記するようにしています)


うまく読めましたね。

2014年1月11日土曜日

node.jsの勉強、謎の動作?

最近あまり話題になってないけど、一時期やたらnode.jsが騒がれていたと思います。特徴として、

  • イベントドリブンなので大量のrequestを受信しても問題が起きない。(単に停止するという、最悪な状態は発生しないよ、というサービスサイドの要求)
  • JavaScriptが基本で、生産性が高い(本当か?)
  • 一方、まだバージョンが0.Xの状態で安定性に欠ける(メモリリークもひどい。これは最初の利点とちょっと矛盾しますが)
とりあえず触ってもみずにあれこれいうのも何なので、少しやってみました。で、動いたことは動いたんですが、ちょっと謎の動きがあり、原因がまだつかめてません。

【現象】
server.on('request', function(req, res) { }

クライアントであるブラウザからの要求(request)のイベントに反応して行う処理を記述する部分ですが、chromeと、IE/FireFoxで動きが異なる。
問題はchromeの方。ページ更新を1回しかしていないのに、2回処理が動いてしまう。
しかもWireSharkで通信内容を調べてみると、node.jsから返信している2回目の内容を画面に反映していない。(従って、連続してページ更新を行うと、1回ごとに2回分の処理が行われるように見える)
但し、送信ボタンを押して処理を行う、というイベント処理では特に2回動くということはなく、chrome/IE/FireFoxとも同じ動きをしています。

WireSharkのログを比較しても、若干違いがあるのはわかるんですが、node.jsがパケットの何をトリガに、このイベントを発生しているのかまだよくわかってないためもう少し時間がかかりそうです.。

少しnode.jsを調べていたら、それらしいhintがみつかりました。そういえばchromeはURL表示欄にFaviconを表示しています。それらはページ更新の際、個別のrequestとしてServerには認識されるそうです。Server処理の方できちんと区別して、試してみて確認しないと。

2014年1月6日月曜日

Ubuntuのnode.js実装

今度はnode.jsを少しかじってみようと思い、手元のUbuntu13に環境を準備します。(こういうこと考えると、vagrantで仮想環境の自動構築って便利だと初めて実感しました。最初は、なんでそんな気機能が必要なのか思いつかなったんで)

ググってみると、ソースをDLしてビルドする人、Ubuntuのapt-getで済ます人、半々のようです。どちらがいいか迷ったんですが、ソースからビルドすると大抵後で削除するのが面倒なことが多いです。他のものに影響を与えても原因追究しづらいし。
ということで、まずはすなおにUbuntuのapt-getでインストールします。


$ sudo apt-get install nodejs npm
[sudo] password for hoge:
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています    

node.js本体とパッケージを管理するnpmを個別にインストールするようです。
メッセージが大量に流れますが、特に問題なくインストールは終了しました。

簡単なプログラムを以下に示します。(JavaScriptになります)
hello.js
var http = require('http');
var server = http.createServer();
server.on('request', function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('Hello World!');
res.end();
});
server.listen(1337, '192.168.24.64');
console.log('Server running at 1337');


赤字はport番号と、(自PCの)IPアドレスです。
これで実行は以下の通りです。


$ nodejs  hello.js
Server running at 1337


(注:他のサイトの例では'node’コマンドでしたが、今回なぜか'nodejs’に変わっていました。おそらくubuntuだけの実装だと思われます)


あとはブラウザで当該port番号で開いてみれば動作を確認できます。無事"Hello World!"の表示を確認できたので、いくつかサンプルを試してみました。

そのうち「ejs」というテンプレートを処理するパッケージを使用するサンプルがでてきて(よく使われるようです)、まずそれをインストールしないといけません。ここでパッケージ管理のnpmの出番になります。

$ npm install ejs
npm http GET https://registry.npmjs.org/ejs


npm ERR! Error: failed to fetch from registry: ejs
npm ERR!     at /usr/share/npm/lib/utils/npm-registry-client/get.js:139:12
npm ERR!     at cb (/usr/share/npm/lib/utils/npm-registry-client/request.js:31:9)
:
:


なんだろう?Ubuntu独自実装のnodejsに問題があるのか?

後日、VMPlayer上に試験環境として用意してある別のPC上のUbuntuにソースからDLしてインストールしてみました。

$  ./configure
$  make
$  sudo make install

(/usr/local以下にinstallされた。わりと行儀がいい。)
次にnpmをインストールしようと思ったが、サイトにあったやり方を見ると、何をしようとしているのかよく意味がわからない。他のサイトではnode.jsと一緒にインストールされるとあったが、調べてみると、/usr/local/bin/npmと既に存在していた。

$ npm install ejs
npm http GET https://registry.npmjs.org/ejs
npm http 200 https://registry.npmjs.org/ejs
npm http GET https://registry.npmjs.org/ejs/-/ejs-0.8.5.tgz
npm http 200 https://registry.npmjs.org/ejs/-/ejs-0.8.5.tgz
ejs@0.8.5 node_modules/ejs
$

サイトの出力例とは若干違うが(バージョンも違うし)、普通にインストールできた。

やはり、Ubuntu独自の実装に問題がありそうだ。