update chart

This commit is contained in:
MuslemRahimi 2025-02-28 16:38:31 +01:00
parent 534cc29512
commit a8211fc1b8
4 changed files with 203 additions and 276 deletions

View File

@ -303,119 +303,115 @@
}); });
const option = { const option = {
silent: true, credits: {
tooltip: { enabled: false,
trigger: "axis",
hideDelay: 100, // Set the delay in milliseconds
}, },
legend: {
enabled: false,
},
plotOptions: {
series: {
animation: false, animation: false,
grid: { },
left: "5%", },
right: "5%", chart: {
bottom: "2%", type: "line",
top: "5%", backgroundColor: "#09090B",
containLabel: true, plotBackgroundColor: "#09090B",
height: 360,
animation: false,
},
title: {
text: null,
},
tooltip: {
shared: true,
useHTML: true,
backgroundColor: "rgba(0, 0, 0, 0.8)", // Semi-transparent black
borderColor: "rgba(255, 255, 255, 0.2)", // Slightly visible white border
borderWidth: 1,
style: {
color: "#fff",
fontSize: "16px",
padding: "10px",
},
borderRadius: 4,
formatter: function () {
// Format the x value to display time in hh:mm format
let tooltipContent = `<span class="text-white m-auto text-black text-[1rem] font-[501]">${
this?.x
}</span><br>`;
// Loop through each point in the shared tooltip
this.points?.forEach((point) => {
tooltipContent += `<span class="text-white font-semibold text-sm">${point.series.name}:</span>
<span class="text-white font-normal text-sm" >${abbreviateNumber(
point.y,
)}</span><br>`;
});
return tooltipContent;
},
}, },
xAxis: { xAxis: {
type: "category", categories: dates,
boundaryGap: false, type: "datetime",
data: dates, labels: {
axisLabel: { style: {
color: "#fff", color: "#fff",
fontSize: "12px",
}, },
}, },
tooltip: {
trigger: "axis",
hideDelay: 100,
borderColor: "#969696", // Black border color
borderWidth: 1, // Border width of 1px
backgroundColor: "#313131", // Optional: Set background color for contrast
textStyle: {
color: "#fff", // Optional: Text color for better visibility
}, },
formatter: function (params) { yAxis: {
// Get the timestamp from the first parameter gridLineWidth: 1,
const timestamp = params[0].axisValue; gridLineColor: "#111827",
labels: {
// Sort the params array to arrange High, Avg, Low style: { color: "white" },
const sortedParams = params.sort((a, b) => {
const order = { High: 0, Avg: 1, Low: 2 };
return order[a.seriesName] - order[b.seriesName];
});
// Initialize result with timestamp
let result = timestamp + "<br/>";
// Loop through each sorted series data
sortedParams.forEach((param) => {
result +=
param.seriesName + ": " + abbreviateNumber(param.value) + "<br/>";
});
return result;
}, },
title: { text: null },
opposite: true,
}, },
yAxis: [
{
type: "value",
splitLine: {
show: false, // Disable x-axis grid lines
},
axisLabel: {
show: false, // Hide y-axis labels
},
},
],
series: [ series: [
{ {
name: "Actual", name: "Actual",
data: valueList, data: valueList,
type: "line", color: "#fff",
itemStyle: { animation: false,
color: "#fff", // Change line plot color to white marker: {
enabled: false, // Hide point symbols
}, },
showSymbol: false, // Show symbols for line plot points
}, },
{ {
name: "Avg", name: "Avg",
data: avgList, data: avgList,
type: "line", color: "#fff",
itemStyle: { dashStyle: "Dash", // Dashed line style
color: "#fff", // Change line plot color to green animation: false,
marker: {
enabled: false,
}, },
lineStyle: {
type: "dashed", // Set the line type to dashed
},
showSymbol: false, // Show symbols for line plot points
}, },
{ {
name: "Low", name: "Low",
data: lowList, data: lowList,
type: "line", // If you want a dashed line with a different color, set the series color to that color.
itemStyle: {
color: "#3CB2EF", // Change line plot color to green
},
lineStyle: {
type: "dashed", // Set the line type to dashed
color: "#c2c7cf", color: "#c2c7cf",
dashStyle: "Dash",
animation: false,
marker: {
enabled: false,
}, },
showSymbol: false, // Show symbols for line plot points
}, },
{ {
name: "High", name: "High",
data: highList, data: highList,
type: "line",
itemStyle: {
color: "#3CB2EF", // Change line plot color to green
},
lineStyle: {
type: "dashed", // Set the line type to dashed
color: "#c2c7cf", color: "#c2c7cf",
dashStyle: "Dash",
animation: false,
marker: {
enabled: false,
}, },
showSymbol: false, // Show symbols for line plot points
}, },
], ],
}; };
@ -451,35 +447,87 @@
); );
const optionsGrowth = { const optionsGrowth = {
credits: {
enabled: false,
},
legend: {
enabled: false,
},
plotOptions: {
series: {
animation: false, animation: false,
grid: {
left: "5%",
right: "5%",
bottom: "2%",
top: "5%",
containLabel: true,
}, },
xAxis: { },
type: "category", chart: {
boundaryGap: false, type: "column",
data: dates, backgroundColor: "#09090B",
axisLabel: { plotBackgroundColor: "#09090B",
height: 360,
animation: false,
},
title: {
text: null,
},
tooltip: {
shared: true,
useHTML: true,
backgroundColor: "rgba(0, 0, 0, 0.8)", // Semi-transparent black
borderColor: "rgba(255, 255, 255, 0.2)", // Slightly visible white border
borderWidth: 1,
style: {
color: "#fff", color: "#fff",
fontSize: "14px",
padding: "10px",
},
borderRadius: 4,
formatter: function () {
// Find the main series point (exclude error bar points)
const mainPoint = this.points.find(
(p) => p.series.type !== "errorbar",
);
const idx = mainPoint.point.index;
const mainValue = mainPoint.y;
let tooltipContent = `<b style="font-weight:501;">${dates[idx]}</b><br>`;
// Use highGrowthList and lowGrowthList from outer scope
const high = highGrowthList[idx];
const low = lowGrowthList[idx];
if (high && high !== "N/A") {
tooltipContent += `<span style="font-weight:501;">High:</span> ${high.toFixed(2)}<br>`;
}
if (mainValue && mainValue !== "N/A") {
tooltipContent += `<span style="font-weight:501;">Avg:</span> ${mainValue.toFixed(2)}<br>`;
}
if (low && low !== "N/A") {
tooltipContent += `<span style="font-weight:501;">Low:</span> ${low.toFixed(2)}<br>`;
}
return tooltipContent;
}, },
}, },
yAxis: [
{ xAxis: {
type: "value", categories: dates,
splitLine: { type: "datetime",
show: false, // Disable x-axis grid lines labels: {
}, style: {
axisLabel: { color: "#fff",
show: false, // Hide y-axis labels fontSize: "12px",
}, },
}, },
], },
yAxis: {
gridLineWidth: 1,
gridLineColor: "#111827",
labels: {
style: { color: "white" },
},
title: { text: null },
opposite: true,
},
series: [ series: [
{ {
// Dynamically set the series name based on dataType
name: name:
dataType === "Revenue" dataType === "Revenue"
? "Revenue Growth" ? "Revenue Growth"
@ -489,129 +537,37 @@
? "Net Income Growth" ? "Net Income Growth"
: "EBITDA Growth", : "EBITDA Growth",
data: growthList?.map((value) => ({ data: growthList?.map((value) => ({
value, y: value,
itemStyle: { // Set color based on the sign of the value
color: value >= 0 ? "#00FC50" : "#D9220E", // Green for >= 0, Red for < 0 color: value >= 0 ? "#338D73" : "#ED3333",
}, borderColor: value >= 0 ? "#338D73" : "#ED3333",
borderRadius: "1px",
})), })),
type: "bar", zIndex: 5,
smooth: true, // 'smooth' is not applicable for column charts
z: 5, // Ensure the bar chart has a lower z-index than the error bars
}, },
{ {
name: "Error Bars", name: "Error Bars",
type: "custom", type: "errorbar",
renderItem: (params, api) => { // Prepare data as [low, high] pairs for each index.
const xValue = api.value(0); data: growthList?.map((value, index) => {
const yValue = api.value(1); const high = highGrowthList[index];
const low = lowGrowthList[index];
// Select high and low lists based on dataType // If either high or low is null/undefined, return nulls.
const highList = highGrowthList; return high != null && low != null ? [low, high] : [null, null];
const lowList = lowGrowthList; }),
color: "#fff",
// Retrieve the corresponding high and low values lineWidth: 2, // Thicker lines for error bars
const high = highList[params.dataIndex]; whiskerLength: 10, // Adjust whisker length as needed
const low = lowList[params.dataIndex]; zIndex: 10,
// Disable tooltip for error bar points
// Skip rendering error bars if high or low values are null or undefined
if (high == null || low == null) return; // Null or undefined values are skipped
const x = api.coord([xValue, yValue])[0];
const highCoord = api.coord([xValue, high])[1];
const lowCoord = api.coord([xValue, low])[1];
return {
type: "group",
children: [
{
type: "line",
shape: {
x1: x,
y1: highCoord,
x2: x,
y2: lowCoord,
},
style: {
stroke: "#fff",
lineWidth: 2, // Set thicker line width
},
},
{
type: "line",
shape: {
x1: x - 5,
y1: highCoord,
x2: x + 5,
y2: highCoord,
},
style: {
stroke: "#fff",
lineWidth: 2, // Set thicker line width
},
},
{
type: "line",
shape: {
x1: x - 5,
y1: lowCoord,
x2: x + 5,
y2: lowCoord,
},
style: {
stroke: "#fff",
lineWidth: 2, // Set thicker line width
},
},
],
};
},
encode: {
x: 0, // Map x-axis values
y: 1, // Map y-axis values
},
data: growthList?.map((value, index) => [index, value]), // Prepare data for error bars
z: 10, // Bring the error bars to the front
},
],
tooltip: { tooltip: {
trigger: "axis", pointFormatter: function () {
hideDelay: 100, return "";
borderColor: "#969696", // Black border color
borderWidth: 1, // Border width of 1px
backgroundColor: "#313131", // Optional: Set background color for contrast
textStyle: {
color: "#fff", // Optional: Text color for better visibility
},
formatter: (params) => {
const dataIndex = params[0].dataIndex;
const mainValue = params[0].value;
// Select high and low lists based on dataType
const highList = highGrowthList;
const lowList = lowGrowthList;
// Retrieve the corresponding high and low values
const high = highList[dataIndex];
const low = lowList[dataIndex];
// Only show High and Low if they are not "N/A"
let tooltipContent = `<b>${dates[dataIndex]}</b><br>`;
if (high && high !== "N/A") {
tooltipContent += `High: ${high.toFixed(2)}<br>`;
}
if (mainValue && mainValue !== "N/A") {
tooltipContent += `Avg: ${mainValue.toFixed(2)}<br>`;
}
if (low && low !== "N/A") {
tooltipContent += `Low: ${low.toFixed(2)}<br>`;
}
return tooltipContent;
}, },
}, },
},
],
}; };
if (dataType === "Revenue") { if (dataType === "Revenue") {
@ -1096,7 +1052,7 @@
<EstimationGraph <EstimationGraph
userTier={data?.user?.tier} userTier={data?.user?.tier}
title="Revenue" title="Revenue"
options={optionsRevenue} config={optionsRevenue}
tableDataList={revenueDateList} tableDataList={revenueDateList}
highDataList={highRevenueList} highDataList={highRevenueList}
avgDataList={avgRevenueList} avgDataList={avgRevenueList}
@ -1108,7 +1064,7 @@
<EstimationGraph <EstimationGraph
userTier={data?.user?.tier} userTier={data?.user?.tier}
title="Revenue Growth" title="Revenue Growth"
options={optionsRevenueGrowth} config={optionsRevenueGrowth}
tableDataList={revenueDateList} tableDataList={revenueDateList}
highDataList={highRevenueList} highDataList={highRevenueList}
avgDataList={avgRevenueList} avgDataList={avgRevenueList}
@ -1122,7 +1078,7 @@
<EstimationGraph <EstimationGraph
userTier={data?.user?.tier} userTier={data?.user?.tier}
title="EPS" title="EPS"
options={optionsEPS} config={optionsEPS}
tableDataList={epsDateList} tableDataList={epsDateList}
highDataList={highEPSList} highDataList={highEPSList}
avgDataList={avgEPSList} avgDataList={avgEPSList}
@ -1134,7 +1090,7 @@
<EstimationGraph <EstimationGraph
userTier={data?.user?.tier} userTier={data?.user?.tier}
title="EPS Growth" title="EPS Growth"
options={optionsEPSGrowth} config={optionsEPSGrowth}
tableDataList={epsDateList} tableDataList={epsDateList}
highDataList={highEPSList} highDataList={highEPSList}
avgDataList={avgEPSList} avgDataList={avgEPSList}
@ -1148,7 +1104,7 @@
<EstimationGraph <EstimationGraph
userTier={data?.user?.tier} userTier={data?.user?.tier}
title="Net Income" title="Net Income"
options={optionsNetIncome} config={optionsNetIncome}
tableDataList={netIncomeDateList} tableDataList={netIncomeDateList}
highDataList={highNetIncomeList} highDataList={highNetIncomeList}
avgDataList={avgNetIncomeList} avgDataList={avgNetIncomeList}
@ -1160,7 +1116,7 @@
<EstimationGraph <EstimationGraph
userTier={data?.user?.tier} userTier={data?.user?.tier}
title="Net Income Growth" title="Net Income Growth"
options={optionsNetIncomeGrowth} config={optionsNetIncomeGrowth}
tableDataList={netIncomeDateList} tableDataList={netIncomeDateList}
highDataList={highNetIncomeList} highDataList={highNetIncomeList}
avgDataList={avgNetIncomeList} avgDataList={avgNetIncomeList}
@ -1174,7 +1130,7 @@
<EstimationGraph <EstimationGraph
userTier={data?.user?.tier} userTier={data?.user?.tier}
title="EBITDA" title="EBITDA"
options={optionsEbitda} config={optionsEbitda}
tableDataList={ebitdaDateList} tableDataList={ebitdaDateList}
highDataList={highEbitdaList} highDataList={highEbitdaList}
avgDataList={avgEbitdaList} avgDataList={avgEbitdaList}
@ -1186,7 +1142,7 @@
<EstimationGraph <EstimationGraph
userTier={data?.user?.tier} userTier={data?.user?.tier}
title="EBITDA Growth" title="EBITDA Growth"
options={optionsEbitdaGrowth} config={optionsEbitdaGrowth}
tableDataList={ebitdaDateList} tableDataList={ebitdaDateList}
highDataList={highEbitdaList} highDataList={highEbitdaList}
avgDataList={avgEbitdaList} avgDataList={avgEbitdaList}

View File

@ -1,21 +1,9 @@
<script lang="ts"> <script lang="ts">
import { Chart } from "svelte-echarts"; import highcharts from "$lib/highcharts.ts";
import { init, use } from "echarts/core";
import { LineChart, CustomChart } from "echarts/charts";
import { GridComponent, TooltipComponent } from "echarts/components";
import { CanvasRenderer } from "echarts/renderers";
import { abbreviateNumber, computeGrowthSingleList } from "$lib/utils"; import { abbreviateNumber, computeGrowthSingleList } from "$lib/utils";
use([
LineChart,
CustomChart,
GridComponent,
TooltipComponent,
CanvasRenderer,
]);
export let userTier; export let userTier;
export let title; export let title;
export let options; export let config;
export let tableDataList; export let tableDataList;
export let highDataList; export let highDataList;
export let avgDataList; export let avgDataList;
@ -29,9 +17,9 @@
<div> <div>
<h2 class="mb-2 text-xl font-bold">{title} Forecast</h2> <h2 class="mb-2 text-xl font-bold">{title} Forecast</h2>
<div class="rounded-sm border p-2 border-gray-600"> <div class="rounded-sm border p-2 border-gray-600">
<div class="app h-[275px] w-full"> <div class="h-[360px] w-full">
{#if options !== null} {#if config !== null}
<Chart {init} {options} class="chart" /> <div use:highcharts={config}></div>
{/if} {/if}
</div> </div>
<div class="mt-3 overflow-x-auto p-0 text-center sm:p-0.5 lg:mt-3.5"> <div class="mt-3 overflow-x-auto p-0 text-center sm:p-0.5 lg:mt-3.5">
@ -129,9 +117,9 @@
<div> <div>
<h2 class="mb-2 text-xl font-bold">{title}</h2> <h2 class="mb-2 text-xl font-bold">{title}</h2>
<div class="rounded-sm border p-2 border-gray-600"> <div class="rounded-sm border p-2 border-gray-600">
<div class="app h-[275px] w-full"> <div class="h-[360px] w-full">
{#if options !== null} {#if config !== null}
<Chart {init} {options} class="chart" /> <div use:highcharts={config}></div>
{/if} {/if}
</div> </div>
<div class="mt-3 overflow-x-auto p-0 text-center sm:p-0.5 lg:mt-3.5"> <div class="mt-3 overflow-x-auto p-0 text-center sm:p-0.5 lg:mt-3.5">
@ -256,20 +244,3 @@
</div> </div>
</div> </div>
{/if} {/if}
<style>
.app {
height: 300px;
max-width: 100%; /* Ensure chart width doesn't exceed the container */
}
@media (max-width: 640px) {
.app {
height: 210px;
}
}
.chart {
width: 100%;
}
</style>

View File

@ -1,7 +1,9 @@
import Highcharts from 'highcharts'; import Highcharts from 'highcharts';
import HighchartsMore from 'highcharts/highcharts-more'; // Add this import
import { browser } from '$app/environment'; import { browser } from '$app/environment';
if (browser) { if (browser) {
HighchartsMore(Highcharts); // Initialize the extension
Highcharts.setOptions({ Highcharts.setOptions({
lang: { lang: {
numericSymbols: ['K', 'M', 'B', 'T', 'P', 'E'] numericSymbols: ['K', 'M', 'B', 'T', 'P', 'E']
@ -58,13 +60,11 @@ export default (node, config) => {
createChart(); createChart();
// Resize observer with optimized logic // Resize observer remains the same
const resizeObserver = new ResizeObserver(() => { const resizeObserver = new ResizeObserver(() => {
if (chart) { if (chart) {
const newWidth = node.clientWidth; const newWidth = node.clientWidth;
const newHeight = 360; // Let height be auto-adjusted const newHeight = 360;
// **Dynamically update size without recreating the chart**
chart?.setSize(newWidth, newHeight, false); chart?.setSize(newWidth, newHeight, false);
} }
}); });

View File

@ -652,7 +652,7 @@
</div> </div>
<div class="grow pt-2 md:pt-4 lg:pl-4 lg:pt-0"> <div class="grow pt-2 md:pt-4 lg:pl-4 lg:pt-0">
<div <div
class="chart mt-5 sm:mt-0 border border-gray-800 rounded" class="chart mt-5 sm:mt-0 border-l border-r sm:border border-gray-800 rounded"
use:highcharts={config} use:highcharts={config}
></div> ></div>
<div <div