record lux_fast and lux _slow

This commit is contained in:
2024-12-11 17:00:53 +08:00
parent 6d89725d65
commit 2a4e21fa25
9 changed files with 444 additions and 202 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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

View File

@@ -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>