|
|
|
@ -201,24 +201,25 @@ document.getElementById("HDParameter").innerHTML = listParametersOptions; |
|
|
|
|
async function writeIn(formId, formData) {//, apiUrl, myid) {
|
|
|
|
|
var myColumn = getName(formId[0]) |
|
|
|
|
var myTitle = document.getElementById(formId[0]+"Text").value; |
|
|
|
|
var myTitleX = document.getElementById(formId+"Title").value; |
|
|
|
|
|
|
|
|
|
// cl("formId[0]: "+formId[0]);
|
|
|
|
|
// cl("formId[0]: "+formId);
|
|
|
|
|
// cl("myColumn: "+myColumn);
|
|
|
|
|
switch(myColumn) { |
|
|
|
|
case "col-left": |
|
|
|
|
// cl("formData from writeIn():"+formData);
|
|
|
|
|
var myid = "parallel-"+Math.floor(Math.random() * 9999999); |
|
|
|
|
await createMyDiv(myid, myColumn, myTitle); |
|
|
|
|
await createMyDiv(myid, myColumn, myTitle, myTitleX); |
|
|
|
|
createParallel(myid, formId, formData); |
|
|
|
|
break; |
|
|
|
|
case "col-center": |
|
|
|
|
var myid = "grid-"+Math.floor(Math.random() * 1000000); |
|
|
|
|
await createMyDiv(myid, myColumn, myTitle); |
|
|
|
|
await createMyDiv(myid, myColumn, myTitle, myTitleX); |
|
|
|
|
createGrid(myid, formId,formData); |
|
|
|
|
break; |
|
|
|
|
case "col-right": |
|
|
|
|
var myid = "horizon-"+Math.floor(Math.random() * 1000000); |
|
|
|
|
await createMyDiv(myid, myColumn, myTitle); |
|
|
|
|
await createMyDiv(myid, myColumn, myTitle, myTitleX); |
|
|
|
|
createHorizon(myid, formId, formData); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -233,7 +234,7 @@ document.getElementById("HDParameter").innerHTML = listParametersOptions; |
|
|
|
|
|
|
|
|
|
//-----------------------------
|
|
|
|
|
// CreateDIV
|
|
|
|
|
async function createMyDiv(myid, myColumn, myTitle) { |
|
|
|
|
async function createMyDiv(myid, myColumn, myTitle, myTitleX) { |
|
|
|
|
var buttonOpenPopup = []; |
|
|
|
|
buttonOpenPopup["col-left"] = '<span class="corner-popup" onclick="openPopup(this)"><i class="fa fa-window-maximize"></i></span>'; |
|
|
|
|
buttonOpenPopup["col-center"] = '<span class="corner-popup" onclick="openPopup(this)"><i class="fa fa-window-maximize"></i></span>'; |
|
|
|
@ -250,7 +251,7 @@ document.getElementById("HDParameter").innerHTML = listParametersOptions; |
|
|
|
|
node.setAttribute("class", "sortable-item"); |
|
|
|
|
} |
|
|
|
|
document.getElementById(myColumn).appendChild(node); |
|
|
|
|
document.getElementById(myid).innerHTML = myButtons+myTitle; |
|
|
|
|
document.getElementById(myid).innerHTML = myButtons+myTitleX; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//-----------------------------
|
|
|
|
@ -727,113 +728,6 @@ function do_grid_monthly(myid, month, year, data, apiUrl) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function do_grid_monthly_one(myid, month, year, data, apiUrl) { |
|
|
|
|
const margin = { top: 60, right: 20, bottom: 20, left: 20 }; |
|
|
|
|
const cellSize = 35; |
|
|
|
|
const width = cellSize * 7; // Number of columns (days)
|
|
|
|
|
const height = cellSize * 7; // Number of rows (days)
|
|
|
|
|
|
|
|
|
|
// Create a tooltip element
|
|
|
|
|
const tooltip = d3.select("body") |
|
|
|
|
.append("div") |
|
|
|
|
.attr("class", "tooltip") |
|
|
|
|
.style("opacity", 0) |
|
|
|
|
.style("position", "absolute"); // Set tooltip position to absolute
|
|
|
|
|
|
|
|
|
|
const svg = d3.select(`#${myid}`) |
|
|
|
|
.append("svg") |
|
|
|
|
.attr("class", "heatmap") |
|
|
|
|
.attr("width", width + margin.left + margin.right) |
|
|
|
|
.attr("height", height + margin.top + margin.bottom) |
|
|
|
|
.append("g") |
|
|
|
|
.attr("transform", `translate(${margin.left},${margin.top})`); |
|
|
|
|
|
|
|
|
|
// Convert data values to numbers
|
|
|
|
|
const numericData = data.map(value => parseFloat(value)); |
|
|
|
|
|
|
|
|
|
// Create a color scale based on numeric data
|
|
|
|
|
const colorScale = d3.scaleLinear() |
|
|
|
|
.domain([d3.min(numericData), d3.max(numericData)]) |
|
|
|
|
.range(["#0571b0", "#ca0020"]); // Replace with your desired color range
|
|
|
|
|
|
|
|
|
|
const rect = svg.selectAll("rect") |
|
|
|
|
.data(numericData) |
|
|
|
|
.enter().append("rect") |
|
|
|
|
.attr("width", cellSize) |
|
|
|
|
.attr("height", cellSize) |
|
|
|
|
.attr("x", (d, i) => ((i + getDayOffset(month, year)) % 7) * cellSize) |
|
|
|
|
.attr("y", (d, i) => Math.floor((i + getDayOffset(month, year)) / 7) * cellSize) |
|
|
|
|
.attr("fill", d => colorScale(d)) // Apply the color scale to data values
|
|
|
|
|
.on("mouseover", function (d) { |
|
|
|
|
// Show the tooltip on hover
|
|
|
|
|
const [x, y] = d3.mouse(this); |
|
|
|
|
const pageX = x + window.scrollX; // Adjust for horizontal scroll
|
|
|
|
|
const pageY = y + window.scrollY; // Adjust for vertical scroll
|
|
|
|
|
tooltip |
|
|
|
|
.style("left", (d3.event.pageX + 10) + "px") |
|
|
|
|
.style("top", (d3.event.pageY - 10) + "px") |
|
|
|
|
.style("background-color", "#c3c3c3") |
|
|
|
|
.style("opacity", 1) |
|
|
|
|
.html("Value: " + d.toFixed(2)); |
|
|
|
|
}) |
|
|
|
|
.on("mouseout", () => { |
|
|
|
|
tooltip.style("opacity", 0); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
svg.selectAll(".day-number") |
|
|
|
|
.data(numericData) |
|
|
|
|
.enter().append("text") |
|
|
|
|
.attr("class", "day-number") |
|
|
|
|
.attr("x", (d, i) => ((i + getDayOffset(month, year)) % 7) * cellSize + cellSize / 2) |
|
|
|
|
.attr("y", (d, i) => Math.floor((i + getDayOffset(month, year)) / 7) * cellSize + cellSize / 2) |
|
|
|
|
.attr("text-anchor", "middle") |
|
|
|
|
.attr("alignment-baseline", "middle") |
|
|
|
|
.text((d, i) => i + 1); |
|
|
|
|
|
|
|
|
|
const weekDays = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; |
|
|
|
|
svg.selectAll(".weekday") |
|
|
|
|
.data(weekDays) |
|
|
|
|
.enter().append("text") |
|
|
|
|
.attr("class", "weekday") |
|
|
|
|
.attr("x", (d, i) => i * cellSize + cellSize / 2) |
|
|
|
|
.attr("y", -10) |
|
|
|
|
.attr("text-anchor", "middle") |
|
|
|
|
.text((d) => d); |
|
|
|
|
|
|
|
|
|
const firstDayOfMonth = new Date(year, month - 1, 1); |
|
|
|
|
const dayOffset = (firstDayOfMonth.getDay() + 6) % 7; // Calculate the day offset for the first day of the month
|
|
|
|
|
const monthName = getMonth(month); |
|
|
|
|
svg.append("text") |
|
|
|
|
.attr("class", "year-label") |
|
|
|
|
.attr("x", width) |
|
|
|
|
.attr("y", -30) |
|
|
|
|
.attr("text-anchor", "end") |
|
|
|
|
.text(monthName + ", " + year); |
|
|
|
|
|
|
|
|
|
function getDayOffset(month, year) { |
|
|
|
|
const firstDayOfMonth = new Date(year, month - 1, 1); |
|
|
|
|
const dayOffset = (firstDayOfMonth.getDay() + 6) % 7; // Calculate the day offset for the first day of the month
|
|
|
|
|
return dayOffset; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function getMonth(month) { |
|
|
|
|
const months = [ |
|
|
|
|
"January", "February", "March", "April", "May", "June", |
|
|
|
|
"July", "August", "September", "October", "November", "December" |
|
|
|
|
]; |
|
|
|
|
return months[month - 1]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------
|
|
|
|
|
// GRID YEARLY d3 diagram
|
|
|
|
|
function do_grid_yearly(myid, year, myData) { |
|
|
|
@ -1025,234 +919,8 @@ for (let i = 0; i < months.length; i++) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function do_grid_yearlyXX(myid, year, myData) { |
|
|
|
|
// Remove the existing SVG if it exists
|
|
|
|
|
d3.select(`#${myid} svg`).remove(); |
|
|
|
|
|
|
|
|
|
// For demonstration purposes, let's create a simple SVG rectangle
|
|
|
|
|
const svg = d3.select(`#${myid}`).append("svg") |
|
|
|
|
.attr("width", 800) |
|
|
|
|
.attr("height", 650); // Increased height for a taller diagram
|
|
|
|
|
|
|
|
|
|
// Append the 'months' group inside the SVG
|
|
|
|
|
const monthsGroup = svg.append("g") |
|
|
|
|
.attr("id", "months"); |
|
|
|
|
|
|
|
|
|
const months = [ |
|
|
|
|
{ name: 'January', days: 31 }, |
|
|
|
|
{ name: 'February', days: 28 }, |
|
|
|
|
{ name: 'March', days: 31 }, |
|
|
|
|
{ name: 'April', days: 30 }, |
|
|
|
|
{ name: 'May', days: 31 }, |
|
|
|
|
{ name: 'June', days: 30 }, |
|
|
|
|
{ name: 'July', days: 31 }, |
|
|
|
|
{ name: 'August', days: 31 }, |
|
|
|
|
{ name: 'September', days: 30 }, |
|
|
|
|
{ name: 'October', days: 31 }, |
|
|
|
|
{ name: 'November', days: 30 }, |
|
|
|
|
{ name: 'December', days: 31 }, |
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
// Number of columns and rows
|
|
|
|
|
const columns = 4; |
|
|
|
|
const rows = 5; // Increased rows for more vertical space
|
|
|
|
|
|
|
|
|
|
// Calculate cell width and height
|
|
|
|
|
const cellWidth = 660 / columns; |
|
|
|
|
const cellHeight = (800 / rows); // Increased cell height to 40px per month
|
|
|
|
|
|
|
|
|
|
// Border width
|
|
|
|
|
const borderWidth = 1; |
|
|
|
|
|
|
|
|
|
// Calculate min and max values for the color scale
|
|
|
|
|
const minValue = Math.min(...myData); |
|
|
|
|
const maxValue = Math.max(...myData); |
|
|
|
|
const valueRange = maxValue - minValue; |
|
|
|
|
|
|
|
|
|
// Create a color scale based on the min, max, and range of values
|
|
|
|
|
const colorScale = d3.scaleLinear() |
|
|
|
|
.domain([minValue, maxValue]) |
|
|
|
|
.range([0, 1]); |
|
|
|
|
|
|
|
|
|
// Create a group for month labels
|
|
|
|
|
const monthLabelsGroup = svg.append("g") |
|
|
|
|
.attr("id", "month-labels"); |
|
|
|
|
|
|
|
|
|
// Function to handle mouseover event and display tooltip
|
|
|
|
|
function handleMouseover(day, value) { |
|
|
|
|
// Show the tooltip on hover
|
|
|
|
|
tooltip |
|
|
|
|
.style("left", (d3.event.pageX + 10) + "px") |
|
|
|
|
.style("top", (d3.event.pageY - 10) + "px") |
|
|
|
|
.style("background-color", "#c3c3c3") |
|
|
|
|
.style("opacity", 1) |
|
|
|
|
.html(`Value: ${value}`); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Create a tooltip element
|
|
|
|
|
const tooltip = d3.select("body") |
|
|
|
|
.append("div") |
|
|
|
|
.attr("class", "tooltip") |
|
|
|
|
.style("opacity", 0); |
|
|
|
|
|
|
|
|
|
// Loop through each month and create the calendar heatmap
|
|
|
|
|
for (let i = 0; i < months.length; i++) { |
|
|
|
|
const month = months[i]; |
|
|
|
|
// Calculate row and column positions
|
|
|
|
|
const row = Math.floor(i / columns); |
|
|
|
|
const col = i % columns; |
|
|
|
|
|
|
|
|
|
// Starting positions for months
|
|
|
|
|
const x = col * cellWidth + borderWidth; |
|
|
|
|
const y = row * cellHeight + borderWidth; |
|
|
|
|
|
|
|
|
|
// Month Label
|
|
|
|
|
const monthLabel = monthLabelsGroup.append("text") |
|
|
|
|
.attr("x", x + cellWidth / 2) |
|
|
|
|
.attr("y", y + 20) // Increased vertical position
|
|
|
|
|
.attr("font-size", "18") |
|
|
|
|
.attr("text-anchor", "middle") |
|
|
|
|
.text(`${month.name} ${year}`); |
|
|
|
|
|
|
|
|
|
// Create a border around the month
|
|
|
|
|
const border = svg.append("rect") |
|
|
|
|
.attr("x", x) |
|
|
|
|
.attr("y", y + 30) // Increased vertical position
|
|
|
|
|
.attr("width", cellWidth - 2 * borderWidth) |
|
|
|
|
.attr("height", cellHeight - 2 * borderWidth - 30) // Adjusted height to avoid overlap
|
|
|
|
|
.attr("fill", "none") |
|
|
|
|
.attr("stroke", "#ffffff") // Border
|
|
|
|
|
.attr("stroke-width", borderWidth); |
|
|
|
|
|
|
|
|
|
// Calendar Days
|
|
|
|
|
for (let day = 1; day <= month.days; day++) { |
|
|
|
|
// Get the value for the current day
|
|
|
|
|
const value = myData[month.days * i + day - 1]; // Calculate index based on month and day
|
|
|
|
|
|
|
|
|
|
// Calculate the color based on the value
|
|
|
|
|
const color = d3.interpolateViridis(colorScale(value)); |
|
|
|
|
|
|
|
|
|
// Calculate the position of the current day
|
|
|
|
|
const dayRow = Math.floor((day - 1) / 7); |
|
|
|
|
const dayCol = (day - 1) % 7; |
|
|
|
|
|
|
|
|
|
// Create a rectangle for each day
|
|
|
|
|
svg.append("rect") |
|
|
|
|
.attr("x", x + (dayCol * (cellWidth / 7))) |
|
|
|
|
.attr("y", y + 60 + (dayRow * (cellHeight / 6))) // Increased vertical position
|
|
|
|
|
.attr("width", cellWidth / 7) |
|
|
|
|
.attr("height", cellHeight / 6) |
|
|
|
|
.attr("fill", color) |
|
|
|
|
.attr("stroke", "#ffffff") // white border
|
|
|
|
|
.attr("class", "day") |
|
|
|
|
.on("mouseover", () => { |
|
|
|
|
const dayValue = myData[month.days * i + day - 1]; // Calculate index based on month and day
|
|
|
|
|
// Call the handleMouseover function with the correct value
|
|
|
|
|
handleMouseover(day, dayValue); |
|
|
|
|
}) |
|
|
|
|
.on("mouseout", () => { |
|
|
|
|
tooltip.style("opacity", 0); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
// Weekday labels
|
|
|
|
|
const weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; |
|
|
|
|
|
|
|
|
|
// Loop through each month and create the calendar heatmap
|
|
|
|
|
for (let i = 0; i < months.length; i++) { |
|
|
|
|
const month = months[i]; |
|
|
|
|
// Calculate row and column positions
|
|
|
|
|
const row = Math.floor(i / columns); |
|
|
|
|
const col = i % columns; |
|
|
|
|
|
|
|
|
|
// Starting positions for months
|
|
|
|
|
const x = col * cellWidth + borderWidth; |
|
|
|
|
const y = row * cellHeight + borderWidth; |
|
|
|
|
|
|
|
|
|
// Month Label
|
|
|
|
|
const monthLabel = monthLabelsGroup.append("text") |
|
|
|
|
.attr("x", x + cellWidth / 2) |
|
|
|
|
.attr("y", y + 20) // Increased vertical position
|
|
|
|
|
.attr("font-size", "18") |
|
|
|
|
.attr("text-anchor", "middle") |
|
|
|
|
.text(`${month.name} ${year}`); |
|
|
|
|
|
|
|
|
|
// Weekday labels
|
|
|
|
|
for (let w = 0; w < weekdays.length; w++) { |
|
|
|
|
const weekdayLabel = svg.append("text") |
|
|
|
|
.attr("x", x + (w * (cellWidth / 7)) + cellWidth / 14) |
|
|
|
|
.attr("y", y + 55) // Increased vertical position
|
|
|
|
|
.attr("font-size", "12") |
|
|
|
|
.attr("text-anchor", "middle") |
|
|
|
|
.text(weekdays[w]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Create a border around the month
|
|
|
|
|
const border = svg.append("rect") |
|
|
|
|
.attr("x", x) |
|
|
|
|
.attr("y", y + 30) // Increased vertical position
|
|
|
|
|
.attr("width", cellWidth - 2 * borderWidth) |
|
|
|
|
.attr("height", cellHeight - 2 * borderWidth - 30) // Adjusted height to avoid overlap
|
|
|
|
|
.attr("fill", "none") |
|
|
|
|
.attr("stroke", "#ffffff") // Border
|
|
|
|
|
.attr("stroke-width", borderWidth); |
|
|
|
|
|
|
|
|
|
// Calendar Days
|
|
|
|
|
for (let day = 1; day <= month.days; day++) { |
|
|
|
|
// Get the value for the current day
|
|
|
|
|
const value = myData[month.days * i + day - 1]; // Calculate index based on month and day
|
|
|
|
|
|
|
|
|
|
// Calculate the color based on the value
|
|
|
|
|
const color = d3.interpolateViridis(colorScale(value)); |
|
|
|
|
|
|
|
|
|
// Calculate the position of the current day
|
|
|
|
|
const dayRow = Math.floor((day - 1) / 7); |
|
|
|
|
const dayCol = (day - 1) % 7; |
|
|
|
|
|
|
|
|
|
// Create a rectangle for each day
|
|
|
|
|
svg.append("rect") |
|
|
|
|
.attr("x", x + (dayCol * (cellWidth / 7))) |
|
|
|
|
.attr("y", y + 60 + (dayRow * (cellHeight / 6))) // Increased vertical position
|
|
|
|
|
.attr("width", cellWidth / 7) |
|
|
|
|
.attr("height", cellHeight / 6) |
|
|
|
|
.attr("fill", color) |
|
|
|
|
.attr("stroke", "#ffffff") // white border
|
|
|
|
|
.attr("class", "day") |
|
|
|
|
.on("mouseover", () => { |
|
|
|
|
const dayValue = myData[month.days * i + day - 1]; // Calculate index based on month and day
|
|
|
|
|
// Call the handleMouseover function with the correct value
|
|
|
|
|
handleMouseover(day, dayValue); |
|
|
|
|
}) |
|
|
|
|
.on("mouseout", () => { |
|
|
|
|
tooltip.style("opacity", 0); |
|
|
|
|
}) |
|
|
|
|
.append("text") // Add text to display the day number
|
|
|
|
|
.attr("x", x + (dayCol * (cellWidth / 7)) + cellWidth / 14) |
|
|
|
|
.attr("y", y + 85 + (dayRow * (cellHeight / 6))) // Increased vertical position
|
|
|
|
|
.attr("font-size", "12") |
|
|
|
|
.attr("text-anchor", "middle") |
|
|
|
|
.text(day); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------
|
|
|
|
|
// HORIZON d3 diagram
|
|
|
|
@ -1314,9 +982,6 @@ function do_horizon_row(data, myid, title, myDates) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|