-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1678214
commit 87e1009
Showing
7 changed files
with
332 additions
and
91 deletions.
There are no files selected for viewing
122 changes: 122 additions & 0 deletions
122
src/lib/ui/time/supabase/analytics/piechart/base-pie-chart.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import * as echarts from "echarts/core"; | ||
import { TooltipComponent, LegendComponent, GridComponent } from "echarts/components"; | ||
import { CanvasRenderer } from "echarts/renderers"; | ||
import { PieChart, BarChart } from "echarts/charts"; | ||
import { LabelLayout } from "echarts/features"; | ||
import type { Course, Lo } from "$lib/services/models/lo-types"; | ||
import { backgroundPattern, textureBackground } from "../../charts/tutors-charts-background-url"; | ||
import type { Session } from "@supabase/supabase-js"; | ||
import type { DrilledDownData } from "$lib/services/types/supabase-metrics"; | ||
|
||
echarts.use([TooltipComponent, LegendComponent, PieChart, BarChart, GridComponent, CanvasRenderer, LabelLayout]); | ||
|
||
const bgTexture = textureBackground; | ||
const bgPatternSrc = backgroundPattern; | ||
|
||
const piePatternImg = new Image(); | ||
piePatternImg.src = bgTexture; | ||
const bgPatternImg = new Image(); | ||
bgPatternImg.src = bgPatternSrc; | ||
|
||
export class BasePieChart<T> { | ||
myChart: any; | ||
course: Course; | ||
session: Session; | ||
totalTimesMap: Map<string, DrilledDownData[]>; | ||
titleTimesMap: Map<string, T>; | ||
|
||
constructor(course: Course, session: Session) { | ||
this.myChart = null; | ||
this.course = course; | ||
this.session = session; | ||
this.titleTimesMap = new Map(); | ||
this.totalTimesMap = new Map(); | ||
} | ||
|
||
initChart() { | ||
if (!this.myChart) { | ||
// Create a new chart instance if it doesn't exist | ||
this.myChart = echarts.init(document.getElementById("chart")); | ||
} else { | ||
// Clear the previous chart to prevent aggregation issues | ||
this.myChart.clear(); | ||
} | ||
} | ||
|
||
handlePieClick() { | ||
if (this.myChart !== null) { | ||
// Remove any existing click listeners to prevent multiple handlers | ||
this.myChart.off("click"); | ||
this.myChart.on("click", (params: { seriesName: string; name: string }) => { | ||
if (params.seriesName === "Inner Pie") { | ||
const outerPieData: DrilledDownData[] = []; // Reset outerPieData array | ||
|
||
// Find the corresponding data for the clicked inner pie slice | ||
this.totalTimesMap.forEach((steps, title) => { | ||
if (title === params.name) { | ||
steps.forEach((step) => { | ||
if (step.value !== 0) { | ||
outerPieData.push({ value: step.value, name: step.name, type: step.type }); | ||
} | ||
}); | ||
} | ||
}); | ||
this.populateOuterPieData(outerPieData); | ||
} | ||
}); | ||
} | ||
} | ||
|
||
populateOuterPieData(outerPieData: DrilledDownData[]) { | ||
// Update the data for the outer pie chart | ||
const element = document.getElementById("chart"); | ||
if (element) { | ||
const chartInstance = echarts.getInstanceByDom(element); | ||
if (chartInstance) { | ||
chartInstance.setOption({ | ||
series: [ | ||
{ | ||
name: "Outer Pie", | ||
data: outerPieData | ||
} | ||
] | ||
}); | ||
} | ||
} | ||
} | ||
|
||
updateMaps(lo: Lo, timeActive: number, getTitle: (lo: Lo) => string) { | ||
const title = getTitle(lo); | ||
const loTitle = lo.title; | ||
// Add timeActive to the total time for the title | ||
if (this.titleTimesMap.has(title)) { | ||
this.titleTimesMap.set(title, ((this.titleTimesMap.get(title)! as number) + timeActive) as unknown as T); | ||
} else { | ||
this.titleTimesMap.set(title, timeActive as unknown as T); | ||
} | ||
|
||
if (!this.totalTimesMap.has(title)) { | ||
this.totalTimesMap.set(title, []); | ||
} | ||
|
||
const existingEntries = this.totalTimesMap.get(title)!; | ||
const existingEntry = existingEntries.find((entry) => entry.name === loTitle); | ||
|
||
if (existingEntry) { | ||
existingEntry.value += timeActive; | ||
} else { | ||
existingEntries.push({ value: timeActive, name: loTitle, type: lo.type }); | ||
} | ||
} | ||
|
||
renderChart() { | ||
this.initChart(); | ||
this.handlePieClick(); | ||
} | ||
|
||
setOption(option: any) { | ||
if (this.myChart) { | ||
this.myChart.setOption(option); | ||
} | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
src/lib/ui/time/supabase/analytics/piechart/lab-pie-chart.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import * as echarts from "echarts/core"; | ||
import { TooltipComponent, LegendComponent, GridComponent } from "echarts/components"; | ||
import { CanvasRenderer } from "echarts/renderers"; | ||
import { PieChart, BarChart } from "echarts/charts"; | ||
import { LabelLayout } from "echarts/features"; | ||
import type { Course } from "$lib/services/models/lo-types"; | ||
import { backgroundPattern, textureBackground } from "../../charts/tutors-charts-background-url"; | ||
import type { Session } from "@supabase/supabase-js"; | ||
import { filterByType } from "$lib/services/models/lo-utils"; | ||
import { piechart } from "../../charts/piechart"; | ||
import type { DrilledDownData } from "$lib/services/types/supabase-metrics"; | ||
import { BasePieChart } from "./base-pie-chart"; | ||
echarts.use([TooltipComponent, LegendComponent, PieChart, BarChart, GridComponent, CanvasRenderer, LabelLayout]); | ||
|
||
const bgTexture = textureBackground; | ||
const bgPatternSrc = backgroundPattern; | ||
|
||
const piePatternImg = new Image(); | ||
piePatternImg.src = bgTexture; | ||
const bgPatternImg = new Image(); | ||
bgPatternImg.src = bgPatternSrc; | ||
|
||
export class LabPieChart extends BasePieChart<number> { | ||
labs: string[]; | ||
|
||
constructor(course: Course, session: Session) { | ||
super(course, session); | ||
this.labs = []; | ||
} | ||
|
||
renderChart() { | ||
super.renderChart(); // Initialize and set up click handlers | ||
|
||
this.titleTimesMap.clear(); | ||
this.totalTimesMap.clear(); | ||
|
||
let labs = filterByType(this.course.los, "lab"); | ||
let steps = filterByType(this.course.los, "step"); | ||
|
||
const allLabSteps = [...labs, ...steps]; | ||
|
||
allLabSteps.forEach((lo) => { | ||
const timeActive = lo.learningRecords?.get(this.session.user.user_metadata.user_name)?.timeActive || 0; | ||
this.updateMaps(lo, timeActive, (lo) => (lo.type === "lab" ? lo.title : lo.parentLo!.title)); | ||
}); | ||
|
||
const singleUserInnerData = Array.from(this.titleTimesMap.entries()).map(([title, timeActive]) => ({ | ||
name: title, | ||
value: timeActive | ||
})); | ||
|
||
const singleUserOuterData: DrilledDownData[] = []; | ||
this.totalTimesMap.forEach((steps, title) => { | ||
steps.forEach((step) => { | ||
if (step.type !== undefined) { | ||
singleUserOuterData.push({ | ||
name: step.name, | ||
value: step.value, | ||
type: step.type | ||
}); | ||
} | ||
}); | ||
}); | ||
|
||
const option = piechart(bgPatternImg, [], singleUserInnerData, singleUserOuterData); | ||
super.setOption(option); | ||
} | ||
} |
88 changes: 88 additions & 0 deletions
88
src/lib/ui/time/supabase/analytics/piechart/topic-pie-chart.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import * as echarts from "echarts/core"; | ||
import { TooltipComponent, LegendComponent, GridComponent } from "echarts/components"; | ||
import { CanvasRenderer } from "echarts/renderers"; | ||
import { PieChart, BarChart } from "echarts/charts"; | ||
import { LabelLayout } from "echarts/features"; | ||
import type { Course, Lo } from "$lib/services/models/lo-types"; | ||
import { backgroundPattern, textureBackground } from "../../charts/tutors-charts-background-url"; | ||
import type { Session } from "@supabase/supabase-js"; | ||
import type { DrilledDownData } from "$lib/services/types/supabase-metrics"; | ||
import { BasePieChart } from "./base-pie-chart"; | ||
import { piechart } from "../../charts/piechart"; | ||
import { getCompositeValues, getSimpleTypesValues } from "$lib/services/utils/supabase-utils"; | ||
|
||
|
||
echarts.use([TooltipComponent, LegendComponent, PieChart, BarChart, GridComponent, CanvasRenderer, LabelLayout]); | ||
|
||
const bgTexture = textureBackground; | ||
const bgPatternSrc = backgroundPattern; | ||
|
||
const piePatternImg = new Image(); | ||
piePatternImg.src = bgTexture; | ||
const bgPatternImg = new Image(); | ||
bgPatternImg.src = bgPatternSrc; | ||
|
||
export class TopicPieChart extends BasePieChart<number> { | ||
topics: string[]; | ||
userIds: string[]; | ||
multipleUsers: boolean; | ||
|
||
constructor(course: Course, session: Session, userIds: string[], multipleUsers: boolean) { | ||
super(course, session); | ||
this.topics = []; | ||
this.userIds = userIds; | ||
this.multipleUsers = multipleUsers; | ||
} | ||
|
||
getOuterPieDataForMultipleUsers(): DrilledDownData[] { | ||
const outerPieData: { value: number; name: string }[] = []; | ||
this.titleTimesMap.forEach((value, key) => { | ||
const existing = outerPieData.find((data) => data.name === key); | ||
if (existing) { | ||
existing.value += value; | ||
} else { | ||
outerPieData.push({ value, name: key }); | ||
} | ||
}); | ||
|
||
return outerPieData; | ||
} | ||
|
||
renderChart() { | ||
super.renderChart(); // Initialize and set up click handlers | ||
|
||
const allComposites = getCompositeValues(this.course.los); | ||
const allSimpleTypes = getSimpleTypesValues(this.course.los); | ||
const allTypes = [...allComposites, ...allSimpleTypes]; | ||
|
||
allTypes.forEach((lo) => { | ||
if (this.userIds && this.userIds.length > 0) { | ||
this.userIds.forEach((userId) => { | ||
const timeActive = lo.learningRecords?.get(userId)?.timeActive || 0; | ||
this.updateMaps(lo, timeActive, (lo) => | ||
lo.parentTopic?.type === "topic" ? lo.parentTopic.title : lo.parentLo?.parentTopic?.type === "topic" ? lo.parentLo?.parentTopic?.title : lo.title | ||
); | ||
}); | ||
} else { | ||
const timeActive = lo.learningRecords?.get(this.session.user.user_metadata.user_name)?.timeActive || 0; | ||
this.updateMaps(lo, timeActive, (lo) => | ||
lo.parentTopic?.type === "topic" ? lo.parentTopic.title : lo.parentLo?.parentTopic?.type === "topic" ? lo.parentLo?.parentTopic?.title : lo.title | ||
); | ||
} | ||
}); | ||
|
||
if (this.multipleUsers === false) { | ||
const singleUserInnerData = Array.from(this.titleTimesMap.entries()).map(([title, timeActive]) => ({ | ||
name: title, | ||
value: timeActive | ||
})); | ||
|
||
const option = piechart(bgPatternImg, [], singleUserInnerData, []); | ||
super.setOption(option); | ||
} else { | ||
const allUsersTopicActivity = this.getOuterPieDataForMultipleUsers(); | ||
const option = piechart(bgPatternImg, allUsersTopicActivity, [], []); | ||
super.setOption(option); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<script lang="ts"> | ||
import { onMount, onDestroy } from "svelte"; | ||
import type { Course } from "$lib/services/models/lo-types"; | ||
import { LabPieChart } from "../analytics/piechart/lab-pie-chart"; | ||
import { TopicPieChart } from "../analytics/piechart/topic-pie-chart"; | ||
import type { Session } from "@supabase/supabase-js"; | ||
export let chartType: 'LabPieChart' | 'TopicPieChart'; | ||
export let course: Course; | ||
export let session: Session; | ||
export let userIds: string[] = []; | ||
export let multipleUsers: boolean = false; | ||
let chartInstance: LabPieChart | TopicPieChart | null = null; | ||
onMount(() => { | ||
if (chartType === 'LabPieChart') { | ||
chartInstance = new LabPieChart(course, session); | ||
} else if (chartType === 'TopicPieChart') { | ||
chartInstance = new TopicPieChart(course, session, userIds, multipleUsers); | ||
} | ||
renderChart(); | ||
}); | ||
const renderChart = () => { | ||
if (chartInstance) { | ||
chartInstance.renderChart(); | ||
} | ||
}; | ||
onDestroy(() => { | ||
if (chartInstance) { | ||
chartInstance = null; | ||
} | ||
}); | ||
window.addEventListener("focus", renderChart); | ||
</script> | ||
|
||
<div class="h-screen"> | ||
<div id="chart" style="height: 100%; width: 100%;"></div> | ||
</div> |
32 changes: 4 additions & 28 deletions
32
src/lib/ui/time/supabase/views/InstructorTopicViewPieChart.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,12 @@ | ||
<script lang="ts"> | ||
import { onMount, onDestroy } from "svelte"; | ||
import type { Course, Topic } from "$lib/services/models/lo-types"; | ||
import { TopicPieChart } from "../analytics/topic-pie"; | ||
import type { Session } from "@supabase/supabase-js"; | ||
import type { Course } from "$lib/services/models/lo-types"; | ||
import type { Session } from "@supabase/supabase-js"; | ||
import Chart from './Chart.svelte'; | ||
export let course: Course; | ||
export let session: Session; | ||
export let userIds: string[]; | ||
const multipleUsers = true; | ||
let topicPieChart: TopicPieChart | null; | ||
onMount(() => { | ||
topicPieChart = new TopicPieChart(course, session, userIds, multipleUsers); | ||
renderChart(); | ||
}); | ||
const renderChart = () => { | ||
if (topicPieChart) { | ||
topicPieChart.renderChart(userIds); | ||
} | ||
}; | ||
onDestroy(() => { | ||
if (topicPieChart) { | ||
topicPieChart = null; | ||
} | ||
}); | ||
window.addEventListener("focus", renderChart); | ||
</script> | ||
|
||
<div class="h-screen"> | ||
<div id={"chart"} style="height: 100%; width:100%"></div> | ||
</div> | ||
<Chart chartType="TopicPieChart" {course} {session} {userIds} {multipleUsers} /> |
Oops, something went wrong.