├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── assets └── logo.svg ├── lerna.json ├── package.json ├── packages ├── datalith-barcode │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.tsx │ ├── tsconfig.json │ └── yarn.lock ├── datalith-dotmap │ ├── README.md │ ├── package.json │ ├── src │ │ ├── components │ │ │ ├── DotMap │ │ │ │ ├── README.md │ │ │ │ └── index.tsx │ │ │ ├── DotMapUs │ │ │ │ ├── README.md │ │ │ │ └── index.tsx │ │ │ └── DotMapWorld │ │ │ │ ├── README.md │ │ │ │ └── index.tsx │ │ └── index.ts │ ├── tsconfig.json │ └── yarn.lock ├── datalith-flower │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.tsx │ ├── tsconfig.json │ └── yarn.lock ├── datalith-gridmap │ ├── README.md │ ├── package.json │ ├── src │ │ ├── components │ │ │ ├── GridMap │ │ │ │ ├── README.md │ │ │ │ └── index.tsx │ │ │ ├── GridMapUs │ │ │ │ ├── README.md │ │ │ │ └── index.tsx │ │ │ └── GridMapWorld │ │ │ │ ├── README.md │ │ │ │ └── index.tsx │ │ ├── index.ts │ │ ├── json │ │ │ ├── italy.json │ │ │ ├── us.json │ │ │ └── world.json │ │ └── utils │ │ │ ├── geometry.ts │ │ │ └── gridMap.ts │ ├── tsconfig.json │ └── yarn.lock ├── datalith-hexmap │ ├── README.md │ ├── package.json │ ├── src │ │ ├── components │ │ │ ├── HexMap │ │ │ │ ├── README.md │ │ │ │ └── index.tsx │ │ │ ├── HexMapUs │ │ │ │ ├── README.md │ │ │ │ └── index.tsx │ │ │ └── HexMapWorld │ │ │ │ ├── README.md │ │ │ │ └── index.tsx │ │ └── index.ts │ ├── tsconfig.json │ └── yarn.lock ├── datalith-pack │ ├── README.md │ ├── package.json │ ├── src │ │ ├── generatePack.ts │ │ └── index.tsx │ ├── tsconfig.json │ └── yarn.lock ├── datalith-pixelmap │ ├── README.md │ ├── package.json │ ├── src │ │ ├── components │ │ │ ├── PixelMap │ │ │ │ ├── README.md │ │ │ │ └── index.tsx │ │ │ ├── PixelMapUs │ │ │ │ ├── README.md │ │ │ │ └── index.tsx │ │ │ └── PixelMapWorld │ │ │ │ ├── README.md │ │ │ │ └── index.tsx │ │ └── index.ts │ ├── tsconfig.json │ └── yarn.lock ├── datalith-ripple │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.tsx │ ├── tsconfig.json │ └── yarn.lock ├── datalith-shutter │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.tsx │ ├── tsconfig.json │ └── yarn.lock ├── datalith-spiral │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.tsx │ ├── tsconfig.json │ └── yarn.lock ├── datalith-storybook │ ├── .storybook │ │ ├── main.js │ │ ├── manager.js │ │ ├── preview-head.html │ │ └── preview.js │ ├── README.md │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── logo-ext.svg │ │ └── logo.svg │ ├── src │ │ ├── components │ │ │ ├── barcode.stories.tsx │ │ │ ├── dotmap.stories.tsx │ │ │ ├── flower.stories.tsx │ │ │ ├── gridmap.stories.tsx │ │ │ ├── hexmap.stories.tsx │ │ │ ├── intro.stories.jsx │ │ │ ├── pack.stories.tsx │ │ │ ├── pixelmap.stories.tsx │ │ │ ├── ripple.stories.tsx │ │ │ ├── shutter.stories.tsx │ │ │ └── spiral.stories.tsx │ │ ├── index.d.ts │ │ ├── lib.ts │ │ └── scripts │ │ │ └── index.ts │ ├── tsconfig.json │ └── yarn.lock ├── datalith-util │ ├── README.md │ ├── package.json │ ├── src │ │ ├── ResponsiveWrapper.tsx │ │ └── index.ts │ ├── tsconfig.json │ └── yarn.lock └── datalith │ ├── README.md │ ├── package.json │ ├── src │ └── index.ts │ ├── tsconfig.json │ └── yarn.lock ├── tsconfig.json ├── tsconfig.test.json ├── tslint.json ├── website ├── assets │ └── images │ │ ├── dotpattern.svg │ │ ├── logo.svg │ │ └── share.jpg ├── favicon.ico ├── index.html └── style.css └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | 6 | # testing 7 | coverage 8 | 9 | # production 10 | dist 11 | storybook 12 | 13 | # IDEs and editors 14 | /.idea 15 | /.vscode 16 | 17 | # misc 18 | .DS_Store 19 | .env.local 20 | .env.development.local 21 | .env.test.local 22 | .env.production.local 23 | Thumbs.db 24 | 25 | *.log 26 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "semi": false, 4 | "singleQuote": true, 5 | "trailingComma": "all" 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Luca Falasco 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

datalith

4 |

