UNPKG

svg-arc-corners

Version:

SVG arc path with rounded corners

122 lines (100 loc) 3.36 kB
const RAD_DEG = Math.PI / 180.0; const PI2 = 2 * Math.PI; /** * @param {Array.<Number>} center * @param {Number} R * @param {Number} angle * @return {Array.<Number>} */ const pointOnArc = (center, R, angle) => { let radians = (angle - 90) * RAD_DEG; return [ center[0] + (R * Math.cos(radians)), center[1] + (R * Math.sin(radians)) ]; }; /** * @param {Array.<Number>} center * @param {Number} R * @param {Number} width * @return {String} */ const drawCircle = (center, R, width) => { let innerR = R - width; let [x, y] = center; return [ 'M', x - R, y, 'A', R, R, 0, 1, 0, x + R, y, 'A', R, R, 0, 1, 0, x - R, y, 'M', x - innerR, y, 'A', innerR, innerR, 0, 1, 0, x + innerR, y, 'A', innerR, innerR, 0, 1, 0, x - innerR, y, 'Z' ]; }; /** * Generates arc path * * @param {Array.<Number>} center * @param {Number} R * @param {Number} start * @param {Number} end * @param {Number} w * @param {Number} corner Corner radius * @param {Booelan=} returnPoints - return array for path or string * * @return {String|Array.<Number|String>} */ const arc = (center, R, start, end, w, corner, returnPoints) => { let points; if (Math.abs(end - start) === 360) { points = drawCircle(center, R, w); return returnPoints ? points : points.join(' '); } let innerR = R - w; let circumference = Math.abs(end - start); corner = Math.min(w / 2, corner); if (360 * (corner / (Math.PI * (R - w))) > Math.abs(start - end)) { corner = (circumference / 360) * innerR * Math.PI; } // inner and outer radiuses let innerR2 = innerR + corner; let outerRadius = R - corner; // butts corner points let oStart = pointOnArc(center, outerRadius, start); let oEnd = pointOnArc(center, outerRadius, end); let iStart = pointOnArc(center, innerR2, start); let iEnd = pointOnArc(center, innerR2, end); let iSection = 360 * (corner / (PI2 * innerR)); let oSection = 360 * (corner / (PI2 * R)); // arcs endpoints let iArcStart = pointOnArc(center, innerR, start + iSection); let iArcEnd = pointOnArc(center, innerR, end - iSection); let oArcStart = pointOnArc(center, R, start + oSection); let oArcEnd = pointOnArc(center, R, end - oSection); let arcSweep1 = circumference > 180 + 2 * oSection ? 1 : 0; let arcSweep2 = circumference > 180 + 2 * iSection ? 1 : 0; points = [ // begin path "M", oStart[0], oStart[1], // outer start corner "A", corner, corner, 0, 0, 1, oArcStart[0], oArcStart[1], // outer main arc "A", R, R, 0, arcSweep1, 1, oArcEnd[0], oArcEnd[1], // outer end corner "A", corner, corner, 0, 0, 1, oEnd[0], oEnd[1], // end butt "L", iEnd[0], iEnd[1], // inner end corner "A", corner, corner, 0, 0, 1, iArcEnd[0], iArcEnd[1], // inner arc "A", innerR, innerR, 0, arcSweep2, 0, iArcStart[0], iArcStart[1], // inner start corner "A", corner, corner, 0, 0, 1, iStart[0], iStart[1], "Z" // end path ]; return returnPoints ? points : points.join(' '); } module.exports = arc; module.exports.pointOnArc = pointOnArc; module.exports.drawCircle = drawCircle;