New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

react-liquidchart

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-liquidchart - npm Package Compare versions

Comparing version 0.1.14 to 0.2.0

__test__/Clip.test.jsx

9

__test__/LiquidChart.test.jsx

@@ -8,13 +8,6 @@ import React from 'react';

it('should render path', () => {
/*
const wrapper = mount(
<Liquid
width={400}
height={400}
/>
<Liquid />,
);
expect(wrapper.find('path').length).toBeGreaterThan(1);
*/
});
});

@@ -13,10 +13,12 @@ 'use strict';

var _d3Timer = require('d3-timer');
var _cloneChildren = require('react-offcharts-core/Utils/cloneChildren');
var _d3Shape = require('d3-shape');
var _cloneChildren2 = _interopRequireDefault(_cloneChildren);
var _d3Ease = require('d3-ease');
var _arcDimension = require('react-offcharts-core/Helpers/arcDimension');
var ease = _interopRequireWildcard(_d3Ease);
var _arcDimension2 = _interopRequireDefault(_arcDimension);
var _numbers = require('react-offcharts-core/Utils/numbers');
var _d3Selection = require('d3-selection');

@@ -26,18 +28,18 @@

var _d3Interpolate = require('d3-interpolate');
var _d3Ease = require('d3-ease');
var _d3Color = require('d3-color');
var ease = _interopRequireWildcard(_d3Ease);
var d3Color = _interopRequireWildcard(_d3Color);
require('d3-transition');
var _ReactIf = require('./ReactIf');
var _d3Interpolate = require('d3-interpolate');
var _ReactIf2 = _interopRequireDefault(_ReactIf);
var _constants = require('../Helpers/constants');
var _Text = require('./Text');
var ch = _interopRequireWildcard(_constants);
var _Text2 = _interopRequireDefault(_Text);
var _dimensions = require('../Helpers/dimensions');
var dh = _interopRequireWildcard(_dimensions);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }

@@ -53,28 +55,23 @@

