add tooltip to graphs

This commit is contained in:
MuslemRahimi 2024-09-23 18:03:15 +02:00
parent 214b98eb67
commit e2d8934fe7
5 changed files with 110 additions and 179 deletions

View File

@ -127,6 +127,7 @@ function findLowestAndHighestFee(data, lastDateStr) {
], ],
series: [ series: [
{ {
name: 'Available Shares',
data: availableList, data: availableList,
type: 'line', type: 'line',
itemStyle: { itemStyle: {
@ -135,6 +136,7 @@ function findLowestAndHighestFee(data, lastDateStr) {
showSymbol: false showSymbol: false
}, },
{ {
name: 'Fee [%]',
data: feeList, data: feeList,
type: 'line', type: 'line',
areaStyle: {opacity: 1}, areaStyle: {opacity: 1},

View File

@ -94,7 +94,7 @@
> >
<div <div
class="circle" class="circle"
style="left:{d.x}px;top:{d.y}px;width:{d.r * ballSize}px;height:{d.r * ballSize}px;background-color:{(index === 1 && d.data.id === 'puts') ? '#FF2F1F' : (index === 1 && d.data.id === 'calls') ? '#0FB307' : '#1E1E1E'}; border: 0px solid #000;" style="left:{d.x}px;top:{d.y}px;width:{d.r * ballSize}px;height:{d.r * ballSize}px;background-color:{(index === 1 && d.data.id === 'puts') ? '#FF2F1F' : (index === 1 && d.data.id === 'calls') ? '#37C97D' : '#1E1E1E'}; border: 0px solid #000;"
/> />
<div <div
class="text-group" class="text-group"

View File

@ -110,6 +110,7 @@ function getPlotOptions() {
], ],
series: [ series: [
{ {
name: 'Total Volume',
data: totalVolumeList, data: totalVolumeList,
type: 'line', type: 'line',
itemStyle: { itemStyle: {
@ -118,12 +119,12 @@ function getPlotOptions() {
showSymbol: false showSymbol: false
}, },
{ {
name: 'Short Volume',
data: shortVolumeList, data: shortVolumeList,
type: 'line', type: 'line',
areaStyle: {opacity: 1}, areaStyle: {opacity: 1},
itemStyle: { itemStyle: {
color: '#3B82F6' // Change bar color to white color: '#E11D48' // Change bar color to white
}, },
showSymbol: false showSymbol: false
}, },
@ -232,7 +233,7 @@ $: {
</div> </div>
<div class="flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center"> <div class="flex flex-col sm:flex-row items-center ml-3 sm:ml-0 w-1/2 justify-center">
<div class="h-full transform -translate-x-1/2 " aria-hidden="true"></div> <div class="h-full transform -translate-x-1/2 " aria-hidden="true"></div>
<div class="w-3 h-3 bg-[#536FC5] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2" aria-hidden="true"></div> <div class="w-3 h-3 bg-[#E11D48] border-4 box-content border-[#27272A] rounded-full transform sm:-translate-x-1/2" aria-hidden="true"></div>
<span class="mt-2 sm:mt-0 text-white text-xs sm:text-md sm:font-medium inline-block"> <span class="mt-2 sm:mt-0 text-white text-xs sm:text-md sm:font-medium inline-block">
Short Volume Short Volume
</span> </span>

View File

@ -6,14 +6,13 @@
import { BarChart } from 'echarts/charts' import { BarChart } 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 { monthNames} from '$lib/utils';
export let data; export let data;
use([BarChart, GridComponent, TooltipComponent, CanvasRenderer]) use([BarChart, GridComponent, TooltipComponent, CanvasRenderer])
const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
let isLoaded = false; let isLoaded = false;
@ -22,25 +21,6 @@
let sentiment; let sentiment;
function normalizer(value) {
if (Math?.abs(value) >= 1e18) {
return { unit: 'Q', denominator: 1e18 };
} else if (Math?.abs(value) >= 1e12) {
return { unit: 'T', denominator: 1e12 };
} else if (Math?.abs(value) >= 1e9) {
return { unit: 'B', denominator: 1e9 };
} else if (Math?.abs(value) >= 1e6) {
return { unit: 'M', denominator: 1e6 };
} else if (Math?.abs(value) >= 1e5) {
return { unit: 'K', denominator: 1e5 };
} else if (Math?.abs(value) >= 1e4) {
return { unit: 'K', denominator: 1e4 };
} else {
return { unit: '', denominator: 1 };
}
}
function getPlotOptions() { function getPlotOptions() {
let dates = []; let dates = [];
let priceList = []; let priceList = [];
@ -59,7 +39,6 @@
sentiment = netCallList?.slice(-1)?.at(0) > netPutList?.slice(-1)?.at(0) ? 'bullish' : 'bearish'; sentiment = netCallList?.slice(-1)?.at(0) > netPutList?.slice(-1)?.at(0) ? 'bullish' : 'bearish';
const {unit, denominator } = normalizer(Math.max(...netCallList) ?? 0)
const option = { const option = {
silent: true, silent: true,
@ -69,8 +48,8 @@
}, },
animation: false, animation: false,
grid: { grid: {
left: '1%', left: '3%',
right: '2%', right: '3%',
bottom: '0%', bottom: '0%',
top: '10%', top: '10%',
containLabel: true containLabel: true
@ -100,18 +79,10 @@
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 show: false // Hide y-axis labels
formatter: function (value, index) {
// Display every second tick
if (index % 2 === 0) {
//value = Math.max(value, 0);
return '$'+(value / denominator)?.toFixed(0) + unit; // Format value in millions
} else {
return ''; // Hide this tick
} }
}
},
}, },
], ],
@ -254,7 +225,6 @@
</div> </div>
{/if} {/if}
{:else} {:else}

View File

@ -1,115 +1,80 @@
<script lang ='ts'> <script lang="ts">
import { abbreviateNumber } from "$lib/utils"; import { abbreviateNumber } from "$lib/utils";
import { swapComponent, stockTicker, screenWidth, getCache, setCache } from '$lib/store'; import { swapComponent, 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 { BarChart } 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';
export let data; export let data: any; // Add type for `data` if possible
use([BarChart, GridComponent, TooltipComponent, CanvasRenderer]) use([ScatterChart, GridComponent, TooltipComponent, CanvasRenderer]);
let isLoaded = false; let isLoaded = false;
const tabs = [ const tabs = [
{ { title: "Effective Date" },
title: "Effective Date", { title: "Expiration Date" },
},
{
title: "Expiration Date",
}
]; ];
let activeIdx = 0; let activeIdx = 0;
function changeTab(index: number) {
function changeTab(index) {
activeIdx = index; activeIdx = index;
optionsData = getPlotOptions(activeIdx === 0 ? 'effectiveDate' : 'expirationDate'); optionsData = getPlotOptions(activeIdx === 0 ? 'effectiveDate' : 'expirationDate');
} }
let rawData = []; let rawData: any[] = [];
let optionsData; let optionsData: any;
let avgNotionalAmount; let avgNotionalAmount: number | undefined;
let avgNotionalQuantity; let avgNotionalQuantity: number | undefined;
function normalizer(value) { function getPlotOptions(state: 'effectiveDate' | 'expirationDate') {
if (Math?.abs(value) >= 1e18) { const combinedData = rawData?.map((item) => ({
return { unit: 'Q', denominator: 1e18 };
} else if (Math?.abs(value) >= 1e12) {
return { unit: 'T', denominator: 1e12 };
} else if (Math?.abs(value) >= 1e9) {
return { unit: 'B', denominator: 1e9 };
} else if (Math?.abs(value) >= 1e6) {
return { unit: 'M', denominator: 1e6 };
} else if (Math?.abs(value) >= 1e5) {
return { unit: 'K', denominator: 1e3 };
} else if (Math?.abs(value) >= 1e4) {
return { unit: 'K', denominator: 1e3 };
} else {
return { unit: '', denominator: 1 };
}
}
function getPlotOptions(state) {
const combinedData = rawData?.map(item => ({
date: state === 'effectiveDate' ? item['Effective Date'] : item['Expiration Date'], date: state === 'effectiveDate' ? item['Effective Date'] : item['Expiration Date'],
notionalAmount: item['Notional amount-Leg 1'], notionalAmount: item['Notional amount-Leg 1'],
notionalQuantity: item['Total notional quantity-Leg 1'] notionalQuantity: item['Total notional quantity-Leg 1'],
})); }));
// Group data by date and sum the values // Group data by date and sum the values
const groupedData = combinedData.reduce((acc, curr) => { const groupedData = combinedData.reduce((acc, curr) => {
const { date, notionalAmount, notionalQuantity } = curr; const { date, notionalAmount, notionalQuantity } = curr;
// If the date already exists in the accumulator, sum up the values
if (acc[date]) { if (acc[date]) {
acc[date].notionalAmount += notionalAmount; acc[date].notionalAmount += notionalAmount;
acc[date].notionalQuantity += notionalQuantity; acc[date].notionalQuantity += notionalQuantity;
} else { } else {
// Otherwise, create a new entry for this date
acc[date] = { acc[date] = {
date, date,
notionalAmount, notionalAmount,
notionalQuantity notionalQuantity,
}; };
} }
return acc; return acc;
}, {}); }, {} as Record<string, any>);
// Convert the grouped data back to an array
const result = Object.values(groupedData); const result = Object.values(groupedData);
// Sort the result array based on the date result?.sort((a, b) => new Date(a?.date).getTime() - new Date(b?.date).getTime());
result?.sort((a, b) => new Date(a?.date) - new Date(b?.date));
// Separate the sorted data back into individual arrays const dates = result?.map((item) => item?.date);
const dates = result?.map(item => item?.date); const notionalAmount = result?.map((item) => item?.notionalAmount);
const notionalAmount = result?.map(item => item?.notionalAmount); const notionalQuantity = result?.map((item) => item?.notionalQuantity);
const notionalQuantity = result?.map(item => item?.notionalQuantity);
// Compute the average of item?.traded
const totalNotionalAmount = notionalAmount?.reduce((acc, item) => acc + item, 0); const totalNotionalAmount = notionalAmount?.reduce((acc, item) => acc + item, 0);
avgNotionalAmount = totalNotionalAmount / notionalAmount?.length; avgNotionalAmount = totalNotionalAmount / notionalAmount?.length;
const totalNotionalQuantity = notionalQuantity?.reduce((acc, item) => acc + item, 0); const totalNotionalQuantity = notionalQuantity?.reduce((acc, item) => acc + item, 0);
avgNotionalQuantity = totalNotionalQuantity / notionalQuantity?.length; avgNotionalQuantity = totalNotionalQuantity / notionalQuantity?.length;
const option = { const option = {
silent: true, silent: true,
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
hideDelay: 100, // Set the delay in milliseconds hideDelay: 100,
}, },
animation: false, animation: false,
grid: { grid: {
@ -117,79 +82,74 @@
right: '3%', right: '3%',
bottom: '0%', bottom: '0%',
top: '10%', top: '10%',
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,
}, },
axisLabel: { axisLabel: {
show: false // Hide y-axis labels show: false,
} },
}, },
{ {
type: 'value', type: 'value',
splitLine: { splitLine: {
show: false, // Disable x-axis grid lines show: false,
}, },
position: 'right', position: 'right',
axisLabel: { axisLabel: {
show: false // Hide y-axis labels show: false,
}, },
}, },
], ],
series: [ series: [
{ {
name: 'Notional Amount', name: 'Notional Amount',
type: 'bar', type: 'scatter',
data: notionalAmount, data: dates?.map((date, index) => [date, notionalAmount[index]]),
barWidth: '50%',
itemStyle: { itemStyle: {
color: '#8F54F4' color: '#8F54F4',
} },
}, },
{ {
name: 'Notional Quantity', name: 'Notional Quantity',
type: 'bar', type: 'scatter',
data: notionalQuantity, data: dates?.map((date, index) => [date, notionalQuantity[index]]),
barWidth: '50%',
yAxisIndex: 1, yAxisIndex: 1,
itemStyle: { itemStyle: {
color: '#FF9E21' color: '#FF9E21',
} },
} },
] ],
}; };
return option; return option;
} }
async function getSwapData(ticker) { async function getSwapData(ticker: string) {
const cachedData = getCache(ticker, 'getSwapData'); const cachedData = getCache(ticker, 'getSwapData');
if (cachedData) { if (cachedData) {
rawData = cachedData; rawData = cachedData;
} else { } else {
try { try {
const postData = {ticker: ticker, path: 'swap-ticker'} const postData = { ticker, path: 'swap-ticker' };
const response = await fetch('/api/ticker-data', { const response = await fetch('/api/ticker-data', {
method: 'POST', method: 'POST',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json',
}, },
body: JSON.stringify(postData) body: JSON.stringify(postData),
}); });
if (!response.ok) throw new Error('API request failed'); if (!response.ok) throw new Error('API request failed');
rawData = await response.json(); rawData = await response.json();
@ -199,7 +159,7 @@
rawData = []; rawData = [];
} }
} }
$swapComponent = rawData?.length !== 0; $swapComponent = rawData?.length !== 0; // Correct the use of `$`
} }
$: if ($stockTicker && typeof window !== 'undefined') { $: if ($stockTicker && typeof window !== 'undefined') {
@ -211,12 +171,10 @@
}); });
} }
$: charNumber = $screenWidth < 640 ? 20 : 40; $: charNumber = $screenWidth < 640 ? 20 : 40;
</script> </script>
<svelte:options immutable={true} />
<section class="overflow-hidden text-white h-full pb-8"> <section class="overflow-hidden text-white h-full pb-8">