2016-08-26 2 views
1

私はグラフをライブ更新しているのを見ることができるように、私は更新パターンに取り入れたいエリアチャートを持っています。私は棒グラフでこれを行うことができましたが、エリアチャートは最終的にデータポイントの量に適しています。エリアチャートを更新する

私の最善の試みは以下の通りです。更新プロセスは、2つの行選択と2つの領域選択の4つの部分に分割されています。これは私にとってうんざりしているようですが、それが私が働くように見えるようにする唯一の方法です。問題は、データを追加すると、グラフがブラウザで非常に低速で実行されてしまうことです。これは私に間違っていることを示唆しています。また、要素の不透明度は以前の静的グラフとは異なって表示され、新しいデータが追加される前に表示されるグラフの部分は、新しいデータを追加すると小さなスパイクに縮小されます。

日付でソートされたエリアチャートに更新パターンを組み込む正しい方法は何ですか?

////////////////////////////////////////////////// 
 
// initial data 
 
////////////////////////////////////////////////// 
 
var tdata = [ 
 

 
{ 
 
    "property":"humidity", 
 
    "date":"2016-06-28 05:47:10", 
 
    "value": 40, "unit": "\%" 
 
}, 
 
{ 
 
    "property":"humidity", 
 
    "date":"2016-06-28 05:47:20", 
 
    "value": 35, "unit": "\%" 
 
}, 
 
{ 
 
    "property":"humidity", 
 
    "date":"2016-06-28 05:47:30", 
 
    "value": 36, "unit": "\%" 
 
} , 
 
{ 
 
    "property":"humidity", 
 
    "date":"2016-06-28 05:47:40", 
 
    "value": 40, "unit": "\%" 
 
}, 
 
{ 
 
    "property":"temperature", 
 
    "date":"2016-06-28 05:47:15", 
 
    "value": 75, "unit": "F" 
 
} , 
 

 
{ 
 
    "property":"temperature", 
 
    "date":"2016-06-28 05:47:25", 
 
    "value": 70, "unit": "F" 
 
} , 
 

 
{ 
 
    "property":"temperature", 
 
    "date":"2016-06-28 05:47:35", 
 
    "value": 72, "unit": "F" 
 
}, 
 

 
{ 
 
    "property":"temperature", 
 
    "date":"2016-06-28 05:47:45", 
 
    "value": 75, "unit": "F" 
 
} , 
 

 
]; 
 
///////////////////////////////////////////////////////// 
 
// d3 code: 
 
///////////////////////////////////////////////////////// 
 

 
    var canvas = d3.select('#disp') 
 
     .append('svg') 
 
     .attr('width', 1200) 
 
     .attr('height', 200); 
 

 
    var x = d3.scale.linear().range([0,700]); 
 

 
    var y = d3.scale.linear() 
 
     .domain([0, 100]) 
 
     .range([200, 0]); 
 

 
    var line = d3.svg.line() 
 
    // .interpolate("cardinal") 
 
     .x(function(d) { 
 
     return x(d.date); 
 
     }) 
 
     .y(function(d) { 
 
     return y(d.value); 
 
     }); 
 

 
    var area = d3.svg.area() 
 
     //.interpolate("cardinal") 
 
     .x(line.x()) 
 
     .y1(line.y()) 
 
     .y0(y(0)); 
 

 
