From 4c316b5cbab9801bec6a5e70d0ca2df9868b219e Mon Sep 17 00:00:00 2001 From: Pouria Ezzati Date: Mon, 25 Nov 2024 08:58:41 +0330 Subject: [PATCH] move stats related javascript code to its own file --- server/views/stats.hbs | 1 + static/scripts/main.js | 446 --------------------------------------- static/scripts/stats.js | 450 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 451 insertions(+), 446 deletions(-) create mode 100644 static/scripts/stats.js diff --git a/server/views/stats.hbs b/server/views/stats.hbs index 1620d88..00dba35 100644 --- a/server/views/stats.hbs +++ b/server/views/stats.hbs @@ -21,4 +21,5 @@ {{> footer}} {{#extend "scripts"}} + {{/extend}} \ No newline at end of file diff --git a/static/scripts/main.js b/static/scripts/main.js index dcd4bfe..ef3b77e 100644 --- a/static/scripts/main.js +++ b/static/scripts/main.js @@ -269,452 +269,6 @@ function canSendVerificationEmail() { checkbox.classList.add('hidden'); } -// create views chart label -function createViewsChartLabel(ctx) { - const period = ctx.dataset.period; - let labels = []; - - if (period === "day") { - const nowHour = new Date().getHours(); - for (let i = 23; i >= 0; --i) { - let h = nowHour - i; - if (h < 0) h = 24 + h; - labels.push(`${Math.floor(h)}:00`); - } - } - - if (period === "week") { - const nowDay = new Date().getDate(); - for (let i = 6; i >= 0; --i) { - const date = new Date(new Date().setDate(nowDay - i)); - labels.push(`${date.getDate()} ${date.toLocaleString("default",{month:"short"})}`); - } - } - - if (period === "month") { - const nowDay = new Date().getDate(); - for (let i = 29; i >= 0; --i) { - const date = new Date(new Date().setDate(nowDay - i)); - labels.push(`${date.getDate()} ${date.toLocaleString("default",{month:"short"})}`); - } - } - - if (period === "year") { - const nowMonth = new Date().getMonth(); - for (let i = 11; i >= 0; --i) { - const date = new Date(new Date().setMonth(nowMonth - i)); - labels.push(`${date.toLocaleString("default",{month:"short"})} ${date.toLocaleString("default",{year:"numeric"})}`); - } - } - - return labels; -} - -// create views chart -function createViewsChart() { - const canvases = document.querySelectorAll("canvas.visits"); - if (!canvases || !canvases.length) return; - - canvases.forEach(ctx => { - const data = JSON.parse(ctx.dataset.data); - const period = ctx.dataset.period; - - const labels = createViewsChartLabel(ctx); - const maxTicksLimitX = period === "year" ? 6 : period === "month" ? 15 : 12; - - const gradient = ctx.getContext("2d").createLinearGradient(0, 0, 0, 300); - gradient.addColorStop(0, "rgba(179, 157, 219, 0.95)"); - gradient.addColorStop(1, "rgba(179, 157, 219, 0.05)"); - - new Chart(ctx, { - type: "line", - data: { - labels: labels, - datasets: [{ - label: "Views", - data, - tension: 0.3, - - elements: { - point: { - pointRadius: 0, - pointHoverRadius: 4 - } - }, - fill: { - target: "start", - }, - backgroundColor: gradient, - borderColor: "rgb(179, 157, 219)", - borderWidth: 1, - }] - }, - options: { - plugins: { - legend: { - display: false, - }, - tooltip: { - backgroundColor: "rgba(255, 255, 255, 0.95)", - titleColor: "#333", - titleFont: { weight: "normal", size: 15 }, - bodyFont: { weight: "normal", size: 16 }, - bodyColor: "rgb(179, 157, 219)", - padding: 12, - cornerRadius: 2, - borderColor: "rgba(0, 0, 0, 0.1)", - borderWidth: 1, - displayColors: false, - } - }, - responsive: true, - interaction: { - intersect: false, - usePointStyle: true, - mode: "index", - }, - scales: { - y: { - grace: "10%", - beginAtZero: true, - ticks: { - maxTicksLimit: 5 - } - }, - x: { - ticks: { - maxTicksLimit: maxTicksLimitX, - } - } - } - } - }); - - // reset the display: block style that chart.js applies automatically - ctx.style.display = ""; - }); -} - -// beautify browser lables -function beautifyBrowserName(name) { - if (name === "firefox") return "Firefox"; - if (name === "chrome") return "Chrome"; - if (name === "edge") return "Edge"; - if (name === "opera") return "Opera"; - if (name === "safari") return "Safari"; - if (name === "other") return "Other"; - if (name === "ie") return "IE"; - return name; -} - -// create browsers chart -function createBrowsersChart() { - const canvases = document.querySelectorAll("canvas.browsers"); - if (!canvases || !canvases.length) return; - - canvases.forEach(ctx => { - const data = JSON.parse(ctx.dataset.data); - const period = ctx.dataset.period; - - const gradient = ctx.getContext("2d").createLinearGradient(500, 0, 0, 0); - const gradientHover = ctx.getContext("2d").createLinearGradient(500, 0, 0, 0); - gradient.addColorStop(0, "rgba(179, 157, 219, 0.95)"); - gradient.addColorStop(1, "rgba(179, 157, 219, 0.05)"); - gradientHover.addColorStop(0, "rgba(179, 157, 219, 0.9)"); - gradientHover.addColorStop(1, "rgba(179, 157, 219, 0.4)"); - - new Chart(ctx, { - type: "bar", - data: { - labels: data.map(d => beautifyBrowserName(d.name)), - datasets: [{ - label: "Views", - data: data.map(d => d.value), - backgroundColor: gradient, - borderColor: "rgba(179, 157, 219, 1)", - borderWidth: 1, - hoverBackgroundColor: gradientHover, - hoverBorderWidth: 2 - }] - }, - options: { - indexAxis: "y", - plugins: { - legend: { - display: false, - }, - tooltip: { - backgroundColor: "rgba(255, 255, 255, 0.95)", - titleColor: "#333", - titleFont: { weight: "normal", size: 15 }, - bodyFont: { weight: "normal", size: 16 }, - bodyColor: "rgb(179, 157, 219)", - padding: 12, - cornerRadius: 2, - borderColor: "rgba(0, 0, 0, 0.1)", - borderWidth: 1, - displayColors: false, - } - }, - responsive: true, - interaction: { - intersect: false, - mode: "index", - axis: "y" - }, - scales: { - x: { - grace: "5%", - beginAtZero: true, - ticks: { - maxTicksLimit: 6, - } - } - } - } - }); - - // reset the display: block style that chart.js applies automatically - ctx.style.display = ""; - }); -} - -// create referrers chart -function createReferrersChart() { - const canvases = document.querySelectorAll("canvas.referrers"); - if (!canvases || !canvases.length) return; - - canvases.forEach(ctx => { - const data = JSON.parse(ctx.dataset.data); - const period = ctx.dataset.period; - let max = Array.from(data).sort((a, b) => a.value > b.value ? -1 : 1)[0]; - - let tooltipEnabled = true; - let hoverBackgroundColor = "rgba(179, 157, 219, 1)"; - let hoverBorderWidth = 2; - let borderColor = "rgba(179, 157, 219, 1)"; - if (data.length === 0) { - data.push({ name: "No views.", value: 1 }); - max = { value: 1000 }; - tooltipEnabled = false; - hoverBackgroundColor = "rgba(179, 157, 219, 0.1)"; - hoverBorderWidth = 1; - borderColor = "rgba(179, 157, 219, 0.2)"; - } - - new Chart(ctx, { - type: "doughnut", - data: { - labels: data.map(d => d.name.replace(/\[dot\]/g, ".")), - datasets: [{ - label: "Views", - data: data.map(d => d.value), - backgroundColor: data.map(d => `rgba(179, 157, 219, ${Math.max((d.value / max.value) - 0.2, 0.1).toFixed(2)})`), - borderWidth: 1, - borderColor, - hoverBackgroundColor, - hoverBorderWidth, - }] - }, - options: { - plugins: { - legend: { - position: "left", - labels: { - boxWidth: 25, - font: { size: 11 } - } - }, - tooltip: { - enabled: tooltipEnabled, - backgroundColor: "rgba(255, 255, 255, 0.95)", - titleColor: "#333", - titleFont: { weight: "normal", size: 15 }, - bodyFont: { weight: "normal", size: 16 }, - bodyColor: "rgb(179, 157, 219)", - padding: 12, - cornerRadius: 2, - borderColor: "rgba(0, 0, 0, 0.1)", - borderWidth: 1, - displayColors: false, - } - }, - responsive: false, - } - }); - - // reset the display: block style that chart.js applies automatically - ctx.style.display = ""; - }); -} - - -// beautify browser lables -function beautifyOsName(name) { - if (name === "android") return "Android"; - if (name === "ios") return "iOS"; - if (name === "linux") return "Linux"; - if (name === "macos") return "macOS"; - if (name === "windows") return "Windows"; - if (name === "other") return "Other"; - return name; -} - - -// create operation systems chart -function createOsChart() { - const canvases = document.querySelectorAll("canvas.os"); - if (!canvases || !canvases.length) return; - - canvases.forEach(ctx => { - const data = JSON.parse(ctx.dataset.data); - const period = ctx.dataset.period; - - const gradient = ctx.getContext("2d").createLinearGradient(500, 0, 0, 0); - const gradientHover = ctx.getContext("2d").createLinearGradient(500, 0, 0, 0); - gradient.addColorStop(0, "rgba(179, 157, 219, 0.95)"); - gradient.addColorStop(1, "rgba(179, 157, 219, 0.05)"); - gradientHover.addColorStop(0, "rgba(179, 157, 219, 0.9)"); - gradientHover.addColorStop(1, "rgba(179, 157, 219, 0.4)"); - - new Chart(ctx, { - type: "bar", - data: { - labels: data.map(d => beautifyOsName(d.name)), - datasets: [{ - label: "Views", - data: data.map(d => d.value), - backgroundColor: gradient, - borderColor: "rgba(179, 157, 219, 1)", - borderWidth: 1, - hoverBackgroundColor: gradientHover, - hoverBorderWidth: 2 - }] - }, - options: { - indexAxis: "y", - plugins: { - legend: { - display: false, - }, - tooltip: { - backgroundColor: "rgba(255, 255, 255, 0.95)", - titleColor: "#333", - titleFont: { weight: "normal", size: 15 }, - bodyFont: { weight: "normal", size: 16 }, - bodyColor: "rgb(179, 157, 219)", - padding: 12, - cornerRadius: 2, - borderColor: "rgba(0, 0, 0, 0.1)", - borderWidth: 1, - displayColors: false, - } - }, - responsive: true, - interaction: { - intersect: false, - mode: "index", - axis: "y" - }, - scales: { - x: { - grace:"5%", - beginAtZero: true, - ticks: { - maxTicksLimit: 6, - } - } - } - } - }); - - // reset the display: block style that chart.js applies automatically - ctx.style.display = ""; - }); -} - -// add data to the map -function feedMapData(period) { - const map = document.querySelector("svg.map"); - const paths = map.querySelectorAll("path"); - if (!map || !paths || !paths.length) return; - - let data = JSON.parse(map.dataset[period || "day"]); - if (!data) return; - - let max = data.sort((a, b) => a.value > b.value ? -1 : 1)[0]; - - if (!max) max = { value: 1 } - - data = data.reduce((a, c) => ({ ...a, [c.name]: c.value }), {}); - - for (let i = 0; i < paths.length; ++i) { - const id = paths[i].dataset.id; - const views = data[id] || 0; - paths[i].dataset.views = views; - const colorLevel = Math.ceil((views / max.value) * 6); - const classList = paths[i].classList; - for (let j = 1; j < 7; j++) { - paths[i].classList.remove(`color-${j}`); - } - paths[i].classList.add(`color-${colorLevel}`) - paths[i].dataset.views = views; - } -} - -// handle map tooltip hover -function mapTooltipHoverOver() { - const tooltip = document.querySelector("#map-tooltip"); - if (!tooltip) return; - if (!event.target.dataset.id) return mapTooltipHoverOut(); - if (!tooltip.classList.contains("active")) { - tooltip.classList.add("visible"); - } - tooltip.dataset.tooltip = `${event.target.ariaLabel}: ${event.target.dataset.views || 0}`; - const rect = event.target.getBoundingClientRect(); - tooltip.style.top = rect.top + (rect.height / 2) + "px"; - tooltip.style.left = rect.left + (rect.width / 2) + "px"; - event.target.classList.add("active"); -} -function mapTooltipHoverOut() { - const tooltip = document.querySelector("#map-tooltip"); - const map = document.querySelector("svg.map"); - const paths = map.querySelectorAll("path"); - if (!tooltip || !map) return; - tooltip.classList.remove("visible"); - for (let i = 0; i < paths.length; ++i) { - paths[i].classList.remove("active"); - } -} - -// create stats charts -function createCharts() { - createViewsChart(); - createBrowsersChart(); - createReferrersChart(); - createOsChart(); - feedMapData(); -} - -// change stats period for showing charts and data -function changeStatsPeriod(event) { - const period = event.target.dataset.period; - if (!period) return; - const canvases = document.querySelector("#stats").querySelectorAll("[data-period]"); - const buttons = document.querySelector("#stats").querySelectorAll(".nav"); - if (!buttons || !canvases) return; - buttons.forEach(b => b.disabled = false); - event.target.disabled = true; - canvases.forEach(canvas => { - if (canvas.dataset.period === period) { - canvas.classList.remove("hidden"); - } else { - canvas.classList.add("hidden"); - } - }); - feedMapData(period); -} - // htmx prefetch extension // https://github.com/bigskysoftware/htmx-extensions/blob/main/src/preload/README.md htmx.defineExtension('preload', { diff --git a/static/scripts/stats.js b/static/scripts/stats.js new file mode 100644 index 0000000..d395c06 --- /dev/null +++ b/static/scripts/stats.js @@ -0,0 +1,450 @@ +// create views chart label +function createViewsChartLabel(ctx) { + const period = ctx.dataset.period; + let labels = []; + + if (period === "day") { + const nowHour = new Date().getHours(); + for (let i = 23; i >= 0; --i) { + let h = nowHour - i; + if (h < 0) h = 24 + h; + labels.push(`${Math.floor(h)}:00`); + } + } + + if (period === "week") { + const nowDay = new Date().getDate(); + for (let i = 6; i >= 0; --i) { + const date = new Date(new Date().setDate(nowDay - i)); + labels.push(`${date.getDate()} ${date.toLocaleString("default",{month:"short"})}`); + } + } + + if (period === "month") { + const nowDay = new Date().getDate(); + for (let i = 29; i >= 0; --i) { + const date = new Date(new Date().setDate(nowDay - i)); + labels.push(`${date.getDate()} ${date.toLocaleString("default",{month:"short"})}`); + } + } + + if (period === "year") { + const nowMonth = new Date().getMonth(); + for (let i = 11; i >= 0; --i) { + const date = new Date(new Date().setMonth(nowMonth - i)); + labels.push(`${date.toLocaleString("default",{month:"short"})} ${date.toLocaleString("default",{year:"numeric"})}`); + } + } + + return labels; +} + +// change stats period for showing charts and data +function changeStatsPeriod(event) { + const period = event.target.dataset.period; + if (!period) return; + const canvases = document.querySelector("#stats").querySelectorAll("[data-period]"); + const buttons = document.querySelector("#stats").querySelectorAll(".nav"); + if (!buttons || !canvases) return; + buttons.forEach(b => b.disabled = false); + event.target.disabled = true; + canvases.forEach(canvas => { + if (canvas.dataset.period === period) { + canvas.classList.remove("hidden"); + } else { + canvas.classList.add("hidden"); + } + }); + feedMapData(period); +} + +// beautify browser lables +function beautifyBrowserName(name) { + if (name === "firefox") return "Firefox"; + if (name === "chrome") return "Chrome"; + if (name === "edge") return "Edge"; + if (name === "opera") return "Opera"; + if (name === "safari") return "Safari"; + if (name === "other") return "Other"; + if (name === "ie") return "IE"; + return name; +} + + +// create views chart +function createViewsChart() { + const canvases = document.querySelectorAll("canvas.visits"); + if (!canvases || !canvases.length) return; + + canvases.forEach(ctx => { + const data = JSON.parse(ctx.dataset.data); + const period = ctx.dataset.period; + + const labels = createViewsChartLabel(ctx); + const maxTicksLimitX = period === "year" ? 6 : period === "month" ? 15 : 12; + + const gradient = ctx.getContext("2d").createLinearGradient(0, 0, 0, 300); + gradient.addColorStop(0, "rgba(179, 157, 219, 0.95)"); + gradient.addColorStop(1, "rgba(179, 157, 219, 0.05)"); + + new Chart(ctx, { + type: "line", + data: { + labels: labels, + datasets: [{ + label: "Views", + data, + tension: 0.3, + + elements: { + point: { + pointRadius: 0, + pointHoverRadius: 4 + } + }, + fill: { + target: "start", + }, + backgroundColor: gradient, + borderColor: "rgb(179, 157, 219)", + borderWidth: 1, + }] + }, + options: { + plugins: { + legend: { + display: false, + }, + tooltip: { + backgroundColor: "rgba(255, 255, 255, 0.95)", + titleColor: "#333", + titleFont: { weight: "normal", size: 15 }, + bodyFont: { weight: "normal", size: 16 }, + bodyColor: "rgb(179, 157, 219)", + padding: 12, + cornerRadius: 2, + borderColor: "rgba(0, 0, 0, 0.1)", + borderWidth: 1, + displayColors: false, + } + }, + responsive: true, + interaction: { + intersect: false, + usePointStyle: true, + mode: "index", + }, + scales: { + y: { + grace: "10%", + beginAtZero: true, + ticks: { + maxTicksLimit: 5 + } + }, + x: { + ticks: { + maxTicksLimit: maxTicksLimitX, + } + } + } + } + }); + + // reset the display: block style that chart.js applies automatically + ctx.style.display = ""; + }); +} + +// create browsers chart +function createBrowsersChart() { + const canvases = document.querySelectorAll("canvas.browsers"); + if (!canvases || !canvases.length) return; + + canvases.forEach(ctx => { + const data = JSON.parse(ctx.dataset.data); + const period = ctx.dataset.period; + + const gradient = ctx.getContext("2d").createLinearGradient(500, 0, 0, 0); + const gradientHover = ctx.getContext("2d").createLinearGradient(500, 0, 0, 0); + gradient.addColorStop(0, "rgba(179, 157, 219, 0.95)"); + gradient.addColorStop(1, "rgba(179, 157, 219, 0.05)"); + gradientHover.addColorStop(0, "rgba(179, 157, 219, 0.9)"); + gradientHover.addColorStop(1, "rgba(179, 157, 219, 0.4)"); + + new Chart(ctx, { + type: "bar", + data: { + labels: data.map(d => beautifyBrowserName(d.name)), + datasets: [{ + label: "Views", + data: data.map(d => d.value), + backgroundColor: gradient, + borderColor: "rgba(179, 157, 219, 1)", + borderWidth: 1, + hoverBackgroundColor: gradientHover, + hoverBorderWidth: 2 + }] + }, + options: { + indexAxis: "y", + plugins: { + legend: { + display: false, + }, + tooltip: { + backgroundColor: "rgba(255, 255, 255, 0.95)", + titleColor: "#333", + titleFont: { weight: "normal", size: 15 }, + bodyFont: { weight: "normal", size: 16 }, + bodyColor: "rgb(179, 157, 219)", + padding: 12, + cornerRadius: 2, + borderColor: "rgba(0, 0, 0, 0.1)", + borderWidth: 1, + displayColors: false, + } + }, + responsive: true, + interaction: { + intersect: false, + mode: "index", + axis: "y" + }, + scales: { + x: { + grace: "5%", + beginAtZero: true, + ticks: { + maxTicksLimit: 6, + } + } + } + } + }); + + // reset the display: block style that chart.js applies automatically + ctx.style.display = ""; + }); +} + +// create referrers chart +function createReferrersChart() { + const canvases = document.querySelectorAll("canvas.referrers"); + if (!canvases || !canvases.length) return; + + canvases.forEach(ctx => { + const data = JSON.parse(ctx.dataset.data); + const period = ctx.dataset.period; + let max = Array.from(data).sort((a, b) => a.value > b.value ? -1 : 1)[0]; + + let tooltipEnabled = true; + let hoverBackgroundColor = "rgba(179, 157, 219, 1)"; + let hoverBorderWidth = 2; + let borderColor = "rgba(179, 157, 219, 1)"; + if (data.length === 0) { + data.push({ name: "No views.", value: 1 }); + max = { value: 1000 }; + tooltipEnabled = false; + hoverBackgroundColor = "rgba(179, 157, 219, 0.1)"; + hoverBorderWidth = 1; + borderColor = "rgba(179, 157, 219, 0.2)"; + } + + new Chart(ctx, { + type: "doughnut", + data: { + labels: data.map(d => d.name.replace(/\[dot\]/g, ".")), + datasets: [{ + label: "Views", + data: data.map(d => d.value), + backgroundColor: data.map(d => `rgba(179, 157, 219, ${Math.max((d.value / max.value) - 0.2, 0.1).toFixed(2)})`), + borderWidth: 1, + borderColor, + hoverBackgroundColor, + hoverBorderWidth, + }] + }, + options: { + plugins: { + legend: { + position: "left", + labels: { + boxWidth: 25, + font: { size: 11 } + } + }, + tooltip: { + enabled: tooltipEnabled, + backgroundColor: "rgba(255, 255, 255, 0.95)", + titleColor: "#333", + titleFont: { weight: "normal", size: 15 }, + bodyFont: { weight: "normal", size: 16 }, + bodyColor: "rgb(179, 157, 219)", + padding: 12, + cornerRadius: 2, + borderColor: "rgba(0, 0, 0, 0.1)", + borderWidth: 1, + displayColors: false, + } + }, + responsive: false, + } + }); + + // reset the display: block style that chart.js applies automatically + ctx.style.display = ""; + }); +} + + +// beautify browser lables +function beautifyOsName(name) { + if (name === "android") return "Android"; + if (name === "ios") return "iOS"; + if (name === "linux") return "Linux"; + if (name === "macos") return "macOS"; + if (name === "windows") return "Windows"; + if (name === "other") return "Other"; + return name; +} + + +// create operation systems chart +function createOsChart() { + const canvases = document.querySelectorAll("canvas.os"); + if (!canvases || !canvases.length) return; + + canvases.forEach(ctx => { + const data = JSON.parse(ctx.dataset.data); + const period = ctx.dataset.period; + + const gradient = ctx.getContext("2d").createLinearGradient(500, 0, 0, 0); + const gradientHover = ctx.getContext("2d").createLinearGradient(500, 0, 0, 0); + gradient.addColorStop(0, "rgba(179, 157, 219, 0.95)"); + gradient.addColorStop(1, "rgba(179, 157, 219, 0.05)"); + gradientHover.addColorStop(0, "rgba(179, 157, 219, 0.9)"); + gradientHover.addColorStop(1, "rgba(179, 157, 219, 0.4)"); + + new Chart(ctx, { + type: "bar", + data: { + labels: data.map(d => beautifyOsName(d.name)), + datasets: [{ + label: "Views", + data: data.map(d => d.value), + backgroundColor: gradient, + borderColor: "rgba(179, 157, 219, 1)", + borderWidth: 1, + hoverBackgroundColor: gradientHover, + hoverBorderWidth: 2 + }] + }, + options: { + indexAxis: "y", + plugins: { + legend: { + display: false, + }, + tooltip: { + backgroundColor: "rgba(255, 255, 255, 0.95)", + titleColor: "#333", + titleFont: { weight: "normal", size: 15 }, + bodyFont: { weight: "normal", size: 16 }, + bodyColor: "rgb(179, 157, 219)", + padding: 12, + cornerRadius: 2, + borderColor: "rgba(0, 0, 0, 0.1)", + borderWidth: 1, + displayColors: false, + } + }, + responsive: true, + interaction: { + intersect: false, + mode: "index", + axis: "y" + }, + scales: { + x: { + grace:"5%", + beginAtZero: true, + ticks: { + maxTicksLimit: 6, + } + } + } + } + }); + + // reset the display: block style that chart.js applies automatically + ctx.style.display = ""; + }); +} + +// add data to the map +function feedMapData(period) { + const map = document.querySelector("svg.map"); + const paths = map.querySelectorAll("path"); + if (!map || !paths || !paths.length) return; + + let data = JSON.parse(map.dataset[period || "day"]); + if (!data) return; + + let max = data.sort((a, b) => a.value > b.value ? -1 : 1)[0]; + + if (!max) max = { value: 1 } + + data = data.reduce((a, c) => ({ ...a, [c.name]: c.value }), {}); + + for (let i = 0; i < paths.length; ++i) { + const id = paths[i].dataset.id; + const views = data[id] || 0; + paths[i].dataset.views = views; + const colorLevel = Math.ceil((views / max.value) * 6); + const classList = paths[i].classList; + for (let j = 1; j < 7; j++) { + paths[i].classList.remove(`color-${j}`); + } + paths[i].classList.add(`color-${colorLevel}`) + paths[i].dataset.views = views; + } +} + +// handle map tooltip hover +function mapTooltipHoverOver() { + const tooltip = document.querySelector("#map-tooltip"); + if (!tooltip) return; + if (!event.target.dataset.id) return mapTooltipHoverOut(); + if (!tooltip.classList.contains("active")) { + tooltip.classList.add("visible"); + } + tooltip.dataset.tooltip = `${event.target.ariaLabel}: ${event.target.dataset.views || 0}`; + const rect = event.target.getBoundingClientRect(); + tooltip.style.top = rect.top + (rect.height / 2) + "px"; + tooltip.style.left = rect.left + (rect.width / 2) + "px"; + event.target.classList.add("active"); +} +function mapTooltipHoverOut() { + const tooltip = document.querySelector("#map-tooltip"); + const map = document.querySelector("svg.map"); + const paths = map.querySelectorAll("path"); + if (!tooltip || !map) return; + tooltip.classList.remove("visible"); + for (let i = 0; i < paths.length; ++i) { + paths[i].classList.remove("active"); + } +} + +// create stats charts +function createCharts() { + if (Chart === undefined) { + setTimeout(function() { createCharts() }, 100); + return; + } + createViewsChart(); + createBrowsersChart(); + createReferrersChart(); + createOsChart(); + feedMapData(); +} \ No newline at end of file