Commit 3a6cef04 authored by Almouhannad Hafez's avatar Almouhannad Hafez

Use Chart factory

parent 88f5d2aa
......@@ -9,7 +9,16 @@
<body>
<div id="scatterplot-container">
<div id="chart-select">
<label for="chart">Select chart:</label>
<select id="charts-select-list" name="charts-select-list">
<option value="" disabled selected></option>
<option value="Scatterplot">Scatterplot</option>
<option value="LineChart">Line chart</option>
</select>
</div>
<div id="Scatterplot-container" style="display: none;">
<div id="scatterplot-tooltip"></div>
<svg id="scatterplot"></svg>
<ul class="legend" id="scatterplot-legend">
......@@ -20,7 +29,7 @@
</ul>
</div>
<div id="line-chart-container">
<div id="LineChart-container" style="display: none;">
<div id="line-chart-tooltip"></div>
<div class="heading">
<p class="title">S&P 500 Index</p>
......
......@@ -8,35 +8,72 @@ body {
background: #f7f7f7;
}
#chart-select {
margin-left: 2em;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
padding: 20px;
width: 300px;
text-align: center;
}
label {
font-size: 1.2em;
margin-bottom: 10px;
display: block;
color: #333;
}
select {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
font-size: 1em;
color: #555;
background-color: #f9f9f9;
transition: border-color 0.3s;
}
select:focus {
border-color: #007BFF;
outline: none;
background-color: #fff;
}
option {
padding: 10px;
}
/* #region scatterplot*/
#scatterplot-container {
#Scatterplot-container {
padding: 1em;
}
#scatterplot-container .source {
#Scatterplot-container .source {
font-size: 10px;
color: #888;
}
#scatterplot-container .source a {
#Scatterplot-container .source a {
color: #888;
}
/* Axes */
#scatterplot-container .axis line {
#Scatterplot-container .axis line {
fill: none;
stroke: #ddd;
shape-rendering: crispEdges;
}
#scatterplot-container .axis text {
#Scatterplot-container .axis text {
font-size: 13px;
fill: #6b6b6b;
}
#scatterplot-container .axis-title {
#Scatterplot-container .axis-title {
font-size: 13px;
fill: #888;
}
......@@ -45,50 +82,50 @@ body {
stroke: #b1b1b1;
}
#scatterplot-container .y-axis .tick:first-child text {
#Scatterplot-container .y-axis .tick:first-child text {
display: none;
}
#scatterplot-container .x-axis .tick:first-child line {
#Scatterplot-container .x-axis .tick:first-child line {
display: none;
}
#scatterplot-container .axis path {
#Scatterplot-container .axis path {
display: none;
}
/* Legend */
#scatterplot-container .legend {
#Scatterplot-container .legend {
margin: 20px 0;
list-style: none;
padding: 0;
}
#scatterplot-container .legend li {
#Scatterplot-container .legend li {
display: inline-block;
margin: 0 20px 0 0;
}
#scatterplot-container .legend-e {
#Scatterplot-container .legend-e {
width: 12px;
height: 12px;
margin-right: 3px;
display: inline-block;
}
#scatterplot-container .legend-e.easy {
#Scatterplot-container .legend-e.easy {
background: #d3eecd;
}
#scatterplot-container .legend-e.intermediate {
#Scatterplot-container .legend-e.intermediate {
background: #7bc77e;
}
#scatterplot-container .legend-e.difficult {
#Scatterplot-container .legend-e.difficult {
background: #2a8d46;
}
#scatterplot-container p {
#Scatterplot-container p {
font-weight: 900;
color: #2a8d46;
}
......@@ -117,28 +154,28 @@ body {
/* #region Area chart */
#line-chart-container .area {
#LineChart-container .area {
fill: #e9eff5;
position: relative;
}
#line-chart-container .line {
#LineChart-container .line {
fill: none;
stroke: #537591;
stroke-width: 2.5px;
}
#line-chart-container .title {
#LineChart-container .title {
font-weight: 900;
font-size: 40px;
}
#line-chart-container .select-text {
#LineChart-container .select-text {
font-weight: 900;
margin-right: 0.5em;
}
#line-chart-container .heading {
#LineChart-container .heading {
margin-left: 3em;
}
......
import { Chart } from "./chart";
import { ChartConfiguration } from "./chartConfiguration";
import { ChartNames } from "./ChartsNames";
import { LineChart } from "./lineChart";
import { Scatterplot } from "./scatter";
export class ChartFactory {
private static chartMap: Map<string, { instance: Chart; datasetName: string }> = new Map();
private static scatterPlot: Chart = new Scatterplot(new ChartConfiguration("#scatterplot"));
private static lineChart: Chart = new LineChart(new ChartConfiguration("#line-chart"));
static {
this.chartMap.set(ChartNames.SCATTER, { instance: this.scatterPlot, datasetName: "/data/vancouver_trails.csv" });
this.chartMap.set(ChartNames.LINE_CHART, { instance: this.lineChart, datasetName: "/data/sp_500_index.csv" });
}
static createChart(chartName: string): { instance: Chart; datasetName: string } {
const chartInstance = this.chartMap.get(chartName);
if (chartInstance) {
return chartInstance;
}
else throw new Error("No such chart");
}
}
export class ChartNames {
static readonly SCATTER = 'Scatterplot';
static readonly LINE_CHART = 'LineChart';
static readonly CHARTS = [this.SCATTER, this.LINE_CHART];
}
\ No newline at end of file
......@@ -156,6 +156,13 @@ export class LineChart extends Chart {
public updateVis(): void {
const vis = this;
const dateParser = d3.timeParse("%Y-%m-%d");
vis.data.forEach((d: any) => {
if (typeof (d.date) == "string")
d.date = dateParser(d.date);
d.close = +d.close;
});
// Specificy accessor functions
vis.xValue = (d: any) => d.date;
vis.yValue = (d: any) => d.close;
......
import { ChartConfiguration } from './chartConfiguration';
import { LineChart } from './lineChart';
import { Scatterplot } from './scatter';
import { Chart } from './chart';
import { ChartFactory } from './ChartFactory';
import { ChartNames } from './ChartsNames';
import '/src/css/style.css';
import * as d3 from 'd3';
const selectedDifficulties: string[] = [];
let data: any[] = [];
const scatterplot = new Scatterplot(new ChartConfiguration("#scatterplot"));
let chart: Chart;
d3.select("#charts-select-list")
.on("change", function () {
let selectedChart: string = d3.select(this).property('value');
let chartInstance = ChartFactory.createChart(selectedChart);
chart = chartInstance.instance;
for (const chartName of ChartNames.CHARTS) {
d3.select(`#${chartName}-container`).style("display", "none");
}
d3.select(`#${selectedChart}-container`).style("display", "block");
/**
* Load data from CSV file
*/
d3.csv(chartInstance.datasetName)
.then(inputData => {
data = inputData;
// Initialize chart
chart.data = inputData;
// Show chart
chart.updateVis();
})
.catch(error => console.error(error));
});
////////////////////// Events handlers //////////////////////
// #region Scatterplot
const selectedDifficulties: string[] = [];
function handleLevelSelectionEvent(element: any, difficulty: string) {
const index = selectedDifficulties.indexOf(difficulty);
if (index > -1) {
......@@ -20,8 +48,8 @@ function handleLevelSelectionEvent(element: any, difficulty: string) {
d3.select(element).style("opacity", 0.5);
}
const filteredData = data.filter(item => !selectedDifficulties.includes(item.difficulty));
scatterplot.data = filteredData;
scatterplot.updateVis();
chart.data = filteredData;
chart.updateVis();
}
const difficulties = ["Easy", "Intermediate", "Difficult"]
// Add click event listeners for each difficulty level
......@@ -32,52 +60,17 @@ for (const level of difficulties) {
handleLevelSelectionEvent(this, level);
});
}
/**
* Load data from CSV file asynchronously and render scatter plot
*/
d3.csv('/data/vancouver_trails.csv')
.then(inputData => {
// Convert strings to numbers
inputData.forEach((d: any) => {
d.time = +d.time;
d.distance = +d.distance;
});
data = inputData;
// Initialize chart
scatterplot.data = inputData;
// Show chart
scatterplot.updateVis();
})
.catch(error => console.error(error));
// #endregion
/**
* Load data from CSV file asynchronously and render scatter plot
*/
const lineChart = new LineChart(new ChartConfiguration("#line-chart"));
let lineChartData: any[];
// #region LineChart
d3.select('#line-chart-year-input')
.on('input', function () {
// Get the current value of the input
let value = d3.select(this).property('value');
value = +value;
console.log(lineChartData[0].date);
const lineChartFilteredData = lineChartData.filter(item => item.date.getFullYear() >= value);
lineChart.data = lineChartFilteredData;
lineChart.updateVis();
});
d3.csv('/data/sp_500_index.csv')
.then(inputData => {
const dateParser = d3.timeParse("%Y-%m-%d");
inputData.forEach((d: any) => {
d.date = dateParser(d.date);
d.close = +d.close;
const lineChartFilteredData = data.filter(item => item.date.getFullYear() >= value);
chart.data = lineChartFilteredData;
chart.updateVis();
});
// #endregion
lineChartData = inputData;
lineChart.data = inputData;
lineChart.updateVis();
})
.catch(error => console.error(error));
......@@ -83,6 +83,10 @@ export class Scatterplot extends Chart {
public updateVis(): void {
let vis = this;
vis.data.forEach((d: any) => {
d.time = +d.time;
d.distance = +d.distance;
});
// Specificy accessor functions
vis.colorValue = d => d.difficulty;
vis.xValue = d => d.time;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment