@@ -9,14 +9,13 @@ import React, { useEffect, useRef, useState } from 'react'
99import { renderToStaticMarkup } from 'react-dom/server'
1010import { default as VegaEmbed } from 'vega-embed'
1111
12- import PopoverMenu from '../../menu/popoverMenu'
12+ import PopoverMenu , { type PopoverMenuItem } from '../../menu/popoverMenu'
1313import type { VegaLiteData } from '../../types'
1414
1515/** The `VegaLiteViz` component is a versatile tool for visualizing data using the Vega-Lite grammar. With support for various graphic types, it empowers users to create engaging and informative data visualizations effortlessly. */
1616function VegaLiteViz ( props : VegaLiteData ) {
1717 const chartRef = useRef < HTMLDivElement > ( null )
1818 const [ hasError , setHasError ] = useState < boolean > ( false )
19- const [ downloadUrls , setDownloadUrls ] = useState < downloadUrls > ( )
2019
2120 const rusticTheme : Theme = useTheme ( )
2221 const isDarkTheme = rusticTheme . palette . mode === 'dark'
@@ -53,38 +52,19 @@ function VegaLiteViz(props: VegaLiteData) {
5352 id : 'rustic-vega-lite-tooltip' ,
5453 }
5554
56- function handleDownload (
57- format : 'svg' | 'png' ,
58- url ?: string ,
59- fileName ?: string
60- ) {
61- if ( url ) {
62- // Create a temporary anchor element
63- const link = document . createElement ( 'a' )
64- const downloadFileName = fileName || 'visualization'
65-
66- link . href = url
67- link . download = `${ downloadFileName } .${ format } `
68-
69- document . body . appendChild ( link )
70- link . click ( )
71- document . body . removeChild ( link )
72- }
73- }
74-
75- const menuItem = [
55+ const menuItems : PopoverMenuItem [ ] = [
7656 {
7757 label : 'Save as SVG' ,
78- onClick : ( ) => handleDownload ( 'svg' ) ,
7958 } ,
8059 {
8160 label : 'Save as PNG' ,
82- onClick : ( ) => handleDownload ( 'png' ) ,
8361 } ,
8462 ]
8563
86- function getScaleFactor ( format : 'svg' | 'png' ) {
87- const scaleFactor = props . options ?. scaleFactor
64+ function getScaleFactor (
65+ format : 'svg' | 'png' ,
66+ scaleFactor : number | { svg ?: number ; png ?: number } | undefined
67+ ) {
8868 if ( scaleFactor ) {
8969 if ( typeof scaleFactor === 'number' ) {
9070 return scaleFactor
@@ -110,15 +90,24 @@ function VegaLiteViz(props: VegaLiteData) {
11090
11191 VegaEmbed ( chartRef . current , props . spec , options )
11292 . then ( ( result ) => {
113- result . view . toImageURL ( 'svg' , getScaleFactor ( 'svg' ) ) . then ( ( url ) => {
114- menuItem [ 0 ] . onClick = ( ) =>
115- handleDownload ( 'svg' , url , options . downloadFileName )
93+ const scaleFactor = result . embedOptions . scaleFactor
94+ typeof scaleFactor === 'number' ? scaleFactor : scaleFactor ?. svg
95+ const fileName =
96+ result . embedOptions . downloadFileName || 'visualization'
97+ const formats = [ 'svg' , 'png' ]
98+
99+ formats . map ( ( format , index ) => {
100+ result . view
101+ . toImageURL (
102+ format ,
103+ getScaleFactor ( format as 'svg' | 'png' , scaleFactor )
104+ )
105+ . then ( ( url ) => {
106+ menuItems [ index ] . href = url
107+ menuItems [ index ] . downloadFileName = fileName
108+ } )
116109 } )
117110
118- result . view . toImageURL ( 'png' , getScaleFactor ( 'png' ) ) . then ( ( url ) => {
119- menuItem [ 1 ] . onClick = ( ) =>
120- handleDownload ( 'png' , url , options . downloadFileName )
121- } )
122111 setHasError ( false )
123112 } )
124113 . catch ( ( ) => {
@@ -147,7 +136,7 @@ function VegaLiteViz(props: VegaLiteData) {
147136 return (
148137 < Stack direction = "column" className = "rustic-vega-lite-container" >
149138 < Box justifyContent = "end" display = "flex" >
150- < PopoverMenu menuItems = { menuItem } ariaLabel = "menu" />
139+ < PopoverMenu menuItems = { menuItems } ariaLabel = "menu" />
151140 </ Box >
152141
153142 { props . title && (
0 commit comments