Giter Site home page Giter Site logo

spotify / reactochart Goto Github PK

View Code? Open in Web Editor NEW
549.0 20.0 54.0 105.16 MB

:chart_with_upwards_trend: React chart component library :chart_with_downwards_trend:

Home Page: https://spotify.github.io/reactochart/docs/

License: Other

HTML 0.03% JavaScript 99.48% Less 0.39% EJS 0.10%
spotify charting-library react-components react data-visualization charts

reactochart's Issues

Deprecate numeral.js

Numeral.js is no longer maintained. Would recommend switching to d3 format. This would be a breaking change as we allow users to send a format array, where each string in the format array maps to numeral's way of formatting.

This would also reduce our bundle size and allow us to leverage more packages already imported by our use of d3.

cannot set CSS classes for labels, titles

Label and title styles must be set through the labelStyle and titleStyle props respectively.

Labels have inline styles by default, that must be overridden by a labelStyle prop to be changed (because inline styles override CSS stylesheet styles, a stylesheet selector cannot be used without the !important flag, which is hacky),
Titles have this issue as well, as well as having no class associated with them, so it isn't possible to select them with a CSS child selector.

This makes it very difficult to have a centralized style sheet that manages styles for all charts.

I'm adding this issue so it can be addressed in the refactor.

An in-range update of enzyme is breaking the build 🚨

There have been updates to the enzyme monorepo:

    • The devDependency enzyme was updated from 3.10.0 to 3.11.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

This monorepo update includes releases of one or more dependencies which all belong to the enzyme group definition.

enzyme is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push: The Travis CI build could not complete due to an error (Details).

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

An in-range update of css-loader is breaking the build 🚨

The devDependency css-loader was updated from 3.2.1 to 3.3.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

css-loader is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push: The Travis CI build could not complete due to an error (Details).

Release Notes for v3.3.0

3.3.0 (2019-12-09)

Features

Bug Fixes

Commits