var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse; 
 

 
var lines = canvas.selectAll('path'); 
 

 
//////////////////// update function: 
 

 
function update(dataset){ 
 
// parse new date strings 
 
dataset.forEach(function(d) { 
 
    if(typeof(d.date) === "string"){ d.date = parseDate(d.date); } 
 
}); 
 
// sort by date 
 
dataset = dataset.sort(sortByDateAscending); 
 
// update domain 
 
x.domain(d3.extent(dataset, function (d) { return d.date; })); 
 
    
 
// (1) make temperature line selection, update 
 
lines = canvas.selectAll('.tline').data(dataset); 
 
    lines 
 
     .attr('class', 'tline') 
 
     .attr("d", function(d) { 
 
     return line(dataset.filter(function(d){ return d.property == 'temperature'})); 
 
     }) 
 
     .style("stroke", function(d){ return 'black'; }); 
 
// append new data to selection  
 
    lines 
 
     .enter().append("path") 
 
     .attr('class', 'tline') 
 
     .attr("d", function(d) { 
 
     return line(dataset.filter(function(d){ return d.property == 'temperature'})); 
 
     }) 
 
     .style("stroke", function(d) { 
 
     return 'black'; 
 
     }); 
 
// remove 
 
    lines.exit().remove(); 
 
// (2) make temperature area selection, update 
 
lines = canvas.selectAll('.tarea').data(dataset); 
 
     lines 
 
     .attr("class", "tarea") 
 
     .style('fill', 'red') 
 
     .style('opacity', '0.3') 
 
     .attr("d", function(d) { 
 
      return area(dataset.filter(function(d){ return d.property == 'temperature'})); 
 
     }); 
 
// append new data to selection  
 
     lines 
 
     .enter().append("path") 
 
     .attr("class", "tarea") 
 
     .style('fill', 'red') 
 
     .style('opacity', '0.3') 
 
     .attr("d", function(d) { 
 
      return area(dataset.filter(function(d){ return d.property == 'temperature'})); 
 
     }); 
 
//remove 
 
     lines.exit().remove(); 
 
// (3) make humidity line selection, update 
 
lines = canvas.selectAll('.hline').data(dataset); 
 
    lines 
 
     .attr('class', 'hline') 
 
     .attr("d", function(d) { 
 
     return line(dataset.filter(function(d){ return d.property == 'humidity'})); 
 
     }) 
 
     .style("stroke", function(d){ return 'black'; }); 
 
// append new data to selection  
 
    lines 
 
     .enter().append("path") 
 
     .attr('class', 'hline') 
 
     .attr("d", function(d) { 
 
     return line(dataset.filter(function(d){ return d.property == 'humidity'})); 
 
     }) 
 
     .style("stroke", function(d) { 
 
     return 'black'; 
 
     }); 
 
// remove 
 
    lines.exit().remove(); 
 
// (4) make humidity area selection, update 
 
lines = canvas.selectAll('.harea').data(dataset); 
 
     lines 
 
     .attr("class", "harea") 
 
     .style('fill', 'steelblue') 
 
     .style('opacity', '0.3') 
 
     .attr("d", function(d) { 
 
      return area(dataset.filter(function(d){ return d.property == 'humidity'})); 
 
     }); 
 
// append new data to selection 
 
     lines 
 
     .enter().append("path") 
 
     .attr("class", "harea") 
 
     .style('fill', 'steelblue') 
 
     .style('opacity', '0.3') 
 
     .attr("d", function(d) { 
 
      return area(dataset.filter(function(d){ return d.property == 'humidity'})); 
 
     }); 
 
// remove 
 
     lines.exit().remove();  
 

 

 
    } 
 

 

 
    function sortByDateAscending(a, b) { 
 
    return Date.parse(a.date) - Date.parse(b.date); 
 
}; 
 
////////////////////////////////////////////////////////////// 
 
// main code: 
 
////////////////////////////////////////////////////////////// 
 
addObjs(tdata) 
 
addObjs(tdata) 
 
addObjs(tdata) 
 
addObjs(tdata) 
 
addObjs(tdata) 
 
addObjs(tdata) 
 
addObjs(tdata) 
 
addObjs(tdata) 
 
addObjs(tdata) 
 

 
update(tdata); 
 

 
function btnfunc(){ 
 
addObjs(tdata) 
 
update(tdata); 
 
} 
 
// function to add new objects to dataset incremented by date 
 
function addObjs(arr) { 
 
var z = 1; 
 
var h = JSON.parse(JSON.stringify(arr[arr.length-2])); 
 
var t = JSON.parse(JSON.stringify(arr[arr.length-1])); 
 

 
h.property = 'humidity'; h.unit = '\%'; 
 
t.property = 'temperature'; t.unit = 'F'; 
 

 
var time = dparse(t.date); 
 
time+= z; 
 
h.date = timeString(time.toString()); 
 
h.value = 15 + Math.floor(Math.random()*31); 
 
time+= z; 
 
t.date = timeString(time.toString()); 
 
t.value = 65 + Math.floor(Math.random()*28); 
 

 
arr.push(h); 
 
arr.push(t); 
 

 
function timeString(ins) { 
 
    return ins.slice(0,4) + '-' + ins.slice(4,6) + '-' + ins.slice(6,8) + ' ' 
 
     + ins.slice(8,10) + ':' + ins.slice(10,12) + ':' + ins.slice(12); 
 
} 
 
function dparse(date){ 
 
var d = date.substr(0,10).replace(/-/g , ''); 
 
var t = date.substr(11,18).replace(/:/g , ''); 
 
var i = parseInt(d+t); 
 
return i; 
 
} 
 
    
 
}
.axis path, 
 
.axis line { 
 
    fill: none; 
 
    stroke: #000; 
 
    shape-rendering: crispEdges; 
 
} 
 

 
.area { 
 
    fill: steelblue; 
 
} 
 
body { 
 
     font: 10px sans-serif; 
 
    } 
 
    
 
    .axis path, 
 
    .axis line { 
 
     fill: none; 
 
     shape-rendering: crispEdges; 
 
    } 
 
    
 
    .tline { 
 
     fill: none; 
 
     stroke-width: 1px; 
 
     
 
    } 
 
    .hline { 
 
     fill: none; 
 
     stroke-width: 1px; 
 
     
 
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 
 
<div id="disp"></div> 
 
<button onclick="btnfunc()">add</button>

+0

DOMがたくさんあるので、それが遅くなりますレンダリングし、各更新はページ全体を再レンダリングします。設定した数の更新後に新しいd3レンダリングを作成するのはどうですか? –

答えて

0

問題は、(エリアチャートに)私は更新機能には全く何も追加すべきではないということでした。

連続したパスしかないので、新しいデータを反映するために棒グラフのように新しいものを追加する必要はありません。パスのデータ属性を更新するだけで、グラフの範囲に渡ってパスが既に存在しているため、必要なことはすべて必要です。

私は最初の追加をinit関数に入れました。

ドメインの更新はまだその奇妙な初期化データをつぶしの振る舞いが、それは必要として、それが動作すること以外を示す:

////////////////////////////////////////////// 
 
// initial data 
 
////////////////////////////////////////////// 
 
var tdata = [ 
 

 
{ 
 
    "property":"humidity", 
 
    "date":"2016-06-28 05:47:10", 
 
    "value": 40, "unit": "\%" 
 
}, 
 
{ 
 
    "property":"humidity", 
 
    "date":"2016-06-28 05:47:20", 
 
    "value": 35, "unit": "\%" 
 
}, 
 
{ 
 
    "property":"humidity", 
 
    "date":"2016-06-28 05:47:30", 
 
    "value": 36, "unit": "\%" 
 
} , 
 
{ 
 
    "property":"humidity", 
 
    "date":"2016-06-28 05:47:40", 
 
    "value": 40, "unit": "\%" 
 
}, 
 
{ 
 
    "property":"temperature", 
 
    "date":"2016-06-28 05:47:15", 
 
    "value": 75, "unit": "F" 
 
} , 
 

 
{ 
 
    "property":"temperature", 
 
    "date":"2016-06-28 05:47:25", 
 
    "value": 70, "unit": "F" 
 
} , 
 

 
{ 
 
    "property":"temperature", 
 
    "date":"2016-06-28 05:47:35", 
 
    "value": 72, "unit": "F" 
 
}, 
 

 
{ 
 
    "property":"temperature", 
 
    "date":"2016-06-28 05:47:45", 
 
    "value": 75, "unit": "F" 
 
} , 
 

 
]; 
 

 
/////////////////////////////////////////////// 
 
// d3 code 
 
/////////////////////////////////////////////// 
 

 
    var canvas = d3.select('#disp') 
 
     .append('svg') 
 
     .attr('width', 800) 
 
     .attr('height', 200); 
 

 
    var x = d3.scale.linear().range([0, 800]); 
 

 
    var y = d3.scale.linear() 
 
     .domain([0, 100]) 
 
     .range([200, 0]); 
 

 
    var line = d3.svg.line() 
 
    // .interpolate("cardinal") 
 
     .x(function(d) { 
 
     return x(d.date); 
 
     }) 
 
     .y(function(d) { 
 
     return y(d.value); 
 
     }); 
 

 
    var area = d3.svg.area() 
 
     //.interpolate("cardinal") 
 
     .x(line.x()) 
 
     .y1(line.y()) 
 
     .y0(y(0)); 
 

 
var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse; 
 

 
    var lines = canvas.selectAll('.property'); 
 

 
    var lE; 
 

 
///////////////////////////// init function 
 
function init(dataset){ 
 
dataset.forEach(function(d) { 
 
    if(typeof(d.date) === "string"){ d.date = parseDate(d.date); } 
 
}); 
 

 
dataset = dataset.sort(sortByDateAscending); 
 

 
x.domain(d3.extent(dataset, function (d) { return d.date; })); 
 

 
lines = canvas.selectAll('.property') 
 
     .data(dataset, function(d) { 
 
     return d.property; 
 
     }); 
 

 
lE = lines.enter() 
 
     .append('g') 
 
     .attr('class', 'property'); 
 
    
 
    lE.append("path") 
 
     .attr('class', 'tline') 
 
     .attr("d", function(d) { 
 
     return line(dataset.filter(function(d){ return d.property == 'temperature'})); 
 
    }) 
 
     .style("stroke", function(d) { 
 
     return 'black'; 
 
     }) 
 

 
    lE.append("path") 
 
     .attr('class', 'hline') 
 
     .attr("d", function(d) { 
 
     return line(dataset.filter(function(d){ return d.property == 'humidity'})); 
 
     }) 
 
     .style("stroke", function(d) { 
 
     return 'black'; 
 
     }) 
 

 
     lE.append("path") 
 
     .attr("class", "tarea") 
 
     .style('fill', 'red') 
 
     .style('opacity', '0.3') 
 
     .attr("d", function(d) { 
 
      return area(dataset.filter(function(d){ return d.property == 'temperature'})); 
 
     }); 
 
     
 
     lE.append("path") 
 
     .attr("class", "harea") 
 
     .style('fill', 'steelblue') 
 
     .style('opacity', '0.9') 
 
     .attr("d", function(d) { 
 
      return area(dataset.filter(function(d){ return d.property == 'humidity'})); 
 
     }); 
 

 
} 
 

 
///////////////////////////// update function 
 
function update(dataset){ 
 

 
dataset.forEach(function(d) { 
 
    if(typeof(d.date) === "string"){ d.date = parseDate(d.date); } 
 
}); 
 

 
dataset = dataset.sort(sortByDateAscending); 
 

 
x.domain(d3.extent(dataset, function (d) { return d.date; })); 
 

 
    lE.select(".tarea") 
 
    // .transition().duration(500) 
 
    .attr("d", function(d) { 
 
      return area(dataset.filter(function(d){ return d.property == 'temperature'})); 
 
     }); 
 

 
    lE.select(".harea") 
 
    // .transition().duration(500) 
 
    .attr("d", function(d) { 
 
      return area(dataset.filter(function(d){ return d.property == 'humidity'})); 
 
     }); 
 

 
    lE.select(".tline") 
 
    // .transition().duration(500) 
 
    .attr("d", function(d) { 
 
      return area(dataset.filter(function(d){ return d.property == 'temperature'})); 
 
     }); 
 

 

 
    lE.select(".hline") 
 
    // .transition().duration(500) 
 
    .attr("d", function(d) { 
 
      return area(dataset.filter(function(d){ return d.property == 'humidity'})); 
 
     }); 
 

 
} 
 

 
    function sortByDateAscending(a, b) { 
 
    return Date.parse(a.date) - Date.parse(b.date); 
 
}; 
 

 
//////////////////////////////////////////////////////// 
 
// main code 
 
//////////////////////////////////////////////////////// 
 

 
var anim = false; 
 
addObjs(tdata) 
 
addObjs(tdata) 
 
addObjs(tdata) 
 
addObjs(tdata) 
 
addObjs(tdata) 
 
addObjs(tdata) 
 
addObjs(tdata) 
 
addObjs(tdata) 
 
addObjs(tdata) 
 

 
init(tdata); \t 
 

 
function btnfunc(){ 
 
addObjs(tdata) 
 
update(tdata); \t 
 
} 
 

 
function rmvfunc(){ 
 
tdata.pop(); tdata.pop(); 
 
update(tdata); \t 
 
} 
 

 
function shiftfunc(){ 
 
addObjs(tdata) 
 
tdata.shift(); tdata.shift(); 
 
update(tdata); \t 
 
} 
 

 
function animfunc() { 
 
\t anim = !anim; 
 
} 
 

 
window.setInterval(function(){ if(anim){btnfunc();} }, 1000); 
 

 
\t 
 
function addObjs(arr) { 
 
var z = 1; 
 
var h = JSON.parse(JSON.stringify(arr[arr.length-2])); 
 
var t = JSON.parse(JSON.stringify(arr[arr.length-1])); 
 

 
h.property = 'humidity'; h.unit = '\%'; 
 
t.property = 'temperature'; t.unit = 'F'; 
 

 
var time = dparse(t.date); 
 
time+= z; 
 
h.date = timeString(time.toString()); 
 
h.value = 15 + Math.floor(Math.random()*31); 
 
time+= z; 
 
t.date = timeString(time.toString()); 
 
t.value = 65 + Math.floor(Math.random()*28); 
 

 
arr.push(h); 
 
arr.push(t); 
 

 
function timeString(ins) { 
 
\t return ins.slice(0,4) + '-' + ins.slice(4,6) + '-' + ins.slice(6,8) + ' ' 
 
     + ins.slice(8,10) + ':' + ins.slice(10,12) + ':' + ins.slice(12); 
 
} 
 
function dparse(date){ 
 
var d = date.substr(0,10).replace(/-/g , ''); 
 
var t = date.substr(11,18).replace(/:/g , ''); 
 
var i = parseInt(d+t); 
 
return i; 
 
} 
 
\t 
 
}
.axis path, 
 
.axis line { 
 
    fill: none; 
 
    shape-rendering: crispEdges; 
 
} 
 

 
.tline { 
 
    fill: none; 
 
    stroke-width: 1px; 
 

 
} 
 
.hline { 
 
    fill: none; 
 
    stroke-width: 1px; 
 

 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 
 
<div id="disp"></div> 
 
<button onclick="btnfunc()">add</button> 
 
<button onclick="shiftfunc()">shift</button> 
 
<button onclick="rmvfunc()">remove</button> 
 
<button onclick="animfunc()">anim on/off</button> 
 
<script src="data.js"></script> 
 
<script src="graph2.js"></script> 
 
<script src="main.js"></script>

関連する問題