UNPKG

vue-slider-component

Version:
464 lines 15 kB
import Decimal from './decimal'; export const ERROR_MSG = { [1 /* VALUE */]: 'The type of the "value" is illegal', [2 /* INTERVAL */]: 'The prop "interval" is invalid, "(max - min)" must be divisible by "interval"', [3 /* MIN */]: 'The "value" must be greater than or equal to the "min".', [4 /* MAX */]: 'The "value" must be less than or equal to the "max".', [5 /* ORDER */]: 'When "order" is false, the parameters "minRange", "maxRange", "fixed", "enabled" are invalid.', }; /** * Slider logic control center * * @export * @class Control */ export default class Control { constructor(options) { this.dotsPos = []; // The position of each slider this.dotsValue = []; // The value of each slider this.cacheRangeDir = {}; this.data = options.data; this.max = options.max; this.min = options.min; this.interval = options.interval; this.order = options.order; this.marks = options.marks; this.included = options.included; this.process = options.process; this.adsorb = options.adsorb; this.dotOptions = options.dotOptions; this.onError = options.onError; if (this.order) { this.minRange = options.minRange || 0; this.maxRange = options.maxRange || 0; this.enableCross = options.enableCross; this.fixed = options.fixed; } else { if (options.minRange || options.maxRange || !options.enableCross || options.fixed) { this.emitError(5 /* ORDER */); } this.minRange = 0; this.maxRange = 0; this.enableCross = true; this.fixed = false; } this.setValue(options.value); } setValue(value) { this.setDotsValue(Array.isArray(value) ? this.order ? [...value].sort((a, b) => this.getIndexByValue(a) - this.getIndexByValue(b)) : [...value] : [value], true); } setDotsValue(value, syncPos) { this.dotsValue = value; if (syncPos) { this.syncDotsPos(); } } // Set the slider position setDotsPos(dotsPos) { const list = this.order ? [...dotsPos].sort((a, b) => a - b) : dotsPos; this.dotsPos = list; this.setDotsValue(list.map(dotPos => this.getValueByPos(dotPos)), this.adsorb); } // Get value by position getValueByPos(pos) { let value = this.parsePos(pos); // When included is true, the return value is the value of the nearest mark if (this.included) { let dir = 100; this.markList.forEach(mark => { const curDir = Math.abs(mark.pos - pos); if (curDir < dir) { dir = curDir; value = mark.value; } }); } return value; } // Sync slider position syncDotsPos() { this.dotsPos = this.dotsValue.map(v => this.parseValue(v)); } /** * Get all the marks * * @readonly * @type {Mark[]} * @memberof Control */ get markList() { if (!this.marks) { return []; } const getMarkByValue = (value, mark) => { const pos = this.parseValue(value); return { pos, value, label: value, active: this.isActiveByPos(pos), ...mark, }; }; if (this.marks === true) { return this.getValues().map(value => getMarkByValue(value)); } else if (Object.prototype.toString.call(this.marks) === '[object Object]') { return Object.keys(this.marks) .sort((a, b) => +a - +b) .map(value => { const item = this.marks[value]; return getMarkByValue(value, typeof item !== 'string' ? item : { label: item }); }); } else if (Array.isArray(this.marks)) { return this.marks.map(value => getMarkByValue(value)); } else if (typeof this.marks === 'function') { return this.getValues() .map(value => ({ value, result: this.marks(value) })) .filter(({ result }) => !!result) .map(({ value, result }) => getMarkByValue(value, result)); } else { return []; } } /** * Get the most recent slider index by position * * @param {number} pos * @returns {number} * @memberof Control */ getRecentDot(pos) { const arr = this.dotsPos .filter((dotPos, index) => !(this.getDotOption(index) && this.getDotOption(index).disabled)) .map(dotPos => Math.abs(dotPos - pos)); return arr.indexOf(Math.min(...arr)); } /** * Get index by value * * @param {Value} value * @returns {number} * @memberof Control */ getIndexByValue(value) { if (this.data) { return this.data.indexOf(value); } return new Decimal(+value).minus(this.min).divide(this.interval).toNumber(); } /** * Get value by index * * @param {index} number * @returns {Value} * @memberof Control */ getValueByIndex(index) { if (index < 0) { index = 0; } else if (index > this.total) { index = this.total; } return this.data ? this.data[index] : new Decimal(index).multiply(this.interval).plus(this.min).toNumber(); } /** * Set the position of a single slider * * @param {number} pos * @param {number} index */ setDotPos(pos, index) { pos = this.getValidPos(pos, index).pos; const changePos = pos - this.dotsPos[index]; if (!changePos) { return; } let changePosArr = new Array(this.dotsPos.length); if (this.fixed) { changePosArr = this.getFixedChangePosArr(changePos, index); } else if (this.minRange || this.maxRange) { changePosArr = this.getLimitRangeChangePosArr(pos, changePos, index); } else { changePosArr[index] = changePos; } this.setDotsPos(this.dotsPos.map((curPos, i) => curPos + (changePosArr[i] || 0))); } /** * In fixed mode, get the position of all slider changes * * @param {number} changePos Change distance of a single slider * @param {number} index slider index * @returns {DotsPosChangeArray} * @memberof Control */ getFixedChangePosArr(changePos, index) { this.dotsPos.forEach((originPos, i) => { if (i !== index) { const { pos: lastPos, inRange } = this.getValidPos(originPos + changePos, i); if (!inRange) { changePos = Math.min(Math.abs(lastPos - originPos), Math.abs(changePos)) * (changePos < 0 ? -1 : 1); } } }); return this.dotsPos.map(_ => changePos); } /** * In minRange/maxRange mode, get the position of all slider changes * * @param {number} pos position of a single slider * @param {number} changePos Change distance of a single slider * @param {number} index slider index * @returns {DotsPosChangeArray} * @memberof Control */ getLimitRangeChangePosArr(pos, changePos, index) { const changeDots = [{ index, changePos }]; const newChangePos = changePos; [this.minRange, this.maxRange].forEach((isLimitRange, rangeIndex) => { if (!isLimitRange) { return false; } const isMinRange = rangeIndex === 0; const isForward = changePos > 0; let next = 0; if (isMinRange) { next = isForward ? 1 : -1; } else { next = isForward ? -1 : 1; } // Determine if the two positions are within the legal interval const inLimitRange = (pos2, pos1) => { const diff = Math.abs(pos2 - pos1); return isMinRange ? diff < this.minRangeDir : diff > this.maxRangeDir; }; let i = index + next; let nextPos = this.dotsPos[i]; let curPos = pos; while (this.isPos(nextPos) && inLimitRange(nextPos, curPos)) { const { pos: lastPos } = this.getValidPos(nextPos + newChangePos, i); changeDots.push({ index: i, changePos: lastPos - nextPos, }); i = i + next; curPos = lastPos; nextPos = this.dotsPos[i]; } }); return this.dotsPos.map((_, i) => { const changeDot = changeDots.filter(dot => dot.index === i); return changeDot.length ? changeDot[0].changePos : 0; }); } isPos(pos) { return typeof pos === 'number'; } /** * Get a valid position by pos * * @param {number} pos * @param {number} index * @returns {{ pos: number, inRange: boolean }} */ getValidPos(pos, index) { const range = this.valuePosRange[index]; let inRange = true; if (pos < range[0]) { pos = range[0]; inRange = false; } else if (pos > range[1]) { pos = range[1]; inRange = false; } return { pos, inRange, }; } /** * Calculate the position of the slider by value * * @param {Value} val * @returns {number} */ parseValue(val) { if (this.data) { val = this.data.indexOf(val); } else if (typeof val === 'number' || typeof val === 'string') { val = +val; if (val < this.min) { this.emitError(3 /* MIN */); return 0; } if (val > this.max) { this.emitError(4 /* MAX */); return 0; } if (typeof val !== 'number' || val !== val) { this.emitError(1 /* VALUE */); return 0; } val = new Decimal(val).minus(this.min).divide(this.interval).toNumber(); } const pos = new Decimal(val).multiply(this.gap).toNumber(); return pos < 0 ? 0 : pos > 100 ? 100 : pos; } /** * Calculate the value by position * * @param {number} pos * @returns {Value} * @memberof Control */ parsePos(pos) { const index = Math.round(pos / this.gap); return this.getValueByIndex(index); } /** * Determine if the location is active * * @param {number} pos * @returns {boolean} * @memberof Control */ isActiveByPos(pos) { return this.processArray.some(([start, end]) => pos >= start && pos <= end); } /** * Get each value * * @returns {Value[]} * @memberof Control */ getValues() { if (this.data) { return this.data; } else { const values = []; for (let i = 0; i <= this.total; i++) { values.push(new Decimal(i).multiply(this.interval).plus(this.min).toNumber()); } return values; } } /** * Calculate the distance of the range * @param range number */ getRangeDir(range) { return range ? new Decimal(range) .divide(new Decimal(this.data ? this.data.length - 1 : this.max) .minus(this.data ? 0 : this.min) .toNumber()) .multiply(100) .toNumber() : 100; } emitError(type) { if (this.onError) { this.onError(type, ERROR_MSG[type]); } } get processArray() { if (this.process) { if (typeof this.process === 'function') { return this.process(this.dotsPos); } else if (this.dotsPos.length === 1) { return [[0, this.dotsPos[0]]]; } else if (this.dotsPos.length > 1) { return [[Math.min(...this.dotsPos), Math.max(...this.dotsPos)]]; } } return []; } /** * The total number of values * * @type {number} * @memberof Control */ get total() { let total = 0; if (this.data) { total = this.data.length - 1; } else { total = new Decimal(this.max).minus(this.min).divide(this.interval).toNumber(); } if (total - Math.floor(total) !== 0) { this.emitError(2 /* INTERVAL */); return 0; } return total; } // Distance between each value get gap() { return 100 / this.total; } // The minimum distance between the two sliders get minRangeDir() { if (this.cacheRangeDir[this.minRange]) { return this.cacheRangeDir[this.minRange]; } return (this.cacheRangeDir[this.minRange] = this.getRangeDir(this.minRange)); } // Maximum distance between the two sliders get maxRangeDir() { if (this.cacheRangeDir[this.maxRange]) return this.cacheRangeDir[this.maxRange]; return (this.cacheRangeDir[this.maxRange] = this.getRangeDir(this.maxRange)); } getDotOption(index) { return Array.isArray(this.dotOptions) ? this.dotOptions[index] : this.dotOptions; } getDotRange(index, key, defaultValue) { if (!this.dotOptions) { return defaultValue; } const option = this.getDotOption(index); return option && option[key] !== void 0 ? this.parseValue(option[key]) : defaultValue; } /** * Sliding range of each slider * * @type {Array<[number, number]>} * @memberof Control */ get valuePosRange() { const dotsPos = this.dotsPos; const valuePosRange = []; dotsPos.forEach((pos, i) => { valuePosRange.push([ Math.max(this.minRange ? this.minRangeDir * i : 0, !this.enableCross ? dotsPos[i - 1] || 0 : 0, this.getDotRange(i, 'min', 0)), Math.min(this.minRange ? 100 - this.minRangeDir * (dotsPos.length - 1 - i) : 100, !this.enableCross ? dotsPos[i + 1] || 100 : 100, this.getDotRange(i, 'max', 100)), ]); }); return valuePosRange; } get dotsIndex() { return this.dotsValue.map(val => this.getIndexByValue(val)); } } //# sourceMappingURL=control.js.map