GithubHelp home page GithubHelp logo

yoctol / react-d3-cloud Goto Github PK

View Code? Open in Web Editor NEW
137.0 15.0 47.0 2.07 MB

A word cloud react component built with d3-cloud.

Home Page: https://yoctol.github.io/react-d3-cloud

License: MIT License

JavaScript 14.63% HTML 2.05% Shell 0.55% TypeScript 82.77%
d3-cloud react word-cloud tag-cloud

react-d3-cloud's Introduction

react-d3-cloud

npm version Build Status

A word cloud react component built with d3-cloud.

image

Installation

npm install react-d3-cloud

Usage

Simple:

import React from 'react';
import { render } from 'react-dom';
import WordCloud from 'react-d3-cloud';

const data = [
  { text: 'Hey', value: 1000 },
  { text: 'lol', value: 200 },
  { text: 'first impression', value: 800 },
  { text: 'very cool', value: 1000000 },
  { text: 'duck', value: 10 },
];

render(<WordCloud data={data} />, document.getElementById('root'));

More configuration:

import React from 'react';
import { render } from 'react-dom';
import WordCloud from 'react-d3-cloud';
import { scaleOrdinal } from 'd3-scale';
import { schemeCategory10 } from 'd3-scale-chromatic';

const data = [
  { text: 'Hey', value: 1000 },
  { text: 'lol', value: 200 },
  { text: 'first impression', value: 800 },
  { text: 'very cool', value: 1000000 },
  { text: 'duck', value: 10 },
];

const schemeCategory10ScaleOrdinal = scaleOrdinal(schemeCategory10);

render(
  <WordCloud
    data={data}
    width={500}
    height={500}
    font="Times"
    fontStyle="italic"
    fontWeight="bold"
    fontSize={(word) => Math.log2(word.value) * 5}
    spiral="rectangular"
    rotate={(word) => word.value % 360}
    padding={5}
    random={Math.random}
    fill={(d, i) => schemeCategory10ScaleOrdinal(i)}
    onWordClick={(event, d) => {
      console.log(`onWordClick: ${d.text}`);
    }}
    onWordMouseOver={(event, d) => {
      console.log(`onWordMouseOver: ${d.text}`);
    }}
    onWordMouseOut={(event, d) => {
      console.log(`onWordMouseOut: ${d.text}`);
    }}
  />,
  document.getElementById('root')
);

Please checkout demo

for more detailed props, please refer to below:

Props

name description type required default
data The words array { text: string, value: number }>[] โœ“
width Width of the layout (px) number 700
height Height of the layout (px) number 600
font The font accessor function, which indicates the font face for each word. A constant may be specified instead of a function. string | (d) => string 'serif'
fontStyle The fontStyle accessor function, which indicates the font style for each word. A constant may be specified instead of a function. string | (d) => string 'normal'
fontWeight The fontWeight accessor function, which indicates the font weight for each word. A constant may be specified instead of a function. string | number | (d) => string | number 'normal'
fontSize The fontSize accessor function, which indicates the numerical font size for each word. (d) => number (d) => Math.sqrt(d.value)
rotate The rotate accessor function, which indicates the rotation angle (in degrees) for each word. (d) => number () => (~~(Math.random() * 6) - 3) * 30
spiral The current type of spiral used for positioning words. This can either be one of the two built-in spirals, "archimedean" and "rectangular", or an arbitrary spiral generator can be used 'archimedean' | 'rectangular' | ([width, height]) => t => [x, y] 'archimedean'
padding The padding accessor function, which indicates the numerical padding for each word. number | (d) => number 1
random The internal random number generator, used for selecting the initial position of each word, and the clockwise/counterclockwise direction of the spiral for each word. This should return a number in the range [0, 1). (d) => number Math.random
fill The fill accessor function, which indicates the color for each word. (d, i) => string (d, i) => schemeCategory10ScaleOrdinal(i)
onWordClick The function will be called when click event is triggered on a word (event, d) => {} null
onWordMouseOver The function will be called when mouseover event is triggered on a word (event, d) => {} null
onWordMouseOut The function will be called when mouseout event is triggered on a word (event, d) => {} null

FAQ

How to Use with Next.js/SSR

To make <WordCloud /> work with Server-Side Rendering (SSR), you need to avoid rendering it on the server:

{
  typeof window !== 'undefined' && <WordCloud data={data} />;
}

How to Avoid Unnecessary Re-render

As of version 0.10.1, <WordCloud /> has been wrapped by React.memo() and deep equal comparison under the hood to avoid unnecessary re-render. All you need to do is to make your function props deep equal comparable using useCallback():

import React, { useCallback } from 'react';
import { render } from 'react-dom';
import WordCloud from 'react-d3-cloud';
import { scaleOrdinal } from 'd3-scale';
import { schemeCategory10 } from 'd3-scale-chromatic';

function App() {
  const data = [
    { text: 'Hey', value: 1000 },
    { text: 'lol', value: 200 },
    { text: 'first impression', value: 800 },
    { text: 'very cool', value: 1000000 },
    { text: 'duck', value: 10 },
  ];

  const fontSize = useCallback((word) => Math.log2(word.value) * 5, []);
  const rotate = useCallback((word) => word.value % 360, []);
  const fill = useCallback((d, i) => scaleOrdinal(schemeCategory10)(i), []);
  const onWordClick = useCallback((word) => {
    console.log(`onWordClick: ${word}`);
  }, []);
  const onWordMouseOver = useCallback((word) => {
    console.log(`onWordMouseOver: ${word}`);
  }, []);
  const onWordMouseOut = useCallback((word) => {
    console.log(`onWordMouseOut: ${word}`);
  }, []);

  return (
    <WordCloud
      data={data}
      width={500}
      height={500}
      font="Times"
      fontStyle="italic"
      fontWeight="bold"
      fontSize={fontSize}
      spiral="rectangular"
      rotate={rotate}
      padding={5}
      random={Math.random}
      fill={fill}
      onWordClick={onWordClick}
      onWordMouseOver={onWordMouseOver}
      onWordMouseOut={onWordMouseOut}
    />
  );
);

Build

npm run build

Test

pre-install

Mac OS X

brew install pkg-config cairo pango libpng jpeg giflib librsvg
npm install

Ubuntu and Other Debian Based Systems

sudo apt-get update
sudo apt-get install libcairo2-dev libjpeg8-dev libpango1.0-dev libgif-dev build-essential g++
npm install

For more details, please check out Installation guides at node-canvas wiki.

Run Tests

npm test

License

MIT ยฉ Yoctol

react-d3-cloud's People

Contributors

aashish-dhiman avatar andycanderson avatar chentsulin avatar dependabot[bot] avatar desduvauchelle avatar greenkeeperio-bot avatar hilb-aibod avatar kpman avatar stegben avatar tw0517tw avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-d3-cloud's Issues

custom fontStyle

Directly provide a fontStyleMapper might be too vague for users to create one. I think a better way is to create some other props like fontOpacityMapper, fontColorMapper, etc. Then we compose all of them into one single mapper, pass it into fontStyle of d3-cloud

some ideas:

  • fontOpacityMapper
  • fontColorMapper
  • fontShaddowMapper

d3-color high severity vulnerability

react-d3-cloud depends on a version of d3-color that is vunerable to reDOS: GHSA-36jr-mh4h-2g58
Any version of d3-color <3.1.0 is vunerable to this. Please update the package.json to get a later version of react-d3-color

(env) duecknoah@Noahs-MacBook-Pro dashboard % npm audit
# npm audit report

d3-color  <3.1.0
Severity: high
d3-color vulnerable to ReDoS - https://github.com/advisories/GHSA-36jr-mh4h-2g58
fix available via `npm audit fix --force`
Will install [email protected], which is a breaking change
node_modules/d3-color
  d3-interpolate  0.1.3 - 2.0.1
  Depends on vulnerable versions of d3-color
  node_modules/d3-interpolate
    d3-scale  0.1.5 - 3.3.0
    Depends on vulnerable versions of d3-interpolate
    node_modules/d3-scale
      react-d3-cloud  >=0.5.0
      Depends on vulnerable versions of d3-scale
      Depends on vulnerable versions of d3-scale-chromatic
      node_modules/react-d3-cloud
    d3-scale-chromatic  0.1.0 - 2.0.0
    Depends on vulnerable versions of d3-color
    Depends on vulnerable versions of d3-interpolate
    node_modules/d3-scale-chromatic

5 high severity vulnerabilities

Responsive aka viewBox attribute

Hello,
would you please consider switching from width and height attributes of <svg> element to viewBox attribute (optionally / default) so the resulting <svg> is responsive?

So, instead of:
<svg width="300" height="300">...</svg>

it would be like this:
<svg viewBox="0 0 300 300" preserveAspectRatio="xMidYMid meet">...</svg>

This would change the SVG canvas to be fully responsive and handled by browser. You will have your canvas set to specific "pixels" but it can be rendered at any width and height (with the same ratio) and allow browser to scale it for full responsive behavior.

more info: https://css-tricks.com/scale-svg/

Test for fontSizeMapper

  • test if correct size is rendered
  • warn if the maximum size of word larger than width or height

Cloud re renders content on any on click event on the same page.

For every onclick event on the page the wordcloud is displayed on all the words shuffle about a bit.

The data prop is provided from redux but does not change prompting a re render of the chart

const fontSizeMapper = (word, data) =>
  (Math.log2(((word.value / data[0].value) * 5) + 1.6) * 14) - 1;

const Cloud = ({ title, data, onWordClick }) => (
  <Card>
    <CardContent>
      {title}
    </CardContent>
    <WordCloud
      data={data}
      onWordClick={onWordClick}
      fontSizeMapper={(word) => {
        return fontSizeMapper(word, data);
      }}
      font="roboto"
    />
  </Card>
);

If I have implemented it wrong let me know.

Thanks

where to put propTypes ?

Now the propTypes are set outside, however some might prefer assign a static property inside. What's the difference?

Document is not defined

Hey
I'm using this library in Nextjs, i've tried to use {typeof window !== undefined} but still getting an error that Document is not defined, any suggestions ?

Supports for server side rendering

When doing server side rendering (SSR), server will throw an error because document is not defined on the server. It would be great if SSR support can be added to this package.

Update to latest version of react?

I think I'm running into issues using this because of version mismatch issues, anyway we can get this updated to be compatible with latest version of React? Thanks!

TypeError running tests.

When I run tests using the react-d3-cloud I'm getting this:
`TypeError: Cannot read property 'getImageData' of null

  at getContext (node_modules/d3-cloud/index.js:90:50)
  at Object.cloud.start (node_modules/d3-cloud/index.js:33:27)
  at WordCloud.render (node_modules/react-d3-cloud/lib/WordCloud.js:85:14)
  at node_modules/react-test-renderer/lib/ReactCompositeComponent.js:795:21
  at measureLifeCyclePerf (node_modules/react-test-renderer/lib/ReactCompositeComponent.js:75:12)
  at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (node_modules/react-test-renderer/lib/ReactCompositeComponent.js:794:25)
  at ReactCompositeComponentWrapper._renderValidatedComponent (node_modules/react-test-renderer/lib/ReactCompositeComponent.js:821:32)
  at ReactCompositeComponentWrapper.performInitialMount (node_modules/react-test-renderer/lib/ReactCompositeComponent.js:361:30)
  at ReactCompositeComponentWrapper.mountComponent (node_modules/react-test-renderer/lib/ReactCompositeComponent.js:257:21)
  at Object.mountComponent (node_modules/react-test-renderer/lib/ReactReconciler.js:45:35)
  at ReactCompositeComponentWrapper.performInitialMount (node_modules/react-test-renderer/lib/ReactCompositeComponent.js:370:34)
  at ReactCompositeComponentWrapper.mountComponent (node_modules/react-test-renderer/lib/ReactCompositeComponent.js:257:21)
  at Object.mountComponent (node_modules/react-test-renderer/lib/ReactReconciler.js:45:35)
  at ReactCompositeComponentWrapper.performInitialMount (node_modules/react-test-renderer/lib/ReactCompositeComponent.js:370:34)
  at ReactCompositeComponentWrapper.mountComponent (node_modules/react-test-renderer/lib/ReactCompositeComponent.js:257:21)
  at Object.mountComponent (node_modules/react-test-renderer/lib/ReactReconciler.js:45:35)
  at ReactTestComponent.mountChildren (node_modules/react-test-renderer/lib/ReactMultiChild.js:236:44)
  at ReactTestComponent.mountComponent (node_modules/react-test-renderer/lib/ReactTestRenderer.js:62:10)
  at Object.mountComponent (node_modules/react-test-renderer/lib/ReactReconciler.js:45:35)
  at ReactTestComponent.mountChildren (node_modules/react-test-renderer/lib/ReactMultiChild.js:236:44)
  at ReactTestComponent.mountComponent (node_modules/react-test-renderer/lib/ReactTestRenderer.js:62:10)
  at Object.mountComponent (node_modules/react-test-renderer/lib/ReactReconciler.js:45:35)
  at ReactTestComponent.mountChildren (node_modules/react-test-renderer/lib/ReactMultiChild.js:236:44)
  at ReactTestComponent.mountComponent (node_modules/react-test-renderer/lib/ReactTestRenderer.js:62:10)
  at Object.mountComponent (node_modules/react-test-renderer/lib/ReactReconciler.js:45:35)
  at ReactTestComponent.mountChildren (node_modules/react-test-renderer/lib/ReactMultiChild.js:236:44)
  at ReactTestComponent.mountComponent (node_modules/react-test-renderer/lib/ReactTestRenderer.js:62:10)
  at Object.mountComponent (node_modules/react-test-renderer/lib/ReactReconciler.js:45:35)
  at ReactCompositeComponentWrapper.performInitialMount (node_modules/react-test-renderer/lib/ReactCompositeComponent.js:370:34)
  at ReactCompositeComponentWrapper.mountComponent (node_modules/react-test-renderer/lib/ReactCompositeComponent.js:257:21)
  at Object.mountComponent (node_modules/react-test-renderer/lib/ReactReconciler.js:45:35)
  at ReactTestComponent.mountChildren (node_modules/react-test-renderer/lib/ReactMultiChild.js:236:44)
  at ReactTestComponent.mountComponent (node_modules/react-test-renderer/lib/ReactTestRenderer.js:62:10)
  at Object.mountComponent (node_modules/react-test-renderer/lib/ReactReconciler.js:45:35)
  at ReactCompositeComponentWrapper.performInitialMount (node_modules/react-test-renderer/lib/ReactCompositeComponent.js:370:34)
  at ReactCompositeComponentWrapper.mountComponent (node_modules/react-test-renderer/lib/ReactCompositeComponent.js:257:21)
  at Object.mountComponent (node_modules/react-test-renderer/lib/ReactReconciler.js:45:35)
  at ReactCompositeComponentWrapper.performInitialMount (node_modules/react-test-renderer/lib/ReactCompositeComponent.js:370:34)
  at ReactCompositeComponentWrapper.mountComponent (node_modules/react-test-renderer/lib/ReactCompositeComponent.js:257:21)
  at Object.mountComponent (node_modules/react-test-renderer/lib/ReactReconciler.js:45:35)
  at mountComponentIntoNode (node_modules/react-test-renderer/lib/ReactTestMount.js:55:31)
  at ReactTestReconcileTransaction.perform (node_modules/react-test-renderer/lib/Transaction.js:143:20)
  at batchedMountComponentIntoNode (node_modules/react-test-renderer/lib/ReactTestMount.js:69:27)
  at ReactDefaultBatchingStrategyTransaction.perform (node_modules/react-test-renderer/lib/Transaction.js:143:20)
  at Object.batchedUpdates (node_modules/react-test-renderer/lib/ReactDefaultBatchingStrategy.js:62:26)
  at Object.batchedUpdates (node_modules/react-test-renderer/lib/ReactUpdates.js:97:27)
  at Object.render (node_modules/react-test-renderer/lib/ReactTestMount.js:128:18)
  at Object.<anonymous> (app/tests/ui/reactjs/extras/Stat.test.js:98:51)
  at Promise.resolve.then.el (node_modules/p-map/index.js:42:16)

`
I alredy did the pre-install and I'm getting the same error.
I even ran the tests given in the code(src/test) and It gave me the same issue
I use jest with the same sintaxis to do tests in my app.

Request to replace the call to "componentWillMount" (React deprecation warning)

This is the warning message:
`Warning: componentWillMount has been renamed, and is not recommended for use. See https://reactjs.org/link/unsafe-component-lifecycles for details.

  • Move code with side effects to componentDidMount, and set initial state in the constructor.
  • Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run npx react-codemod rename-unsafe-lifecycles in your project source folder.

Please update the following components: WordCloud`

Regenerating the cloud adds new SVGs

There is a bug currently if the word props are updated and the cloud is re-rendered. The system keeps adding new svg elements instead of updating the existing one.

The code here seems to be the issue. If you insert a d3.select('svg').remove() right before it, it seems to fix the issue.

I can submit a PR to that effect unless there is a more performant way to do this.

Demo word cloud

Before implement a real demo, this is a example in my own project.
image

npm ERR! 404 Not Found - GET https://registry.npmjs.org/@types%2freact-d3-cloud - Not found

Hello,