5 | 6 | --- 7 | 8 | [![npm](https://img.shields.io/badge/npm-datalith-black.svg?style=for-the-badge&logo=npm)](https://www.npmjs.com/org/datalith) 9 | [![npm version](https://img.shields.io/npm/v/datalith.svg?style=for-the-badge&label)](https://www.npmjs.com/org/datalith) 10 | 11 | ### **Datalith** is a collection of clean, lightweight and easily customizable React components for data visualization. 12 | 13 | The purpose is to provide an easy way to integrate custom data visualizations in any React 14 | project. The components were designed with simplicity in mind, 15 | the dataset is the only requirement. 16 | 17 | Key features: 18 | 19 | - Typed React components for optimal DX 20 | - Simple, shared API 21 | - Easy to integrate, customize, and enhance 22 | 23 | #### **[Read the introduction to the project](https://medium.com/@lucafalasco/turn-your-data-into-beautiful-dataliths-f25bae8bd438?source=friends_link&sk=2cbc67534d9361bfec3e86ad22ac5d1d)** 24 | 25 | --- 26 | 27 | ## Installation 28 | 29 | ```sh 30 | yarn add @datalith/shutter @datalith/hexmap @datalith/ripple 31 | ``` 32 | 33 | To install all modules as a single package: 34 | 35 | ```sh 36 | yarn add datalith 37 | ``` 38 | 39 | Then in you React app: 40 | 41 | ```tsx 42 | import React from 'react' 43 | import ReactDOM from 'react-dom' 44 | import { HexMap } from '@datalith/hexmap' 45 | 46 | ReactDOM.render( 47 | [d.lng, d.lat]} 50 | value={d => d.value} 51 | side={5} 52 | featureCollection={featureCollection} 53 | projection={geoProjection} 54 | />, 55 | document.getElementById('root'), 56 | ) 57 | ``` 58 | 59 | ## Development 60 | 61 | ### Getting Started 62 | 63 | ```bash 64 | $ yarn 65 | $ yarn bootstrap 66 | ``` 67 | 68 | ### Start dev environment (Storybook) 69 | 70 | ```bash 71 | $ yarn start 72 | ``` 73 | 74 | ### Build for production 75 | 76 | ```bash 77 | $ yarn build 78 | ``` 79 | 80 | ## F.A.Q. 81 | 82 | - Axis, labels or legends are not included, what if I need those? 83 | 84 | > The purpose of the project is to provide an easy way to display data in a very straightforward and engaging way, so the focus of _datalith_ is on the shapes and the visual patterns, and that's why axis, labels or legends are not included by default. However, if you need to display them, you can easily create your own components (or use a library like [vx](https://github.com/hshoff/vx)) and include those elements as an additional layer by passing them to the `additionalElements` prop. 85 | 86 | - I need a simple [barchart | scatterplot | piechart | ... ], why is it missing? 87 | 88 | > _datalith_ differs from other data-viz libraries by providing unconventional yet clear and easy-to-read data visualizations, that's why you won't find barcharts or piecharts, there are already a lot of libraries which let you create basic charts like those. This also means ideas about new unique visual models are strongly welcomed, feel free to open an issue to discuss ;) 89 | 90 | - Which packages do I have to use? 91 | 92 | > _datalith_ is meant to be extremely modular, so you can install only the charts you need by using the scoped package install: 93 | 94 | > ```sh 95 | > yarn add @datalith/hexmap 96 | > ``` 97 | 98 | > Optionally, you can also choose to insall the complete collection of charts: 99 | 100 | > ```sh 101 | > yarn add datalith 102 | > ``` 103 | 104 | - What about animations/transitions? 105 | 106 | > As the charts are rendered using SVG, you can use any react animation library you prefer, I suggest [react-spring](https://github.com/react-spring/react-spring), which is the one used in the examples, but there are many other great alternatives as well. 107 | 108 | - Does it come with types? 109 | 110 | > Yes it does. 111 | 112 | #### The project is still at an early stage 113 | -------------------------------------------------------------------------------- /assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "2.9.0", 3 | "packages": [ 4 | "packages/*" 5 | ], 6 | "version": "0.12.1", 7 | "npmClient": "yarn" 8 | } 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "datalith", 3 | "description": "Collection of React components to build cool data visualizations", 4 | "version": "0.0.1", 5 | "private": true, 6 | "author": "Luca Falasco", 7 | "license": "MIT", 8 | "repository": { 9 | "type": "git", 10 | "url": "" 11 | }, 12 | "scripts": { 13 | "postinstall": "yarn bootstrap", 14 | "bootstrap": "lerna bootstrap", 15 | "build": "lerna exec -- yarn build", 16 | "build-storybook": "cd packages/datalith-storybook && yarn build-storybook", 17 | "start": "cd packages/datalith-storybook && yarn storybook", 18 | "format": "prettier --write 'packages/*/src/**/{*.js,*.ts*,*.md}'" 19 | }, 20 | "devDependencies": { 21 | "husky": "^4.0.6", 22 | "lerna": "^3.13.2", 23 | "lint-staged": "^8.1.5", 24 | "prettier": "^1.17.0" 25 | }, 26 | "husky": { 27 | "hooks": { 28 | "pre-commit": "lint-staged" 29 | } 30 | }, 31 | "lint-staged": { 32 | "*.ts*": [ 33 | "prettier --write", 34 | "git add" 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/datalith-barcode/README.md: -------------------------------------------------------------------------------- 1 | # @datalith/barcode 2 | 3 | ```sh 4 | yarn add @datalith/barcode 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | 11 | ``` 12 | 13 | | Name | Default | Type | Description | 14 | | :-------------------- | :------------------------------ | :---------------------------------- | :----------------------------------------------------------- | 15 | | className | | `string` | Custom css classes to apply to the SVG | 16 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 17 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 18 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 19 | | data\* | | `Array` or`Array` | Array of data | 20 | | value | `(Datum) => Datum` | `(Datum) => number` or `number` | Value accessor | 21 | | valueInactive | `1` | `number` | Value Inactive accessor | 22 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 23 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 24 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 25 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 26 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 27 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 28 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 29 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 30 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 31 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 32 | | barWidth | | `number` | Width of the bars | 33 | | center | `{x: width / 2, y: height / 2}` | `{x: number, y: number}` | Center of the dataviz | 34 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 35 | -------------------------------------------------------------------------------- /packages/datalith-barcode/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@datalith/barcode", 3 | "version": "0.12.1", 4 | "description": "datalith barcode", 5 | "main": "dist/index.js", 6 | "module": "dist/index.js", 7 | "types": "dist/types/index.d.ts", 8 | "scripts": { 9 | "prebuild": "rm -rf dist", 10 | "build": "tsc", 11 | "prepublish": "tsc" 12 | }, 13 | "files": [ 14 | "dist" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/lucafalasco/datalith.git" 19 | }, 20 | "keywords": [ 21 | "datalith", 22 | "react", 23 | "d3", 24 | "visualizations", 25 | "charts" 26 | ], 27 | "author": "@lucafalasco", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/lucafalasco/datalith/issues" 31 | }, 32 | "homepage": "https://github.com/lucafalasco/datalith#readme", 33 | "dependencies": { 34 | "@datalith/util": "^0.12.1", 35 | "react-tooltip": "^3.10.0" 36 | }, 37 | "devDependencies": { 38 | "@types/react": "^16.8.5", 39 | "@types/react-tooltip": "^3.9.2", 40 | "raf": "^3.4.1", 41 | "react": "^16.8.5", 42 | "react-dom": "^16.8.5", 43 | "react-test-renderer": "^16.8.5", 44 | "typescript": "^4.2.4" 45 | }, 46 | "peerDependencies": { 47 | "react": "^15.0.0-0 || ^16.0.0-0" 48 | }, 49 | "publishConfig": { 50 | "access": "public" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/datalith-barcode/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | callOrGetValue, 3 | CommonProps, 4 | Datum, 5 | ResponsiveWrapper, 6 | CommonAccessors, 7 | NumberAccessor, 8 | } from '@datalith/util' 9 | import * as React from 'react' 10 | import Tooltip from 'react-tooltip' 11 | 12 | const DEFAULT_BAR_WIDTH = 5 13 | 14 | interface Props extends CommonProps { 15 | /** Value Accessor */ 16 | value: NumberAccessor 17 | /** Width of the bars */ 18 | barWidth: number 19 | /** Center of the dataviz */ 20 | center?: { x: number; y: number } 21 | } 22 | 23 | interface BarProps extends CommonAccessors { 24 | datum: Datum 25 | value: NumberAccessor 26 | barCodeHeight: number 27 | barWidth: number 28 | index: number 29 | tooltip?: (d: Datum) => string 30 | } 31 | 32 | const Bar = ({ 33 | datum, 34 | index, 35 | barCodeHeight, 36 | barWidth, 37 | value: valueAccessor, 38 | fill, 39 | fillOpacity, 40 | stroke, 41 | strokeOpacity, 42 | tooltip, 43 | }: BarProps) => { 44 | const style = { 45 | fill: callOrGetValue(fill, datum, index), 46 | fillOpacity: callOrGetValue(fillOpacity, datum, index), 47 | stroke: callOrGetValue(stroke, datum, index), 48 | strokeOpacity: callOrGetValue(strokeOpacity, datum, index), 49 | } 50 | 51 | const value = callOrGetValue(valueAccessor, datum, index) 52 | 53 | return ( 54 | 55 | 62 | 63 | ) 64 | } 65 | 66 | export class BarCodeComponent extends React.Component { 67 | static defaultProps = { 68 | value: d => d, 69 | barWidth: DEFAULT_BAR_WIDTH, 70 | } 71 | 72 | render() { 73 | const { 74 | className, 75 | style, 76 | additionalElements, 77 | data, 78 | barWidth, 79 | value, 80 | fill, 81 | fillOpacity, 82 | stroke, 83 | strokeOpacity, 84 | tooltip, 85 | size: { width, height }, 86 | center = { 87 | x: width / 2, 88 | y: height / 2, 89 | }, 90 | } = this.props 91 | 92 | const barCodeWidth = barWidth * data.length 93 | const barCodeHeight = Math.max(...data.map((d, i) => callOrGetValue(value, d, i))) 94 | 95 | return ( 96 | <> 97 | 104 | {additionalElements} 105 | 111 | {data.map((datum, i) => { 112 | return ( 113 | 126 | ) 127 | })} 128 | 129 | 130 | 131 | 132 | ) 133 | } 134 | } 135 | 136 | export const BarCode: React.ComponentType> = ResponsiveWrapper(BarCodeComponent) 137 | -------------------------------------------------------------------------------- /packages/datalith-barcode/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "allowJs": false, 6 | "declaration": true, 7 | "declarationDir": "dist/types" 8 | }, 9 | "include": ["src"], 10 | "exclude": ["src/**/*.test.ts*"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/datalith-dotmap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@datalith/dotmap", 3 | "version": "0.12.1", 4 | "description": "datalith dotmap", 5 | "main": "dist/index.js", 6 | "module": "dist/index.js", 7 | "types": "dist/types/index.d.ts", 8 | "scripts": { 9 | "prebuild": "rm -rf dist", 10 | "build": "tsc", 11 | "prepublish": "tsc" 12 | }, 13 | "files": [ 14 | "dist" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/lucafalasco/datalith.git" 19 | }, 20 | "keywords": [ 21 | "datalith", 22 | "react", 23 | "d3", 24 | "visualizations", 25 | "charts" 26 | ], 27 | "author": "@lucafalasco", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/lucafalasco/datalith/issues" 31 | }, 32 | "homepage": "https://github.com/lucafalasco/datalith#readme", 33 | "dependencies": { 34 | "@datalith/gridmap": "^0.12.1", 35 | "@datalith/util": "^0.12.1", 36 | "d3-array": "^2.1.0", 37 | "d3-geo": "^1.11.3", 38 | "d3-scale": "^3.0.0", 39 | "lodash": "^4.17.11", 40 | "react-tooltip": "^3.10.0", 41 | "topojson": "^3.0.2", 42 | "us-atlas": "^2.1.0" 43 | }, 44 | "devDependencies": { 45 | "@types/d3-array": "^2.0.0", 46 | "@types/d3-geo": "^1.11.1", 47 | "@types/d3-scale": "^2.1.1", 48 | "@types/lodash": "^4.14.123", 49 | "@types/react": "^16.8.5", 50 | "@types/react-tooltip": "^3.9.2", 51 | "@types/topojson": "^3.2.2", 52 | "raf": "^3.4.1", 53 | "react": "^16.8.5", 54 | "react-dom": "^16.8.5", 55 | "react-test-renderer": "^16.8.5", 56 | "typescript": "^4.2.4" 57 | }, 58 | "peerDependencies": { 59 | "react": "^15.0.0-0 || ^16.0.0-0" 60 | }, 61 | "publishConfig": { 62 | "access": "public" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /packages/datalith-dotmap/src/components/DotMap/README.md: -------------------------------------------------------------------------------- 1 | # \ 2 | 3 | ```sh 4 | yarn add @datalith/dotmap 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | 17 | ``` 18 | 19 | | Name | Default | Type | Description | 20 | | :-------------------------- | :------------------- | :-------------------------------------------------- | :----------------------------------------------------------- | 21 | | className | | `string` | Custom css classes to apply to the SVG | 22 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 23 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 24 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 25 | | data \* | | `Array` or`Array<[number, number]>` | Array of data | 26 | | coords | `(Datum) => Datum` | `(Datum) => [number, number]` or `[number, number]` | Coords accessor | 27 | | value | `10` | `(Datum) => number` or`number` | Value accessor | 28 | | valueInactive | `1` | `number` | Value Inactive accessor | 29 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 30 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 31 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 32 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 33 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 34 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 35 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 36 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 37 | | featureCollection \* | | `FeatureCollection` | GeoJson object | 38 | | projection | `geoNaturalEarth1()` | `GeoProjection` | D3 GeoProjection to map coordinates | 39 | | side | `5` | `number` | Grid cell dimension | 40 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 41 | -------------------------------------------------------------------------------- /packages/datalith-dotmap/src/components/DotMap/index.tsx: -------------------------------------------------------------------------------- 1 | import { GridMap, GridMapProps } from '@datalith/gridmap' 2 | import * as React from 'react' 3 | 4 | export type DotMapProps = Omit 5 | export class DotMap extends React.Component { 6 | static defaultProps = GridMap.defaultProps as Partial 7 | 8 | render() { 9 | return ( 10 | ( 13 | 14 | )} 15 | /> 16 | ) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/datalith-dotmap/src/components/DotMapUs/README.md: -------------------------------------------------------------------------------- 1 | # \ 2 | 3 | ```sh 4 | yarn add @datalith/dotmap 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | 11 | ``` 12 | 13 | | Name | Default | Type | Description | 14 | | :-------------------- | :----------------- | :-------------------------------------------------- | :----------------------------------------------------------- | 15 | | className | | `string` | Custom css classes to apply to the SVG | 16 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 17 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 18 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 19 | | data\* | | `Array` or`Array<[number, number]>` | Array of data | 20 | | coords | `(Datum) => Datum` | `(Datum) => [number, number]` or `[number, number]` | Coords accessor | 21 | | value | 10 | `(Datum) => number` or`number` | Value accessor | 22 | | valueInactive | `1` | `number` | Value Inactive accessor | 23 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 24 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 25 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 26 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 27 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 28 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 29 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 30 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 31 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 32 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 33 | | projection | `geoAlbersUsa()` | `GeoProjection` | D3 GeoProjection to map coordinates | 34 | | side | `5` | `number` | Grid cell dimension | 35 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 36 | -------------------------------------------------------------------------------- /packages/datalith-dotmap/src/components/DotMapUs/index.tsx: -------------------------------------------------------------------------------- 1 | import { usTopology } from '@datalith/gridmap' 2 | import { geoAlbersUsa } from 'd3-geo' 3 | import * as React from 'react' 4 | import { feature } from 'topojson' 5 | import { DotMap, DotMapProps } from '../DotMap' 6 | 7 | const us = feature(usTopology, usTopology.objects.counties) 8 | 9 | type DotMapUsProps = Omit 10 | 11 | export class DotMapUs extends React.Component { 12 | static defaultProps = DotMap.defaultProps 13 | 14 | render() { 15 | return 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/datalith-dotmap/src/components/DotMapWorld/README.md: -------------------------------------------------------------------------------- 1 | # \ 2 | 3 | ```sh 4 | yarn add @datalith/dotmap 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | 11 | ``` 12 | 13 | | Name | Default | Type | Description | 14 | | :-------------------- | :------------------- | :-------------------------------------------------- | :----------------------------------------------------------- | 15 | | className | | `string` | Custom css classes to apply to the SVG | 16 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 17 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 18 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 19 | | data\* | | `Array` or`Array<[number, number]>` | Array of data | 20 | | coords | `(Datum) => Datum` | `(Datum) => [number, number]` or `[number, number]` | Coords accessor | 21 | | value | 10 | `(Datum) => number` or`number` | Value accessor | 22 | | valueInactive | `1` | `number` | Value Inactive accessor | 23 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 24 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 25 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 26 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 27 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 28 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 29 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 30 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 31 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 32 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 33 | | projection | `geoNaturalEarth1()` | `GeoProjection` | D3 GeoProjection to map coordinates | 34 | | side | `5` | `number` | Grid cell dimension | 35 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 36 | -------------------------------------------------------------------------------- /packages/datalith-dotmap/src/components/DotMapWorld/index.tsx: -------------------------------------------------------------------------------- 1 | import { worldTopology } from '@datalith/gridmap' 2 | import * as React from 'react' 3 | import { feature } from 'topojson' 4 | import { DotMap, DotMapProps } from '../DotMap' 5 | 6 | const world = feature(worldTopology, worldTopology.objects.countries) 7 | 8 | type DotMapWorldProps = Omit 9 | 10 | export class DotMapWorld extends React.Component { 11 | static defaultProps = DotMap.defaultProps 12 | 13 | render() { 14 | return 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/datalith-dotmap/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/DotMap' 2 | export * from './components/DotMapUs' 3 | export * from './components/DotMapWorld' 4 | -------------------------------------------------------------------------------- /packages/datalith-dotmap/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "allowJs": false, 6 | "declaration": true, 7 | "declarationDir": "dist/types" 8 | }, 9 | "include": ["src"], 10 | "exclude": ["src/**/*.test.ts*"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/datalith-flower/README.md: -------------------------------------------------------------------------------- 1 | # @datalith/flower 2 | 3 | ```sh 4 | yarn add @datalith/flower 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | 11 | ``` 12 | 13 | | Name | Default | Type | Description | 14 | | :-------------------- | :------------------------------ | :---------------------------------- | :----------------------------------------------------------- | 15 | | className | | `string` | Custom css classes to apply to the SVG | 16 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 17 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 18 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 19 | | data\* | | `Array` or `Array` | Array of data | 20 | | value | `(Datum) => Datum` | `(Datum) => number` or `number` | Value accessor | 21 | | valueInactive | `1` | `number` | Value Inactive accessor | 22 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 23 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 24 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 25 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 26 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 27 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 28 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 29 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 30 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 31 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 32 | | center | `{x: width / 2, y: height / 2}` | `{x: number, y: number}` | Center of the dataviz | 33 | | padding | `20` | `number` | Padding between elements | 34 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 35 | -------------------------------------------------------------------------------- /packages/datalith-flower/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@datalith/flower", 3 | "version": "0.12.1", 4 | "description": "datalith flower", 5 | "main": "dist/index.js", 6 | "module": "dist/index.js", 7 | "types": "dist/types/index.d.ts", 8 | "scripts": { 9 | "prebuild": "rm -rf dist", 10 | "build": "tsc", 11 | "prepublish": "tsc" 12 | }, 13 | "files": [ 14 | "dist" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/lucafalasco/datalith.git" 19 | }, 20 | "keywords": [ 21 | "datalith", 22 | "react", 23 | "d3", 24 | "visualizations", 25 | "charts" 26 | ], 27 | "author": "@lucafalasco", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/lucafalasco/datalith/issues" 31 | }, 32 | "homepage": "https://github.com/lucafalasco/datalith#readme", 33 | "dependencies": { 34 | "@datalith/util": "^0.12.1", 35 | "d3-scale": "^3.0.0", 36 | "lodash": "^4.17.11", 37 | "react-tooltip": "^3.10.0" 38 | }, 39 | "devDependencies": { 40 | "@types/d3-scale": "^2.1.1", 41 | "@types/lodash": "^4.14.123", 42 | "@types/react": "^16.8.5", 43 | "@types/react-tooltip": "^3.9.2", 44 | "raf": "^3.4.1", 45 | "react": "^16.8.5", 46 | "react-dom": "^16.8.5", 47 | "react-test-renderer": "^16.8.5", 48 | "typescript": "^4.2.4" 49 | }, 50 | "peerDependencies": { 51 | "react": "^15.0.0-0 || ^16.0.0-0" 52 | }, 53 | "publishConfig": { 54 | "access": "public" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/datalith-flower/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | callOrGetValue, 3 | CommonProps, 4 | Datum, 5 | ResponsiveWrapper, 6 | CommonAccessors, 7 | NumberAccessor, 8 | } from '@datalith/util' 9 | import * as React from 'react' 10 | import Tooltip from 'react-tooltip' 11 | 12 | interface Props extends CommonProps { 13 | /** Value Accessor */ 14 | value: NumberAccessor 15 | /** Padding between elements */ 16 | padding: number 17 | /** Center of the dataviz */ 18 | center?: { x: number; y: number } 19 | } 20 | 21 | interface PolygonProps extends CommonAccessors { 22 | datum: Datum 23 | value: NumberAccessor 24 | index: number 25 | dataLength: number 26 | padding: number 27 | center: { x: number; y: number } 28 | tooltip?: (d: Datum) => string 29 | } 30 | 31 | const getShapePoints = ({ index, value, center: { x, y }, padding, dataLength }): string => { 32 | const baseAngle = (Math.PI * 2) / dataLength 33 | const startAngle = Math.PI / 2 + index * baseAngle 34 | const middleAngle = startAngle + baseAngle / 2 35 | const endAngle = startAngle + baseAngle 36 | const complementarAngle = Math.PI - baseAngle / 2 - Math.PI / 2 37 | const side = value * (Math.sin(complementarAngle) + Math.cos(complementarAngle)) 38 | 39 | const p0 = { 40 | x: x + padding * Math.cos(middleAngle), 41 | y: y + padding * Math.sin(middleAngle), 42 | } 43 | const p1 = { 44 | x: p0.x + value * Math.cos(startAngle), 45 | y: p0.y + value * Math.sin(startAngle), 46 | } 47 | const p3 = { 48 | x: p0.x + value * Math.cos(endAngle), 49 | y: p0.y + value * Math.sin(endAngle), 50 | } 51 | 52 | const CP = { 53 | x1: p0.x + side * Math.cos(startAngle), 54 | y1: p0.y + side * Math.sin(startAngle), 55 | x2: p0.x + side * Math.cos(endAngle), 56 | y2: p0.y + side * Math.sin(endAngle), 57 | } 58 | 59 | return `M ${[p0, p1].map(p => `${p.x} ${p.y}`).join(' L ')} 60 | C ${CP.x1} ${CP.y1} ${CP.x2} ${CP.y2} ${p3.x} ${p3.y} Z` 61 | } 62 | 63 | const Polygon = ({ 64 | datum, 65 | value: valueAccessor, 66 | dataLength, 67 | index, 68 | center, 69 | padding, 70 | fill, 71 | fillOpacity, 72 | stroke, 73 | strokeOpacity, 74 | tooltip, 75 | }: PolygonProps) => { 76 | const style = { 77 | fill: callOrGetValue(fill, datum, index), 78 | fillOpacity: callOrGetValue(fillOpacity, datum, index), 79 | stroke: callOrGetValue(stroke, datum, index), 80 | strokeOpacity: callOrGetValue(strokeOpacity, datum, index), 81 | } 82 | const points = getShapePoints({ 83 | index, 84 | dataLength, 85 | value: callOrGetValue(valueAccessor, datum, index), 86 | padding, 87 | center, 88 | }) 89 | 90 | return ( 91 | 92 | 93 | 94 | ) 95 | } 96 | 97 | export class FlowerComponent extends React.Component { 98 | static defaultProps = { 99 | value: d => d, 100 | padding: 20, 101 | } 102 | 103 | render() { 104 | const { 105 | className, 106 | style, 107 | additionalElements, 108 | data, 109 | value, 110 | fill, 111 | fillOpacity, 112 | stroke, 113 | strokeOpacity, 114 | padding, 115 | tooltip, 116 | size: { width, height }, 117 | center = { 118 | x: width / 2, 119 | y: height / 2, 120 | }, 121 | } = this.props 122 | 123 | return ( 124 | <> 125 | 132 | {additionalElements} 133 | {data.map((datum, i) => ( 134 | 148 | ))} 149 | 150 | 151 | 152 | ) 153 | } 154 | } 155 | 156 | export const Flower: React.ComponentType> = ResponsiveWrapper(FlowerComponent) 157 | -------------------------------------------------------------------------------- /packages/datalith-flower/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "allowJs": false, 6 | "declaration": true, 7 | "declarationDir": "dist/types" 8 | }, 9 | "include": ["src"], 10 | "exclude": ["src/**/*.test.ts*"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/datalith-gridmap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@datalith/gridmap", 3 | "version": "0.12.1", 4 | "description": "datalith gridmap", 5 | "main": "dist/index.js", 6 | "module": "dist/index.js", 7 | "types": "dist/types/index.d.ts", 8 | "scripts": { 9 | "prebuild": "rm -rf dist", 10 | "build": "tsc", 11 | "prepublish": "tsc" 12 | }, 13 | "files": [ 14 | "dist" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/lucafalasco/datalith.git" 19 | }, 20 | "keywords": [ 21 | "datalith", 22 | "react", 23 | "d3", 24 | "visualizations", 25 | "charts" 26 | ], 27 | "author": "@lucafalasco", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/lucafalasco/datalith/issues" 31 | }, 32 | "homepage": "https://github.com/lucafalasco/datalith#readme", 33 | "dependencies": { 34 | "@datalith/util": "^0.12.1", 35 | "@turf/flatten": "^5.1.5", 36 | "d3-array": "^2.1.0", 37 | "d3-geo": "^1.11.3", 38 | "d3-scale": "^3.0.0", 39 | "lodash": "^4.17.11", 40 | "react-tooltip": "^3.10.0", 41 | "topojson": "^3.0.2", 42 | "us-atlas": "^2.1.0" 43 | }, 44 | "devDependencies": { 45 | "@types/d3-array": "^2.0.0", 46 | "@types/d3-geo": "^1.11.1", 47 | "@types/d3-scale": "^2.1.1", 48 | "@types/lodash": "^4.14.123", 49 | "@types/react": "^16.8.5", 50 | "@types/react-tooltip": "^3.9.2", 51 | "@types/topojson": "^3.2.2", 52 | "raf": "^3.4.1", 53 | "react": "^16.8.5", 54 | "react-dom": "^16.8.5", 55 | "react-test-renderer": "^16.8.5", 56 | "typescript": "^4.2.4" 57 | }, 58 | "peerDependencies": { 59 | "react": "^15.0.0-0 || ^16.0.0-0" 60 | }, 61 | "publishConfig": { 62 | "access": "public" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /packages/datalith-gridmap/src/components/GridMap/README.md: -------------------------------------------------------------------------------- 1 | # \ 2 | 3 | ```sh 4 | yarn add @datalith/gridmap 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | } 17 | /> 18 | ``` 19 | 20 | | Name | Default | Type | Description | 21 | | :-------------------------- | :------------------- | :--------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------- | 22 | | className | | `string` | Custom css classes to apply to the SVG | 23 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 24 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 25 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 26 | | data \* | | `Array` or`Array<[number, number]>` | Array of data | 27 | | coords | `(Datum) => Datum` | `(Datum) => [number, number]` or `[number, number]` | Coords accessor | 28 | | value | `10` | `(Datum) => number` or`number` | Value accessor | 29 | | valueInactive | `1` | `number` | Value Inactive accessor | 30 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 31 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 32 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 33 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 34 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 35 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 36 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 37 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 38 | | featureCollection \* | | `FeatureCollection` | GeoJson object | 39 | | projection | `geoNaturalEarth1()` | `GeoProjection` | D3 GeoProjection to map coordinates | 40 | | customRender | | `(d: { x: number; y: number; i: number; j: number; value: number; datum?: Datum }, props: any, ) => JSX.Element` | Return custom element to render as data point | 41 | | side | `5` | `number` | Grid cell dimension | 42 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 43 | -------------------------------------------------------------------------------- /packages/datalith-gridmap/src/components/GridMap/index.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | callOrGetValue, 3 | CommonProps, 4 | CoordsAccessor, 5 | Datum, 6 | ResponsiveWrapper, 7 | CommonAccessors, 8 | NumberAccessor, 9 | } from '@datalith/util' 10 | import { geoNaturalEarth1, GeoProjection } from 'd3-geo' 11 | import { FeatureCollection } from 'geojson' 12 | import * as React from 'react' 13 | import Tooltip from 'react-tooltip' 14 | import gridMap from '../../utils/gridMap' 15 | 16 | const DEFAULT_VALUE = 10 17 | const DEFAULT_VALUE_INACTIVE = 1 18 | const DEFAULT_FILL_INACTIVE = '#000' 19 | const DEFAULT_FILL_OPACITY_INACTIVE = 0.3 20 | const DEFAULT_STROKE_INACTIVE = 'transparent' 21 | const DEFAULT_STROKE_OPACITY_INACTIVE = 0.3 22 | const DEFAULT_SIDE = 10 23 | 24 | interface Props extends CommonProps { 25 | /** Value Accessor */ 26 | value: NumberAccessor 27 | /** Value Inactive Accessor */ 28 | valueInactive: number 29 | /** Fill Inactive Accessor */ 30 | fillInactive: string 31 | /** Fill Opacity Inactive Accessor */ 32 | fillOpacityInactive: number 33 | /** Stroke Inactive Accessor */ 34 | strokeInactive: string 35 | /** Stroke Opacity Inactive Accessor */ 36 | strokeOpacityInactive: number 37 | /** Coords Accessor */ 38 | coords: CoordsAccessor 39 | /** GeoJson */ 40 | featureCollection: FeatureCollection 41 | /** GeoProjection */ 42 | projection: GeoProjection 43 | /** Grid cell dimension */ 44 | side: number 45 | /** Return custom element to render as data point */ 46 | customRender?: ( 47 | d: { x: number; y: number; i: number; j: number; value: number; datum?: Datum }, 48 | props: any, 49 | ) => JSX.Element 50 | } 51 | 52 | export type GridMapProps = Props & CommonProps 53 | 54 | interface VisualElementProps { 55 | datum?: Datum 56 | fill?: string 57 | fillOpacity?: number 58 | stroke?: string 59 | strokeOpacity?: number 60 | tooltip?: (d: Datum) => string 61 | render: (props: any) => JSX.Element 62 | } 63 | 64 | const VisualElement = ({ 65 | datum, 66 | fill, 67 | fillOpacity, 68 | stroke, 69 | strokeOpacity, 70 | tooltip, 71 | render: Element, 72 | }: VisualElementProps) => { 73 | const style = { fill, fillOpacity, stroke, strokeOpacity } 74 | 75 | return {Element(style)} 76 | } 77 | 78 | export class GridMapComponent extends React.Component { 79 | static defaultProps: Partial = { 80 | value: DEFAULT_VALUE, 81 | valueInactive: DEFAULT_VALUE_INACTIVE, 82 | fillInactive: DEFAULT_FILL_INACTIVE, 83 | fillOpacityInactive: DEFAULT_FILL_OPACITY_INACTIVE, 84 | strokeInactive: DEFAULT_STROKE_INACTIVE, 85 | strokeOpacityInactive: DEFAULT_STROKE_OPACITY_INACTIVE, 86 | coords: d => d, 87 | side: DEFAULT_SIDE, 88 | projection: geoNaturalEarth1(), 89 | } 90 | 91 | render() { 92 | const { 93 | className, 94 | style, 95 | additionalElements, 96 | data, 97 | coords, 98 | value, 99 | valueInactive, 100 | featureCollection, 101 | projection, 102 | side, 103 | fill, 104 | fillInactive, 105 | fillOpacity, 106 | fillOpacityInactive, 107 | stroke, 108 | strokeInactive, 109 | strokeOpacity, 110 | strokeOpacityInactive, 111 | tooltip, 112 | customRender, 113 | size: { width, height }, 114 | } = this.props 115 | 116 | const gridMapData = gridMap({ 117 | width, 118 | height, 119 | side, 120 | projection, 121 | data, 122 | coords, 123 | value, 124 | featureCollection, 125 | }) 126 | 127 | // DEBUG 128 | // const path = geoPath().projection(projection) 129 | // const features = (featureCollection as FeatureCollection).features 130 | 131 | return ( 132 | <> 133 | 140 | {additionalElements} 141 | 142 | {/* DEBUG */} 143 | {/* {features.map((f, i) => ( 144 | 145 | ))} */} 146 | {gridMapData.map((d, i) => { 147 | const dimension = 148 | d.datum !== undefined ? callOrGetValue(value, d.datum, i) : valueInactive 149 | 150 | const defaultRender = props => 151 | const render = customRender 152 | ? props => 153 | customRender( 154 | { x: d.x, y: d.y, i: d.i, j: d.j, value: dimension, datum: d.datum }, 155 | props, 156 | ) 157 | : defaultRender 158 | 159 | return ( 160 | 180 | ) 181 | })} 182 | 183 | 184 | 185 | 186 | ) 187 | } 188 | } 189 | 190 | export const GridMap: React.ComponentType> = ResponsiveWrapper(GridMapComponent) 191 | -------------------------------------------------------------------------------- /packages/datalith-gridmap/src/components/GridMapUs/README.md: -------------------------------------------------------------------------------- 1 | # \ 2 | 3 | ```sh 4 | yarn add @datalith/gridmap 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | 11 | ``` 12 | 13 | | Name | Default | Type | Description | 14 | | :-------------------- | :----------------- | :--------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------- | 15 | | className | | `string` | Custom css classes to apply to the SVG | 16 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 17 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 18 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 19 | | data\* | | `Array` or`Array<[number, number]>` | Array of data | 20 | | coords | `(Datum) => Datum` | `(Datum) => [number, number]` or `[number, number]` | Coords accessor | 21 | | value | 10 | `(Datum) => number` or`number` | Value accessor | 22 | | valueInactive | `1` | `number` | Value Inactive accessor | 23 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 24 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 25 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 26 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 27 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 28 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 29 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 30 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 31 | | projection | `geoAlbersUsa()` | `GeoProjection` | D3 GeoProjection to map coordinates | 32 | | customRender | | `(d: { x: number; y: number; i: number; j: number; value: number; datum?: Datum }, props: any, ) => JSX.Element` | Return custom element to render as data point | 33 | | side | `5` | `number` | Grid cell dimension | 34 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 35 | -------------------------------------------------------------------------------- /packages/datalith-gridmap/src/components/GridMapUs/index.tsx: -------------------------------------------------------------------------------- 1 | import { geoAlbersUsa } from 'd3-geo' 2 | import * as React from 'react' 3 | import { feature, UsAtlas } from 'topojson' 4 | import us from '../../json/us.json' 5 | import { GridMap, GridMapProps } from '../GridMap' 6 | 7 | export const usTopology = us as UsAtlas 8 | const usAtlas = feature(usTopology, usTopology.objects.counties) 9 | 10 | type GridMapUsProps = Omit 11 | 12 | export class GridMapUs extends React.Component { 13 | static defaultProps = GridMap.defaultProps as Partial 14 | 15 | render() { 16 | return 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/datalith-gridmap/src/components/GridMapWorld/README.md: -------------------------------------------------------------------------------- 1 | # \ 2 | 3 | ```sh 4 | yarn add @datalith/gridmap 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | 11 | ``` 12 | 13 | | Name | Default | Type | Description | 14 | | :-------------------- | :------------------- | :--------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------- | 15 | | className | | `string` | Custom css classes to apply to the SVG | 16 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 17 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 18 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 19 | | data\* | | `Array` or`Array<[number, number]>` | Array of data | 20 | | coords | `(Datum) => Datum` | `(Datum) => [number, number]` or `[number, number]` | Coords accessor | 21 | | value | 10 | `(Datum) => number` or`number` | Value accessor | 22 | | valueInactive | `1` | `number` | Value Inactive accessor | 23 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 24 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 25 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 26 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 27 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 28 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 29 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 30 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 31 | | projection | `geoNaturalEarth1()` | `GeoProjection` | D3 GeoProjection to map coordinates | 32 | | customRender | | `(d: { x: number; y: number; i: number; j: number; value: number; datum?: Datum }, props: any, ) => JSX.Element` | Return custom element to render as data point | 33 | | side | `5` | `number` | Grid cell dimension | 34 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 35 | -------------------------------------------------------------------------------- /packages/datalith-gridmap/src/components/GridMapWorld/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { feature, WorldAtlas } from 'topojson' 3 | import world from '../../json/world.json' 4 | import { GridMap, GridMapProps } from '../GridMap' 5 | 6 | export const worldTopology = world as WorldAtlas 7 | const worldAtlas = feature(worldTopology, worldTopology.objects.countries) 8 | 9 | type GridMapWorldProps = Omit 10 | 11 | export class GridMapWorld extends React.Component { 12 | static defaultProps = GridMap.defaultProps as Partial 13 | 14 | render() { 15 | return 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/datalith-gridmap/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/GridMap' 2 | export * from './components/GridMapUs' 3 | export * from './components/GridMapWorld' 4 | 5 | import { UsAtlas, WorldAtlas } from 'topojson' 6 | import us from './json/us.json' 7 | import world from './json/world.json' 8 | 9 | export const usTopology = us as UsAtlas 10 | export const worldTopology = world as WorldAtlas 11 | -------------------------------------------------------------------------------- /packages/datalith-gridmap/src/utils/geometry.ts: -------------------------------------------------------------------------------- 1 | export function isPointInsidePolygon( 2 | point: [number, number], 3 | polygon: [number, number][], 4 | ): boolean { 5 | // ray-casting algorithm based on 6 | // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html 7 | const x = point[0] 8 | const y = point[1] 9 | let inside = false 10 | let j = polygon.length - 1 11 | for ( 12 | let i = 0, end = polygon.length - 1, asc = 0 <= end; 13 | asc ? i <= end : i >= end; 14 | asc ? i++ : i-- 15 | ) { 16 | const xi = polygon[i][0] 17 | const yi = polygon[i][1] 18 | const xj = polygon[j][0] 19 | const yj = polygon[j][1] 20 | const intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi 21 | if (intersect) { 22 | inside = !inside 23 | } 24 | j = i 25 | } 26 | return inside 27 | } 28 | -------------------------------------------------------------------------------- /packages/datalith-gridmap/src/utils/gridMap.ts: -------------------------------------------------------------------------------- 1 | import { callOrGetValue, CoordsAccessor, Datum, NumberAccessor } from '@datalith/util' 2 | import flattenGeo from '@turf/flatten' 3 | import { GeometryCollection } from '@turf/helpers' 4 | import { sum } from 'd3-array' 5 | import { geoPath, GeoProjection } from 'd3-geo' 6 | import { Feature, FeatureCollection } from 'geojson' 7 | import { isPointInsidePolygon } from './geometry' 8 | import { flatten, some } from 'lodash' 9 | 10 | function getFeatureIdToValues( 11 | data: Datum[], 12 | feature: Feature, 13 | featureIdToValues: Map, 14 | featureIdToDatum: Map, 15 | coordsAccessor: CoordsAccessor, 16 | valueAccessor: NumberAccessor, 17 | ) { 18 | const res = data.find((d, i) => { 19 | const coords = callOrGetValue(coordsAccessor, d, i) 20 | const flattened = flattenGeo(feature as Feature) 21 | const polygons = flatten( 22 | flattened.features.map(feature => feature.geometry.coordinates), 23 | ) as Array> 24 | 25 | return some(polygons, polygon => isPointInsidePolygon([coords[0], coords[1]], polygon)) 26 | }) 27 | 28 | if (res && feature.id) { 29 | const featureIdValue = featureIdToValues.get(feature.id.toString()) 30 | const value = callOrGetValue(valueAccessor, res) as number 31 | featureIdToDatum.set(feature.id.toString(), res) 32 | featureIdToValues.set(feature.id.toString(), featureIdValue ? featureIdValue + value : value) 33 | } 34 | } 35 | 36 | const range = (left: number, right: number, inclusive: boolean) => { 37 | const range: number[] = [] 38 | const ascending = left < right 39 | const end = !inclusive ? right : ascending ? right + 1 : right - 1 40 | for (let i = left; ascending ? i < end : i > end; ascending ? i++ : i--) { 41 | range.push(i) 42 | } 43 | return range 44 | } 45 | 46 | const subGrid = (box: [[number, number], [number, number]], side: number) => { 47 | const x = 1 + Math.floor(box[0][0] / side) 48 | const y = 1 + Math.floor(box[0][1] / side) 49 | const x1 = Math.floor(box[1][0] / side) 50 | const y1 = Math.floor(box[1][1] / side) 51 | if (x1 >= x && y1 >= y) { 52 | return range(y, y1, true) 53 | .map(j => range(x, x1, true).map(i => [i, j])) 54 | .reduce((a, b) => a.concat(b)) 55 | } else { 56 | return [] 57 | } 58 | } 59 | 60 | interface GridMapConfig { 61 | projection: GeoProjection // d3.geo projection 62 | data: Datum[] // d3.map() mapping key to data 63 | coords: CoordsAccessor 64 | value: NumberAccessor 65 | featureCollection: FeatureCollection // array of map features 66 | isDensity?: boolean // set to `true` if data define a density 67 | width?: number 68 | height?: number 69 | side?: number // side of the cells in pixel 70 | key?: string // name of the attribute mapping features to data 71 | } 72 | 73 | export default function gridMap({ 74 | projection, 75 | data, 76 | coords: coordsAccessor, 77 | value: valueAccessor, 78 | featureCollection, 79 | isDensity = true, 80 | width = 1000, 81 | height = 1000, 82 | side = 5, 83 | key = 'id', 84 | }: GridMapConfig) { 85 | const grid: Map< 86 | string, 87 | { keys: string[]; x: number; y: number; i: number; j: number; featureId: string } 88 | > = new Map() 89 | const features = featureCollection.features 90 | const featureIdToValues = new Map() 91 | const featureIdToDatum = new Map() 92 | 93 | projection.fitSize([width, height], featureCollection) 94 | const path = geoPath().projection(projection) 95 | 96 | const area: Map = new Map() 97 | const centroid: Map = new Map() 98 | 99 | features.map(f => { 100 | area.set(f[key].toString(), path.area(f) / (width * height)) 101 | }) 102 | 103 | // define the grid 104 | features.map((f, i) => { 105 | getFeatureIdToValues( 106 | data, 107 | f, 108 | featureIdToValues, 109 | featureIdToDatum, 110 | coordsAccessor, 111 | valueAccessor, 112 | ) 113 | const g = f.geometry 114 | if (g.type === 'Polygon' || g.type === 'MultiPolygon') { 115 | const box = path.bounds(f) 116 | const points = subGrid(box, side) 117 | const featureId = f[key].toString() 118 | const keys = [featureId] 119 | if (points.length) { 120 | const p = path(f) 121 | const polygonsCommands = p ? p.split(/(?=[M])/) : [] 122 | const polygons = polygonsCommands.map(pathString => { 123 | const commands = pathString.split(/(?=[LMCZ])/) 124 | 125 | return commands.map((c, i, a) => { 126 | const command = c.slice(0, 1) 127 | const coords = command === 'Z' ? a[0] : c 128 | 129 | return coords 130 | .slice(1) 131 | .split(',') 132 | .map(c => parseFloat(c)) as [number, number] 133 | }) 134 | }) 135 | 136 | points.forEach(([i, j]) => { 137 | const x = side * i 138 | const y = side * j 139 | const isInside = polygons.some(polygon => isPointInsidePolygon([x, y], polygon)) 140 | if (isInside) { 141 | grid.set(i + ',' + j, { x, y, i, j, keys, featureId }) 142 | } 143 | }) 144 | } else { 145 | const c = path.centroid(f) 146 | if (c) { 147 | centroid.set(f[key].toString(), c) 148 | } 149 | } 150 | } else { 151 | throw new Error( 152 | `Found incompatible 'geometry.type' for GeoJson: Type '${g.type}' is not supported`, 153 | ) 154 | } 155 | }) 156 | 157 | // add not hitted features to the nearest cell 158 | centroid.forEach((v, k) => { 159 | const i = Math.floor(v[0] / side) 160 | const j = Math.floor(v[1] / side) 161 | const cell = grid.get(i + ',' + j) 162 | if (cell) { 163 | cell.keys.push(k) 164 | } 165 | }) 166 | 167 | const density = (keys: string[]): number => { 168 | let num: number 169 | 170 | if (isDensity) { 171 | num = sum(keys.map(j => (featureIdToValues.get(j) as number) * (area.get(j) as number))) 172 | } else { 173 | num = sum(keys.map(j => featureIdToValues.get(j))) 174 | } 175 | 176 | const den = sum(keys.map(j => area.get(j))) 177 | 178 | if (den) { 179 | return num / den 180 | } else { 181 | return 0 182 | } 183 | } 184 | 185 | return Array.from(grid.values()) 186 | .filter(d => d.keys.length) 187 | .map(d => ({ 188 | x: d.x, 189 | y: d.y, 190 | i: d.i, 191 | j: d.j, 192 | value: density(d.keys), 193 | featureId: d.featureId, 194 | datum: featureIdToDatum.get(d.featureId), 195 | })) 196 | } 197 | -------------------------------------------------------------------------------- /packages/datalith-gridmap/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "allowJs": false, 6 | "declaration": true, 7 | "declarationDir": "dist/types" 8 | }, 9 | "include": ["src"], 10 | "exclude": ["src/**/*.test.ts*"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/datalith-hexmap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@datalith/hexmap", 3 | "version": "0.12.1", 4 | "description": "datalith hexmap", 5 | "main": "dist/index.js", 6 | "module": "dist/index.js", 7 | "types": "dist/types/index.d.ts", 8 | "scripts": { 9 | "prebuild": "rm -rf dist", 10 | "build": "tsc", 11 | "prepublish": "tsc" 12 | }, 13 | "files": [ 14 | "dist" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/lucafalasco/datalith.git" 19 | }, 20 | "keywords": [ 21 | "datalith", 22 | "react", 23 | "d3", 24 | "visualizations", 25 | "charts" 26 | ], 27 | "author": "@lucafalasco", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/lucafalasco/datalith/issues" 31 | }, 32 | "homepage": "https://github.com/lucafalasco/datalith#readme", 33 | "dependencies": { 34 | "@datalith/gridmap": "^0.12.1", 35 | "@datalith/util": "^0.12.1", 36 | "d3-array": "^2.1.0", 37 | "d3-geo": "^1.11.3", 38 | "d3-scale": "^3.0.0", 39 | "lodash": "^4.17.11", 40 | "react-tooltip": "^3.10.0", 41 | "topojson": "^3.0.2", 42 | "us-atlas": "^2.1.0" 43 | }, 44 | "devDependencies": { 45 | "@types/d3-array": "^2.0.0", 46 | "@types/d3-geo": "^1.11.1", 47 | "@types/d3-scale": "^2.1.1", 48 | "@types/lodash": "^4.14.123", 49 | "@types/react": "^16.8.5", 50 | "@types/react-tooltip": "^3.9.2", 51 | "@types/topojson": "^3.2.2", 52 | "raf": "^3.4.1", 53 | "react": "^16.8.5", 54 | "react-dom": "^16.8.5", 55 | "react-test-renderer": "^16.8.5", 56 | "typescript": "^4.2.4" 57 | }, 58 | "peerDependencies": { 59 | "react": "^15.0.0-0 || ^16.0.0-0" 60 | }, 61 | "publishConfig": { 62 | "access": "public" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /packages/datalith-hexmap/src/components/HexMap/README.md: -------------------------------------------------------------------------------- 1 | # \ 2 | 3 | ```sh 4 | yarn add @datalith/hexmap 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | 17 | ``` 18 | 19 | | Name | Default | Type | Description | 20 | | :-------------------------- | :------------------- | :-------------------------------------------------- | :----------------------------------------------------------- | 21 | | className | | `string` | Custom css classes to apply to the SVG | 22 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 23 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 24 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 25 | | data \* | | `Array` or`Array<[number, number]>` | Array of data | 26 | | coords | `(Datum) => Datum` | `(Datum) => [number, number]` or `[number, number]` | Coords accessor | 27 | | value | `10` | `(Datum) => number` or`number` | Value accessor | 28 | | valueInactive | `1` | `number` | Value Inactive accessor | 29 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 30 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 31 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 32 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 33 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 34 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 35 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 36 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 37 | | featureCollection \* | | `FeatureCollection` | GeoJson object | 38 | | projection | `geoNaturalEarth1()` | `GeoProjection` | D3 GeoProjection to map coordinates | 39 | | side | `5` | `number` | Grid cell dimension | 40 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 41 | -------------------------------------------------------------------------------- /packages/datalith-hexmap/src/components/HexMap/index.tsx: -------------------------------------------------------------------------------- 1 | import { GridMap, GridMapProps } from '@datalith/gridmap' 2 | import * as React from 'react' 3 | 4 | export type HexMapProps = Omit 5 | export class HexMap extends React.Component { 6 | static defaultProps = GridMap.defaultProps as Partial 7 | 8 | render() { 9 | return ( 10 | { 13 | const sqrt3 = Math.sqrt(3) 14 | // apply offset to x coordinate based on row index (j) 15 | x = j % 2 ? x : x + this.props.side / 2 16 | 17 | return ( 18 | 29 | ) 30 | }} 31 | /> 32 | ) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/datalith-hexmap/src/components/HexMapUs/README.md: -------------------------------------------------------------------------------- 1 | # \ 2 | 3 | ```sh 4 | yarn add @datalith/hexmap 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | 11 | ``` 12 | 13 | | Name | Default | Type | Description | 14 | | :-------------------- | :----------------- | :-------------------------------------------------- | :----------------------------------------------------------- | 15 | | className | | `string` | Custom css classes to apply to the SVG | 16 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 17 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 18 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 19 | | data\* | | `Array` or`Array<[number, number]>` | Array of data | 20 | | coords | `(Datum) => Datum` | `(Datum) => [number, number]` or `[number, number]` | Coords accessor | 21 | | value | 10 | `(Datum) => number` or`number` | Value accessor | 22 | | valueInactive | `1` | `number` | Value Inactive accessor | 23 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 24 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 25 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 26 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 27 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 28 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 29 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 30 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 31 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 32 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 33 | | projection | `geoAlbersUsa()` | `GeoProjection` | D3 GeoProjection to map coordinates | 34 | | side | `5` | `number` | Grid cell dimension | 35 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 36 | -------------------------------------------------------------------------------- /packages/datalith-hexmap/src/components/HexMapUs/index.tsx: -------------------------------------------------------------------------------- 1 | import { usTopology } from '@datalith/gridmap' 2 | import { geoAlbersUsa } from 'd3-geo' 3 | import * as React from 'react' 4 | import { feature } from 'topojson' 5 | import { HexMap, HexMapProps } from '../HexMap' 6 | 7 | const us = feature(usTopology, usTopology.objects.counties) 8 | 9 | type HexMapUsProps = Omit 10 | 11 | export class HexMapUs extends React.Component { 12 | static defaultProps = HexMap.defaultProps 13 | 14 | render() { 15 | return 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/datalith-hexmap/src/components/HexMapWorld/README.md: -------------------------------------------------------------------------------- 1 | # \ 2 | 3 | ```sh 4 | yarn add @datalith/hexmap 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | 11 | ``` 12 | 13 | | Name | Default | Type | Description | 14 | | :-------------------- | :------------------- | :-------------------------------------------------- | :----------------------------------------------------------- | 15 | | className | | `string` | Custom css classes to apply to the SVG | 16 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 17 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 18 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 19 | | data\* | | `Array` or`Array<[number, number]>` | Array of data | 20 | | coords | `(Datum) => Datum` | `(Datum) => [number, number]` or `[number, number]` | Coords accessor | 21 | | value | 10 | `(Datum) => number` or`number` | Value accessor | 22 | | valueInactive | `1` | `number` | Value Inactive accessor | 23 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 24 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 25 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 26 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 27 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 28 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 29 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 30 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 31 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 32 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 33 | | projection | `geoNaturalEarth1()` | `GeoProjection` | D3 GeoProjection to map coordinates | 34 | | side | `5` | `number` | Grid cell dimension | 35 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 36 | -------------------------------------------------------------------------------- /packages/datalith-hexmap/src/components/HexMapWorld/index.tsx: -------------------------------------------------------------------------------- 1 | import { worldTopology } from '@datalith/gridmap' 2 | import * as React from 'react' 3 | import { feature } from 'topojson' 4 | import { HexMap, HexMapProps } from '../HexMap' 5 | 6 | const world = feature(worldTopology, worldTopology.objects.countries) 7 | 8 | type HexMapWorldProps = Omit 9 | 10 | export class HexMapWorld extends React.Component { 11 | static defaultProps = HexMap.defaultProps 12 | 13 | render() { 14 | return 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/datalith-hexmap/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/HexMap' 2 | export * from './components/HexMapUs' 3 | export * from './components/HexMapWorld' 4 | -------------------------------------------------------------------------------- /packages/datalith-hexmap/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "allowJs": false, 6 | "declaration": true, 7 | "declarationDir": "dist/types" 8 | }, 9 | "include": ["src"], 10 | "exclude": ["src/**/*.test.ts*"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/datalith-pack/README.md: -------------------------------------------------------------------------------- 1 | # @datalith/pack 2 | 3 | ```sh 4 | yarn add @datalith/pack 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | 11 | ``` 12 | 13 | | Name | Default | Type | Description | 14 | | :-------------------- | :------------------------------ | :---------------------------------- | :----------------------------------------------------------- | 15 | | className | | `string` | Custom css classes to apply to the SVG | 16 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 17 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 18 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 19 | | data\* | | `Array` or`Array` | Array of data | 20 | | value | `(Datum) => Datum` | `(Datum) => number` or `number` | Value accessor | 21 | | valueInactive | `1` | `number` | Value Inactive accessor | 22 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 23 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 24 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 25 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 26 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 27 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 28 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 29 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 30 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 31 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 32 | | center | `{x: width / 2, y: height / 2}` | `{x: number, y: number}` | Center of the dataviz | 33 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 34 | -------------------------------------------------------------------------------- /packages/datalith-pack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@datalith/pack", 3 | "version": "0.12.1", 4 | "description": "datalith pack", 5 | "main": "dist/index.js", 6 | "module": "dist/index.js", 7 | "types": "dist/types/index.d.ts", 8 | "scripts": { 9 | "prebuild": "rm -rf dist", 10 | "build": "tsc", 11 | "prepublish": "tsc" 12 | }, 13 | "files": [ 14 | "dist" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/lucafalasco/datalith.git" 19 | }, 20 | "keywords": [ 21 | "datalith", 22 | "react", 23 | "d3", 24 | "visualizations", 25 | "charts" 26 | ], 27 | "author": "@lucafalasco", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/lucafalasco/datalith/issues" 31 | }, 32 | "homepage": "https://github.com/lucafalasco/datalith#readme", 33 | "dependencies": { 34 | "@datalith/util": "^0.12.1", 35 | "d3-scale": "^3.0.0", 36 | "lodash": "^4.17.11", 37 | "react-tooltip": "^3.10.0" 38 | }, 39 | "devDependencies": { 40 | "@types/d3-scale": "^2.1.1", 41 | "@types/lodash": "^4.14.123", 42 | "@types/react": "^16.8.5", 43 | "@types/react-tooltip": "^3.9.2", 44 | "raf": "^3.4.1", 45 | "react": "^16.8.5", 46 | "react-dom": "^16.8.5", 47 | "react-test-renderer": "^16.8.5", 48 | "typescript": "^4.2.4" 49 | }, 50 | "peerDependencies": { 51 | "react": "^15.0.0-0 || ^16.0.0-0" 52 | }, 53 | "publishConfig": { 54 | "access": "public" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/datalith-pack/src/generatePack.ts: -------------------------------------------------------------------------------- 1 | interface Box { 2 | w: number 3 | h: number 4 | i: number 5 | } 6 | 7 | interface PackBox extends Box { 8 | x: number 9 | y: number 10 | } 11 | 12 | export default function generatePack(boxes: Box[]) { 13 | const packBoxes: PackBox[] = [] 14 | 15 | // calculate total box area and maximum box width 16 | let area = 0 17 | let maxWidth = 0 18 | 19 | boxes.forEach(box => { 20 | area += box.w * box.h 21 | maxWidth = Math.max(maxWidth, box.w) 22 | }) 23 | 24 | // sort the boxes for insertion by height, descending 25 | boxes.sort((a, b) => b.h - a.h) 26 | 27 | // aim for a squarish resulting container, 28 | // slightly adjusted for sub-100% space utilization 29 | const startWidth = Math.max(Math.ceil(Math.sqrt(area / 0.95)), maxWidth) 30 | 31 | // start with a single empty space, unbounded at the bottom 32 | const spaces = [{ x: 0, y: 0, w: startWidth, h: Infinity }] 33 | 34 | let width = 0 35 | let height = 0 36 | 37 | boxes.forEach(box => { 38 | // look through spaces backwards so that we check smaller spaces first 39 | for (let i = spaces.length - 1; i >= 0; i--) { 40 | const space = spaces[i] 41 | 42 | // look for empty spaces that can accommodate the current box 43 | if (box.w > space.w || box.h > space.h) { 44 | continue 45 | } 46 | 47 | // found the space; add the box to its top-left corner 48 | // |-------|-------| 49 | // | box | | 50 | // |_______| | 51 | // | space | 52 | // |_______________| 53 | const positionedBox = { 54 | x: space.x, 55 | y: space.y, 56 | ...box, 57 | } 58 | packBoxes.push(positionedBox) 59 | 60 | height = Math.max(height, positionedBox.y + box.h) 61 | width = Math.max(width, positionedBox.x + box.w) 62 | 63 | if (box.w === space.w && box.h === space.h) { 64 | // space matches the box exactly; remove it 65 | const last = spaces.pop() 66 | if (i < spaces.length && last) { 67 | spaces[i] = last 68 | } 69 | } else if (box.h === space.h) { 70 | // space matches the box height; update it accordingly 71 | // |-------|---------------| 72 | // | box | updated space | 73 | // |_______|_______________| 74 | space.x += box.w 75 | space.w -= box.w 76 | } else if (box.w === space.w) { 77 | // space matches the box width; update it accordingly 78 | // |---------------| 79 | // | box | 80 | // |_______________| 81 | // | updated space | 82 | // |_______________| 83 | space.y += box.h 84 | space.h -= box.h 85 | } else { 86 | // otherwise the box splits the space into two spaces 87 | // |-------|-----------| 88 | // | box | new space | 89 | // |_______|___________| 90 | // | updated space | 91 | // |___________________| 92 | spaces.push({ 93 | x: space.x + box.w, 94 | y: space.y, 95 | w: space.w - box.w, 96 | h: box.h, 97 | }) 98 | space.y += box.h 99 | space.h -= box.h 100 | } 101 | break 102 | } 103 | }) 104 | 105 | return { 106 | packBoxes, 107 | boundingBox: { 108 | w: width, // container width 109 | h: height, // container height 110 | fill: area / (width * height) || 0, // space utilization 111 | }, 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /packages/datalith-pack/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | callOrGetValue, 3 | CommonProps, 4 | Datum, 5 | ResponsiveWrapper, 6 | CommonAccessors, 7 | NumberAccessor, 8 | } from '@datalith/util' 9 | import * as React from 'react' 10 | import Tooltip from 'react-tooltip' 11 | import generatePack from './generatePack' 12 | 13 | interface Props extends CommonProps { 14 | /** Value Accessor */ 15 | value: NumberAccessor 16 | /** Center of the dataviz */ 17 | center?: { x: number; y: number } 18 | } 19 | 20 | interface Box { 21 | x: number 22 | y: number 23 | w: number 24 | h: number 25 | } 26 | 27 | interface BoxProps extends CommonAccessors { 28 | datum: Datum 29 | box: Box 30 | index: number 31 | tooltip?: (d: Datum) => string 32 | } 33 | 34 | const Box = ({ 35 | datum, 36 | box, 37 | index, 38 | fill, 39 | fillOpacity, 40 | stroke, 41 | strokeOpacity, 42 | tooltip, 43 | }: BoxProps) => { 44 | const style = { 45 | fill: callOrGetValue(fill, datum, index), 46 | fillOpacity: callOrGetValue(fillOpacity, datum, index), 47 | stroke: callOrGetValue(stroke, datum, index), 48 | strokeOpacity: callOrGetValue(strokeOpacity, datum, index), 49 | } 50 | 51 | return ( 52 | 53 | 54 | 55 | ) 56 | } 57 | 58 | export class PackComponent extends React.Component { 59 | static defaultProps = { 60 | value: d => d, 61 | } 62 | 63 | render() { 64 | const { 65 | className, 66 | style, 67 | additionalElements, 68 | data, 69 | value, 70 | fill, 71 | fillOpacity, 72 | stroke, 73 | strokeOpacity, 74 | tooltip, 75 | size: { width, height }, 76 | center = { 77 | x: width / 2, 78 | y: height / 2, 79 | }, 80 | } = this.props 81 | 82 | const boxes = data.map((datum, i) => { 83 | const sideLength = callOrGetValue(value, datum, i) 84 | return { w: sideLength, h: sideLength, i } 85 | }) 86 | const pack = generatePack(boxes) 87 | 88 | return ( 89 | <> 90 | 97 | {additionalElements} 98 | 104 | {pack.packBoxes.map((box, i) => { 105 | return ( 106 | 117 | ) 118 | })} 119 | 120 | 121 | 122 | 123 | ) 124 | } 125 | } 126 | 127 | export const Pack: React.ComponentType> = ResponsiveWrapper(PackComponent) 128 | -------------------------------------------------------------------------------- /packages/datalith-pack/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "allowJs": false, 6 | "declaration": true, 7 | "declarationDir": "dist/types" 8 | }, 9 | "include": ["src"], 10 | "exclude": ["src/**/*.test.ts*"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/datalith-pixelmap/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@datalith/pixelmap", 3 | "version": "0.12.1", 4 | "description": "datalith pixelmap", 5 | "main": "dist/index.js", 6 | "module": "dist/index.js", 7 | "types": "dist/types/index.d.ts", 8 | "scripts": { 9 | "prebuild": "rm -rf dist", 10 | "build": "tsc", 11 | "prepublish": "tsc" 12 | }, 13 | "files": [ 14 | "dist" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/lucafalasco/datalith.git" 19 | }, 20 | "keywords": [ 21 | "datalith", 22 | "react", 23 | "d3", 24 | "visualizations", 25 | "charts" 26 | ], 27 | "author": "@lucafalasco", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/lucafalasco/datalith/issues" 31 | }, 32 | "homepage": "https://github.com/lucafalasco/datalith#readme", 33 | "dependencies": { 34 | "@datalith/gridmap": "^0.12.1", 35 | "@datalith/util": "^0.12.1", 36 | "d3-array": "^2.1.0", 37 | "d3-geo": "^1.11.3", 38 | "d3-scale": "^3.0.0", 39 | "lodash": "^4.17.11", 40 | "react-tooltip": "^3.10.0", 41 | "topojson": "^3.0.2", 42 | "us-atlas": "^2.1.0" 43 | }, 44 | "devDependencies": { 45 | "@types/d3-array": "^2.0.0", 46 | "@types/d3-geo": "^1.11.1", 47 | "@types/d3-scale": "^2.1.1", 48 | "@types/lodash": "^4.14.123", 49 | "@types/react": "^16.8.5", 50 | "@types/react-tooltip": "^3.9.2", 51 | "@types/topojson": "^3.2.2", 52 | "raf": "^3.4.1", 53 | "react": "^16.8.5", 54 | "react-dom": "^16.8.5", 55 | "react-test-renderer": "^16.8.5", 56 | "typescript": "^4.2.4" 57 | }, 58 | "peerDependencies": { 59 | "react": "^15.0.0-0 || ^16.0.0-0" 60 | }, 61 | "publishConfig": { 62 | "access": "public" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /packages/datalith-pixelmap/src/components/PixelMap/README.md: -------------------------------------------------------------------------------- 1 | # \ 2 | 3 | ```sh 4 | yarn add @datalith/pixelmap 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | 17 | ``` 18 | 19 | | Name | Default | Type | Description | 20 | | :-------------------------- | :------------------- | :-------------------------------------------------- | :----------------------------------------------------------- | 21 | | className | | `string` | Custom css classes to apply to the SVG | 22 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 23 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 24 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 25 | | data \* | | `Array` or`Array<[number, number]>` | Array of data | 26 | | coords | `(Datum) => Datum` | `(Datum) => [number, number]` or `[number, number]` | Coords accessor | 27 | | value | `10` | `(Datum) => number` or`number` | Value accessor | 28 | | valueInactive | `1` | `number` | Value Inactive accessor | 29 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 30 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 31 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 32 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 33 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 34 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 35 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 36 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 37 | | featureCollection \* | | `FeatureCollection` | GeoJson object | 38 | | projection | `geoNaturalEarth1()` | `GeoProjection` | D3 GeoProjection to map coordinates | 39 | | side | `5` | `number` | Grid cell dimension | 40 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 41 | -------------------------------------------------------------------------------- /packages/datalith-pixelmap/src/components/PixelMap/index.tsx: -------------------------------------------------------------------------------- 1 | import { GridMap, GridMapProps } from '@datalith/gridmap' 2 | import * as React from 'react' 3 | 4 | export type PixelMapProps = Omit 5 | export class PixelMap extends React.Component { 6 | static defaultProps = GridMap.defaultProps as Partial 7 | 8 | render() { 9 | return ( 10 | ( 13 | 20 | )} 21 | /> 22 | ) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/datalith-pixelmap/src/components/PixelMapUs/README.md: -------------------------------------------------------------------------------- 1 | # \ 2 | 3 | ```sh 4 | yarn add @datalith/pixelmap 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | 11 | ``` 12 | 13 | | Name | Default | Type | Description | 14 | | :-------------------- | :----------------- | :-------------------------------------------------- | :----------------------------------------------------------- | 15 | | className | | `string` | Custom css classes to apply to the SVG | 16 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 17 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 18 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 19 | | data\* | | `Array` or`Array<[number, number]>` | Array of data | 20 | | coords | `(Datum) => Datum` | `(Datum) => [number, number]` or `[number, number]` | Coords accessor | 21 | | value | 10 | `(Datum) => number` or`number` | Value accessor | 22 | | valueInactive | `1` | `number` | Value Inactive accessor | 23 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 24 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 25 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 26 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 27 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 28 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 29 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 30 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 31 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 32 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 33 | | projection | `geoAlbersUsa()` | `GeoProjection` | D3 GeoProjection to map coordinates | 34 | | side | `5` | `number` | Grid cell dimension | 35 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 36 | -------------------------------------------------------------------------------- /packages/datalith-pixelmap/src/components/PixelMapUs/index.tsx: -------------------------------------------------------------------------------- 1 | import { usTopology } from '@datalith/gridmap' 2 | import { geoAlbersUsa } from 'd3-geo' 3 | import * as React from 'react' 4 | import { feature } from 'topojson' 5 | import { PixelMap, PixelMapProps } from '../PixelMap' 6 | 7 | const us = feature(usTopology, usTopology.objects.counties) 8 | 9 | type PixelMapUsProps = Omit 10 | 11 | export class PixelMapUs extends React.Component { 12 | static defaultProps = PixelMap.defaultProps 13 | 14 | render() { 15 | return 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/datalith-pixelmap/src/components/PixelMapWorld/README.md: -------------------------------------------------------------------------------- 1 | # \ 2 | 3 | ```sh 4 | yarn add @datalith/pixelmap 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | 11 | ``` 12 | 13 | | Name | Default | Type | Description | 14 | | :-------------------- | :------------------- | :-------------------------------------------------- | :----------------------------------------------------------- | 15 | | className | | `string` | Custom css classes to apply to the SVG | 16 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 17 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 18 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 19 | | data\* | | `Array` or`Array<[number, number]>` | Array of data | 20 | | coords | `(Datum) => Datum` | `(Datum) => [number, number]` or `[number, number]` | Coords accessor | 21 | | value | 10 | `(Datum) => number` or`number` | Value accessor | 22 | | valueInactive | `1` | `number` | Value Inactive accessor | 23 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 24 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 25 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 26 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 27 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 28 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 29 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 30 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 31 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 32 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 33 | | projection | `geoNaturalEarth1()` | `GeoProjection` | D3 GeoProjection to map coordinates | 34 | | side | `5` | `number` | Grid cell dimension | 35 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 36 | -------------------------------------------------------------------------------- /packages/datalith-pixelmap/src/components/PixelMapWorld/index.tsx: -------------------------------------------------------------------------------- 1 | import { worldTopology } from '@datalith/gridmap' 2 | import * as React from 'react' 3 | import { feature } from 'topojson' 4 | import { PixelMap, PixelMapProps } from '../PixelMap' 5 | 6 | const world = feature(worldTopology, worldTopology.objects.countries) 7 | 8 | type PixelMapWorldProps = Omit 9 | 10 | export class PixelMapWorld extends React.Component { 11 | static defaultProps = PixelMap.defaultProps 12 | 13 | render() { 14 | return 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/datalith-pixelmap/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/PixelMap' 2 | export * from './components/PixelMapUs' 3 | export * from './components/PixelMapWorld' 4 | -------------------------------------------------------------------------------- /packages/datalith-pixelmap/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "allowJs": false, 6 | "declaration": true, 7 | "declarationDir": "dist/types" 8 | }, 9 | "include": ["src"], 10 | "exclude": ["src/**/*.test.ts*"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/datalith-ripple/README.md: -------------------------------------------------------------------------------- 1 | # @datalith/ripple 2 | 3 | ```sh 4 | yarn add @datalith/ripple 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | 11 | ``` 12 | 13 | | Name | Default | Type | Description | 14 | | :-------------------- | :------------------------------ | :---------------------------------- | :----------------------------------------------------------- | 15 | | className | | `string` | Custom css classes to apply to the SVG | 16 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 17 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 18 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 19 | | data\* | | `Array` or `Array` | Array of data | 20 | | value | `(Datum) => Datum` | `(Datum) => number` or `number` | Value accessor | 21 | | valueInactive | `1` | `number` | Value Inactive accessor | 22 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 23 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 24 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 25 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 26 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 27 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 28 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 29 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 30 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 31 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 32 | | center | `{x: width / 2, y: height / 2}` | `{x: number, y: number}` | Center of the dataviz | 33 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 34 | -------------------------------------------------------------------------------- /packages/datalith-ripple/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@datalith/ripple", 3 | "version": "0.12.1", 4 | "description": "datalith ripple", 5 | "main": "dist/index.js", 6 | "module": "dist/index.js", 7 | "types": "dist/types/index.d.ts", 8 | "scripts": { 9 | "prebuild": "rm -rf dist", 10 | "build": "tsc", 11 | "prepublish": "tsc" 12 | }, 13 | "files": [ 14 | "dist" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/lucafalasco/datalith.git" 19 | }, 20 | "keywords": [ 21 | "datalith", 22 | "react", 23 | "d3", 24 | "visualizations", 25 | "charts" 26 | ], 27 | "author": "@lucafalasco", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/lucafalasco/datalith/issues" 31 | }, 32 | "homepage": "https://github.com/lucafalasco/datalith#readme", 33 | "dependencies": { 34 | "@datalith/util": "^0.12.1", 35 | "d3-scale": "^3.0.0", 36 | "lodash": "^4.17.11", 37 | "react-tooltip": "^3.10.0" 38 | }, 39 | "devDependencies": { 40 | "@types/d3-scale": "^2.1.1", 41 | "@types/lodash": "^4.14.123", 42 | "@types/react": "^16.8.5", 43 | "@types/react-tooltip": "^3.9.2", 44 | "raf": "^3.4.1", 45 | "react": "^16.8.5", 46 | "react-dom": "^16.8.5", 47 | "react-test-renderer": "^16.8.5", 48 | "typescript": "^4.2.4" 49 | }, 50 | "peerDependencies": { 51 | "react": "^15.0.0-0 || ^16.0.0-0" 52 | }, 53 | "publishConfig": { 54 | "access": "public" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/datalith-ripple/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | callOrGetValue, 3 | CommonProps, 4 | Datum, 5 | ResponsiveWrapper, 6 | NumberAccessor, 7 | CommonAccessors, 8 | } from '@datalith/util' 9 | import { normalize } from '@datalith/util' 10 | import * as React from 'react' 11 | import Tooltip from 'react-tooltip' 12 | 13 | interface Props extends CommonProps { 14 | /** Value Accessor */ 15 | value: NumberAccessor 16 | /** Center of the dataviz */ 17 | center?: { x: number; y: number } 18 | } 19 | 20 | interface Center { 21 | x: number 22 | y: number 23 | } 24 | 25 | interface CircleProps extends CommonAccessors { 26 | datum: Datum 27 | value: NumberAccessor 28 | dataLength: number 29 | index: number 30 | center: Center 31 | tooltip?: (d: Datum) => string 32 | } 33 | 34 | const Circle = ({ 35 | datum, 36 | value: valueAccessor, 37 | dataLength, 38 | index, 39 | center, 40 | fill, 41 | fillOpacity, 42 | stroke, 43 | strokeOpacity, 44 | tooltip, 45 | }: CircleProps) => { 46 | const style = { 47 | fill: callOrGetValue(fill, datum, index), 48 | fillOpacity: 49 | !fill && !fillOpacity 50 | ? normalize(index, 0, dataLength) 51 | : callOrGetValue(fillOpacity, datum, index), 52 | stroke: callOrGetValue(stroke, datum, index), 53 | strokeOpacity: callOrGetValue(strokeOpacity, datum, index), 54 | } 55 | 56 | const radius = callOrGetValue(valueAccessor, datum, index) 57 | 58 | return ( 59 | 60 | 61 | 62 | ) 63 | } 64 | 65 | export class RippleComponent extends React.Component { 66 | static defaultProps = { 67 | value: d => d, 68 | } 69 | 70 | render() { 71 | const { 72 | className, 73 | style, 74 | additionalElements, 75 | data, 76 | value, 77 | fill, 78 | fillOpacity, 79 | stroke, 80 | strokeOpacity, 81 | tooltip, 82 | size: { width, height }, 83 | center = { 84 | x: width / 2, 85 | y: height / 2, 86 | }, 87 | } = this.props 88 | 89 | return ( 90 | <> 91 | 98 | {additionalElements} 99 | {data 100 | .sort((a, b) => callOrGetValue(value, b) - callOrGetValue(value, a, 0)) 101 | .map((datum, i) => ( 102 | 115 | ))} 116 | 117 | 118 | 119 | ) 120 | } 121 | } 122 | 123 | export const Ripple: React.ComponentType> = ResponsiveWrapper(RippleComponent) 124 | -------------------------------------------------------------------------------- /packages/datalith-ripple/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "allowJs": false, 6 | "declaration": true, 7 | "declarationDir": "dist/types" 8 | }, 9 | "include": ["src"], 10 | "exclude": ["src/**/*.test.ts*"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/datalith-shutter/README.md: -------------------------------------------------------------------------------- 1 | # @datalith/shutter 2 | 3 | ```sh 4 | yarn add @datalith/shutter 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | 11 | ``` 12 | 13 | | Name | Default | Type | Description | 14 | | :-------------------- | :------------------------------------ | :---------------------------------- | :----------------------------------------------------------- | 15 | | className | | `string` | Custom css classes to apply to the SVG | 16 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 17 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 18 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 19 | | data\* | | `Array` or `Array` | Array of data | 20 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 21 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 22 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 23 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 24 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 25 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 26 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 27 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 28 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 29 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 30 | | center | `{x: width / 2, y: height / 2}` | `{x: number, y: number}` | Center of the dataviz | 31 | | radiusOuter | `(Math.min(width, height) / 2) * 0.7` | `number` | Outer radius | 32 | | radiusInner | `radiusInner * 0.8` | `number` | Inner radius | 33 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 34 | -------------------------------------------------------------------------------- /packages/datalith-shutter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@datalith/shutter", 3 | "version": "0.12.1", 4 | "description": "datalith shutter", 5 | "main": "dist/index.js", 6 | "module": "dist/index.js", 7 | "types": "dist/types/index.d.ts", 8 | "scripts": { 9 | "prebuild": "rm -rf dist", 10 | "build": "tsc", 11 | "prepublish": "tsc" 12 | }, 13 | "files": [ 14 | "dist" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/lucafalasco/datalith.git" 19 | }, 20 | "keywords": [ 21 | "datalith", 22 | "react", 23 | "d3", 24 | "visualizations", 25 | "charts" 26 | ], 27 | "author": "@lucafalasco", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/lucafalasco/datalith/issues" 31 | }, 32 | "homepage": "https://github.com/lucafalasco/datalith#readme", 33 | "dependencies": { 34 | "@datalith/util": "^0.12.1", 35 | "d3-scale": "^3.0.0", 36 | "lodash": "^4.17.11", 37 | "react-tooltip": "^3.10.0" 38 | }, 39 | "devDependencies": { 40 | "@types/d3-scale": "^2.1.1", 41 | "@types/lodash": "^4.14.123", 42 | "@types/react": "^16.8.5", 43 | "@types/react-tooltip": "^3.9.2", 44 | "raf": "^3.4.1", 45 | "react": "^16.8.5", 46 | "react-dom": "^16.8.5", 47 | "react-test-renderer": "^16.8.5", 48 | "typescript": "^4.2.4" 49 | }, 50 | "peerDependencies": { 51 | "react": "^15.0.0-0 || ^16.0.0-0" 52 | }, 53 | "publishConfig": { 54 | "access": "public" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/datalith-shutter/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | callOrGetValue, 3 | CommonProps, 4 | Datum, 5 | ResponsiveWrapper, 6 | CommonAccessors, 7 | } from '@datalith/util' 8 | import { range } from 'lodash' 9 | import * as React from 'react' 10 | import Tooltip from 'react-tooltip' 11 | 12 | interface Props extends CommonProps { 13 | radiusInner?: number 14 | radiusOuter?: number 15 | /** Center of the visualization */ 16 | center?: { x: number; y: number } 17 | } 18 | 19 | interface Coords { 20 | x: number 21 | y: number 22 | } 23 | 24 | interface Polygon { 25 | p0: Coords 26 | p1: Coords 27 | p2: Coords 28 | } 29 | 30 | interface PolygonProps extends CommonAccessors { 31 | datum: Datum 32 | index: number 33 | dataLength: number 34 | radiusInner: number 35 | radiusOuter: number 36 | center: { x: number; y: number } 37 | tooltip?: (d: Datum) => string 38 | } 39 | 40 | function createPolygon(n: number, radius: number, offsetRad: number, center: Coords): Coords[] { 41 | const polygon = range(n).map((_, i) => { 42 | const theta = (i / n) * 2 * Math.PI + offsetRad 43 | const x = radius * Math.cos(theta) + center.x 44 | const y = radius * Math.sin(theta) + center.y 45 | return { x, y } 46 | }) 47 | return polygon 48 | } 49 | 50 | const getPolygonPoints = (polygon: Polygon): string => { 51 | const points = [polygon.p0, polygon.p1, polygon.p2] 52 | return points.map(p => `${p.x},${p.y}`).join(' ') 53 | } 54 | 55 | const Polygon = ({ 56 | datum, 57 | dataLength, 58 | index, 59 | center, 60 | radiusInner, 61 | radiusOuter, 62 | fill, 63 | fillOpacity, 64 | stroke, 65 | strokeOpacity, 66 | tooltip, 67 | }: PolygonProps) => { 68 | const theta = 0 // Angle (deg) that determines how the entire shutter is rotated: increasing theta will rotate the entire shutter counterclockwise 69 | const OM = radiusInner * Math.cos(Math.PI / dataLength) // lenght of the segment that link the center of the circle to the midpoint of a side of the inner (small) polygon 70 | const alpha = Math.acos(OM / radiusOuter!) + Math.PI / dataLength + theta // angle of rotation of the inner polygon (small) 71 | 72 | const polygonBig = createPolygon(dataLength, radiusOuter!, theta, center) 73 | const polygonSmall = createPolygon(dataLength, radiusInner!, alpha, center) 74 | 75 | const j = index === dataLength - 1 ? 0 : index + 1 76 | const d = { p0: polygonBig[index], p1: polygonBig[j], p2: polygonSmall[index] } 77 | 78 | const style = { 79 | fill: callOrGetValue(fill, datum, index), 80 | fillOpacity: callOrGetValue(fillOpacity, datum, index), 81 | stroke: callOrGetValue(stroke, datum, index), 82 | strokeOpacity: callOrGetValue(strokeOpacity, datum, index), 83 | } 84 | 85 | const points = getPolygonPoints(d) 86 | 87 | return ( 88 | 89 | 90 | 91 | ) 92 | } 93 | 94 | export class ShutterComponent extends React.Component { 95 | static defaultProps = { 96 | fill: d => d, 97 | } 98 | 99 | render() { 100 | const defaultRadius = (Math.min(this.props.size.width, this.props.size.height) / 2) * 0.4 101 | const { 102 | className, 103 | style, 104 | additionalElements, 105 | data, 106 | fill, 107 | fillOpacity, 108 | stroke, 109 | strokeOpacity, 110 | tooltip, 111 | radiusInner = defaultRadius, 112 | radiusOuter = defaultRadius + 50, 113 | size: { width, height }, 114 | center = { 115 | x: width / 2, 116 | y: height / 2, 117 | }, 118 | } = this.props 119 | 120 | return ( 121 | <> 122 | 129 | {additionalElements} 130 | {data.map((datum, i) => ( 131 | 145 | ))} 146 | 147 | 148 | 149 | ) 150 | } 151 | } 152 | 153 | export const Shutter: React.ComponentType> = ResponsiveWrapper(ShutterComponent) 154 | -------------------------------------------------------------------------------- /packages/datalith-shutter/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "allowJs": false, 6 | "declaration": true, 7 | "declarationDir": "dist/types" 8 | }, 9 | "include": ["src"], 10 | "exclude": ["src/**/*.test.ts*"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/datalith-spiral/README.md: -------------------------------------------------------------------------------- 1 | # @datalith/spiral 2 | 3 | ```sh 4 | yarn add @datalith/spiral 5 | ``` 6 | 7 | ## Docs 8 | 9 | ```jsx 10 | 11 | ``` 12 | 13 | | Name | Default | Type | Description | 14 | | :-------------------- | :------------------------------------------------ | :---------------------------------------------------------------------------- | :----------------------------------------------------------- | 15 | | className | | `string` | Custom css classes to apply to the SVG | 16 | | style | | `React.CSSProperties` | Custom style object to apply to the SVG | 17 | | additionalElements | | `JSX.Element` | Optional elements to add to the SVG | 18 | | size | | `{ width: number; height: number }` | Width and Height of the SVG. Default is parent node size. | 19 | | data\* | | `Array` or `Array` | Array of data | 20 | | value | `(Datum) => Datum` | `(Datum) => number` or `number` | Value accessor | 21 | | valueInactive | `1` | `number` | Value Inactive accessor | 22 | | fill | | `(Datum) => string` or `string` | Fill color accessor | 23 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 24 | | fillOpacity | | `(Datum) => number` or `number` | Fill Opacity accessor | 25 | | fillOpacityInactive | `0.3` | `number` | Fill Opacity Inactive accessor | 26 | | fillInactive | `#000` | `string` | Fill Inactive accessor | 27 | | stroke | | `(Datum) => string` or `string` | Stroke color accessor | 28 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 29 | | strokeOpacity | | `(Datum) => number` or `number` | Stroke Opacity accessor | 30 | | strokeOpacityInactive | `0.3` | `number` | Stroke Opacity Inactive accessor | 31 | | strokeInactive | `transparent` | `string` | Stroke Inactive accessor | 32 | | spacing | `Math.min(Math.min(width, height), 2000) * 0.015` | `number` | Spacing between points | 33 | | getSpiralCoords | | `(size: { width: number; height: number; }) => Array<{x: number, y: number}>` | Optional function to manually compute data points position | 34 | | center | `{x: width / 2, y: height / 2}` | `{x: number, y: number}` | Center of the dataviz | 35 | | tooltip | | `(Datum) => string` | Return HTML or text as a string to show on element mouseover | 36 | -------------------------------------------------------------------------------- /packages/datalith-spiral/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@datalith/spiral", 3 | "version": "0.12.1", 4 | "description": "datalith spiral", 5 | "main": "dist/index.js", 6 | "module": "dist/index.js", 7 | "types": "dist/types/index.d.ts", 8 | "scripts": { 9 | "prebuild": "rm -rf dist", 10 | "build": "tsc", 11 | "prepublish": "tsc" 12 | }, 13 | "files": [ 14 | "dist" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/lucafalasco/datalith.git" 19 | }, 20 | "keywords": [ 21 | "datalith", 22 | "react", 23 | "d3", 24 | "visualizations", 25 | "charts" 26 | ], 27 | "author": "@lucafalasco", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/lucafalasco/datalith/issues" 31 | }, 32 | "homepage": "https://github.com/lucafalasco/datalith#readme", 33 | "dependencies": { 34 | "@datalith/util": "^0.12.1", 35 | "d3-scale": "^3.0.0", 36 | "lodash": "^4.17.11", 37 | "react-tooltip": "^3.10.0" 38 | }, 39 | "devDependencies": { 40 | "@types/d3-scale": "^2.1.1", 41 | "@types/lodash": "^4.14.123", 42 | "@types/react": "^16.8.23", 43 | "@types/react-tooltip": "^3.9.2", 44 | "raf": "^3.4.1", 45 | "react": "^16.8.5", 46 | "react-dom": "^16.8.5", 47 | "react-test-renderer": "^16.8.5", 48 | "typescript": "^4.2.4" 49 | }, 50 | "peerDependencies": { 51 | "react": "^15.0.0-0 || ^16.0.0-0" 52 | }, 53 | "publishConfig": { 54 | "access": "public" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/datalith-spiral/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | callOrGetValue, 3 | CommonProps, 4 | Datum, 5 | ResponsiveWrapper, 6 | NumberAccessor, 7 | CommonAccessors, 8 | } from '@datalith/util' 9 | import * as React from 'react' 10 | import Tooltip from 'react-tooltip' 11 | 12 | interface Props extends CommonProps { 13 | /** Value Accessor */ 14 | value: NumberAccessor 15 | /** Center of the dataviz */ 16 | center?: { x: number; y: number } 17 | /** Spacing between points */ 18 | spacing?: number 19 | /** 20 | * Optional function to manually compute data points position. 21 | * Passing this function overrides `spacing` prop value 22 | * @param size container dimensions, defined as an object {width, height} 23 | * @return Array of xy coordinates starting from center origin , defined as an object {x, y} 24 | **/ 25 | getSpiralCoords?: (size: { width: number; height: number }) => Array<{ x: number; y: number }> 26 | } 27 | 28 | interface CircleProps extends CommonAccessors { 29 | datum: Datum 30 | value: NumberAccessor 31 | x: number 32 | y: number 33 | index: number 34 | tooltip?: (d: Datum) => string 35 | } 36 | 37 | function getDefaultSpiralCoords(data: Datum[], spacing: number) { 38 | let angle = 0 39 | const coords: Array<{ x: number; y: number }> = [] 40 | 41 | for (let i = 0; i < data.length; i++) { 42 | const radius = Math.pow(angle, 2) 43 | 44 | // using quadratic formula as suggested here: https://stackoverflow.com/questions/13894715/draw-equidistant-points-on-a-spiral 45 | const delta = (-2 * radius + Math.sqrt(4 * radius * radius + 20 * spacing)) / 4 46 | 47 | coords.push({ 48 | x: radius * Math.cos(angle), 49 | y: radius * Math.sin(angle), 50 | }) 51 | 52 | angle += delta 53 | } 54 | 55 | return coords 56 | } 57 | 58 | const Circle = ({ 59 | datum, 60 | value: valueAccessor, 61 | index, 62 | x, 63 | y, 64 | fill, 65 | fillOpacity, 66 | stroke, 67 | strokeOpacity, 68 | tooltip, 69 | }: CircleProps) => { 70 | const style = { 71 | fill: callOrGetValue(fill, datum, index), 72 | fillOpacity: !fill && !fillOpacity ? 0.8 : callOrGetValue(fillOpacity, datum, index), 73 | stroke: callOrGetValue(stroke, datum, index), 74 | strokeOpacity: callOrGetValue(strokeOpacity, datum, index), 75 | } 76 | 77 | const radius = callOrGetValue(valueAccessor, datum, index) 78 | 79 | return ( 80 | 81 | 82 | 83 | ) 84 | } 85 | 86 | export class SpiralComponent extends React.Component { 87 | static defaultProps = { 88 | value: d => d, 89 | } 90 | 91 | render() { 92 | const { 93 | className, 94 | style, 95 | additionalElements, 96 | data, 97 | value, 98 | fill, 99 | fillOpacity, 100 | stroke, 101 | strokeOpacity, 102 | tooltip, 103 | getSpiralCoords, 104 | size: { width, height }, 105 | center = { 106 | x: width / 2, 107 | y: height / 2, 108 | }, 109 | } = this.props 110 | 111 | const { spacing = Math.min(Math.min(width, height), 2000) * 0.015 } = this.props 112 | const coords = getSpiralCoords 113 | ? getSpiralCoords({ width, height }) 114 | : getDefaultSpiralCoords(data, spacing) 115 | 116 | return ( 117 | <> 118 | 125 | {additionalElements} 126 | 127 | {data.map((datum, i) => ( 128 | 141 | ))} 142 | 143 | 144 | 145 | 146 | ) 147 | } 148 | } 149 | 150 | export const Spiral: React.ComponentType> = ResponsiveWrapper(SpiralComponent) 151 | -------------------------------------------------------------------------------- /packages/datalith-spiral/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "allowJs": false, 6 | "declaration": true, 7 | "declarationDir": "dist/types" 8 | }, 9 | "include": ["src"], 10 | "exclude": ["src/**/*.test.ts*"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/datalith-storybook/.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | stories: ['../src/components/*.stories.@(tsx|jsx)'], 3 | addons: ['@storybook/addon-docs'], 4 | } 5 | -------------------------------------------------------------------------------- /packages/datalith-storybook/.storybook/manager.js: -------------------------------------------------------------------------------- 1 | import { create } from '@storybook/theming' 2 | import { addons } from '@storybook/addons' 3 | import Logo from '../public/logo-ext.svg' 4 | 5 | const theme = create({ 6 | base: 'light', 7 | 8 | // // Color palette 9 | // colorPrimary: '', // primary color 10 | colorSecondary: '#171f2c', // secondary color 11 | 12 | // // UI 13 | // appBg: '', 14 | // appContentBg: '', 15 | // appBorderColor: '', 16 | // appBorderRadius: 2, 17 | 18 | // // Fonts 19 | fontBase: '"Titillium Web", sans-serif', 20 | fontCode: 'Menlo, monospace', 21 | 22 | // // Text colors 23 | // textColor: '', 24 | // textInverseColor: '', 25 | 26 | // // Toolbar default and active colors 27 | // barTextColor: '', 28 | // barSelectedColor: '', 29 | // barBg: '', 30 | 31 | // // Form colors 32 | // inputBg: '', 33 | // inputBorder: '', 34 | // inputTextColor: '', 35 | // inputBorderRadius: 2, 36 | 37 | // Brand logo/text 38 | brandImage: Logo, 39 | brandTitle: 'datalith', 40 | }) 41 | 42 | addons.setConfig({ theme }) 43 | -------------------------------------------------------------------------------- /packages/datalith-storybook/.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | 45 | -------------------------------------------------------------------------------- /packages/datalith-storybook/.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import { 2 | Title, 3 | Subtitle, 4 | Description, 5 | ArgsTable, 6 | PRIMARY_STORY, 7 | Source, 8 | } from '@storybook/addon-docs/blocks' 9 | 10 | export const parameters = { 11 | options: { 12 | storySort: { 13 | order: ['INTRO', 'DATALITHS'], 14 | }, 15 | }, 16 | docs: { 17 | page: () => ( 18 | <> 19 | 20 | <Subtitle /> 21 | <Description /> 22 | <Source dark={true} /> 23 | <ArgsTable story={PRIMARY_STORY} /> 24 | </> 25 | ), 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /packages/datalith-storybook/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucafalasco/datalith/f3a304eadb1d2ff7220c93bcf48295e8c81f3a60/packages/datalith-storybook/README.md -------------------------------------------------------------------------------- /packages/datalith-storybook/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@datalith/storybook", 3 | "description": "datalith storybook", 4 | "version": "0.12.1", 5 | "author": "Luca Falasco", 6 | "license": "MIT", 7 | "main": "dist/index.js", 8 | "types": "dist/types/index.d.ts", 9 | "scripts": { 10 | "test": "jest", 11 | "test:watch": "jest --watch", 12 | "lint": "tslint --project tsconfig.json -t codeFrame 'src/**/*.ts*'", 13 | "prebuild": "rm -rf dist", 14 | "build": "tsc", 15 | "storybook": "start-storybook -p 6006 -s ./public", 16 | "build-storybook": "build-storybook -s ./public -o ../../storybook" 17 | }, 18 | "dependencies": { 19 | "@datalith/barcode": "^0.12.1", 20 | "@datalith/dotmap": "^0.12.1", 21 | "@datalith/flower": "^0.12.1", 22 | "@datalith/gridmap": "^0.12.1", 23 | "@datalith/hexmap": "^0.12.1", 24 | "@datalith/pack": "^0.12.1", 25 | "@datalith/pixelmap": "^0.12.1", 26 | "@datalith/ripple": "^0.12.1", 27 | "@datalith/shutter": "^0.12.1", 28 | "@datalith/spiral": "^0.12.1", 29 | "@datalith/util": "^0.12.1", 30 | "d3-array": "^2.0.3", 31 | "d3-geo": "^1.11.6", 32 | "d3-scale": "^3.0.0", 33 | "react-spring": "^8.0.19", 34 | "topojson": "^3.0.2" 35 | }, 36 | "peerDependencies": { 37 | "react": "^16.x", 38 | "react-dom": "^16.x" 39 | }, 40 | "devDependencies": { 41 | "@babel/core": "^7.13.14", 42 | "@storybook/addon-docs": "^6.2.5", 43 | "@storybook/addon-essentials": "^6.2.5", 44 | "@storybook/addons": "^6.2.5", 45 | "@storybook/react": "^6.2.5", 46 | "@storybook/theming": "^6.2.5", 47 | "@types/d3-array": "^2.0.0", 48 | "@types/d3-geo": "^2.0.0", 49 | "@types/d3-scale": "^3.2.2", 50 | "@types/enzyme": "^3.9.1", 51 | "@types/jest": "^26.0.22", 52 | "@types/node": "^14.14.37", 53 | "@types/react": "^17.0.3", 54 | "@types/react-dom": "^17.0.3", 55 | "@types/storybook__react": "^5.2.1", 56 | "@types/topojson": "^3.2.3", 57 | "babel-loader": "^8.2.2", 58 | "css-loader": "^2.1.1", 59 | "del-cli": "^2.0.0", 60 | "file-loader": "^3.0.1", 61 | "glob-loader": "^0.3.0", 62 | "react": "^17.0.2", 63 | "react-dom": "^17.0.2", 64 | "react-scripts": "^4.0.3", 65 | "style-loader": "^0.23.1", 66 | "ts-loader": "^8.1.0", 67 | "tslint": "^6.1.3", 68 | "tslint-config-prettier": "^1.18.0", 69 | "tslint-react": "^5.0.0", 70 | "typescript": "^4.2.4" 71 | }, 72 | "publishConfig": { 73 | "access": "public" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /packages/datalith-storybook/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucafalasco/datalith/f3a304eadb1d2ff7220c93bcf48295e8c81f3a60/packages/datalith-storybook/public/favicon.ico -------------------------------------------------------------------------------- /packages/datalith-storybook/public/logo-ext.svg: -------------------------------------------------------------------------------- 1 | <svg width="228" height="56" viewBox="0 0 228 56" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <path d="M10.0938 1.5H46.9062C51.6591 1.5 55.5 5.34093 55.5 10.0938V45.4813C55.5 50.2341 51.6591 54.075 46.9062 54.075H10.0938C5.34093 54.075 1.5 50.2341 1.5 45.4813V10.0938C1.5 5.34093 5.34093 1.5 10.0938 1.5Z" fill="#212121" stroke="#E5E5E5" stroke-width="3"/> 3 | <path d="M27.5149 16.3875C36.096 16.3875 39.1839 20.7432 39.1839 28.1592C39.3301 34.1666 35.0559 39.2833 28.3275 39.1861H17.8125V16.3875H27.5149Z" fill="white" stroke="white" stroke-width="3" stroke-linejoin="round"/> 4 | <path d="M78.79 38.1H70V18H78.49C81.95 18 84.44 18.78 85.96 20.34C87.48 21.9 88.24 24.4 88.24 27.84C88.24 31.26 87.51 33.83 86.05 35.55C84.59 37.25 82.17 38.1 78.79 38.1ZM81.22 28.17C81.22 26.37 81.03 25.17 80.65 24.57C80.29 23.97 79.47 23.67 78.19 23.67H76.96V32.43H78.19C79.23 32.43 80 32.17 80.5 31.65C80.98 31.13 81.22 29.97 81.22 28.17Z" fill="#212121"/> 5 | <path d="M92.493 38.1L96.933 18H107.463L111.993 38.1H104.973L104.403 35.79H99.813L99.333 38.1H92.493ZM101.853 23.46L100.713 30.48H103.683L102.603 23.46H101.853Z" fill="#212121"/> 6 | <path d="M114.874 23.67V18H129.874V23.67H125.974V38.1H119.014V23.67H114.874Z" fill="#212121"/> 7 | <path d="M132.841 38.1L137.281 18H147.811L152.341 38.1H145.321L144.751 35.79H140.161L139.681 38.1H132.841ZM142.201 23.46L141.061 30.48H144.031L142.951 23.46H142.201Z" fill="#212121"/> 8 | <path d="M171.051 38.1H157.551V18H164.511V32.43H171.051V38.1Z" fill="#212121"/> 9 | <path d="M176.729 38.1V18H183.689V38.1H176.729Z" fill="#212121"/> 10 | <path d="M189.358 23.67V18H204.358V23.67H200.458V38.1H193.498V23.67H189.358Z" fill="#212121"/> 11 | <path d="M220.935 38.1V31.08H217.005V38.1H210.045V18H217.005V25.41H220.935V18H227.895V38.1H220.935Z" fill="#212121"/> 12 | </svg> 13 | -------------------------------------------------------------------------------- /packages/datalith-storybook/public/logo.svg: -------------------------------------------------------------------------------- 1 | <svg width="240" height="234" viewBox="0 0 240 234" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <path d="M42.5 0H197.5C221 0 240 19 240 42.5V191.5C240 215 221 234 197.5 234H42.5C19 234 0 215 0 191.5V42.5C0 19 19 0 42.5 0Z" fill="#212121"/> 3 | <path d="M115.087 60C157.616 60 172.919 81.5875 172.919 118.342C173.644 148.115 152.46 173.475 119.114 172.993H67V60H115.087Z" fill="#EBEBEB" stroke="#EBEBEB" stroke-width="10" stroke-linejoin="round"/> 4 | </svg> 5 | -------------------------------------------------------------------------------- /packages/datalith-storybook/src/components/barcode.stories.tsx: -------------------------------------------------------------------------------- 1 | import { BarCode, BarCodeComponent } from '@datalith/barcode/src' 2 | import { scaleLinear } from 'd3-scale' 3 | import React from 'react' 4 | import { Spring } from 'react-spring/renderprops' 5 | import { easeInOutCubic } from '../lib' 6 | import { genDateValue } from '../scripts' 7 | 8 | const defaultData = genDateValue(100) 9 | const defaultDataLong = genDateValue(200) 10 | 11 | const y = d => d.value 12 | 13 | const defs = ( 14 | <defs> 15 | <linearGradient id="gradient" gradientTransform="rotate(90)"> 16 | <stop offset="0%" stopColor="#6f42c1" /> 17 | <stop offset="100%" stopColor="#0bbba9" /> 18 | </linearGradient> 19 | </defs> 20 | ) 21 | 22 | // scales 23 | const yScale = scaleLinear() 24 | .domain([0, Math.max(...defaultData.map(y))]) 25 | .range([0, 100]) 26 | 27 | const zScale = scaleLinear() 28 | .domain([0, Math.max(...defaultData.map(y))]) 29 | .range([0.1, 0.9]) 30 | .nice() 31 | 32 | export default { 33 | title: 'DATALITHS/BarCode', 34 | component: BarCodeComponent, 35 | } 36 | 37 | export const basic = () => ( 38 | <BarCode data={defaultData} value={d => yScale(d.value)} fillOpacity={d => zScale(d.value)} /> 39 | ) 40 | export const large = () => { 41 | return ( 42 | <BarCode 43 | style={{ backgroundColor: '#171f2c' }} 44 | data={defaultDataLong} 45 | value={d => yScale(d.value)} 46 | fill="#12c5e5" 47 | fillOpacity={d => zScale(d.value)} 48 | /> 49 | ) 50 | } 51 | export const strip = () => { 52 | return ( 53 | <BarCode 54 | style={{ backgroundColor: '#171f2c' }} 55 | data={defaultData} 56 | value={100} 57 | barWidth={7} 58 | fill="#0bbba9" 59 | fillOpacity={d => zScale(d.value)} 60 | /> 61 | ) 62 | } 63 | export const animated = () => { 64 | return ( 65 | <Spring 66 | from={{ index: 0, opacity: defaultData.map(d => 0) }} 67 | to={{ index: defaultData.length, opacity: defaultData.map(d => zScale(d.value)) }} 68 | config={{ duration: 1500, easing: easeInOutCubic }} 69 | > 70 | {props => { 71 | const data = defaultData.slice(0, props.index) 72 | 73 | return ( 74 | <BarCode 75 | style={{ backgroundColor: '#171f2c' }} 76 | data={data} 77 | value={d => yScale(d.value)} 78 | fill="#6f42c1" 79 | fillOpacity={(d, i) => props.opacity[i]} 80 | /> 81 | ) 82 | }} 83 | </Spring> 84 | ) 85 | } 86 | export const tooltip = () => { 87 | return ( 88 | <BarCode 89 | style={{ backgroundColor: '#171f2c' }} 90 | data={defaultDataLong} 91 | additionalElements={defs} 92 | value={d => yScale(d.value)} 93 | fill="url(#gradient)" 94 | fillOpacity={d => zScale(d.value)} 95 | tooltip={({ date, value }) => 96 | `<p><b>Date: </b><u>${date.toLocaleDateString()}</u></p> 97 | <p><b>Value: </b>${Number(value).toFixed(2)}</p>` 98 | } 99 | /> 100 | ) 101 | } 102 | -------------------------------------------------------------------------------- /packages/datalith-storybook/src/components/dotmap.stories.tsx: -------------------------------------------------------------------------------- 1 | import { DotMap, DotMapUs, DotMapWorld } from '@datalith/dotmap/src' 2 | import italyTopology from '@datalith/gridmap/src/json/italy.json' 3 | import { geoNaturalEarth1, geoOrthographic } from 'd3-geo' 4 | import { scaleLinear } from 'd3-scale' 5 | import * as React from 'react' 6 | import { feature } from 'topojson' 7 | import { genCoordsValue, genCoordsValueIt, genCoordsValueUs } from '../scripts' 8 | 9 | interface ItalyAtlas extends TopoJSON.Topology { 10 | objects: { 11 | sub: TopoJSON.GeometryCollection 12 | } 13 | } 14 | 15 | const y = d => d.value 16 | const defaultData = genCoordsValue(200) 17 | const side = 10 18 | 19 | const defaultDataUs = genCoordsValueUs(1000) 20 | const defaultDataIt = genCoordsValueIt(200) 21 | const italyAtlas = italyTopology as any 22 | const italy = feature(italyAtlas, (italyAtlas as ItalyAtlas).objects.sub) 23 | const projection = geoNaturalEarth1() 24 | 25 | const yScale = scaleLinear() 26 | .domain([Math.min(...defaultData.map(y)), Math.max(...defaultData.map(y))]) 27 | .range([1, side * 0.5]) 28 | 29 | const zScale = scaleLinear() 30 | .domain([0, Math.max(...defaultData.map(y))]) 31 | .range([0.1, 0.9]) 32 | .nice() 33 | 34 | export default { 35 | title: 'DATALITHS/DotMap', 36 | component: DotMap, 37 | } 38 | 39 | export const naturalEarth = () => { 40 | return ( 41 | <DotMapWorld 42 | style={{ backgroundColor: '#171f2c' }} 43 | side={side} 44 | data={defaultData} 45 | coords={d => [d.lng, d.lat]} 46 | value={side * 0.4} 47 | valueInactive={side * 0.4} 48 | fill="#0bbba9" 49 | fillInactive="#2b3a53" 50 | fillOpacity={d => zScale(d.value)} 51 | fillOpacityInactive={0.4} 52 | /> 53 | ) 54 | } 55 | export const orthographic = () => { 56 | return ( 57 | <DotMapWorld 58 | style={{ backgroundColor: '#171f2c' }} 59 | side={side} 60 | data={defaultData} 61 | fill="#0bbba9" 62 | fillInactive="#2b3a53" 63 | coords={d => [d.lng, d.lat]} 64 | value={d => yScale(d.value)} 65 | projection={geoOrthographic()} 66 | /> 67 | ) 68 | } 69 | export const outline = () => { 70 | return ( 71 | <DotMapWorld 72 | style={{ backgroundColor: '#171f2c' }} 73 | side={side} 74 | data={defaultData} 75 | coords={d => [d.lng, d.lat]} 76 | value={d => yScale(d.value)} 77 | stroke="#12c5e5" 78 | strokeInactive="#12c5e5" 79 | fillInactive="transparent" 80 | fill="transparent" 81 | /> 82 | ) 83 | } 84 | export const tooltip = () => { 85 | return ( 86 | <DotMapWorld 87 | style={{ backgroundColor: '#171f2c' }} 88 | side={side} 89 | data={defaultData} 90 | coords={d => [d.lng, d.lat]} 91 | value={side * 0.4} 92 | valueInactive={side * 0.4} 93 | fill="#6f42c1" 94 | fillInactive="#2b3a53" 95 | fillOpacity={d => zScale(d.value)} 96 | fillOpacityInactive={0.4} 97 | tooltip={({ value }) => `<p><b>Value: </b>${value.toFixed(2)}</p>`} 98 | /> 99 | ) 100 | } 101 | export const us = () => { 102 | return ( 103 | <DotMapUs 104 | style={{ backgroundColor: '#171f2c' }} 105 | side={side} 106 | data={defaultDataUs} 107 | coords={d => [d.lng, d.lat]} 108 | value={side * 0.4} 109 | valueInactive={side * 0.4} 110 | fill="#0bbba9" 111 | fillInactive="#2b3a53" 112 | fillOpacity={d => zScale(d.value)} 113 | fillOpacityInactive={0.4} 114 | tooltip={({ value }) => `<p><b>Value: </b>${value.toFixed(2)}</p>`} 115 | /> 116 | ) 117 | } 118 | export const customGeojson = () => { 119 | return ( 120 | <DotMap 121 | style={{ backgroundColor: '#171f2c' }} 122 | side={side} 123 | data={defaultDataIt} 124 | featureCollection={italy} 125 | projection={projection} 126 | coords={d => [d.lng, d.lat]} 127 | value={side * 0.4} 128 | valueInactive={side * 0.4} 129 | fill="#6f42c1" 130 | fillInactive="#2b3a53" 131 | fillOpacity={d => zScale(d.value)} 132 | fillOpacityInactive={0.4} 133 | tooltip={({ value }) => `<p><b>Value: </b>${value.toFixed(2)}</p>`} 134 | /> 135 | ) 136 | } 137 | -------------------------------------------------------------------------------- /packages/datalith-storybook/src/components/flower.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Flower, FlowerComponent } from '@datalith/flower/src' 2 | import { normalize } from '@datalith/util' 3 | import { scaleLinear } from 'd3-scale' 4 | import * as React from 'react' 5 | import { Spring } from 'react-spring/renderprops' 6 | import { easeInOutCubic } from '../lib' 7 | import { genDateValue } from '../scripts' 8 | 9 | const width = window.innerWidth 10 | const height = window.innerHeight 11 | const defaultData = genDateValue(20) 12 | 13 | const y = d => d.value 14 | 15 | const defs = ( 16 | <defs> 17 | <linearGradient id="gradient" gradientTransform="rotate(90)"> 18 | <stop offset="0%" stopColor="#6f42c1" /> 19 | <stop offset="100%" stopColor="#0bbba9" /> 20 | </linearGradient> 21 | </defs> 22 | ) 23 | 24 | // scales 25 | const yScale = scaleLinear() 26 | .domain([0, Math.max(...defaultData.map(y))]) 27 | .range([0, Math.min(width, height) * 0.2]) 28 | 29 | const zScale = scaleLinear() 30 | .domain([0, Math.max(...defaultData.map(y))]) 31 | .range([0.1, 0.9]) 32 | .nice() 33 | 34 | export default { 35 | title: 'DATALITHS/Flower', 36 | component: FlowerComponent, 37 | } 38 | 39 | export const basic = () => { 40 | return <Flower data={defaultData} value={d => yScale(d.value)} /> 41 | } 42 | export const outline = () => { 43 | const data = defaultData.map(d => yScale(d.value)) 44 | return ( 45 | <Flower 46 | style={{ backgroundColor: '#171f2c' }} 47 | data={data} 48 | stroke="#0bbba9" 49 | fill="transparent" 50 | /> 51 | ) 52 | } 53 | export const sorted = () => { 54 | const data = [...defaultData].sort((a, b) => b.value - a.value) 55 | 56 | return ( 57 | <Flower 58 | style={{ backgroundColor: '#171f2c' }} 59 | data={data} 60 | value={d => yScale(d.value)} 61 | fill="#12c5e5" 62 | fillOpacity={(d, i) => normalize(i + 1, 1, data.length)} 63 | /> 64 | ) 65 | } 66 | export const animated = () => { 67 | return ( 68 | <Spring 69 | from={{ value: defaultData.map(d => 0) }} 70 | to={{ value: defaultData.map(y) }} 71 | config={{ duration: 1000, easing: easeInOutCubic }} 72 | > 73 | {props => { 74 | return ( 75 | <Flower 76 | style={{ backgroundColor: '#171f2c' }} 77 | data={defaultData} 78 | value={(d, i) => yScale(props.value[i])} 79 | fill={(d, i) => (i % 2 ? '#12c5e5' : '#6f42c1')} 80 | /> 81 | ) 82 | }} 83 | </Spring> 84 | ) 85 | } 86 | export const tooltip = () => { 87 | return ( 88 | <Flower 89 | style={{ backgroundColor: '#171f2c' }} 90 | data={defaultData} 91 | value={d => yScale(d.value)} 92 | fill="#00d09b" 93 | fillOpacity={d => zScale(d.value)} 94 | tooltip={({ date, value }) => 95 | `<p><b>Date: </b><u>${date.toLocaleDateString()}</u></p> 96 | <p><b>Value: </b>${yScale.invert(Number(value)).toFixed(2)}</p>` 97 | } 98 | /> 99 | ) 100 | } 101 | export const gradient = () => { 102 | return ( 103 | <Flower 104 | style={{ backgroundColor: '#171f2c' }} 105 | data={defaultData} 106 | additionalElements={defs} 107 | value={d => yScale(d.value)} 108 | fill="url('#gradient')" 109 | /> 110 | ) 111 | } 112 | -------------------------------------------------------------------------------- /packages/datalith-storybook/src/components/gridmap.stories.tsx: -------------------------------------------------------------------------------- 1 | import { GridMap, GridMapComponent, GridMapUs, GridMapWorld } from '@datalith/gridmap/src' 2 | import italyTopology from '@datalith/gridmap/src/json/italy.json' 3 | import { geoNaturalEarth1 } from 'd3-geo' 4 | import { scaleLinear } from 'd3-scale' 5 | import * as React from 'react' 6 | import { feature } from 'topojson' 7 | import { genCoordsValue, genCoordsValueIt, genCoordsValueUs } from '../scripts' 8 | 9 | interface ItalyAtlas extends TopoJSON.Topology { 10 | objects: { 11 | sub: TopoJSON.GeometryCollection 12 | } 13 | } 14 | 15 | const y = d => d.value 16 | const defaultData = genCoordsValue(200) 17 | const side = 10 18 | 19 | const defaultDataUs = genCoordsValueUs(1000) 20 | const defaultDataIt = genCoordsValueIt(200) 21 | const italyAtlas = italyTopology as any 22 | const italy = feature(italyAtlas, (italyAtlas as ItalyAtlas).objects.sub) 23 | const projection = geoNaturalEarth1() 24 | 25 | const yScale = scaleLinear() 26 | .domain([Math.min(...defaultData.map(y)), Math.max(...defaultData.map(y))]) 27 | .range([1, side * 0.8]) 28 | 29 | const zScale = scaleLinear() 30 | .domain([0, Math.max(...defaultData.map(y))]) 31 | .range([0.1, 0.9]) 32 | .nice() 33 | 34 | export default { 35 | title: 'DATALITHS/GridMap', 36 | component: GridMapComponent, 37 | } 38 | 39 | export const cross = () => { 40 | return ( 41 | <GridMapWorld 42 | style={{ backgroundColor: '#171f2c' }} 43 | side={side} 44 | data={defaultData} 45 | coords={d => [d.lng, d.lat]} 46 | value={d => yScale(d.value)} 47 | stroke="#0bbba9" 48 | customRender={({ x, y, value, datum }, defaultProps) => 49 | datum !== undefined ? ( 50 | <path 51 | strokeWidth={1} 52 | strokeLinecap="round" 53 | d={`M${x - value / 2} ${y - value / 2} 54 | L${x + value / 2} ${y + value / 2} 55 | M${x + value / 2} ${y - value / 2} 56 | L${x - value / 2} ${y + value / 2}`} 57 | {...defaultProps} 58 | /> 59 | ) : ( 60 | <circle cx={x} cy={y} r={2} fill="#2b3a53" /> 61 | ) 62 | } 63 | /> 64 | ) 65 | } 66 | export const text = () => { 67 | return ( 68 | <GridMapWorld 69 | style={{ backgroundColor: '#171f2c' }} 70 | side={side} 71 | data={defaultData} 72 | fill="#12c5e5" 73 | fillInactive="#2b3a53" 74 | coords={d => [d.lng, d.lat]} 75 | customRender={({ x, y, datum }, defaultProps) => ( 76 | <text 77 | x={x} 78 | y={y} 79 | textAnchor="middle" 80 | fontSize={10} 81 | fontFamily="monospace" 82 | fontWeight={700} 83 | alignmentBaseline="middle" 84 | {...defaultProps} 85 | > 86 | {datum ? '1' : '0'} 87 | </text> 88 | )} 89 | /> 90 | ) 91 | } 92 | export const triangles = () => { 93 | return ( 94 | <GridMapWorld 95 | style={{ backgroundColor: '#171f2c' }} 96 | side={side} 97 | data={defaultData} 98 | coords={d => [d.lng, d.lat]} 99 | value={d => yScale(d.value) * 0.7} 100 | fill="#6f42c1" 101 | fillOpacity={d => zScale(d.value)} 102 | customRender={({ x, y, value, datum }, defaultProps) => 103 | datum ? ( 104 | <path 105 | d={`M${x - value} ${y + value} 106 | L${x + value} ${y + value} 107 | L${x} ${y - value} 108 | Z`} 109 | {...defaultProps} 110 | /> 111 | ) : ( 112 | <circle cx={x} cy={y} r={2} fill="#2b3a53" /> 113 | ) 114 | } 115 | /> 116 | ) 117 | } 118 | export const us = () => { 119 | return ( 120 | <GridMapUs 121 | style={{ backgroundColor: '#171f2c' }} 122 | side={side} 123 | data={defaultDataUs} 124 | coords={d => [d.lng, d.lat]} 125 | value={d => yScale(d.value) * 0.7} 126 | fill="#0bbba9" 127 | fillOpacity={d => zScale(d.value)} 128 | customRender={({ x, y, value, datum }, defaultProps) => 129 | datum ? ( 130 | <path 131 | d={`M${x - value} ${y + value} 132 | L${x + value} ${y + value} 133 | L${x} ${y - value} 134 | Z`} 135 | {...defaultProps} 136 | /> 137 | ) : ( 138 | <circle cx={x} cy={y} r={2} fill="#2b3a53" /> 139 | ) 140 | } 141 | /> 142 | ) 143 | } 144 | export const customGeojson = () => { 145 | return ( 146 | <GridMap 147 | style={{ backgroundColor: '#171f2c' }} 148 | side={side} 149 | data={defaultDataIt} 150 | featureCollection={italy} 151 | projection={projection} 152 | coords={d => [d.lng, d.lat]} 153 | value={d => yScale(d.value) * 0.7} 154 | fill="#6f42c1" 155 | fillOpacity={d => zScale(d.value)} 156 | customRender={({ x, y, value, datum }, defaultProps) => 157 | datum ? ( 158 | <path 159 | d={`M${x - value} ${y + value} 160 | L${x + value} ${y + value} 161 | L${x} ${y - value} 162 | Z`} 163 | {...defaultProps} 164 | /> 165 | ) : ( 166 | <circle cx={x} cy={y} r={2} fill="#2b3a53" /> 167 | ) 168 | } 169 | /> 170 | ) 171 | } 172 | -------------------------------------------------------------------------------- /packages/datalith-storybook/src/components/hexmap.stories.tsx: -------------------------------------------------------------------------------- 1 | import italyTopology from '@datalith/gridmap/src/json/italy.json' 2 | import { HexMap, HexMapUs, HexMapWorld } from '@datalith/hexmap/src' 3 | import { geoNaturalEarth1, geoOrthographic } from 'd3-geo' 4 | import { scaleLinear } from 'd3-scale' 5 | import * as React from 'react' 6 | import { feature } from 'topojson' 7 | import { genCoordsValue, genCoordsValueIt, genCoordsValueUs } from '../scripts' 8 | 9 | interface ItalyAtlas extends TopoJSON.Topology { 10 | objects: { 11 | sub: TopoJSON.GeometryCollection 12 | } 13 | } 14 | 15 | const y = d => d.value 16 | const defaultData = genCoordsValue(200) 17 | const side = 12 18 | 19 | const defaultDataUs = genCoordsValueUs(1000) 20 | const defaultDataIt = genCoordsValueIt(200) 21 | const italyAtlas = italyTopology as any 22 | const italy = feature(italyAtlas, (italyAtlas as ItalyAtlas).objects.sub) 23 | const projection = geoNaturalEarth1() 24 | 25 | const yScale = scaleLinear() 26 | .domain([Math.min(...defaultData.map(y)), Math.max(...defaultData.map(y))]) 27 | .range([1, side * 0.5]) 28 | 29 | const zScale = scaleLinear() 30 | .domain([0, Math.max(...defaultData.map(y))]) 31 | .range([0.1, 0.9]) 32 | .nice() 33 | 34 | export default { 35 | title: 'DATALITHS/HexMap', 36 | component: HexMap, 37 | } 38 | 39 | export const naturalEarth = () => { 40 | return ( 41 | <HexMapWorld 42 | style={{ backgroundColor: '#171f2c' }} 43 | side={side} 44 | data={defaultData} 45 | coords={d => [d.lng, d.lat]} 46 | value={side * 0.5} 47 | valueInactive={side * 0.5} 48 | fill="#0bbba9" 49 | fillInactive="#2b3a53" 50 | fillOpacity={d => zScale(d.value)} 51 | fillOpacityInactive={0.4} 52 | /> 53 | ) 54 | } 55 | export const orthographic = () => { 56 | return ( 57 | <HexMapWorld 58 | style={{ backgroundColor: '#171f2c' }} 59 | side={side} 60 | data={defaultData} 61 | fill="#0bbba9" 62 | fillInactive="#2b3a53" 63 | coords={d => [d.lng, d.lat]} 64 | value={d => yScale(d.value)} 65 | projection={geoOrthographic()} 66 | /> 67 | ) 68 | } 69 | export const outline = () => { 70 | return ( 71 | <HexMapWorld 72 | style={{ backgroundColor: '#171f2c' }} 73 | side={side} 74 | data={defaultData} 75 | coords={d => [d.lng, d.lat]} 76 | value={d => yScale(d.value)} 77 | stroke="#12c5e5" 78 | strokeInactive="#12c5e5" 79 | fillInactive="transparent" 80 | fill="transparent" 81 | /> 82 | ) 83 | } 84 | export const tooltip = () => { 85 | return ( 86 | <HexMapWorld 87 | style={{ backgroundColor: '#171f2c' }} 88 | side={side} 89 | data={defaultData} 90 | coords={d => [d.lng, d.lat]} 91 | value={side * 0.5} 92 | valueInactive={side * 0.5} 93 | fill="#6f42c1" 94 | fillInactive="#2b3a53" 95 | fillOpacity={d => zScale(d.value)} 96 | fillOpacityInactive={0.4} 97 | tooltip={({ value }) => `<p><b>Value: </b>${value.toFixed(2)}</p>`} 98 | /> 99 | ) 100 | } 101 | export const us = () => { 102 | return ( 103 | <HexMapUs 104 | style={{ backgroundColor: '#171f2c' }} 105 | side={side} 106 | data={defaultDataUs} 107 | coords={d => [d.lng, d.lat]} 108 | value={side * 0.5} 109 | valueInactive={side * 0.5} 110 | fill="#0bbba9" 111 | fillInactive="#2b3a53" 112 | fillOpacity={d => zScale(d.value)} 113 | fillOpacityInactive={0.4} 114 | tooltip={({ value }) => `<p><b>Value: </b>${value.toFixed(2)}</p>`} 115 | /> 116 | ) 117 | } 118 | export const customGeojson = () => { 119 | return ( 120 | <HexMap 121 | style={{ backgroundColor: '#171f2c' }} 122 | side={side} 123 | data={defaultDataIt} 124 | featureCollection={italy} 125 | projection={projection} 126 | coords={d => [d.lng, d.lat]} 127 | value={side * 0.5} 128 | valueInactive={side * 0.5} 129 | fill="#6f42c1" 130 | fillInactive="#2b3a53" 131 | fillOpacity={d => zScale(d.value)} 132 | fillOpacityInactive={0.4} 133 | tooltip={({ value }) => `<p><b>Value: </b>${value.toFixed(2)}</p>`} 134 | /> 135 | ) 136 | } 137 | -------------------------------------------------------------------------------- /packages/datalith-storybook/src/components/intro.stories.jsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import Logo from '../../public/logo.svg' 3 | 4 | export default { 5 | title: 'INTRO/Getting Started', 6 | parameters: { 7 | previewTabs: { 8 | 'storybook/docs/panel': { 9 | hidden: true, 10 | }, 11 | }, 12 | }, 13 | } 14 | 15 | export const readme = () => { 16 | return ( 17 | <div 18 | style={{ 19 | width: '100%', 20 | height: '100%', 21 | fontSize: 20, 22 | lineHeight: 1.5, 23 | }} 24 | > 25 | <div 26 | style={{ 27 | width: '100%', 28 | margin: 'auto', 29 | display: 'flex', 30 | flexDirection: 'column', 31 | justifyContent: 'center', 32 | alignItems: 'center', 33 | }} 34 | > 35 | <img src={Logo} width="180px" style={{ margin: '4rem 0 2rem 0' }} /> 36 | <p style={{ marginTop: 50, width: `100%`, maxWidth: 450 }}> 37 | <b>Datalith</b> is a collection of clean, lightweight and easily customizable{' '} 38 | <b>React components for data visualization.</b> 39 | </p> 40 | <div 41 | style={{ 42 | textAlign: 'left', 43 | width: '100%', 44 | maxWidth: 450, 45 | }} 46 | > 47 | <div style={{ fontSize: 16, marginBottom: 5 }}>Single install:</div> 48 | <code 49 | style={{ 50 | borderRadius: 5, 51 | padding: 10, 52 | display: 'block', 53 | }} 54 | > 55 | $ yarn add datalith 56 | </code> 57 | <br /> 58 | <div style={{ fontSize: 16, marginBottom: 5 }}>Scoped packages install:</div> 59 | <code 60 | style={{ 61 | borderRadius: 5, 62 | padding: 10, 63 | display: 'block', 64 | }} 65 | > 66 | $ yarn add @datalith/flower @datalith/hexmap 67 | </code> 68 | </div> 69 | <br /> 70 | <p style={{ fontSize: 18, width: `100%`, maxWidth: 450 }}> 71 | Select a <b>datalith</b> from the sidebar to see example usage. <br /> 72 | You can read the documentation for each component by clicking on the <b>Docs</b> tab on 73 | the top toolbar. 74 | <br /> 75 | <br /> 76 | <span style={{ color: '#171f2c', fontSize: 16, fontWeight: 700 }}> 77 | View on{' '} 78 | <a 79 | target="_blank" 80 | href="https://github.com/lucafalasco/datalith/tree/master/packages/datalith-storybook/src/components" 81 | style={{ color: '#171f2c' }} 82 | > 83 | <b>Github</b> 84 | </a> 85 | </span> 86 | </p> 87 | </div> 88 | </div> 89 | ) 90 | } 91 | -------------------------------------------------------------------------------- /packages/datalith-storybook/src/components/pack.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Pack, PackComponent } from '@datalith/pack/src' 2 | import { normalize } from '@datalith/util' 3 | import { scaleLinear, scaleQuantize } from 'd3-scale' 4 | import * as React from 'react' 5 | import { Spring } from 'react-spring/renderprops' 6 | import { easeInOutCubic } from '../lib' 7 | import { genDateValue } from '../scripts' 8 | 9 | const defaultData = genDateValue(300) 10 | 11 | const y = d => d.value 12 | 13 | // scales 14 | const yScale = scaleQuantize() 15 | .domain([0, Math.max(...defaultData.map(y))]) 16 | .range([5, 7, 10, 12, 15, 18, 20, 30, 40]) 17 | 18 | const zScale = scaleLinear() 19 | .domain([0, Math.max(...defaultData.map(y))]) 20 | .range([0.1, 0.9]) 21 | .nice() 22 | 23 | export default { 24 | title: 'DATALITHS/Pack', 25 | component: PackComponent, 26 | } 27 | 28 | export const basic = () => { 29 | return ( 30 | <Pack data={defaultData} value={d => yScale(d.value)} fillOpacity={d => zScale(d.value2)} /> 31 | ) 32 | } 33 | export const colors = () => { 34 | return ( 35 | <Pack 36 | style={{ backgroundColor: '#171f2c' }} 37 | data={defaultData} 38 | value={d => yScale(d.value)} 39 | fill="#0bbba9" 40 | fillOpacity={() => Math.random()} 41 | /> 42 | ) 43 | } 44 | export const outline = () => { 45 | const data = defaultData.map(d => yScale(d.value)) 46 | return ( 47 | <Pack style={{ backgroundColor: '#171f2c' }} data={data} stroke="#12c5e5" fill="transparent" /> 48 | ) 49 | } 50 | export const animated = () => { 51 | const sortedData = [...defaultData].sort((a, b) => b.value - a.value) 52 | return ( 53 | <Spring 54 | from={{ index: 0 }} 55 | to={{ index: defaultData.length }} 56 | config={{ duration: 1500, easing: easeInOutCubic }} 57 | > 58 | {props => { 59 | const data = sortedData.slice(0, props.index) 60 | 61 | return ( 62 | <Pack 63 | style={{ backgroundColor: '#171f2c' }} 64 | data={data} 65 | value={d => yScale(d.value)} 66 | fill="#6f42c1" 67 | stroke="#171f2c" 68 | fillOpacity={d => zScale(d.value)} 69 | /> 70 | ) 71 | }} 72 | </Spring> 73 | ) 74 | } 75 | export const tooltip = () => { 76 | return ( 77 | <Pack 78 | style={{ backgroundColor: '#171f2c' }} 79 | data={defaultData} 80 | value={d => yScale(d.value)} 81 | fill="#00d09b" 82 | fillOpacity={d => zScale(d.value2)} 83 | stroke="#171f2c" 84 | strokeOpacity={0.5} 85 | tooltip={({ date, value }) => 86 | `<p><b>Date: </b><u>${date.toLocaleDateString()}</u></p> 87 | <p><b>Value: </b>${Number(value).toFixed(2)}</p>` 88 | } 89 | /> 90 | ) 91 | } 92 | -------------------------------------------------------------------------------- /packages/datalith-storybook/src/components/pixelmap.stories.tsx: -------------------------------------------------------------------------------- 1 | import italyTopology from '@datalith/gridmap/src/json/italy.json' 2 | import { PixelMap, PixelMapUs, PixelMapWorld } from '@datalith/pixelmap/src' 3 | import { geoNaturalEarth1, geoOrthographic } from 'd3-geo' 4 | import { scaleLinear } from 'd3-scale' 5 | import * as React from 'react' 6 | import { feature } from 'topojson' 7 | import { genCoordsValue, genCoordsValueIt, genCoordsValueUs } from '../scripts' 8 | 9 | interface ItalyAtlas extends TopoJSON.Topology { 10 | objects: { 11 | sub: TopoJSON.GeometryCollection 12 | } 13 | } 14 | 15 | const y = d => d.value 16 | const defaultData = genCoordsValue(200) 17 | const side = 10 18 | 19 | const defaultDataUs = genCoordsValueUs(1000) 20 | const defaultDataIt = genCoordsValueIt(200) 21 | const italyAtlas = italyTopology as any 22 | const italy = feature(italyAtlas, (italyAtlas as ItalyAtlas).objects.sub) 23 | const projection = geoNaturalEarth1() 24 | 25 | const yScale = scaleLinear() 26 | .domain([Math.min(...defaultData.map(y)), Math.max(...defaultData.map(y))]) 27 | .range([1, side * 0.9]) 28 | 29 | const zScale = scaleLinear() 30 | .domain([0, Math.max(...defaultData.map(y))]) 31 | .range([0.1, 0.9]) 32 | .nice() 33 | 34 | export default { 35 | title: 'DATALITHS/PixelMap', 36 | component: PixelMap, 37 | } 38 | 39 | export const naturalEarth = () => { 40 | return ( 41 | <PixelMapWorld 42 | style={{ backgroundColor: '#171f2c' }} 43 | side={side} 44 | data={defaultData} 45 | coords={d => [d.lng, d.lat]} 46 | value={side * 0.9} 47 | valueInactive={side * 0.9} 48 | fill="#0bbba9" 49 | fillInactive="#2b3a53" 50 | fillOpacity={d => zScale(d.value)} 51 | fillOpacityInactive={0.4} 52 | /> 53 | ) 54 | } 55 | export const orthographic = () => { 56 | return ( 57 | <PixelMapWorld 58 | style={{ backgroundColor: '#171f2c' }} 59 | side={side} 60 | data={defaultData} 61 | fill="#0bbba9" 62 | fillInactive="#2b3a53" 63 | coords={d => [d.lng, d.lat]} 64 | value={d => yScale(d.value)} 65 | projection={geoOrthographic()} 66 | /> 67 | ) 68 | } 69 | export const outline = () => { 70 | return ( 71 | <PixelMapWorld 72 | style={{ backgroundColor: '#171f2c' }} 73 | side={side} 74 | data={defaultData} 75 | coords={d => [d.lng, d.lat]} 76 | value={d => yScale(d.value)} 77 | stroke="#12c5e5" 78 | strokeInactive="#12c5e5" 79 | fillInactive="transparent" 80 | fill="transparent" 81 | /> 82 | ) 83 | } 84 | export const tooltip = () => { 85 | return ( 86 | <PixelMapWorld 87 | style={{ backgroundColor: '#171f2c' }} 88 | side={side} 89 | data={defaultData} 90 | coords={d => [d.lng, d.lat]} 91 | value={side * 0.9} 92 | valueInactive={side * 0.9} 93 | fill="#6f42c1" 94 | fillInactive="#2b3a53" 95 | fillOpacity={d => zScale(d.value)} 96 | fillOpacityInactive={0.4} 97 | tooltip={({ value }) => `<p><b>Value: </b>${value.toFixed(2)}</p>`} 98 | /> 99 | ) 100 | } 101 | export const us = () => { 102 | return ( 103 | <PixelMapUs 104 | style={{ backgroundColor: '#171f2c' }} 105 | side={side} 106 | data={defaultDataUs} 107 | coords={d => [d.lng, d.lat]} 108 | value={side * 0.9} 109 | valueInactive={side * 0.9} 110 | fill="#0bbba9" 111 | fillInactive="#2b3a53" 112 | fillOpacity={d => zScale(d.value)} 113 | fillOpacityInactive={0.4} 114 | tooltip={({ value }) => `<p><b>Value: </b>${value.toFixed(2)}</p>`} 115 | /> 116 | ) 117 | } 118 | export const customGeojson = () => { 119 | return ( 120 | <PixelMap 121 | style={{ backgroundColor: '#171f2c' }} 122 | side={side} 123 | data={defaultDataIt} 124 | featureCollection={italy} 125 | projection={projection} 126 | coords={d => [d.lng, d.lat]} 127 | value={side * 0.9} 128 | valueInactive={side * 0.9} 129 | fill="#6f42c1" 130 | fillInactive="#2b3a53" 131 | fillOpacity={d => zScale(d.value)} 132 | fillOpacityInactive={0.4} 133 | tooltip={({ value }) => `<p><b>Value: </b>${value.toFixed(2)}</p>`} 134 | /> 135 | ) 136 | } 137 | -------------------------------------------------------------------------------- /packages/datalith-storybook/src/components/ripple.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Ripple, RippleComponent } from '@datalith/ripple/src' 2 | import { scaleLinear } from 'd3-scale' 3 | import * as React from 'react' 4 | import { Spring } from 'react-spring/renderprops' 5 | import { easeInOutCubic } from '../lib' 6 | import { genDateValue } from '../scripts' 7 | 8 | const width = window.innerWidth 9 | const height = window.innerHeight 10 | const defaultData = genDateValue(20) 11 | 12 | const y = d => d.value 13 | 14 | // scales 15 | const yScale = scaleLinear() 16 | .domain([Math.min(...defaultData.map(y)), Math.max(...defaultData.map(y))]) 17 | .range([0, Math.min(width, height) * 0.3]) 18 | .clamp(true) 19 | 20 | const zScale = scaleLinear() 21 | .domain([0, Math.max(...defaultData.map(y))]) 22 | .range([0.9, 0.1]) 23 | .nice() 24 | 25 | export default { 26 | title: 'DATALITHS/Ripple', 27 | component: RippleComponent, 28 | args: { 29 | primary: true, 30 | }, 31 | } 32 | 33 | export const basic = () => { 34 | const data = defaultData.map(d => yScale(d.value)) 35 | return <Ripple data={data} /> 36 | } 37 | export const colors = () => { 38 | return ( 39 | <Ripple 40 | style={{ backgroundColor: '#171f2c' }} 41 | data={defaultData} 42 | value={d => yScale(d.value)} 43 | fill="#12c5e5" 44 | fillOpacity={() => Math.random() / 5} 45 | /> 46 | ) 47 | } 48 | export const outline = () => { 49 | const data = defaultData.map(d => yScale(d.value)) 50 | return ( 51 | <Ripple 52 | style={{ backgroundColor: '#171f2c' }} 53 | data={data} 54 | stroke="#0bbba9" 55 | fill="transparent" 56 | /> 57 | ) 58 | } 59 | export const animated = () => { 60 | const sortedData = [...defaultData].sort((a, b) => b.value - a.value) 61 | 62 | return ( 63 | <Spring 64 | config={{ duration: 1000, easing: easeInOutCubic }} 65 | from={{ value: sortedData.map(d => 0), index: 0 }} 66 | to={{ value: sortedData.map(y), index: sortedData.length }} 67 | > 68 | {props => { 69 | const data = sortedData.slice(0, props.index) 70 | 71 | return ( 72 | <Ripple 73 | style={{ backgroundColor: '#171f2c' }} 74 | data={data} 75 | fill="#6f42c1" 76 | fillOpacity={d => zScale(d.value)} 77 | value={(d, i) => yScale(props.value[i])} 78 | /> 79 | ) 80 | }} 81 | </Spring> 82 | ) 83 | } 84 | export const tooltip = () => { 85 | return ( 86 | <Ripple 87 | style={{ backgroundColor: '#171f2c' }} 88 | data={defaultData} 89 | value={d => yScale(d.value)} 90 | fill="#12c5e5" 91 | fillOpacity={d => zScale(d.value)} 92 | stroke="#171f2c" 93 | strokeOpacity={d => zScale(d.value)} 94 | tooltip={({ date, value }) => 95 | `<p><b>Date: </b><u>${date.toLocaleDateString()}</u></p> 96 | <p><b>Value: </b>${value.toFixed(2)}</p>` 97 | } 98 | /> 99 | ) 100 | } 101 | -------------------------------------------------------------------------------- /packages/datalith-storybook/src/components/shutter.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Shutter, ShutterComponent } from '@datalith/shutter/src' 2 | import { scaleLinear } from 'd3-scale' 3 | import * as React from 'react' 4 | import { Spring } from 'react-spring/renderprops' 5 | import { easeInOutCubic } from '../lib' 6 | import { genDateValue } from '../scripts' 7 | 8 | const width = window.innerWidth 9 | const height = window.innerHeight 10 | const defaultData = genDateValue(20) 11 | 12 | const y = d => d.value 13 | 14 | // scales 15 | const zScale = scaleLinear() 16 | .domain([0, Math.max(...defaultData.map(y))]) 17 | .range([0.1, 1]) 18 | 19 | export default { 20 | title: 'DATALITHS/Shutter', 21 | component: ShutterComponent, 22 | } 23 | 24 | export const basic = () => { 25 | return <Shutter data={defaultData} fillOpacity={d => zScale(d.value)} /> 26 | } 27 | export const sorted = () => { 28 | const data = [...defaultData].sort((a, b) => b.value - a.value) 29 | 30 | return ( 31 | <Shutter 32 | style={{ backgroundColor: '#171f2c' }} 33 | data={data} 34 | fill="#0bbba9" 35 | fillOpacity={d => zScale(d.value)} 36 | /> 37 | ) 38 | } 39 | export const animated = () => { 40 | const radiusTo = (Math.min(width, height) / 2) * 0.4 41 | 42 | return ( 43 | <Spring 44 | from={{ radius: 0 }} 45 | to={{ radius: radiusTo }} 46 | config={{ duration: 1000, easing: easeInOutCubic }} 47 | > 48 | {props => { 49 | return ( 50 | <Shutter 51 | style={{ backgroundColor: '#171f2c' }} 52 | data={defaultData} 53 | fill="#12c5e5" 54 | fillOpacity={d => zScale(d.value)} 55 | radiusInner={props.radius} 56 | radiusOuter={radiusTo + 50} 57 | /> 58 | ) 59 | }} 60 | </Spring> 61 | ) 62 | } 63 | export const tooltip = () => { 64 | return ( 65 | <Shutter 66 | style={{ backgroundColor: '#171f2c' }} 67 | data={defaultData} 68 | fill="#6f42c1" 69 | fillOpacity={d => zScale(d.value)} 70 | tooltip={({ date, value }) => 71 | `<p><b>Date: </b><u>${date.toLocaleDateString()}</u></p> 72 | <p><b>Value: </b>${parseFloat(zScale(value).toFixed(2))}</p> 73 | <p><b>Color: </b> rgba(0, 0, 255, ${zScale(value).toFixed(2)})</p>` 74 | } 75 | /> 76 | ) 77 | } 78 | -------------------------------------------------------------------------------- /packages/datalith-storybook/src/components/spiral.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Spiral, SpiralComponent } from '@datalith/spiral/src' 2 | import { scaleLinear } from 'd3-scale' 3 | import * as React from 'react' 4 | import { Spring } from 'react-spring/renderprops' 5 | import { genDateValue } from '../scripts' 6 | 7 | const defaultData = genDateValue(110) 8 | 9 | const y = d => d.value 10 | 11 | // scales 12 | const yScale = scaleLinear() 13 | .domain([0, Math.max(...defaultData.map(y))]) 14 | .range([1, 20]) 15 | 16 | const opacityScale = scaleLinear() 17 | .domain([Math.min(...defaultData.map(y)), Math.max(...defaultData.map(y))]) 18 | .range([0.3, 0.8]) 19 | 20 | export default { 21 | title: 'DATALITHS/Spiral', 22 | component: SpiralComponent, 23 | } 24 | 25 | export const basic = () => { 26 | const data = defaultData.map(d => yScale(d.value)) 27 | return <Spiral data={data} /> 28 | } 29 | export const archimedean = () => { 30 | return ( 31 | <Spiral 32 | style={{ backgroundColor: '#171f2c' }} 33 | data={defaultData} 34 | value={d => yScale(d.value)} 35 | fill="#0bbba9" 36 | fillOpacity={d => opacityScale(d.value)} 37 | getSpiralCoords={({ width, height }) => { 38 | let angle = 0 39 | const coords: { x: number; y: number }[] = [] 40 | const increment = 0.12 41 | const aperture = Math.min(width, height) / 10 42 | 43 | for (let i = 0; i < defaultData.length; i++) { 44 | const radius = aperture + i * 2 45 | 46 | coords.push({ 47 | x: radius * Math.cos(angle), 48 | y: radius * Math.sin(angle), 49 | }) 50 | angle += increment 51 | } 52 | 53 | return coords 54 | }} 55 | /> 56 | ) 57 | } 58 | export const customSpiral = () => { 59 | return ( 60 | <Spiral 61 | style={{ backgroundColor: '#171f2c' }} 62 | data={defaultData} 63 | fill="#12c5e5" 64 | fillOpacity={d => opacityScale(d.value)} 65 | value={d => yScale(d.value)} 66 | getSpiralCoords={({ width, height }) => { 67 | let angle = 0 68 | const coords: { x: number; y: number }[] = [] 69 | const aperture = Math.min(width, height) / 20 70 | 71 | for (let i = 0; i < defaultData.length; i++) { 72 | const radius = aperture + i * 3 73 | 74 | coords.push({ 75 | x: radius * Math.cos(angle), 76 | y: radius * Math.sin(angle), 77 | }) 78 | angle += 1 / radius - 20 79 | } 80 | 81 | return coords 82 | }} 83 | /> 84 | ) 85 | } 86 | export const outline = () => { 87 | return ( 88 | <Spiral 89 | style={{ backgroundColor: '#171f2c' }} 90 | data={defaultData} 91 | value={d => yScale(d.value)} 92 | fill="transparent" 93 | stroke="#12c5e5" 94 | strokeOpacity={d => opacityScale(d.value)} 95 | /> 96 | ) 97 | } 98 | export const animated = () => { 99 | return ( 100 | <Spring 101 | config={{ duration: 1000, easing: t => t * (2 - t) }} 102 | from={{ index: 0 }} 103 | to={{ index: defaultData.length }} 104 | > 105 | {props => { 106 | const data = defaultData.slice(0, props.index) 107 | 108 | return ( 109 | <Spiral 110 | style={{ backgroundColor: '#171f2c' }} 111 | fill="#12c5e5" 112 | data={data} 113 | value={(d, i) => yScale(d.value)} 114 | /> 115 | ) 116 | }} 117 | </Spring> 118 | ) 119 | } 120 | export const tooltip = () => { 121 | const sortedData = [...defaultData].sort((a, b) => a.date.getTime() - b.date.getTime()) 122 | return ( 123 | <Spiral 124 | data={sortedData} 125 | style={{ backgroundColor: '#171f2c' }} 126 | value={d => yScale(d.value)} 127 | fill="#6f42c1" 128 | fillOpacity={d => opacityScale(d.value)} 129 | tooltip={({ date, value }) => 130 | `<p><b>Date: </b><u>${date.toLocaleDateString()}</u></p> 131 | <p><b>Value: </b>${yScale.invert(Number(value)).toFixed(2)}</p>` 132 | } 133 | /> 134 | ) 135 | } 136 | -------------------------------------------------------------------------------- /packages/datalith-storybook/src/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.md' { 2 | const content: string 3 | export default content 4 | } 5 | -------------------------------------------------------------------------------- /packages/datalith-storybook/src/lib.ts: -------------------------------------------------------------------------------- 1 | export const easeInOutCubic = (t: number) => 2 | t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1 3 | -------------------------------------------------------------------------------- /packages/datalith-storybook/src/scripts/index.ts: -------------------------------------------------------------------------------- 1 | function getRandomInt(min: number, max: number) { 2 | min = Math.ceil(min) 3 | max = Math.floor(max) 4 | return Math.floor(Math.random() * (max - min + 1)) + min 5 | } 6 | 7 | export function genDateValue(n: number) { 8 | return Array(n) 9 | .fill(1) 10 | .map((d, i) => { 11 | return { 12 | date: new Date(Date.now() - i * 3600000), 13 | value: Math.max(250, Math.random() * 3000), 14 | value2: Math.max(250, Math.random() * 3000), 15 | } 16 | }) 17 | } 18 | 19 | export function genCoordsValue(n: number) { 20 | return Array(n) 21 | .fill(1) 22 | .map((d, i) => { 23 | return { 24 | lat: getRandomInt(-90, 90), 25 | lng: getRandomInt(-180, 180), 26 | value: Math.max(250, Math.random() * 3000), 27 | } 28 | }) 29 | } 30 | 31 | export function genCoordsValueUs(n: number) { 32 | return Array(n) 33 | .fill(1) 34 | .map((d, i) => { 35 | return { 36 | lat: getRandomInt(20, 50), 37 | lng: getRandomInt(-70, -125), 38 | value: Math.max(250, Math.random() * 3000), 39 | } 40 | }) 41 | } 42 | 43 | export function genCoordsValueIt(n: number) { 44 | return Array(n) 45 | .fill(1) 46 | .map((d, i) => { 47 | return { 48 | lat: getRandomInt(35, 47), 49 | lng: getRandomInt(8, 17), 50 | value: Math.max(250, Math.random() * 3000), 51 | } 52 | }) 53 | } 54 | -------------------------------------------------------------------------------- /packages/datalith-storybook/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "allowJs": false, 6 | "jsx": "react", 7 | "declaration": true, 8 | "declarationDir": "dist/types" 9 | }, 10 | "include": ["src"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/datalith-util/README.md: -------------------------------------------------------------------------------- 1 | # @datalith/util 2 | 3 | #### Collection of React components to build cool data visualizations 4 | 5 | ```sh 6 | yarn add @datalith/util 7 | ``` 8 | -------------------------------------------------------------------------------- /packages/datalith-util/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@datalith/util", 3 | "version": "0.12.1", 4 | "description": "datalith util", 5 | "main": "dist/index.js", 6 | "module": "dist/index.js", 7 | "types": "dist/types/index.d.ts", 8 | "scripts": { 9 | "prebuild": "rm -rf dist", 10 | "build": "tsc", 11 | "prepublish": "tsc" 12 | }, 13 | "files": [ 14 | "dist" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/lucafalasco/datalith.git" 19 | }, 20 | "keywords": [ 21 | "datalith", 22 | "visualizations", 23 | "charts" 24 | ], 25 | "author": "@lucafalasco", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/lucafalasco/datalith/issues" 29 | }, 30 | "homepage": "https://github.com/lucafalasco/datalith#readme", 31 | "dependencies": { 32 | "lodash": "^4.17.11", 33 | "react-sizeme": "^2.6.7" 34 | }, 35 | "devDependencies": { 36 | "@types/lodash": "^4.14.135", 37 | "@types/react": "^16.8.5", 38 | "react": "^16.8.5", 39 | "react-dom": "^16.8.5", 40 | "react-test-renderer": "^16.8.5", 41 | "typescript": "^4.2.4" 42 | }, 43 | "peerDependencies": { 44 | "react": "^15.0.0-0 || ^16.0.0-0" 45 | }, 46 | "publishConfig": { 47 | "access": "public" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/datalith-util/src/ResponsiveWrapper.tsx: -------------------------------------------------------------------------------- 1 | import React, { ComponentType } from 'react' 2 | import { SizeMe } from 'react-sizeme' 3 | import { CommonProps } from '.' 4 | 5 | export default function ResponsiveWrapper<P extends CommonProps>(Component: ComponentType<P>) { 6 | return class Wrapper extends React.Component<P> { 7 | static defaultProps = Component.defaultProps as Partial<P> 8 | 9 | render() { 10 | return this.props.size ? ( 11 | <Component {...this.props} style={{ ...this.props.style, ...this.props.size }} /> 12 | ) : ( 13 | <SizeMe monitorWidth monitorHeight> 14 | {({ size }) => ( 15 | <div style={{ position: 'relative', height: '100%' }}> 16 | <div style={{ position: 'absolute', width: '100%', height: '100%' }}> 17 | <Component 18 | {...this.props} 19 | style={{ ...size, ...this.props.style }} 20 | size={{ 21 | width: (this.props.style && this.props.style.width) || size.width, 22 | height: (this.props.style && this.props.style.height) || size.height, 23 | }} 24 | /> 25 | </div> 26 | </div> 27 | )} 28 | </SizeMe> 29 | ) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/datalith-util/src/index.ts: -------------------------------------------------------------------------------- 1 | import { isFunction } from 'lodash' 2 | import ResponsiveWrapper from './ResponsiveWrapper' 3 | 4 | export type Datum = any 5 | 6 | type AccessorFunction<T> = (d: Datum, i: number) => T 7 | export type Accessor<T> = AccessorFunction<T> | T 8 | 9 | export type CoordsAccessor = Accessor<[number, number]> 10 | export type StringAccessor = Accessor<string> 11 | export type NumberAccessor = Accessor<number> 12 | 13 | export interface CommonAccessors { 14 | /** Fill color accessor */ 15 | fill?: StringAccessor 16 | /** Fill opacity accessor */ 17 | fillOpacity?: NumberAccessor 18 | /** Stroke color accessor */ 19 | stroke?: StringAccessor 20 | /** Stroke opacity accessor */ 21 | strokeOpacity?: NumberAccessor 22 | } 23 | 24 | export interface CommonProps extends CommonAccessors { 25 | /** Custom css classes to apply to the SVG */ 26 | className?: string 27 | /** Custom style object to apply to the SVG */ 28 | style?: React.CSSProperties 29 | /** Optional elements to add to the SVG */ 30 | additionalElements?: JSX.Element 31 | /** Data array */ 32 | data: Datum[] 33 | /** Width and Height of the SVG */ 34 | size: { width: number; height: number } 35 | /** Return HTML or text as a string to show on element mouseover */ 36 | tooltip?: (d: Datum) => string 37 | } 38 | 39 | export { ResponsiveWrapper } 40 | 41 | export function callOrGetValue<T>(funcOrValue: ((...args: any) => T) | T, ...args: any) { 42 | return isFunction(funcOrValue) ? funcOrValue(...args) : funcOrValue 43 | } 44 | 45 | export function normalize(n: number, min: number, max: number) { 46 | return (n - min) / (max - min) 47 | } 48 | -------------------------------------------------------------------------------- /packages/datalith-util/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "allowJs": false, 6 | "declaration": true, 7 | "declarationDir": "dist/types" 8 | }, 9 | "include": ["src"], 10 | "exclude": ["src/**/*.test.ts*"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/datalith-util/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/lodash@^4.14.135": 6 | version "4.14.135" 7 | resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.135.tgz#d2607c35dd68f70c2b35ba020c667493dedd8447" 8 | 9 | "@types/prop-types@*": 10 | version "15.7.1" 11 | resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.1.tgz#f1a11e7babb0c3cad68100be381d1e064c68f1f6" 12 | 13 | "@types/react@^16.8.5": 14 | version "16.8.23" 15 | resolved "https://registry.yarnpkg.com/@types/react/-/react-16.8.23.tgz#ec6be3ceed6353a20948169b6cb4c97b65b97ad2" 16 | integrity sha512-abkEOIeljniUN9qB5onp++g0EY38h7atnDHxwKUFz1r3VH1+yG1OKi2sNPTyObL40goBmfKFpdii2lEzwLX1cA== 17 | dependencies: 18 | "@types/prop-types" "*" 19 | csstype "^2.2.0" 20 | 21 | batch-processor@^1.0.0: 22 | version "1.0.0" 23 | resolved "https://registry.yarnpkg.com/batch-processor/-/batch-processor-1.0.0.tgz#75c95c32b748e0850d10c2b168f6bdbe9891ace8" 24 | 25 | csstype@^2.2.0: 26 | version "2.6.5" 27 | resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.5.tgz#1cd1dff742ebf4d7c991470ae71e12bb6751e034" 28 | 29 | element-resize-detector@^1.1.15: 30 | version "1.1.15" 31 | resolved "https://registry.yarnpkg.com/element-resize-detector/-/element-resize-detector-1.1.15.tgz#48eba1a2eaa26969a4c998d972171128c971d8d2" 32 | dependencies: 33 | batch-processor "^1.0.0" 34 | 35 | invariant@^2.2.4: 36 | version "2.2.4" 37 | resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" 38 | dependencies: 39 | loose-envify "^1.0.0" 40 | 41 | "js-tokens@^3.0.0 || ^4.0.0": 42 | version "4.0.0" 43 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 44 | 45 | lodash@^4.17.11: 46 | version "4.17.21" 47 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 48 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 49 | 50 | loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: 51 | version "1.4.0" 52 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" 53 | dependencies: 54 | js-tokens "^3.0.0 || ^4.0.0" 55 | 56 | object-assign@^4.1.1: 57 | version "4.1.1" 58 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 59 | 60 | prop-types@^15.6.2: 61 | version "15.7.2" 62 | resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" 63 | dependencies: 64 | loose-envify "^1.4.0" 65 | object-assign "^4.1.1" 66 | react-is "^16.8.1" 67 | 68 | react-dom@^16.8.5: 69 | version "16.8.6" 70 | resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.6.tgz#71d6303f631e8b0097f56165ef608f051ff6e10f" 71 | dependencies: 72 | loose-envify "^1.1.0" 73 | object-assign "^4.1.1" 74 | prop-types "^15.6.2" 75 | scheduler "^0.13.6" 76 | 77 | react-is@^16.8.1, react-is@^16.8.6: 78 | version "16.8.6" 79 | resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" 80 | 81 | react-sizeme@^2.6.7: 82 | version "2.6.7" 83 | resolved "https://registry.yarnpkg.com/react-sizeme/-/react-sizeme-2.6.7.tgz#231339ce8821ac2c26424c791e0027f89dae3e90" 84 | dependencies: 85 | element-resize-detector "^1.1.15" 86 | invariant "^2.2.4" 87 | shallowequal "^1.1.0" 88 | throttle-debounce "^2.1.0" 89 | 90 | react-test-renderer@^16.8.5: 91 | version "16.8.6" 92 | resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.8.6.tgz#188d8029b8c39c786f998aa3efd3ffe7642d5ba1" 93 | dependencies: 94 | object-assign "^4.1.1" 95 | prop-types "^15.6.2" 96 | react-is "^16.8.6" 97 | scheduler "^0.13.6" 98 | 99 | react@^16.8.5: 100 | version "16.8.6" 101 | resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe" 102 | dependencies: 103 | loose-envify "^1.1.0" 104 | object-assign "^4.1.1" 105 | prop-types "^15.6.2" 106 | scheduler "^0.13.6" 107 | 108 | scheduler@^0.13.6: 109 | version "0.13.6" 110 | resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.6.tgz#466a4ec332467b31a91b9bf74e5347072e4cd889" 111 | dependencies: 112 | loose-envify "^1.1.0" 113 | object-assign "^4.1.1" 114 | 115 | shallowequal@^1.1.0: 116 | version "1.1.0" 117 | resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" 118 | 119 | throttle-debounce@^2.1.0: 120 | version "2.1.0" 121 | resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.1.0.tgz#257e648f0a56bd9e54fe0f132c4ab8611df4e1d5" 122 | 123 | typescript@^4.2.4: 124 | version "4.2.4" 125 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" 126 | integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== 127 | -------------------------------------------------------------------------------- /packages/datalith/README.md: -------------------------------------------------------------------------------- 1 | # datalith 2 | 3 | #### Collection of React components to build cool data visualizations 4 | 5 | ```sh 6 | yarn add datalith 7 | ``` 8 | -------------------------------------------------------------------------------- /packages/datalith/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "datalith", 3 | "version": "0.12.1", 4 | "description": "Collection of React components to build cool data visualizations", 5 | "main": "dist/index.js", 6 | "module": "dist/index.js", 7 | "types": "dist/types/index.d.ts", 8 | "scripts": { 9 | "prebuild": "rm -rf dist", 10 | "build": "tsc", 11 | "prepublish": "tsc" 12 | }, 13 | "files": [ 14 | "dist" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/lucafalasco/datalith.git" 19 | }, 20 | "keywords": [ 21 | "datalith", 22 | "react", 23 | "d3", 24 | "visualizations", 25 | "charts" 26 | ], 27 | "author": "@lucafalasco", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/lucafalasco/datalith/issues" 31 | }, 32 | "homepage": "https://github.com/lucafalasco/datalith#readme", 33 | "dependencies": { 34 | "@datalith/barcode": "^0.12.1", 35 | "@datalith/dotmap": "^0.12.1", 36 | "@datalith/flower": "^0.12.1", 37 | "@datalith/gridmap": "^0.12.1", 38 | "@datalith/hexmap": "^0.12.1", 39 | "@datalith/pack": "^0.12.1", 40 | "@datalith/pixelmap": "^0.12.1", 41 | "@datalith/ripple": "^0.12.1", 42 | "@datalith/shutter": "^0.12.1", 43 | "@datalith/spiral": "^0.12.1", 44 | "@datalith/util": "^0.12.1" 45 | }, 46 | "devDependencies": { 47 | "@types/react": "^16.8.5", 48 | "react": "^16.8.5", 49 | "react-dom": "^16.8.5", 50 | "typescript": "^4.2.4" 51 | }, 52 | "peerDependencies": { 53 | "react": "^15.0.0-0 || ^16.0.0-0" 54 | }, 55 | "publishConfig": { 56 | "access": "public" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /packages/datalith/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from '@datalith/barcode' 2 | export * from '@datalith/dotmap' 3 | export * from '@datalith/flower' 4 | export * from '@datalith/gridmap' 5 | export * from '@datalith/hexmap' 6 | export * from '@datalith/pack' 7 | export * from '@datalith/pixelmap' 8 | export * from '@datalith/ripple' 9 | export * from '@datalith/shutter' 10 | export * from '@datalith/spiral' 11 | export * from '@datalith/util' 12 | -------------------------------------------------------------------------------- /packages/datalith/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "allowJs": false, 6 | "declaration": true, 7 | "declarationDir": "dist/types" 8 | }, 9 | "include": ["src"], 10 | "exclude": ["src/**/*.test.ts*"] 11 | } 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "dist", 4 | "module": "esnext", 5 | "target": "es5", 6 | "lib": ["es6", "dom"], 7 | "sourceMap": true, 8 | "allowJs": true, 9 | "jsx": "react", 10 | "moduleResolution": "node", 11 | "forceConsistentCasingInFileNames": true, 12 | "noImplicitReturns": true, 13 | "noImplicitThis": true, 14 | "noImplicitAny": false, 15 | "strictNullChecks": true, 16 | "suppressImplicitAnyIndexErrors": true, 17 | "noUnusedLocals": false, 18 | "experimentalDecorators": true, 19 | "skipLibCheck": true, 20 | "resolveJsonModule": true, 21 | "esModuleInterop": true 22 | }, 23 | "exclude": ["node_modules", "build", "scripts", "webpack", "jest"] 24 | } 25 | -------------------------------------------------------------------------------- /tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs" 5 | } 6 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], 3 | "rules": { 4 | "arrow-parens": false, 5 | "interface-name": [true, "never-prefix"], 6 | "jsx-no-multiline-js": false, 7 | "jsx-boolean-value": false, 8 | "jsx-no-lambda": false, 9 | "member-access": false, 10 | "no-empty": false, 11 | "no-shadowed-variable": false, 12 | "object-literal-key-quotes": [true, "as-needed"], 13 | "object-literal-sort-keys": false, 14 | "quotemark": false, 15 | "semicolon": false, 16 | "trailing-comma": true, 17 | "no-console": false, 18 | "no-bitwise": false 19 | }, 20 | "linterOptions": { 21 | "exclude": ["config/**/*.js", "node_modules/**/*.ts"] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /website/assets/images/dotpattern.svg: -------------------------------------------------------------------------------- 1 | <svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <rect opacity="0.2" width="2" height="2" rx="1" fill="#161617"/> 3 | </svg> 4 | -------------------------------------------------------------------------------- /website/assets/images/logo.svg: -------------------------------------------------------------------------------- 1 | <svg width="228" height="56" viewBox="0 0 228 56" fill="none" xmlns="http://www.w3.org/2000/svg"> 2 | <path d="M10.0938 1.5H46.9062C51.6591 1.5 55.5 5.34093 55.5 10.0938V45.4813C55.5 50.2341 51.6591 54.075 46.9062 54.075H10.0938C5.34093 54.075 1.5 50.2341 1.5 45.4813V10.0938C1.5 5.34093 5.34093 1.5 10.0938 1.5Z" fill="#212121" stroke="#E5E5E5" stroke-width="3"/> 3 | <path d="M27.5149 16.3875C36.096 16.3875 39.1839 20.7432 39.1839 28.1592C39.3301 34.1666 35.0559 39.2833 28.3275 39.1861H17.8125V16.3875H27.5149Z" fill="white" stroke="white" stroke-width="3" stroke-linejoin="round"/> 4 | <path d="M78.79 38.1H70V18H78.49C81.95 18 84.44 18.78 85.96 20.34C87.48 21.9 88.24 24.4 88.24 27.84C88.24 31.26 87.51 33.83 86.05 35.55C84.59 37.25 82.17 38.1 78.79 38.1ZM81.22 28.17C81.22 26.37 81.03 25.17 80.65 24.57C80.29 23.97 79.47 23.67 78.19 23.67H76.96V32.43H78.19C79.23 32.43 80 32.17 80.5 31.65C80.98 31.13 81.22 29.97 81.22 28.17Z" fill="#212121"/> 5 | <path d="M92.493 38.1L96.933 18H107.463L111.993 38.1H104.973L104.403 35.79H99.813L99.333 38.1H92.493ZM101.853 23.46L100.713 30.48H103.683L102.603 23.46H101.853Z" fill="#212121"/> 6 | <path d="M114.874 23.67V18H129.874V23.67H125.974V38.1H119.014V23.67H114.874Z" fill="#212121"/> 7 | <path d="M132.841 38.1L137.281 18H147.811L152.341 38.1H145.321L144.751 35.79H140.161L139.681 38.1H132.841ZM142.201 23.46L141.061 30.48H144.031L142.951 23.46H142.201Z" fill="#212121"/> 8 | <path d="M171.051 38.1H157.551V18H164.511V32.43H171.051V38.1Z" fill="#212121"/> 9 | <path d="M176.729 38.1V18H183.689V38.1H176.729Z" fill="#212121"/> 10 | <path d="M189.358 23.67V18H204.358V23.67H200.458V38.1H193.498V23.67H189.358Z" fill="#212121"/> 11 | <path d="M220.935 38.1V31.08H217.005V38.1H210.045V18H217.005V25.41H220.935V18H227.895V38.1H220.935Z" fill="#212121"/> 12 | </svg> 13 | -------------------------------------------------------------------------------- /website/assets/images/share.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucafalasco/datalith/f3a304eadb1d2ff7220c93bcf48295e8c81f3a60/website/assets/images/share.jpg -------------------------------------------------------------------------------- /website/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucafalasco/datalith/f3a304eadb1d2ff7220c93bcf48295e8c81f3a60/website/favicon.ico -------------------------------------------------------------------------------- /website/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Titillium+Web:ital,wght@0,400;0,700;1,700&display=swap'); 2 | 3 | html, 4 | body { 5 | font-family: 'Titillium Web', sans-serif; 6 | text-rendering: optimizeLegibility; 7 | font-size: 14px; 8 | width: 100%; 9 | background: #efefef; 10 | color: #171f2c; 11 | margin: 0; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | code { 17 | font-family: 'Roboto Mono', monospace; 18 | font-size: 1.1rem; 19 | } 20 | 21 | pre code { 22 | font-size: 0.85rem !important; 23 | } 24 | 25 | h1 { 26 | font-size: 5rem !important; 27 | line-height: 1 !important; 28 | } 29 | 30 | h2 { 31 | font-size: 3rem; 32 | } 33 | 34 | .w6 { 35 | width: 32rem; 36 | } 37 | 38 | .h6 { 39 | height: 32rem; 40 | } 41 | 42 | .min-w5 { 43 | min-width: 16rem; 44 | } 45 | 46 | .pointer-events-none { 47 | pointer-events: none; 48 | } 49 | 50 | .bg-dark { 51 | background-color: #171f2c; 52 | } 53 | 54 | .bg-darker { 55 | background-color: #101720; 56 | } 57 | 58 | .bg-darkest { 59 | background-color: #0b1016; 60 | } 61 | 62 | .blue { 63 | color: #12c5e5; 64 | } 65 | 66 | .blue-light { 67 | color: #9ff0ff; 68 | } 69 | 70 | .purple { 71 | color: #6f42c1; 72 | } 73 | 74 | .purple-light { 75 | color: #a08cfc; 76 | } 77 | 78 | .teal { 79 | color: #0bbba9; 80 | } 81 | 82 | .teal-light { 83 | color: #a7e8e0; 84 | } 85 | 86 | ::selection { 87 | background: #000; 88 | color: #fff; 89 | } 90 | 91 | @media only screen and (max-width: 480px) { 92 | html, 93 | body { 94 | font-size: 13px; 95 | } 96 | 97 | code { 98 | font-size: 1.3rem; 99 | } 100 | 101 | .card { 102 | max-width: 100%; 103 | max-height: 300px; 104 | overflow: hidden; 105 | } 106 | 107 | h1 { 108 | font-size: 3.2rem !important; 109 | } 110 | } 111 | --------------------------------------------------------------------------------