diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 6398c5d7b..d80b31d8a 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -1,6 +1,9 @@ name: Cypress Percy Tests -on: [push] +on: + push: + branches: + - main jobs: build: diff --git a/package.json b/package.json index 7d91ce548..bc298218e 100644 --- a/package.json +++ b/package.json @@ -67,8 +67,5 @@ }, "lint-staged": { "*.{js,ts,jsx,tsx,svelte}": "eslint --quiet --cache --fix" - }, - "dependencies": { - "seedrandom": "^3.0.5" } } diff --git a/packages/dev/cypress.config.ts b/packages/dev/cypress.config.ts index 8d8196fad..fb434cdfc 100644 --- a/packages/dev/cypress.config.ts +++ b/packages/dev/cypress.config.ts @@ -1,5 +1,4 @@ import { defineConfig } from 'cypress' -// import webpackConfig from './webpack.config' export default defineConfig({ e2e: { diff --git a/packages/dev/cypress/e2e/unovis.cy.ts b/packages/dev/cypress/e2e/unovis.cy.ts index 32e4a0c79..af233cf6a 100644 --- a/packages/dev/cypress/e2e/unovis.cy.ts +++ b/packages/dev/cypress/e2e/unovis.cy.ts @@ -1,3 +1,5 @@ +const scopeSelector = '.exampleViewer' + describe('Unovis Test', () => { beforeEach(() => { cy.visit('/') @@ -10,349 +12,349 @@ describe('Unovis Test', () => { it('Basic Annotation', () => { cy.contains('Basic Annotations').click() cy.wait(3000) - cy.percySnapshot('Basic Annotation', { scope: '.exampleViewer' }) + cy.percySnapshot('Basic Annotation', { scope: scopeSelector }) }) it('Single Container', () => { cy.contains('Single Container').click() cy.wait(3000) - cy.percySnapshot('Single Container', { scope: '.exampleViewer' }) + cy.percySnapshot('Single Container', { scope: scopeSelector }) }) it('Bullet Shapes', () => { cy.contains('Bullet Shapes').click() cy.wait(3000) - cy.percySnapshot('Bullet Shapes', { scope: '.exampleViewer' }) + cy.percySnapshot('Bullet Shapes', { scope: scopeSelector }) }) it('Basic Bullet Legend', () => { cy.contains('Basic Bullet Legend').click() cy.wait(3000) - cy.percySnapshot('Basic Bullet Legend', { scope: '.exampleViewer' }) + cy.percySnapshot('Basic Bullet Legend', { scope: scopeSelector }) }) it('Line Legend', () => { cy.contains('Line Legend').click() cy.wait(3000) - cy.percySnapshot('Line Legend', { scope: '.exampleViewer' }) + cy.percySnapshot('Line Legend', { scope: scopeSelector }) }) it('Shape Legend', () => { cy.contains('Shape Legend').click() cy.wait(3000) - cy.percySnapshot('Shape Legend', { scope: '.exampleViewer' }) + cy.percySnapshot('Shape Legend', { scope: scopeSelector }) }) it('Vertical Legend', () => { cy.contains('Vertical Legend').click() cy.wait(3000) - cy.percySnapshot('Vertical Legend', { scope: '.exampleViewer' }) + cy.percySnapshot('Vertical Legend', { scope: scopeSelector }) }) it('Scrollable Container Comparison', () => { cy.contains('Scrollable Container Comparison').click() cy.wait(3000) - cy.percySnapshot('Scrollable Container Comparison', { scope: '.exampleViewer' }) + cy.percySnapshot('Scrollable Container Comparison', { scope: scopeSelector }) }) it('Light and Dark Theme', () => { cy.contains('Light and Dark Theme').click() cy.wait(6000) - cy.percySnapshot('Light and Dark Theme', { scope: '.exampleViewer' }) + cy.percySnapshot('Light and Dark Theme', { scope: scopeSelector }) }) it('Raster Leaflet Map', () => { cy.contains('Raster Leaflet Map').click() cy.wait(3000) - cy.percySnapshot('Raster Leaflet Map', { scope: '.exampleViewer' }) + cy.percySnapshot('Raster Leaflet Map', { scope: scopeSelector }) }) it('Vector Map', () => { cy.contains('Vector Map').click() cy.wait(3000) - cy.percySnapshot('Vector Map', { scope: '.exampleViewer' }) + cy.percySnapshot('Vector Map', { scope: scopeSelector }) }) it('Donut: Empty Segments', () => { cy.contains('Donut: Empty Segments').click() cy.wait(3000) - cy.percySnapshot('Donut: Empty Segments', { scope: '.exampleViewer' }) + cy.percySnapshot('Donut: Empty Segments', { scope: scopeSelector }) }) it('Donut Data Transitions', () => { cy.contains('Donut Data Transitions').click() cy.wait(3000) - cy.percySnapshot('Donut Data Transitions', { scope: '.exampleViewer' }) + cy.percySnapshot('Donut Data Transitions', { scope: scopeSelector }) }) it('Basic Nested Donut', () => { cy.contains('Basic Nested Donut').click() cy.wait(3000) - cy.percySnapshot('Basic Nested Donut', { scope: '.exampleViewer' }) + cy.percySnapshot('Basic Nested Donut', { scope: scopeSelector }) }) it('Nested Donut Data Transitions', () => { cy.contains('Nested Donut Data Transitions').click() cy.wait(3000) - cy.percySnapshot('Nested Donut Data Transitions', { scope: '.exampleViewer' }) + cy.percySnapshot('Nested Donut Data Transitions', { scope: scopeSelector }) }) it('Interactive Nested Donut', () => { cy.contains('Interactive Nested Donut').click() cy.wait(3000) - cy.percySnapshot('Interactive Nested Donut', { scope: '.exampleViewer' }) + cy.percySnapshot('Interactive Nested Donut', { scope: scopeSelector }) }) it('Segment labels', () => { cy.contains('Segment labels').click() cy.wait(3000) - cy.percySnapshot('Segment labels', { scope: '.exampleViewer' }) + cy.percySnapshot('Segment labels', { scope: scopeSelector }) }) it('Nested Donut Layer Configuration', () => { cy.contains('Nested Donut Layer Configuration').click() cy.wait(3000) - cy.percySnapshot('Nested Donut Layer Configurationt', { scope: '.exampleViewer' }) + cy.percySnapshot('Nested Donut Layer Configurationt', { scope: scopeSelector }) }) it('Segment values', () => { cy.contains('Segment values').click() cy.wait(3000) - cy.percySnapshot('Segment values', { scope: '.exampleViewer' }) + cy.percySnapshot('Segment values', { scope: scopeSelector }) }) it('Empty Segments', () => { cy.contains('Empty Segments').click() cy.wait(3000) - cy.percySnapshot('Empty Segments', { scope: '.exampleViewer' }) + cy.percySnapshot('Empty Segments', { scope: scopeSelector }) }) it('Chord Diagram Hierarchy Nodes', () => { cy.contains('Chord Diagram Hierarchy').click() cy.wait(5000) - cy.percySnapshot('Chord Diagram Hierarchy Nodes', { scope: '.exampleViewer' }) + cy.percySnapshot('Chord Diagram Hierarchy Nodes', { scope: scopeSelector }) }) it('Node Levels', () => { cy.contains('Node Levels').click() cy.wait(3000) - cy.percySnapshot('Node Levels', { scope: '.exampleViewer' }) + cy.percySnapshot('Node Levels', { scope: scopeSelector }) }) it('Basic Chord Diagram', () => { cy.contains('Basic Chord Diagram').click() cy.wait(5000) - cy.percySnapshot('Basic Chord Diagram', { scope: '.exampleViewer' }) + cy.percySnapshot('Basic Chord Diagram', { scope: scopeSelector }) }) it('Labels and Radius Scale Exponent', () => { cy.contains('Labels and Radius Scale Exponent').click() cy.wait(3000) - cy.percySnapshot('Labels and Radius Scale Exponent', { scope: '.exampleViewer' }) + cy.percySnapshot('Labels and Radius Scale Exponent', { scope: scopeSelector }) }) it('Chord Diagram Node Selection', () => { cy.contains('Chord Diagram Node').click() cy.wait(3000) - cy.percySnapshot('Chord Diagram Node Selection', { scope: '.exampleViewer' }) + cy.percySnapshot('Chord Diagram Node Selection', { scope: scopeSelector }) }) it('Graph: Custom Node Fills', () => { cy.contains('Graph: Custom Node Fills').click() cy.wait(3000) - cy.percySnapshot('Graph: Custom Node Fills', { scope: '.exampleViewer' }) + cy.percySnapshot('Graph: Custom Node Fills', { scope: scopeSelector }) }) it('Graph: SVG Node Icons', () => { cy.contains('Graph: SVG Node Icons').click() cy.wait(3000) - cy.percySnapshot('Graph: SVG Node Icons', { scope: '.exampleViewer' }) + cy.percySnapshot('Graph: SVG Node Icons', { scope: scopeSelector }) }) it('Dynamic Layout', () => { cy.contains('Dynamic Layout').click() cy.wait(3000) - cy.percySnapshot('Dynamic Layout', { scope: '.exampleViewer' }) + cy.percySnapshot('Dynamic Layout', { scope: scopeSelector }) }) it('Layout: ELK', () => { cy.contains('Layout: ELK').click() cy.wait(3000) - cy.percySnapshot('Layout: ELK', { scope: '.exampleViewer' }) + cy.percySnapshot('Layout: ELK', { scope: scopeSelector }) }) it('Link Arrows', () => { cy.contains('Link Arrows').click() cy.wait(3000) - cy.percySnapshot('Link Arrows', { scope: '.exampleViewer' }) + cy.percySnapshot('Link Arrows', { scope: scopeSelector }) }) it('Node and Link Circle Labels', () => { cy.contains('Node and Link Circle Labels').click() cy.wait(3000) - cy.percySnapshot('Node and Link Circle Labels', { scope: '.exampleViewer' }) + cy.percySnapshot('Node and Link Circle Labels', { scope: scopeSelector }) }) it('Graph Brushing', () => { cy.contains('Graph Brushing').click() cy.wait(3000) - cy.percySnapshot('Graph Brushing', { scope: '.exampleViewer' }) + cy.percySnapshot('Graph Brushing', { scope: scopeSelector }) }) it('Node Labels and Sub-labels', () => { cy.contains('Node Labels and Sub-labels').click() cy.wait(3000) - cy.percySnapshot('Node Labels and Sub-labels', { scope: '.exampleViewer' }) + cy.percySnapshot('Node Labels and Sub-labels', { scope: scopeSelector }) }) it('Graph: Node Positions', () => { cy.contains('Graph: Node Positions').click() cy.wait(3000) - cy.percySnapshot('Graph: Node Positions', { scope: '.exampleViewer' }) + cy.percySnapshot('Graph: Node Positions', { scope: scopeSelector }) }) it('Graph: Node Selection', () => { cy.contains('Graph: Node Selection').click() cy.wait(3000) - cy.percySnapshot('Graph: Node Selection', { scope: '.exampleViewer' }) + cy.percySnapshot('Graph: Node Selection', { scope: scopeSelector }) }) it('Sankey Data Transitions', () => { cy.contains('Sankey Data Transitions').click() cy.wait(3000) - cy.percySnapshot('Sankey Data Transitions', { scope: '.exampleViewer' }) + cy.percySnapshot('Sankey Data Transitions', { scope: scopeSelector }) }) it('API Endpoints Tree', () => { cy.contains('API Endpoints Tree').click() cy.wait(3000) - cy.percySnapshot('API Endpoints Tree', { scope: '.exampleViewer', widths: [1300], minHeight: 2400 }) + cy.percySnapshot('API Endpoints Tree', { scope: scopeSelector, widths: [1300], minHeight: 2400 }) }) it('Area Chart with Baseline', () => { cy.contains('Area Chart with Baseline').click() cy.wait(3000) - cy.percySnapshot('Area Chart with Baseline', { scope: '.exampleViewer' }) + cy.percySnapshot('Area Chart with Baseline', { scope: scopeSelector }) }) it('Basic Area Chart', () => { cy.contains('Basic Area Chart').click() cy.wait(3000) - cy.percySnapshot('Basic Area Chart', { scope: '.exampleViewer' }) + cy.percySnapshot('Basic Area Chart', { scope: scopeSelector }) }) it('Area Data Transitions', () => { cy.contains('Area Data Transitions').click() cy.wait(3000) - cy.percySnapshot('Area Data Transitions', { scope: '.exampleViewer' }) + cy.percySnapshot('Area Data Transitions', { scope: scopeSelector }) }) it('Axis with Ticks Rotation', () => { cy.contains('Axis with Ticks Rotation').click() cy.wait(3000) - cy.percySnapshot('Axis with Ticks Rotation', { scope: '.exampleViewer' }) + cy.percySnapshot('Axis with Ticks Rotation', { scope: scopeSelector }) }) it('Axis', () => { cy.contains('Axis').click() cy.wait(3000) - cy.percySnapshot('Axis', { scope: '.exampleViewer' }) + cy.percySnapshot('Axis', { scope: scopeSelector }) }) it('Custom Style Brush', () => { cy.contains('Custom Style Brush').click() cy.wait(3000) - cy.percySnapshot('Custom Style Brush', { scope: '.exampleViewer' }) + cy.percySnapshot('Custom Style Brush', { scope: scopeSelector }) }) it('Stacked vs Non-Stacked', () => { cy.contains('Stacked vs Non-Stacked').click() cy.wait(3000) - cy.percySnapshot('Stacked vs Non-Stacked', { scope: '.exampleViewer' }) + cy.percySnapshot('Stacked vs Non-Stacked', { scope: scopeSelector }) }) it('Dual Axis Chart', () => { cy.contains('Dual Axis Chart').click() cy.wait(3000) - cy.percySnapshot('Dual Axis Chart', { scope: '.exampleViewer' }) + cy.percySnapshot('Dual Axis Chart', { scope: scopeSelector }) }) it('Basic Grouped Bar Chart', () => { cy.contains('Basic Grouped Bar Chart').click() cy.wait(3000) - cy.percySnapshot('Basic Grouped Bar Chart', { scope: '.exampleViewer' }) + cy.percySnapshot('Basic Grouped Bar Chart', { scope: scopeSelector }) }) it('Grouped Bar Chart', () => { cy.contains('Grouped Bar Chart').click() cy.wait(3000) - cy.percySnapshot('Grouped Bar Chart', { scope: '.exampleViewer' }) + cy.percySnapshot('Grouped Bar Chart', { scope: scopeSelector }) }) it('Multi Line Chart', () => { cy.contains('Multi Line Chart').click() cy.wait(3000) - cy.percySnapshot('Multi Line Chart', { scope: '.exampleViewer' }) + cy.percySnapshot('Multi Line Chart', { scope: scopeSelector }) }) it('Points with labels', () => { cy.contains('Points with labels').click() cy.wait(3000) - cy.percySnapshot('Points with labels', { scope: '.exampleViewer' }) + cy.percySnapshot('Points with labels', { scope: scopeSelector }) }) it('Points with stroke', () => { cy.contains('Points with stroke').click() cy.wait(3000) - cy.percySnapshot('Points with stroke', { scope: '.exampleViewer' }) + cy.percySnapshot('Points with stroke', { scope: scopeSelector }) }) it('Scatter with Line', () => { cy.contains('Scatter with Line').click() cy.wait(3000) - cy.percySnapshot('Scatter with Line', { scope: '.exampleViewer' }) + cy.percySnapshot('Scatter with Line', { scope: scopeSelector }) }) it('Basic Stacked Bar Chart', () => { cy.contains('Basic Stacked Bar Chart').click() cy.wait(3000) - cy.percySnapshot('Basic Stacked Bar Chart', { scope: '.exampleViewer' }) + cy.percySnapshot('Basic Stacked Bar Chart', { scope: scopeSelector }) }) it('Stacked Bar Data Transitions', () => { cy.contains('Stacked Bar Data Transitions').click() cy.wait(3000) - cy.percySnapshot('Stacked Bar Data Transitions', { scope: '.exampleViewer' }) + cy.percySnapshot('Stacked Bar Data Transitions', { scope: scopeSelector }) }) it('Timeline Data Transitions', () => { cy.contains('Timeline Data Transitions').click() cy.wait(3000) - cy.percySnapshot('Timeline Data Transitions', { scope: '.exampleViewer' }) + cy.percySnapshot('Timeline Data Transitions', { scope: scopeSelector }) }) it('Timeline: Negative Lengths', () => { cy.contains('Timeline: Negative Lengths').click() cy.wait(3000) - cy.percySnapshot('Timeline: Negative Lengths', { scope: '.exampleViewer' }) + cy.percySnapshot('Timeline: Negative Lengths', { scope: scopeSelector }) }) it('Tooltip and Scrolling', () => { cy.contains('Tooltip and Scrolling').click() cy.wait(3000) - cy.percySnapshot('Tooltip and Scrolling', { scope: '.exampleViewer' }) + cy.percySnapshot('Tooltip and Scrolling', { scope: scopeSelector }) }) it('Scale by Domain', () => { cy.contains('Scale by Domain').click() cy.wait(3000) - cy.percySnapshot('Scale by Domain', { scope: '.exampleViewer' }) + cy.percySnapshot('Scale by Domain', { scope: scopeSelector }) }) it('Stacked Bar with Labels', () => { cy.contains('Stacked Bar with Labels').click() cy.wait(3000) - cy.percySnapshot('Stacked Bar with Labels', { scope: '.exampleViewer' }) + cy.percySnapshot('Stacked Bar with Labels', { scope: scopeSelector }) }) }) diff --git a/packages/dev/cypress/fixtures/example.json b/packages/dev/cypress/fixtures/example.json deleted file mode 100644 index 02e425437..000000000 --- a/packages/dev/cypress/fixtures/example.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Using fixtures to represent data", - "email": "hello@cypress.io", - "body": "Fixtures are a great way to mock data for responses to routes" -} diff --git a/packages/dev/cypress/support/commands.ts b/packages/dev/cypress/support/commands.ts deleted file mode 100644 index 95857aea4..000000000 --- a/packages/dev/cypress/support/commands.ts +++ /dev/null @@ -1,37 +0,0 @@ -/// -// *********************************************** -// This example commands.ts shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** -// -// -// -- This is a parent command -- -// Cypress.Commands.add('login', (email, password) => { ... }) -// -// -// -- This is a child command -- -// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) -// -// declare global { -// namespace Cypress { -// interface Chainable { -// login(email: string, password: string): Chainable -// drag(subject: string, options?: Partial): Chainable -// dismiss(subject: string, options?: Partial): Chainable -// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable -// } -// } -// } diff --git a/packages/dev/package-lock.json b/packages/dev/package-lock.json index 59f9522cf..e93040f41 100644 --- a/packages/dev/package-lock.json +++ b/packages/dev/package-lock.json @@ -14,6 +14,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.4.5", + "seedrandom": "^3.0.5", "serve": "^14.2.3" }, "devDependencies": { @@ -6980,6 +6981,11 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" + }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", diff --git a/packages/dev/package.json b/packages/dev/package.json index 153759339..b5c21c75b 100644 --- a/packages/dev/package.json +++ b/packages/dev/package.json @@ -33,6 +33,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.4.5", + "seedrandom": "^3.0.5", "serve": "^14.2.3" }, "peerDependencies": { diff --git a/packages/dev/src/examples/auxiliary/annotations/basic-annotations/index.tsx b/packages/dev/src/examples/auxiliary/annotations/basic-annotations/index.tsx index f5d317ef9..01b35a9e9 100644 --- a/packages/dev/src/examples/auxiliary/annotations/basic-annotations/index.tsx +++ b/packages/dev/src/examples/auxiliary/annotations/basic-annotations/index.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useRef, useState } from 'react' import { VisXYContainer, VisLine, VisAxis, VisAnnotations, VisLineRef } from '@unovis/react' import { AnnotationItem } from '@unovis/ts' -import { rng } from '@src/utils/data' +import { randomNumberGenerator } from '@src/utils/data' export const title = 'Basic Annotations' export const subTitle = 'Dynamic Data Updates' @@ -11,7 +11,7 @@ export const component = (): JSX.Element => { const length = 10 const min = 3 const max = 8 - const generateData = (): number[] => Array.from({ length }, () => rng() * (max - min) + min) + const generateData = (): number[] => Array.from({ length }, () => randomNumberGenerator() * (max - min) + min) const ref = useRef>(null) const [data, setData] = useState(generateData) diff --git a/packages/dev/src/examples/auxiliary/bullet-legend/legend-stacked-bar-donut/index.tsx b/packages/dev/src/examples/auxiliary/bullet-legend/legend-stacked-bar-donut/index.tsx index 4e46da4d2..b09248d04 100644 --- a/packages/dev/src/examples/auxiliary/bullet-legend/legend-stacked-bar-donut/index.tsx +++ b/packages/dev/src/examples/auxiliary/bullet-legend/legend-stacked-bar-donut/index.tsx @@ -1,7 +1,7 @@ import React from 'react' import { sum } from 'd3-array' import { VisBulletLegend, VisSingleContainer, VisDonut, VisXYContainer, VisStackedBar } from '@unovis/react' -import { rng } from '@src/utils/data' +import { randomNumberGenerator } from '@src/utils/data' import s from './styles.module.css' @@ -17,7 +17,7 @@ export const component = (): JSX.Element => { const items = Array(6).fill(0).map((_, i) => ({ name: `y${i}` })) const data = Array(10).fill(0).map((_, i) => ({ x: i, - ys: items.map(() => rng()), + ys: items.map(() => randomNumberGenerator()), })) const accessors = items.map((_, i) => (d: DataRecord) => d.ys[i]) diff --git a/packages/dev/src/examples/auxiliary/bullet-legend/vertical-legend/index.tsx b/packages/dev/src/examples/auxiliary/bullet-legend/vertical-legend/index.tsx index b9a32f47a..0f55a5265 100644 --- a/packages/dev/src/examples/auxiliary/bullet-legend/vertical-legend/index.tsx +++ b/packages/dev/src/examples/auxiliary/bullet-legend/vertical-legend/index.tsx @@ -1,7 +1,7 @@ import React from 'react' import { VisBulletLegend, VisXYContainer, VisAxis, VisStackedBar } from '@unovis/react' import { BulletLegendOrientation } from '@unovis/ts' -import { rng } from '@src/utils/data' +import { randomNumberGenerator } from '@src/utils/data' import s from './styles.module.css' @@ -17,7 +17,7 @@ const data = Array.from({ length: 150 }, (_, i) => ({ ...seriesLabels .reduce((acc, label) => ({ ...acc, - [label]: label.length + rng() * 5, + [label]: label.length + randomNumberGenerator() * 5, }), {} as Record), })) diff --git a/packages/dev/src/examples/networks-and-flows/chord-diagram/chord-diagram-levels/index.tsx b/packages/dev/src/examples/networks-and-flows/chord-diagram/chord-diagram-levels/index.tsx index 2baac142a..29b87a4a9 100644 --- a/packages/dev/src/examples/networks-and-flows/chord-diagram/chord-diagram-levels/index.tsx +++ b/packages/dev/src/examples/networks-and-flows/chord-diagram/chord-diagram-levels/index.tsx @@ -1,5 +1,6 @@ import React from 'react' import { VisSingleContainer, VisChordDiagram } from '@unovis/react' +import { randomNumberGenerator } from '@src/utils/data' export const title = 'Node Levels' export const subTitle = 'Side by side comparison' @@ -22,7 +23,7 @@ const data = { { source: 'B0', target: 'C1' }, { source: 'B1', target: 'C2' }, { source: 'C0', target: 'A2' }, - ].map((l) => ({ ...l, value: Math.random() })), + ].map((l) => ({ ...l, value: randomNumberGenerator() })), } export const component = (): JSX.Element => { return ( diff --git a/packages/dev/src/examples/networks-and-flows/chord-diagram/chord-diagram-perpendicular-labels/data.ts b/packages/dev/src/examples/networks-and-flows/chord-diagram/chord-diagram-perpendicular-labels/data.ts index 8022e9660..c6b19d22b 100644 --- a/packages/dev/src/examples/networks-and-flows/chord-diagram/chord-diagram-perpendicular-labels/data.ts +++ b/packages/dev/src/examples/networks-and-flows/chord-diagram/chord-diagram-perpendicular-labels/data.ts @@ -1,3 +1,4 @@ +import { randomNumberGenerator } from '@src/utils/data' export type NodeDatum = { group: string; color: string; id: string } export type LinkDatum = { source: string; target: string } @@ -17,8 +18,8 @@ export function getData (): { nodes: NodeDatum[]; links: LinkDatum[] } { data.nodes.push(...Array(count).fill(0).map((_, i) => ({ ...n, id: `${n.group}${i}` }))) links.forEach((x, index) => { data.links.push(...Array(x).fill(0).map(() => ({ - source: `${n.group}${Math.floor(Math.random() * count)}`, - target: `${groups[index].group}${Math.floor(Math.random() * groups[index].count)}`, + source: `${n.group}${Math.floor(randomNumberGenerator() * count)}`, + target: `${groups[index].group}${Math.floor(randomNumberGenerator() * groups[index].count)}`, }))) }) }) diff --git a/packages/dev/src/examples/networks-and-flows/graph/graph-dynamic-layout/index.tsx b/packages/dev/src/examples/networks-and-flows/graph/graph-dynamic-layout/index.tsx index 98b72cfe4..c05a36238 100644 --- a/packages/dev/src/examples/networks-and-flows/graph/graph-dynamic-layout/index.tsx +++ b/packages/dev/src/examples/networks-and-flows/graph/graph-dynamic-layout/index.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useMemo, useState } from 'react' import { VisSingleContainer, VisGraph } from '@unovis/react' import { GraphLayoutType } from '@unovis/ts' -import { generateNodeLinkData, rng } from '@src/utils/data' +import { generateNodeLinkData, randomNumberGenerator } from '@src/utils/data' export const title = 'Dynamic Layout' export const subTitle = 'Select Layout From Dropdown' @@ -15,12 +15,12 @@ export const component = (): JSX.Element => { // Generate new data every 2 seconds useEffect(() => { setTimeout(() => { - const newData = generateNodeLinkData(10 + Math.floor(rng() * 50)) + const newData = generateNodeLinkData(10 + Math.floor(randomNumberGenerator() * 50)) // Adding some random x, y values to the nodes for `GraphLayoutType.Precalculated` newData.nodes.forEach(n => { - n.x = rng() * 1000 - n.y = rng() * 1000 + n.x = randomNumberGenerator() * 1000 + n.y = randomNumberGenerator() * 1000 }) setData(newData) diff --git a/packages/dev/src/examples/networks-and-flows/graph/graph-link-label/index.tsx b/packages/dev/src/examples/networks-and-flows/graph/graph-link-label/index.tsx index cf6797ed1..74e515e89 100644 --- a/packages/dev/src/examples/networks-and-flows/graph/graph-link-label/index.tsx +++ b/packages/dev/src/examples/networks-and-flows/graph/graph-link-label/index.tsx @@ -1,6 +1,6 @@ import React from 'react' import { VisSingleContainer, VisGraph } from '@unovis/react' -import { generateNodeLinkData, NodeDatum, LinkDatum, rng } from '@src/utils/data' +import { generateNodeLinkData, NodeDatum, LinkDatum, randomNumberGenerator } from '@src/utils/data' import { GraphCircleLabel } from '@unovis/ts' export const title = 'Node and Link Circle Labels' @@ -9,11 +9,11 @@ export const subTitle = 'with custom configuration' export const component = (): JSX.Element => { const data = generateNodeLinkData(15) const linkLabels: GraphCircleLabel[] = data.links.map((link, i) => { - const hasCustomAppearance = rng() > 0.8 + const hasCustomAppearance = randomNumberGenerator() > 0.8 return { text: hasCustomAppearance ? `${i}${i}${i}` : `${i * 10}`, fontSize: hasCustomAppearance ? '8px' : undefined, - radius: hasCustomAppearance ? 0 : 5 + 10 * rng(), + radius: hasCustomAppearance ? 0 : 5 + 10 * randomNumberGenerator(), cursor: 'pointer', textColor: hasCustomAppearance ? 'blue' : undefined, } diff --git a/packages/dev/src/examples/networks-and-flows/graph/graph-node-labels/index.tsx b/packages/dev/src/examples/networks-and-flows/graph/graph-node-labels/index.tsx index 2a02f307c..9dd08b0b9 100644 --- a/packages/dev/src/examples/networks-and-flows/graph/graph-node-labels/index.tsx +++ b/packages/dev/src/examples/networks-and-flows/graph/graph-node-labels/index.tsx @@ -1,7 +1,7 @@ import React from 'react' import { VisSingleContainer, VisGraph } from '@unovis/react' import { TrimMode } from '@unovis/ts' -import { generateNodeLinkData, NodeDatum, LinkDatum, rng } from '@src/utils/data' +import { generateNodeLinkData, NodeDatum, LinkDatum, randomNumberGenerator } from '@src/utils/data' import { sample } from '@src/utils/array' export const title = 'Node Labels and Sub-labels' @@ -16,12 +16,12 @@ export const component = (): JSX.Element => { const labels = data.nodes.map((d, i) => ({ label: `${sample(animals)} ${sample(colors)}`, subLabel: `${sample(regions)} ${sample(colors)} ${sample(animals)}`, - labelTrim: rng() > 0.2, + labelTrim: randomNumberGenerator() > 0.2, labelTrimMode: sample(trimModes), - labelTrimLength: Math.round(3 + 12 * rng()), - subLabelTrim: rng() > 0.2, + labelTrimLength: Math.round(3 + 12 * randomNumberGenerator()), + subLabelTrim: randomNumberGenerator() > 0.2, subLabelTrimMode: sample(trimModes), - subLabelTrimLength: Math.round(3 + 12 * rng()), + subLabelTrimLength: Math.round(3 + 12 * randomNumberGenerator()), })) return ( diff --git a/packages/dev/src/examples/xy-components/xy-labels/labels-stacked-bar/index.tsx b/packages/dev/src/examples/xy-components/xy-labels/labels-stacked-bar/index.tsx index e2986338d..1141edffc 100644 --- a/packages/dev/src/examples/xy-components/xy-labels/labels-stacked-bar/index.tsx +++ b/packages/dev/src/examples/xy-components/xy-labels/labels-stacked-bar/index.tsx @@ -2,7 +2,7 @@ import React, { useRef } from 'react' import { XYLabels } from '@unovis/ts' import { VisXYContainer, VisStackedBar, VisAxis, VisTooltip, VisCrosshair, VisXYLabels } from '@unovis/react' -import { XYDataRecord, generateXYDataRecords, rng } from '@src/utils/data' +import { XYDataRecord, generateXYDataRecords, randomNumberGenerator } from '@src/utils/data' // Style import s from './style.module.css' @@ -21,7 +21,7 @@ export const component = (): JSX.Element => { type AlertDataRecord = { x: number; label: string } const alerts: AlertDataRecord[] = Array(10).fill(null).map(() => ({ - x: data[Math.floor(rng() * data.length)].x, + x: data[Math.floor(randomNumberGenerator() * data.length)].x, label: '❕', })) diff --git a/packages/dev/src/utils/array.ts b/packages/dev/src/utils/array.ts index 569572fe5..daca0b916 100644 --- a/packages/dev/src/utils/array.ts +++ b/packages/dev/src/utils/array.ts @@ -1,4 +1,4 @@ -import { rng } from '@src/utils/data' +import { randomNumberGenerator } from '@src/utils/data' export function groupBy> (arr: T[], key: string): Record { return arr.reduce( (grouped, v, i, a, k = v[key]) => (((grouped[k] || (grouped[k] = [])).push(v), grouped)), @@ -6,4 +6,4 @@ export function groupBy> (arr: T[], key: string): ) } -export const sample = (arr: T[]): T => arr[Math.floor(rng() * arr.length)] +export const sample = (arr: T[]): T => arr[Math.floor(randomNumberGenerator() * arr.length)] diff --git a/packages/dev/src/utils/data.ts b/packages/dev/src/utils/data.ts index 80012034b..23c2ad4cb 100644 --- a/packages/dev/src/utils/data.ts +++ b/packages/dev/src/utils/data.ts @@ -1,8 +1,8 @@ +import * as Seedramdon from 'seedrandom' import { GenericDataRecord } from '@unovis/ts' import { sample } from './array' -/* eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/naming-convention */ -const SeedRandom = require('seedrandom') -export const rng = new SeedRandom('hello.') + +export const randomNumberGenerator = new Seedramdon('unovis') export type XYDataRecord = { x: number; @@ -45,36 +45,36 @@ export type NestedDatum = GenericDataRecord & { export function generateXYDataRecords (n = 10): XYDataRecord[] { return Array(n).fill(0).map((_, i) => ({ x: i, - y: 5 + 5 * rng(), - y1: 1 + 3 * rng(), - y2: 2 * rng(), + y: 5 + 5 * randomNumberGenerator(), + y1: 1 + 3 * randomNumberGenerator(), + y2: 2 * randomNumberGenerator(), })) } export function generateStackedDataRecords (n = 10, count = 6): StackedDataRecord[] { return Array(n).fill(0).map((_, i) => ({ x: i, - ys: Array(count).fill(0).map((_, i) => (i * count / 3) + (count * rng())), + ys: Array(count).fill(0).map((_, i) => (i * count / 3) + (count * randomNumberGenerator())), })) } export function generateTimeSeries (n = 10, types = n, lengthMultiplier = 1): TimeDataRecord[] { const groups = Array(types).fill(0).map((_, i) => String.fromCharCode(i + 65)) return Array(n).fill(0).map((_, i: number) => ({ - timestamp: Date.now() + i * 1000 * 60 * 60 * 24 + (rng() - 0.5) * 5 * 1000 * 60 * 60 * 24, + timestamp: Date.now() + i * 1000 * 60 * 60 * 24 + (randomNumberGenerator() - 0.5) * 5 * 1000 * 60 * 60 * 24, value: i / 10 + Math.sin(i / 5) + Math.cos(i / 3), - length: Math.round(lengthMultiplier * 1000 * 60 * 60 * 24) * (0.2 + rng()), + length: Math.round(lengthMultiplier * 1000 * 60 * 60 * 24) * (0.2 + randomNumberGenerator()), type: groups[i % groups.length], })) } export function generateNodeLinkData (n = 10, numNeighbourLinks = () => 1): NodeLinkData { - const nodes = Array(n).fill(0).map((_, i) => ({ i, id: (i + 1).toString(), value: 100 * rng() })) + const nodes = Array(n).fill(0).map((_, i) => ({ i, id: (i + 1).toString(), value: 100 * randomNumberGenerator() })) const options = [...nodes].slice(1) const links = nodes.reduce((arr, n) => { if (options.length) { - const num = Math.max(1, rng() * options.length) + const num = Math.max(1, randomNumberGenerator() * options.length) for (let i = 0; i < num; i++) { const targetId = options.shift()?.id for (let k = 0; k < numNeighbourLinks(); k++) { @@ -82,7 +82,7 @@ export function generateNodeLinkData (n = 10, numNeighbourLinks = () => 1): Node id: `${n.id}-${targetId}`, source: n.id, target: targetId, - value: rng(), + value: randomNumberGenerator(), } arr.push(link) } @@ -98,14 +98,14 @@ export function generatePrecalculatedNodeLinkData (n = 10, numNeighbourLinks = ( const nodes = Array(n).fill(0).map((_, i) => ({ i, id: (i + 1).toString(), - value: 100 * rng(), + value: 100 * randomNumberGenerator(), x: 50 * i, y: 50 * i, })) const options = [...nodes].slice(1) const links = nodes.reduce((arr, n) => { if (options.length) { - const num = Math.max(1, rng() * options.length) + const num = Math.max(1, randomNumberGenerator() * options.length) for (let i = 0; i < num; i++) { const targetId = options.shift()?.id for (let k = 0; k < numNeighbourLinks(); k++) { @@ -113,7 +113,7 @@ export function generatePrecalculatedNodeLinkData (n = 10, numNeighbourLinks = ( id: `${n.id}-${targetId}`, source: n.id, target: targetId, - value: rng(), + value: randomNumberGenerator(), } arr.push(link) } @@ -142,7 +142,7 @@ export function generateHierarchyData (n: number, levels: Record const nodes = Array(n).fill(0).map((_, i) => { const obj: NodeDatum = { id: i.toString(), label: `N${i}` } Object.keys(levels).forEach(key => { - obj[key] = `${key}${Math.floor(rng() * levels[key])}` + obj[key] = `${key}${Math.floor(randomNumberGenerator() * levels[key])}` }) return obj }) @@ -151,7 +151,7 @@ export function generateHierarchyData (n: number, levels: Record links: Array(n / 2).fill(0).map(() => ({ source: sample(nodes), target: sample(nodes), - value: rng(), + value: randomNumberGenerator(), })), } }