diff --git a/src/routes/stocks/[tickerID]/forecast/+page.svelte b/src/routes/stocks/[tickerID]/forecast/+page.svelte
index 1f42fd35..41d60b1c 100644
--- a/src/routes/stocks/[tickerID]/forecast/+page.svelte
+++ b/src/routes/stocks/[tickerID]/forecast/+page.svelte
@@ -12,24 +12,11 @@
} from "$lib/utils";
import highcharts from "$lib/highcharts.ts";
- import { Chart } from "svelte-echarts";
- import { init, use } from "echarts/core";
- import { LineChart, BarChart, GaugeChart } from "echarts/charts";
- import { GridComponent, TooltipComponent } from "echarts/components";
- import { CanvasRenderer } from "echarts/renderers";
import { goto } from "$app/navigation";
import SEO from "$lib/components/SEO.svelte";
export let data;
- use([
- LineChart,
- GaugeChart,
- BarChart,
- GridComponent,
- TooltipComponent,
- CanvasRenderer,
- ]);
let index = 0;
let changeRevenue = 0;
@@ -103,7 +90,7 @@
categories = ["Strong Buy", "Buy", "Hold", "Sell", "Strong Sell"];
}
- optionsData = getPlotOptions() || null;
+ optionsBarChart = getPlotOptions() || null;
optionsPieChart = getPieChart() || null;
config = getPriceForecastChart() || null;
}
@@ -151,88 +138,113 @@
}
};
- function getPlotOptions() {
+ function getBarChart() {
if (!rawAnalystList || rawAnalystList.length === 0) {
return null;
}
- // Define categories in the exact order you specified
- const categories = ["Strong Sell", "Sell", "Hold", "Buy", "Strong Buy"];
- const colors = ["#9E190A", "#D9220E", "#f5b700", "#31B800", "#008A00"];
+ const categories = ["Strong Buy", "Buy", "Hold", "Sell", "Strong Sell"];
+ const colors = ["#008A00", "#31B800", "#F5B700", "#D9220E", "#9E190A"];
- // Create a consistent mapping for data
- const formattedData = rawAnalystList?.map((item) =>
+ // Step 1: Store original values
+ const formattedData = rawAnalystList.map((item) =>
categories.map((cat) => item[cat] || 0),
);
- // Normalize data to percentages
+ // Step 2: Create normalized data for visualization
const normalizedData = formattedData.map((row) => {
const total = row.reduce((sum, val) => sum + val, 0);
return row.map((val) => (total > 0 ? (val / total) * 100 : 0));
});
- // Calculate total percentage for each category across all dates
- const totalData = [];
- for (let i = 0; i < categories.length; ++i) {
- let sum = 0;
- for (let j = 0; j < normalizedData.length; ++j) {
- sum += normalizedData[j][i];
- }
- totalData.push(sum / normalizedData.length);
- }
-
- // Define series based on categories with color mapping
+ // Step 3: Include original values in data points
const series = categories.map((name, idx) => ({
- name,
- type: "bar",
- stack: "total",
- barWidth: "60%",
- data: normalizedData.map((row) => row[idx]),
- itemStyle: {
- color: colors[idx],
- },
+ name: name,
+ data: normalizedData?.map((row, dataIndex) => ({
+ y: formattedData[dataIndex][idx], // Normalized percentage for chart
+ originalValue: formattedData[dataIndex][idx], // Original value for tooltip
+ })),
+ color: colors[idx],
+ borderColor: colors[idx],
+ borderRadius: "1px",
}));
- // Define chart option
- const option = {
- grid: {
- left: "2%",
- right: "2%",
- bottom: "10%",
- top: "5%",
- containLabel: true,
- },
+ const xCategories = rawAnalystList.map((item) => {
+ const dateParts = item?.date?.split("-");
+ const year = dateParts[0];
+ const monthIndex = parseInt(dateParts[1], 10) - 1;
+ return `${monthNames[monthIndex]} ${year}`;
+ });
+ // Define and return the Highcharts options object
+ const options = {
+ chart: {
+ type: "column",
+ backgroundColor: "#09090B",
+ plotBackgroundColor: "#09090B",
+ animation: false,
+ height: 360, // Add fixed height
+ marginTop: 40, // Reduce top margin
+ marginBottom: 60, // Increase bottom margin for x-axis labels
+ },
+ legend: {
+ enabled: false,
+ },
+ title: {
+ text: null,
+ },
xAxis: {
- type: "category",
- data: rawAnalystList.map((item) => item.date),
- axisLabel: {
- color: "#fff",
- formatter: function (value) {
- const dateParts = value.split("-");
- const year = dateParts[0].substring(0);
- const monthIndex = parseInt(dateParts[1]) - 1;
- return `${monthNames[monthIndex]} ${year}`;
+ categories: xCategories,
+ labels: {
+ style: {
+ color: "#fff",
},
},
},
- yAxis: {
- type: "value",
- max: 100,
-
- axisLabel: {
- show: false, // Hide y-axis labels
+ tooltip: {
+ shared: true,
+ useHTML: true,
+ backgroundColor: "rgba(0, 0, 0, 0.8)",
+ borderColor: "rgba(255, 255, 255, 0.2)",
+ borderWidth: 1,
+ style: {
+ color: "#fff",
+ fontSize: "16px",
+ padding: "10px",
},
- splitLine: {
- show: false,
+ borderRadius: 4,
+ headerFormat:
+ '{point.key}
',
+ pointFormat:
+ '\u25CF ' +
+ "{series.name}: {point.originalValue}
",
+ },
+ yAxis: {
+ gridLineWidth: 1,
+ gridLineColor: "#111827",
+ labels: {
+ style: { color: "white" },
+ },
+ title: { text: null },
+ },
+ plotOptions: {
+ column: {
+ stacking: "normal", // stacks the columns so that each column adds up to 100%
+ pointWidth: 40, // adjust this value as needed to mimic your desired "barWidth"
+ pointPadding: 0.1, // More spacing between bars
+ groupPadding: 0.1, // More spacing between groups
+ },
+ series: {
+ animation: false,
},
},
- series,
- animation: false,
- silent: true,
+ credits: {
+ enabled: false,
+ },
+ series: series,
};
- return option;
+ return options;
}
function getPieChart() {
@@ -680,7 +692,7 @@
return options;
}
- let optionsData = getPlotOptions() || null;
+ let optionsBarChart = getBarChart() || null;
let optionsPieChart = getPieChart() || null;
let config = getPriceForecastChart() || null;
@@ -921,11 +933,12 @@