record lux_fast and lux _slow
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
test/Sensor_datas/2024-12-11_16-54-17.txt
Normal file
1
test/Sensor_datas/2024-12-11_16-54-17.txt
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 2.0 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.7 MiB |
@@ -5,21 +5,15 @@
|
||||
<title>D3.js Multiple Line Chart</title>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
|
||||
.line { fill: none; stroke-width: 2px; }
|
||||
.axis { font-size: 12px; }
|
||||
.legend { font-size: 12px; }
|
||||
.tooltip {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 120px;
|
||||
height: 40px;
|
||||
padding: 2px;
|
||||
font: 12px sans-serif;
|
||||
background: lightsteelblue;
|
||||
border: 0px;
|
||||
border-radius: 8px;
|
||||
pointer-events: none;
|
||||
.line {
|
||||
fill: none;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
.axis-label {
|
||||
font-size: 16px;
|
||||
}
|
||||
.legend {
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@@ -28,207 +22,140 @@
|
||||
<div id="chart"></div>
|
||||
|
||||
<script>
|
||||
// Sample multiple dataset
|
||||
const data = [
|
||||
{"lux":10.0,"timestamp":442470841810000},
|
||||
{"lux":20.0,"timestamp":442471010509000},
|
||||
{"lux":30.0,"timestamp":442471182576000},
|
||||
{"lux":40.0,"timestamp":442471360117000},
|
||||
{"lux":100.0,"timestamp":442471522264000}
|
||||
// Data
|
||||
const sample_data = [
|
||||
{"lux":1263.0,"timestamp":18188401,"lux_fast":1000.0,"lux_slow":900.0},
|
||||
{"lux":1000.0,"timestamp":18188571,"lux_fast":1263.0,"lux_slow":1000.0},
|
||||
{"lux":900.0,"timestamp":18188741,"lux_fast":1262.0,"lux_slow":1263.0}
|
||||
];
|
||||
const colorMap = new Map();
|
||||
colorMap.set('original', 'steelblue');
|
||||
colorMap.set('fastLuxData', 'green');
|
||||
colorMap.set('slowLuxData', 'red');
|
||||
|
||||
function weightIntegral(x) {
|
||||
return x * (x * 0.5 + 4000000000);
|
||||
}
|
||||
|
||||
function calculateLux(datas, now) {
|
||||
var sum = 0, totalWeight = 0, endDelta = 100000000;
|
||||
for (var i = datas.length - 1; i >= 0; i--) {
|
||||
var eventTime = datas[i].timestamp;
|
||||
var startDelta = eventTime - now;
|
||||
var weight = weightIntegral(endDelta) - weightIntegral(startDelta);
|
||||
var lux = datas[i].lux;
|
||||
totalWeight += weight;
|
||||
sum += lux * weight;
|
||||
endDelta = startDelta;
|
||||
}
|
||||
return sum / totalWeight;
|
||||
}
|
||||
|
||||
// Render multiple line chart
|
||||
function renderMultiLineChart(data) {
|
||||
var timestampNow;
|
||||
var fastLuxData = [];
|
||||
var slowLuxData = [];
|
||||
var datasets = [];
|
||||
for (timestampNow=data[0].timestamp; timestampNow<=data[data.length-1].timestamp; timestampNow+=200000000) {
|
||||
var fastRingBuffer = data.filter((value) => value.timestamp >= timestampNow-2000000000 && value.timestamp <= timestampNow);
|
||||
var slowRingBuffer = data.filter((value) => value.timestamp >= timestampNow-4000000000 && value.timestamp <= timestampNow);
|
||||
if (fastRingBuffer.length <= 1) {
|
||||
fastLuxData.push(data[0]);
|
||||
} else {
|
||||
fastLuxData.push({timestamp:timestampNow, lux:calculateLux(fastRingBuffer, timestampNow)});
|
||||
}
|
||||
if (slowRingBuffer.length <= 1) {
|
||||
slowLuxData.push(data[0]);
|
||||
} else {
|
||||
slowLuxData.push({timestamp:timestampNow, lux:calculateLux(slowRingBuffer, timestampNow)});
|
||||
}
|
||||
}
|
||||
var dataObj = new Object();
|
||||
dataObj.name = "original";
|
||||
dataObj.values = data;
|
||||
datasets.push(dataObj);
|
||||
var fastLuxDataObj = new Object();
|
||||
fastLuxDataObj.name = "fastLuxData";
|
||||
fastLuxDataObj.values = fastLuxData;
|
||||
datasets.push(fastLuxDataObj);
|
||||
var slowLuxDataObj = new Object();
|
||||
slowLuxDataObj.name = "slowLuxData";
|
||||
slowLuxDataObj.values = slowLuxData;
|
||||
datasets.push(slowLuxDataObj);
|
||||
console.log(datasets.length);
|
||||
console.log(datasets[0]);
|
||||
|
||||
// Clear previous chart
|
||||
d3.select("#chart").html("");
|
||||
|
||||
// Chart dimensions
|
||||
const margin = {top: 50, right: 50, bottom: 50, left: 50};
|
||||
const width = 800 - margin.left - margin.right;
|
||||
function createChart(data) {
|
||||
d3.select("#chart").select("svg").remove();
|
||||
// Set the dimensions and margins of the graph
|
||||
const margin = {top: 20, right: 80, bottom: 50, left: 60};
|
||||
const width = 600 - margin.left - margin.right;
|
||||
const height = 400 - margin.top - margin.bottom;
|
||||
|
||||
// Tooltip
|
||||
const tooltip = d3.select("body")
|
||||
.append("div")
|
||||
.attr("class", "tooltip")
|
||||
.style("opacity", 0);
|
||||
|
||||
// Create SVG
|
||||
// Append the svg object to the body of the page
|
||||
const svg = d3.select("#chart")
|
||||
.append("svg")
|
||||
.attr("width", width + margin.left + margin.right)
|
||||
.attr("height", height + margin.top + margin.bottom)
|
||||
.attr("width", width + margin.left + margin.right)
|
||||
.attr("height", height + margin.top + margin.bottom)
|
||||
.append("g")
|
||||
.attr("transform", `translate(${margin.left},${margin.top})`);
|
||||
.attr("transform", `translate(${margin.left},${margin.top})`);
|
||||
|
||||
// Parse dates
|
||||
const parseTime = d3.timeParse("%Y-%m-%d");
|
||||
const formatTime = d3.timeFormat("%Y-%m-%d");
|
||||
/*datasets.forEach(series => {
|
||||
series.values.forEach(d => {
|
||||
d.timestamp = parseTime(d.timestamp);
|
||||
});
|
||||
});*/
|
||||
|
||||
// Combine all values for scale
|
||||
const allValues = datasets.flatMap(series => series.values.map(d => d.lux));
|
||||
|
||||
// Scales
|
||||
// X scale
|
||||
const x = d3.scaleLinear()
|
||||
.domain(d3.extent(datasets[0].values, d => d.timestamp))
|
||||
.domain(d3.extent(data, d => d.timestamp))
|
||||
.range([0, width]);
|
||||
|
||||
// Y scale
|
||||
const y = d3.scaleLinear()
|
||||
.domain([
|
||||
d3.min(allValues) * 0.9,
|
||||
d3.max(allValues) * 1.1
|
||||
])
|
||||
.domain([d3.min(data, d => Math.min(d.lux, d.lux_fast, d.lux_slow)) - 0.5,
|
||||
d3.max(data, d => Math.max(d.lux, d.lux_fast, d.lux_slow)) + 0.5])
|
||||
.range([height, 0]);
|
||||
|
||||
// Add X axis
|
||||
svg.append("g")
|
||||
.attr("transform", `translate(0,${height})`)
|
||||
.call(d3.axisBottom(x));
|
||||
|
||||
// Add Y axis
|
||||
svg.append("g")
|
||||
.call(d3.axisLeft(y));
|
||||
|
||||
// X axis label
|
||||
svg.append("text")
|
||||
.attr("class", "axis-label")
|
||||
.attr("text-anchor", "middle")
|
||||
.attr("x", width / 2)
|
||||
.attr("y", height + margin.bottom - 10)
|
||||
.text("Timestamp");
|
||||
|
||||
// Y axis label
|
||||
svg.append("text")
|
||||
.attr("class", "axis-label")
|
||||
.attr("text-anchor", "middle")
|
||||
.attr("transform", "rotate(-90)")
|
||||
.attr("y", -margin.left + 20)
|
||||
.attr("x", -height / 2)
|
||||
.text("Lux Value");
|
||||
|
||||
// Line generator
|
||||
const line = d3.line()
|
||||
.x(d => x(d.timestamp))
|
||||
.y(d => y(d.lux));
|
||||
|
||||
// X-axis
|
||||
svg.append("g")
|
||||
.attr("class", "axis")
|
||||
.attr("transform", `translate(0,${height})`)
|
||||
.call(d3.axisBottom(x));
|
||||
// Add the lux line
|
||||
svg.append("path")
|
||||
.datum(data)
|
||||
.attr("class", "line")
|
||||
.attr("d", line)
|
||||
.attr("stroke", "blue");
|
||||
|
||||
// Y-axis
|
||||
svg.append("g")
|
||||
.attr("class", "axis")
|
||||
.call(d3.axisLeft(y));
|
||||
// Add the lux_fast
|
||||
svg.append("path")
|
||||
.datum(data)
|
||||
.attr("class", "line")
|
||||
.attr("d", d3.line()
|
||||
.x(d => x(d.timestamp))
|
||||
.y(d => y(d.lux_fast)))
|
||||
.attr("stroke", "red");
|
||||
|
||||
// Lines and data points for each dataset
|
||||
datasets.forEach(series => {
|
||||
// Line
|
||||
svg.append("path")
|
||||
.datum(series.values)
|
||||
.attr("class", "line")
|
||||
.attr("fill", "none")
|
||||
.attr("stroke", colorMap.get(series.name))
|
||||
.attr("stroke-width", 2)
|
||||
.attr("d", line);
|
||||
// Add the lux_slow line
|
||||
svg.append("path")
|
||||
.datum(data)
|
||||
.attr("class", "line")
|
||||
.attr("d", d3.line()
|
||||
.x(d => x(d.timestamp))
|
||||
.y(d => y(d.lux_slow)))
|
||||
.attr("stroke", "green");
|
||||
|
||||
// Data points
|
||||
svg.selectAll(`.dot-${series.name}`)
|
||||
.data(series.values)
|
||||
.enter().append("circle")
|
||||
.attr("class", `dot dot-${series.name}`)
|
||||
.attr("cx", d => x(d.timestamp))
|
||||
.attr("cy", d => y(d.lux))
|
||||
.attr("r", 5)
|
||||
.attr("fill", colorMap.get(series.name))
|
||||
.on("mouseover", function(event, d) {
|
||||
tooltip.transition()
|
||||
.duration(200)
|
||||
.style("opacity", .9);
|
||||
tooltip.html(`${series.name}<br/>timestamp: ${d.timestamp}<br/>lux: ${d.lux}`)
|
||||
.style("left", (event.pageX + 5) + "px")
|
||||
.style("top", (event.pageY - 28) + "px");
|
||||
})
|
||||
.on("mouseout", function(d) {
|
||||
tooltip.transition()
|
||||
.duration(500)
|
||||
.style("opacity", 0);
|
||||
});
|
||||
// Add legend
|
||||
const legend = svg.append("g")
|
||||
.attr("class", "legend")
|
||||
.attr("transform", `translate(${width + 10}, 0)`);
|
||||
|
||||
const legendItems = [
|
||||
{ label: "Lux", color: "blue" },
|
||||
{ label: "Lux Fast", color: "red" },
|
||||
{ label: "Lux Slow", color: "green" }
|
||||
];
|
||||
|
||||
legendItems.forEach((item, index) => {
|
||||
const legendItem = legend.append("g")
|
||||
.attr("transform", `translate(0, ${index * 20})`);
|
||||
|
||||
legendItem.append("rect")
|
||||
.attr("width", 10)
|
||||
.attr("height", 10)
|
||||
.attr("fill", item.color);
|
||||
|
||||
legendItem.append("text")
|
||||
.attr("x", 15)
|
||||
.attr("y", 10)
|
||||
.text(item.label);
|
||||
});
|
||||
|
||||
// Legend
|
||||
const legend = svg.selectAll(".legend")
|
||||
.data(datasets)
|
||||
.enter().append("g")
|
||||
.attr("class", "legend")
|
||||
.attr("transform", (d, i) => `translate(${width + 10},${i * 20})`);
|
||||
|
||||
legend.append("rect")
|
||||
.attr("x", 0)
|
||||
.attr("width", 10)
|
||||
.attr("height", 10)
|
||||
.style("fill", d => colorMap.get(d.name));
|
||||
|
||||
legend.append("text")
|
||||
.attr("x", 20)
|
||||
.attr("y", 9)
|
||||
.text(d => d.name)
|
||||
.style("text-anchor", "start");
|
||||
}
|
||||
|
||||
// Render chart
|
||||
renderMultiLineChart(data);
|
||||
// File input handler
|
||||
// File input event listener
|
||||
document.getElementById('fileInput').addEventListener('change', function(e) {
|
||||
const file = e.target.files[0];
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = function(event) {
|
||||
try {
|
||||
const jsonData = JSON.parse(event.target.result);
|
||||
renderMultiLineChart(jsonData);
|
||||
} catch (error) {
|
||||
alert('Error parsing JSON file: ' + error);
|
||||
}
|
||||
};
|
||||
|
||||
reader.readAsText(file);
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
const contents = e.target.result;
|
||||
try {
|
||||
const data = JSON.parse(contents);
|
||||
createChart(data);
|
||||
} catch (error) {
|
||||
console.error("Error parsing JSON:", error);
|
||||
alert("Error parsing JSON file. Please make sure it's a valid JSON.");
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
});
|
||||
createChart(sample_data);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user