This commit is contained in:
MuslemRahimi 2025-02-24 19:43:27 +01:00
parent 2dfad5dd84
commit d001f2dac1

View File

@ -4,11 +4,13 @@
import SEO from "$lib/components/SEO.svelte"; import SEO from "$lib/components/SEO.svelte";
import { setCache, getCache } from "$lib/store"; import { setCache, getCache } from "$lib/store";
import { onDestroy } from "svelte"; import { onDestroy } from "svelte";
import toast from "svelte-french-toast";
export let data; export let data;
let isLoaded = false;
let rawData = data?.getData; let rawData = data?.getData;
let iframe: HTMLIFrameElement; let iframe: HTMLIFrameElement;
let iframeLoaded = false;
let selectedFormat: "png" | "jpeg" | "svg" = "png"; let selectedFormat: "png" | "jpeg" | "svg" = "png";
let selectedTimePeriod = "1D"; let selectedTimePeriod = "1D";
let iframeUrl: string; let iframeUrl: string;
@ -36,6 +38,10 @@
} }
async function downloadPlot(item) { async function downloadPlot(item) {
return toast.promise(
(async () => {
let selectedFormat;
if (item === "PNG") { if (item === "PNG") {
selectedFormat = "png"; selectedFormat = "png";
} else if (item === "JPG") { } else if (item === "JPG") {
@ -44,39 +50,39 @@
selectedFormat = "svg"; selectedFormat = "svg";
} }
if (!iframe || !iframeLoaded) return; if (!iframe || !isLoaded) throw new Error("Iframe not ready");
try {
const iframeWindow = iframe.contentWindow; const iframeWindow = iframe.contentWindow;
if (!iframeWindow) return; if (!iframeWindow) throw new Error("Iframe window not available");
const Plotly = (iframeWindow as any).Plotly; const Plotly = iframeWindow.Plotly;
if (!Plotly) throw new Error("Plotly not found in iframe"); if (!Plotly) throw new Error("Plotly not found in iframe");
const plotDiv = const plotDiv =
iframe.contentDocument?.querySelector(".plotly-graph-div"); iframe.contentDocument?.querySelector(".plotly-graph-div");
if (!plotDiv) throw new Error("Plotly div not found"); if (!plotDiv) throw new Error("Plotly div not found");
// Configure image options based on format
const options = { const options = {
format: selectedFormat, format: selectedFormat,
width: 1200, width: 1200,
height: 800, height: 800,
}; };
// Get image data URL
const imageData = await Plotly.toImage(plotDiv, options); const imageData = await Plotly.toImage(plotDiv, options);
// Create download link
const link = document.createElement("a"); const link = document.createElement("a");
link.href = imageData; link.href = imageData;
link.download = `sp500-heatmap-${selectedTimePeriod}`; link.download = `sp500-heatmap-${selectedTimePeriod}`;
document.body.appendChild(link); document.body.appendChild(link);
link.click(); link.click();
document.body.removeChild(link); document.body.removeChild(link);
} catch (error) { })(),
console.error("Download failed:", error); {
} loading: "Downloading heatmap...",
success: "Heatmap downloaded!",
error: "Download failed. Try again.",
},
);
} }
onDestroy(() => { onDestroy(() => {
@ -86,16 +92,14 @@
$: { $: {
if (selectedTimePeriod && typeof window !== "undefined") { if (selectedTimePeriod && typeof window !== "undefined") {
(async () => { (async () => {
await getHeatMap(); isLoaded = false;
getHeatMap();
isLoaded = true;
})(); })();
} }
} }
</script> </script>
<svelte:head>
<script src="https://cdn.plot.ly/plotly-2.18.0.min.js" defer></script>
</svelte:head>
<SEO <SEO
title="S&P 500 Stock Market Heatmap" title="S&P 500 Stock Market Heatmap"
description="A stock market heatmap showing the performance of the individual stocks, sectors and industries in the S&P500." description="A stock market heatmap showing the performance of the individual stocks, sectors and industries in the S&P500."
@ -212,7 +216,7 @@
<div class="flex items-center"> <div class="flex items-center">
<button <button
on:click={() => downloadPlot(item)} on:click={() => downloadPlot(item)}
disabled={!iframeLoaded} disabled={!isLoaded}
class="cursor-pointer text-white" class="cursor-pointer text-white"
> >
<span class="mr-8">Download {item}</span> <span class="mr-8">Download {item}</span>
@ -226,14 +230,27 @@
</div> </div>
</div> </div>
<div class="w-full min-h-screen bg-[#09090B] overflow-hidden"> <div class="w-full min-h-screen bg-[#09090B] overflow-hidden">
{#if isLoaded}
{#if rawData} {#if rawData}
<iframe <iframe
bind:this={iframe} bind:this={iframe}
src={iframeUrl} src={iframeUrl}
class="w-full h-screen border-none" class="w-full h-screen border-none"
on:load={() => (iframeLoaded = true)}
/> />
{/if} {/if}
{:else}
<div class="flex justify-center items-center h-80">
<div class="relative">
<label
class="bg-secondary rounded-md h-14 w-14 flex justify-center items-center absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"
>
<span
class="loading loading-spinner loading-md text-gray-400"
></span>
</label>
</div>
</div>
{/if}
</div> </div>
</main> </main>
</div> </div>