2

データベースから一連のセンサー情報を取得する D3 アプリケーションを作成しました。30秒ループで遷移・動作して情報を更新するようにしました。Javascript オブジェクトを解析し、各センサーの線をグラフにプロットします。すべてが順調に進んでいるように見えますが、アプリを数時間使用すると停止し、更新が停止します。次に、スクリプトが応答しないと文句を言います。プロットのJSは次のとおりです。

var thresholdTemp = 72;
var minutes = 5;
var transInterval;

//Main function to create a graph plot
function plot(date1, date2, interval) {
        var data;
        //If we define a date search parameter then we don't want to have it load          interactive
        if (date1 == undefined && date2==undefined) {
                data = loadMinutesJSON(minutes);
        } else {
                data = searchJSON(date1, date2, interval);

        }
        var margin = {top: 20, right: 80, bottom: 60, left: 50},
        width = 960 - margin.left - margin.right ,
        height = 500 - margin.top - margin.bottom;

        //Re-order the data to be more usable  by the rest of the script
        var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
        //Convert the JSON to be better usable by D3
        data = convertJSON(data);
        //Nest the data so that it's grouped by serial number
        data = d3.nest().key(function(d) { return d.serial; }).entries(data);

        //Set the X domain to exist within the date and times given
        var x = d3.time.scale().domain([getMinDate(data), getMaxDate(data)]).range([0, (width)]);


        //Y Axis scale set to start at 45 degrees and go up to 30 degrees over highest temp
        var y = d3.scale.linear()
            .domain([
                45,
                getMaxTemp(data) + 10
             ])
            .range([height, 0]);


        //Set up the line colors based on serial number, this generates a color based on an ordinal value
        var color = d3.scale.category20()
                        .domain(d3.keys(data[0]).filter(function(key)  { return key === 'serial';}));

        //Define where the X axis is    
        var xAxis = d3.svg.axis()
            .scale(x)
            .orient("bottom")
            .tickFormat(d3.time.format("%b %d %H:%M:%S"));

        //Define where the Y axis is
        var yAxis = d3.svg.axis()
            .scale(y)
            .orient("left");

        //When called creates a line with the given datapoints
        var line = d3.svg.line()
            .interpolate("basis")
            .x(function(d) { return x(d.date); })
        y(function(d) { return y(d.reading); });

        //An extra line to define a maximum temperature threshold
        var threshold = d3.svg.line()
            .x(function(d) { return x(d.date);})
            .y(function(d) { return y(thresholdTemp); });

        //Append the SVG to the HTML element
        var svg = d3.select("#plot").append("svg")
            .attr("width", (width + margin.left + margin.right))
            .attr("height", height + margin.top + margin.bottom)
            .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        //Define the clipping boundaries
        svg.append("defs").append("clipPath")
            .attr("id", "clip")
            .append("rect")
            .attr("width", (width + margin.left +  margin.right))
            .attr("height", height +  margin.top + margin.bottom);

        //Add the X axis        
        svg.append("g")
                .attr("class", "x axis")
                .attr("transform", "translate(0," + height + ")")
                .call(xAxis)
                .selectAll("text")
                .style("text-anchor", "end")
                .attr("dx", "-.8em")
                .attr("dy", ".15em")
                .attr("transform" , function (d) {return "rotate(-35)"});

        //Add the Y axis and a label denoting it as temperature in F    
        svg.append("g")
                .attr("class", "y axis")
                .call(yAxis)
                .append("text")
                .attr("transform", "rotate(-90)")
                .attr("y", 6)
                .attr("dy", ".71em")
                .style("text-anchor", "end")
                .text("Temperature (F)");

        //Create the lines based on serial number
        var serial = svg.selectAll(".serial")
                .data(data, function(d) { return d.key;})
                .enter().append("g")
                .attr("class", "serial");
        //Add the extra line for a threshold and align it with the current time
        var threshElement = svg.selectAll(".thresh")
                .data(data, function(d) { return d.key;})
                .enter().append("g")
                .attr("class", ".thresh");
        //Add the path to draw lines and clipping so they stay within bounds    
        var path = serial.append("path")
                .attr("clip-path", "url(#clip)")
                .attr("class", "line")
                .attr("d", function (d) {return line(d.values);})
                .style("stroke", function(d) {return color(d.key);});

        //Custom path to add a line showing the temperature threshold
        var threshpath = threshElement.append("path")
                .attr("class", "line")
                .attr("d", function(d) { return threshold(d.values);})
                .style("stroke", "red");

        //Add a label to the end of the threshold line denoting it as the threshold
        threshElement.append("text")
                .attr("transform", "translate(" + x(getMaxDate(data)) + "," + y(thresholdTemp + .5) + ")")
                .attr("x", 3)
                .attr("dy", ".35em")
                .text("Threshold");
        //Add the legend
        plotLegend(data);

        //Load in the new data and add it to the SVG

        function transition() {
                var newdata = loadMinutesJSON(minutes);
                newdata = convertJSON(newdata);
                console.log(newdata.length);
                newdata = d3.nest().key(function(d) { return d.serial; }).entries(newdata);
                if (data[0]["values"][0]["date"].toString() === newdata[0]["values"][0]["date"].toString()) { console.log("No New Data");return;}

                //Merge the new data with the old and remove duplicates
                data = merge(data,newdata);
                //Chop off the preceding data that is no longer needed or visible
                data = reduce(data, minutes);

                x.domain([getMinDate(data), getMaxDate(data)]);
                y.domain([45, getMaxTemp(data) + 10]);
                d3.select(".x.axis")
                        .transition()
                        .duration(500).call(xAxis)
                        .selectAll("text")
                        .style("text-anchor", "end")
                        .attr("dx", "-.8em")
                        .attr("dy", ".15em")
                        .attr("transform" , function (d) {return "rotate(-35)"});

                d3.select(".y.axis").transition().duration(500).call(yAxis);
                var serial2 = svg.selectAll(".serial")
                        .data(data, function(d) { return d.key;});
                        serial2.enter().append("g").attr("class", "line");

                var threshold2 = svg.selectAll(".thresh")
                        .data(data, function(d) { return d.key;});
                        threshold2.enter().append("g").attr("class", "line");

                threshpath
                        .attr("d", function(d) {return threshold(d.values);})
                .attr("transform", null)
                        .transition()
                        .duration(500)
                        .ease("linear");

                threshElement.selectAll("text")
                        .attr("transform", "translate(" + x(getMaxDate(data)) + "," + y(thresholdTemp + .5 ) + ")")
                        .attr("x", 3)
                        .transition()
                        .duration(500)
                        .ease("linear");

                path
                        .attr("d", function(d) { return line(d.values);})
                        .attr("transform", null)
                        .transition()
                        .duration(500)
                        .ease("linear");
                        //.attr("transform", "translate(" + x(0) + ")");
                console.log(svg);
                serial2.exit().remove();
                threshold2.exit().remove();

                //Remove the old, unused data
                //data = reduce(data, minutes);
        }

        if(date1 == undefined && date2 == undefined) {
                //Set the transition loop to run every 30 seconds
                transInterval = setInterval(transition,30000);

        }
}

