UNPKG

react-circle-slider-hooked-17

Version:
233 lines (204 loc) 7.78 kB
import React, { useRef } from 'react'; function polarToCartesian(centerX, centerY, radius, angleInDegrees) { var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; return { x: centerX + radius * Math.cos(angleInRadians), y: centerY + radius * Math.sin(angleInRadians) }; } function buildPath(_a) { var cx = _a.cx, cy = _a.cy, radius = _a.radius, startAngle = _a.startAngle, endAngle = _a.endAngle, thickness = _a.thickness; var start = polarToCartesian(cx, cy, radius, endAngle); var end = polarToCartesian(cx, cy, radius, startAngle); var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1"; var cutoutRadius = radius - thickness; var start2 = polarToCartesian(cx, cy, cutoutRadius, endAngle); var end2 = polarToCartesian(cx, cy, cutoutRadius, startAngle); return ["M", start.x, start.y, "A", radius, radius, 0, largeArcFlag, 0, end.x, end.y, "L", cx, cy, "Z", "M", start2.x, start2.y, "A", cutoutRadius, cutoutRadius, 0, largeArcFlag, 0, end2.x, end2.y, "L", cx, cy, "Z"].join(" "); } var THRESHOLD = 0.01; var CircleSlider = function CircleSlider(_a) { var _b = _a.value, value = _b === void 0 ? 0 : _b, _c = _a.size, size = _c === void 0 ? 180 : _c, _d = _a.stepSize, stepSize = _d === void 0 ? 1 : _d, _e = _a.min, min = _e === void 0 ? 0 : _e, _f = _a.max, max = _f === void 0 ? 100 : _f, _g = _a.circleWidth, circleWidth = _g === void 0 ? 5 : _g, _h = _a.circleColor, circleColor = _h === void 0 ? "#e9eaee" : _h, _j = _a.progressWidth, progressWidth = _j === void 0 ? 10 : _j, _k = _a.progressColor, progressColor = _k === void 0 ? "#007aff" : _k, _l = _a.knobColor, knobColor = _l === void 0 ? "#e9eaee" : _l, _m = _a.knobRadius, knobRadius = _m === void 0 ? 10 : _m, _o = _a.disabled, disabled = _o === void 0 ? false : _o, _p = _a.shadow, shadow = _p === void 0 ? true : _p, _q = _a.showTooltip, showTooltip = _q === void 0 ? false : _q, _r = _a.valuePrefix, valuePrefix = _r === void 0 ? "" : _r, _s = _a.valueSuffix, valueSuffix = _s === void 0 ? "" : _s, _t = _a.tooltipSize, tooltipSize = _t === void 0 ? 32 : _t, _u = _a.tooltipColor, tooltipColor = _u === void 0 ? "#333" : _u, onChange = _a.onChange, className = _a.className; // takes care of min, max and stepSize var formatValue = function formatValue(input) { return Math.round((input || (value < min ? min : value > max ? max : value)) / stepSize) * stepSize; }; var valueToAngle = function valueToAngle() { var newAngle = Math.round((formatValue() - min) / (max - min) * 360); return newAngle === 360 ? newAngle - THRESHOLD : newAngle % 360; }; var angleToValue = function angleToValue(newAngle) { return formatValue(newAngle / (360 / (max - min))) + min; }; var svgRef = useRef(); var prevX = useRef(); // necessary since functional component var updateSliderFromEvent = function updateSliderFromEvent(event) { var rectSize = svgRef.current.getBoundingClientRect(); var rectCenter = rectSize.width / 2; var x = event.clientX - rectSize.left - rectCenter; var y = event.clientY - rectSize.top - rectCenter; var angleBetweenTwoVectors = Math.atan2(y, x); var newAngle = Math.round(angleBetweenTwoVectors * 180 / Math.PI) + 90; if (x < 0 && y < 0) { newAngle += 360; } // prevent jumping from "< 360 to > 0" and "> 0 to < 360" if (y < 0) { if (prevX.current < 0 && x > 0) { newAngle = 360 - THRESHOLD; // can't go over 360 } else if (prevX.current > 0 && x < 0) { newAngle = THRESHOLD; // can't go lower than 0 } else { prevX.current = x; } } else { prevX.current = x; } onChange(angleToValue(newAngle)); }; // mouse event handlers // -------------------- // react event var handleMouseDown = function handleMouseDown(event) { event.preventDefault(); svgRef.current.addEventListener("mousemove", handleMouseMove); svgRef.current.addEventListener("mouseup", handleMouseUp); }; // regular dom event var handleMouseMove = function handleMouseMove(event) { event.preventDefault(); updateSliderFromEvent(event); }; // regular dom event var handleMouseUp = function handleMouseUp(event) { event.preventDefault(); svgRef.current.removeEventListener("mousemove", handleMouseMove); svgRef.current.removeEventListener("mouseup", handleMouseUp); }; // touch event handlers // -------------------- // react event var handleTouchStart = function handleTouchStart() { svgRef.current.addEventListener("touchmove", handleTouchMove); svgRef.current.addEventListener("touchend", handleTouchUp); }; // regular dom event var handleTouchMove = function handleTouchMove(event) { var targetTouches = event.targetTouches; var currentTouch = targetTouches.item(targetTouches.length - 1); if (currentTouch) { updateSliderFromEvent(currentTouch); } }; // regular dom event var handleTouchUp = function handleTouchUp() { svgRef.current.removeEventListener("touchmove", handleTouchMove); svgRef.current.removeEventListener("touchend", handleTouchUp); }; var center = size / 2; // if there is a shadow we need to draw a bit smaller to not cut if off var radius = center - Math.max(circleWidth, progressWidth, knobRadius * 2) / 2 - (shadow ? 10 : 0); var progressPath = buildPath({ cx: center, cy: center, radius: radius + progressWidth / 2, startAngle: 0, endAngle: valueToAngle(), thickness: progressWidth }); var knobCenter = polarToCartesian(center, center, radius, valueToAngle()); return /*#__PURE__*/React.createElement("svg", { ref: svgRef, className: className, height: size, width: size, viewBox: "0 0 " + size + " " + size, onMouseDown: disabled ? undefined : handleMouseDown, onTouchStart: disabled ? undefined : handleTouchStart, style: { boxSizing: "border-box", touchAction: "none" } }, /*#__PURE__*/React.createElement("circle", { style: { fill: "none", stroke: circleColor, strokeWidth: circleWidth }, r: radius, cx: center, cy: center }), /*#__PURE__*/React.createElement("path", { style: { fill: progressColor, fillRule: "evenodd", stroke: "none" }, d: progressPath }), shadow && /*#__PURE__*/React.createElement("filter", { id: "dropShadow", filterUnits: "userSpaceOnUse" }, /*#__PURE__*/React.createElement("feGaussianBlur", { "in": "SourceAlpha", stdDeviation: "3" }), /*#__PURE__*/React.createElement("feOffset", { dx: "2", dy: "2" }), /*#__PURE__*/React.createElement("feComponentTransfer", null, /*#__PURE__*/React.createElement("feFuncA", { type: "linear", slope: "0.3" })), /*#__PURE__*/React.createElement("feMerge", null, /*#__PURE__*/React.createElement("feMergeNode", null), /*#__PURE__*/React.createElement("feMergeNode", { "in": "SourceGraphic" }))), /*#__PURE__*/React.createElement("circle", { style: { cursor: disabled ? "not-allowed" : "pointer", fill: knobColor }, filter: shadow ? "url(#dropShadow)" : "none", r: knobRadius, cx: knobCenter.x, cy: knobCenter.y }), showTooltip && /*#__PURE__*/React.createElement("text", { x: size / 2, y: size / 2 + tooltipSize / 3, textAnchor: "middle", fontSize: tooltipSize, fontFamily: "Arial", fill: tooltipColor }, valuePrefix, formatValue(), valueSuffix)); }; export { CircleSlider }; //# sourceMappingURL=index.js.map