D3.js Cubism.js ... 美しい作品。
複数の水平線グラフを同期させて表示する必要があるため、独自のデータソースで Cubism.js を使用してみました。
更新の間隔は非常に短い (1 秒未満) ため、データ ソースから値をバッチで取得する必要があります。すべて 1 回の呼び出しで行います。
要求された START,STOP と格納されている lastSTART,lastSTOP を比較して、最新のデータをロードするかどうかを決定します。
私のコードでは機能していますが、水平グラフごとにデータ更新 CALLBACK 関数を正しく呼び出す方法がわかりません。
表示時は直近のグラフのみ更新されます。
誰でもこの問題を解決するのを手伝ってくれますか?
コード:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:lang="sk">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta charset="utf-8"/>
<title>DRI_realtimeSeries</title>
<link type="text/css" rel="stylesheet" href="./style.css"/>
<script src="./d3.v2.js"></script>
<!-- <script src="./d3.js"></script> problem with d3.CSV !!!! -->
<script src="./cubism.v1.js"></script>
</head>
<body>
<div id="view"></div>
<script id="JSON" type="text/javascript">//<![CDATA[
var context = cubism.context()
.serverDelay(1 * 1000)
.clientDelay(1 * 1000)
.step(1000)
;
var horizon = context.horizon();
var metrics = [ "en", "es", "de", "fr"];
var lastStart = null, lastStop = null;
var callArr = {};
var horizon = context.horizon()
.metric(function(d) {
return context.metric(
function(start, stop, step, callback) {
callArr[md] = callback;
if ((+lastStart != +start) || (+lastStop != +stop)) {
lastStart = +start; lastStop = +stop;
d3.json("http://localhost/COMPONENTS/Cubism/DRI_data.php"
+ "?expression=" + encodeURIComponent("sum(request.eq(language,'" + md + "'))")
+ "&list=" + encodeURIComponent(JSON.stringify(metrics))
+ "&start=" + d3.time.format.iso(start) //cubism_cubeFormatDate(start)
+ "&stop=" + d3.time.format.iso(stop) //cubism_cubeFormatDate(stop)
+ "&step=" + step,
function(data) {
{"en":[ {"time":"2012-10-24T14:47:53.000Z","value":-37},
{"time":"2012-10-24T14:47:54.000Z","value":115},
{"time":"2012-10-24T14:47:55.000Z","value":100},
....
{"time":"2012-10-24T14:48:00.000Z","value":94}
],
"es":[ {"time":"2012-10-24T14:47:53.000Z","value":32},
....
{"time":"2012-10-24T14:48:00.000Z","value":0}
],
....
}
for (var imd in callArr) {
if (callArr.hasOwnProperty(imd)) {
var callbackI = callArr[imd];
//HERE is something WRONG
if (!data) { return callbackI(new Error("unable to load data")); };
callbackI( null, data[imd].map( function(d) { return d.value; } ));
}
}
}
);
}
}, md=d );
}
);
d3.select("body").selectAll(".horizon")
.data(metrics)
.enter().append("div")
.attr("class", "horizon")
.call(horizon);
//]]></script>
</body>
</html>
PHP バックエンド:
シミュレーション目的のみ - タイムスタンプ付きの値の名前付き配列を持つ JSON オブジェクトを
返す
<?php
//default:
$GP = array('list' => '["all"]');
if (isset($_POST['expression'])) $GP['expression'] =$_POST['expression']; elseif (isset($_GET['expression'])) $GP['expression'] =$_GET['expression'];
if (isset($_POST['start'])) $GP['start'] =$_POST['start']; elseif (isset($_GET['start'])) $GP['start'] =$_GET['start'];
if (isset($_POST['stop'])) $GP['stop'] =$_POST['stop']; elseif (isset($_GET['stop'])) $GP['stop'] =$_GET['stop'];
if (isset($_POST['step'])) $GP['step'] =$_POST['step']; elseif (isset($_GET['step'])) $GP['step'] =$_GET['step'];
if (isset($_POST['list'])) $GP['list'] =$_POST['list']; elseif (isset($_GET['list'])) $GP['list'] =$_GET['list'];
if ( ! ( isset($GP['expression']) && isset($GP['start']) && isset($GP['stop']) && isset($GP['step']) ) ) {
exit;
}
$iso_format = "%Y-%m-%dT%H:%M:%S.%LZ";
$start = umktime(strptime($GP['start'], $iso_format));
$stop = umktime(strptime($GP['stop' ], $iso_format));
$step = $GP['step' ]; //milisecs
$GP['list'] = json_decode($GP['list']); if (! $GP['list']) { exit;}
$cnt = count($GP['list']);
$larray = array();
for($i = 0; $i < $cnt; $i++) {
$rarray = array();
for ($dt = $start; $dt <= $stop; $dt+= ($step/1000.)) {
$rarray[] =
array(
"time"=> strftime("%Y-%m-%dT%H:%M:%S",$dt).sprintf(".%03dZ",($dt - (int)$dt)*1000),
"value"=> rand(-50,150)
);
}
$larray[$GP['list'][$i]] = $rarray;
}
echo json_encode($cnt == 1 ? $rarray : $larray);
function umktime($u_tm_arr) {
//int mktime ([ int $hour = date("H") [, int $minute = date("i") [, int $second = date("s") [, int $month = date("n") [, int $day = date("j") [, int $year = date("Y") [, int $is_dst = -1 ]]]]]]] )
$mkt = mktime( $u_tm_arr['tm_hour'],$u_tm_arr['tm_min'],$u_tm_arr['tm_sec'],$u_tm_arr['tm_mon'] + 1,$u_tm_arr['tm_mday'],($u_tm_arr['tm_year'] + 1900) - 2000 );
$mkt = (float)$mkt;
if (isset($u_tm_arr['tm_msec'])) { $mkt += (((float)$u_tm_arr['tm_msec'])/1000) ; }
return $mkt;
}
//Windows strptime
function strptime($date, $format) {
$masks = array( '%d' => '(?P<d>[0-9]{2})', '%m' => '(?P<m>[0-9]{2})', '%Y' => '(?P<Y>[0-9]{4})',
'%H' => '(?P<H>[0-9]{2})', '%M' => '(?P<M>[0-9]{2})', '%S' => '(?P<S>[0-9]{2})', // usw..
'%L' => '(?P<L>[0-9]{3})', '%u' => '(?P<u>[0-9]{3})',
);
$rexep = "#".strtr(preg_quote($format), $masks)."#";
if(!preg_match($rexep, $date, $out)) {
return false;
}
$ret = array( "tm_sec" => (int) $out['S'], "tm_min" => (int) $out['M'], "tm_hour" => (int) $out['H'],
"tm_mday" => (int) $out['d'], "tm_mon" => $out['m']?$out['m']-1:0, "tm_year" => $out['Y'] > 1900 ? $out['Y'] - 1900 : 0,
"tm_msec" => (int) (isset($out['u']) ? $out['u'] : (isset($out['L']) ? $out['L'] : 0) ),
);
return $ret;
}
?>