/*
PropType for fill and stroke..
*/
var fillStroke = _react.PropTypes.shape({
fill: _react.PropTypes.string,
stroke: _react.PropTypes.string
});
var sample = 60;
var Liquid = function (_Component) {
_inherits(Liquid, _Component);
var LiquidChart = function (_Component) {
_inherits(LiquidChart, _Component);
function Liquid(props) {
_classCallCheck(this, Liquid);
function LiquidChart() {
_classCallCheck(this, LiquidChart);
var _this = _possibleConstructorReturn(this, (Liquid.__proto__ || Object.getPrototypeOf(Liquid)).call(this));
return _possibleConstructorReturn(this, (LiquidChart.__proto__ || Object.getPrototypeOf(LiquidChart)).apply(this, arguments));
if (props.innerBound > props.outerBound) {
console.warn(ch.INNER_BIGGER_THAN_OUTER);
} else if (props.outerBound > 1) {
console.warn(ch.OUTER_BIGGER_THAN_ONE);
}
_this.iter = 0;
return _this;
}
_createClass(LiquidChart, [{
_createClass(Liquid, [{
key: 'componentDidMount',
value: function componentDidMount() {
if (this.props.animate) {
this.animate();
return;
}
this.draw();
this.renderChart();
}

@@ -84,138 +81,216 @@ }, {

value: function componentDidUpdate(prevProps, prevState) {
if (this.props.animate) {
this.animate();
return;
this.renderChart();
}
}, {
key: 'getEasing',
value: function getEasing() {
var animationEase = ease[this.props.animationEase];
if (typeof animationEase === 'function') {
return animationEase;
}
this.draw();
return ease.easeCubicInOut;
}
}, {
key: 'setRes',
value: function setRes() {
// set an array filled with zeros,
// we are just going to use the index anyways
this.arr = new Array(100);
// get the clip path
this.wave = (0, _d3Selection.select)(this.clipPath).datum([this.props.value]);
// get the tspan
this.text = (0, _d3Selection.select)(this.container).selectAll('text').selectAll('tspan.value');
key: 'getAnimationTime',
value: function getAnimationTime() {
var animationTime = this.props.animationTime;
var height = this.props.height * (this.props.innerRadius - this.props.margin) / 2;
// to animate the wave we need to set the width of the path double the diameter
// of the liquid.
this.x = (0, _d3Scale.scaleLinear)().range([-this.liquidRadius * 2, this.liquidRadius * 2]).domain([0, 100]);
this.y = (0, _d3Scale.scaleLinear)().range([height, -height]).domain([0, 100]);
if (animationTime === undefined) {
return 2000;
}
return animationTime;
}
}, {
key: 'draw',
value: function draw() {
key: 'animateBackAndForth',
value: function animateBackAndForth() {
var _this2 = this;
// ready the chart
this.setRes();
// some basic trig
var val = (0, _d3Shape.area)().x(function (d, i) {
return _this2.x(i);
}).y0(function (d, i) {
return _this2.y(_this2.props.amplitude * Math.sin(i / _this2.props.frequency) + _this2.props.value);
}).y1(function (d) {
return _this2.props.height / 2;
// Set the sampling array to a new array of X times undefines
// does not matter because we only use zeros
var arr = new Array(ch.SAMPLING);
// Get the container element
var container = (0, _d3Selection.select)(this.container);
// select the clippath that is going to be animated
var wave = container.select('clipPath').select('path');
// Get the easing type, if the user misspelled the easing or
var animationEase = this.getEasing();
// Get the animationtime
var animationTime = this.getAnimationTime();
// get the wavescale
var waveScale = dh.getWaveScaleLimit(this.props);
// get the scales and the area function
var _dh$getWaveArea = dh.getWaveArea(this.props),
waveArea = _dh$getWaveArea.waveArea,
x = _dh$getWaveArea.x,
y = _dh$getWaveArea.y; // { waveArea, x, y, w, h }
var _dh$getBackAndForth = dh.getBackAndForth(),
forthAmplitude = _dh$getBackAndForth.forthAmplitude,
backAmplitude = _dh$getBackAndForth.backAmplitude,
forthFrequency = _dh$getBackAndForth.forthFrequency,
backFrequency = _dh$getBackAndForth.backFrequency;
var textValue = container.selectAll('.' + ch.TEXT_VALUE);
var textDecimal = container.selectAll('.' + ch.TEXT_DECIMAL);
var animation = function animation() {
wave.transition().duration(_this2.props.animationWavesTime).ease(ease.easeSinInOut).attrTween('d', function () {
wave.node().M = 1;
return function (t1) {
var amp = forthAmplitude(t1);
var freq = forthFrequency(t1);
var ws = amp * waveScale(_this2.props.value);
waveArea.y0(function (d, i) {
return y(dh.sine(ws, i, _this2.props.frequency, freq) + _this2.props.value);
});
wave.node().A = amp;
wave.node().F = freq;
return waveArea(arr);
};
}).transition().duration(_this2.props.animationWavesTime).ease(ease.easeSinInOut).attrTween('d', function () {
wave.node().M = 0;
return function (t1) {
var amp = backAmplitude(t1);
var freq = backFrequency(t1);
var ws = amp * waveScale(_this2.props.value);
waveArea.y0(function (d, i) {
return y(dh.sine(ws, i, _this2.props.frequency, freq) + _this2.props.value);
});
wave.node().A = amp;
wave.node().F = freq;
return waveArea(arr);
};
}).on('end', function () {
animation();
});
};
wave.transition().duration(animationTime).ease(animationEase).attrTween('d', function () {
var interVal = (0, _d3Interpolate.interpolate)(wave.node().old || 0, _this2.props.value);
var _dh$getWaveValueMovem = dh.getWaveValueMovement(wave.node()),
amplitudeScale = _dh$getWaveValueMovem.amplitudeScale,
frequencyScale = _dh$getWaveValueMovem.frequencyScale;
var updateNum = function updateNum(val) {
var value = (0, _numbers.round)(val);
var sp = (0, _numbers.splitNumber)(value, _this2.props.deliminator);
textValue.text(sp.number);
textDecimal.text('.' + sp.fraction);
};
return function (t) {
var val = interVal(t);
var amp = amplitudeScale(t);
var freq = frequencyScale(t);
var ws = amp * waveScale(val);
waveArea.y0(function (d, i) {
return y(dh.sine(ws, i, _this2.props.frequency, freq) + val);
});
wave.node().old = val;
wave.node().A = amp;
wave.node().F = freq;
updateNum(val);
return waveArea(arr);
};
}).on('end', function () {
animation();
});
// set the clip path d attribute
this.wave.attr('d', val(this.arr));
// set the text to the rounded value
// decimal formatting todo
this.text.text(Math.round(this.props.value));
}
}, {
key: 'animate',
value: function animate() {
key: 'animateValue',
value: function animateValue() {
var _this3 = this;
// set the ease
var easeFn = ease[this.props.ease] ? ease[this.props.ease] : ease.easeCubicInOut;
// ready the chart and do calculations
this.setRes();
var val = (0, _d3Shape.area)().x(function (d, i) {
return _this3.x(i);
}).y1(function (d) {
return _this3.props.height / 2;
});
// reduce the wave when it's close to 0 or 100
var waveScale = void 0;
if (this.props.waveScaleLimit) {
waveScale = (0, _d3Scale.scaleLinear)().range([0, this.props.amplitude, 0]).domain([0, 50, 100]);
} else {
waveScale = (0, _d3Scale.scaleLinear)().range([this.props.amplitude, this.props.amplitude]).domain([0, 50, 100]);
}
// Set the sampling array to a new array of X times undefines
// does not matter because we only use zeros
var arr = new Array(ch.SAMPLING);
if (this.props.animateWaves) {
this.animateWave();
}
// the d3 timer goes from from 0 to 1
var time = (0, _d3Scale.scaleLinear)().range([0, 1]).domain([0, this.props.animationTime]);
// if the wave does not have old value then interpolate from 0 to value else old to value
var interpolateValue = (0, _d3Interpolate.interpolate)(this.wave.node().old || 0, this.props.value);
// Get the container element
var container = (0, _d3Selection.select)(this.container);
// start animation
var animationTimer = (0, _d3Timer.timer)(function (t) {
// set the easing
var animate = easeFn(time(t));
var value = interpolateValue(animate);
// calculate the wave
val.y0(function (d, i) {
return _this3.y(waveScale(value) * Math.sin(i / _this3.props.frequency) + value);
});
// set the text value
_this3.text.text(Math.round(value));
// set the wave data attribute
_this3.wave.attr('d', val(_this3.arr));
// the transition has ended
if (t >= _this3.props.animationTime) {
// stop the timer
animationTimer.stop();
// Make sure that the animation stops in the right place
// we set 1 as the interpolation parameter
val.y0(function (d, i) {
return _this3.y(waveScale(_this3.props.value) * Math.sin(i / _this3.props.frequency) + interpolateValue(1));
// select the clippath that is going to be animated
var wave = container.select('clipPath').select('path');
// Get the easing type, if the user misspelled the easing or
var animationEase = this.getEasing();
// Get the animationtime
var animationTime = this.getAnimationTime();
// get the wavescale
var waveScale = dh.getWaveScaleLimit(this.props);
// get the areafunction and dimensions
var _dh$getWaveArea2 = dh.getWaveArea(this.props),
waveArea = _dh$getWaveArea2.waveArea,
x = _dh$getWaveArea2.x,
y = _dh$getWaveArea2.y; // { waveArea, x, y, w, h }
// get the text variables
var textValue = container.selectAll('.' + ch.TEXT_VALUE);
var textDecimal = container.selectAll('.' + ch.TEXT_DECIMAL);
wave.transition().duration(animationTime).ease(animationEase).attrTween('d', function () {
var interVal = (0, _d3Interpolate.interpolate)(wave.node().old || 0, _this3.props.value);
var updateNum = function updateNum(val) {
var value = (0, _numbers.round)(val);
var sp = (0, _numbers.splitNumber)(value, '.');
textValue.text(sp.number);
textDecimal.text('.' + sp.fraction);
};
return function (t) {
var val = interVal(t);
var ws = waveScale(val);
waveArea.y0(function (d, i) {
return y(dh.sine(ws, i, _this3.props.frequency, 0) + val);
});
_this3.text.text(Math.round(interpolateValue(1)));
_this3.wave.attr('d', val(_this3.arr));
// if the onEnd prop is set then call the function
if (_this3.props.onEnd !== undefined) {
_this3.props.onEnd();
}
}
wave.node().old = val;
updateNum(val);
return waveArea(arr);
};
});
// Store the old node value so that we can animate from
// that point again
this.wave.node().old = this.props.value;
}
// animate the wave from 0 to liquidRadius repeat
// not perfect but works
}, {
key: 'animateWave',
value: function animateWave() {
var _this4 = this;
key: 'animate',
value: function animate() {
if (this.props.animationWavesTime) {
this.animateBackAndForth();
return;
}
this.animateValue();
}
}, {
key: 'draw',
value: function draw() {
var arr = new Array(ch.SAMPLING);
var container = (0, _d3Selection.select)(this.container);
var el = container.select('clipPath').select('path');
var textValue = container.selectAll('.' + ch.TEXT_VALUE);
var decimalValue = container.selectAll('.' + ch.TEXT_DECIMAL);
decimalValue.text('.3');
textValue.text(parseInt(this.props.value, 10));
el.attr('d', dh.getWave(this.props)(arr));
}
}, {
key: 'renderChart',
value: function renderChart() {
var shouldAnimate = this.props.animationTime || this.props.animationEase;
// put a lock on animate function
// so it's not called often
if (!this.isOn) {
(function () {
_this4.isOn = true;
var anime = function anime() {
_this4.wave.attr('transform', 'translate(0,0)').transition().duration(_this4.props.animationWavesTime).ease(ease.easeLinear).attrTween('transform', function () {
var i = (0, _d3Interpolate.interpolate)(0, _this4.liquidRadius);
if (shouldAnimate) {
this.animate();
return;
}
return function (t) {
var yex = 3;
return 'translate(' + i(t) + ',0)';
};
}).on('end', function () {
anime();
});
};
anime();
})();
}
this.draw();
}

@@ -225,60 +300,14 @@ }, {

value: function render() {
var _this5 = this;
var _this4 = this;
this.radius = Math.min(this.props.height / 2, this.props.width / 2);
this.liquidRadius = this.radius * (this.props.innerRadius - this.props.margin);
// set the outerArc arc parameters
var outerArc = (0, _d3Shape.arc)().outerRadius(this.props.outerRadius * this.radius).innerRadius(this.props.innerRadius * this.radius).startAngle(0).endAngle(Math.PI * 2);
// set the chart center
var cX = this.props.width / 2;
var cY = this.props.height / 2;
var fillCircle = this.props.liquid.fill;
if (this.props.gradient) {
fillCircle = 'url(#gradient)';
}
var d = dh.getDimensions(this.props);
return _react2.default.createElement(
'g',
{
transform: 'translate(' + cX + ',' + cY + ')',
ref: function ref(c) {
_this5.container = c;
}
_this4.container = c;
},
transform: 'translate(' + d.cx + ',' + d.cy + ')'
},
_react2.default.createElement(
'defs',
null,
_react2.default.createElement(
'clipPath',
{ id: 'clip' },
_react2.default.createElement('path', { ref: function ref(c) {
_this5.clipPath = c;
} })
)
),
(0, _Text2.default)(this.props, this.props.number),
_react2.default.createElement(
'g',
{ clipPath: 'url(#clip)' },
_react2.default.createElement('circle', {
r: this.liquidRadius,
fill: fillCircle
}),
(0, _Text2.default)(this.props, this.props.liquidNumber)
),
_react2.default.createElement('path', {
d: outerArc(),
fill: this.props.outerArcStyle.fill,
stroke: this.props.outerArcStyle.stroke
}),
_react2.default.createElement('circle', {
r: this.radius,
fill: 'rgba(0,0,0,0)',
stroke: 'rgba(0,0,0,0)',
style: { pointerEvents: 'all' },
onClick: function onClick() {
_this5.props.onClick();
}
})
(0, _cloneChildren2.default)(this.props, d)
);

@@ -288,80 +317,22 @@ }

return LiquidChart;
return Liquid;
}(_react.Component);
LiquidChart.propTypes = {
// a percentage from 0 to 100
value: _react.PropTypes.number,
// boolean if true then animate
animate: _react.PropTypes.bool,
// comes from Chart parent
width: _react.PropTypes.number,
// comes from Chart parent
height: _react.PropTypes.number,
// innerRadius
innerRadius: _react.PropTypes.number,
// outer radius
outerRadius: _react.PropTypes.number,
// margin between inner liquid and innerRadius
margin: _react.PropTypes.number,
// callback function called when animation is done
onEnd: _react.PropTypes.func,
// string
ease: _react.PropTypes.string,
// animation Time
Liquid.propTypes = {
value: _react.PropTypes.oneOfType([_react.PropTypes.string, _react.PropTypes.number]),
outerBound: _react.PropTypes.number,
innerBound: _react.PropTypes.number,
animationEase: _react.PropTypes.string,
animationTime: _react.PropTypes.number,
// animation wave time
animationWavesTime: _react.PropTypes.number,
// The fill and stroke for the outer arc
outerArcStyle: fillStroke,
// The fill and stroke for the liquid
liquid: fillStroke,
// The fill and stroke for the number part that
// is drenched in liquid
liquidNumber: fillStroke,
// the fill and stroke of the number that is not drenched in liquid
number: fillStroke,
// the wave amplitude
amplitude: _react.PropTypes.number,
// the wave frequncy inverse, the higer the number the fewer the waves
frequency: _react.PropTypes.number,
// scaling the wave when it´s close to 0 or 100
waveScaleLimit: _react.PropTypes.bool,
// on click
onClick: _react.PropTypes.func,
// if true then animate waves
animateWaves: _react.PropTypes.bool,
// 1 for linear 2 for radial
gradient: _react.PropTypes.number
frequency: _react.PropTypes.number
};
LiquidChart.defaultProps = {
value: 65,
animate: false,
outerRadius: 0.9,
innerRadius: 0.8,
margin: 0.025,
ease: 'easeCubicInOut',
animationTime: 2000,
animationWavesTime: 2000,
amplitude: 2,
Liquid.defaultProps = {
amplitude: 1,
liquidMargin: 0.005,
waveScaleLimit: true,
frequency: 4,
outerArcStyle: {
fill: 'rgb(23, 139, 202)'
},
liquid: {
fill: 'rgb(23, 139, 202)'
},
liquidNumber: {
fill: 'rgb(164, 219, 248)'
},
number: {
fill: 'rgb(4, 86, 129)'
},
offsetX: 1,
offsetY: 1,
onClick: function onClick() {},
fontSize: '7rem',
smallFontSize: '3rem'
deliminator: '.',
postfix: ''
};
exports.default = LiquidChart;
exports.default = Liquid;

@@ -13,6 +13,30 @@ 'use strict';

var _Chart = require('./Chart');
var _Chart = require('react-offcharts-core/Components/Chart');
var _Chart2 = _interopRequireDefault(_Chart);
var _ReactIf = require('react-offcharts-core/Components/ReactIf');
var _ReactIf2 = _interopRequireDefault(_ReactIf);
var _Gradients = require('react-offcharts-core/Components/Defs/Gradients');
var _Gradients2 = _interopRequireDefault(_Gradients);
var _guid = require('react-offcharts-core/Utils/guid');
var _guid2 = _interopRequireDefault(_guid);
var _Clip = require('./Clip');
var _Clip2 = _interopRequireDefault(_Clip);
var _Text = require('./Text');
var _Text2 = _interopRequireDefault(_Text);
var _Shape = require('./Shape');
var _Shape2 = _interopRequireDefault(_Shape);
var _Liquid = require('./Liquid');

@@ -22,19 +46,124 @@

var _Gradient = require('./Gradient');
var _props = require('../Helpers/props');
var _Gradient2 = _interopRequireDefault(_Gradient);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var gradientId = (0, _guid2.default)();
var LiquidChart = function LiquidChart(props) {
return _react2.default.createElement(
_Chart2.default,
_extends({
childRules: false
}, props),
_react2.default.createElement(_Liquid2.default, null),
_react2.default.createElement(_Gradient2.default, null)
{
width: props.width,
height: props.height,
responsive: props.responsive,
value: props.value,
clipId: (0, _guid2.default)(),
gradientId: gradientId
},
_react2.default.createElement(
_Liquid2.default,
{
outerBound: 0.95,
innerBound: 0.85,
amplitude: props.amplitude,
frequency: props.frequency,
waveScaleLimit: props.waveScaleLimit,
animationWavesTime: props.animationWavesTime,
animationTime: props.animationTime,
animationEase: props.animationEase
},
_react2.default.createElement(
_Shape2.default,
{
type: props.type,
outerStyle: props.outerStyle,
liquidStyle: props.liquidStyle,
wetStyle: props.wetStyle,
dryStyle: props.dryStyle
},
_react2.default.createElement(_Text2.default, {
deliminator: props.deliminator,
postfix: props.postfix,
showDecimal: props.showDecimal,
fontSizes: props.fontSizes,
legend: props.legend
})
),
_react2.default.createElement(
_ReactIf2.default,
{ condition: props.gradient.type, el: _react2.default.createElement('g', null) },
_react2.default.createElement(_Gradients2.default, _extends({
id: gradientId
}, props.gradient, {
fill: props.liquidStyle.fill
}))
),
_react2.default.createElement(_Clip2.default, null)
)
);
};
LiquidChart.propTypes = {
width: _react.PropTypes.number,
height: _react.PropTypes.number,
responsive: _react.PropTypes.bool,
value: _react.PropTypes.number,
amplitude: _react.PropTypes.number,
frequency: _react.PropTypes.number,
waveScaleLimit: _react.PropTypes.bool,
animationWavesTime: _react.PropTypes.number,
animationEase: _react.PropTypes.string,
animationTime: _react.PropTypes.number,
type: _react.PropTypes.number,
outerStyle: _props.fillAndStroke,
liquidStyle: _props.fillAndStroke,
wetStyle: _props.fillAndStroke,
dryStyle: _props.fillAndStroke,
deliminator: _react.PropTypes.string,
postfix: _react.PropTypes.string,
legend: _react.PropTypes.string,
showDecimal: _react.PropTypes.bool,
fontSizes: _react.PropTypes.shape({
value: _react.PropTypes.number,
decimal: _react.PropTypes.number,
postfix: _react.PropTypes.number,
legend: _react.PropTypes.number
}),
gradient: _react.PropTypes.shape({
type: _react.PropTypes.number,
r: _react.PropTypes.number,
x: _react.PropTypes.number,
x1: _react.PropTypes.number,
x2: _react.PropTypes.number,
y: _react.PropTypes.number,
y1: _react.PropTypes.number,
y2: _react.PropTypes.number,
cx: _react.PropTypes.number,
cy: _react.PropTypes.number,
fx: _react.PropTypes.number,
fy: _react.PropTypes.number,
stops: _react.PropTypes.arrayOf(_react.PropTypes.node)
})
};
LiquidChart.defaultProps = {
outerBound: 0.9,
innerBound: 0.85,
margin: 0.005,
frequency: 2,
amplitude: 4,
waveScaleLimit: true,
outerStyle: { fill: 'rgb(23,139,202)' },
liquidStyle: { fill: 'rgb(23, 139, 202)' },
dryStyle: { fill: 'rgb(4, 86, 129)' },
wetStyle: { fill: 'rgb(164, 219, 248)' },
gradient: {
x1: 0,
x2: 0,
y1: 100,
y2: 0
}
};
exports.default = LiquidChart;

@@ -1,2 +0,2 @@

"use strict";
'use strict';

@@ -7,30 +7,50 @@ Object.defineProperty(exports, "__esModule", {

var _react = require("react");
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _constants = require('../Helpers/constants');
var ch = _interopRequireWildcard(_constants);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var Text = function Text(props, _ref) {
var fill = _ref.fill,
stroke = _ref.stroke;
var LiquidText = function LiquidText(props) {
return _react2.default.createElement(
"text",
{
textAnchor: "middle",
fontSize: props.fontSize,
fill: fill,
stroke: stroke,
dy: props.dy,
dx: props.dx
},
'g',
null,
_react2.default.createElement(
"tspan",
{ className: "value" },
props.value
'text',
_extends({}, props.style, { textAnchor: 'middle' }),
_react2.default.createElement('tspan', {
className: ch.TEXT_VALUE,
fontSize: props.fontSizes.value * props.radius
}),
props.showDecimal ? _react2.default.createElement('tspan', {
className: ch.TEXT_DECIMAL,
dx: props.fontSizes.decimal * props.radius * -0.01,
fontSize: props.fontSizes.decimal * props.radius
}) : null,
_react2.default.createElement(
'tspan',
{
className: ch.TEXT_POSTFIX,
fontSize: props.fontSizes.postfix * props.radius
},
props.postfix
)
),
_react2.default.createElement(
"tspan",
{ fontSize: props.smallFontSize },
"%"
'text',
_extends({}, props.style, {
className: ch.TEXT_LEGEND,
dy: props.radius * (props.fontSizes.legend + 0.05),
fontSize: props.radius * props.fontSizes.legend,
textAnchor: 'middle'
}),
props.legend
)

@@ -40,10 +60,30 @@ );

Text.propTypes = {
value: _react.PropTypes.number,
smallFontSize: _react.PropTypes.string,
fontSize: _react.PropTypes.string,
dy: _react.PropTypes.string,
dx: _react.PropTypes.string
var dShape = _react.PropTypes.shape({
dx: _react.PropTypes.number,
dy: _react.PropTypes.number
});
LiquidText.propTypes = {
fontSizes: _react.PropTypes.shape({
value: _react.PropTypes.number,
decimal: _react.PropTypes.number,
postfix: _react.PropTypes.number,
legend: _react.PropTypes.number
}),
radius: _react.PropTypes.number,
postfix: _react.PropTypes.string,
legend: _react.PropTypes.string,
style: _react.PropTypes.shape({}),
showDecimal: _react.PropTypes.bool
};
exports.default = Text;
LiquidText.defaultProps = {
fontSizes: {
value: 0.5,
decimal: 0.35,
postfix: 0.25,
legend: 0.1
}
};
exports.default = LiquidText;

@@ -6,7 +6,7 @@ 'use strict';

});
exports.Gradient = exports.Liquid = exports.Chart = undefined;
exports.Text = exports.Liquid = exports.Clip = exports.Shape = undefined;
var _Chart = require('./Chart/Chart');
var _Shape = require('./Chart/Shape');
var _Chart2 = _interopRequireDefault(_Chart);
var _Shape2 = _interopRequireDefault(_Shape);

@@ -17,6 +17,10 @@ var _Liquid = require('./Chart/Liquid');

var _Gradient = require('./Chart/Gradient');
var _Clip = require('./Chart/Clip');
var _Gradient2 = _interopRequireDefault(_Gradient);
var _Clip2 = _interopRequireDefault(_Clip);
var _Text = require('./Chart/Text');
var _Text2 = _interopRequireDefault(_Text);
var _LiquidChart = require('./Chart/LiquidChart');

@@ -28,5 +32,6 @@

exports.Chart = _Chart2.default;
exports.Shape = _Shape2.default;
exports.Clip = _Clip2.default;
exports.Liquid = _Liquid2.default;
exports.Gradient = _Gradient2.default;
exports.Text = _Text2.default;
exports.default = _LiquidChart2.default;
import React, { Component } from 'react';
import { render } from 'react-dom';
import LiquidChart, { Chart, Liquid, Gradient } from '../src/index';
import LiquidChart from '../src/index';
class ChartLiquid extends Component {
const style = {
width: '50%',
height: '500px',
};
class TestLiquid extends Component {
constructor() {
super();
this.onClick = this.onClick.bind(this);
this.state = ({
value: (Math.random() * 100),
});
this.onClickOne = this.onClickOne.bind(this);
this.onClickTwo = this.onClickTwo.bind(this);
this.state = {
valueOne: Math.random() * 100,
valueTwo: Math.random() * 100,
};
}
onClick() {
this.setState({
value: (Math.random() * 100),
});
onClickOne() {
this.setState({ valueOne: Math.random() * 100 });
}
onClickTwo() {
this.setState({ valueTwo: Math.random() * 100 });
}
render() {
const Comp = (
<div
style={{
width: '100%',
height: '500px',
}}
>
<Chart
responsive
gradient={2}
>
<Liquid
animate
animateWaves
animationWavesTime={4000}
onClick={this.onClick}
return (
<span>
<div style={style}>
<LiquidChart
responsive
legend="Percentage of Completed Tasks"
value={this.state.valueOne}
amplitude={4}
value={this.state.value}
frequency={2}
animationTime={2000}
animationWavesTime={2250}
showDecimal
gradient={{
type: 1,
x1: 0,
x2: 0,
y1: 100,
y2: 0,
}}
postfix="%"
legendFontSize={0.1}
/>
<Gradient />
</Chart>
</div>
</div>
<button onClick={() => { this.onClickOne(); }}>RANDOM</button>
<div style={style}>
<LiquidChart
responsive
legend="Percentage of Completed Tasks"
value={this.state.valueTwo}
waveScaleLimit
amplitude={2}
frequency={4}
/>
</div>
</span>
);
}
const Easy = (
<div
style={{
width: '100%',
height: '500px',
}}
>
<LiquidChart
responsive
gradient="liquid"
animate
animateWaves
animationWavesTime={150}
onClick={this.onClick}
amplitude={4}
value={this.state.value}
/>
</div>
);
return (
Comp
);
}
}
render(<TestLiquid />, document.getElementById('app'));
render(<ChartLiquid />, document.getElementById('app'));

@@ -1,2 +0,2 @@

Original
Original Copyright Curtis Bratton

@@ -31,3 +31,3 @@ BSD 2-Clause License

Modfications licence
Modfications licence Arnthor Agustsson

@@ -59,4 +59,4 @@ BSD 2-Clause License

Open source under BSD 2-clause
Copyright (c) 2016 Arnthor Agustsson
Copyright (c) 2017 Arnthor Agustsson
All rights reserved.
{
"name": "react-liquidchart",
"version": "0.1.14",
"version": "0.2.0",
"description": "A Reusable liquid chart made with d3 and react",
"main": "dist/index.js",
"scripts": {
"test": "jest --watch",
"test": "jest",
"test:watch": "jest --watch",
"coverage": "jest --coverage",
"start": "webpack-dev-server --inline --hot",
"coveralls": "npm run coverage | coveralls",
"build": "babel src -d dist"

@@ -32,2 +35,3 @@ },

"babel-preset-stage-0": "^6.16.0",
"coveralls": "^2.11.15",
"enzyme": "^2.6.0",

@@ -56,8 +60,7 @@ "eslint": "^3.11.1",

"d3-shape": "^1.0.4",
"d3-timer": "^1.0.3",
"d3-transition": "^1.0.3",
"lodash.throttle": "^4.1.1",
"react": "^15.4.1",
"react-dom": "^15.4.1"
"react-dom": "^15.4.1",
"react-offcharts-core": "^0.1.2"
}
}
## React-liquidchart
[![Build Status](https://travis-ci.org/arnthor3/react-liquidchart.svg?branch=master)](https://travis-ci.org/arnthor3/react-liquidchart)
[![Coverage Status](https://coveralls.io/repos/github/arnthor3/react-liquidchart/badge.svg?branch=)](https://coveralls.io/github/arnthor3/react-liquidchart?branch=)
A Nice looking liquid chart done with d3 and react, based off http://bl.ocks.org/brattonc/5e5ce9beee483220e2f6
I will put up an example page when I am finished with all the graph types that I want to do and use - about 4 -5 more.
### Install from NPM

@@ -11,54 +12,7 @@ ```sh

### Example
For now, [this](https://arnthor3.github.io/arnthor3/offcharts) will have to do.
### Usage
``` js
import React, { Component } from 'react';
import { render } from 'react-dom';
import { Chart, Liquid, Gradient } from 'react-liquidchart';
class ChartLiquid extends Component {
constructor() {
super();
this.onClick = this.onClick.bind(this);
this.state = ({
value: (Math.random() * 100),
});
}
onClick() {
this.setState({
value: (Math.random() * 100),
});
}
render() {
return (
<div
style={{
width: '100%',
height: '500px',
}}
>
<Chart
responsive
gradient="liquid"
>
<Liquid
animate
animateWaves
onClick={this.onClick}
amplitude={4}
value={this.state.value}
/>
<Gradient />
</Chart>
</div>
);
}
}
render(<ChartLiquid />, document.getElementById('app'));
```
### Simpler version but with no gradient control
``` js

@@ -72,14 +26,4 @@ import React, { Component } from 'react';

super();
this.onClick = this.onClick.bind(this);
this.state = ({
value: (Math.random() * 100),
});
}
onClick() {
this.setState({
value: (Math.random() * 100),
});
}
render() {

@@ -94,12 +38,20 @@ return (

<LiquidChart
responsive
gradient="liquid"
animate
ease='easeBackIn'
animateWaves
animationWavesTime={4000}
onClick={this.onClick}
amplitude={4}
value={this.state.value}
/>
responsive
legend="Percentage of Completed Tasks"
value={Math.random() * 100}
showDecimal
amplitude={4}
frequency={2}
animationTime={2000}
animationWavesTime={2250}
gradient={{
type: 1,
x1: 0,
x2: 0,
y1: 100,
y2: 0,
}}
postfix="%"
legendFontSize={0.1}
/>
</div>

@@ -112,79 +64,26 @@ );

## Components
This chart is broken down into components.
### Chart
This is the container that renders the SVG element and the children.
It can keep the chart responsive so you dont have to worry about the width and heigth if you have a responsive layout.
### Chart PropTypes
### LiquidChart PropTypes
Name|Type|Default|Description|
---|---|---|---
responsive|boolean|*true*| Rerenders the chart on screen resize
width|number|*none*| sets the width of the component, if responsive is true then it will take fill out into the parent container
height|number|*none*| sets the height of the component, the same applies here to the responsive prop.
gradient|number|*null*| sets a gradient on the chart 1 is for linear 2 is for radial, you can plug in stop children in the Gradient component if you want to customize the colors, by default this takes the liquid fill and creates a small color scale around that.
### Liquid
This is the main element that renders all the visable elements in the chart along with one defs for the clipPath.
### Liquid PropTypes
Name|Type|Default|Description|
---|---|---|---
Value|number|*65*|The value
animate|bool|*false*|If true then the chart is animated
animateWaves|bool|*false*|if true then the waves will loop between the liquid radius and 0 forever.
animationWavesTime|number|*2000*|The speed of the wave animation
animationTime|number|2000| milliseconds for animation length
ease|string|*'easeCubicInOut'*|The name of the d3 easing function, other values like, easeBack, easeBackInOut, easeSinInOut, easeExpInOut. See d3 easing page for more ideas.
outerRadius|number|*0.9*|This is the outerRadius of the chart where 1 would be 100% of the radius and 0 would be 0% of the radius..
innerRadius|number|*0.8*|The innerwidth of the outerpath surronding the liquid, again 0.8 would be 80% of the radius.
Width|number|*null*| The width of the chart, used if responsive is false
height|number|*null*|The width of the chart, used if responsive is false
responsive|bool|*true*|If set to true then the element will fill out into parent container, and resize on window dimension change
Value|number|*65*|The value, tops at 100 and 0 is the minimum
animationWavesTime|number|*null*|The speed of the wave animation, going back and forth
animationTime|number|*2000*| milliseconds for animation when updating value
animationEase|string|*'easeCubicInOut'*|The name of the d3 easing function, other values like, easeBack, easeBackInOut, easeSinInOut, easeExpInOut. See d3 easing page for more ideas.
outerBound|number|*0.9*|This is the outerRadius of the chart where 1 would be 100% of the radius and 0 would be 0% of the radius..
innerBound|number|*0.8*|The innerwidth of the outerpath surronding the liquid, again 0.8 would be 80% of the radius.
margin|number|*0.025*|The margin between the outer path and the liquid, here 0.025 would be 2.5%
amplitude|number|2|The Amplitude X * sine(frequency) part of the formula
frequency|number|4|Still have to fix this one, this is actually the inverse of frequency it's sine(x/freq) so the higher the number the smoother the wave.
waveScaleLimit|bool|true|This is in the original, this will create a scale that limits the wave height close to 0 or 100
outerArcStyle|shape|{ fill: 'rgb(23,139,202)'}| The style of the outerarc fill and stroke
liquid|shape|{ fill: 'rgb(23, 139, 202)'}| The style of the liquid, fill and stroke
liquidNumber|shape|{fill: 'rgb(164, 219, 248)'}| The style of the number that is in the liquid, fill and stroke
number|shape|{fill: 'rgb(4, 86, 129)'}| The style of the number that is not in the liquid, fill and stroke
amplitude|number|*4*|The Amplitude X * sine(frequency) part of the formula
frequency|number|*2*|The frequency, how many full circles are in the chart.
waveScaleLimit|bool|*true*|This is in the original, this will create a scale that limits the wave height close to 0 or 100
outerStyle|shape|*{ fill: 'rgb(23,139,202)'}*| The style of the outerarc fill and stroke
liquidStyle|shape|*{ fill: 'rgb(23, 139, 202)'}*| The style of the liquid, fill and stroke
dryStyle|shape|*{fill: 'rgb(164, 219, 248)'}*| The style of the number that is in the liquid, fill and stroke
wetStyle|shape|*{fill: 'rgb(4, 86, 129)'}*| The style of the number that is not in the liquid, fill and stroke
fontSizes|shape|| The sizes of the fonts in ratio to the radius.
### Gradient
This component is nothing more than an ultra thin wrapper around a linearGradient defs.
It takes in stop to create the gradient effect.
But by default it uses shades of the liquid.fill color to create a simple gradient.
### Gradient PropTypes
Name|Type|Default|Description|
---|---|---|---
x1|number|*0*|The X start coordinate
x2|number|*0*|The X end coordinate
y1|number|*100*|The Y start coordinate, remember it starts on the bottom
y2|number|*0*|The Y end coordinate
#### Example
```js
// Create a Gradient effect going from the bottom left to the top right part of the liquid area
<Gradient
x1={0}
y1={100}
x2={100}
y2={0}
>
<stop stopColor={someColor1} offset="0%" />
<stop stopColor={someColor2} offset="25%" />
<stop stopColor={someColor3} offset="50%" />
<stop stopColor={someColor4} offset="75%" />
<stop stopColor={someColor5} offset="100%" />
</Gradient>
```
### LiquidChart PropTypes
All of the above propTypes apply, except you cant insert the stop children into the gradient so it just uses
the liquid.fill color to create the gradient.
### TODO
1. Write some tests
2. Create a Text Component
#### Licence
This software was available initially under the BSD-2-Clause and it still is.
Please see the original and put a github like on it at https://gist.github.com/brattonc/5e5ce9beee483220e2f6
import React, { Component, PropTypes } from 'react';
import { timer } from 'd3-timer';
import { arc, area } from 'd3-shape';
import * as ease from 'd3-ease';
import cloneChildren from 'react-offcharts-core/Utils/cloneChildren';
import arcDim from 'react-offcharts-core/Helpers/arcDimension';
import { round, splitNumber } from 'react-offcharts-core/Utils/numbers';
import { select, selectAll } from 'd3-selection';
import { scaleLinear } from 'd3-scale';
import * as ease from 'd3-ease';
import 'd3-transition';
import { interpolate } from 'd3-interpolate';
import * as d3Color from 'd3-color';
import 'd3-transition';
import ReactIf from './ReactIf';
import Text from './Text';
import * as ch from '../Helpers/constants';
import * as dh from '../Helpers/dimensions';
/*
PropType for fill and stroke..
*/
const fillStroke = PropTypes.shape({
fill: PropTypes.string,
stroke: PropTypes.string,
});
const sample = 60;
export default class LiquidChart extends Component {
export default class Liquid extends Component {
static propTypes = {
// a percentage from 0 to 100
value: PropTypes.number,
// boolean if true then animate
animate: PropTypes.bool,
// comes from Chart parent
width: PropTypes.number,
// comes from Chart parent
height: PropTypes.number,
// innerRadius
innerRadius: PropTypes.number,
// outer radius
outerRadius: PropTypes.number,
// margin between inner liquid and innerRadius
margin: PropTypes.number,
// callback function called when animation is done
onEnd: PropTypes.func,
// string
ease: PropTypes.string,
// animation Time
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
outerBound: PropTypes.number,
innerBound: PropTypes.number,
animationEase: PropTypes.string,
animationTime: PropTypes.number,
// animation wave time
animationWavesTime: PropTypes.number,
// The fill and stroke for the outer arc
outerArcStyle: fillStroke,
// The fill and stroke for the liquid
liquid: fillStroke,
// The fill and stroke for the number part that
// is drenched in liquid
liquidNumber: fillStroke,
// the fill and stroke of the number that is not drenched in liquid
number: fillStroke,
// the wave amplitude
amplitude: PropTypes.number,
// the wave frequncy inverse, the higer the number the fewer the waves
frequency: PropTypes.number,
// scaling the wave when it´s close to 0 or 100
waveScaleLimit: PropTypes.bool,
// on click
onClick: PropTypes.func,
// if true then animate waves
animateWaves: PropTypes.bool,
// 1 for linear 2 for radial
gradient: PropTypes.number,
}
static defaultProps = {
value: 65,
animate: false,
outerRadius: 0.9,
innerRadius: 0.8,
margin: 0.025,
ease: 'easeCubicInOut',
animationTime: 2000,
animationWavesTime: 2000,
amplitude: 2,
amplitude: 1,
liquidMargin: 0.005,
waveScaleLimit: true,
frequency: 4,
outerArcStyle: {
fill: 'rgb(23, 139, 202)',
},
liquid: {
fill: 'rgb(23, 139, 202)',
},
liquidNumber: {
fill: 'rgb(164, 219, 248)',
},
number: {
fill: 'rgb(4, 86, 129)',
},
offsetX: 1,
offsetY: 1,
onClick: () => {},
fontSize: '7rem',
smallFontSize: '3rem',
};
deliminator: '.',
postfix: '',
}
constructor(props) {
super();
if (props.innerBound > props.outerBound) {
console.warn(ch.INNER_BIGGER_THAN_OUTER);
} else if (props.outerBound > 1) {
console.warn(ch.OUTER_BIGGER_THAN_ONE);
}
this.iter = 0;
}
componentDidMount() {
if (this.props.animate) {
this.animate();
return;
}
this.draw();
this.renderChart();
}
componentDidUpdate(prevProps, prevState) {
if (this.props.animate) {
this.animate();
return;
this.renderChart();
}
getEasing() {
const animationEase = ease[this.props.animationEase];
if (typeof animationEase === 'function') {
return animationEase;
}
this.draw();
return ease.easeCubicInOut;
}
setRes() {
// set an array filled with zeros,
// we are just going to use the index anyways
this.arr = new Array(100);
// get the clip path
this.wave = select(this.clipPath).datum([this.props.value]);
// get the tspan
this.text = select(this.container)
.selectAll('text')
.selectAll('tspan.value');
getAnimationTime() {
const animationTime = this.props.animationTime;
const height = (this.props.height * (this.props.innerRadius - this.props.margin)) / 2;
// to animate the wave we need to set the width of the path double the diameter
// of the liquid.
this.x = scaleLinear().range([-this.liquidRadius * 2, this.liquidRadius * 2]).domain([0, 100]);
this.y = scaleLinear().range([height, -height]).domain([0, 100]);
if (animationTime === undefined) {
return 2000;
}
return animationTime;
}
draw() {
// ready the chart
this.setRes();
// some basic trig
const val = area()
.x((d, i) => this.x(i))
.y0((d, i) => this.y(
(this.props.amplitude * Math.sin(i / this.props.frequency)) +
this.props.value))
.y1(d => this.props.height / 2);
// set the clip path d attribute
this.wave.attr('d', val(this.arr));
// set the text to the rounded value
// decimal formatting todo
this.text.text(Math.round(this.props.value));
animateBackAndForth() {
// Set the sampling array to a new array of X times undefines
// does not matter because we only use zeros
const arr = new Array(ch.SAMPLING);
// Get the container element
const container = select(this.container);
// select the clippath that is going to be animated
const wave = container.select('clipPath').select('path');
// Get the easing type, if the user misspelled the easing or
const animationEase = this.getEasing();
// Get the animationtime
const animationTime = this.getAnimationTime();
// get the wavescale
const waveScale = dh.getWaveScaleLimit(this.props);
// get the scales and the area function
const { waveArea, x, y } = dh.getWaveArea(this.props); // { waveArea, x, y, w, h }
const { forthAmplitude, backAmplitude, forthFrequency, backFrequency } = dh.getBackAndForth();
const textValue = container.selectAll(`.${ch.TEXT_VALUE}`);
const textDecimal = container.selectAll(`.${ch.TEXT_DECIMAL}`);
const animation = () => {
wave
.transition()
.duration(this.props.animationWavesTime)
.ease(ease.easeSinInOut)
.attrTween('d', () => {
wave.node().M = 1;
return (t1) => {
const amp = forthAmplitude(t1);
const freq = forthFrequency(t1);
const ws = amp * waveScale(this.props.value);
waveArea
.y0((d, i) => (
y(dh.sine(ws, i, this.props.frequency, freq) + this.props.value)
));
wave.node().A = amp;
wave.node().F = freq;
return waveArea(arr);
};
})
.transition()
.duration(this.props.animationWavesTime)
.ease(ease.easeSinInOut)
.attrTween('d', () => {
wave.node().M = 0;
return (t1) => {
const amp = backAmplitude(t1);
const freq = backFrequency(t1);
const ws = amp * waveScale(this.props.value);
waveArea
.y0((d, i) => (
y(dh.sine(ws, i, this.props.frequency, freq) + this.props.value)
));
wave.node().A = amp;
wave.node().F = freq;
return waveArea(arr);
};
})
.on('end', () => {
animation();
});
};
wave
.transition()
.duration(animationTime)
.ease(animationEase)
.attrTween('d', () => {
const interVal = interpolate(wave.node().old || 0, this.props.value);
const {
amplitudeScale,
frequencyScale,
} = dh.getWaveValueMovement(wave.node());
const updateNum = (val) => {
const value = round(val);
const sp = splitNumber(value, this.props.deliminator);
textValue.text(sp.number);
textDecimal.text(`.${sp.fraction}`);
};
return (t) => {
const val = interVal(t);
const amp = amplitudeScale(t);
const freq = frequencyScale(t);
const ws = amp * waveScale(val);
waveArea
.y0((d, i) => (
y(dh.sine(ws, i, this.props.frequency, freq) + val)
));
wave.node().old = val;
wave.node().A = amp;
wave.node().F = freq;
updateNum(val);
return waveArea(arr);
};
})
.on('end', () => {
animation();
});
}
animate() {
// set the ease
const easeFn = ease[this.props.ease] ? ease[this.props.ease] : ease.easeCubicInOut;
// ready the chart and do calculations
this.setRes();
const val = area()
.x((d, i) => this.x(i))
.y1(d => this.props.height / 2);
// reduce the wave when it's close to 0 or 100
let waveScale;
if (this.props.waveScaleLimit) {
waveScale = scaleLinear()
.range([0, this.props.amplitude, 0])
.domain([0, 50, 100]);
} else {
waveScale = scaleLinear()
.range([this.props.amplitude, this.props.amplitude])
.domain([0, 50, 100]);
}
animateValue() {
// Set the sampling array to a new array of X times undefines
// does not matter because we only use zeros
const arr = new Array(ch.SAMPLING);
if (this.props.animateWaves) {
this.animateWave();
}
// the d3 timer goes from from 0 to 1
const time = scaleLinear().range([0, 1]).domain([0, this.props.animationTime]);
// if the wave does not have old value then interpolate from 0 to value else old to value
const interpolateValue = interpolate(this.wave.node().old || 0, this.props.value);
// Get the container element
const container = select(this.container);
// start animation
const animationTimer = timer((t) => {
// set the easing
const animate = easeFn(time(t));
const value = interpolateValue(animate);
// calculate the wave
val.y0((d, i) => this.y(
(waveScale(value) * Math.sin(i / this.props.frequency))
+ value));
// set the text value
this.text.text(Math.round(value));
// set the wave data attribute
this.wave.attr('d', val(this.arr));
// the transition has ended
if (t >= this.props.animationTime) {
// stop the timer
animationTimer.stop();
// Make sure that the animation stops in the right place
// we set 1 as the interpolation parameter
val.y0((d, i) => this.y(
(waveScale(this.props.value) * Math.sin(i / this.props.frequency))
+ interpolateValue(1)));
this.text.text(Math.round(interpolateValue(1)));
this.wave.attr('d', val(this.arr));
// if the onEnd prop is set then call the function
if (this.props.onEnd !== undefined) {
this.props.onEnd();
}
}
});
// Store the old node value so that we can animate from
// that point again
this.wave.node().old = this.props.value;
// select the clippath that is going to be animated
const wave = container.select('clipPath').select('path');
// Get the easing type, if the user misspelled the easing or
const animationEase = this.getEasing();
// Get the animationtime
const animationTime = this.getAnimationTime();
// get the wavescale
const waveScale = dh.getWaveScaleLimit(this.props);
// get the areafunction and dimensions
const { waveArea, x, y } = dh.getWaveArea(this.props); // { waveArea, x, y, w, h }
// get the text variables
const textValue = container.selectAll(`.${ch.TEXT_VALUE}`);
const textDecimal = container.selectAll(`.${ch.TEXT_DECIMAL}`);
wave
.transition()
.duration(animationTime)
.ease(animationEase)
.attrTween('d', () => {
const interVal = interpolate(wave.node().old || 0, this.props.value);
const updateNum = (val) => {
const value = round(val);
const sp = splitNumber(value, '.');
textValue.text(sp.number);
textDecimal.text(`.${sp.fraction}`);
};
return (t) => {
const val = interVal(t);
const ws = waveScale(val);
waveArea
.y0((d, i) => (
y(dh.sine(ws, i, this.props.frequency, 0) + val)
));
wave.node().old = val;
updateNum(val);
return waveArea(arr);
};
});
}
// animate the wave from 0 to liquidRadius repeat
// not perfect but works
animateWave() {
// put a lock on animate function
// so it's not called often
if (!this.isOn) {
this.isOn = true;
const anime = () => {
this.wave
.attr('transform', 'translate(0,0)')
.transition()
.duration(this.props.animationWavesTime)
.ease(ease.easeLinear)
.attrTween('transform', () => {
const i = interpolate(0, this.liquidRadius);
return (t) => {
const yex = 3;
return `translate(${i(t)},0)`;
};
})
.on('end', () => {
anime();
});
};
anime();
animate() {
if (this.props.animationWavesTime) {
this.animateBackAndForth();
return;
}
this.animateValue();
}
render() {
this.radius = Math.min(this.props.height / 2, this.props.width / 2);
this.liquidRadius = this.radius * (this.props.innerRadius - this.props.margin);
// set the outerArc arc parameters
const outerArc = arc()
.outerRadius(this.props.outerRadius * this.radius)
.innerRadius(this.props.innerRadius * this.radius)
.startAngle(0)
.endAngle(Math.PI * 2);
// set the chart center
const cX = this.props.width / 2;
const cY = this.props.height / 2;
draw() {
const arr = new Array(ch.SAMPLING);
const container = select(this.container);
const el = container.select('clipPath').select('path');
const textValue = container.selectAll(`.${ch.TEXT_VALUE}`);
const decimalValue = container.selectAll(`.${ch.TEXT_DECIMAL}`);
decimalValue.text('.3');
textValue.text(parseInt(this.props.value, 10));
el.attr('d', dh.getWave(this.props)(arr));
}
let fillCircle = this.props.liquid.fill;
renderChart() {
const shouldAnimate = (
this.props.animationTime || this.props.animationEase
);
if (this.props.gradient) {
fillCircle = 'url(#gradient)';
if (shouldAnimate) {
this.animate();
return;
}
this.draw();
}
render() {
const d = dh.getDimensions(this.props);
return (
<g
transform={`translate(${cX},${cY})`}
ref={(c) => { this.container = c; }}
transform={`translate(${d.cx},${d.cy})`}
>
<defs>
<clipPath id="clip">
<path ref={(c) => { this.clipPath = c; }} />
</clipPath>
</defs>
{Text(this.props, this.props.number)}
<g clipPath="url(#clip)">
<circle
r={this.liquidRadius}
fill={fillCircle}
/>
{Text(this.props, this.props.liquidNumber)}
</g>
<path
d={outerArc()}
fill={this.props.outerArcStyle.fill}
stroke={this.props.outerArcStyle.stroke}
/>
<circle
r={this.radius}
fill="rgba(0,0,0,0)"
stroke="rgba(0,0,0,0)"
style={{ pointerEvents: 'all' }}
onClick={() => { this.props.onClick(); }}
/>
{cloneChildren(this.props, d)}
</g>

@@ -289,0 +274,0 @@ );

import React, { PropTypes } from 'react';
import Chart from './Chart';
import Chart from 'react-offcharts-core/Components/Chart';
import ReactIf from 'react-offcharts-core/Components/ReactIf';
import Gradients from 'react-offcharts-core/Components/Defs/Gradients';
import guid from 'react-offcharts-core/Utils/guid';
import Clip from './Clip';
import Text from './Text';
import Shape from './Shape';
import Liquid from './Liquid';
import Gradient from './Gradient';
import { dShape, fillAndStroke, gradientProps } from '../Helpers/props';
const gradientId = guid();
const LiquidChart = props => (
<Chart
childRules={false}
{...props}
width={props.width}
height={props.height}
responsive={props.responsive}
value={props.value}
clipId={guid()}
gradientId={gradientId}
>
<Liquid />
<Gradient />
<Liquid
outerBound={0.95}
innerBound={0.85}
amplitude={props.amplitude}
frequency={props.frequency}
waveScaleLimit={props.waveScaleLimit}
animationWavesTime={props.animationWavesTime}
animationTime={props.animationTime}
animationEase={props.animationEase}
>
<Shape
type={props.type}
outerStyle={props.outerStyle}
liquidStyle={props.liquidStyle}
wetStyle={props.wetStyle}
dryStyle={props.dryStyle}
>
<Text
deliminator={props.deliminator}
postfix={props.postfix}
showDecimal={props.showDecimal}
fontSizes={props.fontSizes}
legend={props.legend}
/>
</Shape>
<ReactIf condition={props.gradient.type} el={<g />}>
<Gradients
id={gradientId}
{...props.gradient}
fill={props.liquidStyle.fill}
/>
</ReactIf>
<Clip />
</Liquid>
</Chart>
);
LiquidChart.propTypes = {
width: PropTypes.number,
height: PropTypes.number,
responsive: PropTypes.bool,
value: PropTypes.number,
amplitude: PropTypes.number,
frequency: PropTypes.number,
waveScaleLimit: PropTypes.bool,
animationWavesTime: PropTypes.number,
animationEase: PropTypes.string,
animationTime: PropTypes.number,
type: PropTypes.number,
outerStyle: fillAndStroke,
liquidStyle: fillAndStroke,
wetStyle: fillAndStroke,
dryStyle: fillAndStroke,
deliminator: PropTypes.string,
postfix: PropTypes.string,
legend: PropTypes.string,
showDecimal: PropTypes.bool,
fontSizes: PropTypes.shape({
value: PropTypes.number,
decimal: PropTypes.number,
postfix: PropTypes.number,
legend: PropTypes.number,
}),
gradient: PropTypes.shape({
type: PropTypes.number,
r: PropTypes.number,
x: PropTypes.number,
x1: PropTypes.number,
x2: PropTypes.number,
y: PropTypes.number,
y1: PropTypes.number,
y2: PropTypes.number,
cx: PropTypes.number,
cy: PropTypes.number,
fx: PropTypes.number,
fy: PropTypes.number,
stops: PropTypes.arrayOf(PropTypes.node),
}),
};
LiquidChart.defaultProps = {
outerBound: 0.9,
innerBound: 0.85,
margin: 0.005,
frequency: 2,
amplitude: 4,
waveScaleLimit: true,
outerStyle: { fill: 'rgb(23,139,202)' },
liquidStyle: { fill: 'rgb(23, 139, 202)' },
dryStyle: { fill: 'rgb(4, 86, 129)' },
wetStyle: { fill: 'rgb(164, 219, 248)' },
gradient: {
x1: 0,
x2: 0,
y1: 100,
y2: 0,
},
};
export default LiquidChart;

@@ -1,25 +0,62 @@

import React, { Component, PropTypes } from 'react';
import React, { PropTypes } from 'react';
import * as ch from '../Helpers/constants';
const Text = (props, { fill, stroke }) => (
<text
textAnchor="middle"
fontSize={props.fontSize}
fill={fill}
stroke={stroke}
dy={props.dy}
dx={props.dx}
>
<tspan className="value">{props.value}</tspan>
<tspan fontSize={props.smallFontSize}>%</tspan>
</text>
const LiquidText = props => (
<g>
<text {...props.style} textAnchor="middle">
<tspan
className={ch.TEXT_VALUE}
fontSize={props.fontSizes.value * props.radius}
/>
{ props.showDecimal ?
<tspan
className={ch.TEXT_DECIMAL}
dx={(props.fontSizes.decimal * props.radius) * -0.01}
fontSize={props.fontSizes.decimal * props.radius}
/> : null
}
<tspan
className={ch.TEXT_POSTFIX}
fontSize={props.fontSizes.postfix * props.radius}
>{props.postfix}</tspan>
</text>
<text
{...props.style}
className={ch.TEXT_LEGEND}
dy={props.radius * (props.fontSizes.legend + 0.05)}
fontSize={props.radius * props.fontSizes.legend}
textAnchor="middle"
>{props.legend}</text>
</g>
);
Text.propTypes = {
value: PropTypes.number,
smallFontSize: PropTypes.string,
fontSize: PropTypes.string,
dy: PropTypes.string,
dx: PropTypes.string,
const dShape = PropTypes.shape({
dx: PropTypes.number,
dy: PropTypes.number,
});
LiquidText.propTypes = {
fontSizes: PropTypes.shape({
value: PropTypes.number,
decimal: PropTypes.number,
postfix: PropTypes.number,
legend: PropTypes.number,
}),
radius: PropTypes.number,
postfix: PropTypes.string,
legend: PropTypes.string,
style: PropTypes.shape({}),
showDecimal: PropTypes.bool,
};
export default Text;
LiquidText.defaultProps = {
fontSizes: {
value: 0.5,
decimal: 0.35,
postfix: 0.25,
legend: 0.1,
},
};
export default LiquidText;

@@ -1,8 +0,9 @@

import Chart from './Chart/Chart';
import Shape from './Chart/Shape';
import Liquid from './Chart/Liquid';
import Gradient from './Chart/Gradient';
import Clip from './Chart/Clip';
import Text from './Chart/Text';
import LiquidChart from './Chart/LiquidChart';
export { Chart, Liquid, Gradient };
export { Shape, Clip, Liquid, Text };
export default LiquidChart;

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc