react-simple-knob
Version:
A simple knob element for react
551 lines (483 loc) • 15.4 kB
JavaScript
'use strict';
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var React = _interopDefault(require('react'));
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly) symbols = symbols.filter(function (sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread2(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
if (i % 2) {
ownKeys(Object(source), true).forEach(function (key) {
_defineProperty(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(Object(source)).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
}
return target;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true
}
});
if (superClass) _setPrototypeOf(subClass, superClass);
}
function _getPrototypeOf(o) {
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _getPrototypeOf(o);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function _objectWithoutProperties(source, excluded) {
if (source == null) return {};
var target = _objectWithoutPropertiesLoose(source, excluded);
var key, i;
if (Object.getOwnPropertySymbols) {
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
for (i = 0; i < sourceSymbolKeys.length; i++) {
key = sourceSymbolKeys[i];
if (excluded.indexOf(key) >= 0) continue;
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
target[key] = source[key];
}
}
return target;
}
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
function _possibleConstructorReturn(self, call) {
if (call && (typeof call === "object" || typeof call === "function")) {
return call;
}
return _assertThisInitialized(self);
}
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';
var ReactPropTypesSecret_1 = ReactPropTypesSecret;
function emptyFunction() {}
function emptyFunctionWithReset() {}
emptyFunctionWithReset.resetWarningCache = emptyFunction;
var factoryWithThrowingShims = function() {
function shim(props, propName, componentName, location, propFullName, secret) {
if (secret === ReactPropTypesSecret_1) {
// It is still safe when called from React.
return;
}
var err = new Error(
'Calling PropTypes validators directly is not supported by the `prop-types` package. ' +
'Use PropTypes.checkPropTypes() to call them. ' +
'Read more at http://fb.me/use-check-prop-types'
);
err.name = 'Invariant Violation';
throw err;
} shim.isRequired = shim;
function getShim() {
return shim;
} // Important!
// Keep this list in sync with production version in `./factoryWithTypeCheckers.js`.
var ReactPropTypes = {
array: shim,
bool: shim,
func: shim,
number: shim,
object: shim,
string: shim,
symbol: shim,
any: shim,
arrayOf: getShim,
element: shim,
elementType: shim,
instanceOf: getShim,
node: shim,
objectOf: getShim,
oneOf: getShim,
oneOfType: getShim,
shape: getShim,
exact: getShim,
checkPropTypes: emptyFunctionWithReset,
resetWarningCache: emptyFunction
};
ReactPropTypes.PropTypes = ReactPropTypes;
return ReactPropTypes;
};
var propTypes = createCommonjsModule(function (module) {
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
{
// By explicitly using `prop-types` you are opting into new production behavior.
// http://fb.me/prop-types-in-prod
module.exports = factoryWithThrowingShims();
}
});
var pointOnCircle = function pointOnCircle(center, radius, angle) {
return {
x: center + radius * Math.cos(angle),
y: center + radius * Math.sin(angle)
};
};
var degTorad = function degTorad(deg) {
return Math.PI * deg / 180;
};
var calcPath = function calcPath(_ref) {
var percentage = _ref.percentage,
angleOffset = _ref.angleOffset,
angleRange = _ref.angleRange,
arcWidth = _ref.arcWidth,
outerRadius = _ref.radius,
center = _ref.center;
var angle = angleRange * percentage;
var startAngle = angleOffset - 90;
var innerRadius = outerRadius - arcWidth;
var startAngleDegree = degTorad(startAngle);
var endAngleDegree = degTorad(startAngle + angle);
var largeArcFlag = angle < 180 ? 0 : 1;
var p1 = pointOnCircle(center, outerRadius, endAngleDegree);
var p2 = pointOnCircle(center, outerRadius, startAngleDegree);
var p3 = pointOnCircle(center, innerRadius, startAngleDegree);
var p4 = pointOnCircle(center, innerRadius, endAngleDegree);
return "M".concat(p1.x, ",").concat(p1.y, " A").concat(outerRadius, ",").concat(outerRadius, " 0 ").concat(largeArcFlag, " 0 ").concat(p2.x, ",").concat(p2.y, "L").concat(p3.x, ",").concat(p3.y, " A").concat(innerRadius, ",").concat(innerRadius, " 0 ").concat(largeArcFlag, " 1 ").concat(p4.x, ",").concat(p4.y, " L").concat(p1.x, ",").concat(p1.y);
};
var Arc = (function (_ref2) {
var color = _ref2.color,
background = _ref2.background,
style = _ref2.style,
props = _objectWithoutProperties(_ref2, ["color", "background", "style"]);
return React.createElement("g", null, background && React.createElement("path", {
d: calcPath(_objectSpread2({}, props, {
percentage: 1
})),
style: {
fill: background,
transform: style.transform
}
}), React.createElement("path", {
d: calcPath(props),
style: {
fill: color,
transform: style.transform
}
}));
});
var viewBox = {
height: 150,
width: 250
};
var angleRange = 270;
var angleOffset = 180;
var Knob =
/*#__PURE__*/
function (_React$Component) {
_inherits(Knob, _React$Component);
function Knob(props) {
var _this;
_classCallCheck(this, Knob);
_this = _possibleConstructorReturn(this, _getPrototypeOf(Knob).call(this, props));
_this.state = {
drag: false,
angle: props.defaultPercentage * angleRange,
text: {
x: 0,
y: 0
},
svgRatio: 1,
nameWidth: 20,
lastVal: null
};
_this.handleDown = _this.handleDown.bind(_assertThisInitialized(_this));
_this.handleMove = _this.handleMove.bind(_assertThisInitialized(_this));
_this.handleUp = _this.handleUp.bind(_assertThisInitialized(_this));
_this.calcAngle = _this.calcAngle.bind(_assertThisInitialized(_this));
_this.calcSvgRatio = _this.calcSvgRatio.bind(_assertThisInitialized(_this));
_this.onWindowResize = _this.onWindowResize.bind(_assertThisInitialized(_this));
return _this;
}
_createClass(Knob, [{
key: "handleDown",
value: function handleDown(_ref) {
var pageY = _ref.pageY;
this.setState({
drag: true
});
}
}, {
key: "handleUp",
value: function handleUp() {
this.setState({
drag: false,
prevPageY: null
});
}
}, {
key: "handleMove",
value: function handleMove(_ref2) {
var pageY = _ref2.pageY;
if (!this.state.drag) return;
var _this$props = this.props,
transform = _this$props.transform,
onChange = _this$props.onChange,
mouseSpeed = _this$props.mouseSpeed;
var _this$state = this.state,
angle = _this$state.angle,
prevPageY = _this$state.prevPageY;
if (!prevPageY) {
this.setState({
prevPageY: pageY
});
return;
}
var delta = (prevPageY - pageY) * mouseSpeed;
angle = this.calcAngle(angle, delta, angleRange);
onChange(transform(angle / angleRange));
this.setState({
angle: angle,
prevPageY: pageY
});
}
}, {
key: "calcAngle",
value: function calcAngle(angle, delta, angleRange) {
angle += delta;
if (angle > angleRange) {
angle -= angle - angleRange;
} else if (angle < 0) {
angle += Math.abs(angle);
}
return angle;
}
}, {
key: "componentDidMount",
value: function componentDidMount() {
window.addEventListener("resize", this.onWindowResize);
window.addEventListener("mousemove", this.handleMove);
window.addEventListener("mouseup", this.handleUp); // NOTE: We call this initially, to set the width and height values.
this.onWindowResize();
}
}, {
key: "calcSvgRatio",
value: function calcSvgRatio() {
var _this2 = this;
var _this$refs$box$getBou = this.refs.box.getBoundingClientRect(),
width = _this$refs$box$getBou.width; // NOTE: As the svg preserves it's aspect ratio, we have to calculate only
// one value that accounts for both width and height ratios.
return new Promise(function (resolve) {
_this2.setState({
svgRatio: width / viewBox.width
}, resolve);
});
}
}, {
key: "onWindowResize",
value: function onWindowResize() {
return regeneratorRuntime.async(function onWindowResize$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return regeneratorRuntime.awrap(this.calcSvgRatio());
case 2:
this.fitText();
case 3:
case "end":
return _context.stop();
}
}
}, null, this);
}
}, {
key: "fitText",
value: function fitText() {
var svgRatio = this.state.svgRatio;
var rect = this.refs.name.getBoundingClientRect();
this.setState({
nameWidth: rect.width / svgRatio
});
}
}, {
key: "render",
value: function render() {
var _this$props2 = this.props,
bg = _this$props2.bg,
fg = _this$props2.fg,
transform = _this$props2.transform,
step = _this$props2.step,
unit = _this$props2.unit,
name = _this$props2.name,
style = _this$props2.style;
var _this$state2 = this.state,
svgRatio = _this$state2.svgRatio,
angle = _this$state2.angle,
nameWidth = _this$state2.nameWidth;
var percentage = angle / angleRange;
var width = viewBox.width,
height = viewBox.height;
var outerCircle = {
arcWidth: 10,
radius: 40
};
var font = {
marginBottom: 5,
size: style && style.fontSize || 40,
family: style && style.fontFamily || "Arial"
};
return React.createElement("svg", {
ref: "box",
onMouseDown: this.handleDown,
style: style,
viewBox: "0 0 ".concat(width, " ").concat(height)
}, React.createElement("text", {
ref: "name",
style: {
fill: style && style.color,
fontFamily: font.family,
pointerEvents: "none",
cursor: "pointer",
userSelect: "none"
},
x: "0",
y: font.size,
fontSize: font.size
}, name), React.createElement("circle", {
fill: bg,
r: 25,
cx: outerCircle.arcWidth + outerCircle.radius,
cy: 50 + font.size + font.marginBottom
}), React.createElement(Arc, {
percentage: percentage,
angleOffset: angleOffset,
angleRange: angleRange,
arcWidth: outerCircle.arcWidth,
radius: outerCircle.radius,
center: 50,
background: bg,
color: fg,
style: {
transform: "translateY(".concat(font.size + font.marginBottom, "px)")
}
}), React.createElement("text", {
ref: "value",
style: {
fill: style && style.color,
fontFamily: style && style.fontFamily || "Arial",
pointerEvents: "none",
cursor: "pointer",
userSelect: "none"
},
x: 80,
y: outerCircle.arcWidth + 2 * outerCircle.radius + font.size,
fontSize: font.size
}, "".concat(transform(percentage), " ").concat(unit)));
}
}]);
return Knob;
}(React.Component);
Knob.propTypes = {
defaultPercentage: propTypes.number,
onChange: propTypes.func.isRequired,
transform: propTypes.func,
mouseSpeed: propTypes.number,
unit: propTypes.string,
name: propTypes.string,
style: propTypes.object,
bg: propTypes.string,
fg: propTypes.string
};
Knob.defaultProps = {
defaultPercentage: 0,
transform: function transform(p) {
return p;
},
mouseSpeed: 1,
unit: "",
name: "",
bg: "black",
fg: "white"
};
module.exports = Knob;
//# sourceMappingURL=react-simple-knob.cjs.js.map