I am using your package to create a wordcloud, but I also want to modify it in terms of font weight, colors, and adding tooltips. But the WordCloud.js when I modify it, it has no effect on the application. For some reason it cannot be linked with the project.

when I run this comman: npm install @types/react-d3-cloud

I get these errors:

https://imgur.com/RlYDAhd

https://imgur.com/8MIiLUF

https://imgur.com/nXWBo86

I hope you can answer me soon. Thank you very much.

hover on word

Hi all, is it possible to display for example value of a word on hover event

thanks

When using libery warning message : React 17.x Warning: componentWillMount has been renamed

Node : v8.17.0
Ubuntu : 19
Chrome : 83.0.4103.97 (Official Build) (64-bit)
npm : 6.13.4
React : 16.6.3

warning display in DevTools

react-dom.development.js:88 Warning: componentWillMount has been renamed, and is not recommended for use. See https://fb.me/react-unsafe-component-lifecycles for details.

  • Move code with side effects to componentDidMount, and set initial state in the constructor.
  • Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run npx react-codemod rename-unsafe-lifecycles in your project source folder.

Please update the following components: WordCloud
printWarning @ react-dom.development.js:88

Font family does not work.

The word object returns the font correctly. For example: word.font is set to the prop value. But for some reason, the d3 font-family remains the default Impact and does not change what so ever.

Improved fontSizeMapper function

As I couldn't find any optimized fontSizeMapper function, I have created one,

const getRelativeValue = (value, max, totalHashtags) => {
  let percentage = 100 - Math.abs((max - value) / max) * 100;
  let maxFontSize;
  if (totalHashtags > 60) {
    maxFontSize = 50;
  } else {
    maxFontSize = 70;
  }
  const minFontSize = 12;
  const fontSizeDiff = maxFontSize - minFontSize;
  const relativeFontSize = 12 + Math.floor((fontSizeDiff * percentage) / 100);
  return relativeFontSize;
};

here, getHashtagData function will assign your word a fontSize directly to it's value attribute by the help of getRelativeValue function.
I count every word's relative value, if word has minimum value then fontSize 12 will be assigned, and same for max value.

The condition (totalHashtags > 60) is added because if you get so many of words and if WordCloud coudn't able to feet in the area then I changed the maxFontSize to 50.

const getHashtagData = data => {
  let d = [];
  if (data) {
    let max = 0;
    data.forEach(item => {
      // based on whatever structure you have in data
      if (item.count1 + item.count2 > max) {
        max = item.count1 + item.count2;
      }
    });
    data.forEach(item =>
      d.push({
        text: item.text,
        value: getRelativeValue(
          item.count1 + item.count2,
          max,
          data.length,
        ),
      }),
    );
  }
  return d;
};
const fontSizeMapper = (word) => {
  return word.value;
};
<WordCloud
        data={getHashtagData(hashtagArray)}
        fontSizeMapper={fontSizeMapper}
        onWordClick={onWordClick}
        height={250}
        width={this.props.width}
  />

Hope you liked the simple but useful logic.

Static width/height

Hello !
Is it possible to pass width/height as string to make div fix to parent and not with a static width/height ?

webpack unable to resolve reference to react-d3-cloud since updating from 0.11.0 to 1.0.3

I am working on a project using an older version of react-d3-cloud, 0.11.0, before it was converted to Typescript.

When I update the dependency to 1.0.3, webpack fails to build.

The library is imported in a normal way: import WordCloud from 'react-d3-cloud'; However, webpack is unable to resolve the reference.

Looking at package.json, I believe the main field is defined correctly:

"main": "lib/index.js",

The exports field was added in 1.0.1, and it is defined as:

"import": "./esm/index.js",
"require": "./index.js"

The webpack documentation says that the exports field overrides the value of main.

I believe the paths in the values for these two fields is incorrect. Looking at the actual package inside node_modules after installing, I believe these field values should be

    "import": "./lib/esm/index.js", 
    "require": "./lib/index.js" 

If I use 1.0.0 (the first version with Typescript), webpack builds correctly. If I use 1.0.1, when the exports field was added, webpack fails.

Is this correct, or am I installing/using react-d3-cloud incorrectly?

Canvas2D Warning

Is there any way to prevent this warning?

Canvas2D: Multiple readback operations using getImageData are faster with the willReadFrequently attribute set to true. See: https://html.spec.whatwg.org/multipage/canvas.html#concept-canvas-will-read-frequently

Thanks!

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.