155 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			155 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| const { removeLeadingZero } = require('../lib/svgo/tools.js');
 | |
| 
 | |
| exports.name = 'cleanupListOfValues';
 | |
| exports.type = 'visitor';
 | |
| exports.active = false;
 | |
| exports.description = 'rounds list of values to the fixed precision';
 | |
| 
 | |
| const regNumericValues =
 | |
|   /^([-+]?\d*\.?\d+([eE][-+]?\d+)?)(px|pt|pc|mm|cm|m|in|ft|em|ex|%)?$/;
 | |
| const regSeparator = /\s+,?\s*|,\s*/;
 | |
| const absoluteLengths = {
 | |
|   // relative to px
 | |
|   cm: 96 / 2.54,
 | |
|   mm: 96 / 25.4,
 | |
|   in: 96,
 | |
|   pt: 4 / 3,
 | |
|   pc: 16,
 | |
|   px: 1,
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Round list of values to the fixed precision.
 | |
|  *
 | |
|  * @example
 | |
|  * <svg viewBox="0 0 200.28423 200.28423" enable-background="new 0 0 200.28423 200.28423">
 | |
|  *         ⬇
 | |
|  * <svg viewBox="0 0 200.284 200.284" enable-background="new 0 0 200.284 200.284">
 | |
|  *
 | |
|  * <polygon points="208.250977 77.1308594 223.069336 ... "/>
 | |
|  *         ⬇
 | |
|  * <polygon points="208.251 77.131 223.069 ... "/>
 | |
|  *
 | |
|  * @author kiyopikko
 | |
|  *
 | |
|  * @type {import('../lib/types').Plugin<{
 | |
|  *   floatPrecision?: number,
 | |
|  *   leadingZero?: boolean,
 | |
|  *   defaultPx?: boolean,
 | |
|  *   convertToPx?: boolean
 | |
|  * }>}
 | |
|  */
 | |
| exports.fn = (_root, params) => {
 | |
|   const {
 | |
|     floatPrecision = 3,
 | |
|     leadingZero = true,
 | |
|     defaultPx = true,
 | |
|     convertToPx = true,
 | |
|   } = params;
 | |
| 
 | |
|   /**
 | |
|    * @type {(lists: string) => string}
 | |
|    */
 | |
|   const roundValues = (lists) => {
 | |
|     const roundedList = [];
 | |
| 
 | |
|     for (const elem of lists.split(regSeparator)) {
 | |
|       const match = elem.match(regNumericValues);
 | |
|       const matchNew = elem.match(/new/);
 | |
| 
 | |
|       // if attribute value matches regNumericValues
 | |
|       if (match) {
 | |
|         // round it to the fixed precision
 | |
|         let num = Number(Number(match[1]).toFixed(floatPrecision));
 | |
|         /**
 | |
|          * @type {any}
 | |
|          */
 | |
|         let matchedUnit = match[3] || '';
 | |
|         /**
 | |
|          * @type{'' | keyof typeof absoluteLengths}
 | |
|          */
 | |
|         let units = matchedUnit;
 | |
| 
 | |
|         // convert absolute values to pixels
 | |
|         if (convertToPx && units && units in absoluteLengths) {
 | |
|           const pxNum = Number(
 | |
|             (absoluteLengths[units] * Number(match[1])).toFixed(floatPrecision)
 | |
|           );
 | |
| 
 | |
|           if (pxNum.toString().length < match[0].length) {
 | |
|             num = pxNum;
 | |
|             units = 'px';
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         // and remove leading zero
 | |
|         let str;
 | |
|         if (leadingZero) {
 | |
|           str = removeLeadingZero(num);
 | |
|         } else {
 | |
|           str = num.toString();
 | |
|         }
 | |
| 
 | |
|         // remove default 'px' units
 | |
|         if (defaultPx && units === 'px') {
 | |
|           units = '';
 | |
|         }
 | |
| 
 | |
|         roundedList.push(str + units);
 | |
|       }
 | |
|       // if attribute value is "new"(only enable-background).
 | |
|       else if (matchNew) {
 | |
|         roundedList.push('new');
 | |
|       } else if (elem) {
 | |
|         roundedList.push(elem);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return roundedList.join(' ');
 | |
|   };
 | |
| 
 | |
|   return {
 | |
|     element: {
 | |
|       enter: (node) => {
 | |
|         if (node.attributes.points != null) {
 | |
|           node.attributes.points = roundValues(node.attributes.points);
 | |
|         }
 | |
| 
 | |
|         if (node.attributes['enable-background'] != null) {
 | |
|           node.attributes['enable-background'] = roundValues(
 | |
|             node.attributes['enable-background']
 | |
|           );
 | |
|         }
 | |
| 
 | |
|         if (node.attributes.viewBox != null) {
 | |
|           node.attributes.viewBox = roundValues(node.attributes.viewBox);
 | |
|         }
 | |
| 
 | |
|         if (node.attributes['stroke-dasharray'] != null) {
 | |
|           node.attributes['stroke-dasharray'] = roundValues(
 | |
|             node.attributes['stroke-dasharray']
 | |
|           );
 | |
|         }
 | |
| 
 | |
|         if (node.attributes.dx != null) {
 | |
|           node.attributes.dx = roundValues(node.attributes.dx);
 | |
|         }
 | |
| 
 | |
|         if (node.attributes.dy != null) {
 | |
|           node.attributes.dy = roundValues(node.attributes.dy);
 | |
|         }
 | |
| 
 | |
|         if (node.attributes.x != null) {
 | |
|           node.attributes.x = roundValues(node.attributes.x);
 | |
|         }
 | |
| 
 | |
|         if (node.attributes.y != null) {
 | |
|           node.attributes.y = roundValues(node.attributes.y);
 | |
|         }
 | |
|       },
 | |
|     },
 | |
|   };
 | |
| };
 |