Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/app/static/js/tailwindconfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ tailwind.config = {
colors: {
dark: {
bg: '#121212',
fg: '#181818',
fg: '#191919',
primary: '#E0E0E0',
secondary: '#B0B0B0',
border: '#343434',
Expand Down
198 changes: 170 additions & 28 deletions src/app/static/js/visualise.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,175 @@
document.addEventListener("DOMContentLoaded", function() {
fetch('/chart/unit_data')
.then(res => res.json())
.then(data => {
new Chart(document.getElementById('unit_data'), {
type: 'bar',
data: {
labels: data.labels,
datasets: [
{
label: 'Friend Picks',
data: data.friend_count,
backgroundColor: 'rgba(29, 71, 225, 1)'
},
{
label: 'Total Picks',
data: data.total_count,
backgroundColor: 'rgba(192, 75, 75, 1)'
}
]
document.addEventListener("DOMContentLoaded", () => {
const friendBtn = document.getElementById('friendPicks');
const totalBtn = document.getElementById('totalPicks');
Chart.register(ChartDataLabels);
const ctx = document.getElementById('unit_data').getContext('2d');
let currentType = 'friend';
let chart;

//heatmap colors
const palette = [
'#ffa600',
'#ff7c43',
'#f95d6a',
'#d45087',
'#a05195',
'#665191',
'#2f4b7c',
'#003f5c',
'#2f4b7c',
'#665191',
'#a05195',
'#d45087',
'#f95d6a',
'#ff7c43'
];

function isDarkMode() { //checks if any of the current elements contain the dark class
return document.documentElement.classList.contains('dark');
}

function interpolateColor(startColor, endColor, factor) {
// take the r g and b values and turn them into ints
const start = startColor.match(/\w\w/g).map(x => parseInt(x, 16));
const end = endColor.match(/\w\w/g).map(x => parseInt(x, 16));

// interpolate the ints
const result = start.map((startValue, i) =>
Math.round(startValue + factor * (end[i] - startValue))
);

// convert back to hex format
return '#' + result.map(v => v.toString(16).padStart(2, '0')).join('');
}

function buildOrUpdate(data) {
// filter out data with 0 entries
const filteredData = {
labels: [],
friend_count: [],
total_count: []
};

const values = currentType === 'friend' ? data.friend_count : data.total_count;

// Create filtered array
data.labels.forEach((label, i) => {
if (values[i] !== 0) {
filteredData.labels.push(label);
filteredData.friend_count.push(data.friend_count[i]);
filteredData.total_count.push(data.total_count[i]);
}
});

const labels = filteredData.labels;
const filteredValues = currentType === 'friend' ? filteredData.friend_count : filteredData.total_count;
const dark = isDarkMode();

// give all of the bars a nice color using the pallete and the interpolation function
const colors = labels.map((_, i) => {
const totalSteps = labels.length - 1;
const t = i / totalSteps;
const scaledT = t * (palette.length - 1);
const lowerIndex = Math.floor(scaledT);
const upperIndex = Math.min(lowerIndex + 1, palette.length - 1);
const localT = scaledT - lowerIndex;
return interpolateColor(palette[lowerIndex], palette[upperIndex], localT);
});

ctx.canvas.height = labels.length * 50; // the labels are too big??

const dataset = {
label: currentType === 'friend' ? 'Friend Picks' : 'Total Picks',
data: filteredValues,
backgroundColor: colors,
// adjust these to mess around with the bar thicnkess and padding
borderRadius: 6,
maxBarThickness: 30,
barPercentage: 1.2,
categoryPercentage: 0.6
};
// darkmode variants TODO: have the graph redraw when the user togles between the two modes
const gridColor = dark ? 'rgba(255,255,255,0.05)' : 'rgba(229,231,235,0.3)';
const fontColor = dark ? '#D1D5DB' : '#6B7280';
const labelColor = dark ? '#F9FAFB' : '#111827';

const chartOptions = {
responsive: true,
maintainAspectRatio: false,
indexAxis: 'y',
scales: {
x: {
beginAtZero: true,
grid: { color: gridColor },
ticks: {
font: { family: 'Inter, sans-serif', size: 12 },
color: fontColor
}
},
options: {
indexAxis: 'y',
scales: {
x: {
beginAtZero: true
}
y: {
ticks: {
padding: 12,
font: { family: 'Inter, sans-serif', size: 13, weight: '600' },
color: labelColor
},
grid: { display: false }
}
},
plugins: {
legend: { display: false },
tooltip: {
backgroundColor: dark ? '#111827' : '#1F2937',
titleColor: dark ? '#F9FAFB' : '#F9FAFB',
bodyColor: dark ? '#D1D5DB' : '#D1D5DB',
cornerRadius: 6,
padding: 10,
callbacks: {
label: ctx => `${ctx.dataset.label}: ${ctx.parsed.x}`
}
},
datalabels: {
anchor: 'start',
align: 'end',
color: '#F9FAFB',
font: {
family: 'Inter, sans-serif',
size: 12,
weight: '600'
},
formatter: value => value
}
}
};

if (chart) {
chart.data.labels = labels;
chart.data.datasets = [dataset];
chart.options = chartOptions;
chart.update();
} else {
chart = new Chart(ctx, {
type: 'bar',
data: { labels, datasets: [dataset] },
options: chartOptions
});
});
});
}
}

function fetchData() {
fetch('/chart/unit_data')
.then(res => res.json())
.then(buildOrUpdate);
}

friendBtn.addEventListener('click', () => {
currentType = 'friend';
fetchData();
});

totalBtn.addEventListener('click', () => {
currentType = 'total';
fetchData();
});

fetchData();
});
2 changes: 1 addition & 1 deletion src/app/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
<!-- TailwindCSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0"></script>
<script src="{{ url_for('static', filename='js/tailwindconfig.js') }}" defer></script>
<script src="{{ url_for('static', filename='js/darkmode.js') }}" defer></script>
<link rel="stylesheet" href="{{ url_for('static', filename='css/tailwindglobals.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/alert.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/dashboard.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/discover.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/dropdown.css') }}">
Expand Down
24 changes: 21 additions & 3 deletions src/app/templates/visualise.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,26 @@
{% block title %}Visualise{% endblock %}

{% block content %}
<div class="flex w-full gap-8 items-start" style="max-height: 80vh;">
<canvas id="unit_data"></canvas>
<div class="flex flex-col w-full gap-6 items-start p-4 bg-white rounded-2xl shadow-md dark:bg-dark-fg">
<!-- buttons row -->
<div class="flex space-x-3 mb-4">
<button id="friendPicks" class="py-2 px-5 rounded-full font-medium transition
bg-indigo-100 hover:bg-indigo-200 text-indigo-800 dark:bg-indigo-800 dark:hover:bg-indigo-700 dark:text-white
focus:outline-none focus:ring-2 focus:ring-indigo-400">

Friend Picks
</button>
<button id="totalPicks" class="py-2 px-5 rounded-full font-medium transition
bg-slate-100 hover:bg-slate-200 text-slate-800 dark:bg-slate-800 dark:hover:bg-slate-700 dark:text-white
focus:outline-none focus:ring-2 focus:ring-slate-400">
Total Picks
</button>
</div>


<div class="w-full relative">
<canvas id="unit_data" class="w-full dark:bg-dark-bg"></canvas>
</div>
</div>
<script src="{{ url_for('static', filename='js/visualise.js') }}"></script>
{% endblock %}
{% endblock %}