#Animation
Les animations de VSeed prennent en charge les étapes d'apparition, de boucle, d'ambiance, de mise à jour et de sortie. Ce guide regroupe des exemples pour les graphiques à barres, lignes/aires, secteurs, radar et nuage de points afin de comparer les configurations selon les types de graphiques.
#Animation des graphiques barres / colonnes
Tous les exemples reposent sur le thème grand écran (sombre) et proposent une liste déroulante pour changer de thème.
Les thèmes sont chargés depuis : https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json
#1. Animation d'apparition
L'animation d'apparition est le mouvement joué lorsque le graphique entre pour la première fois dans la vue.
Pour les séries barres/colonnes, l'effet d'apparition prend actuellement en charge growth.
#1.1 growth (croissance)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes } from '@visactor/vseed'
const THEME_URL = 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
const DIMENSIONS = [
{ id: 'HqlYadRdHJ5c', alias: 'Category' },
{ id: '7ti8XuX4kcY1', alias: 'Year' },
]
const MEASURES = [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }]
const useLargeScreenThemes = () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
fetch(THEME_URL)
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
const firstKey = Object.keys(remote)[0] || ''
setThemeKey(firstKey)
})
.catch(() => {})
}, [])
return { themes, themeKey, setThemeKey }
}
const ThemeSelect = ({ themes, themeKey, onChange }) => (
<select
value={themeKey}
onChange={(e) => onChange(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
)
export default () => {
const { themes, themeKey, setThemeKey } = useLargeScreenThemes()
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'columnParallel',
dataset: DATASET,
dimensions: DIMENSIONS,
measures: MEASURES,
label: { enable: false },
animation: {
enable: true,
params: {
appear: { enable: true, effects: ['growth'], ease: 'circInOut', duration: 1 },
},
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<ThemeSelect themes={themes} themeKey={themeKey} onChange={setThemeKey} />
<VSeedRender vseed={vseedConfig} />
</div>
)
}#2. Animation en boucle
L'animation en boucle est le mouvement continu après le rendu initial, utile pour mettre en évidence ou maintenir un rythme dynamique.
#2.1 highlight (mise en évidence de groupe) + atmosphere (effet d'ambiance)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes } from '@visactor/vseed'
const THEME_URL = 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
export default () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json')
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'columnParallel',
dataset: DATASET,
dimensions: [
{ id: 'HqlYadRdHJ5c', alias: 'Category' },
{ id: '7ti8XuX4kcY1', alias: 'Year' },
],
measures: [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }],
label: { enable: false },
animation: {
enable: true,
params: {
appear: { enable: true, effects: ['growth'], ease: 'linear', duration: 1 },
loop: {
enable: true,
interval: 3,
loop: { enable: true, effects: ['highLight'], ease: 'linear', duration: 1 },
atmosphere: { effect: 'breath', ease: 'linear', color: '#4A90E2' },
},
},
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<select
value={themeKey}
onChange={(e) => setThemeKey(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
<VSeedRender vseed={vseedConfig} />
</div>
)
}#2.2 growth (boucle) + atmosphere (effet d'ambiance)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes } from '@visactor/vseed'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
export default () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json')
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'barParallel',
dataset: DATASET,
dimensions: [
{ id: 'HqlYadRdHJ5c', alias: 'Category' },
{ id: '7ti8XuX4kcY1', alias: 'Year' },
],
measures: [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }],
label: { enable: false },
animation: {
enable: true,
params: {
appear: { enable: true, effects: ['growth'], ease: 'linear', duration: 1 },
loop: {
enable: true,
interval: 2,
loop: { enable: true, effects: ['growth'], ease: 'linear', duration: 1 },
atmo: { effect: 'breath', ease: 'linear', color: '#4A90E2' },
},
},
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<select
value={themeKey}
onChange={(e) => setThemeKey(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
<VSeedRender vseed={vseedConfig} />
</div>
)
}#2.3 moveIn (boucle) + atmosphere (effet d'ambiance)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes } from '@visactor/vseed'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
export default () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json')
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'columnParallel',
dataset: DATASET,
dimensions: [
{ id: 'HqlYadRdHJ5c', alias: 'Category' },
{ id: '7ti8XuX4kcY1', alias: 'Year' },
],
measures: [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }],
label: { enable: false },
animation: {
enable: true,
params: {
appear: { enable: true, effects: ['growth'], ease: 'linear', duration: 1 },
loop: {
enable: true,
interval: 2,
loop: { enable: true, effects: ['moveIn'], ease: 'linear', duration: 1 },
atmo: { effect: 'breath', ease: 'linear', color: '#4A90E2' },
},
},
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<select
value={themeKey}
onChange={(e) => setThemeKey(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
<VSeedRender vseed={vseedConfig} />
</div>
)
}#Animation des graphiques ligne / aire
Tous les exemples reposent sur le thème grand écran (sombre) et proposent une liste déroulante pour changer de thème.
Les thèmes sont chargés depuis : https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json
#1. Animation d'apparition
L'animation d'apparition introduit visuellement le graphique lorsqu'il entre pour la première fois dans la page.
#1.1 load (chargement)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes, Builder } from '@visactor/vseed'
const THEME_URL = 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
const DIMENSIONS = [
{ id: 'HqlYadRdHJ5c', alias: 'Category' },
{ id: '7ti8XuX4kcY1', alias: 'Year' },
]
const MEASURES = [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }]
const useLargeScreenThemes = () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
Builder.updateSpec('line', (spec) => ({
...spec,
point: { ...spec.point, style: { ...(spec.point && spec.point.style), lineWidth: 0, stroke: null } },
}))
Builder.updateSpec('area', (spec) => ({
...spec,
point: { ...spec.point, style: { ...(spec.point && spec.point.style), lineWidth: 0, stroke: null } },
}))
Builder.updateSpec('areaPercent', (spec) => ({
...spec,
point: { ...spec.point, style: { ...(spec.point && spec.point.style), lineWidth: 0, stroke: null } },
}))
fetch(THEME_URL)
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
return { themes, themeKey, setThemeKey }
}
const ThemeSelect = ({ themes, themeKey, onChange }) => (
<select
value={themeKey}
onChange={(e) => onChange(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
)
export default () => {
const { themes, themeKey, setThemeKey } = useLargeScreenThemes()
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'line',
dataset: DATASET,
dimensions: DIMENSIONS,
measures: MEASURES,
label: { enable: false },
animation: {
enable: true,
params: { appear: { enable: true, effects: ['load'], ease: 'circInOut', duration: 1 } },
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<ThemeSelect themes={themes} themeKey={themeKey} onChange={setThemeKey} />
<VSeedRender vseed={vseedConfig} />
</div>
)
}#1.2 growth (croissance)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes, Builder } from '@visactor/vseed'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
export default () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
Builder.updateSpec('line', (spec) => ({
...spec,
point: { ...spec.point, style: { ...(spec.point && spec.point.style), lineWidth: 0, stroke: null } },
}))
Builder.updateSpec('area', (spec) => ({
...spec,
point: { ...spec.point, style: { ...(spec.point && spec.point.style), lineWidth: 0, stroke: null } },
}))
Builder.updateSpec('areaPercent', (spec) => ({
...spec,
point: { ...spec.point, style: { ...(spec.point && spec.point.style), lineWidth: 0, stroke: null } },
}))
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json')
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'area',
dataset: DATASET,
dimensions: [
{ id: 'HqlYadRdHJ5c', alias: 'Category' },
{ id: '7ti8XuX4kcY1', alias: 'Year' },
],
measures: [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }],
label: { enable: false },
animation: {
enable: true,
params: { appear: { enable: true, effects: ['growth'], ease: 'linear', duration: 1 } },
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<select
value={themeKey}
onChange={(e) => setThemeKey(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
<VSeedRender vseed={vseedConfig} />
</div>
)
}#2. Animation en boucle
L'animation en boucle maintient le graphique dans un mouvement cyclique pour les affichages de longue durée.
#2.1 load (boucle) + atmosphere (breath)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes, Builder } from '@visactor/vseed'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
export default () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
Builder.updateSpec('line', (spec) => ({
...spec,
point: { ...spec.point, style: { ...(spec.point && spec.point.style), lineWidth: 0, stroke: null } },
}))
Builder.updateSpec('area', (spec) => ({
...spec,
point: { ...spec.point, style: { ...(spec.point && spec.point.style), lineWidth: 0, stroke: null } },
}))
Builder.updateSpec('areaPercent', (spec) => ({
...spec,
point: { ...spec.point, style: { ...(spec.point && spec.point.style), lineWidth: 0, stroke: null } },
}))
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json')
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'line',
dataset: DATASET,
dimensions: [
{ id: 'HqlYadRdHJ5c', alias: 'Category' },
{ id: '7ti8XuX4kcY1', alias: 'Year' },
],
measures: [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }],
label: { enable: false },
animation: {
enable: true,
params: {
appear: { enable: true, effects: ['load'], ease: 'linear', duration: 1 },
loop: {
enable: true,
interval: 2,
loop: { enable: true, effects: ['load'], ease: 'linear', duration: 1 },
atmosphere: { effect: 'breath', ease: 'linear' },
},
},
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<select
value={themeKey}
onChange={(e) => setThemeKey(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
<VSeedRender vseed={vseedConfig} />
</div>
)
}#2.2 load (boucle) + atmosphere (ripple)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes, Builder } from '@visactor/vseed'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
export default () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
Builder.updateSpec('line', (spec) => ({
...spec,
point: { ...spec.point, style: { ...(spec.point && spec.point.style), lineWidth: 0, stroke: null } },
}))
Builder.updateSpec('area', (spec) => ({
...spec,
point: { ...spec.point, style: { ...(spec.point && spec.point.style), lineWidth: 0, stroke: null } },
}))
Builder.updateSpec('areaPercent', (spec) => ({
...spec,
point: { ...spec.point, style: { ...(spec.point && spec.point.style), lineWidth: 0, stroke: null } },
}))
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json')
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'areaPercent',
dataset: DATASET,
dimensions: [
{ id: 'HqlYadRdHJ5c', alias: 'Category' },
{ id: '7ti8XuX4kcY1', alias: 'Year' },
],
measures: [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }],
label: { enable: false },
animation: {
enable: true,
params: {
appear: { enable: true, effects: ['growth'], ease: 'linear', duration: 1 },
loop: {
enable: true,
interval: 3,
loop: { enable: true, effects: ['load'], ease: 'circInOut', duration: 1 },
atmosphere: { effect: 'ripple', ease: 'linear' },
},
},
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<select
value={themeKey}
onChange={(e) => setThemeKey(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
<VSeedRender vseed={vseedConfig} />
</div>
)
}#Animation des graphiques secteurs / anneau / rose
Tous les exemples reposent sur le thème grand écran (sombre) et proposent une liste déroulante pour changer de thème.
Les thèmes sont chargés depuis : https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json
#1. Animation d'apparition
L'animation d'apparition contrôle la première entrée des secteurs dans la vue.
#1.1 radial (depuis le centre)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes } from '@visactor/vseed'
const THEME_URL = 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
const DIMENSIONS = [{ id: 'HqlYadRdHJ5c', alias: 'Category' }]
const MEASURES = [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }]
const useLargeScreenThemes = () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
fetch(THEME_URL)
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
return { themes, themeKey, setThemeKey }
}
const ThemeSelect = ({ themes, themeKey, onChange }) => (
<select
value={themeKey}
onChange={(e) => onChange(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
)
export default () => {
const { themes, themeKey, setThemeKey } = useLargeScreenThemes()
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'pie',
dataset: DATASET,
dimensions: DIMENSIONS,
measures: MEASURES,
label: { enable: false },
animation: {
enable: true,
params: { appear: { enable: true, effects: ['radial'], ease: 'circInOut', duration: 1 } },
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<ThemeSelect themes={themes} themeKey={themeKey} onChange={setThemeKey} />
<VSeedRender vseed={vseedConfig} />
</div>
)
}#1.2 scale (mise à l'échelle)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes } from '@visactor/vseed'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
export default () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json')
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'donut',
dataset: DATASET,
dimensions: [{ id: 'HqlYadRdHJ5c', alias: 'Category' }],
measures: [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }],
label: { enable: false },
animation: {
enable: true,
params: { appear: { enable: true, effects: ['scale'], ease: 'circInOut', duration: 1 } },
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<select
value={themeKey}
onChange={(e) => setThemeKey(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
<VSeedRender vseed={vseedConfig} />
</div>
)
}#2. Animation en boucle
L'animation en boucle continue de mettre certains secteurs en évidence de façon périodique.
#2.1 enlarge (modifier la taille)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes } from '@visactor/vseed'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
export default () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json')
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'pie',
dataset: DATASET,
dimensions: [{ id: 'HqlYadRdHJ5c', alias: 'Category' }],
measures: [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }],
label: { enable: false },
animation: {
enable: true,
params: {
appear: { enable: true, effects: ['scale'], ease: 'linear', duration: 1 },
loop: { enable: true, interval: 2, loop: { enable: true, effects: ['enlarge'], ease: 'linear', duration: 1 } },
},
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<select
value={themeKey}
onChange={(e) => setThemeKey(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
<VSeedRender vseed={vseedConfig} />
</div>
)
}#2.2 relocate (déplacer le centre)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes } from '@visactor/vseed'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
export default () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json')
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'pie',
dataset: DATASET,
dimensions: [{ id: 'HqlYadRdHJ5c', alias: 'Category' }],
measures: [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }],
label: { enable: false },
animation: {
enable: true,
params: {
appear: { enable: true, effects: ['radial'], ease: 'linear', duration: 1 },
loop: { enable: true, interval: 2, loop: { enable: true, effects: ['relocate'], ease: 'linear', duration: 1 } },
},
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<select
value={themeKey}
onChange={(e) => setThemeKey(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
<VSeedRender vseed={vseedConfig} />
</div>
)
}#Animation radar
Tous les exemples reposent sur le thème grand écran (sombre) et proposent une liste déroulante pour changer de thème.
Les thèmes sont chargés depuis : https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json
#1. Animation d'apparition
L'animation d'apparition contrôle la première présentation des surfaces radar et des points.
#1.1 radial (depuis le centre)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes, Builder } from '@visactor/vseed'
const THEME_URL = 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
const DIMENSIONS = [{ id: 'HqlYadRdHJ5c', alias: 'Category' }]
const MEASURES = [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }]
const useLargeScreenThemes = () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
Builder.updateSpec('radar', (spec) => ({
...spec,
point: { ...spec.point, style: { ...(spec.point && spec.point.style), lineWidth: 0, stroke: null } },
axes: [
{
orient: 'radius',
tick: { forceTickCount: 3 },
grid: { smooth: false, style: { stroke: 'rgba(255,255,255,0.15)', lineWidth: 1 } },
label: { visible: false, style: { fontFamily: 'D-DIN' } },
},
{
orient: 'angle',
sampling: false,
tick: { visible: true, style: () => ({ visible: false }) },
domainLine: { style: { visible: false } },
grid: { style: () => ({ stroke: 'rgba(255,255,255,0.15)', lineDash: [2, 1], lineWidth: 1 }) },
label: { style: { fontFamily: 'D-DIN', fill: 'rgba(255,255,255,0.65)', fontSize: 12 }, visible: true },
},
],
}))
fetch(THEME_URL)
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
return { themes, themeKey, setThemeKey }
}
const ThemeSelect = ({ themes, themeKey, onChange }) => (
<select
value={themeKey}
onChange={(e) => onChange(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
)
export default () => {
const { themes, themeKey, setThemeKey } = useLargeScreenThemes()
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'radar',
dataset: DATASET,
dimensions: DIMENSIONS,
measures: MEASURES,
label: { enable: false },
animation: {
enable: true,
params: { appear: { enable: true, effects: ['radial'], ease: 'circInOut', duration: 1 } },
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<ThemeSelect themes={themes} themeKey={themeKey} onChange={setThemeKey} />
<VSeedRender vseed={vseedConfig} />
</div>
)
}#1.2 scale (mise à l'échelle)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes, Builder } from '@visactor/vseed'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
export default () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
Builder.updateSpec('radar', (spec) => ({
...spec,
point: { ...spec.point, style: { ...(spec.point && spec.point.style), lineWidth: 0, stroke: null } },
axes: [
{
orient: 'radius',
tick: { forceTickCount: 3 },
grid: { smooth: false, style: { stroke: 'rgba(255,255,255,0.15)', lineWidth: 1 } },
label: { visible: false, style: { fontFamily: 'D-DIN' } },
},
{
orient: 'angle',
sampling: false,
tick: { visible: true, style: () => ({ visible: false }) },
domainLine: { style: { visible: false } },
grid: { style: () => ({ stroke: 'rgba(255,255,255,0.15)', lineDash: [2, 1], lineWidth: 1 }) },
label: { style: { fontFamily: 'D-DIN', fill: 'rgba(255,255,255,0.65)', fontSize: 12 }, visible: true },
},
],
}))
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json')
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'radar',
dataset: DATASET,
dimensions: [{ id: 'HqlYadRdHJ5c', alias: 'Category' }],
measures: [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }],
label: { enable: false },
animation: {
enable: true,
params: { appear: { enable: true, effects: ['scale'], ease: 'circInOut', duration: 1 } },
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<select
value={themeKey}
onChange={(e) => setThemeKey(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
<VSeedRender vseed={vseedConfig} />
</div>
)
}#2. Animation en boucle
L'animation en boucle du radar s'exprime avec atmosphere.effect pour produire un mouvement d'ambiance continu.
#2.1 none (boucle) + atmosphere (ripple)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes, Builder } from '@visactor/vseed'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
export default () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
Builder.updateSpec('radar', (spec) => ({
...spec,
point: { ...spec.point, style: { ...(spec.point && spec.point.style), lineWidth: 0, stroke: null } },
axes: [
{
orient: 'radius',
tick: { forceTickCount: 3 },
grid: { smooth: false, style: { stroke: 'rgba(255,255,255,0.15)', lineWidth: 1 } },
label: { visible: false, style: { fontFamily: 'D-DIN' } },
},
{
orient: 'angle',
sampling: false,
tick: { visible: true, style: () => ({ visible: false }) },
domainLine: { style: { visible: false } },
grid: { style: () => ({ stroke: 'rgba(255,255,255,0.15)', lineDash: [2, 1], lineWidth: 1 }) },
label: { style: { fontFamily: 'D-DIN', fill: 'rgba(255,255,255,0.65)', fontSize: 12 }, visible: true },
},
],
}))
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json')
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'radar',
dataset: DATASET,
dimensions: [{ id: 'HqlYadRdHJ5c', alias: 'Category' }],
measures: [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }],
label: { enable: false },
animation: {
enable: true,
params: {
appear: { enable: true, effects: ['radial'], ease: 'linear', duration: 1 },
loop: { enable: true, interval: 2, atmosphere: { effect: 'ripple', ease: 'linear' } },
},
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<select
value={themeKey}
onChange={(e) => setThemeKey(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
<VSeedRender vseed={vseedConfig} />
</div>
)
}#2.2 none (boucle) + atmosphere (reveal)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes, Builder } from '@visactor/vseed'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
export default () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
Builder.updateSpec('radar', (spec) => ({
...spec,
point: { ...spec.point, style: { ...(spec.point && spec.point.style), lineWidth: 0, stroke: null } },
axes: [
{
orient: 'radius',
tick: { forceTickCount: 3 },
grid: { smooth: false, style: { stroke: 'rgba(255,255,255,0.15)', lineWidth: 1 } },
label: { visible: false, style: { fontFamily: 'D-DIN' } },
},
{
orient: 'angle',
sampling: false,
tick: { visible: true, style: () => ({ visible: false }) },
domainLine: { style: { visible: false } },
grid: { style: () => ({ stroke: 'rgba(255,255,255,0.15)', lineDash: [2, 1], lineWidth: 1 }) },
label: { style: { fontFamily: 'D-DIN', fill: 'rgba(255,255,255,0.65)', fontSize: 12 }, visible: true },
},
],
}))
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json')
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'radar',
dataset: DATASET,
dimensions: [{ id: 'HqlYadRdHJ5c', alias: 'Category' }],
measures: [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }],
label: { enable: false },
animation: {
enable: true,
params: {
appear: { enable: true, effects: ['scale'], ease: 'linear', duration: 1 },
loop: { enable: true, interval: 3, atmosphere: { effect: 'reveal', ease: 'linear' } },
},
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<select
value={themeKey}
onChange={(e) => setThemeKey(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
<VSeedRender vseed={vseedConfig} />
</div>
)
}#2.3 none (boucle) + atmosphere (breath)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes, Builder } from '@visactor/vseed'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
export default () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
Builder.updateSpec('radar', (spec) => ({
...spec,
point: { ...spec.point, style: { ...(spec.point && spec.point.style), lineWidth: 0, stroke: null } },
axes: [
{
orient: 'radius',
tick: { forceTickCount: 3 },
grid: { smooth: false, style: { stroke: 'rgba(255,255,255,0.15)', lineWidth: 1 } },
label: { visible: false, style: { fontFamily: 'D-DIN' } },
},
{
orient: 'angle',
sampling: false,
tick: { visible: true, style: () => ({ visible: false }) },
domainLine: { style: { visible: false } },
grid: { style: () => ({ stroke: 'rgba(255,255,255,0.15)', lineDash: [2, 1], lineWidth: 1 }) },
label: { style: { fontFamily: 'D-DIN', fill: 'rgba(255,255,255,0.65)', fontSize: 12 }, visible: true },
},
],
}))
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json')
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'radar',
dataset: DATASET,
dimensions: [{ id: 'HqlYadRdHJ5c', alias: 'Category' }],
measures: [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }],
label: { enable: false },
animation: {
enable: true,
params: {
appear: { enable: true, effects: ['scale'], ease: 'linear', duration: 1 },
loop: { enable: true, interval: 2, atmosphere: { effect: 'breath', ease: 'linear' } },
},
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<select
value={themeKey}
onChange={(e) => setThemeKey(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
<VSeedRender vseed={vseedConfig} />
</div>
)
}#Animation des nuages de points
Tous les exemples reposent sur le thème grand écran (sombre) et proposent une liste déroulante pour changer de thème.
Les thèmes sont chargés depuis : https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json
#1. Animation d'apparition
L'animation d'apparition contrôle la première apparition des points.
#1.1 scale (mise à l'échelle)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes } from '@visactor/vseed'
const THEME_URL = 'https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
const DIMENSIONS = [{ id: 'HqlYadRdHJ5c', alias: 'Category' }]
const MEASURES = [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }]
const useLargeScreenThemes = () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
fetch(THEME_URL)
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
return { themes, themeKey, setThemeKey }
}
const ThemeSelect = ({ themes, themeKey, onChange }) => (
<select
value={themeKey}
onChange={(e) => onChange(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
)
export default () => {
const { themes, themeKey, setThemeKey } = useLargeScreenThemes()
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'scatter',
dataset: DATASET,
dimensions: DIMENSIONS,
measures: MEASURES,
label: { enable: false },
animation: {
enable: true,
params: { appear: { enable: true, effects: ['scale'], ease: 'circInOut', duration: 1 } },
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<ThemeSelect themes={themes} themeKey={themeKey} onChange={setThemeKey} />
<VSeedRender vseed={vseedConfig} />
</div>
)
}#1.2 fadeIn (fondu entrant)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes } from '@visactor/vseed'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
export default () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json')
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'scatter',
dataset: DATASET,
dimensions: [{ id: 'HqlYadRdHJ5c', alias: 'Category' }],
measures: [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }],
label: { enable: false },
animation: {
enable: true,
params: { appear: { enable: true, effects: ['fadeIn'], ease: 'circInOut', duration: 1 } },
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<select
value={themeKey}
onChange={(e) => setThemeKey(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
<VSeedRender vseed={vseedConfig} />
</div>
)
}#2. Animation en boucle
L'animation en boucle des nuages de points s'exprime généralement avec atmosphere pour maintenir un rythme continu.
#2.1 none (boucle) + atmosphere (ripple)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes } from '@visactor/vseed'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
export default () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json')
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'scatter',
dataset: DATASET,
dimensions: [{ id: 'HqlYadRdHJ5c', alias: 'Category' }],
measures: [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }],
label: { enable: false },
animation: {
enable: true,
params: {
appear: { enable: true, effects: ['scale'], ease: 'linear', duration: 1 },
loop: { enable: true, interval: 2, atmosphere: { effect: 'ripple', ease: 'linear' } },
},
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<select
value={themeKey}
onChange={(e) => setThemeKey(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
<VSeedRender vseed={vseedConfig} />
</div>
)
}#2.2 none (boucle) + atmosphere (breath)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes } from '@visactor/vseed'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
export default () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json')
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'scatter',
dataset: DATASET,
dimensions: [{ id: 'HqlYadRdHJ5c', alias: 'Category' }],
measures: [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }],
label: { enable: false },
animation: {
enable: true,
params: {
appear: { enable: true, effects: ['fadeIn'], ease: 'linear', duration: 1 },
loop: { enable: true, interval: 2, atmosphere: { effect: 'breath', ease: 'linear' } },
},
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<select
value={themeKey}
onChange={(e) => setThemeKey(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
<VSeedRender vseed={vseedConfig} />
</div>
)
}#2.3 none (boucle) + atmosphere (reveal)
import { useEffect, useState } from 'react'
import { VSeedRender } from '@components'
import { registerTokenThemes } from '@visactor/vseed'
const DATASET = [
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 24,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Labels',
Tn97A7q0XVDq: 24,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Tables',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 40,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 40,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 20,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Storage',
Tn97A7q0XVDq: 20,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 10,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Furn',
Tn97A7q0XVDq: 10,
'7ti8XuX4kcY1': '2022',
},
{
10001: 'Sales',
10002: 50,
10003: 'Tn97A7q0XVDq',
30001: '2023',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 50,
'7ti8XuX4kcY1': '2023',
},
{
10001: 'Sales',
10002: 30,
10003: 'Tn97A7q0XVDq',
30001: '2022',
HqlYadRdHJ5c: 'Art',
Tn97A7q0XVDq: 30,
'7ti8XuX4kcY1': '2022',
},
]
export default () => {
const [themes, setThemes] = useState({})
const [themeKey, setThemeKey] = useState('')
useEffect(() => {
fetch('https://lf9-dp-fe-cms-tos.byteorg.com/obj/bit-cloud/theme.json')
.then((r) => r.json())
.then((remote) => {
const registry = {}
Object.entries(remote).forEach(([key, value]) => {
const colors = value?.colors || []
registry[key] = {
baseTheme: 'dark',
colorScheme: colors.length >= 2 ? colors : [colors[0] || '#00D5FF', '#227BFF'],
linearColorScheme: [colors[0] || '#003B73', colors[1] || '#00D5FF'],
textPrimary: '#EAF7FF',
textSecondary: '#8FC7FF',
borderColor: 'rgba(82, 191, 255, 0.28)',
surfaceColor: '#071A33',
tooltipBackgroundColor: 'rgba(5, 18, 38, 0.92)',
axisGridColor: 'rgba(82, 191, 255, 0.18)',
accentColor: colors[0] || '#00D5FF',
}
})
registerTokenThemes(registry, { ensureRegisterAll: false })
setThemes(remote)
setThemeKey(Object.keys(remote)[0] || '')
})
.catch(() => {})
}, [])
if (!themeKey) return null
const vseedConfig = {
theme: themeKey,
chartType: 'scatter',
dataset: DATASET,
dimensions: [{ id: 'HqlYadRdHJ5c', alias: 'Category' }],
measures: [{ id: 'Tn97A7q0XVDq', alias: 'Sales' }],
label: { enable: false },
animation: {
enable: true,
params: {
appear: { enable: true, effects: ['scale'], ease: 'linear', duration: 1 },
loop: { enable: true, interval: 3, atmosphere: { effect: 'reveal', ease: 'linear' } },
},
},
}
return (
<div style={{ padding: 16, background: '#061A33' }}>
<select
value={themeKey}
onChange={(e) => setThemeKey(e.target.value)}
style={{
marginBottom: 12,
color: '#EAF7FF',
background: 'rgba(0, 213, 255, 0.18)',
border: '1px solid rgba(0, 213, 255, 0.45)',
padding: '6px 12px',
}}
>
{Object.entries(themes).map(([key, value]) => (
<option key={key} value={key} style={{ color: '#000' }}>
{value?.name || key}
</option>
))}
</select>
<VSeedRender vseed={vseedConfig} />
</div>
)
}