Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

VSlider.js 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
  2. // Styles
  3. import '../../../src/stylus/components/_sliders.styl';
  4. // Components
  5. import { VScaleTransition } from '../transitions';
  6. // Extensions
  7. import VInput from '../VInput';
  8. // Directives
  9. import ClickOutside from '../../directives/click-outside';
  10. // Utilities
  11. import { addOnceEventListener, convertToUnit, createRange, keyCodes, deepEqual } from '../../util/helpers';
  12. import { consoleWarn } from '../../util/console';
  13. import Loadable from '../../mixins/loadable';
  14. /* @vue/component */
  15. export default VInput.extend({
  16. name: 'v-slider',
  17. directives: { ClickOutside: ClickOutside },
  18. mixins: [Loadable],
  19. props: {
  20. alwaysDirty: Boolean,
  21. inverseLabel: Boolean,
  22. label: String,
  23. min: {
  24. type: [Number, String],
  25. default: 0
  26. },
  27. max: {
  28. type: [Number, String],
  29. default: 100
  30. },
  31. step: {
  32. type: [Number, String],
  33. default: 1
  34. },
  35. ticks: {
  36. type: [Boolean, String],
  37. default: false,
  38. validator: function validator(v) {
  39. return typeof v === 'boolean' || v === 'always';
  40. }
  41. },
  42. tickLabels: {
  43. type: Array,
  44. default: function _default() {
  45. return [];
  46. }
  47. },
  48. tickSize: {
  49. type: [Number, String],
  50. default: 1
  51. },
  52. thumbColor: {
  53. type: String,
  54. default: null
  55. },
  56. thumbLabel: {
  57. type: [Boolean, String],
  58. default: null,
  59. validator: function validator(v) {
  60. return typeof v === 'boolean' || v === 'always';
  61. }
  62. },
  63. thumbSize: {
  64. type: [Number, String],
  65. default: 32
  66. },
  67. trackColor: {
  68. type: String,
  69. default: null
  70. },
  71. value: [Number, String]
  72. },
  73. data: function data(vm) {
  74. return {
  75. app: {},
  76. isActive: false,
  77. keyPressed: 0,
  78. lazyValue: typeof vm.value !== 'undefined' ? vm.value : Number(vm.min),
  79. oldValue: null
  80. };
  81. },
  82. computed: {
  83. classes: function classes() {
  84. return {
  85. 'v-input--slider': true,
  86. 'v-input--slider--ticks': this.showTicks,
  87. 'v-input--slider--inverse-label': this.inverseLabel,
  88. 'v-input--slider--ticks-labels': this.tickLabels.length > 0,
  89. 'v-input--slider--thumb-label': this.thumbLabel || this.$scopedSlots.thumbLabel
  90. };
  91. },
  92. showTicks: function showTicks() {
  93. return this.tickLabels.length > 0 || !this.disabled && this.stepNumeric && !!this.ticks;
  94. },
  95. showThumbLabel: function showThumbLabel() {
  96. return !this.disabled && (!!this.thumbLabel || this.thumbLabel === '' || this.$scopedSlots['thumb-label']);
  97. },
  98. computedColor: function computedColor() {
  99. if (this.disabled) return null;
  100. return this.validationState || this.color || 'primary';
  101. },
  102. computedTrackColor: function computedTrackColor() {
  103. return this.disabled ? null : this.trackColor || null;
  104. },
  105. computedThumbColor: function computedThumbColor() {
  106. if (this.disabled || !this.isDirty) return null;
  107. return this.validationState || this.thumbColor || this.color || 'primary';
  108. },
  109. internalValue: {
  110. get: function get() {
  111. return this.lazyValue;
  112. },
  113. set: function set(val) {
  114. var min = this.min,
  115. max = this.max;
  116. // Round value to ensure the
  117. // entire slider range can
  118. // be selected with step
  119. var value = this.roundValue(Math.min(Math.max(val, min), max));
  120. if (value === this.lazyValue) return;
  121. this.lazyValue = value;
  122. this.$emit('input', value);
  123. this.validate();
  124. }
  125. },
  126. stepNumeric: function stepNumeric() {
  127. return this.step > 0 ? parseFloat(this.step) : 0;
  128. },
  129. trackFillStyles: function trackFillStyles() {
  130. var left = this.$vuetify.rtl ? 'auto' : 0;
  131. var right = this.$vuetify.rtl ? 0 : 'auto';
  132. var width = this.inputWidth + '%';
  133. if (this.disabled) width = 'calc(' + this.inputWidth + '% - 8px)';
  134. return {
  135. transition: this.trackTransition,
  136. left: left,
  137. right: right,
  138. width: width
  139. };
  140. },
  141. trackPadding: function trackPadding() {
  142. return this.isActive || this.inputWidth > 0 || this.disabled ? 0 : 7;
  143. },
  144. trackStyles: function trackStyles() {
  145. var trackPadding = this.disabled ? 'calc(' + this.inputWidth + '% + 8px)' : this.trackPadding + 'px';
  146. var left = this.$vuetify.rtl ? 'auto' : trackPadding;
  147. var right = this.$vuetify.rtl ? trackPadding : 'auto';
  148. var width = this.disabled ? 'calc(' + (100 - this.inputWidth) + '% - 8px)' : '100%';
  149. return {
  150. transition: this.trackTransition,
  151. left: left,
  152. right: right,
  153. width: width
  154. };
  155. },
  156. tickStyles: function tickStyles() {
  157. var size = Number(this.tickSize);
  158. return {
  159. 'border-width': size + 'px',
  160. 'border-radius': size > 1 ? '50%' : null,
  161. transform: size > 1 ? 'translateX(-' + size + 'px) translateY(-' + (size - 1) + 'px)' : null
  162. };
  163. },
  164. trackTransition: function trackTransition() {
  165. return this.keyPressed >= 2 ? 'none' : '';
  166. },
  167. numTicks: function numTicks() {
  168. return Math.ceil((this.max - this.min) / this.stepNumeric);
  169. },
  170. inputWidth: function inputWidth() {
  171. return (this.roundValue(this.internalValue) - this.min) / (this.max - this.min) * 100;
  172. },
  173. isDirty: function isDirty() {
  174. return this.internalValue > this.min || this.alwaysDirty;
  175. }
  176. },
  177. watch: {
  178. min: function min(val) {
  179. val > this.internalValue && this.$emit('input', parseFloat(val));
  180. },
  181. max: function max(val) {
  182. val < this.internalValue && this.$emit('input', parseFloat(val));
  183. },
  184. value: function value(val) {
  185. this.internalValue = val;
  186. }
  187. },
  188. mounted: function mounted() {
  189. // Without a v-app, iOS does not work with body selectors
  190. this.app = document.querySelector('[data-app]') || consoleWarn('Missing v-app or a non-body wrapping element with the [data-app] attribute', this);
  191. },
  192. methods: {
  193. genDefaultSlot: function genDefaultSlot() {
  194. var children = [this.genLabel()];
  195. var slider = this.genSlider();
  196. this.inverseLabel ? children.unshift(slider) : children.push(slider);
  197. children.push(this.genProgress());
  198. return children;
  199. },
  200. genListeners: function genListeners() {
  201. return {
  202. blur: this.onBlur,
  203. click: this.onSliderClick,
  204. focus: this.onFocus,
  205. keydown: this.onKeyDown,
  206. keyup: this.onKeyUp
  207. };
  208. },
  209. genInput: function genInput() {
  210. return this.$createElement('input', {
  211. attrs: _extends({
  212. 'aria-label': this.label,
  213. name: this.name,
  214. role: 'slider',
  215. tabindex: this.disabled ? -1 : this.$attrs.tabindex,
  216. value: this.internalValue,
  217. readonly: true,
  218. 'aria-readonly': String(this.readonly),
  219. 'aria-valuemin': this.min,
  220. 'aria-valuemax': this.max,
  221. 'aria-valuenow': this.internalValue
  222. }, this.$attrs),
  223. on: this.genListeners(),
  224. ref: 'input'
  225. });
  226. },
  227. genSlider: function genSlider() {
  228. return this.$createElement('div', {
  229. staticClass: 'v-slider',
  230. 'class': {
  231. 'v-slider--is-active': this.isActive
  232. },
  233. directives: [{
  234. name: 'click-outside',
  235. value: this.onBlur
  236. }]
  237. }, this.genChildren());
  238. },
  239. genChildren: function genChildren() {
  240. return [this.genInput(), this.genTrackContainer(), this.genSteps(), this.genThumbContainer(this.internalValue, this.inputWidth, this.isFocused || this.isActive, this.onThumbMouseDown)];
  241. },
  242. genSteps: function genSteps() {
  243. var _this = this;
  244. if (!this.step || !this.showTicks) return null;
  245. var ticks = createRange(this.numTicks + 1).map(function (i) {
  246. var children = [];
  247. if (_this.tickLabels[i]) {
  248. children.push(_this.$createElement('span', _this.tickLabels[i]));
  249. }
  250. return _this.$createElement('span', {
  251. key: i,
  252. staticClass: 'v-slider__ticks',
  253. class: {
  254. 'v-slider__ticks--always-show': _this.ticks === 'always' || _this.tickLabels.length > 0
  255. },
  256. style: _extends({}, _this.tickStyles, {
  257. left: i * (100 / _this.numTicks) + '%'
  258. })
  259. }, children);
  260. });
  261. return this.$createElement('div', {
  262. staticClass: 'v-slider__ticks-container'
  263. }, ticks);
  264. },
  265. genThumb: function genThumb() {
  266. return this.$createElement('div', this.setBackgroundColor(this.computedThumbColor, {
  267. staticClass: 'v-slider__thumb'
  268. }));
  269. },
  270. genThumbContainer: function genThumbContainer(value, valueWidth, isActive, onDrag) {
  271. var children = [this.genThumb()];
  272. var thumbLabelContent = this.getLabel(value);
  273. this.showThumbLabel && children.push(this.genThumbLabel(thumbLabelContent));
  274. return this.$createElement('div', this.setTextColor(this.computedThumbColor, {
  275. staticClass: 'v-slider__thumb-container',
  276. 'class': {
  277. 'v-slider__thumb-container--is-active': isActive,
  278. 'v-slider__thumb-container--show-label': this.showThumbLabel
  279. },
  280. style: {
  281. transition: this.trackTransition,
  282. left: (this.$vuetify.rtl ? 100 - valueWidth : valueWidth) + '%'
  283. },
  284. on: {
  285. touchstart: onDrag,
  286. mousedown: onDrag
  287. }
  288. }), children);
  289. },
  290. genThumbLabel: function genThumbLabel(content) {
  291. var size = convertToUnit(this.thumbSize);
  292. return this.$createElement(VScaleTransition, {
  293. props: { origin: 'bottom center' }
  294. }, [this.$createElement('div', {
  295. staticClass: 'v-slider__thumb-label__container',
  296. directives: [{
  297. name: 'show',
  298. value: this.isFocused || this.isActive || this.thumbLabel === 'always'
  299. }]
  300. }, [this.$createElement('div', this.setBackgroundColor(this.computedThumbColor, {
  301. staticClass: 'v-slider__thumb-label',
  302. style: {
  303. height: size,
  304. width: size
  305. }
  306. }), [content])])]);
  307. },
  308. genTrackContainer: function genTrackContainer() {
  309. var children = [this.$createElement('div', this.setBackgroundColor(this.computedTrackColor, {
  310. staticClass: 'v-slider__track',
  311. style: this.trackStyles
  312. })), this.$createElement('div', this.setBackgroundColor(this.computedColor, {
  313. staticClass: 'v-slider__track-fill',
  314. style: this.trackFillStyles
  315. }))];
  316. return this.$createElement('div', {
  317. staticClass: 'v-slider__track__container',
  318. ref: 'track'
  319. }, children);
  320. },
  321. getLabel: function getLabel(value) {
  322. return this.$scopedSlots['thumb-label'] ? this.$scopedSlots['thumb-label']({ value: value }) : this.$createElement('span', value);
  323. },
  324. onBlur: function onBlur(e) {
  325. if (this.keyPressed === 2) return;
  326. this.isActive = false;
  327. this.isFocused = false;
  328. this.$emit('blur', e);
  329. },
  330. onFocus: function onFocus(e) {
  331. this.isFocused = true;
  332. this.$emit('focus', e);
  333. },
  334. onThumbMouseDown: function onThumbMouseDown(e) {
  335. this.oldValue = this.internalValue;
  336. this.keyPressed = 2;
  337. var options = { passive: true };
  338. this.isActive = true;
  339. this.isFocused = false;
  340. if ('touches' in e) {
  341. this.app.addEventListener('touchmove', this.onMouseMove, options);
  342. addOnceEventListener(this.app, 'touchend', this.onSliderMouseUp);
  343. } else {
  344. this.app.addEventListener('mousemove', this.onMouseMove, options);
  345. addOnceEventListener(this.app, 'mouseup', this.onSliderMouseUp);
  346. }
  347. this.$emit('start', this.internalValue);
  348. },
  349. onSliderMouseUp: function onSliderMouseUp() {
  350. this.keyPressed = 0;
  351. var options = { passive: true };
  352. this.isActive = false;
  353. this.isFocused = false;
  354. this.app.removeEventListener('touchmove', this.onMouseMove, options);
  355. this.app.removeEventListener('mousemove', this.onMouseMove, options);
  356. this.$emit('end', this.internalValue);
  357. if (!deepEqual(this.oldValue, this.internalValue)) {
  358. this.$emit('change', this.internalValue);
  359. }
  360. },
  361. onMouseMove: function onMouseMove(e) {
  362. var _parseMouseMove = this.parseMouseMove(e),
  363. value = _parseMouseMove.value,
  364. isInsideTrack = _parseMouseMove.isInsideTrack;
  365. if (isInsideTrack) {
  366. this.setInternalValue(value);
  367. }
  368. },
  369. onKeyDown: function onKeyDown(e) {
  370. if (this.disabled || this.readonly) return;
  371. var value = this.parseKeyDown(e);
  372. if (value == null) return;
  373. this.setInternalValue(value);
  374. this.$emit('change', value);
  375. },
  376. onKeyUp: function onKeyUp() {
  377. this.keyPressed = 0;
  378. },
  379. onSliderClick: function onSliderClick(e) {
  380. this.isFocused = true;
  381. this.onMouseMove(e);
  382. this.$emit('change', this.internalValue);
  383. },
  384. parseMouseMove: function parseMouseMove(e) {
  385. var _$refs$track$getBound = this.$refs.track.getBoundingClientRect(),
  386. offsetLeft = _$refs$track$getBound.left,
  387. trackWidth = _$refs$track$getBound.width;
  388. var clientX = 'touches' in e ? e.touches[0].clientX : e.clientX;
  389. // It is possible for left to be NaN, force to number
  390. var left = Math.min(Math.max((clientX - offsetLeft) / trackWidth, 0), 1) || 0;
  391. if (this.$vuetify.rtl) left = 1 - left;
  392. var isInsideTrack = clientX >= offsetLeft - 8 && clientX <= offsetLeft + trackWidth + 8;
  393. var value = parseFloat(this.min) + left * (this.max - this.min);
  394. return { value: value, isInsideTrack: isInsideTrack };
  395. },
  396. parseKeyDown: function parseKeyDown(e) {
  397. var value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.internalValue;
  398. if (this.disabled) return;
  399. var pageup = keyCodes.pageup,
  400. pagedown = keyCodes.pagedown,
  401. end = keyCodes.end,
  402. home = keyCodes.home,
  403. left = keyCodes.left,
  404. right = keyCodes.right,
  405. down = keyCodes.down,
  406. up = keyCodes.up;
  407. if (![pageup, pagedown, end, home, left, right, down, up].includes(e.keyCode)) return;
  408. e.preventDefault();
  409. var step = this.stepNumeric || 1;
  410. var steps = (this.max - this.min) / step;
  411. if ([left, right, down, up].includes(e.keyCode)) {
  412. this.keyPressed += 1;
  413. var increase = this.$vuetify.rtl ? [left, up] : [right, up];
  414. var direction = increase.includes(e.keyCode) ? 1 : -1;
  415. var multiplier = e.shiftKey ? 3 : e.ctrlKey ? 2 : 1;
  416. value = value + direction * step * multiplier;
  417. } else if (e.keyCode === home) {
  418. value = parseFloat(this.min);
  419. } else if (e.keyCode === end) {
  420. value = parseFloat(this.max);
  421. } else /* if (e.keyCode === keyCodes.pageup || e.keyCode === pagedown) */{
  422. // Page up/down
  423. var _direction = e.keyCode === pagedown ? 1 : -1;
  424. value = value - _direction * step * (steps > 100 ? steps / 10 : 10);
  425. }
  426. return value;
  427. },
  428. roundValue: function roundValue(value) {
  429. if (!this.stepNumeric) return value;
  430. // Format input value using the same number
  431. // of decimals places as in the step prop
  432. var trimmedStep = this.step.toString().trim();
  433. var decimals = trimmedStep.indexOf('.') > -1 ? trimmedStep.length - trimmedStep.indexOf('.') - 1 : 0;
  434. var offset = this.min % this.stepNumeric;
  435. var newValue = Math.round((value - offset) / this.stepNumeric) * this.stepNumeric + offset;
  436. return parseFloat(Math.max(Math.min(newValue, this.max), this.min).toFixed(decimals));
  437. },
  438. setInternalValue: function setInternalValue(value) {
  439. this.internalValue = value;
  440. }
  441. }
  442. });
  443. //# sourceMappingURL=VSlider.js.map