eps forecast limited to two decimal number
This commit is contained in:
parent
239340886e
commit
ba71c34e52
@ -1,285 +1,266 @@
|
|||||||
<script lang='ts'>
|
<script lang="ts">
|
||||||
import {analystEstimateComponent, stockTicker, screenWidth, getCache, setCache} from '$lib/store';
|
import { analystEstimateComponent, stockTicker, screenWidth, getCache, setCache } from "$lib/store";
|
||||||
import InfoModal from '$lib/components/InfoModal.svelte';
|
import InfoModal from "$lib/components/InfoModal.svelte";
|
||||||
|
|
||||||
import { Chart } from 'svelte-echarts'
|
import { Chart } from "svelte-echarts";
|
||||||
import { init, use } from 'echarts/core'
|
import { init, use } from "echarts/core";
|
||||||
import { ScatterChart } from 'echarts/charts'
|
import { ScatterChart } from "echarts/charts";
|
||||||
import { GridComponent, TooltipComponent } from 'echarts/components'
|
import { GridComponent, TooltipComponent } from "echarts/components";
|
||||||
import { CanvasRenderer } from 'echarts/renderers'
|
import { CanvasRenderer } from "echarts/renderers";
|
||||||
import { abbreviateNumber } from '$lib/utils';
|
import { abbreviateNumber } from "$lib/utils";
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
use([ScatterChart, GridComponent, TooltipComponent, CanvasRenderer])
|
use([ScatterChart, GridComponent, TooltipComponent, CanvasRenderer]);
|
||||||
|
|
||||||
|
let analystEstimateList = [];
|
||||||
|
let isLoaded = false;
|
||||||
|
|
||||||
let analystEstimateList = [];
|
let deactivateContent = data?.user?.tier === "Pro" ? false : true;
|
||||||
let isLoaded = false;
|
|
||||||
|
|
||||||
let deactivateContent = data?.user?.tier === 'Pro' ? false : true;
|
let xData = [];
|
||||||
|
let optionsData;
|
||||||
|
|
||||||
let xData = [];
|
let displayData = "Revenue";
|
||||||
let optionsData;
|
|
||||||
|
|
||||||
let displayData = 'Revenue';
|
function changeStatement(event) {
|
||||||
|
|
||||||
function changeStatement(event)
|
|
||||||
{
|
|
||||||
displayData = event.target.value;
|
displayData = event.target.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizer(value) {
|
||||||
function normalizer(value) {
|
|
||||||
if (Math?.abs(value) >= 1e18) {
|
if (Math?.abs(value) >= 1e18) {
|
||||||
return { unit: 'Q', denominator: 1e18 };
|
return { unit: "Q", denominator: 1e18 };
|
||||||
} else if (Math?.abs(value) >= 1e12) {
|
} else if (Math?.abs(value) >= 1e12) {
|
||||||
return { unit: 'T', denominator: 1e12 };
|
return { unit: "T", denominator: 1e12 };
|
||||||
} else if (Math?.abs(value) >= 1e9) {
|
} else if (Math?.abs(value) >= 1e9) {
|
||||||
return { unit: 'B', denominator: 1e9 };
|
return { unit: "B", denominator: 1e9 };
|
||||||
} else if (Math?.abs(value) >= 1e6) {
|
} else if (Math?.abs(value) >= 1e6) {
|
||||||
return { unit: 'M', denominator: 1e6 };
|
return { unit: "M", denominator: 1e6 };
|
||||||
} else if (Math?.abs(value) >= 1e5) {
|
} else if (Math?.abs(value) >= 1e5) {
|
||||||
return { unit: 'K', denominator: 1e5 };
|
return { unit: "K", denominator: 1e5 };
|
||||||
} else {
|
} else {
|
||||||
return { unit: '', denominator: 1 };
|
return { unit: "", denominator: 1 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let tableDataActual = [];
|
||||||
|
let tableDataForecast = [];
|
||||||
|
|
||||||
|
const getAnalystEstimate = async (ticker) => {
|
||||||
let tableDataActual = [];
|
|
||||||
let tableDataForecast = [];
|
|
||||||
|
|
||||||
const getAnalystEstimate = async (ticker) => {
|
|
||||||
// Get cached data for the specific tickerID
|
// Get cached data for the specific tickerID
|
||||||
const cachedData = getCache(ticker, 'getAnalystEstimate');
|
const cachedData = getCache(ticker, "getAnalystEstimate");
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
analystEstimateList = cachedData;
|
analystEstimateList = cachedData;
|
||||||
} else {
|
} else {
|
||||||
|
const postData = { ticker: ticker };
|
||||||
|
|
||||||
const postData = {'ticker': ticker};
|
const response = await fetch(data?.apiURL + "/analyst-estimate", {
|
||||||
|
method: "POST",
|
||||||
const response = await fetch(data?.apiURL + '/analyst-estimate', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json", "X-API-KEY": data?.apiKey
|
"Content-Type": "application/json",
|
||||||
|
"X-API-KEY": data?.apiKey,
|
||||||
},
|
},
|
||||||
body: JSON.stringify(postData)
|
body: JSON.stringify(postData),
|
||||||
});
|
});
|
||||||
|
|
||||||
analystEstimateList = await response?.json();
|
analystEstimateList = await response?.json();
|
||||||
analystEstimateList = analystEstimateList?.filter(item => !item.date.toString().startsWith("19"));
|
analystEstimateList = analystEstimateList?.filter((item) => !item.date.toString().startsWith("19"));
|
||||||
|
|
||||||
// Cache the data for this specific tickerID with a specific name 'getAnalystEstimate'
|
// Cache the data for this specific tickerID with a specific name 'getAnalystEstimate'
|
||||||
setCache(ticker, analystEstimateList, 'getAnalystEstimate');
|
setCache(ticker, analystEstimateList, "getAnalystEstimate");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(analystEstimateList?.length !== 0) {
|
if (analystEstimateList?.length !== 0) {
|
||||||
$analystEstimateComponent = true;
|
$analystEstimateComponent = true;
|
||||||
} else {
|
} else {
|
||||||
$analystEstimateComponent = false;
|
$analystEstimateComponent = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getPlotOptions() {
|
||||||
function getPlotOptions() {
|
|
||||||
let dates = [];
|
let dates = [];
|
||||||
let valueList = [];
|
let valueList = [];
|
||||||
let estimatedValueList = [];
|
let estimatedValueList = [];
|
||||||
|
|
||||||
let filteredData = analystEstimateList?.filter(item => item.date >= 2015) ?? [];
|
let filteredData = analystEstimateList?.filter((item) => item.date >= 2015) ?? [];
|
||||||
|
|
||||||
// Iterate over the data and extract required information
|
// Iterate over the data and extract required information
|
||||||
if( displayData === 'Revenue') {
|
if (displayData === "Revenue") {
|
||||||
filteredData?.slice(-20)?.forEach(item => {
|
filteredData?.slice(-20)?.forEach((item) => {
|
||||||
dates.push(`FY${item?.date?.toString()?.slice(-2)}`);
|
dates.push(`FY${item?.date?.toString()?.slice(-2)}`);
|
||||||
valueList.push(item?.revenue); // Handle null values by using 0 or any placeholder value
|
valueList.push(item?.revenue); // Handle null values by using 0 or any placeholder value
|
||||||
estimatedValueList.push(item?.estimatedRevenueAvg);
|
estimatedValueList.push(item?.estimatedRevenueAvg);
|
||||||
});
|
});
|
||||||
} else if ( displayData === 'Net Income') {
|
} else if (displayData === "Net Income") {
|
||||||
filteredData?.slice(-20)?.forEach(item => {
|
filteredData?.slice(-20)?.forEach((item) => {
|
||||||
dates.push(`FY${item?.date?.toString()?.slice(-2)}`);
|
dates.push(`FY${item?.date?.toString()?.slice(-2)}`);
|
||||||
valueList.push(item?.netIncome); // Handle null values by using 0 or any placeholder value
|
valueList.push(item?.netIncome); // Handle null values by using 0 or any placeholder value
|
||||||
estimatedValueList.push(item?.estimatedNetIncomeAvg);
|
estimatedValueList.push(item?.estimatedNetIncomeAvg);
|
||||||
});
|
});
|
||||||
} else if ( displayData === 'EBITDA') {
|
} else if (displayData === "EBITDA") {
|
||||||
filteredData?.slice(-20)?.forEach(item => {
|
filteredData?.slice(-20)?.forEach((item) => {
|
||||||
dates.push(`FY${item?.date?.toString()?.slice(-2)}`);
|
dates.push(`FY${item?.date?.toString()?.slice(-2)}`);
|
||||||
valueList.push(item?.ebitda); // Handle null values by using 0 or any placeholder value
|
valueList.push(item?.ebitda); // Handle null values by using 0 or any placeholder value
|
||||||
estimatedValueList.push(item?.estimatedEbitdaAvg);
|
estimatedValueList.push(item?.estimatedEbitdaAvg);
|
||||||
});
|
});
|
||||||
} else if ( displayData === 'EPS') {
|
} else if (displayData === "EPS") {
|
||||||
filteredData?.slice(-20)?.forEach(item => {
|
filteredData?.slice(-20)?.forEach((item) => {
|
||||||
dates.push(`FY${item?.date?.toString()?.slice(-2)}`);
|
dates.push(`FY${item?.date?.toString()?.slice(-2)}`);
|
||||||
valueList.push(item?.eps); // Handle null values by using 0 or any placeholder value
|
valueList.push(item?.eps); // Handle null values by using 0 or any placeholder value
|
||||||
estimatedValueList.push(item?.estimatedEpsAvg);
|
estimatedValueList.push(item?.estimatedEpsAvg);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Normalize the data if needed (not required in this case, but leaving it here for reference)
|
// Normalize the data if needed (not required in this case, but leaving it here for reference)
|
||||||
const { unit, denominator } = normalizer(Math.max(...valueList, ...estimatedValueList) ?? 0);
|
const { unit, denominator } = normalizer(Math.max(...valueList, ...estimatedValueList) ?? 0);
|
||||||
|
|
||||||
const option = {
|
const option = {
|
||||||
silent: true,
|
silent: true,
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: "axis",
|
||||||
hideDelay: 100, // Set the delay in milliseconds
|
hideDelay: 100, // Set the delay in milliseconds
|
||||||
},
|
},
|
||||||
animation: false,
|
animation: false,
|
||||||
grid: {
|
grid: {
|
||||||
left: '2%',
|
left: "2%",
|
||||||
right: '2%',
|
right: "2%",
|
||||||
bottom: '2%',
|
bottom: "2%",
|
||||||
top: '5%',
|
top: "5%",
|
||||||
containLabel: true
|
containLabel: true,
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: 'category',
|
type: "category",
|
||||||
boundaryGap: false,
|
boundaryGap: false,
|
||||||
data: dates,
|
data: dates,
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
color: '#fff',
|
color: "#fff",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
type: 'value',
|
type: "value",
|
||||||
splitLine: {
|
splitLine: {
|
||||||
show: false, // Disable x-axis grid lines
|
show: false, // Disable x-axis grid lines
|
||||||
},
|
},
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
color: '#fff', // Change label color to white
|
color: "#fff", // Change label color to white
|
||||||
formatter: function (value, index) {
|
formatter: function (value, index) {
|
||||||
// Display every second tick
|
// Display every second tick
|
||||||
if (index % 2 === 0) {
|
if (index % 2 === 0) {
|
||||||
return (value / denominator)?.toFixed(0) + unit; // Format value in millions
|
return (value / denominator)?.toFixed(0) + unit; // Format value in millions
|
||||||
} else {
|
} else {
|
||||||
return ''; // Hide this tick
|
return ""; // Hide this tick
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: 'Actual',
|
name: "Actual",
|
||||||
data: valueList,
|
data: valueList,
|
||||||
type: 'scatter',
|
type: "scatter",
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: '#fff' // Change scatter plot color to white
|
color: "#fff", // Change scatter plot color to white
|
||||||
},
|
},
|
||||||
showSymbol: true // Show symbols for scatter plot points
|
showSymbol: true, // Show symbols for scatter plot points
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Forecast',
|
name: "Forecast",
|
||||||
data: estimatedValueList,
|
data: estimatedValueList,
|
||||||
type: 'scatter',
|
type: "scatter",
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: '#E11D48' // Change scatter plot color to green
|
color: "#E11D48", // Change scatter plot color to green
|
||||||
},
|
},
|
||||||
showSymbol: true // Show symbols for scatter plot points
|
showSymbol: true, // Show symbols for scatter plot points
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
return option;
|
return option;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//To-do: Optimize this piece of shit
|
|
||||||
function prepareData() {
|
|
||||||
|
|
||||||
|
//To-do: Optimize this piece of shit
|
||||||
|
function prepareData() {
|
||||||
tableDataActual = [];
|
tableDataActual = [];
|
||||||
tableDataForecast = [];
|
tableDataForecast = [];
|
||||||
|
|
||||||
let filteredData = analystEstimateList?.filter(item => item.date >= 2015) ?? [];
|
let filteredData = analystEstimateList?.filter((item) => item.date >= 2015) ?? [];
|
||||||
|
|
||||||
xData = filteredData?.map(({ date }) => Number(String(date)?.slice(-2)));
|
xData = filteredData?.map(({ date }) => Number(String(date)?.slice(-2)));
|
||||||
|
|
||||||
if(displayData === 'Revenue') {
|
if (displayData === "Revenue") {
|
||||||
|
filteredData?.forEach((item) => {
|
||||||
|
tableDataActual?.push({
|
||||||
filteredData?.forEach(item => {
|
FY: Number(String(item?.date)?.slice(-2)),
|
||||||
|
val: item?.revenue,
|
||||||
tableDataActual?.push({ 'FY': Number(String(item?.date)?.slice(-2)), 'val': (item?.revenue)});
|
});
|
||||||
tableDataForecast?.push({ 'FY': Number(String(item?.date)?.slice(-2)), 'val': item?.estimatedRevenueAvg, 'numOfAnalysts': item?.numOfAnalysts});
|
tableDataForecast?.push({
|
||||||
|
FY: Number(String(item?.date)?.slice(-2)),
|
||||||
})
|
val: item?.estimatedRevenueAvg,
|
||||||
}
|
numOfAnalysts: item?.numOfAnalysts,
|
||||||
|
});
|
||||||
else if(displayData === 'Net Income') {
|
});
|
||||||
|
} else if (displayData === "Net Income") {
|
||||||
|
filteredData?.forEach((item) => {
|
||||||
filteredData?.forEach(item => {
|
tableDataActual?.push({
|
||||||
|
FY: Number(String(item?.date)?.slice(-2)),
|
||||||
tableDataActual?.push({ 'FY': Number(String(item?.date)?.slice(-2)), 'val': (item?.netIncome )});
|
val: item?.netIncome,
|
||||||
tableDataForecast?.push({ 'FY': Number(String(item?.date)?.slice(-2)), 'val': item?.estimatedNetIncomeAvg, 'numOfAnalysts': item?.numOfAnalysts});
|
});
|
||||||
|
tableDataForecast?.push({
|
||||||
|
FY: Number(String(item?.date)?.slice(-2)),
|
||||||
|
val: item?.estimatedNetIncomeAvg,
|
||||||
|
numOfAnalysts: item?.numOfAnalysts,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else if (displayData === "EPS") {
|
||||||
|
filteredData?.forEach((item) => {
|
||||||
|
tableDataActual?.push({
|
||||||
|
FY: Number(String(item?.date)?.slice(-2)),
|
||||||
|
val: item?.eps ?? null,
|
||||||
|
});
|
||||||
|
tableDataForecast?.push({
|
||||||
|
FY: Number(String(item?.date)?.slice(-2)),
|
||||||
|
val: item?.estimatedEpsAvg,
|
||||||
|
numOfAnalysts: item?.numOfAnalysts,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else if (displayData === "EBITDA") {
|
||||||
|
filteredData?.forEach((item) => {
|
||||||
|
tableDataActual?.push({
|
||||||
|
FY: Number(String(item?.date)?.slice(-2)),
|
||||||
|
val: item?.ebitda,
|
||||||
|
});
|
||||||
|
tableDataForecast?.push({
|
||||||
|
FY: Number(String(item?.date)?.slice(-2)),
|
||||||
|
val: item?.estimatedEbitdaAvg,
|
||||||
|
numOfAnalysts: item?.numOfAnalysts,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(displayData === 'EPS') {
|
|
||||||
filteredData?.forEach(item => {
|
|
||||||
|
|
||||||
tableDataActual?.push({ 'FY': Number(String(item?.date)?.slice(-2)), 'val': item?.eps ?? null});
|
|
||||||
tableDataForecast?.push({ 'FY': Number(String(item?.date)?.slice(-2)), 'val': item?.estimatedEpsAvg, 'numOfAnalysts': item?.numOfAnalysts});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(displayData === 'EBITDA') {
|
$: {
|
||||||
|
if ($stockTicker && displayData && typeof window !== "undefined") {
|
||||||
filteredData?.forEach(item => {
|
|
||||||
|
|
||||||
tableDataActual?.push({ 'FY': Number(String(item?.date)?.slice(-2)), 'val': (item?.ebitda)});
|
|
||||||
tableDataForecast?.push({ 'FY': Number(String(item?.date)?.slice(-2)), 'val': item?.estimatedEbitdaAvg, 'numOfAnalysts': item?.numOfAnalysts});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$: {
|
|
||||||
if ($stockTicker && displayData && typeof window !== 'undefined')
|
|
||||||
{
|
|
||||||
isLoaded = false;
|
isLoaded = false;
|
||||||
|
|
||||||
|
const asyncFunctions = [getAnalystEstimate($stockTicker)];
|
||||||
const asyncFunctions = [
|
|
||||||
getAnalystEstimate($stockTicker)
|
|
||||||
];
|
|
||||||
Promise.all(asyncFunctions)
|
Promise.all(asyncFunctions)
|
||||||
.then((results) => {
|
.then((results) => {
|
||||||
//prepareData(analystEstimateList)
|
//prepareData(analystEstimateList)
|
||||||
optionsData = getPlotOptions();
|
optionsData = getPlotOptions();
|
||||||
prepareData()
|
prepareData();
|
||||||
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('An error occurred:', error);
|
console.error("An error occurred:", error);
|
||||||
});
|
});
|
||||||
isLoaded = true;
|
isLoaded = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<section class="overflow-hidden text-white h-full pb-8 sm:pb-2">
|
<section class="overflow-hidden text-white h-full pb-8 sm:pb-2">
|
||||||
<main class="overflow-hidden ">
|
<main class="overflow-hidden">
|
||||||
<div class="w-full m-auto mt-5 sm:mt-0">
|
<div class="w-full m-auto mt-5 sm:mt-0">
|
||||||
|
|
||||||
<div class="flex flex-row items-center">
|
<div class="flex flex-row items-center">
|
||||||
<label for="predictiveFundamentalsInfo" class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-3xl font-bold">
|
<label for="predictiveFundamentalsInfo" class="mr-1 cursor-pointer flex flex-row items-center text-white text-xl sm:text-3xl font-bold"> Predictive Fundamentals </label>
|
||||||
Predictive Fundamentals
|
|
||||||
</label>
|
|
||||||
<InfoModal
|
<InfoModal
|
||||||
title={"Predictive Fundamentals"}
|
title={"Predictive Fundamentals"}
|
||||||
content={`If quarterly earnings for a year are incomplete, we offer a summarized view based on available data. For instance, if the Q4 report is missing, we display revenue as X, reflecting the sum of Q1-Q3 only. Q4 data will be added later when available.`}
|
content={`If quarterly earnings for a year are incomplete, we offer a summarized view based on available data. For instance, if the Q4 report is missing, we display revenue as X, reflecting the sum of Q1-Q3 only. Q4 data will be added later when available.`}
|
||||||
@ -287,168 +268,119 @@ $: {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="text-white text-[1rem] mt-1 sm:mt-3 mb-1 w-full sm:w-5/6">We analyze insights from various analysts to offer both historical and future fundamental data forecasts.</div>
|
||||||
|
|
||||||
<div class="text-white text-[1rem] mt-1 sm:mt-3 mb-1 w-full sm:w-5/6">
|
{#if data?.user?.tier === "Pro"}
|
||||||
We analyze insights from various analysts to offer both historical and future fundamental data forecasts.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if data?.user?.tier === 'Pro'}
|
|
||||||
{#if isLoaded}
|
{#if isLoaded}
|
||||||
|
|
||||||
{#if analystEstimateList?.length !== 0}
|
{#if analystEstimateList?.length !== 0}
|
||||||
|
|
||||||
|
|
||||||
<select class="mt-5 mb-5 sm:mb-0 sm:mt-3 ml-1 w-44 select select-bordered select-sm p-0 pl-5 overflow-y-auto bg-[#2A303C]" on:change={changeStatement}>
|
<select class="mt-5 mb-5 sm:mb-0 sm:mt-3 ml-1 w-44 select select-bordered select-sm p-0 pl-5 overflow-y-auto bg-[#2A303C]" on:change={changeStatement}>
|
||||||
<option disabled>Choose Fundamental Data</option>
|
<option disabled>Choose Fundamental Data</option>
|
||||||
<option disabled={deactivateContent} value="EPS">
|
<option disabled={deactivateContent} value="EPS"> EPS </option>
|
||||||
EPS
|
<option disabled={deactivateContent} value="EBITDA"> EBITDA </option>
|
||||||
</option>
|
<option value="Net Income"> Net Income </option>
|
||||||
<option disabled={deactivateContent} value="EBITDA">
|
|
||||||
EBITDA
|
|
||||||
</option>
|
|
||||||
<option value="Net Income">
|
|
||||||
Net Income
|
|
||||||
</option>
|
|
||||||
<option value="Revenue" selected>Revenue</option>
|
<option value="Revenue" selected>Revenue</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
||||||
<div class="pb-2">
|
<div class="pb-2">
|
||||||
|
|
||||||
|
|
||||||
<div class="app w-full h-[300px] mt-5">
|
<div class="app w-full h-[300px] mt-5">
|
||||||
<Chart {init} options={optionsData} class="chart" />
|
<Chart {init} options={optionsData} class="chart" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="flex flex-row items-center justify-between m-auto mt-10">
|
<div class="flex flex-row items-center justify-between m-auto mt-10">
|
||||||
|
|
||||||
<div class="flex flex-row items-center w-1/2 sm:w-full justify-center">
|
<div class="flex flex-row items-center w-1/2 sm:w-full justify-center">
|
||||||
<div class="h-full bg-gray-800 transform -translate-x-1/2 " aria-hidden="true"></div>
|
<div class="h-full bg-gray-800 transform -translate-x-1/2" aria-hidden="true"></div>
|
||||||
<div class="w-3 h-3 bg-[#fff] border-4 box-content border-gray-900 rounded-full transform -translate-x-1/2" aria-hidden="true"></div>
|
<div class="w-3 h-3 bg-[#fff] border-4 box-content border-gray-900 rounded-full transform -translate-x-1/2" aria-hidden="true"></div>
|
||||||
<span class="text-white text-sm sm:text-md sm:font-medium inline-block">
|
<span class="text-white text-sm sm:text-md sm:font-medium inline-block"> Actual </span>
|
||||||
Actual
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-row items-center w-1/2 sm:w-full justify-center">
|
<div class="flex flex-row items-center w-1/2 sm:w-full justify-center">
|
||||||
<div class="h-full bg-gray-800 transform -translate-x-1/2 " aria-hidden="true"></div>
|
<div class="h-full bg-gray-800 transform -translate-x-1/2" aria-hidden="true"></div>
|
||||||
<div class="w-3 h-3 bg-[#E11D48] border-4 box-content border-gray-900 rounded-full transform -translate-x-1/2" aria-hidden="true"></div>
|
<div class="w-3 h-3 bg-[#E11D48] border-4 box-content border-gray-900 rounded-full transform -translate-x-1/2" aria-hidden="true"></div>
|
||||||
<span class="text-white text-sm sm:text-md sm:font-medium inline-block">
|
<span class="text-white text-sm sm:text-md sm:font-medium inline-block"> Analyst Forecast </span>
|
||||||
Analyst Forecast
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="no-scrollbar flex justify-start items-center w-screen sm:w-full mt-6 m-auto overflow-x-scroll pr-5 sm:pr-0">
|
<div class="no-scrollbar flex justify-start items-center w-screen sm:w-full mt-6 m-auto overflow-x-scroll pr-5 sm:pr-0">
|
||||||
<table class="table table-sm shaodow table-pin-cols table-compact rounded-none sm:rounded-md w-full bg-[#09090B] border-bg-[#09090B]">
|
<table class="table table-sm shaodow table-pin-cols table-compact rounded-none sm:rounded-md w-full bg-[#09090B] border-bg-[#09090B]">
|
||||||
<thead class="">
|
<thead class="">
|
||||||
<tr class="">
|
<tr class="">
|
||||||
<th class="bg-[#27272A] border-b border-[#000] text-white font-semibold text-sm sm:text-[1rem] text-start">Year</th>
|
<th class="bg-[#27272A] border-b border-[#000] text-white font-semibold text-sm sm:text-[1rem] text-start">Year</th>
|
||||||
{#each xData as item}
|
{#each xData as item}
|
||||||
<td class="z-20 bg-[#27272A] border-b border-[#000] text-white font-semibold text-sm sm:text-[1rem] text-center bg-[#09090B]">{'FY'+item}</td>
|
<td class="z-20 bg-[#27272A] border-b border-[#000] text-white font-semibold text-sm sm:text-[1rem] text-center bg-[#09090B]">{"FY" + item}</td>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="shadow-md">
|
<tbody class="shadow-md">
|
||||||
|
|
||||||
<tr class="bg-[#09090B] border-b-[#09090B]">
|
<tr class="bg-[#09090B] border-b-[#09090B]">
|
||||||
<th class="text-white whitespace-nowrap text-sm sm:text-[1rem] text-start font-medium bg-[#09090B] border-b border-[#09090B]">
|
<th class="text-white whitespace-nowrap text-sm sm:text-[1rem] text-start font-medium bg-[#09090B] border-b border-[#09090B]"> Forecast </th>
|
||||||
Forecast
|
|
||||||
</th>
|
|
||||||
{#each tableDataForecast as item}
|
{#each tableDataForecast as item}
|
||||||
<td class="text-white text-sm sm:text-[1rem] text-end font-medium border-b border-[#09090B]">
|
<td class="text-white text-sm sm:text-[1rem] text-end font-medium border-b border-[#09090B]">
|
||||||
{(item?.val === '0.00' || item?.val === null || item?.val === 0) ? '-' : abbreviateNumber(item?.val)}
|
{item?.val === "0.00" || item?.val === null || item?.val === 0 ? "-" : abbreviateNumber(item?.val.toFixed(2))}
|
||||||
</td>
|
</td>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr class="bg-[#27272A] border-b-[#27272A]">
|
<tr class="bg-[#27272A] border-b-[#27272A]">
|
||||||
<th class="bg-[#27272A] text-sm sm:text-[1rem] whitespace-nowrap text-white text-start font-medium bg-[#27272A] border-b border-[#27272A]">
|
<th class="bg-[#27272A] text-sm sm:text-[1rem] whitespace-nowrap text-white text-start font-medium bg-[#27272A] border-b border-[#27272A]"> Actual </th>
|
||||||
Actual
|
|
||||||
</th>
|
|
||||||
{#each tableDataActual as item}
|
{#each tableDataActual as item}
|
||||||
<td class="text-white text-sm sm:text-[1rem] text-end font-medium bg-[#27272A]">
|
<td class="text-white text-sm sm:text-[1rem] text-end font-medium bg-[#27272A]">
|
||||||
{(item?.val === '0.00' || item?.val === null || item?.val === 0) ? '-' : abbreviateNumber(item?.val)}
|
{item?.val === "0.00" || item?.val === null || item?.val === 0 ? "-" : abbreviateNumber(item?.val)}
|
||||||
</td>
|
</td>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr class="bg-[#09090B] border-b-[#09090B]">
|
<tr class="bg-[#09090B] border-b-[#09090B]">
|
||||||
<th class="bg-[#09090B] whitespace-nowrap text-sm sm:text-[1rem] text-white text-start font-medium border-b border-[#09090B]">
|
<th class="bg-[#09090B] whitespace-nowrap text-sm sm:text-[1rem] text-white text-start font-medium border-b border-[#09090B]"> % Change </th>
|
||||||
% Change
|
|
||||||
</th>
|
|
||||||
{#each tableDataActual as item, index}
|
{#each tableDataActual as item, index}
|
||||||
<td class="text-white text-sm sm:text-[1rem] text-end font-medium bg-[#09090B]">
|
<td class="text-white text-sm sm:text-[1rem] text-end font-medium bg-[#09090B]">
|
||||||
{#if index === 0 || tableDataActual?.length === 0}
|
{#if index === 0 || tableDataActual?.length === 0}
|
||||||
-
|
-
|
||||||
{:else}
|
{:else if item?.val === null}
|
||||||
{#if item?.val === null}
|
{#if tableDataForecast[index]?.val - tableDataForecast[index - 1]?.val > 0}
|
||||||
{#if (tableDataForecast[index]?.val - tableDataForecast[index-1]?.val) > 0}
|
|
||||||
<span class="text-orange-400">
|
<span class="text-orange-400">
|
||||||
{(((tableDataForecast[index]?.val - tableDataForecast[index-1]?.val) / Math.abs(tableDataForecast[index-1]?.val)) * 100 )?.toFixed(2)}%*
|
{(((tableDataForecast[index]?.val - tableDataForecast[index - 1]?.val) / Math.abs(tableDataForecast[index - 1]?.val)) * 100)?.toFixed(2)}%*
|
||||||
</span>
|
</span>
|
||||||
{:else if (tableDataForecast[index]?.val - tableDataForecast[index-1]?.val ) < 0}
|
{:else if tableDataForecast[index]?.val - tableDataForecast[index - 1]?.val < 0}
|
||||||
<span class="text-orange-400">
|
<span class="text-orange-400">
|
||||||
{(((tableDataForecast[index]?.val - tableDataForecast[index-1]?.val ) / Math.abs(tableDataForecast[index-1]?.val)) * 100 )?.toFixed(2)}%*
|
{(((tableDataForecast[index]?.val - tableDataForecast[index - 1]?.val) / Math.abs(tableDataForecast[index - 1]?.val)) * 100)?.toFixed(2)}%*
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
{:else if (item?.val - tableDataActual[index-1]?.val) > 0}
|
{:else if item?.val - tableDataActual[index - 1]?.val > 0}
|
||||||
<span class="text-[#10DB06]">
|
<span class="text-[#10DB06]">
|
||||||
{(((item?.val - tableDataActual[index-1]?.val) / Math.abs(tableDataActual[index-1]?.val)) * 100 )?.toFixed(2)}%
|
{(((item?.val - tableDataActual[index - 1]?.val) / Math.abs(tableDataActual[index - 1]?.val)) * 100)?.toFixed(2)}%
|
||||||
</span>
|
</span>
|
||||||
{:else if (item?.val - tableDataActual[index-1]?.val ) < 0}
|
{:else if item?.val - tableDataActual[index - 1]?.val < 0}
|
||||||
<span class="text-[#FF2F1F]">
|
<span class="text-[#FF2F1F]">
|
||||||
{(((item?.val - tableDataActual[index-1]?.val ) / Math.abs(tableDataActual[index-1]?.val)) * 100 )?.toFixed(2)}%
|
{(((item?.val - tableDataActual[index - 1]?.val) / Math.abs(tableDataActual[index - 1]?.val)) * 100)?.toFixed(2)}%
|
||||||
</span>
|
</span>
|
||||||
{:else}
|
{:else}
|
||||||
0.00%
|
0.00%
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
|
||||||
</td>
|
</td>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr class="bg-[#27272A] border-b-[#27272A]">
|
<tr class="bg-[#27272A] border-b-[#27272A]">
|
||||||
<th class="bg-[#27272A] whitespace-nowrap text-sm sm:text-[1rem] text-white text-start font-medium bg-[#27272A] border-b border-[#27272A]">
|
<th class="bg-[#27272A] whitespace-nowrap text-sm sm:text-[1rem] text-white text-start font-medium bg-[#27272A] border-b border-[#27272A]"> No. Analysts </th>
|
||||||
No. Analysts
|
|
||||||
</th>
|
|
||||||
{#each tableDataForecast as item}
|
{#each tableDataForecast as item}
|
||||||
<td class="text-white text-sm sm:text-[1rem] text-end font-medium bg-[#27272A]">
|
<td class="text-white text-sm sm:text-[1rem] text-end font-medium bg-[#27272A]">
|
||||||
{item?.numOfAnalysts === (null || 0) ? '-' : item?.numOfAnalysts}
|
{item?.numOfAnalysts === (null || 0) ? "-" : item?.numOfAnalysts}
|
||||||
</td>
|
</td>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-orange-400 text-xs sm:text-sm mt-2">
|
<div class="text-orange-400 text-xs sm:text-sm mt-2">* This value depends on the forecast</div>
|
||||||
* This value depends on the forecast
|
|
||||||
</div>
|
|
||||||
<div class="mt-5 text-gray-100 text-sm sm:text-[1rem] sm:rounded-lg h-auto border border-slate-800 p-4">
|
<div class="mt-5 text-gray-100 text-sm sm:text-[1rem] sm:rounded-lg h-auto border border-slate-800 p-4">
|
||||||
<svg class="w-5 h-5 inline-block mr-0.5 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><path fill="#a474f6" d="M128 24a104 104 0 1 0 104 104A104.11 104.11 0 0 0 128 24m-4 48a12 12 0 1 1-12 12a12 12 0 0 1 12-12m12 112a16 16 0 0 1-16-16v-40a8 8 0 0 1 0-16a16 16 0 0 1 16 16v40a8 8 0 0 1 0 16"/></svg>
|
<svg class="w-5 h-5 inline-block mr-0.5 flex-shrink-0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"
|
||||||
|
><path fill="#a474f6" d="M128 24a104 104 0 1 0 104 104A104.11 104.11 0 0 0 128 24m-4 48a12 12 0 1 1-12 12a12 12 0 0 1 12-12m12 112a16 16 0 0 1-16-16v-40a8 8 0 0 1 0-16a16 16 0 0 1 16 16v40a8 8 0 0 1 0 16" /></svg
|
||||||
|
>
|
||||||
For the current Fiscal Year we use available quarterly data. Complete annual data, used to compare against analyst estimates, is only finalized after the year ends.
|
For the current Fiscal Year we use available quarterly data. Complete annual data, used to compare against analyst estimates, is only finalized after the year ends.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex justify-center items-center h-80">
|
<div class="flex justify-center items-center h-80">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
@ -458,38 +390,32 @@ $: {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{:else}
|
{:else}
|
||||||
<div class="shadow-lg shadow-bg-[#000] bg-[#111112] sm:bg-opacity-[0.5] text-sm sm:text-[1rem] rounded-md w-full p-4 min-h-24 mt-4 text-white m-auto flex justify-center items-center text-center font-semibold">
|
<div class="shadow-lg shadow-bg-[#000] bg-[#111112] sm:bg-opacity-[0.5] text-sm sm:text-[1rem] rounded-md w-full p-4 min-h-24 mt-4 text-white m-auto flex justify-center items-center text-center font-semibold">
|
||||||
<svg class="mr-1.5 w-5 h-5 inline-block"xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#A3A3A3" d="M17 9V7c0-2.8-2.2-5-5-5S7 4.2 7 7v2c-1.7 0-3 1.3-3 3v7c0 1.7 1.3 3 3 3h10c1.7 0 3-1.3 3-3v-7c0-1.7-1.3-3-3-3M9 7c0-1.7 1.3-3 3-3s3 1.3 3 3v2H9z"/></svg>
|
<svg class="mr-1.5 w-5 h-5 inline-block" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
|
||||||
Unlock content with <a class="inline-block ml-2 text-blue-400 hover:sm:text-white" href="/pricing">Pro Subscription</a>
|
><path fill="#A3A3A3" d="M17 9V7c0-2.8-2.2-5-5-5S7 4.2 7 7v2c-1.7 0-3 1.3-3 3v7c0 1.7 1.3 3 3 3h10c1.7 0 3-1.3 3-3v-7c0-1.7-1.3-3-3-3M9 7c0-1.7 1.3-3 3-3s3 1.3 3 3v2H9z" /></svg
|
||||||
|
>
|
||||||
|
Unlock content with
|
||||||
|
<a class="inline-block ml-2 text-blue-400 hover:sm:text-white" href="/pricing">Pro Subscription</a>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.app {
|
||||||
|
height: 300px;
|
||||||
|
max-width: 100%; /* Ensure chart width doesn't exceed the container */
|
||||||
|
}
|
||||||
|
|
||||||
.app {
|
@media (max-width: 640px) {
|
||||||
height: 300px;
|
.app {
|
||||||
max-width: 100%; /* Ensure chart width doesn't exceed the container */
|
height: 210px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.app {
|
|
||||||
height: 210px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user