Skip to content

Commit

Permalink
Merge pull request #1 from SamHillierDev/dev
Browse files Browse the repository at this point in the history
Further development
  • Loading branch information
SamHillierDev authored Dec 15, 2024
2 parents 15807ab + 166432f commit 14f691a
Show file tree
Hide file tree
Showing 7 changed files with 324 additions and 13 deletions.
18 changes: 15 additions & 3 deletions src/components/CountriesBarChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,23 @@ import BarChart from "./BarChart.vue";
interface DataItem {
countrycode: string;
product: string;
}
const props = defineProps<{
data: DataItem[];
selectedGame: string;
sortOrder?: "asc" | "desc";
}>();
const filteredData = computed(() => {
if (!props.selectedGame) return props.data;
return props.data.filter((item) => item.product === props.selectedGame);
});
const sortedData = computed(() => {
const fullData = sortData(
props.data,
filteredData.value,
(item) => item.countrycode,
props.sortOrder || "desc",
);
Expand All @@ -29,15 +36,20 @@ const sortedData = computed(() => {
dataset: top10Dataset.reverse(),
};
});
const chartTitle = computed(
() =>
`Top 10 Countries by Mentions${props.selectedGame ? ` - ${props.selectedGame}` : ""}`,
);
</script>

<template>
<div>
<h2 class="mb-6 text-2xl font-semibold">Most Mentions by Country</h2>
<h2 class="mb-6 text-2xl font-semibold">{{ chartTitle }}</h2>
<BarChart
:labels="sortedData.labels"
:dataset="sortedData.dataset"
chartTitle="Most Mentions by Country"
:chartTitle="chartTitle"
xAxisLabel="Countries"
yAxisLabel="Mentions"
/>
Expand Down
17 changes: 14 additions & 3 deletions src/components/CountriesTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,22 @@ import { countryCodeToName } from "../utils/constants";
interface DataItem {
countrycode: string;
product: string;
}
const props = defineProps<{ data: DataItem[] }>();
const props = defineProps<{
data: DataItem[];
selectedGame: string;
}>();
const filteredData = computed(() => {
if (!props.selectedGame) return props.data;
return props.data.filter((item) => item.product === props.selectedGame);
});
const groupedByCountry = computed(() => {
const { labels, dataset } = sortData(
props.data,
filteredData.value,
(item) => item.countrycode,
"desc",
);
Expand Down Expand Up @@ -41,7 +50,9 @@ const countryColumns = [

<template>
<div>
<h2 class="mb-6 text-2xl font-semibold">Most Mentions by Country</h2>
<h2 class="mb-6 text-2xl font-semibold">
Most Mentions by Country{{ selectedGame ? ` - ${selectedGame}` : "" }}
</h2>
<div class="max-h-96 overflow-y-auto rounded-md border border-gray-300 p-2">
<Table :columns="countryColumns" :rows="groupedByCountry" />
</div>
Expand Down
63 changes: 63 additions & 0 deletions src/components/GameSelector.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<script setup lang="ts">
import { ref, computed } from "vue";
interface Game {
product: string;
}
const props = defineProps<{ games: Game[] }>();
const emits = defineEmits<{
(event: "gameSelected", value: string): void;
}>();
const uniqueSortedGames = computed(() => {
const uniqueGames = Array.from(
new Map(props.games.map((game) => [game.product, game])).values(),
);
return uniqueGames.sort((a, b) => a.product.localeCompare(b.product));
});
const selectedGame = ref("");
const handleSelection = (event: Event) => {
selectedGame.value = (event.target as HTMLSelectElement).value;
emits("gameSelected", selectedGame.value);
};
const clearSelection = () => {
selectedGame.value = "";
emits("gameSelected", "");
};
</script>

<template>
<div>
<h2 class="mb-4 text-xl font-semibold">Select a Game</h2>
<div class="flex items-center gap-2">
<select
v-model="selectedGame"
@change="handleSelection"
class="w-full rounded border bg-blue-50 px-2 py-1 text-gray-900 dark:border-gray-600 dark:bg-slate-700 dark:text-gray-100"
>
<option value="" disabled class="text-gray-400 dark:text-gray-500">
Select a game
</option>
<option
v-for="game in uniqueSortedGames"
:key="game.product"
:value="game.product"
class="text-gray-900 dark:text-gray-100"
>
{{ game.product }}
</option>
</select>
<button
v-if="selectedGame"
@click="clearSelection"
class="cursor-pointer rounded bg-[#29377C] px-4 py-1 text-white transition hover:bg-[#4f5a99]"
>
Clear
</button>
</div>
</div>
</template>
4 changes: 2 additions & 2 deletions src/components/GamesBarChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ const sortedData = computed(() => {

<template>
<div>
<h2 class="mb-6 text-2xl font-semibold">Most Popular Games</h2>
<h2 class="mb-6 text-2xl font-semibold">Top 10 Games by Mentions</h2>
<BarChart
:labels="sortedData.labels"
:dataset="sortedData.dataset"
chartTitle="Most Popular Games"
chartTitle="Top 10 Games by Mentions"
xAxisLabel="Games"
yAxisLabel="Mentions"
/>
Expand Down
78 changes: 78 additions & 0 deletions src/components/GamesLineGraph.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<script setup lang="ts">
import { computed } from "vue";
import LineGraph from "./LineGraph.vue";
interface DataEntry {
product: string;
date: string;
}
const props = defineProps<{
data: DataEntry[];
selectedGame: string;
}>();
const monthsOf2024 = [
{ id: "2024-01", label: "Jan 24" },
{ id: "2024-02", label: "Feb 24" },
{ id: "2024-03", label: "Mar 24" },
{ id: "2024-04", label: "Apr 24" },
{ id: "2024-05", label: "May 24" },
{ id: "2024-06", label: "Jun 24" },
{ id: "2024-07", label: "Jul 24" },
{ id: "2024-08", label: "Aug 24" },
{ id: "2024-09", label: "Sep 24" },
{ id: "2024-10", label: "Oct 24" },
{ id: "2024-11", label: "Nov 24" },
{ id: "2024-12", label: "Dec 24" },
];
const chartData = computed(() => {
if (!props.selectedGame) {
return {
labels: monthsOf2024.map((m) => m.label),
dataset: new Array(12).fill(0),
};
}
const filteredData = props.data.filter(
(entry) => entry.product === props.selectedGame,
);
const mentionsByMonth = filteredData.reduce(
(acc, entry) => {
const month = new Date(entry.date).toISOString().slice(0, 7);
if (monthsOf2024.some((m) => m.id === month)) {
acc[month] = (acc[month] || 0) + 1;
}
return acc;
},
{} as Record<string, number>,
);
const dataset = monthsOf2024.map((month) => mentionsByMonth[month.id] || 0);
return {
labels: monthsOf2024.map((m) => m.label),
dataset,
};
});
const chartTitle = computed(
() =>
`Mentions in 2024${props.selectedGame ? ` - ${props.selectedGame}` : ""}`,
);
</script>

<template>
<div>
<h2 class="mb-6 text-2xl font-semibold">{{ chartTitle }}</h2>
<LineGraph
:labels="chartData.labels"
:dataset="chartData.dataset"
:chartTitle="chartTitle"
xAxisLabel="Month"
yAxisLabel="Mentions"
/>
</div>
</template>
103 changes: 103 additions & 0 deletions src/components/LineGraph.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<script setup lang="ts">
import { ref, watch, onMounted } from "vue";
import {
Chart,
LineController,
LineElement,
PointElement,
LinearScale,
Title,
CategoryScale,
Tooltip,
Legend,
} from "chart.js";
import type { ChartData, ChartConfiguration } from "chart.js";
Chart.register(
LineController,
LineElement,
PointElement,
LinearScale,
Title,
CategoryScale,
Tooltip,
Legend,
);
const props = defineProps<{
labels: string[];
dataset: number[];
chartTitle?: string;
xAxisLabel?: string;
yAxisLabel?: string;
}>();
const chartCanvas = ref<HTMLCanvasElement | null>(null);
let chartInstance: Chart<"line", number[], string> | null = null;
const updateChart = () => {
if (!chartCanvas.value) return;
if (chartInstance) {
chartInstance.destroy();
}
const data: ChartData<"line", number[], string> = {
labels: props.labels,
datasets: [
{
label: "Mentions",
data: props.dataset,
borderColor: "#34479b",
backgroundColor: "rgba(41, 55, 124, 0.5)",
tension: 0.3,
},
],
};
const config: ChartConfiguration<"line", number[], string> = {
type: "line",
data,
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
title: {
display: true,
text: props.chartTitle || "Line Chart",
},
},
scales: {
x: {
title: {
display: true,
text: props.xAxisLabel || "X-Axis",
},
},
y: {
title: {
display: true,
text: props.yAxisLabel || "Y-Axis",
},
beginAtZero: true,
},
},
animation: {
duration: 1000,
easing: "easeInOutQuad",
},
},
};
chartInstance = new Chart(chartCanvas.value, config);
};
onMounted(updateChart);
watch(() => [props.labels, props.dataset], updateChart);
</script>

<template>
<div class="h-100 w-full">
<canvas ref="chartCanvas"></canvas>
</div>
</template>
Loading

0 comments on commit 14f691a

Please sign in to comment.