Fixed live charts updarte in radar mode

This commit is contained in:
RZ_MINIX\rober 2025-06-24 19:16:53 -07:00
parent 5649360929
commit 7317e5e67e
2 changed files with 305 additions and 133 deletions

View File

@ -758,6 +758,30 @@ def GetDeviceDetailsSingle(device_id):
return device_record return device_record
def GetDeviceDetailsSingleFromMac(device_mac):
conn = get_db_connection()
sql = "SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'devices';"
with conn.cursor() as cur:
cur.execute(sql)
columns_names = cur.fetchall()
sql = "SELECT * FROM public.devices WHERE device_mac = '" + device_mac + "'"
device_record = {}
with conn.cursor() as cur:
cur.execute(sql)
result = cur.fetchone() #cur.fetchall()
if result != None:
cnt = 0
for field in columns_names:
device_record[field[0]] = result[cnt]
cnt += 1
else:
#device is not in DB so first lets find it in
pass
return device_record
def DeploymentDetails(deployment_id): def DeploymentDetails(deployment_id):
@ -1546,20 +1570,20 @@ def StoreDevice2DB(parameters, editing_device_id):
description = '{CleanObject(parameters.get('description'))}', description = '{CleanObject(parameters.get('description'))}',
location = '{CleanObject(parameters.get('location'))}', location = '{CleanObject(parameters.get('location'))}',
close_to = '{CleanObject(parameters.get('close_to'))}', close_to = '{CleanObject(parameters.get('close_to'))}',
group_id = {CleanObject(parameters.get('group_id'))},
radar_threshold = '{CleanObject(parameters.get('radar_threshold'))}', radar_threshold = '{CleanObject(parameters.get('radar_threshold'))}',
temperature_calib = '{CleanObject(parameters.get('temperature_calib'))}', temperature_calib = '{CleanObject(parameters.get('temperature_calib'))}',
humidity_calib = '{CleanObject(parameters.get('humidity_calib'))}' humidity_calib = '{CleanObject(parameters.get('humidity_calib'))}'
WHERE device_id = {editing_device_id}; WHERE device_id = {editing_device_id};
""" """
else: else:
sql = f""" sql = f"""
INSERT INTO public.devices INSERT INTO public.devices
(device_mac, well_id, description, location, close_to, radar_threshold, temperature_calib, humidity_calib) (device_mac, well_id, description, location, close_to, radar_threshold, temperature_calib, humidity_calib, group_id)
VALUES VALUES
('{CleanObject(parameters.get('device_mac'))}', '{CleanObject(parameters.get('well_id'))}', '{CleanObject(parameters.get('description'))}', ('{CleanObject(parameters.get('device_mac'))}', '{CleanObject(parameters.get('well_id'))}', '{CleanObject(parameters.get('description'))}',
'{CleanObject(parameters.get('location'))}', '{CleanObject(parameters.get('close_to'))}', '{CleanObject(parameters.get('radar_threshold'))}', '{CleanObject(parameters.get('location'))}', '{CleanObject(parameters.get('close_to'))}', '{CleanObject(parameters.get('radar_threshold'))}',
'{CleanObject(parameters.get('temperature_calib'))}', '{CleanObject(parameters.get('humidity_calib'))}'); '{CleanObject(parameters.get('temperature_calib'))}', '{CleanObject(parameters.get('humidity_calib'))}', {CleanObject(parameters.get('group_id'))});
""" """
logger.debug(f"sql= {sql}") logger.debug(f"sql= {sql}")
# Execute update query # Execute update query
@ -7718,7 +7742,7 @@ def CreateMapFast(map_file, devices_list, selected_date, bw, time_zone_s, radar_
stripes = devices_c * sensors_c #2 for upper maxes, lower mins stripes = devices_c * sensors_c #2 for upper maxes, lower mins
arr_source_template = np.full((stripes, minutes+4), -0.001, dtype=float) arr_source_template = np.full((stripes, minutes+4), -0.001, dtype=float)
arr_stretched_template = np.zeros((int(stripes*stretch_by), minutes, 3), dtype=np.uint8) # 3 for RGB channels arr_stretched_template = np.zeros((int(stripes*stretch_by), minutes, 3), dtype=np.uint8) # 3 for RGB channels
arr_source = fast_fill_array_from_timescale_single(day_data, time_from_str, devices_list[1], arr_source_template, s_table_temp[0], time_zone_s) arr_source = fast_fill_array_from_timescale(day_data, time_from_str, devices_list[1], arr_source_template, time_zone_s)
arr_source = AddLimits_optimized(arr_source, devices_c, sensors_c, percentile=100) arr_source = AddLimits_optimized(arr_source, devices_c, sensors_c, percentile=100)
scaled_day = CalcExtremes(arr_source, minutes, stripes) scaled_day = CalcExtremes(arr_source, minutes, stripes)
arr_stretched, vocs_scaled = FillImage_optimized(scaled_day, devices_c, sensors_c, arr_stretched_template, group_by, bw) arr_stretched, vocs_scaled = FillImage_optimized(scaled_day, devices_c, sensors_c, arr_stretched_template, group_by, bw)
@ -13575,6 +13599,17 @@ def decode_state(b64_state):
logger.error(f"Failed to decode client_state '{b64_state}': {e}") logger.error(f"Failed to decode client_state '{b64_state}': {e}")
return [] return []
def create_client_state(base_event, call_control_id, prefix):
"""Create a base64 encoded client state string as required by Telnyx API"""
# Create the plain text client state string
plain_state = f"{prefix}_{base_event}_{call_control_id[:8]}" if call_control_id else f"{prefix}_{base_event}_unknownccid"
# Encode to base64 as required by Telnyx API
base64_state = base64.b64encode(plain_state.encode('utf-8')).decode('ascii')
logger.debug(f"Client state created: '{plain_state}' -> base64: '{base64_state}'")
return base64_state
def send_telnyx_command(action_path, params, api_key): def send_telnyx_command(action_path, params, api_key):
""" """
Sends a command to the Telnyx Call Control API actions endpoint. Sends a command to the Telnyx Call Control API actions endpoint.
@ -14614,6 +14649,35 @@ def AddLimits_optimized_filtered(arr_source, devices_c, sensors_c, filtered_s_ta
arr_source[:, 1441] = max_vals arr_source[:, 1441] = max_vals
return arr_source return arr_source
def GetNextWellId(min_well_id):
conn = get_db_connection()
sql = """
SELECT COALESCE(MAX(well_id), 0) AS max_well_id
FROM public.devices
"""
try:
with conn.cursor() as cur:
cur.execute(sql)
result = cur.fetchone()
if result == None:
return min_well_id
else:
max_wel_id = result[0]
if max_wel_id != None and min_well_id != None:
if max_wel_id + 1 > min_well_id:
return max_wel_id + 1
else:
return min_well_id
else:
if max_wel_id != None:
return max_wel_id + 1
except Exception as e:
return min_well_id
#==================================== ADD FUNCTIONS BEFORE ============================================ #==================================== ADD FUNCTIONS BEFORE ============================================
# Main API class # Main API class
@ -15925,10 +15989,9 @@ class WellApi:
time_zone_s = GetTimeZoneOfDeployment(deployment_id) time_zone_s = GetTimeZoneOfDeployment(deployment_id)
selected_date = form_data.get('date') selected_date = form_data.get('date')
date_to = form_data.get('to_date') date_to = form_data.get('to_date')
if date_to == None: if date_to == None:
date_to = selected_date date_to = selected_date
start_date = datetime.datetime.strptime(selected_date, '%Y-%m-%d') start_date = datetime.datetime.strptime(selected_date, '%Y-%m-%d')
end_date = datetime.datetime.strptime(date_to, '%Y-%m-%d') end_date = datetime.datetime.strptime(date_to, '%Y-%m-%d')
@ -16595,28 +16658,40 @@ class WellApi:
elif function == "get_device": elif function == "get_device":
device_id = form_data.get('device_id') device_id = form_data.get('device_id')
devices = GetVisibleDevices(privileges) device_mac = form_data.get('mac')
dataa = {} min_well_id = form_data.get('min_well_id')
dataa['Function'] = "device_details"
dataa['device_details'] = []
if privileges == "-1":
#device_det = GetDeviceDetails(device_id)
device_det = GetDeviceDetailsSingle(device_id)
if device_det['radar_threshold'] == None or device_det['radar_threshold'] == "":
device_det['radar_threshold'] = '["s3_max",12]'
dataa['device_details'] = device_det
else:
devices_list = []
for device_id_temp in devices:
devices_list.append(str(device_id_temp[0]))
if device_id in devices_list: if device_mac != None:
device_det = GetDeviceDetailsSingleFromMac(device_mac)
print(device_det)
dataa = {}
dataa['Function'] = "device_details"
dataa['device_details'] = device_det
if device_det == {}:
dataa['next_well_id'] = GetNextWellId(min_well_id)
else:
devices = GetVisibleDevices(privileges)
dataa = {}
dataa['Function'] = "device_details"
dataa['device_details'] = {}
if privileges == "-1":
#device_det = GetDeviceDetails(device_id)
device_det = GetDeviceDetailsSingle(device_id) device_det = GetDeviceDetailsSingle(device_id)
if device_det['radar_threshold'] == None or device_det['radar_threshold'] == "": if device_det['radar_threshold'] == None or device_det['radar_threshold'] == "":
device_det['radar_threshold'] = '["s3_max",12]' device_det['radar_threshold'] = '["s3_max",12]'
dataa['device_details'] = device_det dataa['device_details'] = device_det
else:
devices_list = []
for device_id_temp in devices:
devices_list.append(str(device_id_temp[0]))
if device_id in devices_list:
device_det = GetDeviceDetailsSingle(device_id)
if device_det['radar_threshold'] == None or device_det['radar_threshold'] == "":
device_det['radar_threshold'] = '["s3_max",12]'
dataa['device_details'] = device_det
resp.media = package_response(dataa) resp.media = package_response(dataa)

View File

@ -5,7 +5,7 @@
<!-- <!--
Written By: Robert Zmrzli robert@zmrinc.com Written By: Robert Zmrzli robert@zmrinc.com
deployment.html deployment.html
V3.0 V3.01
--> -->
@ -1619,103 +1619,200 @@ function ProcessQueue() {
vall = -1000000; vall = -1000000;
switch(message["payload"]["mtype"]) { switch(message["payload"]["mtype"]) {
case "radar": case "radar":
case 16:
//lets charts dictate which sensors are to be displayed //lets charts dictate which sensors are to be displayed
MAC = message["topic"].substring(1); MAC = message["topic"].substring(1);
if(document.getElementById("map_type").value == 1){
i = 4; //4=radar
if (MAC+sensor_tablesn[i] in series_indexes){
i = 4; //4=radar series_index = series_indexes[MAC+sensor_tablesn[i]];
if (MAC+sensor_tablesn[i] in series_indexes){ series = UniversalChart.series.items[series_index];
if (series.visible == true) {
radar_part = document.getElementById("RadarPart").value;
timee = message["payload"]["time"];
switch(radar_part) {
case "absent":
vall = message["payload"]["radar"][0][1]/message["payload"]["radar"][0][0];
break;
case "moving":
vall = message["payload"]["radar"][0][2]/message["payload"]["radar"][0][0];
break;
case "stationary":
vall = message["payload"]["radar"][0][3]/message["payload"]["radar"][0][0];
break;
case "both":
vall = message["payload"]["radar"][0][4]/message["payload"]["radar"][0][0];
break;
case "m0":
vall = message["payload"]["radar"][0][5]/message["payload"]["radar"][0][0];
break;
case "m1":
vall = message["payload"]["radar"][0][6]/message["payload"]["radar"][0][0];
break;
case "m2":
vall = message["payload"]["radar"][0][7]/message["payload"]["radar"][0][0];
break;
case "m3":
vall = message["payload"]["radar"][0][8]/message["payload"]["radar"][0][0];
break;
case "m4":
vall = message["payload"]["radar"][0][9]/message["payload"]["radar"][0][0];
break;
case "m5":
vall = message["payload"]["radar"][0][10]/message["payload"]["radar"][0][0];
break;
case "m6":
vall = message["payload"]["radar"][0][11]/message["payload"]["radar"][0][0];
break;
case "m7":
vall = message["payload"]["radar"][0][12]/message["payload"]["radar"][0][0];
break;
case "m8":
vall = message["payload"]["radar"][0][13]/message["payload"]["radar"][0][0];
break;
case "s2":
vall = message["payload"]["radar"][1][3]/message["payload"]["radar"][1][0];
break;
case "s3":
vall = message["payload"]["radar"][1][4]/message["payload"]["radar"][1][0];
break;
case "s4":
vall = message["payload"]["radar"][1][5]/message["payload"]["radar"][1][0];
break;
case "s5":
vall = message["payload"]["radar"][1][6]/message["payload"]["radar"][1][0];
break;
case "s6":
vall = message["payload"]["radar"][1][7]/message["payload"]["radar"][1][0];
break;
case "s7":
vall = message["payload"]["radar"][1][8]/message["payload"]["radar"][1][0];
break;
case "s8":
vall = message["payload"]["radar"][1][9]/message["payload"]["radar"][1][0];
break;
case "s28":
vall = 0;
for (i_=3; i_<=9; i_++){
vall += message["payload"]["radar"][1][i_]
}
vall = vall/(7.0*message["payload"]["radar"][1][0]);
break;
}
}
if (vall != -1000000) {
epoch_ms = (timee+hours_delta * 3600) * 1000;
series.data.x.push(new Date(epoch_ms));
series.data.values.push(vall);
//series.data.values.push(vall);
//time_obj = new Date(epoch_ms);
//series.data.x.push(time_obj);
series_index = series_indexes[MAC+sensor_tablesn[i]]; UniversalChart.axes.bottom.labels.roundFirst = true;
series = UniversalChart.series.items[series_index]; UniversalChart.axes.bottom.labels.dateFormat = "shortDateTime";
if (series.visible == true) { UniversalChart.draw();
radar_part = document.getElementById("RadarPart").value;
timee = message["payload"]["time"];
switch(radar_part) {
case "absent":
vall = message["payload"]["radar"][0][1]/message["payload"]["radar"][0][0];
break;
case "moving":
vall = message["payload"]["radar"][0][2]/message["payload"]["radar"][0][0];
break;
case "stationary":
vall = message["payload"]["radar"][0][3]/message["payload"]["radar"][0][0];
break;
case "both":
vall = message["payload"]["radar"][0][4]/message["payload"]["radar"][0][0];
break;
case "m0":
vall = message["payload"]["radar"][0][5]/message["payload"]["radar"][0][0];
break;
case "m1":
vall = message["payload"]["radar"][0][6]/message["payload"]["radar"][0][0];
break;
case "m2":
vall = message["payload"]["radar"][0][7]/message["payload"]["radar"][0][0];
break;
case "m3":
vall = message["payload"]["radar"][0][8]/message["payload"]["radar"][0][0];
break;
case "m4":
vall = message["payload"]["radar"][0][9]/message["payload"]["radar"][0][0];
break;
case "m5":
vall = message["payload"]["radar"][0][10]/message["payload"]["radar"][0][0];
break;
case "m6":
vall = message["payload"]["radar"][0][11]/message["payload"]["radar"][0][0];
break;
case "m7":
vall = message["payload"]["radar"][0][12]/message["payload"]["radar"][0][0];
break;
case "m8":
vall = message["payload"]["radar"][0][13]/message["payload"]["radar"][0][0];
break;
case "s2":
vall = message["payload"]["radar"][1][3]/message["payload"]["radar"][1][0];
break;
case "s3":
vall = message["payload"]["radar"][1][4]/message["payload"]["radar"][1][0];
break;
case "s4":
vall = message["payload"]["radar"][1][5]/message["payload"]["radar"][1][0];
break;
case "s5":
vall = message["payload"]["radar"][1][6]/message["payload"]["radar"][1][0];
break;
case "s6":
vall = message["payload"]["radar"][1][7]/message["payload"]["radar"][1][0];
break;
case "s7":
vall = message["payload"]["radar"][1][8]/message["payload"]["radar"][1][0];
break;
case "s8":
vall = message["payload"]["radar"][1][9]/message["payload"]["radar"][1][0];
break;
case "s28":
vall = 0;
for (i_=3; i_<=9; i_++){
vall += message["payload"]["radar"][1][i_]
}
vall = vall/(7.0*message["payload"]["radar"][1][0]);
break;
} }
} }
if (vall != -1000000) { }
epoch_ms = (timee+hours_delta * 3600) * 1000; else{
series.data.x.push(new Date(epoch_ms)); for(i = 0; i<=18; i++){
series.data.values.push(vall); if (MAC+radar_tablesn[i] in series_indexes){
//series.data.values.push(vall);
//time_obj = new Date(epoch_ms);
//series.data.x.push(time_obj);
UniversalChart.axes.bottom.labels.roundFirst = true; series_index = series_indexes[MAC+radar_tablesn[i]];
UniversalChart.axes.bottom.labels.dateFormat = "shortDateTime"; series = UniversalChart.series.items[series_index];
UniversalChart.draw(); if (series.visible == true) {
radar_part = document.getElementById("RadarPart").value;
timee = message["payload"]["time"];
switch(radar_part) {
case "absent":
vall = message["payload"]["radar"][0][1]/message["payload"]["radar"][0][0];
break;
case "moving":
vall = message["payload"]["radar"][0][2]/message["payload"]["radar"][0][0];
break;
case "stationary":
vall = message["payload"]["radar"][0][3]/message["payload"]["radar"][0][0];
break;
case "both":
vall = message["payload"]["radar"][0][4]/message["payload"]["radar"][0][0];
break;
case "m0":
vall = message["payload"]["radar"][0][5]/message["payload"]["radar"][0][0];
break;
case "m1":
vall = message["payload"]["radar"][0][6]/message["payload"]["radar"][0][0];
break;
case "m2":
vall = message["payload"]["radar"][0][7]/message["payload"]["radar"][0][0];
break;
case "m3":
vall = message["payload"]["radar"][0][8]/message["payload"]["radar"][0][0];
break;
case "m4":
vall = message["payload"]["radar"][0][9]/message["payload"]["radar"][0][0];
break;
case "m5":
vall = message["payload"]["radar"][0][10]/message["payload"]["radar"][0][0];
break;
case "m6":
vall = message["payload"]["radar"][0][11]/message["payload"]["radar"][0][0];
break;
case "m7":
vall = message["payload"]["radar"][0][12]/message["payload"]["radar"][0][0];
break;
case "m8":
vall = message["payload"]["radar"][0][13]/message["payload"]["radar"][0][0];
break;
case "s2":
vall = message["payload"]["radar"][1][3]/message["payload"]["radar"][1][0];
break;
case "s3":
vall = message["payload"]["radar"][1][4]/message["payload"]["radar"][1][0];
break;
case "s4":
vall = message["payload"]["radar"][1][5]/message["payload"]["radar"][1][0];
break;
case "s5":
vall = message["payload"]["radar"][1][6]/message["payload"]["radar"][1][0];
break;
case "s6":
vall = message["payload"]["radar"][1][7]/message["payload"]["radar"][1][0];
break;
case "s7":
vall = message["payload"]["radar"][1][8]/message["payload"]["radar"][1][0];
break;
case "s8":
vall = message["payload"]["radar"][1][9]/message["payload"]["radar"][1][0];
break;
case "s28":
vall = 0;
for (i_=3; i_<=9; i_++){
vall += message["payload"]["radar"][1][i_]
}
vall = vall/(7.0*message["payload"]["radar"][1][0]);
break;
}
}
if (vall != -1000000) {
epoch_ms = (timee+hours_delta * 3600) * 1000;
series.data.x.push(new Date(epoch_ms));
series.data.values.push(vall);
//series.data.values.push(vall);
//time_obj = new Date(epoch_ms);
//series.data.x.push(time_obj);
UniversalChart.axes.bottom.labels.roundFirst = true;
UniversalChart.axes.bottom.labels.dateFormat = "shortDateTime";
UniversalChart.draw();
}
}
} }
} }
break; break;
case "sensors": case "sensors":
case 17:
//case "light": //case "light":
//message["payload"]["topic"] //message["payload"]["topic"]
map_type = document.getElementById("map_type").value; map_type = document.getElementById("map_type").value;
@ -2218,7 +2315,7 @@ function createCustomLegend() {
const legendWidth = 150; // Width for the legend const legendWidth = 150; // Width for the legend
const chartTopMargin = 35; // Approximate top margin of chart (for title, etc.) const chartTopMargin = 35; // Approximate top margin of chart (for title, etc.)
const chartBottomMargin = 40; // Approximate bottom margin (for axis labels, etc.) const chartBottomMargin = 40; // Approximate bottom margin (for axis labels, etc.)
// Create or update custom legend container // Create or update custom legend container
let legendDiv = document.getElementById('custom-chart-legend'); let legendDiv = document.getElementById('custom-chart-legend');
if (!legendDiv) { if (!legendDiv) {
@ -2235,20 +2332,20 @@ function createCustomLegend() {
legendDiv.style.overflowY = 'auto'; legendDiv.style.overflowY = 'auto';
chartContainer.appendChild(legendDiv); chartContainer.appendChild(legendDiv);
} }
// Clear existing legend // Clear existing legend
legendDiv.innerHTML = ''; legendDiv.innerHTML = '';
// Calculate series area height to match legend height if needed // Calculate series area height to match legend height if needed
const seriesAreaHeight = canvasRect.height - chartTopMargin - chartBottomMargin; const seriesAreaHeight = canvasRect.height - chartTopMargin - chartBottomMargin;
legendDiv.style.height = seriesAreaHeight + 'px'; legendDiv.style.height = seriesAreaHeight + 'px';
// Create Select All/None controls // Create Select All/None controls
const controlsDiv = document.createElement('div'); const controlsDiv = document.createElement('div');
controlsDiv.style.marginBottom = '1px'; controlsDiv.style.marginBottom = '1px';
controlsDiv.style.paddingBottom = '1px'; controlsDiv.style.paddingBottom = '1px';
controlsDiv.style.borderBottom = '1px solid #ddd'; controlsDiv.style.borderBottom = '1px solid #ddd';
// Select All button // Select All button
const selectAllBtn = document.createElement('button'); const selectAllBtn = document.createElement('button');
selectAllBtn.textContent = 'All'; selectAllBtn.textContent = 'All';
@ -2258,7 +2355,7 @@ function createCustomLegend() {
selectAllBtn.style.cursor = 'pointer'; selectAllBtn.style.cursor = 'pointer';
selectAllBtn.style.border = '1px solid #ccc'; selectAllBtn.style.border = '1px solid #ccc';
selectAllBtn.style.backgroundColor = '#f8f8f8'; selectAllBtn.style.backgroundColor = '#f8f8f8';
// Select None button // Select None button
const selectNoneBtn = document.createElement('button'); const selectNoneBtn = document.createElement('button');
selectNoneBtn.textContent = 'None'; selectNoneBtn.textContent = 'None';
@ -2267,12 +2364,12 @@ function createCustomLegend() {
selectNoneBtn.style.cursor = 'pointer'; selectNoneBtn.style.cursor = 'pointer';
selectNoneBtn.style.border = '1px solid #ccc'; selectNoneBtn.style.border = '1px solid #ccc';
selectNoneBtn.style.backgroundColor = '#f8f8f8'; selectNoneBtn.style.backgroundColor = '#f8f8f8';
// Add buttons to controls // Add buttons to controls
controlsDiv.appendChild(selectAllBtn); controlsDiv.appendChild(selectAllBtn);
controlsDiv.appendChild(selectNoneBtn); controlsDiv.appendChild(selectNoneBtn);
legendDiv.appendChild(controlsDiv); legendDiv.appendChild(controlsDiv);
// Function to update all checkboxes // Function to update all checkboxes
function updateAllCheckboxes(checked) { function updateAllCheckboxes(checked) {
const checkboxes = legendDiv.querySelectorAll('input[type="checkbox"][data-series-index]'); const checkboxes = legendDiv.querySelectorAll('input[type="checkbox"][data-series-index]');
@ -2283,40 +2380,40 @@ function createCustomLegend() {
}); });
UniversalChart.draw(); UniversalChart.draw();
} }
// Add event listeners for Select All/None buttons // Add event listeners for Select All/None buttons
selectAllBtn.addEventListener('click', function() { selectAllBtn.addEventListener('click', function() {
updateAllCheckboxes(true); updateAllCheckboxes(true);
}); });
selectNoneBtn.addEventListener('click', function() { selectNoneBtn.addEventListener('click', function() {
updateAllCheckboxes(false); updateAllCheckboxes(false);
}); });
// Add legend items // Add legend items
for (let i = 0; i < UniversalChart.series.count(); i++) { for (let i = 0; i < UniversalChart.series.count(); i++) {
const series = UniversalChart.series.items[i]; const series = UniversalChart.series.items[i];
// Create legend item container // Create legend item container
const itemDiv = document.createElement('div'); const itemDiv = document.createElement('div');
itemDiv.style.marginBottom = '5px'; itemDiv.style.marginBottom = '5px';
itemDiv.style.display = 'flex'; itemDiv.style.display = 'flex';
itemDiv.style.alignItems = 'center'; itemDiv.style.alignItems = 'center';
// Create checkbox // Create checkbox
const checkbox = document.createElement('input'); const checkbox = document.createElement('input');
checkbox.type = 'checkbox'; checkbox.type = 'checkbox';
checkbox.checked = series.visible; checkbox.checked = series.visible;
checkbox.style.marginRight = '5px'; checkbox.style.marginRight = '5px';
checkbox.setAttribute('data-series-index', i); checkbox.setAttribute('data-series-index', i);
// Add event listener for checkbox // Add event listener for checkbox
checkbox.addEventListener('change', function() { checkbox.addEventListener('change', function() {
const seriesIndex = parseInt(this.getAttribute('data-series-index')); const seriesIndex = parseInt(this.getAttribute('data-series-index'));
UniversalChart.series.items[seriesIndex].visible = this.checked; UniversalChart.series.items[seriesIndex].visible = this.checked;
UniversalChart.draw(); UniversalChart.draw();
}); });
// Create color swatch // Create color swatch
const colorSwatch = document.createElement('span'); const colorSwatch = document.createElement('span');
colorSwatch.style.display = 'inline-block'; colorSwatch.style.display = 'inline-block';
@ -2324,31 +2421,31 @@ function createCustomLegend() {
colorSwatch.style.height = '12px'; colorSwatch.style.height = '12px';
colorSwatch.style.backgroundColor = series.format.stroke.fill; colorSwatch.style.backgroundColor = series.format.stroke.fill;
colorSwatch.style.marginRight = '5px'; colorSwatch.style.marginRight = '5px';
// Create label // Create label
const label = document.createElement('span'); const label = document.createElement('span');
label.textContent = series.title; label.textContent = series.title;
label.style.fontSize = '12px'; label.style.fontSize = '12px';
// Add elements to item // Add elements to item
itemDiv.appendChild(checkbox); itemDiv.appendChild(checkbox);
itemDiv.appendChild(colorSwatch); itemDiv.appendChild(colorSwatch);
itemDiv.appendChild(label); itemDiv.appendChild(label);
// Add item to legend // Add item to legend
legendDiv.appendChild(itemDiv); legendDiv.appendChild(itemDiv);
} }
// Hide the built-in legend // Hide the built-in legend
UniversalChart.legend.visible = false; UniversalChart.legend.visible = false;
// Shift the chart panel to the right to make space for the legend // Shift the chart panel to the right to make space for the legend
// This might require adjusting the chart margins or bounds // This might require adjusting the chart margins or bounds
const chartWidth = UniversalChart.canvas.width; const chartWidth = UniversalChart.canvas.width;
const marginPercentage = ((30+legendWidth) / chartWidth) * 100; const marginPercentage = ((30+legendWidth) / chartWidth) * 100;
UniversalChart.panel.margins.left = marginPercentage; // 20px extra spacing UniversalChart.panel.margins.left = marginPercentage; // 20px extra spacing
UniversalChart.panel.margins.right = 0; UniversalChart.panel.margins.right = 0;
// Redraw the chart with new dimensions // Redraw the chart with new dimensions
UniversalChart.draw(); UniversalChart.draw();
} }
@ -3619,12 +3716,12 @@ async function GetZGraph() {
formData.append('time', timee); formData.append('time', timee);
formData.append('data_type', data_type); formData.append('data_type', data_type);
if (document.getElementById("rcr-check").checked){ if (document.getElementById("rcr-check").checked){
formData.append('refresh', 1); formData.append('refresh', 1);
} }
else{ else{
formData.append('refresh', 0); formData.append('refresh', 0);
} }
data = await SubmitForm(formData); data = await SubmitForm(formData);
if (data.status !== "200 OK") { if (data.status !== "200 OK") {