データ構造の例を次に示します。

[{"serial":"2D0008017075F210","date":"2013-08-23T14:35:19.000Z","reading":76.1,"elevation":null,"room":null,"system":null},{"serial":"2D0008017075F210","date":"2013-08-23T14:35:50.000Z","reading":76.1,"elevation":null,"room":null,"system":null},{"serial":"2D0008017075F210","date":"2013-08-23T14:36:20.000Z","reading":76.1,"elevation":null,"room":null,"system":null},{"serial":"2D0008017075F210","date":"2013-08-23T14:36:50.000Z","reading":76.1,"elevation":null,"room":null,"system":null},{"serial":"2D0008017075F210","date":"2013-08-23T14:37:20.000Z","reading":76.1,"elevation":null,"room":null,"system":null},{"serial":"2D0008017075F210","date":"2013-08-23T14:37:50.000Z","reading":76.1,"elevation":null,"room":null,"system":null},{"serial":"2D0008017075F210","date":"2013-08-23T14:38:20.000Z","reading":76.1,"elevation":null,"room":null,"system":null},{"serial":"2D0008017075F210","date":"2013-08-23T14:38:50.000Z","reading":76.1,"elevation":null,"room":null,"system":null},{"serial":"2D0008017075F210","date":"2013-08-23T14:39:20.000Z","reading":76.1,"elevation":null,"room":null,"system":null},{"serial":"2D0008017075F210","date":"2013-08-23T14:39:50.000Z","reading":76.1,"elevation":null,"room":null,"system":null},{"serial":"1D00080170496D10","date":"2013-08-23T14:35:19.000Z","reading":73.4,"elevation":null,"room":null,"system":null},{"serial":"1D00080170496D10","date":"2013-08-23T14:35:50.000Z","reading":73.4,"elevation":null,"room":null,"system":null},{"serial":"1D00080170496D10","date":"2013-08-23T14:36:20.000Z","reading":73.4,"elevation":null,"room":null,"system":null},{"serial":"1D00080170496D10","date":"2013-08-23T14:36:50.000Z","reading":73.4,"elevation":null,"room":null,"system":null},{"serial":"1D00080170496D10","date":"2013-08-23T14:37:20.000Z","reading":73.4,"elevation":null,"room":null,"system":null},{"serial":"1D00080170496D10","date":"2013-08-23T14:37:50.000Z","reading":73.4,"elevation":null,"room":null,"system":null},{"serial":"1D00080170496D10","date":"2013-08-23T14:38:20.000Z","reading":73.4,"elevation":null,"room":null,"system":null},{"serial":"1D00080170496D10","date":"2013-08-23T14:38:50.000Z","reading":73.4,"elevation":null,"room":null,"system":null},{"serial":"1D00080170496D10","date":"2013-08-23T14:39:20.000Z","reading":73.4,"elevation":null,"room":null,"system":null},{"serial":"1D00080170496D10","date":"2013-08-23T14:39:50.000Z","reading":73.4,"elevation":null,"room":null,"system":null},{"serial":"380008017037ED10","date":"2013-08-23T14:35:19.000Z","reading":74.3,"elevation":null,"room":null,"system":null},{"serial":"380008017037ED10","date":"2013-08-23T14:35:50.000Z","reading":74.3,"elevation":null,"room":null,"system":null},{"serial":"380008017037ED10","date":"2013-08-23T14:36:20.000Z","reading":74.3,"elevation":null,"room":null,"system":null},{"serial":"380008017037ED10","date":"2013-08-23T14:36:50.000Z","reading":74.3,"elevation":null,"room":null,"system":null},{"serial":"380008017037ED10","date":"2013-08-23T14:37:20.000Z","reading":74.3,"elevation":null,"room":null,"system":null},{"serial":"380008017037ED10","date":"2013-08-23T14:37:50.000Z","reading":74.3,"elevation":null,"room":null,"system":null},{"serial":"380008017037ED10","date":"2013-08-23T14:38:20.000Z","reading":74.3,"elevation":null,"room":null,"system":null},{"serial":"380008017037ED10","date":"2013-08-23T14:38:50.000Z","reading":74.3,"elevation":null,"room":null,"system":null},{"serial":"380008017037ED10","date":"2013-08-23T14:39:20.000Z","reading":74.3,"elevation":null,"room":null,"system":null},{"serial":"380008017037ED10","date":"2013-08-23T14:39:50.000Z","reading":74.3,"elevation":null,"room":null,"system":null}]
4

1 に答える 1