The new version differs by 5 commits.

  • 889807a chore(release): 3.3.0
  • 6177af5 feat: support pure css modules (#1008)
  • 6769783 fix: do not crash when an assert return null or undefined (#1006)
  • 80e9662 fix: reduce count of require (#1004)
  • e662b61 refactor: code (#1003)

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

measure-text's dependencies are declared as dev-dependencies

Right now if there is a conflict of Reactochart's dependency measure-text's dependencies. measure-text's dev-dependencies are declared as regular dependencies. This can cause an error of Cannot read property 'context' of undefined if there are conflicts of version.

Deprecate Moment.js

Moment is big and bloats bundles, would be nice to deprecate that use in favor of d3-time-format or d3-time

Some of this functionality might be bundled into the standard d3 import by default.

Proposed API changes for v0.4.x

I've picked up work on Reactochart again and am working towards a new release with more features & improved docs & tests. As a part of this release, there are some rough parts of the API that I'd like to propose changing. Please comment here if you have any thoughts or objections.

1. Rename all getThing ("getter") props to just thing; update them to accept either a constant value or accessor function (when possible).

Currently there are a number of special "getter" props which start with get (eg. getX/getY, getClassName) which tell the chart how to access a data value & determine a prop for each thing in a series (eg. a bunch of bars in a bar chart). However, many of these currently need two separate props - a "getter" prop for when the user wants it to be dynamic, and a regular prop if the user wants just a single static value. For example, BarChart has a getClass prop (a function which dynamically assigns a class to each bar), and a barClassName prop (a string className, which would be applied to all bars).

Instead, I propose that we combine them into a single prop, without get in the prop name. Such props would allow either a simple individual value to be passed, or (whenever possible) a function which would be called with each datum. Examples:

OLD: <BarChart getClass={(d) => d.name} /> OR <BarChart barClassName="my-bar" />
NEW: <BarChart barClassName={(d) => d.name} /> OR <BarChart barClassName="my-bar" />

The main advantages here are consistency, reducing the number of props, and allowing as many props as possible to take either static or dynamic (function) values.

Affected props: getX --> x, getY --> y, getClass --> className (or barClassName, etc.), getArea --> area, getValue --> value, etc.

2. Deprecate string/number/null shorthand for "getter" props.

Closely related to #1 above. Currently "getter" props like getX/getY accept functions, but they also accept a "shorthand" string/number which is transformed into a key/index accessor function. For example, if you render <BarChart getX={'foo'} />, this is internally turned into the function (d) => d.foo which is called on each datum to get the bar's X value. See the docs for more info on this behavior.

This can be convenient sometimes, but adds complexity to Reactochart code and requires a lot of explanation in the docs. More importantly, it conflicts with #1 above: If we deprecated getClass in favor of className but did not deprecate these shorthand accessors, something like <... className="foo" /> would become ambiguous - does it mean "use the string 'foo' for my className" or "use the function d => d.foo to determine className"? For this reason, we must do BOTH #1 and #2, or neither.

The only downside I see here is that users will probably replace a lot of their shorthand getX and getYs with arrow functions, eg.:

OLD: <BarChart getX={0} ... />
NEW: <BarChart x={(d) => x[0]} ... />
OLD: <BarChart getX="x" ... />
NEW: <BarChart x={(d) => d.x} ... />

This is fine for charts which aren't re-rendered, but can cause performance issues for those which are interactive or need to be re-rendered often - because by creating a new arrow function on each render, the user would cause oldProps.x !== newProps.x, causing the entire chart to re-render every time. The performant solution is for the user to create the accessor function once, outside of their render function, so that it ===s itself on every new render. This is definitely a bit less convenient, but is already an issue with any props which pass an arrow function, so React developers should already be familiar with it.

Affected props: x (getX), y (getY), and any other props which use shorthand string/number getters.

3. Deprecate combined thing={{x:..., y:...}} props in favor of separate xThing and yThing props

Currently there are several combined "X/Y" axis-related props that accept either an {x, y}-shaped object, or a single value to be applied to both X and Y axes. I want to replace these with separate xThing and yThing props, for example:

OLD: <BarChart domain={{x: xDomain, y: yDomain}} /> or <... domain={commonDomain} />
NEW: <BarChart xDomain={xDomain} yDomain={yDomain} />

The old way is potentially confusing (since there are two different behaviors) and it adds some unnecessary complexity in our components. Furthermore, it's problematic for PureComponent performance optimization: we expect that when a user re-renders a chart, any props which have not changed since the last render will === their old values. However, when users render charts using object literals, a new object literal is created on every render, so old props !== the new ones, making it harder to avoid unnecessary re-renders.

Affected props: domain --> xDomain/yDomain, scaleType --> xScaleType/yScaleType, nice --> xNice/yNice, invertScale --> invertXScale/invertYScale.

4. Deprecate combined thing={{top:..., bottom:..., left:..., right:...}} props in favor of separate thingTop, thingBottom, thingLeft, thingRight props.

Essentially the same thing as #3 except with top/bottom/left/right instead of x/y, & same rationale.

OLD: <XYPlot margin={{top: 12, right: 50}} ... />
NEW: <XYPlot marginTop={12} marginRight={50} ... />

If we wanted, we could still have a general margin prop that accepts a number that would be applied to all top/bottom/left/right, for more convenience when you want to pass the same number for all 4 values, but I'm not sure how common a use case that is.

Affected props: padding --> paddingTop/paddingBottom/paddingLeft/paddingRight, margin --> marginTop/marginBottom/marginLeft/marginRight, spacing --> spacingTop/spacingBottom/spacingLeft/spacingRight

An in-range update of webpack is breaking the build 🚨

The devDependency webpack was updated from 4.41.2 to 4.41.3.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

webpack is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push: The Travis CI build could not complete due to an error (Details).

Release Notes for v4.41.3

Security

  • force upgrade terser-webpack-plugin dependency for security fix (not affecting webpack)

Funding

  • add npm funding field to package.json
Commits

The new version differs by 5 commits.

  • df9f3eb 4.41.3
  • fe71d68 Merge pull request #10010 from webpack/funding
  • b396d96 Merge pull request #10123 from pustovalov/webpack-4-serialize
  • 29b2bdd Update terser-webpack-plugin to ^1.4.3
  • bedb566 chore: funding field

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Add Style prop to XYPlot component

  • Adding a style or plotStyle prop would allow a user to pass in styles to the XYPlot (a component used by most almost users).
  • For reference, SankeyDiagram has a style prop, so this would provide similar parity.
  • A benefit would be that a user wouldn't have to use classname-based styling in their entire implementation and stick to one methodology.

Specifying ticks prop on XAxis or YAxis throws error

the error is in /src/utils/Scale.js

Scale.js:104 Uncaught ReferenceError: combineDomains is not defined

It seems that that function should be imported from lib/utils/Data.js but it isn't included in the Scale module.

An in-range update of d3 is breaking the build 🚨

The dependency d3 was updated from 5.14.2 to 5.15.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

d3 is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • continuous-integration/travis-ci/push: The Travis CI build failed (Details).

Commits

The new version differs by 3 commits.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

resolvers in `resolveXYScale` should recursively traverse `children` tree

The new code in 0.2.1 is improving but has a significant regression - All of the resolvers in resolveXYScales used to recursively check the component's children to find the necessary props. However @thehindenburg 's new mapOverChildren, while being a nicer abstraction, does not do recursion - it only maps over an element's direct children.

Recursion is necessary IMHO because we want to support the use case of the user having intermediate layer components between XYPlot and their charts, eg.:

<XYPlot>
  <CustomChartWrapper>
    <LineChart />
    <AreaChart />
    <BarChart />
  </CustomChartWrapper>
</XYPlot>

Without recursion, this would never try to resolve anything on the actual chart components, it would stop at CustomChartWrapper. We should improve the general resolution functions in resolveXYScales to handle this case

Reactochart Breaks with Fragments as Children

It'd be amazing if Reactochart could handle Fragments in some way. Currently if you pass in a component with Fragments, it doesn't render properly and the entire visualization breaks.

0.2.x roadmap

Work has begun on v0.2.0 and will be tracked in the 0.2.x branch. Main objectives are:

  • Improved label layout features and speed due to better pre-emptive label measuring.
  • More modularization of component structure - export parts of charts, not just entire charts, so the parts can be composed individually.
  • Encapsulation of reusable and extractable Component features using higher-order components. Not just for DRY-ness, but to make the Components themselves as simple as possible.

The feature roadmap will be tracked in this checklist, which we'll add to and edit as we go along:

  • Refactor mouse events on new XYPlot component
  • Production build of examples sandbox, for performance testing
  • Port existing charts to new XYPlot format (see below)
  • Bar component
  • RangeRect component
  • Use class-type components instead of createClass
  • resolveXYScales HOC to resolve scale prop from domain/range/data/size/etc.
  • resolveObjectProps HOC to handle setting default props for {x,y} and {top, bottom, left, right} shaped props
  • Use measure-text to pre-measure labels
  • XAxis and YAxis components
  • Unit test which renders the examples
  • Update lodash to 4.5.x
  • Add babel plugin for ESNext class properties
  • Axis label placement - see AUDINP-232

An in-range update of eslint-plugin-react is breaking the build 🚨

The devDependency eslint-plugin-react was updated from 7.16.0 to 7.17.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

eslint-plugin-react is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push: The Travis CI build failed (Details).

Release Notes for v7.17.0

Added

Fixed

Changed

Commits

The new version differs by 26 commits.

  • 027ebd9 Update CHANGELOG and bump version
  • 89911de [Deps] update jsx-ast-utils, object.fromentries, resolve
  • cfef664 [Dev Deps] update @types/eslint, @types/estree, @types/node, coveralls, typescript
  • d3b5d71 [New] jsx-no-target-blank: add allowReferrer option
  • 83ac4c0 [eslint] fix func-names and change object-shorthand to 'always'
  • 225b433 [Docs] jsx-first-prop-new-line: Fix documentation formatting
  • 62df1dd [Docs] prop-types: Update 'skipUndeclared' in rule options
  • 87d4cab [Docs] jsx-first-prop-new-line: fix wrong rule name
  • 55b605f [Fix] sort-prop-types, jsx-sort-default-props: disable broken autofix
  • 71c7d01 [Tests] temporarily pin eslint 6 tests to v6.6
  • 8093565 [New] jsx-handler-names: add checkLocalVariables option
  • 5be539b [Fix] no-typos: improve report location
  • d9d2193 [eslint] enable eslint-plugin-eslint-plugin
  • 39e4396 [Docs] jsx-props-no-multi-spaces: suggest using core rule instead
  • 9e4ad21 [Docs] jsx-first-prop-new-line: add rule options

There are 26 commits in total.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Changelog

Reactochart should have a Changelog file. Should retroactively include API changes for 0.4.x (see #47 )

Upgrade to d3 5.x

To enable resolving multiple d3 imports in my project, reactochart should be upgraded to the latest d3 version.

Closing #140 as this makes it harder to prevent multiple imports of d3 in a project.

An in-range update of style-loader is breaking the build 🚨


☝️ Important announcement: Greenkeeper will be saying goodbye 👋 and passing the torch to Snyk on June 3rd, 2020! Find out how to migrate to Snyk and more at greenkeeper.io


The devDependency style-loader was updated from 1.1.3 to 1.1.4.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

style-loader is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push: The Travis CI build could not complete due to an error (Details).

Release Notes for v1.1.4

1.1.4 (2020-04-15)

Chore

  • update deps
Commits

The new version differs by 3 commits.

  • 171a747 chore(release): 1.1.4
  • af1b4a9 chore(deps): update
  • a003f05 docs: add links for the options table (#460)

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Specifying only x or only y domain in XYPlot breaks resolveXYScales in some cases

This problem only occurs when either x or y is set in the domain prop of XYPlot, but not when both are set, nor when the domain prop is not specified.

The error occurs in /src/utils/resolveXYScales.js. I only see the error in the built code, but after trying to parse it out of the unbuilt code I believe it's line 360-361. It's possible to resolve this issue by explicitly specifying both x and y in the scaleType prop on XYPlot.

As a way to reproduce, the example on the following line will generate the error if the scaleType="linear" prop is removed:
https://github.com/spotify/reactochart/blob/0.2.1/examples/src/Examples.jsx#L111

Namespace default classNames

Currently by default we render (& style) elements with very general classNames eg. chart-bar or xy-plot which could accidentally collide with classNames that users would use in their apps. Per suggestion from @ekh64 we should prefix these with a namespace eg rc-chart-bar. rc- seems best, but I want to check out rc-slider (common slider library) and similar to make sure we don't use the same prefix they do.

v4.17 of lodash causes slowness in XYPlot

the v4.17 lodash release yesterday causes some major slowness in reactochart (https://github.com/lodash/lodash/wiki/Changelog). Since it’s a ‘non-breaking’ release it can creep in when you npm install from scratch (or deploy to dev which builds on server). This problem occurs with the _.omit on line 92 of XYPlot (https://github.com/spotify/reactochart/blob/master/src/XYPlot.js#L92). Since the latest lodash version adds deep path support to _.omit the child tree of every XYPlot gets traversed and cloned for different comparison functions.

Override barClassName prop in BarChart to allow for functions returning dynamic classNames

reactochart 0.1.0 had a getClass function prop in the BarChart component that would allow the individual bars to dynamically generate their classnames. This prop is not present in the 0.2.1 version.

To replace this funcitonality, the barClassName prop of BarChart should be overridden to allow a string or a function, and the optional evaluation of that function will occur in the RangeBarChart component. Props passed to that function should be the datum, index, and potentially some of the scale information.

Add precommit hooks from spotify web-scripts

We've migrated our eslint and prettier configs to pull from Spotify's.
I don't think we necessarily need to add all the scripts they're using but we should take advantage of husky precommit hooks.

{
  "scripts": {
    "test": "web-scripts test",
    "lint": "web-scripts lint",
    "build": "web-scripts build",
    "commit": "web-scripts commit",
    "release": "web-scripts release"
  },
  "husky": {
    "hooks": {
      "commit-msg": "web-scripts commitmsg",
      "pre-commit": "web-scripts precommit"
    }
  }
}

See here for more documentation https://github.com/spotify/web-scripts

Modularize lodash

Lodash can be modularized, but the results can look gross. I took a stab on my fork, but the result was pretty gnarly (and not 100% functional)

Maybe there's a way to do this without explicit imports? Maybe something in the bundling?

Upgrade to d3 4.x

As of v4, d3 has been broken up into many modules (e.g. d3-scale, d3-selection, etc). There are also some API changes.

Not only is it a good idea to stay on the current major version, but the final size would drop quite a bit if reactochart only imports the d3 packages it needs.

I've ported a few examples and projects from 3.x to 4.x and it's relatively simple. Changing import d3 from "d3" to import * as d3 from 'd3' then doing a search-and-replace for the new methods names (old: d3.scale.ordinal new: d3.scaleOrdinal, etc) will get you pretty far. Converting to statements like import { scaleLinear, scaleOrdinal } from 'd3-scale' should be the ultimate goal, but I typically save that for a second pass after things are converted and working.

The changes to selections are probably the most substantial but, in my experience, don't take much effort to convert.

Minify output

Hey, you should minify your css and js, check out the config here on how its done.

Love <3

Allow support for scaleUtc for xScaleType and yScaleType

In our app, we had previously used scaleUtc, in our charts. This allowed for tests run on CI to not care about time zones when parsing/reading dates. Reactochart doesn't have an option to use this scale type, only scaleTime, which is set to your local time zone.

It's be great to have a different scaleType we can pass in the generate scales using UTC dates

Component props marked as required should not have defaults

There are component props listed as required within the component's PropTypes and docs but are given a default. This is misleading. In an effort to clean up this confusion, I've outlined the component and the props below that should change by either removing the isRequired or the default.

I'm also proposing that going forward we don't mark data as required and supply either a default empty array or return null in render if data is undefined. Would like some feedback on this though @spotify/reactochart-dev!

AreaChart

  • remove isRequired from data prop
  • set data: [] in defaultProps
  • set pathStyle to default to {} and remove || {} on lines 189, 190 and 221

AreaHeatmap

  • remove isRequired from data prop
  • set data: [] in defaultProps

ColorHeatmap

  • remove isRequired from data prop
  • set data: [] in defaultProps

FunnelChart

  • remove isRequired from data prop
  • set data: [] in defaultProps
  • set pathStyle default to {}
  • set style = pathStyle on line 129

Histogram

  • remove isRequired from data prop
  • set data: [] in defaultProps
  • remove isRequired from thresholds prop
  • set barClassName: '' in defaultProps
  • set barStyle: {} in defaultProps

KernelDensityEstimation

  • remove isRequired from data prop
  • set data: [] in defaultProps
  • set lineStyle: {} in defaultProps
  • set lineClassName: '' in defaultProps

LineChart

  • remove isRequired from data prop
  • set data: [] in defaultProps

MarkerLineChart

  • remove isRequired from data prop
  • set data: [] in defaultProps

PieChart

  • remove isRequired from data prop
  • set data: [] in defaultProps

SankeyDiagram

  • remove isRequired from nodes prop
  • set nodes: [] in defaultProps
  • remove isRequired from links prop
  • set links: [] in defaultProps
  • remove isRequired from width prop
  • remove isRequired from height prop

ScatterPlot

  • remove isRequired from data prop
  • set data: [] in defaultProps

TreeMap

  • remove isRequired from data prop
  • set data: {} in defaultProps

Upgrade to react & react-dom 16.x

My projects are relying on React 16.4.x, and while Reactochart functions as expected, I do get a incorrect peer dependency warning on the react and react-dom modules. Reactochart appears to be working as expected, but it would be nice to have these versions of React officially supported.

Convert test suite from mocha to jest

Our tests currently leverage mocha, chai and sinon. We should migrate our test suite to use jest.

  • It's Spotify's preferred Javascript test framework and aligns web-scripts out of the box eslint configuration. See here.
  • Jest is a kitchen sink that works out of the box, removing the need to manage multiple dependencies.
  • Jest is overtaking mocha in community adoption (as of 10/29/19 5.1 million vs 3.3 million weekly downloads). Adopting the tools used more frequently by our community can reduce barrier to contribution.

Not able to change layout in Histogram.js and Histogram.js.example accurately.

Hi,

I am new to open source and I am trying to solve an issue I have been getting.

To do

So I am trying to add a button in Histogram.js.example which changes the layout between vertical and Horizontal Histogram.

Output

It does change the sizes of the layout but it is not adjusting the graph exactly.

Here is what I am getting -

g1 g2

I just need help on how i can solve this.

Cheers,

Thoughts on implementing semantic versioning

Hello!

Reactochart doesn't have any official release & versioning procedures and I wanted to propose the official adoption of semantic versioning going forward. Per semver this would mean

  1. MAJOR version when you make incompatible API changes,
  2. MINOR version when you add functionality in a backwards-compatible manner, and
  3. PATCH version when you make backwards-compatible bug fixes.

Goals

  • Provide Reactochart users with a more meaningful idea of what each version upgrade entails. Major version upgrades relate to breaking API changes. Minor version upgrades relate to newly added or updated API changes with backward compatibility. Patch versions are for bugs and refactors that don't affect the API.
  • Removes subjectivity and human emotion from versioning through rules that are easy to reason with

What this doesn't solve

  • Documentation: Reactochart is for developers (not machines) and as maintainers we are responsible for documenting the changes of each release. This means being descriptive with our changes via the changelog, and updating our docs on gh-pages with each release.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.