Skip to content

Commit

Permalink
Merge pull request #7 from ownadi/feature/custom-rng
Browse files Browse the repository at this point in the history
Add an ability to provide custom rng
  • Loading branch information
madox2 authored Mar 14, 2019
2 parents c81bc60 + 2ec4ffe commit dd21fa1
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 24 deletions.
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,14 @@ const SimpleCloud = () => (

| Option | Type | Required | Note |
|-----------|----------|--------|---|
|`tags` |`Array` |`true`|Array of objects representing tags (see [Tag object](#tag-object))|
|`maxSize` |`Number` |`true` |Maximal font size (px) used in cloud|
|`minSize` |`Number` |`true` |Minimal font size (px) used in cloud|
|`shuffle` |`Boolean` |`false`|If true, tags are shuffled. When `tags` are modified, cloud is re-shuffled. Default: `true`|
|`colorOptions` |`Object` |`false`|Random color options (see [randomColor#options](https://github.com/davidmerfield/randomColor#options))|
|`disableRandomColor`|`Boolean` |`false`|If `true`, random color is not used|
|`renderer` |`Function`|`false`|Function used to render each tag|
|`tags` |`Array` |`true`|Array of objects representing tags (see [Tag object](#tag-object))|
|`maxSize` |`Number` |`true` |Maximal font size (px) used in cloud|
|`minSize` |`Number` |`true` |Minimal font size (px) used in cloud|
|`shuffle` |`Boolean` |`false`|If true, tags are shuffled. When `tags` are modified, cloud is re-shuffled. Default: `true`|
|`randomNumberGenerator`|`Function`|`false`|Specifies a custom random number generator that is being used by shuffle algorithm. Default: `Math.random`
|`colorOptions` |`Object` |`false`|Random color options (see [randomColor#options](https://github.com/davidmerfield/randomColor#options))|
|`disableRandomColor` |`Boolean` |`false`|If `true`, random color is not used|
|`renderer` |`Function`|`false`|Function used to render each tag|

*Note:* Furthermore you can pass any other option and it will be passed forward to the wrapping `<div />` component (e.g. `style`, `className`).

Expand Down
13 changes: 12 additions & 1 deletion __tests__/TagCloud-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ jest.unmock('../src/TagCloud');
jest.unmock('../src/defaultRenderer');
jest.unmock('../src/helpers');

jest.mock('array-shuffle', () => arr => arr.slice().reverse());
jest.mock('shuffle-array', () => (arr, opts = {}) => {
opts.rng && opts.rng();
return arr.slice().reverse();
});

import React from 'react';
import ReactDOM from 'react-dom';
Expand Down Expand Up @@ -120,4 +123,12 @@ describe('TagCloud', () => {
cloud._data.forEach((t, i) => expect(t.tag).toEqual(data[i]));
});

it('should use custom rng', () => {
const rng = jest.fn();
TestUtils.renderIntoDocument(
<TagCloud minSize={12} maxSize={30} tags={data} shuffle={true} randomNumberGenerator={rng} />
);

expect(rng).toHaveBeenCalled();
});
});
3 changes: 2 additions & 1 deletion examples/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ const examples = [
{file: 'simple-cloud.js', title: 'Simple cloud', key: 1},
{file: 'custom-color-options.js', title: 'Custom color options', key: 2},
{file: 'custom-styles.js', title: 'Custom styles', key: 3},
{file: 'custom-renderer.js', title: 'Custom renderer', key: 4}
{file: 'custom-renderer.js', title: 'Custom renderer', key: 4},
{file: 'shuffle-with-seed.js', title: 'Shuffle with seed', key: 5}
];

class App extends React.Component {
Expand Down
29 changes: 29 additions & 0 deletions examples/src/shuffle-with-seed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import { TagCloud } from "react-tagcloud";

const data = [
{ value: "jQuery", count: 25 }, { value: "MongoDB", count: 18 },
{ value: "JavaScript", count: 38 }, { value: "React", count: 30 },
{ value: "Nodejs", count: 28 }, { value: "Express.js", count: 25 },
{ value: "HTML5", count: 33 }, { value: "CSS3", count: 20 },
{ value: "Webpack", count: 22 }, { value: "Babel.js", count: 7 },
{ value: "ECMAScript", count: 25 }, { value: "Jest", count: 15 },
{ value: "Mocha", count: 17 }, { value: "React Native", count: 27 },
{ value: "Angular.js", count: 30 }, { value: "TypeScript", count: 15 },
{ value: "Flow", count: 30 }, { value: "NPM", count: 11 },
];

// bring your own implementation of rng
let seed = 1337;
function random() {
const x = Math.sin(seed++) * 10000;
return x - Math.floor(x);
}

export default () => (
<TagCloud minSize={12}
maxSize={35}
tags={data}
randomNumberGenerator={random} />
);

14 changes: 8 additions & 6 deletions lib/TagCloud.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ var _propTypes2 = _interopRequireDefault(_propTypes);

var _defaultRenderer = require('./defaultRenderer');

var _arrayShuffle = require('array-shuffle');
var _shuffleArray = require('shuffle-array');

var _arrayShuffle2 = _interopRequireDefault(_arrayShuffle);
var _shuffleArray2 = _interopRequireDefault(_shuffleArray);

var _randomcolor = require('randomcolor');

Expand All @@ -38,7 +38,7 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var eventHandlers = ['onClick', 'onDoubleClick', 'onMouseMove'];
var cloudProps = ['tags', 'shuffle', 'renderer', 'maxSize', 'minSize', 'colorOptions', 'disableRandomColor'];
var cloudProps = ['tags', 'shuffle', 'renderer', 'maxSize', 'minSize', 'colorOptions', 'disableRandomColor', 'randomNumberGenerator'];

var generateColor = function generateColor(tag, _ref) {
var disableRandomColor = _ref.disableRandomColor,
Expand Down Expand Up @@ -116,7 +116,8 @@ var TagCloud = exports.TagCloud = function (_React$Component) {
var tags = props.tags,
shuffle = props.shuffle,
minSize = props.minSize,
maxSize = props.maxSize;
maxSize = props.maxSize,
randomNumberGenerator = props.randomNumberGenerator;

var counts = tags.map(function (tag) {
return tag.count;
Expand All @@ -130,7 +131,7 @@ var TagCloud = exports.TagCloud = function (_React$Component) {
fontSize: (0, _helpers.fontSizeConverter)(tag.count, min, max, minSize, maxSize)
};
});
this._data = shuffle ? (0, _arrayShuffle2.default)(data) : data;
this._data = shuffle ? (0, _shuffleArray2.default)(data, { copy: true, rng: randomNumberGenerator }) : data;
}
}]);

Expand All @@ -145,7 +146,8 @@ TagCloud.propTypes = {
colorOptions: _propTypes2.default.object,
disableRandomColor: _propTypes2.default.bool,
renderer: _propTypes2.default.func,
className: _propTypes2.default.string
className: _propTypes2.default.string,
randomNumberGenerator: _propTypes2.default.func
};

TagCloud.defaultProps = {
Expand Down
4 changes: 2 additions & 2 deletions lib/tag-cloud.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ var _defaultRenderer = require("./default-renderer");

var _defaultRenderer2 = _interopRequireDefault(_defaultRenderer);

var _arrayShuffle = require("array-shuffle");
var _arrayShuffle = require("shuffle-array");

var _arrayShuffle2 = _interopRequireDefault(_arrayShuffle);

Expand Down Expand Up @@ -105,4 +105,4 @@ TagCloud.defaultProps = {
shuffle: true,
className: "tag-cloud"
};
module.exports = exports["default"];
module.exports = exports["default"];
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@
"collectCoverage": true
},
"dependencies": {
"array-shuffle": "^1.0.0",
"object-assign": "^4.1.0",
"prop-types": "^15.6.2",
"randomcolor": "^0.4.2"
"randomcolor": "^0.4.2",
"shuffle-array": "^1.0.1"
},
"peerDependencies": {
"react": "^16.0.0"
Expand Down
11 changes: 6 additions & 5 deletions src/TagCloud.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import { defaultRenderer } from './defaultRenderer';
import arrayShuffle from 'array-shuffle';
import arrayShuffle from 'shuffle-array';
import randomColor from 'randomcolor';
import { omitProps, includeProps, fontSizeConverter, arraysEqual, propertiesEqual } from './helpers';

const eventHandlers = ['onClick', 'onDoubleClick', 'onMouseMove'];
const cloudProps = ['tags', 'shuffle', 'renderer', 'maxSize', 'minSize', 'colorOptions', 'disableRandomColor'];
const cloudProps = ['tags', 'shuffle', 'renderer', 'maxSize', 'minSize', 'colorOptions', 'disableRandomColor', 'randomNumberGenerator'];

const generateColor = (tag, {disableRandomColor, colorOptions}) => {
if (tag.color) {
Expand Down Expand Up @@ -59,7 +59,7 @@ export class TagCloud extends React.Component {
}

_populate(props) {
const { tags, shuffle, minSize, maxSize } = props;
const { tags, shuffle, minSize, maxSize, randomNumberGenerator } = props;
const counts = tags.map(tag => tag.count),
min = Math.min(...counts),
max = Math.max(...counts);
Expand All @@ -68,7 +68,7 @@ export class TagCloud extends React.Component {
color: generateColor(tag, props),
fontSize: fontSizeConverter(tag.count, min, max, minSize, maxSize)
}));
this._data = shuffle ? arrayShuffle(data) : data;
this._data = shuffle ? arrayShuffle(data, { copy: true, rng: randomNumberGenerator }) : data;
}

}
Expand All @@ -81,7 +81,8 @@ TagCloud.propTypes = {
colorOptions: PropTypes.object,
disableRandomColor: PropTypes.bool,
renderer: PropTypes.func,
className: PropTypes.string
className: PropTypes.string,
randomNumberGenerator: PropTypes.func,
};

TagCloud.defaultProps = {
Expand Down

0 comments on commit dd21fa1

Please sign in to comment.