{"id":517,"date":"2025-07-16T13:40:06","date_gmt":"2025-07-16T13:40:06","guid":{"rendered":"https:\/\/jciseguridad.com.ar\/?page_id=517"},"modified":"2025-07-16T15:57:50","modified_gmt":"2025-07-16T15:57:50","slug":"pnt","status":"publish","type":"page","link":"https:\/\/jciseguridad.com.ar\/en\/pnt\/","title":{"rendered":"pnt"},"content":{"rendered":"<div data-elementor-type=\"wp-page\" data-elementor-id=\"517\" class=\"elementor elementor-517\" data-elementor-post-type=\"page\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-63c48c0 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"63c48c0\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-4604daa\" data-id=\"4604daa\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-f0742a9 elementor-widget elementor-widget-html\" data-id=\"f0742a9\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!DOCTYPE html>\r\n<html lang=\"es\">\r\n<head>\r\n  <meta charset=\"UTF-8\" \/>\r\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" \/>\r\n  <title>PNT - EL PRADO<\/title>\r\n  <link rel=\"stylesheet\" href=\"https:\/\/unpkg.com\/leaflet\/dist\/leaflet.css\" \/>\r\n  <style>\r\n    body {\r\n      font-family: Arial, sans-serif;\r\n      background-color: #f0fdf4;\r\n      margin: 20px;\r\n      color: #2e5339;\r\n    }\r\n    #map {\r\n      height: 400px;\r\n      margin-top: 15px;\r\n      border: 2px solid #a8d5b4;\r\n      border-radius: 8px;\r\n    }\r\n    table {\r\n      width: 100%;\r\n      border-collapse: collapse;\r\n      margin-top: 15px;\r\n    }\r\n    table, th, td {\r\n      border: 1px solid #b6d6be;\r\n    }\r\n    th {\r\n      background-color: #c6e8d2;\r\n    }\r\n    .chart-container {\r\n  width: 550px;\r\n  height: 300px;\r\n  display: inline-block;\r\n  vertical-align: top;\r\n}\r\n.chart-container canvas {\r\n  width: 100% !important;\r\n  height: 100% !important;\r\n  display: block;\r\n}\r\n\r\n\r\n  <\/style>\r\n<\/head>\r\n<body>\r\n\r\n<div id=\"pnt-app\">\r\n  <h1>PNT - EL PRADO<\/h1>\r\n\r\n  <button id=\"apply-filters-btn\">Aplicar filtros<\/button>\r\n  <button onclick=\"toggleMarkers()\">Mostrar\/Ocultar Marcadores<\/button>\r\n  <button onclick=\"toggleTable()\">Mostrar\/Ocultar Tabla<\/button>\r\n  <button onclick=\"resetFilters()\">Resetear Filtros<\/button>\r\n  <br><br>\r\n\r\n  <label>Desde: <input type=\"date\" id=\"date-from\"><\/label>\r\n  <label>Hasta: <input type=\"date\" id=\"date-to\"><\/label>\r\n\r\n  <select id=\"sector-filter\" multiple size=\"5\" style=\"width:200px;\"><\/select>\r\n  <select id=\"color-filter\" multiple size=\"3\" style=\"width:250px;\">\r\n    <option value=\"green\">Verde (m\u00e1s de 50 visitas)<\/option>\r\n    <option value=\"yellow\">Amarillo (26 a 50 visitas)<\/option>\r\n    <option value=\"red\">Rojo (25 visitas o menos)<\/option>\r\n  <\/select>\r\n\r\n  <div id=\"no-data-message\" style=\"color:red;font-weight:bold;display:none;\">\r\n    No hay datos para mostrar con los filtros seleccionados.\r\n  <\/div>\r\n\r\n  <div class=\"chart-container\">\r\n    <canvas id=\"chart-sector-visits\"><\/canvas>\r\n  <\/div>\r\n  <div class=\"chart-container\">\r\n    <canvas id=\"chart-user-visits\"><\/canvas>\r\n  <\/div>\r\n\r\n  <div id=\"map\"><\/div>\r\n\r\n  <div id=\"table-container\">\r\n    <table id=\"data-table\">\r\n      <thead>\r\n        <tr>\r\n          <th>PUNTO<\/th><th>Referencia<\/th><th>Sector<\/th><th>A\u00f1o<\/th>\r\n          <th>Mes<\/th><th>D\u00eda<\/th><th>Fecha<\/th><th>Usuario<\/th><th>Mapa (lat,long)<\/th>\r\n        <\/tr>\r\n      <\/thead>\r\n      <tbody><\/tbody>\r\n    <\/table>\r\n  <\/div>\r\n<\/div>\r\n\r\n<!-- Librer\u00edas -->\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/papaparse@5.3.2\/papaparse.min.js\"><\/script>\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js\"><\/script>\r\n<script src=\"https:\/\/unpkg.com\/leaflet\/dist\/leaflet.js\"><\/script>\r\n\r\n<script>\r\nconst sheetURL = \"https:\/\/docs.google.com\/spreadsheets\/d\/e\/2PACX-1vSa3DmYUN6QK411_Ur0v1VIojkzXwDywubxnoeNmzlrNT4lVC_4ASarWbE-xoaVo4hai-4j1KGQExjG\/pub?gid=0&single=true&output=csv\";\r\n\r\nlet dataRows = [], markers = [], allSectors = [];\r\nlet chartSectorInstance, chartUserInstance;\r\n\r\nconst map = L.map(\"map\").setView([-24.83, -65.48], 15);\r\nL.tileLayer(\"https:\/\/{s}.tile.openstreetmap.org\/{z}\/{x}\/{y}.png\").addTo(map);\r\n\r\nfunction cleanCoords(value) {\r\n  if (!value) return \"\";\r\n  let text = value.replace(\/[\"']\/g, \"\").trim().replace(\";\", \",\");\r\n  const parts = text.split(\",\").map(p => parseFloat(p.trim()));\r\n  return parts.length === 2 && parts.every(p => !isNaN(p)) ? parts.join(\",\") : \"\";\r\n}\r\n\r\nfunction parseFecha(fechaRaw) {\r\n  if (!fechaRaw) return null;\r\n  const d = new Date(fechaRaw);\r\n  return isNaN(d) ? null : d;\r\n}\r\n\r\nasync function loadDataFromGoogleSheet() {\r\n  try {\r\n    const response = await fetch(sheetURL);\r\n    const csvText = await response.text();\r\n    const parsed = Papa.parse(csvText.trim(), { skipEmptyLines: true });\r\n    const rows = parsed.data;\r\n\r\n    dataRows = rows.slice(1).map(r => {\r\n      return {\r\n        punto: r[0] || \"\",\r\n        referencia: r[1] || \"\",\r\n        sector: r[2] || \"\",\r\n        anio: r[3] || \"\",\r\n        mes: r[4] || \"\",\r\n        dia: r[5] || \"\",\r\n        fecha: r[6] || \"\",\r\n        fechaObj: parseFecha(r[6]),\r\n        usuario: r[7] || \"\",\r\n        coords: cleanCoords(r[8] || \"\")\r\n      };\r\n    }).filter(r => r.coords);\r\n\r\n    allSectors = [...new Set(dataRows.map(r => r.sector).filter(Boolean))].sort();\r\n    fillSectorOptions();\r\n    updateMap();\r\n  } catch (error) {\r\n    console.error(\"Error al cargar datos:\", error);\r\n  }\r\n}\r\n\r\nfunction fillSectorOptions() {\r\n  const selector = document.getElementById(\"sector-filter\");\r\n  selector.innerHTML = allSectors.map(s => `<option value=\"${s}\">${s}<\/option>`).join(\"\");\r\n}\r\n\r\nfunction updateMap() {\r\n  markers.forEach(m => map.removeLayer(m));\r\n  markers = [];\r\n\r\n  const from = parseFecha(document.getElementById(\"date-from\").value);\r\n  const to = parseFecha(document.getElementById(\"date-to\").value);\r\n  const sectorFilter = Array.from(document.getElementById(\"sector-filter\").selectedOptions).map(o => o.value);\r\n  const colorFilter = Array.from(document.getElementById(\"color-filter\").selectedOptions).map(o => o.value);\r\n\r\n  const filtered = dataRows.filter(r => {\r\n    if (from && r.fechaObj < from) return false;\r\n    if (to && r.fechaObj > to) return false;\r\n    if (sectorFilter.length && !sectorFilter.includes(r.sector)) return false;\r\n    return true;\r\n  });\r\n\r\n  const visitasPorSector = {}, visitasPorUsuario = {}, sectorCoords = {};\r\n  dataRows.forEach(r => {\r\n    if (r.sector && r.coords && !sectorCoords[r.sector]) sectorCoords[r.sector] = r.coords;\r\n  });\r\n  filtered.forEach(r => {\r\n    visitasPorSector[r.sector] = (visitasPorSector[r.sector] || 0) + 1;\r\n    visitasPorUsuario[r.usuario] = (visitasPorUsuario[r.usuario] || 0) + 1;\r\n  });\r\n\r\n  const sectoresAMostrar = sectorFilter.length ? sectorFilter : allSectors;\r\n  let rowsParaTabla = [];\r\n\r\n  sectoresAMostrar.forEach(sector => {\r\n    const visitas = visitasPorSector[sector] || 0;\r\n    let color = visitas > 50 ? \"green\" : (visitas > 25 ? \"yellow\" : \"red\");\r\n\r\n    if (colorFilter.length && !colorFilter.includes(color)) return;\r\n\r\n    const coordsRaw = sectorCoords[sector];\r\n    if (!coordsRaw) return;\r\n\r\n    const coords = coordsRaw.split(\",\").map(p => parseFloat(p));\r\n    if (coords.length !== 2 || coords.some(isNaN)) return;\r\n\r\n    const circle = L.circle(coords, {\r\n      color,\r\n      fillColor: color,\r\n      fillOpacity: 0.5,\r\n      radius: 50\r\n    }).addTo(map);\r\n    circle.bindPopup(`<b>Sector:<\/b> ${sector}<br><b>Visitas:<\/b> ${visitas}`);\r\n    markers.push(circle);\r\n\r\n    rowsParaTabla.push(...filtered.filter(r => r.sector === sector));\r\n  });\r\n\r\n  if (markers.length) {\r\n    const group = L.featureGroup(markers);\r\n    map.fitBounds(group.getBounds());\r\n  }\r\n\r\n  fillTable(rowsParaTabla);\r\n  updateCharts(visitasPorSector, visitasPorUsuario);\r\n\r\n  document.getElementById(\"no-data-message\").style.display = markers.length ? \"none\" : \"block\";\r\n}\r\n\r\nfunction fillTable(rows) {\r\n  const tbody = document.querySelector(\"#data-table tbody\");\r\n  tbody.innerHTML = \"\";\r\n  rows.forEach(r => {\r\n    const row = document.createElement(\"tr\");\r\n    row.innerHTML = `<td>${r.punto}<\/td><td>${r.referencia}<\/td><td>${r.sector}<\/td>\r\n    <td>${r.anio}<\/td><td>${r.mes}<\/td><td>${r.dia}<\/td><td>${r.fecha}<\/td>\r\n    <td>${r.usuario}<\/td><td>${r.coords}<\/td>`;\r\n    tbody.appendChild(row);\r\n  });\r\n}\r\n\r\nfunction updateCharts(vps, vpu) {\r\n  const destroy = chart => { if (chart) chart.destroy(); };\r\n  destroy(chartSectorInstance); destroy(chartUserInstance);\r\n\r\n  const ctx1 = document.getElementById(\"chart-sector-visits\").getContext(\"2d\");\r\n  chartSectorInstance = new Chart(ctx1, {\r\n    type: \"bar\",\r\n    data: {\r\n      labels: Object.keys(vps),\r\n      datasets: [{ label: \"Visitas por sector\", data: Object.values(vps), backgroundColor: \"#6bcf99\" }]\r\n    }\r\n  });\r\n\r\n  const ctx2 = document.getElementById(\"chart-user-visits\").getContext(\"2d\");\r\n  chartUserInstance = new Chart(ctx2, {\r\n    type: \"bar\",\r\n    data: {\r\n      labels: Object.keys(vpu),\r\n      datasets: [{ label: \"Visitas por usuario\", data: Object.values(vpu), backgroundColor: \"#f2b654\" }]\r\n    }\r\n  });\r\n}\r\n\r\nfunction toggleMarkers() {\r\n  markers.forEach(m => map.hasLayer(m) ? map.removeLayer(m) : m.addTo(map));\r\n}\r\nfunction toggleTable() {\r\n  const t = document.getElementById(\"table-container\");\r\n  t.style.display = t.style.display === \"none\" ? \"block\" : \"none\";\r\n}\r\nfunction resetFilters() {\r\n  document.getElementById(\"date-from\").value = \"\";\r\n  document.getElementById(\"date-to\").value = \"\";\r\n  document.getElementById(\"sector-filter\").selectedIndex = -1;\r\n  document.getElementById(\"color-filter\").selectedIndex = -1;\r\n  updateMap();\r\n}\r\n\r\ndocument.getElementById(\"apply-filters-btn\").addEventListener(\"click\", updateMap);\r\n[\"date-from\", \"date-to\", \"sector-filter\", \"color-filter\"].forEach(id => {\r\n  document.getElementById(id).addEventListener(\"change\", updateMap);\r\n});\r\n\r\nloadDataFromGoogleSheet();\r\n<\/script>\r\n\r\n<\/body>\r\n<\/html>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>","protected":false},"excerpt":{"rendered":"<p>PNT &#8211; EL PRADO PNT &#8211; EL PRADO Aplicar filtros Mostrar\/Ocultar Marcadores Mostrar\/Ocultar Tabla Resetear Filtros Desde: Hasta: Verde (m\u00e1s de 50 visitas)Amarillo (26 a 50 visitas)Rojo (25 visitas o menos) No hay datos para mostrar con los filtros seleccionados. PUNTO Referencia Sector A\u00f1o Mes D\u00eda Fecha Usuario Mapa (lat,long)<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-517","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/jciseguridad.com.ar\/en\/wp-json\/wp\/v2\/pages\/517","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jciseguridad.com.ar\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/jciseguridad.com.ar\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/jciseguridad.com.ar\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jciseguridad.com.ar\/en\/wp-json\/wp\/v2\/comments?post=517"}],"version-history":[{"count":106,"href":"https:\/\/jciseguridad.com.ar\/en\/wp-json\/wp\/v2\/pages\/517\/revisions"}],"predecessor-version":[{"id":626,"href":"https:\/\/jciseguridad.com.ar\/en\/wp-json\/wp\/v2\/pages\/517\/revisions\/626"}],"wp:attachment":[{"href":"https:\/\/jciseguridad.com.ar\/en\/wp-json\/wp\/v2\/media?parent=517"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}