@twab/visualization 1.9.3 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/visualization.js +453 -96
  2. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  import VTooltip from 'v-tooltip';
2
2
  import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
3
3
  import { library } from '@fortawesome/fontawesome-svg-core';
4
- import { faBackward, faStepBackward, faClock, faStepForward, faForward, faPlay, faStop, faBorderAll, faSlidersH, faCut, faHourglassStart, faHourglassEnd, faVideo, faInfoCircle, faTachometerAlt, faServer, faEye, faEyeSlash, faBan, faSync, faArrowTurnDown, faArrowCircleDown, faPause, faArrowsLeftRightToLine, faExclamationTriangle, faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
4
+ import { faBackward, faStepBackward, faClock, faStepForward, faForward, faPlay, faStop, faBorderAll, faSlidersH, faCut, faHourglassStart, faHourglassEnd, faVideo, faInfoCircle, faTachometerAlt, faServer, faEye, faEyeSlash, faBan, faSync, faArrowTurnDown, faArrowCircleDown, faPause, faArrowsLeftRightToLine, faExclamationTriangle, faExclamationCircle, faMaximize, faMinimize } from '@fortawesome/free-solid-svg-icons';
5
5
  import VueMask from 'v-mask';
6
6
  import VueLoading from 'vue-loading-twa';
7
7
  import axios from 'axios';
@@ -110,7 +110,9 @@ function registerIcons () {
110
110
  faPause,
111
111
  faArrowsLeftRightToLine,
112
112
  faExclamationTriangle,
113
- faExclamationCircle
113
+ faExclamationCircle,
114
+ faMaximize,
115
+ faMinimize
114
116
  );
115
117
  }
116
118
 
@@ -229,6 +231,10 @@ var script$5 = {
229
231
  type: Number,
230
232
  default: 11 / 9,
231
233
  },
234
+ stretchFrame: {
235
+ type: Boolean,
236
+ default: false,
237
+ },
232
238
  },
233
239
  data() {
234
240
  return {
@@ -336,20 +342,22 @@ var script$5 = {
336
342
  (this.fullMaxWidth - this.gridSettings.framesPerRow * 10) /
337
343
  this.gridSettings.framesPerRow;
338
344
 
345
+ const rowSpacing = 29 * this.gridSettings.numberOfRows;
346
+
339
347
  let heightAvailable =
340
348
  height -
341
349
  (commandBarSize?.offsetHeight || 0) -
342
350
  infoBarSize?.offsetHeight -
343
- 29 * this.gridSettings.numberOfRows;
351
+ rowSpacing -
352
+ 2; // bottom padding
353
+
344
354
  if (this.gridSettings.numberOfRows > 1) {
345
355
  heightAvailable += 12;
346
356
  }
347
357
 
348
- this.maxHeight =
349
- this.gridSettings.numberOfRows === 2
350
- ? (heightAvailable - 12) / 2
351
- : heightAvailable;
352
- this.maxHeight = this.maxHeight >= 75 ? this.maxHeight : 75;
358
+ this.maxHeight = heightAvailable / this.gridSettings.numberOfRows;
359
+ const minHeightPerRow = this.gridSettings.numberOfRows > 2 ? 50 : 60;
360
+ this.maxHeight = Math.max(this.maxHeight, minHeightPerRow);
353
361
 
354
362
  if (this.maxWidth / this.aspectRatio > this.maxHeight) {
355
363
  this.height = this.maxHeight;
@@ -358,9 +366,24 @@ var script$5 = {
358
366
  this.width = this.maxWidth;
359
367
  this.height = this.maxWidth / this.aspectRatio;
360
368
  }
361
-
369
+ this.applyImageStyles();
362
370
  this.maxHeight = this.height;
363
371
  },
372
+ applyImageStyles() {
373
+ this.$nextTick(() => {
374
+ const frameImages = this.$el.querySelectorAll(
375
+ '.frame-container img, .dummy-frame img'
376
+ );
377
+
378
+ frameImages.forEach((img) => {
379
+ img.style.width = '100%';
380
+ img.style.height = '100%';
381
+ img.style.objectFit = 'fill';
382
+ img.style.aspectRatio = 'auto';
383
+ img.style.display = 'block';
384
+ });
385
+ });
386
+ },
364
387
  async playOrPause() {
365
388
  switch (this.videoStatus) {
366
389
  case Status.stopped:
@@ -704,65 +727,83 @@ var __vue_render__$5 = function () {
704
727
  },
705
728
  }),
706
729
  _vm._v(" "),
707
- _c("div", { staticStyle: { "background-color": "black" } }, [
708
- !_vm.isLoading
709
- ? _c(
710
- "div",
711
- {
712
- class: {
713
- "frame-content":
714
- _vm.frame.title === -1 ||
715
- _vm.videoStatus !== _vm.Status.stopped,
716
- },
717
- style: {
718
- minHeight: _vm.height + "px",
719
- minWidth: _vm.width + "px",
720
- maxHeight: _vm.height + "px",
721
- maxWidth: _vm.width + "px",
722
- color: "white",
723
- },
724
- on: { dblclick: _vm.playOrPause },
725
- },
726
- [
727
- _vm.frame.image && _vm.videoStatus === _vm.Status.stopped
728
- ? _c("div", {
729
- class: { "dummy-frame": _vm.frame.title === -1 },
730
- staticStyle: { width: "100%", height: "100%" },
731
- domProps: { innerHTML: _vm._s(_vm.frame.image) },
732
- })
733
- : _vm._e(),
734
- _vm._v(" "),
735
- !_vm.videoOnModal &&
736
- _vm.videoStatus !== _vm.Status.stopped &&
737
- !_vm.videoIsLoading
738
- ? _c("video", {
739
- ref: "videoPlayer",
740
- style: {
730
+ _c(
731
+ "div",
732
+ {
733
+ style: {
734
+ backgroundColor: "black",
735
+ width: _vm.stretchFrame ? "100%" : "auto",
736
+ height: _vm.stretchFrame ? "100%" : "auto",
737
+ },
738
+ },
739
+ [
740
+ !_vm.isLoading
741
+ ? _c(
742
+ "div",
743
+ {
744
+ class: {
745
+ "frame-content":
746
+ _vm.frame.title === -1 ||
747
+ _vm.videoStatus !== _vm.Status.stopped,
748
+ },
749
+ style: _vm.stretchFrame
750
+ ? {
751
+ height: _vm.maxHeight + "px",
741
752
  width: "100%",
742
- aspectRatio: _vm.aspectRatioFrac,
743
- },
744
- attrs: {
753
+ color: "white",
754
+ }
755
+ : {
756
+ minHeight: _vm.height + "px",
757
+ minWidth: _vm.width + "px",
745
758
  maxHeight: _vm.height + "px",
746
759
  maxWidth: _vm.width + "px",
747
- src: _vm.videoUrlString,
760
+ color: "white",
748
761
  },
749
- on: {
750
- timeupdate: _vm.updateTimeLabel,
751
- ended: _vm.videoEnded,
752
- click: _vm.playOrPause,
753
- canplay: _vm.canPlay,
754
- error: function () {
755
- return _vm.stop(false)
762
+ on: { dblclick: _vm.playOrPause },
763
+ },
764
+ [
765
+ _vm.frame.image && _vm.videoStatus === _vm.Status.stopped
766
+ ? _c("div", {
767
+ class: { "dummy-frame": _vm.frame.title === -1 },
768
+ staticStyle: { width: "100%", height: "100%" },
769
+ domProps: { innerHTML: _vm._s(_vm.frame.image) },
770
+ })
771
+ : _vm._e(),
772
+ _vm._v(" "),
773
+ !_vm.videoOnModal &&
774
+ _vm.videoStatus !== _vm.Status.stopped &&
775
+ !_vm.videoIsLoading
776
+ ? _c("video", {
777
+ ref: "videoPlayer",
778
+ style: {
779
+ width: "100%",
780
+ aspectRatio: _vm.aspectRatioFrac,
756
781
  },
757
- },
758
- })
759
- : _vm._e(),
760
- _vm._v(" "),
761
- !_vm.loading ? _c("div", { staticClass: "overlay" }) : _vm._e(),
762
- ]
763
- )
764
- : _vm._e(),
765
- ]),
782
+ attrs: {
783
+ maxHeight: _vm.height + "px",
784
+ maxWidth: _vm.width + "px",
785
+ src: _vm.videoUrlString,
786
+ },
787
+ on: {
788
+ timeupdate: _vm.updateTimeLabel,
789
+ ended: _vm.videoEnded,
790
+ click: _vm.playOrPause,
791
+ canplay: _vm.canPlay,
792
+ error: function () {
793
+ return _vm.stop(false)
794
+ },
795
+ },
796
+ })
797
+ : _vm._e(),
798
+ _vm._v(" "),
799
+ !_vm.loading
800
+ ? _c("div", { staticClass: "overlay" })
801
+ : _vm._e(),
802
+ ]
803
+ )
804
+ : _vm._e(),
805
+ ]
806
+ ),
766
807
  _vm._v(" "),
767
808
  _c(
768
809
  "dialog",
@@ -817,11 +858,11 @@ __vue_render__$5._withStripped = true;
817
858
  /* style */
818
859
  const __vue_inject_styles__$5 = function (inject) {
819
860
  if (!inject) return
820
- inject("data-v-75056fcc_0", { source: "\n.frame-container > div[data-v-75056fcc] {\r\n max-height: 100%;\n}\n.frame-container[data-v-75056fcc] {\r\n background-color: black;\r\n display: flex;\r\n justify-content: center;\n}\n.frame-content[data-v-75056fcc],\r\n.dummy-frame[data-v-75056fcc] {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\n}\n.frame-content video[data-v-75056fcc] {\r\n flex-grow: 1;\r\n object-fit: fill;\r\n z-index: 0;\n}\n.overlay[data-v-75056fcc] {\r\n width: 100%;\r\n height: 100%;\r\n z-index: 5;\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n border: 4px solid transparent;\r\n pointer-events: none;\n}\n.active .overlay[data-v-75056fcc] {\r\n border-color: var(--visualization-primary);\n}\n.between-time .overlay[data-v-75056fcc] {\r\n border-top-color: var(--visualization-secondary);\n}\n.between-time.active .overlay[data-v-75056fcc] {\r\n border-color: var(--visualization-secondary);\n}\n.initial-time .overlay[data-v-75056fcc] {\r\n border-top-color: var(--visualization-start);\n}\n.initial-time.active .overlay[data-v-75056fcc] {\r\n border-color: var(--visualization-start);\n}\n.end-time .overlay[data-v-75056fcc] {\r\n border-top-color: var(--visualization-end);\n}\n.end-time.active .overlay[data-v-75056fcc] {\r\n border-color: var(--visualization-end);\n}\n.initial-time.end-time .overlay[data-v-75056fcc] {\r\n border-top-color: var(--visualization-start);\r\n border-bottom-color: var(--visualization-end);\n}\n.initial-time.end-time.active .overlay[data-v-75056fcc] {\r\n border-top-color: var(--visualization-start);\r\n border-left-color: var(--visualization-start);\r\n border-bottom-color: var(--visualization-end);\r\n border-right-color: var(--visualization-end);\n}\n.div-frame[data-v-75056fcc] img {\r\n width: 90vh !important;\n}\r\n", map: {"version":3,"sources":["C:\\Workspace\\visualization\\src\\components\\Frame.vue"],"names":[],"mappings":";AA8aA;EACA,gBAAA;AACA;AACA;EACA,uBAAA;EACA,aAAA;EACA,uBAAA;AACA;AACA;;EAEA,aAAA;EACA,mBAAA;EACA,uBAAA;AACA;AACA;EACA,YAAA;EACA,gBAAA;EACA,UAAA;AACA;AACA;EACA,WAAA;EACA,YAAA;EACA,UAAA;EACA,kBAAA;EACA,MAAA;EACA,OAAA;EACA,6BAAA;EACA,oBAAA;AACA;AACA;EACA,0CAAA;AACA;AACA;EACA,gDAAA;AACA;AACA;EACA,4CAAA;AACA;AACA;EACA,4CAAA;AACA;AACA;EACA,wCAAA;AACA;AACA;EACA,0CAAA;AACA;AACA;EACA,sCAAA;AACA;AACA;EACA,4CAAA;EACA,6CAAA;AACA;AACA;EACA,4CAAA;EACA,6CAAA;EACA,6CAAA;EACA,4CAAA;AACA;AACA;EACA,sBAAA;AACA","file":"Frame.vue","sourcesContent":["<template>\r\n <div\r\n :style=\"{\r\n maxHeight: `${maxHeight}px`,\r\n width: '100%',\r\n position: 'relative',\r\n }\"\r\n :class=\"{\r\n 'frame-container': true,\r\n 'initial-time': initialTime,\r\n 'end-time': endTime,\r\n 'between-time': betweenTime,\r\n active: active,\r\n }\"\r\n >\r\n <GlobalEvents\r\n v-if=\"active && activeTab && parentComponent.settingsClosed\"\r\n @keydown.32.prevent=\"playOrPause\"\r\n @keydown.27.prevent=\"stop\"\r\n @keydown.79=\"toogleDetailFrame\"\r\n @keydown.13.prevent=\"jumpFrameToStart\"\r\n />\r\n <GlobalEvents\r\n v-if=\"showFrame\"\r\n @keydown.27.prevent=\"toogleDetailFrame\"\r\n @keydown.13.prevent=\"toogleDetailFrame\"\r\n />\r\n\r\n <vue-loading\r\n :active=\"isLoading\"\r\n spinner=\"ring\"\r\n color=\"var(--visualization-primary)\"\r\n background-color=\"#cacaca\"\r\n :style=\"{\r\n 'z-index': 0,\r\n minHeight: `${height}px`,\r\n minWidth: `${width}px`,\r\n }\"\r\n :text=\"videoIsLoading ? $t('infoBar.createVideo') : ''\"\r\n />\r\n <div style=\"background-color: black\">\r\n <div\r\n v-if=\"!isLoading\"\r\n :class=\"{\r\n 'frame-content': frame.title === -1 || videoStatus !== Status.stopped,\r\n }\"\r\n :style=\"{\r\n minHeight: `${height}px`,\r\n minWidth: `${width}px`,\r\n maxHeight: `${height}px`,\r\n maxWidth: `${width}px`,\r\n color: 'white',\r\n }\"\r\n @dblclick=\"playOrPause\"\r\n >\r\n <div\r\n v-if=\"frame.image && videoStatus === Status.stopped\"\r\n :class=\"{ 'dummy-frame': frame.title === -1 }\"\r\n v-html=\"frame.image\"\r\n style=\"width: 100%; height: 100%\"\r\n />\r\n <video\r\n v-if=\"\r\n !videoOnModal && videoStatus !== Status.stopped && !videoIsLoading\r\n \"\r\n ref=\"videoPlayer\"\r\n :maxHeight=\"`${height}px`\"\r\n :maxWidth=\"`${width}px`\"\r\n :src=\"videoUrlString\"\r\n @timeupdate=\"updateTimeLabel\"\r\n @ended=\"videoEnded\"\r\n @click=\"playOrPause\"\r\n @canplay=\"canPlay\"\r\n @error=\"() => stop(false)\"\r\n :style=\"{ width: '100%', aspectRatio: aspectRatioFrac }\"\r\n ></video>\r\n <div v-if=\"!loading\" class=\"overlay\"></div>\r\n </div>\r\n </div>\r\n\r\n <dialog\r\n ref=\"imageDetailsDialog\"\r\n style=\"\r\n top: 50%;\r\n left: 50%;\r\n transform: translateY(-50%) translateX(-50%);\r\n border: none;\r\n background: grey;\r\n width: 60%;\r\n \"\r\n >\r\n <div\r\n v-if=\"videoStatus == Status.stopped\"\r\n style=\"justify-content: center; display: flex\"\r\n :class=\"{\r\n 'dummy-frame': frame.title === -1,\r\n 'div-frame': frame.title !== -1,\r\n }\"\r\n v-html=\"frame.image\"\r\n @dblclick=\"changeToVideo\"\r\n ></div>\r\n <video\r\n v-if=\"videoOnModal && videoStatus !== Status.stopped && !videoIsLoading\"\r\n ref=\"videoPlayer\"\r\n :src=\"videoUrlString\"\r\n autoplay\r\n @ended=\"videoEnded\"\r\n style=\"width: 100%; aspect-ratio: 11/9\"\r\n controls=\"true\"\r\n width=\"200%\"\r\n ></video>\r\n </dialog>\r\n </div>\r\n</template>\r\n<script>\r\nimport VueLoading from 'vue-loading-twa'\r\n\r\nconst Status = Object.freeze({\r\n stopped: 0,\r\n playing: 1,\r\n paused: 2,\r\n})\r\n\r\nexport default {\r\n components: {\r\n VueLoading,\r\n },\r\n name: 'frame-component',\r\n props: {\r\n frame: {\r\n type: [Object, Number],\r\n required: true,\r\n },\r\n index: {\r\n type: Number,\r\n required: true,\r\n },\r\n loading: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n gridSettings: {\r\n type: Object,\r\n required: true,\r\n },\r\n initialTime: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n endTime: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n betweenTime: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n active: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n activeTab: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n videoUrl: {\r\n type: [String, Promise],\r\n required: true,\r\n },\r\n playbackRate: {\r\n type: Number,\r\n default: 1,\r\n },\r\n videoControls: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n aspectRatio: {\r\n type: Number,\r\n default: 11 / 9,\r\n },\r\n },\r\n data() {\r\n return {\r\n Status,\r\n width: 0,\r\n height: 0,\r\n maxWidth: 0,\r\n fullMaxWidth: 0,\r\n maxHeight: 0,\r\n showFrame: false,\r\n videoStatus: Status.stopped,\r\n videoStartTime: null,\r\n videoCurrentTime: null,\r\n videoUrlString: '',\r\n parentComponent: null,\r\n videoIsLoading: false,\r\n currentBlock: null,\r\n lastTimeEnterPressed: null,\r\n videoOnModal: false,\r\n }\r\n },\r\n created() {\r\n this.parentComponent = this.$parent\r\n },\r\n watch: {\r\n playbackRate(val) {\r\n if (\r\n this.videoStatus === Status.playing ||\r\n this.videoStatus === Status.paused\r\n ) {\r\n this.$refs.videoPlayer.playbackRate = val\r\n }\r\n },\r\n },\r\n computed: {\r\n isLoading() {\r\n return (\r\n ((!this.frame.image || !this.frame.time) && this.frame.title !== -1) ||\r\n this.loading ||\r\n this.videoIsLoading\r\n )\r\n },\r\n aspectRatioFrac() {\r\n var gcd = function (a, b) {\r\n if (b < 0.0000001) return a\r\n\r\n return gcd(b, Math.floor(a % b))\r\n }\r\n\r\n var denominator = Math.pow(10, this.aspectRatio.toString().length - 2)\r\n var numerator = this.aspectRatio * denominator\r\n\r\n var divisor = gcd(numerator, denominator)\r\n\r\n return `${Math.floor(numerator / divisor)}/${Math.floor(\r\n denominator / divisor\r\n )}`\r\n },\r\n },\r\n methods: {\r\n canPlay() {\r\n this.$refs.videoPlayer.play()\r\n },\r\n changeToVideo() {\r\n this.videoOnModal = true\r\n this.playOrPause()\r\n },\r\n jumpFrameToStart() {\r\n if (this.active) {\r\n const currentTime = new Date().getTime()\r\n\r\n if (currentTime - this.lastTimeEnterPressed <= 500) {\r\n this.parentComponent.changeHour(\r\n this.parentComponent.convertToAudienceTime(this.frame.time)\r\n )\r\n }\r\n\r\n this.lastTimeEnterPressed = currentTime\r\n }\r\n },\r\n changeSettings(value) {\r\n this.videoCurrentTime = value\r\n },\r\n toogleDetailFrame() {\r\n this.stop()\r\n if (this.showFrame) {\r\n this.videoOnModal = false\r\n this.$refs.imageDetailsDialog.close()\r\n } else {\r\n this.$refs.imageDetailsDialog.showModal()\r\n }\r\n this.showFrame = !this.showFrame\r\n },\r\n getMaxWidth() {\r\n const commandBarSize = document.getElementById('command-bar')\r\n\r\n return commandBarSize?.clientWidth\r\n },\r\n resize(height) {\r\n const commandBarSize = document.getElementById('command-bar')\r\n const infoBarSize = document.getElementById('info-bar')\r\n\r\n this.fullMaxWidth = infoBarSize?.clientWidth\r\n this.maxWidth =\r\n (this.fullMaxWidth - this.gridSettings.framesPerRow * 10) /\r\n this.gridSettings.framesPerRow\r\n\r\n let heightAvailable =\r\n height -\r\n (commandBarSize?.offsetHeight || 0) -\r\n infoBarSize?.offsetHeight -\r\n 29 * this.gridSettings.numberOfRows\r\n if (this.gridSettings.numberOfRows > 1) {\r\n heightAvailable += 12\r\n }\r\n\r\n this.maxHeight =\r\n this.gridSettings.numberOfRows === 2\r\n ? (heightAvailable - 12) / 2\r\n : heightAvailable\r\n this.maxHeight = this.maxHeight >= 75 ? this.maxHeight : 75\r\n\r\n if (this.maxWidth / this.aspectRatio > this.maxHeight) {\r\n this.height = this.maxHeight\r\n this.width = this.maxHeight * this.aspectRatio\r\n } else {\r\n this.width = this.maxWidth\r\n this.height = this.maxWidth / this.aspectRatio\r\n }\r\n\r\n this.maxHeight = this.height\r\n },\r\n async playOrPause() {\r\n switch (this.videoStatus) {\r\n case Status.stopped:\r\n this.videoIsLoading = true\r\n try {\r\n this.videoUrlString = await this.videoUrl\r\n const blockInfo =\r\n await this.parentComponent.fInterface?.getVideoStartTime(\r\n this.frame\r\n )\r\n\r\n this.videoStartTime = blockInfo.start\r\n this.videoUrlString =\r\n this.parentComponent.fInterface.getVideoRequestByUrl(\r\n blockInfo.url,\r\n this.frame.number + this.parentComponent.shiftFrames\r\n )\r\n } catch (error) {\r\n console.log(error)\r\n }\r\n this.videoIsLoading = false\r\n this.videoStatus = Status.playing\r\n this.$nextTick(() => {\r\n this.$refs.videoPlayer.onloaded = (e) => {\r\n this.$refs.videoPlayer.playbackRate = this.playbackRate\r\n // * atualizar slider\r\n this.$emit('updateSlider', this.videoStartTime, this.frame.time)\r\n //*\r\n this.$emit('startPlaying', this.frame, e.target.duration)\r\n this.$emit('playPauseStatus', true)\r\n }\r\n })\r\n break\r\n case Status.paused:\r\n this.$refs.videoPlayer.play()\r\n this.$refs.videoPlayer.playbackRate = this.playbackRate\r\n this.videoStatus = Status.playing\r\n this.$emit('playPauseStatus', true)\r\n break\r\n case Status.playing:\r\n this.$refs.videoPlayer.pause()\r\n\r\n this.videoStatus = Status.paused\r\n this.$emit('playPauseStatus', false)\r\n break\r\n }\r\n },\r\n stop(jump = true) {\r\n this.videoOnModal = false\r\n if (\r\n this.videoStatus === Status.playing ||\r\n this.videoStatus === Status.paused\r\n ) {\r\n if (jump) {\r\n this.parentComponent.changeHour(\r\n this.parentComponent.convertToAudienceTime(\r\n parseInt(this.videoCurrentTime)\r\n )\r\n )\r\n }\r\n this.videoStatus = Status.stopped\r\n this.videoUrlString = null\r\n this.videoCurrentTime = null\r\n this.videoStartTime = null\r\n }\r\n this.$emit('stopPlaying')\r\n },\r\n //eslint-disable-next-line\r\n videoJumpTo(time) {\r\n this.videoCurrentTime = this.videoStartTime + time\r\n this.$refs.videoPlayer.currentTime = time\r\n },\r\n async videoJumpToTimeStamp(time) {\r\n let frame = {\r\n time: time,\r\n }\r\n if (!time) return\r\n if (\r\n !(\r\n this.currentBlock &&\r\n time >= this.currentBlock.start &&\r\n time <= this.currentBlock.end\r\n )\r\n ) {\r\n this.currentBlock = await this.parentComponent.fInterface?.getBlockInfo(\r\n frame\r\n )\r\n this.videoStartTime = this.currentBlock.start\r\n this.videoUrlString =\r\n this.parentComponent.fInterface.getVideoUrlForTime(\r\n this.videoStartTime\r\n )\r\n }\r\n this.videoCurrentTime = time - this.videoStartTime\r\n this.$refs.videoPlayer.currentTime = this.videoCurrentTime\r\n },\r\n updateTimeLabel(e) {\r\n this.videoCurrentTime = this.videoStartTime + e.target.currentTime\r\n this.parentComponent.updateVideoTime(this.index, this.videoCurrentTime)\r\n this.parentComponent.updateVideoStatus(e.target.currentTime)\r\n },\r\n async videoEnded() {\r\n this.videoStartTime =\r\n await this.parentComponent.fInterface?.getNextVideoStartTime(\r\n this.frame.time - this.parentComponent.shiftFrames\r\n )\r\n this.videoUrlString = this.parentComponent.fInterface.getVideoUrlForTime(\r\n this.videoStartTime\r\n )\r\n // * Ao acabar o vídeo tenho de mandar atualizar slider\r\n // * aqui o video current time tambem vai ser o videoStartTime\r\n this.$emit('updateSlider', this.videoStartTime, this.videoStartTime)\r\n },\r\n },\r\n}\r\n</script>\r\n<style scoped>\r\n.frame-container > div {\r\n max-height: 100%;\r\n}\r\n.frame-container {\r\n background-color: black;\r\n display: flex;\r\n justify-content: center;\r\n}\r\n.frame-content,\r\n.dummy-frame {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n.frame-content video {\r\n flex-grow: 1;\r\n object-fit: fill;\r\n z-index: 0;\r\n}\r\n.overlay {\r\n width: 100%;\r\n height: 100%;\r\n z-index: 5;\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n border: 4px solid transparent;\r\n pointer-events: none;\r\n}\r\n.active .overlay {\r\n border-color: var(--visualization-primary);\r\n}\r\n.between-time .overlay {\r\n border-top-color: var(--visualization-secondary);\r\n}\r\n.between-time.active .overlay {\r\n border-color: var(--visualization-secondary);\r\n}\r\n.initial-time .overlay {\r\n border-top-color: var(--visualization-start);\r\n}\r\n.initial-time.active .overlay {\r\n border-color: var(--visualization-start);\r\n}\r\n.end-time .overlay {\r\n border-top-color: var(--visualization-end);\r\n}\r\n.end-time.active .overlay {\r\n border-color: var(--visualization-end);\r\n}\r\n.initial-time.end-time .overlay {\r\n border-top-color: var(--visualization-start);\r\n border-bottom-color: var(--visualization-end);\r\n}\r\n.initial-time.end-time.active .overlay {\r\n border-top-color: var(--visualization-start);\r\n border-left-color: var(--visualization-start);\r\n border-bottom-color: var(--visualization-end);\r\n border-right-color: var(--visualization-end);\r\n}\r\n.div-frame >>> img {\r\n width: 90vh !important;\r\n}\r\n</style>\r\n"]}, media: undefined });
861
+ inject("data-v-2297f9cd_0", { source: "\n.frame-container > div[data-v-2297f9cd] {\r\n max-height: 100%;\r\n height: 100%; /* Add this */\n}\n.frame-container[data-v-2297f9cd] {\r\n background-color: black;\r\n display: flex;\r\n justify-content: center;\n}\n.frame-content[data-v-2297f9cd],\r\n.dummy-frame[data-v-2297f9cd] {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\n}\n.frame-content video[data-v-2297f9cd] {\r\n flex-grow: 1;\r\n object-fit: fill;\r\n z-index: 0;\n}\n.overlay[data-v-2297f9cd] {\r\n width: 100%;\r\n height: 100%;\r\n z-index: 5;\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n border: 4px solid transparent;\r\n pointer-events: none;\n}\n.active .overlay[data-v-2297f9cd] {\r\n border-color: var(--visualization-primary);\n}\n.between-time .overlay[data-v-2297f9cd] {\r\n border-top-color: var(--visualization-secondary);\n}\n.between-time.active .overlay[data-v-2297f9cd] {\r\n border-color: var(--visualization-secondary);\n}\n.initial-time .overlay[data-v-2297f9cd] {\r\n border-top-color: var(--visualization-start);\n}\n.initial-time.active .overlay[data-v-2297f9cd] {\r\n border-color: var(--visualization-start);\n}\n.end-time .overlay[data-v-2297f9cd] {\r\n border-top-color: var(--visualization-end);\n}\n.end-time.active .overlay[data-v-2297f9cd] {\r\n border-color: var(--visualization-end);\n}\n.initial-time.end-time .overlay[data-v-2297f9cd] {\r\n border-top-color: var(--visualization-start);\r\n border-bottom-color: var(--visualization-end);\n}\n.initial-time.end-time.active .overlay[data-v-2297f9cd] {\r\n border-top-color: var(--visualization-start);\r\n border-left-color: var(--visualization-start);\r\n border-bottom-color: var(--visualization-end);\r\n border-right-color: var(--visualization-end);\n}\r\n\r\n/* new styles */\n.frame-content[data-v-2297f9cd] img,\r\n.dummy-frame[data-v-2297f9cd] img {\r\n width: 100% !important;\r\n height: 100% !important;\r\n object-fit: fill !important;\r\n aspect-ratio: auto !important;\r\n display: block !important;\n}\n.frame-content[data-v-2297f9cd] div,\r\n.dummy-frame[data-v-2297f9cd] div {\r\n width: 100% !important;\r\n height: 100% !important;\n}\n.frame-content video[data-v-2297f9cd] {\r\n width: 100%;\r\n height: 100%;\r\n object-fit: fill;\r\n z-index: 0;\n}\n.overlay[data-v-2297f9cd] {\r\n width: 100%;\r\n height: 100%;\r\n z-index: 5;\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n border: 4px solid transparent;\r\n pointer-events: none;\n}\r\n/* «««««««« */\n.div-frame[data-v-2297f9cd] img {\r\n width: 90vh !important;\n}\r\n", map: {"version":3,"sources":["C:\\Workspace\\visualization\\src\\components\\Frame.vue"],"names":[],"mappings":";AAwcA;EACA,gBAAA;EACA,YAAA,EAAA,aAAA;AACA;AACA;EACA,uBAAA;EACA,aAAA;EACA,uBAAA;AACA;AACA;;EAEA,aAAA;EACA,mBAAA;EACA,uBAAA;AACA;AACA;EACA,YAAA;EACA,gBAAA;EACA,UAAA;AACA;AACA;EACA,WAAA;EACA,YAAA;EACA,UAAA;EACA,kBAAA;EACA,MAAA;EACA,OAAA;EACA,6BAAA;EACA,oBAAA;AACA;AACA;EACA,0CAAA;AACA;AACA;EACA,gDAAA;AACA;AACA;EACA,4CAAA;AACA;AACA;EACA,4CAAA;AACA;AACA;EACA,wCAAA;AACA;AACA;EACA,0CAAA;AACA;AACA;EACA,sCAAA;AACA;AACA;EACA,4CAAA;EACA,6CAAA;AACA;AACA;EACA,4CAAA;EACA,6CAAA;EACA,6CAAA;EACA,4CAAA;AACA;;AAEA,eAAA;AACA;;EAEA,sBAAA;EACA,uBAAA;EACA,2BAAA;EACA,6BAAA;EACA,yBAAA;AACA;AAEA;;EAEA,sBAAA;EACA,uBAAA;AACA;AAEA;EACA,WAAA;EACA,YAAA;EACA,gBAAA;EACA,UAAA;AACA;AAEA;EACA,WAAA;EACA,YAAA;EACA,UAAA;EACA,kBAAA;EACA,MAAA;EACA,OAAA;EACA,6BAAA;EACA,oBAAA;AACA;AACA,aAAA;AACA;EACA,sBAAA;AACA","file":"Frame.vue","sourcesContent":["<template>\r\n <div\r\n :style=\"{\r\n maxHeight: `${maxHeight}px`,\r\n width: '100%',\r\n position: 'relative',\r\n }\"\r\n :class=\"{\r\n 'frame-container': true,\r\n 'initial-time': initialTime,\r\n 'end-time': endTime,\r\n 'between-time': betweenTime,\r\n active: active,\r\n }\">\r\n <GlobalEvents\r\n v-if=\"active && activeTab && parentComponent.settingsClosed\"\r\n @keydown.32.prevent=\"playOrPause\"\r\n @keydown.27.prevent=\"stop\"\r\n @keydown.79=\"toogleDetailFrame\"\r\n @keydown.13.prevent=\"jumpFrameToStart\" />\r\n <GlobalEvents\r\n v-if=\"showFrame\"\r\n @keydown.27.prevent=\"toogleDetailFrame\"\r\n @keydown.13.prevent=\"toogleDetailFrame\" />\r\n\r\n <vue-loading\r\n :active=\"isLoading\"\r\n spinner=\"ring\"\r\n color=\"var(--visualization-primary)\"\r\n background-color=\"#cacaca\"\r\n :style=\"{\r\n 'z-index': 0,\r\n minHeight: `${height}px`,\r\n minWidth: `${width}px`,\r\n }\"\r\n :text=\"videoIsLoading ? $t('infoBar.createVideo') : ''\" />\r\n <div\r\n :style=\"{\r\n backgroundColor: 'black',\r\n width: stretchFrame ? '100%' : 'auto',\r\n height: stretchFrame ? '100%' : 'auto',\r\n }\">\r\n <div\r\n v-if=\"!isLoading\"\r\n :class=\"{\r\n 'frame-content': frame.title === -1 || videoStatus !== Status.stopped,\r\n }\"\r\n :style=\"\r\n stretchFrame\r\n ? {\r\n height: `${maxHeight}px`,\r\n width: '100%',\r\n color: 'white',\r\n }\r\n : {\r\n minHeight: `${height}px`,\r\n minWidth: `${width}px`,\r\n maxHeight: `${height}px`,\r\n maxWidth: `${width}px`,\r\n color: 'white',\r\n }\r\n \"\r\n @dblclick=\"playOrPause\">\r\n <div\r\n v-if=\"frame.image && videoStatus === Status.stopped\"\r\n :class=\"{ 'dummy-frame': frame.title === -1 }\"\r\n v-html=\"frame.image\"\r\n style=\"width: 100%; height: 100%\" />\r\n\r\n <video\r\n v-if=\"\r\n !videoOnModal && videoStatus !== Status.stopped && !videoIsLoading\r\n \"\r\n ref=\"videoPlayer\"\r\n :maxHeight=\"`${height}px`\"\r\n :maxWidth=\"`${width}px`\"\r\n :src=\"videoUrlString\"\r\n @timeupdate=\"updateTimeLabel\"\r\n @ended=\"videoEnded\"\r\n @click=\"playOrPause\"\r\n @canplay=\"canPlay\"\r\n @error=\"() => stop(false)\"\r\n :style=\"{ width: '100%', aspectRatio: aspectRatioFrac }\"></video>\r\n <div v-if=\"!loading\" class=\"overlay\"></div>\r\n \r\n </div>\r\n </div>\r\n\r\n <dialog\r\n ref=\"imageDetailsDialog\"\r\n style=\"\r\n top: 50%;\r\n left: 50%;\r\n transform: translateY(-50%) translateX(-50%);\r\n border: none;\r\n background: grey;\r\n width: 60%;\r\n \">\r\n <div\r\n v-if=\"videoStatus == Status.stopped\"\r\n style=\"justify-content: center; display: flex\"\r\n :class=\"{\r\n 'dummy-frame': frame.title === -1,\r\n 'div-frame': frame.title !== -1,\r\n }\"\r\n v-html=\"frame.image\"\r\n @dblclick=\"changeToVideo\"></div>\r\n <video\r\n v-if=\"videoOnModal && videoStatus !== Status.stopped && !videoIsLoading\"\r\n ref=\"videoPlayer\"\r\n :src=\"videoUrlString\"\r\n autoplay\r\n @ended=\"videoEnded\"\r\n style=\"width: 100%; aspect-ratio: 11/9\"\r\n controls=\"true\"\r\n width=\"200%\"></video>\r\n </dialog>\r\n </div>\r\n</template>\r\n<script>\r\nimport VueLoading from 'vue-loading-twa'\r\n\r\nconst Status = Object.freeze({\r\n stopped: 0,\r\n playing: 1,\r\n paused: 2,\r\n})\r\n\r\nexport default {\r\n components: {\r\n VueLoading,\r\n },\r\n name: 'frame-component',\r\n props: {\r\n frame: {\r\n type: [Object, Number],\r\n required: true,\r\n },\r\n index: {\r\n type: Number,\r\n required: true,\r\n },\r\n loading: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n gridSettings: {\r\n type: Object,\r\n required: true,\r\n },\r\n initialTime: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n endTime: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n betweenTime: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n active: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n activeTab: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n videoUrl: {\r\n type: [String, Promise],\r\n required: true,\r\n },\r\n playbackRate: {\r\n type: Number,\r\n default: 1,\r\n },\r\n videoControls: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n aspectRatio: {\r\n type: Number,\r\n default: 11 / 9,\r\n },\r\n stretchFrame: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n },\r\n data() {\r\n return {\r\n Status,\r\n width: 0,\r\n height: 0,\r\n maxWidth: 0,\r\n fullMaxWidth: 0,\r\n maxHeight: 0,\r\n showFrame: false,\r\n videoStatus: Status.stopped,\r\n videoStartTime: null,\r\n videoCurrentTime: null,\r\n videoUrlString: '',\r\n parentComponent: null,\r\n videoIsLoading: false,\r\n currentBlock: null,\r\n lastTimeEnterPressed: null,\r\n videoOnModal: false,\r\n }\r\n },\r\n created() {\r\n this.parentComponent = this.$parent\r\n },\r\n watch: {\r\n playbackRate(val) {\r\n if (\r\n this.videoStatus === Status.playing ||\r\n this.videoStatus === Status.paused\r\n ) {\r\n this.$refs.videoPlayer.playbackRate = val\r\n }\r\n },\r\n },\r\n computed: {\r\n isLoading() {\r\n return (\r\n ((!this.frame.image || !this.frame.time) && this.frame.title !== -1) ||\r\n this.loading ||\r\n this.videoIsLoading\r\n )\r\n },\r\n aspectRatioFrac() {\r\n var gcd = function (a, b) {\r\n if (b < 0.0000001) return a\r\n\r\n return gcd(b, Math.floor(a % b))\r\n }\r\n\r\n var denominator = Math.pow(10, this.aspectRatio.toString().length - 2)\r\n var numerator = this.aspectRatio * denominator\r\n\r\n var divisor = gcd(numerator, denominator)\r\n\r\n return `${Math.floor(numerator / divisor)}/${Math.floor(\r\n denominator / divisor\r\n )}`\r\n },\r\n },\r\n methods: {\r\n canPlay() {\r\n this.$refs.videoPlayer.play()\r\n },\r\n changeToVideo() {\r\n this.videoOnModal = true\r\n this.playOrPause()\r\n },\r\n jumpFrameToStart() {\r\n if (this.active) {\r\n const currentTime = new Date().getTime()\r\n\r\n if (currentTime - this.lastTimeEnterPressed <= 500) {\r\n this.parentComponent.changeHour(\r\n this.parentComponent.convertToAudienceTime(this.frame.time)\r\n )\r\n }\r\n\r\n this.lastTimeEnterPressed = currentTime\r\n }\r\n },\r\n changeSettings(value) {\r\n this.videoCurrentTime = value\r\n },\r\n toogleDetailFrame() {\r\n this.stop()\r\n if (this.showFrame) {\r\n this.videoOnModal = false\r\n this.$refs.imageDetailsDialog.close()\r\n } else {\r\n this.$refs.imageDetailsDialog.showModal()\r\n }\r\n this.showFrame = !this.showFrame\r\n },\r\n getMaxWidth() {\r\n const commandBarSize = document.getElementById('command-bar')\r\n\r\n return commandBarSize?.clientWidth\r\n },\r\n resize(height) {\r\n const commandBarSize = document.getElementById('command-bar')\r\n const infoBarSize = document.getElementById('info-bar')\r\n\r\n this.fullMaxWidth = infoBarSize?.clientWidth\r\n this.maxWidth =\r\n (this.fullMaxWidth - this.gridSettings.framesPerRow * 10) /\r\n this.gridSettings.framesPerRow\r\n\r\n const rowSpacing = 29 * this.gridSettings.numberOfRows\r\n \r\n let heightAvailable =\r\n height -\r\n (commandBarSize?.offsetHeight || 0) -\r\n infoBarSize?.offsetHeight -\r\n rowSpacing -\r\n 2 // bottom padding\r\n\r\n if (this.gridSettings.numberOfRows > 1) {\r\n heightAvailable += 12\r\n }\r\n\r\n this.maxHeight = heightAvailable / this.gridSettings.numberOfRows\r\n const minHeightPerRow = this.gridSettings.numberOfRows > 2 ? 50 : 60\r\n this.maxHeight = Math.max(this.maxHeight, minHeightPerRow)\r\n\r\n if (this.maxWidth / this.aspectRatio > this.maxHeight) {\r\n this.height = this.maxHeight\r\n this.width = this.maxHeight * this.aspectRatio\r\n } else {\r\n this.width = this.maxWidth\r\n this.height = this.maxWidth / this.aspectRatio\r\n }\r\n this.applyImageStyles()\r\n this.maxHeight = this.height\r\n },\r\n applyImageStyles() {\r\n this.$nextTick(() => {\r\n const frameImages = this.$el.querySelectorAll(\r\n '.frame-container img, .dummy-frame img'\r\n )\r\n\r\n frameImages.forEach((img) => {\r\n img.style.width = '100%'\r\n img.style.height = '100%'\r\n img.style.objectFit = 'fill'\r\n img.style.aspectRatio = 'auto'\r\n img.style.display = 'block'\r\n })\r\n })\r\n },\r\n async playOrPause() {\r\n switch (this.videoStatus) {\r\n case Status.stopped:\r\n this.videoIsLoading = true\r\n try {\r\n this.videoUrlString = await this.videoUrl\r\n const blockInfo =\r\n await this.parentComponent.fInterface?.getVideoStartTime(\r\n this.frame\r\n )\r\n\r\n this.videoStartTime = blockInfo.start\r\n this.videoUrlString =\r\n this.parentComponent.fInterface.getVideoRequestByUrl(\r\n blockInfo.url,\r\n this.frame.number + this.parentComponent.shiftFrames\r\n )\r\n } catch (error) {\r\n console.log(error)\r\n }\r\n this.videoIsLoading = false\r\n this.videoStatus = Status.playing\r\n this.$nextTick(() => {\r\n this.$refs.videoPlayer.onloaded = (e) => {\r\n this.$refs.videoPlayer.playbackRate = this.playbackRate\r\n // * atualizar slider\r\n this.$emit('updateSlider', this.videoStartTime, this.frame.time)\r\n //*\r\n this.$emit('startPlaying', this.frame, e.target.duration)\r\n this.$emit('playPauseStatus', true)\r\n }\r\n })\r\n break\r\n case Status.paused:\r\n this.$refs.videoPlayer.play()\r\n this.$refs.videoPlayer.playbackRate = this.playbackRate\r\n this.videoStatus = Status.playing\r\n this.$emit('playPauseStatus', true)\r\n break\r\n case Status.playing:\r\n this.$refs.videoPlayer.pause()\r\n\r\n this.videoStatus = Status.paused\r\n this.$emit('playPauseStatus', false)\r\n break\r\n }\r\n },\r\n stop(jump = true) {\r\n this.videoOnModal = false\r\n if (\r\n this.videoStatus === Status.playing ||\r\n this.videoStatus === Status.paused\r\n ) {\r\n if (jump) {\r\n this.parentComponent.changeHour(\r\n this.parentComponent.convertToAudienceTime(\r\n parseInt(this.videoCurrentTime)\r\n )\r\n )\r\n }\r\n this.videoStatus = Status.stopped\r\n this.videoUrlString = null\r\n this.videoCurrentTime = null\r\n this.videoStartTime = null\r\n }\r\n this.$emit('stopPlaying')\r\n },\r\n //eslint-disable-next-line\r\n videoJumpTo(time) {\r\n this.videoCurrentTime = this.videoStartTime + time\r\n this.$refs.videoPlayer.currentTime = time\r\n },\r\n async videoJumpToTimeStamp(time) {\r\n let frame = {\r\n time: time,\r\n }\r\n if (!time) return\r\n if (\r\n !(\r\n this.currentBlock &&\r\n time >= this.currentBlock.start &&\r\n time <= this.currentBlock.end\r\n )\r\n ) {\r\n this.currentBlock = await this.parentComponent.fInterface?.getBlockInfo(\r\n frame\r\n )\r\n this.videoStartTime = this.currentBlock.start\r\n this.videoUrlString =\r\n this.parentComponent.fInterface.getVideoUrlForTime(\r\n this.videoStartTime\r\n )\r\n }\r\n this.videoCurrentTime = time - this.videoStartTime\r\n this.$refs.videoPlayer.currentTime = this.videoCurrentTime\r\n },\r\n updateTimeLabel(e) {\r\n this.videoCurrentTime = this.videoStartTime + e.target.currentTime\r\n this.parentComponent.updateVideoTime(this.index, this.videoCurrentTime)\r\n this.parentComponent.updateVideoStatus(e.target.currentTime)\r\n },\r\n async videoEnded() {\r\n this.videoStartTime =\r\n await this.parentComponent.fInterface?.getNextVideoStartTime(\r\n this.frame.time - this.parentComponent.shiftFrames\r\n )\r\n this.videoUrlString = this.parentComponent.fInterface.getVideoUrlForTime(\r\n this.videoStartTime\r\n )\r\n // * Ao acabar o vídeo tenho de mandar atualizar slider\r\n // * aqui o video current time tambem vai ser o videoStartTime\r\n this.$emit('updateSlider', this.videoStartTime, this.videoStartTime)\r\n },\r\n },\r\n}\r\n</script>\r\n<style scoped>\r\n.frame-container > div {\r\n max-height: 100%;\r\n height: 100%; /* Add this */\r\n}\r\n.frame-container {\r\n background-color: black;\r\n display: flex;\r\n justify-content: center;\r\n}\r\n.frame-content,\r\n.dummy-frame {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n.frame-content video {\r\n flex-grow: 1;\r\n object-fit: fill;\r\n z-index: 0;\r\n}\r\n.overlay {\r\n width: 100%;\r\n height: 100%;\r\n z-index: 5;\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n border: 4px solid transparent;\r\n pointer-events: none;\r\n}\r\n.active .overlay {\r\n border-color: var(--visualization-primary);\r\n}\r\n.between-time .overlay {\r\n border-top-color: var(--visualization-secondary);\r\n}\r\n.between-time.active .overlay {\r\n border-color: var(--visualization-secondary);\r\n}\r\n.initial-time .overlay {\r\n border-top-color: var(--visualization-start);\r\n}\r\n.initial-time.active .overlay {\r\n border-color: var(--visualization-start);\r\n}\r\n.end-time .overlay {\r\n border-top-color: var(--visualization-end);\r\n}\r\n.end-time.active .overlay {\r\n border-color: var(--visualization-end);\r\n}\r\n.initial-time.end-time .overlay {\r\n border-top-color: var(--visualization-start);\r\n border-bottom-color: var(--visualization-end);\r\n}\r\n.initial-time.end-time.active .overlay {\r\n border-top-color: var(--visualization-start);\r\n border-left-color: var(--visualization-start);\r\n border-bottom-color: var(--visualization-end);\r\n border-right-color: var(--visualization-end);\r\n}\r\n\r\n/* new styles */\r\n.frame-content >>> img,\r\n.dummy-frame >>> img {\r\n width: 100% !important;\r\n height: 100% !important;\r\n object-fit: fill !important;\r\n aspect-ratio: auto !important;\r\n display: block !important;\r\n}\r\n\r\n.frame-content >>> div,\r\n.dummy-frame >>> div {\r\n width: 100% !important;\r\n height: 100% !important;\r\n}\r\n\r\n.frame-content video {\r\n width: 100%;\r\n height: 100%;\r\n object-fit: fill;\r\n z-index: 0;\r\n}\r\n\r\n.overlay {\r\n width: 100%;\r\n height: 100%;\r\n z-index: 5;\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n border: 4px solid transparent;\r\n pointer-events: none;\r\n}\r\n/* «««««««« */\r\n.div-frame >>> img {\r\n width: 90vh !important;\r\n}\r\n</style>\r\n"]}, media: undefined });
821
862
 
822
863
  };
823
864
  /* scoped */
824
- const __vue_scope_id__$5 = "data-v-75056fcc";
865
+ const __vue_scope_id__$5 = "data-v-2297f9cd";
825
866
  /* module identifier */
826
867
  const __vue_module_identifier__$5 = undefined;
827
868
  /* functional template */
@@ -869,12 +910,14 @@ var FramesService = {
869
910
  direction,
870
911
  channel,
871
912
  split,
913
+ size,
872
914
  time,
873
915
  quality,
874
916
  factor,
875
917
  useCache = true,
876
918
  signal,
877
919
  } = {}) {
920
+ let fileSize = size > 180 ? '88x72' : '352x288';
878
921
  return API().get(`Get${direction}FramesBlockInFiles`, {
879
922
  params: {
880
923
  Channel: channel,
@@ -884,6 +927,7 @@ var FramesService = {
884
927
  Step: 0,
885
928
  JpegQuality: quality,
886
929
  JpegSizeFactor: factor,
930
+ FileSize: fileSize,
887
931
  },
888
932
  signal,
889
933
  })
@@ -899,6 +943,9 @@ var FramesService = {
899
943
  useCache = true,
900
944
  signal,
901
945
  } = {}) {
946
+ //console.log('Getting small block request', size)
947
+
948
+ let fileSize = size > 180 ? '88x72' : '352x288';
902
949
  return API().get('GetSmallFramesBlockInFiles', {
903
950
  params: {
904
951
  Channel: channel,
@@ -909,6 +956,7 @@ var FramesService = {
909
956
  JpegQuality: quality,
910
957
  JpegSizeFactor: factor,
911
958
  Size: size,
959
+ FileSize: fileSize,
912
960
  },
913
961
  signal,
914
962
  })
@@ -1303,6 +1351,7 @@ FramesManager.prototype.getBlock = async function (
1303
1351
  channel,
1304
1352
  split,
1305
1353
  time,
1354
+ size: this.size * 15,
1306
1355
  quality: ENUM.StepsQuality[this.currentStep],
1307
1356
  factor: ENUM.StepsFactor[this.currentStep],
1308
1357
  signal: this.requests[requestId].signal,
@@ -2283,6 +2332,13 @@ __vue_render__$4._withStripped = true;
2283
2332
  //
2284
2333
  //
2285
2334
  //
2335
+ //
2336
+ //
2337
+ //
2338
+ //
2339
+ //
2340
+ //
2341
+ //
2286
2342
 
2287
2343
  var script$3 = {
2288
2344
  props: {
@@ -2328,9 +2384,16 @@ var script$3 = {
2328
2384
  hourEnd: {
2329
2385
  type: [Number, Boolean],
2330
2386
  },
2387
+ showStretchFrame: {
2388
+ type: Boolean,
2389
+ default: false,
2390
+ },
2391
+
2331
2392
  },
2332
2393
  data() {
2333
- return {}
2394
+ return {
2395
+ stretchFrames: false,
2396
+ }
2334
2397
  },
2335
2398
  computed: {
2336
2399
  blockTotalTime() {
@@ -2499,6 +2562,34 @@ var __vue_render__$3 = function () {
2499
2562
  "div",
2500
2563
  { staticClass: "settings-container" },
2501
2564
  [
2565
+ _c("font-awesome-icon", {
2566
+ directives: [
2567
+ {
2568
+ name: "show",
2569
+ rawName: "v-show",
2570
+ value: _vm.showStretchFrame,
2571
+ expression: "showStretchFrame",
2572
+ },
2573
+ {
2574
+ name: "tooltip",
2575
+ rawName: "v-tooltip",
2576
+ value: _vm.$t("infoBar.stretchFrames"),
2577
+ expression: "$t('infoBar.stretchFrames')",
2578
+ },
2579
+ ],
2580
+ attrs: {
2581
+ icon: !_vm.stretchFrames
2582
+ ? ["fas", "fa-maximize"]
2583
+ : ["fas", "fa-minimize"],
2584
+ },
2585
+ on: {
2586
+ click: function ($event) {
2587
+ _vm.stretchFrames = !_vm.stretchFrames;
2588
+ _vm.$emit("update-stretch-frames", _vm.stretchFrames);
2589
+ },
2590
+ },
2591
+ }),
2592
+ _vm._v(" "),
2502
2593
  _c("font-awesome-icon", {
2503
2594
  directives: [
2504
2595
  {
@@ -2606,11 +2697,11 @@ __vue_render__$3._withStripped = true;
2606
2697
  /* style */
2607
2698
  const __vue_inject_styles__$3 = function (inject) {
2608
2699
  if (!inject) return
2609
- inject("data-v-848911da_0", { source: "\n.visualization-row[data-v-848911da] {\r\n display: flex;\r\n flex-wrap: wrap;\r\n flex: 1 1 auto;\n}\n.visualization-col[data-v-848911da] {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\n}\n.visualization-divider[data-v-848911da] {\r\n display: block;\r\n flex: 1 1 100%;\r\n height: 0px;\r\n max-height: 0px;\r\n opacity: 1;\r\n transition: inherit;\r\n border-style: solid;\r\n border-width: thin 0 0 0;\r\n border-color: rgba(0, 0, 0, 0.12);\r\n margin: 0;\n}\n.visualization-divider.vertical[data-v-848911da] {\r\n align-self: stretch;\r\n border-width: 0 thin 0 0;\r\n display: inline-flex;\r\n height: inherit;\r\n margin-left: -1px;\r\n max-height: 100%;\r\n max-width: 0px;\r\n vertical-align: text-bottom;\r\n width: 0px;\n}\n.visualization-card[data-v-848911da] {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\r\n width: 100%;\r\n transition-property: box-shadow, opacity, -webkit-box-shadow;\r\n overflow-wrap: break-word;\r\n /*box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);*/\n}\n.visualization-justify-center[data-v-848911da],[data-v-848911da] .visualization-justify-center {\r\n justify-content: center;\n}\n.visualization-align-center[data-v-848911da] {\r\n align-items: center;\n}\n#visualization-container[data-v-848911da] {\r\n max-width: 100% !important;\r\n margin: 0 auto !important;\r\n height: 100%;\r\n border-bottom: none;\n}\n#visualization-container > .card[data-v-848911da] {\r\n border-radius: 0 !important;\r\n font-size: 12px;\r\n width: 100%;\r\n box-shadow: none;\r\n height: 100%;\n}\n#command-bar[data-v-848911da],\r\n#info-bar[data-v-848911da] {\r\n background-color: #f5f5f5;\r\n box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);\n}\n#command-bar button[data-v-848911da] {\r\n width: 42px;\r\n height: 36px;\r\n border: none;\r\n background: none;\n}\n#command-bar button[data-v-848911da]:hover {\r\n cursor: pointer;\r\n background: rgba(0, 0, 0, 0.12);\n}\n#command-bar svg[data-v-848911da] {\r\n font-size: 16px;\n}\n#command-bar[data-v-848911da] {\r\n padding: 0 !important;\n}\n#info-bar[data-v-848911da] {\r\n padding: 4px;\r\n font-size: 14px;\r\n position: relative;\n}\n.settings-container[data-v-848911da] {\r\n position: absolute;\r\n right: 14px;\r\n top: 50%;\r\n transform: translateY(-50%);\n}\n.settings-container > *[data-v-848911da] {\r\n margin: 0 2px;\r\n cursor: pointer;\n}\n#info-bar svg[data-v-848911da] {\r\n font-size: 16px;\n}\n#info-bar .divider[data-v-848911da] {\r\n margin: 0 8px;\n}\nsvg[data-v-848911da]:focus {\r\n border: none;\n}\n.visualization-card[data-v-848911da] {\r\n border-left: 8px solid #eee;\n}\n.active-tab[data-v-848911da] {\r\n border-left: 8px solid var(--visualization-primary) !important;\r\n border-image-slice: 1;\n}\n[id^='frame-'][data-v-848911da] {\r\n padding: 1px;\r\n display: flex;\r\n flex-flow: column;\n}\n.tooltip[data-v-848911da] {\r\n display: block !important;\r\n z-index: 10000;\n}\n.tooltip .tooltip-inner[data-v-848911da] {\r\n background: var(--visualization-primary);\r\n color: white;\r\n border-radius: 16px;\r\n padding: 5px 10px 4px;\n}\n.tooltip .tooltip-arrow[data-v-848911da] {\r\n width: 0;\r\n height: 0;\r\n border-style: solid;\r\n position: absolute;\r\n margin: 5px;\r\n border-color: var(--visualization-primary);\r\n z-index: 1;\n}\n.tooltip[x-placement^='top'][data-v-848911da] {\r\n margin-bottom: 5px;\n}\n.tooltip[x-placement^='top'] .tooltip-arrow[data-v-848911da] {\r\n border-width: 5px 5px 0 5px;\r\n border-left-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n bottom: -5px;\r\n left: calc(50% - 5px);\r\n margin-top: 0;\r\n margin-bottom: 0;\n}\n.tooltip[x-placement^='bottom'][data-v-848911da] {\r\n margin-top: 5px;\n}\n.tooltip[x-placement^='bottom'] .tooltip-arrow[data-v-848911da] {\r\n border-width: 0 5px 5px 5px;\r\n border-left-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-top-color: transparent !important;\r\n top: -5px;\r\n left: calc(50% - 5px);\r\n margin-top: 0;\r\n margin-bottom: 0;\n}\n.tooltip[x-placement^='right'][data-v-848911da] {\r\n margin-left: 5px;\n}\n.tooltip[x-placement^='right'] .tooltip-arrow[data-v-848911da] {\r\n border-width: 5px 5px 5px 0;\r\n border-left-color: transparent !important;\r\n border-top-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n left: -5px;\r\n top: calc(50% - 5px);\r\n margin-left: 0;\r\n margin-right: 0;\n}\n.tooltip[x-placement^='left'][data-v-848911da] {\r\n margin-right: 5px;\n}\n.tooltip[x-placement^='left'] .tooltip-arrow[data-v-848911da] {\r\n border-width: 5px 0 5px 5px;\r\n border-top-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n right: -5px;\r\n top: calc(50% - 5px);\r\n margin-left: 0;\r\n margin-right: 0;\n}\n.tooltip.popover .popover-inner[data-v-848911da] {\r\n background: #f9f9f9;\r\n color: black;\r\n padding: 24px;\r\n border-radius: 5px;\r\n box-shadow: 0 5px 30px rgba(black, 0.1);\n}\n.tooltip.popover .popover-arrow[data-v-848911da] {\r\n border-color: #f9f9f9;\n}\n.tooltip[aria-hidden='true'][data-v-848911da] {\r\n visibility: hidden;\r\n opacity: 0;\r\n transition: opacity 0.15s, visibility 0.15s;\n}\n.tooltip[aria-hidden='false'][data-v-848911da] {\r\n visibility: visible;\r\n opacity: 1;\r\n transition: opacity 0.15s;\n}\r\n", map: {"version":3,"sources":["C:\\Workspace\\visualization\\src\\components\\Infos.vue"],"names":[],"mappings":";AA+LA;EACA,aAAA;EACA,eAAA;EACA,cAAA;AACA;AAEA;EACA,aAAA;EACA,YAAA;EACA,eAAA;EACA,aAAA;AACA;AAEA;EACA,cAAA;EACA,cAAA;EACA,WAAA;EACA,eAAA;EACA,UAAA;EACA,mBAAA;EACA,mBAAA;EACA,wBAAA;EACA,iCAAA;EACA,SAAA;AACA;AAEA;EACA,mBAAA;EACA,wBAAA;EACA,oBAAA;EACA,eAAA;EACA,iBAAA;EACA,gBAAA;EACA,cAAA;EACA,2BAAA;EACA,UAAA;AACA;AAEA;EACA,aAAA;EACA,YAAA;EACA,eAAA;EACA,aAAA;EACA,WAAA;EACA,4DAAA;EACA,yBAAA;EACA;qCACA;AACA;AAEA;EAEA,uBAAA;AACA;AAEA;EACA,mBAAA;AACA;AAEA;EACA,0BAAA;EACA,yBAAA;EACA,YAAA;EACA,mBAAA;AACA;AACA;EACA,2BAAA;EACA,eAAA;EACA,WAAA;EACA,gBAAA;EACA,YAAA;AACA;AAEA;;EAEA,yBAAA;EACA;mCACA;AACA;AACA;EACA,WAAA;EACA,YAAA;EACA,YAAA;EACA,gBAAA;AACA;AAEA;EACA,eAAA;EACA,+BAAA;AACA;AAEA;EACA,eAAA;AACA;AAEA;EACA,qBAAA;AACA;AAEA;EACA,YAAA;EACA,eAAA;EACA,kBAAA;AACA;AAEA;EACA,kBAAA;EACA,WAAA;EACA,QAAA;EACA,2BAAA;AACA;AAEA;EACA,aAAA;EACA,eAAA;AACA;AAEA;EACA,eAAA;AACA;AAEA;EACA,aAAA;AACA;AAEA;EACA,YAAA;AACA;AAEA;EACA,2BAAA;AACA;AAEA;EACA,8DAAA;EACA,qBAAA;AACA;AAEA;EACA,YAAA;EACA,aAAA;EACA,iBAAA;AACA;AAEA;EACA,yBAAA;EACA,cAAA;AACA;AAEA;EACA,wCAAA;EACA,YAAA;EACA,mBAAA;EACA,qBAAA;AACA;AAEA;EACA,QAAA;EACA,SAAA;EACA,mBAAA;EACA,kBAAA;EACA,WAAA;EACA,0CAAA;EACA,UAAA;AACA;AAEA;EACA,kBAAA;AACA;AAEA;EACA,2BAAA;EACA,yCAAA;EACA,0CAAA;EACA,2CAAA;EACA,YAAA;EACA,qBAAA;EACA,aAAA;EACA,gBAAA;AACA;AAEA;EACA,eAAA;AACA;AAEA;EACA,2BAAA;EACA,yCAAA;EACA,0CAAA;EACA,wCAAA;EACA,SAAA;EACA,qBAAA;EACA,aAAA;EACA,gBAAA;AACA;AAEA;EACA,gBAAA;AACA;AAEA;EACA,2BAAA;EACA,yCAAA;EACA,wCAAA;EACA,2CAAA;EACA,UAAA;EACA,oBAAA;EACA,cAAA;EACA,eAAA;AACA;AAEA;EACA,iBAAA;AACA;AAEA;EACA,2BAAA;EACA,wCAAA;EACA,0CAAA;EACA,2CAAA;EACA,WAAA;EACA,oBAAA;EACA,cAAA;EACA,eAAA;AACA;AAEA;EACA,mBAAA;EACA,YAAA;EACA,aAAA;EACA,kBAAA;EACA,uCAAA;AACA;AAEA;EACA,qBAAA;AACA;AAEA;EACA,kBAAA;EACA,UAAA;EACA,2CAAA;AACA;AAEA;EACA,mBAAA;EACA,UAAA;EACA,yBAAA;AACA","file":"Infos.vue","sourcesContent":["<template>\r\n <div\r\n id=\"info-bar\"\r\n class=\"visualization-col\"\r\n :style=\"\r\n !commandsShow ? 'border-top-right-radius: 6px; padding: 0' : 'padding: 0'\r\n \"\r\n >\r\n <div\r\n class=\"visualization-row visualization-justify-center visualization-align-center\"\r\n style=\"position: relative; padding: 4px\"\r\n >\r\n <span> {{ playbackRate }}x </span>\r\n <hr class=\"visualization-divider vertical\" style=\"margin: 0 8px\" />\r\n <span>\r\n {{\r\n $t('infoBar.selected', {\r\n seconds: hourEnd && hourIni ? hourEnd - hourIni + 1 : 0,\r\n hour_ini: convertToAudienceTime(hourIni),\r\n hour_end: convertToAudienceTime(hourEnd),\r\n })\r\n }}\r\n </span>\r\n <hr class=\"visualization-divider vertical\" style=\"margin: 0 8px\" />\r\n <span>\r\n {{\r\n $t('infoBar.interval', {\r\n seconds: secondsPerFrame,\r\n })\r\n }}\r\n </span>\r\n <hr class=\"visualization-divider vertical\" style=\"margin: 0 8px\" />\r\n <span>\r\n {{\r\n $t('infoBar.block', {\r\n time1: convertToAudienceTime(blockStartTime),\r\n time2: convertToAudienceTime(blockTotalTime),\r\n })\r\n }}\r\n </span>\r\n <hr class=\"visualization-divider vertical\" style=\"margin: 0 8px\" />\r\n {{ framesPerRow * numberOfRows }}\r\n <hr class=\"visualization-divider vertical\" style=\"margin: 0 8px\" />\r\n {{ framesPerRow + '*' + numberOfRows }}\r\n <span\r\n class=\"visualization-divider vertical\"\r\n v-if=\"!cache\"\r\n style=\"margin: 0 8px\"\r\n />\r\n <span v-if=\"!cache\">\r\n <font-awesome-icon\r\n icon=\"fa-solid fa-exclamation-circle\"\r\n style=\"margin: 0 4px\"\r\n />\r\n <strong>{{ $t('infoBar.notUsingCache') }}</strong>\r\n </span>\r\n <div class=\"settings-container\">\r\n <font-awesome-icon\r\n icon=\"fa-solid fa-server\"\r\n @click=\"$emit('change-server')\"\r\n v-tooltip=\"\r\n alternativeServer\r\n ? $t('infoBar.changeServer')\r\n : $t('infoBar.changeServer')\r\n \"\r\n />\r\n <font-awesome-icon\r\n :icon=\"commandsShow ? 'fa-solid fa-eye' : 'fa-solid fa-eye-slash'\"\r\n @click=\"$emit('toogle-commands-visibility')\"\r\n v-tooltip=\"\r\n commandsShow\r\n ? $t('moduletelentry.showButtons')\r\n : $t('moduletelentry.hideButtons')\r\n \"\r\n />\r\n <font-awesome-icon\r\n :icon=\"cache ? 'fa-solid fa-ban' : 'fa-solid fa-sync'\"\r\n @click=\"$emit('toogle-cache')\"\r\n v-tooltip=\"\r\n cache ? $t('infoBar.disableCache') : $t('infoBar.activateCache')\r\n \"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div\r\n v-if=\"alternativeServer\"\r\n class=\"visualization-row visualization-justify-center visualization-align-center\"\r\n style=\"\r\n color: white;\r\n background-color: orange;\r\n font-weight: bold;\r\n padding: 4px;\r\n \"\r\n >\r\n {{ $t('infoBar.alternativeServer') }}\r\n <font-awesome-icon\r\n icon=\"fa-solid fa-exclamation-triangle\"\r\n style=\"margin: 0 4px\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n<script>\r\nexport default {\r\n props: {\r\n playbackRate: {\r\n type: Number,\r\n required: true,\r\n },\r\n secondsPerFrame: {\r\n type: Number,\r\n required: true,\r\n },\r\n commandsShow: {\r\n type: Boolean,\r\n required: true,\r\n },\r\n cache: {\r\n type: Boolean,\r\n required: true,\r\n },\r\n blockStartTime: {\r\n type: Number,\r\n required: true,\r\n },\r\n videoTotalDuration: {\r\n type: Number,\r\n required: true,\r\n },\r\n alternativeServer: {\r\n type: Boolean,\r\n required: true,\r\n },\r\n framesPerRow: {\r\n type: Number,\r\n required: true,\r\n },\r\n numberOfRows: {\r\n type: Number,\r\n required: true,\r\n },\r\n hourIni: {\r\n type: [Number, Boolean],\r\n },\r\n hourEnd: {\r\n type: [Number, Boolean],\r\n },\r\n },\r\n data() {\r\n return {}\r\n },\r\n computed: {\r\n blockTotalTime() {\r\n return this.videoTotalDuration + this.blockStartTime\r\n },\r\n },\r\n methods: {\r\n convertToAudienceTime(time, separator = ':') {\r\n const limit = Date.UTC(null, null, null, 23, 59, 59) / 1000\r\n\r\n let hour = this.dateInUtc(time * 1000)\r\n .toTimeString()\r\n .split(' ')[0]\r\n .split(':')\r\n .map(Number)\r\n\r\n if (time > limit && time <= limit + this.startAudienceSeconds) {\r\n hour[0] = 24 + hour[0]\r\n }\r\n return hour\r\n .map((part) => (part > 9 ? part.toString() : '0' + part))\r\n .join(separator)\r\n },\r\n\r\n dateInUtc(miliSeconds) {\r\n var date = new Date(miliSeconds)\r\n var utc = new Date(\r\n date.getUTCFullYear(),\r\n date.getUTCMonth(),\r\n date.getUTCDate(),\r\n date.getUTCHours(),\r\n date.getUTCMinutes(),\r\n date.getUTCSeconds()\r\n )\r\n return utc\r\n },\r\n },\r\n}\r\n</script>\r\n<style scoped>\r\n.visualization-row {\r\n display: flex;\r\n flex-wrap: wrap;\r\n flex: 1 1 auto;\r\n}\r\n\r\n.visualization-col {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\r\n}\r\n\r\n.visualization-divider {\r\n display: block;\r\n flex: 1 1 100%;\r\n height: 0px;\r\n max-height: 0px;\r\n opacity: 1;\r\n transition: inherit;\r\n border-style: solid;\r\n border-width: thin 0 0 0;\r\n border-color: rgba(0, 0, 0, 0.12);\r\n margin: 0;\r\n}\r\n\r\n.visualization-divider.vertical {\r\n align-self: stretch;\r\n border-width: 0 thin 0 0;\r\n display: inline-flex;\r\n height: inherit;\r\n margin-left: -1px;\r\n max-height: 100%;\r\n max-width: 0px;\r\n vertical-align: text-bottom;\r\n width: 0px;\r\n}\r\n\r\n.visualization-card {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\r\n width: 100%;\r\n transition-property: box-shadow, opacity, -webkit-box-shadow;\r\n overflow-wrap: break-word;\r\n /*box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);*/\r\n}\r\n\r\n.visualization-justify-center,\r\n/deep/ .visualization-justify-center {\r\n justify-content: center;\r\n}\r\n\r\n.visualization-align-center {\r\n align-items: center;\r\n}\r\n\r\n#visualization-container {\r\n max-width: 100% !important;\r\n margin: 0 auto !important;\r\n height: 100%;\r\n border-bottom: none;\r\n}\r\n#visualization-container > .card {\r\n border-radius: 0 !important;\r\n font-size: 12px;\r\n width: 100%;\r\n box-shadow: none;\r\n height: 100%;\r\n}\r\n\r\n#command-bar,\r\n#info-bar {\r\n background-color: #f5f5f5;\r\n box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);\r\n}\r\n#command-bar button {\r\n width: 42px;\r\n height: 36px;\r\n border: none;\r\n background: none;\r\n}\r\n\r\n#command-bar button:hover {\r\n cursor: pointer;\r\n background: rgba(0, 0, 0, 0.12);\r\n}\r\n\r\n#command-bar svg {\r\n font-size: 16px;\r\n}\r\n\r\n#command-bar {\r\n padding: 0 !important;\r\n}\r\n\r\n#info-bar {\r\n padding: 4px;\r\n font-size: 14px;\r\n position: relative;\r\n}\r\n\r\n.settings-container {\r\n position: absolute;\r\n right: 14px;\r\n top: 50%;\r\n transform: translateY(-50%);\r\n}\r\n\r\n.settings-container > * {\r\n margin: 0 2px;\r\n cursor: pointer;\r\n}\r\n\r\n#info-bar svg {\r\n font-size: 16px;\r\n}\r\n\r\n#info-bar .divider {\r\n margin: 0 8px;\r\n}\r\n\r\nsvg:focus {\r\n border: none;\r\n}\r\n\r\n.visualization-card {\r\n border-left: 8px solid #eee;\r\n}\r\n\r\n.active-tab {\r\n border-left: 8px solid var(--visualization-primary) !important;\r\n border-image-slice: 1;\r\n}\r\n\r\n[id^='frame-'] {\r\n padding: 1px;\r\n display: flex;\r\n flex-flow: column;\r\n}\r\n\r\n.tooltip {\r\n display: block !important;\r\n z-index: 10000;\r\n}\r\n\r\n.tooltip .tooltip-inner {\r\n background: var(--visualization-primary);\r\n color: white;\r\n border-radius: 16px;\r\n padding: 5px 10px 4px;\r\n}\r\n\r\n.tooltip .tooltip-arrow {\r\n width: 0;\r\n height: 0;\r\n border-style: solid;\r\n position: absolute;\r\n margin: 5px;\r\n border-color: var(--visualization-primary);\r\n z-index: 1;\r\n}\r\n\r\n.tooltip[x-placement^='top'] {\r\n margin-bottom: 5px;\r\n}\r\n\r\n.tooltip[x-placement^='top'] .tooltip-arrow {\r\n border-width: 5px 5px 0 5px;\r\n border-left-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n bottom: -5px;\r\n left: calc(50% - 5px);\r\n margin-top: 0;\r\n margin-bottom: 0;\r\n}\r\n\r\n.tooltip[x-placement^='bottom'] {\r\n margin-top: 5px;\r\n}\r\n\r\n.tooltip[x-placement^='bottom'] .tooltip-arrow {\r\n border-width: 0 5px 5px 5px;\r\n border-left-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-top-color: transparent !important;\r\n top: -5px;\r\n left: calc(50% - 5px);\r\n margin-top: 0;\r\n margin-bottom: 0;\r\n}\r\n\r\n.tooltip[x-placement^='right'] {\r\n margin-left: 5px;\r\n}\r\n\r\n.tooltip[x-placement^='right'] .tooltip-arrow {\r\n border-width: 5px 5px 5px 0;\r\n border-left-color: transparent !important;\r\n border-top-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n left: -5px;\r\n top: calc(50% - 5px);\r\n margin-left: 0;\r\n margin-right: 0;\r\n}\r\n\r\n.tooltip[x-placement^='left'] {\r\n margin-right: 5px;\r\n}\r\n\r\n.tooltip[x-placement^='left'] .tooltip-arrow {\r\n border-width: 5px 0 5px 5px;\r\n border-top-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n right: -5px;\r\n top: calc(50% - 5px);\r\n margin-left: 0;\r\n margin-right: 0;\r\n}\r\n\r\n.tooltip.popover .popover-inner {\r\n background: #f9f9f9;\r\n color: black;\r\n padding: 24px;\r\n border-radius: 5px;\r\n box-shadow: 0 5px 30px rgba(black, 0.1);\r\n}\r\n\r\n.tooltip.popover .popover-arrow {\r\n border-color: #f9f9f9;\r\n}\r\n\r\n.tooltip[aria-hidden='true'] {\r\n visibility: hidden;\r\n opacity: 0;\r\n transition: opacity 0.15s, visibility 0.15s;\r\n}\r\n\r\n.tooltip[aria-hidden='false'] {\r\n visibility: visible;\r\n opacity: 1;\r\n transition: opacity 0.15s;\r\n}\r\n</style>\r\n"]}, media: undefined });
2700
+ inject("data-v-25cfa24c_0", { source: "\n.visualization-row[data-v-25cfa24c] {\r\n display: flex;\r\n flex-wrap: wrap;\r\n flex: 1 1 auto;\n}\n.visualization-col[data-v-25cfa24c] {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\n}\n.visualization-divider[data-v-25cfa24c] {\r\n display: block;\r\n flex: 1 1 100%;\r\n height: 0px;\r\n max-height: 0px;\r\n opacity: 1;\r\n transition: inherit;\r\n border-style: solid;\r\n border-width: thin 0 0 0;\r\n border-color: rgba(0, 0, 0, 0.12);\r\n margin: 0;\n}\n.visualization-divider.vertical[data-v-25cfa24c] {\r\n align-self: stretch;\r\n border-width: 0 thin 0 0;\r\n display: inline-flex;\r\n height: inherit;\r\n margin-left: -1px;\r\n max-height: 100%;\r\n max-width: 0px;\r\n vertical-align: text-bottom;\r\n width: 0px;\n}\n.visualization-card[data-v-25cfa24c] {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\r\n width: 100%;\r\n transition-property: box-shadow, opacity, -webkit-box-shadow;\r\n overflow-wrap: break-word;\r\n /*box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);*/\n}\n.visualization-justify-center[data-v-25cfa24c],[data-v-25cfa24c] .visualization-justify-center {\r\n justify-content: center;\n}\n.visualization-align-center[data-v-25cfa24c] {\r\n align-items: center;\n}\n#visualization-container[data-v-25cfa24c] {\r\n max-width: 100% !important;\r\n margin: 0 auto !important;\r\n height: 100%;\r\n border-bottom: none;\n}\n#visualization-container > .card[data-v-25cfa24c] {\r\n border-radius: 0 !important;\r\n font-size: 12px;\r\n width: 100%;\r\n box-shadow: none;\r\n height: 100%;\n}\n#command-bar[data-v-25cfa24c],\r\n#info-bar[data-v-25cfa24c] {\r\n background-color: #f5f5f5;\r\n box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);\n}\n#command-bar button[data-v-25cfa24c] {\r\n width: 42px;\r\n height: 36px;\r\n border: none;\r\n background: none;\n}\n#command-bar button[data-v-25cfa24c]:hover {\r\n cursor: pointer;\r\n background: rgba(0, 0, 0, 0.12);\n}\n#command-bar svg[data-v-25cfa24c] {\r\n font-size: 16px;\n}\n#command-bar[data-v-25cfa24c] {\r\n padding: 0 !important;\n}\n#info-bar[data-v-25cfa24c] {\r\n padding: 4px;\r\n font-size: 14px;\r\n position: relative;\n}\n.settings-container[data-v-25cfa24c] {\r\n position: absolute;\r\n right: 14px;\r\n top: 50%;\r\n transform: translateY(-50%);\n}\n.settings-container > *[data-v-25cfa24c] {\r\n margin: 0 2px;\r\n cursor: pointer;\n}\n#info-bar svg[data-v-25cfa24c] {\r\n font-size: 16px;\n}\n#info-bar .divider[data-v-25cfa24c] {\r\n margin: 0 8px;\n}\nsvg[data-v-25cfa24c]:focus {\r\n border: none;\n}\n.visualization-card[data-v-25cfa24c] {\r\n border-left: 8px solid #eee;\n}\n.active-tab[data-v-25cfa24c] {\r\n border-left: 8px solid var(--visualization-primary) !important;\r\n border-image-slice: 1;\n}\n[id^='frame-'][data-v-25cfa24c] {\r\n padding: 1px;\r\n display: flex;\r\n flex-flow: column;\n}\n.tooltip[data-v-25cfa24c] {\r\n display: block !important;\r\n z-index: 10000;\n}\n.tooltip .tooltip-inner[data-v-25cfa24c] {\r\n background: var(--visualization-primary);\r\n color: white;\r\n border-radius: 16px;\r\n padding: 5px 10px 4px;\n}\n.tooltip .tooltip-arrow[data-v-25cfa24c] {\r\n width: 0;\r\n height: 0;\r\n border-style: solid;\r\n position: absolute;\r\n margin: 5px;\r\n border-color: var(--visualization-primary);\r\n z-index: 1;\n}\n.tooltip[x-placement^='top'][data-v-25cfa24c] {\r\n margin-bottom: 5px;\n}\n.tooltip[x-placement^='top'] .tooltip-arrow[data-v-25cfa24c] {\r\n border-width: 5px 5px 0 5px;\r\n border-left-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n bottom: -5px;\r\n left: calc(50% - 5px);\r\n margin-top: 0;\r\n margin-bottom: 0;\n}\n.tooltip[x-placement^='bottom'][data-v-25cfa24c] {\r\n margin-top: 5px;\n}\n.tooltip[x-placement^='bottom'] .tooltip-arrow[data-v-25cfa24c] {\r\n border-width: 0 5px 5px 5px;\r\n border-left-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-top-color: transparent !important;\r\n top: -5px;\r\n left: calc(50% - 5px);\r\n margin-top: 0;\r\n margin-bottom: 0;\n}\n.tooltip[x-placement^='right'][data-v-25cfa24c] {\r\n margin-left: 5px;\n}\n.tooltip[x-placement^='right'] .tooltip-arrow[data-v-25cfa24c] {\r\n border-width: 5px 5px 5px 0;\r\n border-left-color: transparent !important;\r\n border-top-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n left: -5px;\r\n top: calc(50% - 5px);\r\n margin-left: 0;\r\n margin-right: 0;\n}\n.tooltip[x-placement^='left'][data-v-25cfa24c] {\r\n margin-right: 5px;\n}\n.tooltip[x-placement^='left'] .tooltip-arrow[data-v-25cfa24c] {\r\n border-width: 5px 0 5px 5px;\r\n border-top-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n right: -5px;\r\n top: calc(50% - 5px);\r\n margin-left: 0;\r\n margin-right: 0;\n}\n.tooltip.popover .popover-inner[data-v-25cfa24c] {\r\n background: #f9f9f9;\r\n color: black;\r\n padding: 24px;\r\n border-radius: 5px;\r\n box-shadow: 0 5px 30px rgba(black, 0.1);\n}\n.tooltip.popover .popover-arrow[data-v-25cfa24c] {\r\n border-color: #f9f9f9;\n}\n.tooltip[aria-hidden='true'][data-v-25cfa24c] {\r\n visibility: hidden;\r\n opacity: 0;\r\n transition: opacity 0.15s, visibility 0.15s;\n}\n.tooltip[aria-hidden='false'][data-v-25cfa24c] {\r\n visibility: visible;\r\n opacity: 1;\r\n transition: opacity 0.15s;\n}\r\n", map: {"version":3,"sources":["C:\\Workspace\\visualization\\src\\components\\Infos.vue"],"names":[],"mappings":";AA6MA;EACA,aAAA;EACA,eAAA;EACA,cAAA;AACA;AAEA;EACA,aAAA;EACA,YAAA;EACA,eAAA;EACA,aAAA;AACA;AAEA;EACA,cAAA;EACA,cAAA;EACA,WAAA;EACA,eAAA;EACA,UAAA;EACA,mBAAA;EACA,mBAAA;EACA,wBAAA;EACA,iCAAA;EACA,SAAA;AACA;AAEA;EACA,mBAAA;EACA,wBAAA;EACA,oBAAA;EACA,eAAA;EACA,iBAAA;EACA,gBAAA;EACA,cAAA;EACA,2BAAA;EACA,UAAA;AACA;AAEA;EACA,aAAA;EACA,YAAA;EACA,eAAA;EACA,aAAA;EACA,WAAA;EACA,4DAAA;EACA,yBAAA;EACA;qCACA;AACA;AAEA;EAEA,uBAAA;AACA;AAEA;EACA,mBAAA;AACA;AAEA;EACA,0BAAA;EACA,yBAAA;EACA,YAAA;EACA,mBAAA;AACA;AACA;EACA,2BAAA;EACA,eAAA;EACA,WAAA;EACA,gBAAA;EACA,YAAA;AACA;AAEA;;EAEA,yBAAA;EACA;mCACA;AACA;AACA;EACA,WAAA;EACA,YAAA;EACA,YAAA;EACA,gBAAA;AACA;AAEA;EACA,eAAA;EACA,+BAAA;AACA;AAEA;EACA,eAAA;AACA;AAEA;EACA,qBAAA;AACA;AAEA;EACA,YAAA;EACA,eAAA;EACA,kBAAA;AACA;AAEA;EACA,kBAAA;EACA,WAAA;EACA,QAAA;EACA,2BAAA;AACA;AAEA;EACA,aAAA;EACA,eAAA;AACA;AAEA;EACA,eAAA;AACA;AAEA;EACA,aAAA;AACA;AAEA;EACA,YAAA;AACA;AAEA;EACA,2BAAA;AACA;AAEA;EACA,8DAAA;EACA,qBAAA;AACA;AAEA;EACA,YAAA;EACA,aAAA;EACA,iBAAA;AACA;AAEA;EACA,yBAAA;EACA,cAAA;AACA;AAEA;EACA,wCAAA;EACA,YAAA;EACA,mBAAA;EACA,qBAAA;AACA;AAEA;EACA,QAAA;EACA,SAAA;EACA,mBAAA;EACA,kBAAA;EACA,WAAA;EACA,0CAAA;EACA,UAAA;AACA;AAEA;EACA,kBAAA;AACA;AAEA;EACA,2BAAA;EACA,yCAAA;EACA,0CAAA;EACA,2CAAA;EACA,YAAA;EACA,qBAAA;EACA,aAAA;EACA,gBAAA;AACA;AAEA;EACA,eAAA;AACA;AAEA;EACA,2BAAA;EACA,yCAAA;EACA,0CAAA;EACA,wCAAA;EACA,SAAA;EACA,qBAAA;EACA,aAAA;EACA,gBAAA;AACA;AAEA;EACA,gBAAA;AACA;AAEA;EACA,2BAAA;EACA,yCAAA;EACA,wCAAA;EACA,2CAAA;EACA,UAAA;EACA,oBAAA;EACA,cAAA;EACA,eAAA;AACA;AAEA;EACA,iBAAA;AACA;AAEA;EACA,2BAAA;EACA,wCAAA;EACA,0CAAA;EACA,2CAAA;EACA,WAAA;EACA,oBAAA;EACA,cAAA;EACA,eAAA;AACA;AAEA;EACA,mBAAA;EACA,YAAA;EACA,aAAA;EACA,kBAAA;EACA,uCAAA;AACA;AAEA;EACA,qBAAA;AACA;AAEA;EACA,kBAAA;EACA,UAAA;EACA,2CAAA;AACA;AAEA;EACA,mBAAA;EACA,UAAA;EACA,yBAAA;AACA","file":"Infos.vue","sourcesContent":["<template>\r\n <div\r\n id=\"info-bar\"\r\n class=\"visualization-col\"\r\n :style=\"\r\n !commandsShow ? 'border-top-right-radius: 6px; padding: 0' : 'padding: 0'\r\n \"\r\n >\r\n <div\r\n class=\"visualization-row visualization-justify-center visualization-align-center\"\r\n style=\"position: relative; padding: 4px\"\r\n >\r\n <span> {{ playbackRate }}x </span>\r\n <hr class=\"visualization-divider vertical\" style=\"margin: 0 8px\" />\r\n <span>\r\n {{\r\n $t('infoBar.selected', {\r\n seconds: hourEnd && hourIni ? hourEnd - hourIni + 1 : 0,\r\n hour_ini: convertToAudienceTime(hourIni),\r\n hour_end: convertToAudienceTime(hourEnd),\r\n })\r\n }}\r\n </span>\r\n <hr class=\"visualization-divider vertical\" style=\"margin: 0 8px\" />\r\n <span>\r\n {{\r\n $t('infoBar.interval', {\r\n seconds: secondsPerFrame,\r\n })\r\n }}\r\n </span>\r\n <hr class=\"visualization-divider vertical\" style=\"margin: 0 8px\" />\r\n <span>\r\n {{\r\n $t('infoBar.block', {\r\n time1: convertToAudienceTime(blockStartTime),\r\n time2: convertToAudienceTime(blockTotalTime),\r\n })\r\n }}\r\n </span>\r\n <hr class=\"visualization-divider vertical\" style=\"margin: 0 8px\" />\r\n {{ framesPerRow * numberOfRows }}\r\n <hr class=\"visualization-divider vertical\" style=\"margin: 0 8px\" />\r\n {{ framesPerRow + '*' + numberOfRows }}\r\n <span\r\n class=\"visualization-divider vertical\"\r\n v-if=\"!cache\"\r\n style=\"margin: 0 8px\"\r\n />\r\n <span v-if=\"!cache\">\r\n <font-awesome-icon\r\n icon=\"fa-solid fa-exclamation-circle\"\r\n style=\"margin: 0 4px\"\r\n />\r\n <strong>{{ $t('infoBar.notUsingCache') }}</strong>\r\n </span>\r\n \r\n <div class=\"settings-container\">\r\n <font-awesome-icon\r\n v-show=\"showStretchFrame\"\r\n :icon=\"!stretchFrames ? ['fas', 'fa-maximize'] : ['fas', 'fa-minimize']\"\r\n @click=\"stretchFrames = !stretchFrames; $emit('update-stretch-frames', stretchFrames)\"\r\n v-tooltip=\"$t('infoBar.stretchFrames')\"\r\n />\r\n <font-awesome-icon\r\n icon=\"fa-solid fa-server\"\r\n @click=\"$emit('change-server')\"\r\n v-tooltip=\"\r\n alternativeServer\r\n ? $t('infoBar.changeServer')\r\n : $t('infoBar.changeServer')\r\n \"\r\n />\r\n <font-awesome-icon\r\n :icon=\"commandsShow ? 'fa-solid fa-eye' : 'fa-solid fa-eye-slash'\"\r\n @click=\"$emit('toogle-commands-visibility')\"\r\n v-tooltip=\"\r\n commandsShow\r\n ? $t('moduletelentry.showButtons')\r\n : $t('moduletelentry.hideButtons')\r\n \"\r\n />\r\n <font-awesome-icon\r\n :icon=\"cache ? 'fa-solid fa-ban' : 'fa-solid fa-sync'\"\r\n @click=\"$emit('toogle-cache')\"\r\n v-tooltip=\"\r\n cache ? $t('infoBar.disableCache') : $t('infoBar.activateCache')\r\n \"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div\r\n v-if=\"alternativeServer\"\r\n class=\"visualization-row visualization-justify-center visualization-align-center\"\r\n style=\"\r\n color: white;\r\n background-color: orange;\r\n font-weight: bold;\r\n padding: 4px;\r\n \"\r\n >\r\n {{ $t('infoBar.alternativeServer') }}\r\n <font-awesome-icon\r\n icon=\"fa-solid fa-exclamation-triangle\"\r\n style=\"margin: 0 4px\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n<script>\r\nexport default {\r\n props: {\r\n playbackRate: {\r\n type: Number,\r\n required: true,\r\n },\r\n secondsPerFrame: {\r\n type: Number,\r\n required: true,\r\n },\r\n commandsShow: {\r\n type: Boolean,\r\n required: true,\r\n },\r\n cache: {\r\n type: Boolean,\r\n required: true,\r\n },\r\n blockStartTime: {\r\n type: Number,\r\n required: true,\r\n },\r\n videoTotalDuration: {\r\n type: Number,\r\n required: true,\r\n },\r\n alternativeServer: {\r\n type: Boolean,\r\n required: true,\r\n },\r\n framesPerRow: {\r\n type: Number,\r\n required: true,\r\n },\r\n numberOfRows: {\r\n type: Number,\r\n required: true,\r\n },\r\n hourIni: {\r\n type: [Number, Boolean],\r\n },\r\n hourEnd: {\r\n type: [Number, Boolean],\r\n },\r\n showStretchFrame: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n \r\n },\r\n data() {\r\n return {\r\n stretchFrames: false,\r\n }\r\n },\r\n computed: {\r\n blockTotalTime() {\r\n return this.videoTotalDuration + this.blockStartTime\r\n },\r\n },\r\n methods: {\r\n convertToAudienceTime(time, separator = ':') {\r\n const limit = Date.UTC(null, null, null, 23, 59, 59) / 1000\r\n\r\n let hour = this.dateInUtc(time * 1000)\r\n .toTimeString()\r\n .split(' ')[0]\r\n .split(':')\r\n .map(Number)\r\n\r\n if (time > limit && time <= limit + this.startAudienceSeconds) {\r\n hour[0] = 24 + hour[0]\r\n }\r\n return hour\r\n .map((part) => (part > 9 ? part.toString() : '0' + part))\r\n .join(separator)\r\n },\r\n\r\n dateInUtc(miliSeconds) {\r\n var date = new Date(miliSeconds)\r\n var utc = new Date(\r\n date.getUTCFullYear(),\r\n date.getUTCMonth(),\r\n date.getUTCDate(),\r\n date.getUTCHours(),\r\n date.getUTCMinutes(),\r\n date.getUTCSeconds()\r\n )\r\n return utc\r\n },\r\n },\r\n}\r\n</script>\r\n<style scoped>\r\n.visualization-row {\r\n display: flex;\r\n flex-wrap: wrap;\r\n flex: 1 1 auto;\r\n}\r\n\r\n.visualization-col {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\r\n}\r\n\r\n.visualization-divider {\r\n display: block;\r\n flex: 1 1 100%;\r\n height: 0px;\r\n max-height: 0px;\r\n opacity: 1;\r\n transition: inherit;\r\n border-style: solid;\r\n border-width: thin 0 0 0;\r\n border-color: rgba(0, 0, 0, 0.12);\r\n margin: 0;\r\n}\r\n\r\n.visualization-divider.vertical {\r\n align-self: stretch;\r\n border-width: 0 thin 0 0;\r\n display: inline-flex;\r\n height: inherit;\r\n margin-left: -1px;\r\n max-height: 100%;\r\n max-width: 0px;\r\n vertical-align: text-bottom;\r\n width: 0px;\r\n}\r\n\r\n.visualization-card {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\r\n width: 100%;\r\n transition-property: box-shadow, opacity, -webkit-box-shadow;\r\n overflow-wrap: break-word;\r\n /*box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);*/\r\n}\r\n\r\n.visualization-justify-center,\r\n/deep/ .visualization-justify-center {\r\n justify-content: center;\r\n}\r\n\r\n.visualization-align-center {\r\n align-items: center;\r\n}\r\n\r\n#visualization-container {\r\n max-width: 100% !important;\r\n margin: 0 auto !important;\r\n height: 100%;\r\n border-bottom: none;\r\n}\r\n#visualization-container > .card {\r\n border-radius: 0 !important;\r\n font-size: 12px;\r\n width: 100%;\r\n box-shadow: none;\r\n height: 100%;\r\n}\r\n\r\n#command-bar,\r\n#info-bar {\r\n background-color: #f5f5f5;\r\n box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);\r\n}\r\n#command-bar button {\r\n width: 42px;\r\n height: 36px;\r\n border: none;\r\n background: none;\r\n}\r\n\r\n#command-bar button:hover {\r\n cursor: pointer;\r\n background: rgba(0, 0, 0, 0.12);\r\n}\r\n\r\n#command-bar svg {\r\n font-size: 16px;\r\n}\r\n\r\n#command-bar {\r\n padding: 0 !important;\r\n}\r\n\r\n#info-bar {\r\n padding: 4px;\r\n font-size: 14px;\r\n position: relative;\r\n}\r\n\r\n.settings-container {\r\n position: absolute;\r\n right: 14px;\r\n top: 50%;\r\n transform: translateY(-50%);\r\n}\r\n\r\n.settings-container > * {\r\n margin: 0 2px;\r\n cursor: pointer;\r\n}\r\n\r\n#info-bar svg {\r\n font-size: 16px;\r\n}\r\n\r\n#info-bar .divider {\r\n margin: 0 8px;\r\n}\r\n\r\nsvg:focus {\r\n border: none;\r\n}\r\n\r\n.visualization-card {\r\n border-left: 8px solid #eee;\r\n}\r\n\r\n.active-tab {\r\n border-left: 8px solid var(--visualization-primary) !important;\r\n border-image-slice: 1;\r\n}\r\n\r\n[id^='frame-'] {\r\n padding: 1px;\r\n display: flex;\r\n flex-flow: column;\r\n}\r\n\r\n.tooltip {\r\n display: block !important;\r\n z-index: 10000;\r\n}\r\n\r\n.tooltip .tooltip-inner {\r\n background: var(--visualization-primary);\r\n color: white;\r\n border-radius: 16px;\r\n padding: 5px 10px 4px;\r\n}\r\n\r\n.tooltip .tooltip-arrow {\r\n width: 0;\r\n height: 0;\r\n border-style: solid;\r\n position: absolute;\r\n margin: 5px;\r\n border-color: var(--visualization-primary);\r\n z-index: 1;\r\n}\r\n\r\n.tooltip[x-placement^='top'] {\r\n margin-bottom: 5px;\r\n}\r\n\r\n.tooltip[x-placement^='top'] .tooltip-arrow {\r\n border-width: 5px 5px 0 5px;\r\n border-left-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n bottom: -5px;\r\n left: calc(50% - 5px);\r\n margin-top: 0;\r\n margin-bottom: 0;\r\n}\r\n\r\n.tooltip[x-placement^='bottom'] {\r\n margin-top: 5px;\r\n}\r\n\r\n.tooltip[x-placement^='bottom'] .tooltip-arrow {\r\n border-width: 0 5px 5px 5px;\r\n border-left-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-top-color: transparent !important;\r\n top: -5px;\r\n left: calc(50% - 5px);\r\n margin-top: 0;\r\n margin-bottom: 0;\r\n}\r\n\r\n.tooltip[x-placement^='right'] {\r\n margin-left: 5px;\r\n}\r\n\r\n.tooltip[x-placement^='right'] .tooltip-arrow {\r\n border-width: 5px 5px 5px 0;\r\n border-left-color: transparent !important;\r\n border-top-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n left: -5px;\r\n top: calc(50% - 5px);\r\n margin-left: 0;\r\n margin-right: 0;\r\n}\r\n\r\n.tooltip[x-placement^='left'] {\r\n margin-right: 5px;\r\n}\r\n\r\n.tooltip[x-placement^='left'] .tooltip-arrow {\r\n border-width: 5px 0 5px 5px;\r\n border-top-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n right: -5px;\r\n top: calc(50% - 5px);\r\n margin-left: 0;\r\n margin-right: 0;\r\n}\r\n\r\n.tooltip.popover .popover-inner {\r\n background: #f9f9f9;\r\n color: black;\r\n padding: 24px;\r\n border-radius: 5px;\r\n box-shadow: 0 5px 30px rgba(black, 0.1);\r\n}\r\n\r\n.tooltip.popover .popover-arrow {\r\n border-color: #f9f9f9;\r\n}\r\n\r\n.tooltip[aria-hidden='true'] {\r\n visibility: hidden;\r\n opacity: 0;\r\n transition: opacity 0.15s, visibility 0.15s;\r\n}\r\n\r\n.tooltip[aria-hidden='false'] {\r\n visibility: visible;\r\n opacity: 1;\r\n transition: opacity 0.15s;\r\n}\r\n</style>\r\n"]}, media: undefined });
2610
2701
 
2611
2702
  };
2612
2703
  /* scoped */
2613
- const __vue_scope_id__$3 = "data-v-848911da";
2704
+ const __vue_scope_id__$3 = "data-v-25cfa24c";
2614
2705
  /* module identifier */
2615
2706
  const __vue_module_identifier__$3 = undefined;
2616
2707
  /* functional template */
@@ -2842,6 +2933,8 @@ var GridImages = {
2842
2933
  'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1NTguMiAxODMuNiIgIHhtbG5zOnY9Imh0dHBzOi8vdmVjdGEuaW8vbmFubyI+PHBhdGggZD0iTTU1OC4yIDB2OTAuMWgtODguNWMtMS42IDAtMS42IDAtMS42LTEuNlYxLjdjMC0xLjYgMC0xLjYgMS42LTEuNmw4OC41LS4xeiIgZmlsbD0iIzE1NjVjMCIvPjxwYXRoIGQ9Ik05MC4yIDE4My41SDBWOTUuMWMwLTEuNyAwLTEuNyAxLjctMS43aDg2LjdjMS44IDAgMS44IDAgMS44IDEuOHY4OC4zem05My42IDBIOTMuNlY5NS4zYzAtMS45IDAtMS45IDEuOS0xLjlIMTgyYzEuOCAwIDEuOCAwIDEuOCAxLjh2ODguM3ptMjgwLjkgMGgtOTAuMlY5NS4xYzAtMS43IDAtMS43IDEuNi0xLjdINDYzYzEuNiAwIDEuNiAwIDEuNiAxLjd2NjQuMWwuMSAyNC4zem05My41LTkwdjg5YzAgLjktLjIgMS4xLTEuMSAxLjFINDY4Vjk1LjJjMC0xLjcgMC0xLjcgMS43LTEuN2g4OC41em0tMjgwLjkgOTBoLTkwVjk0LjhjMC0uOS4xLTEuNSAxLjItMS41SDI3NmMuOSAwIDEuMi4zIDEuMiAxLjJsLjEgODl6bTkzLjYgMGgtOTBWOTUuMWMwLTEuNyAwLTEuNyAxLjctMS43aDg2LjVjMS44IDAgMS44IDAgMS44IDEuOHY4OC4zeiIgZmlsbD0iI2NiY2JjYiIvPjxwYXRoIGQ9Ik0wIDQ1LjFWMS41QzAgLjMuMyAwIDEuNCAwaDg3LjNjMS4yIDAgMS41LjMgMS40IDEuNXY4Ny4xYzAgMS4yLS4zIDEuNS0xLjUgMS41SDEuNGMtMS4zIDAtMS41LS40LTEuNS0xLjZMMCA0NS4xem05My42LS4xVjEuNUM5My42LjMgOTMuOSAwIDk1IDBoODcuM2MxLjIgMCAxLjQuMyAxLjQgMS41djg3LjJjMCAxLjItLjQgMS40LTEuNSAxLjRIOTVjLTEuMiAwLTEuNS0uNC0xLjUtMS41bC4xLTQzLjZ6TTQxOS43IDBoNDMuNGMxLjIgMCAxLjYuMiAxLjYgMS41djg3LjFjMCAxLjItLjMgMS41LTEuNSAxLjVIMzc2Yy0xLjEgMC0xLjUtLjMtMS41LTEuNFYxLjVjMC0xLjIuMy0xLjQgMS41LTEuNGw0My43LS4xek0yNzcuMyA0NS4xdjQzLjNjMCAxLjYgMCAxLjYtMS42IDEuNmgtODYuOGMtMS43IDAtMS43IDAtMS43LTEuNlYxLjVjMC0xLjIuMy0xLjUgMS41LTEuNWg4Ny4yYzEuMiAwIDEuNC40IDEuNCAxLjV2NDMuNnptMy42LS4yVjEuNGMwLTEuMS4zLTEuNSAxLjQtMS41aDg3LjJjMS4zIDAgMS41LjQgMS41IDEuNnY4Ni45YzAgMS42IDAgMS42LTEuNSAxLjZoLTg3Yy0xLjEgMC0xLjUtLjMtMS41LTEuNGwtLjEtNDMuN3oiIGZpbGw9IiMxNTY1YzAiLz48L3N2Zz4=',
2843
2934
  '6x2':
2844
2935
  'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyOC4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FtYWRhXzEiIHhtbG5zOnY9Imh0dHBzOi8vdmVjdGEuaW8vbmFubyINCgkgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCA1NTguMiAxODMuNiINCgkgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNTU4LjIgMTgzLjY7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoJLnN0MHtmaWxsOiMxNTY1QzA7fQ0KPC9zdHlsZT4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik01NTguMiwwdjkwLjFoLTg4LjVjLTEuNiwwLTEuNiwwLTEuNi0xLjZWMS43YzAtMS42LDAtMS42LDEuNi0xLjZDNDY5LjcsMC4xLDU1OC4yLDAsNTU4LjIsMHoiLz4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik05MC4yLDE4My41SDBWOTUuMWMwLTEuNywwLTEuNywxLjctMS43aDg2LjdjMS44LDAsMS44LDAsMS44LDEuOFYxODMuNXogTTE4My44LDE4My41SDkzLjZWOTUuMw0KCWMwLTEuOSwwLTEuOSwxLjktMS45SDE4MmMxLjgsMCwxLjgsMCwxLjgsMS44TDE4My44LDE4My41TDE4My44LDE4My41eiBNNDY0LjcsMTgzLjVoLTkwLjJWOTUuMWMwLTEuNywwLTEuNywxLjYtMS43SDQ2Mw0KCWMxLjYsMCwxLjYsMCwxLjYsMS43djY0LjFMNDY0LjcsMTgzLjVMNDY0LjcsMTgzLjV6IE01NTguMiw5My41djg5YzAsMC45LTAuMiwxLjEtMS4xLDEuMUg0NjhWOTUuMmMwLTEuNywwLTEuNywxLjctMS43SDU1OC4yDQoJTDU1OC4yLDkzLjV6IE0yNzcuMywxODMuNWgtOTBWOTQuOGMwLTAuOSwwLjEtMS41LDEuMi0xLjVIMjc2YzAuOSwwLDEuMiwwLjMsMS4yLDEuMkwyNzcuMywxODMuNUwyNzcuMywxODMuNXogTTM3MC45LDE4My41aC05MA0KCVY5NS4xYzAtMS43LDAtMS43LDEuNy0xLjdoODYuNWMxLjgsMCwxLjgsMCwxLjgsMS44VjE4My41eiIvPg0KPHBhdGggY2xhc3M9InN0MCIgZD0iTTAsNDUuMVYxLjVDMCwwLjMsMC4zLDAsMS40LDBoODcuM2MxLjIsMCwxLjUsMC4zLDEuNCwxLjV2ODcuMWMwLDEuMi0wLjMsMS41LTEuNSwxLjVIMS40DQoJYy0xLjMsMC0xLjUtMC40LTEuNS0xLjZMMCw0NS4xeiBNOTMuNiw0NVYxLjVDOTMuNiwwLjMsOTMuOSwwLDk1LDBoODcuM2MxLjIsMCwxLjQsMC4zLDEuNCwxLjV2ODcuMmMwLDEuMi0wLjQsMS40LTEuNSwxLjRIOTUNCgljLTEuMiwwLTEuNS0wLjQtMS41LTEuNUw5My42LDQ1eiBNNDE5LjcsMGg0My40YzEuMiwwLDEuNiwwLjIsMS42LDEuNXY4Ny4xYzAsMS4yLTAuMywxLjUtMS41LDEuNUgzNzZjLTEuMSwwLTEuNS0wLjMtMS41LTEuNFYxLjUNCgljMC0xLjIsMC4zLTEuNCwxLjUtMS40QzM3NiwwLjEsNDE5LjcsMCw0MTkuNywweiBNMjc3LjMsNDUuMXY0My4zYzAsMS42LDAsMS42LTEuNiwxLjZoLTg2LjhjLTEuNywwLTEuNywwLTEuNy0xLjZWMS41DQoJYzAtMS4yLDAuMy0xLjUsMS41LTEuNWg4Ny4yYzEuMiwwLDEuNCwwLjQsMS40LDEuNUwyNzcuMyw0NS4xTDI3Ny4zLDQ1LjF6IE0yODAuOSw0NC45VjEuNGMwLTEuMSwwLjMtMS41LDEuNC0xLjVoODcuMg0KCWMxLjMsMCwxLjUsMC40LDEuNSwxLjZ2ODYuOWMwLDEuNiwwLDEuNi0xLjUsMS42aC04N2MtMS4xLDAtMS41LTAuMy0xLjUtMS40TDI4MC45LDQ0Ljl6Ii8+DQo8L3N2Zz4NCg==',
2936
+ custom:
2937
+ 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgNTU4LjIgMTgzLjYiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDU1OC4yIDE4My42OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2ZpbGw6IzE1NjVDMDt9Cgkuc3Qxe2ZpbGw6bm9uZTtzdHJva2U6IzE1NjVDMDtzdHJva2Utd2lkdGg6Nzt9Cgkuc3Qye2ZpbGw6I0NDQ0NDQzt9Cjwvc3R5bGU+CjwhLS0gR3JleSBzcXVhcmVzIGluIHRvcCByb3cgd2l0aCAxMHB4IHBhZGRpbmcgLS0+CjxyZWN0IHg9IjEwIiB5PSIxMCIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBjbGFzcz0ic3QyIi8+CjxyZWN0IHg9IjEwMy42IiB5PSIxMCIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBjbGFzcz0ic3QyIi8+CjxyZWN0IHg9IjE5Ny4yIiB5PSIxMCIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBjbGFzcz0ic3QyIi8+CjxyZWN0IHg9IjI5MC45IiB5PSIxMCIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBjbGFzcz0ic3QyIi8+CjxyZWN0IHg9IjM4NC41IiB5PSIxMCIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBjbGFzcz0ic3QyIi8+CjxyZWN0IHg9IjQ3OCIgeT0iMTAiIHdpZHRoPSI3MC4yIiBoZWlnaHQ9IjgwIiBjbGFzcz0ic3QyIi8+Cgo8IS0tIEdyZXkgc3F1YXJlcyBpbiBib3R0b20gcm93IHdpdGggMTBweCBwYWRkaW5nIC0tPgo8cmVjdCB4PSIxMCIgeT0iOTMuNiIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBjbGFzcz0ic3QyIi8+CjxyZWN0IHg9IjEwMy42IiB5PSI5My42IiB3aWR0aD0iODAiIGhlaWdodD0iODAiIGNsYXNzPSJzdDIiLz4KPHJlY3QgeD0iMTk3LjIiIHk9IjkzLjYiIHdpZHRoPSI4MCIgaGVpZ2h0PSI4MCIgY2xhc3M9InN0MiIvPgo8cmVjdCB4PSIyOTAuOSIgeT0iOTMuNiIgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiBjbGFzcz0ic3QyIi8+CjxyZWN0IHg9IjM4NC41IiB5PSI5My42IiB3aWR0aD0iODAiIGhlaWdodD0iODAiIGNsYXNzPSJzdDIiLz4KPHJlY3QgeD0iNDc4IiB5PSI5My42IiB3aWR0aD0iNzAuMiIgaGVpZ2h0PSI4MCIgY2xhc3M9InN0MiIvPgoKPCEtLSBCb3JkZXIgLS0+CjxyZWN0IHg9IjEuNSIgeT0iMS41IiB3aWR0aD0iNTU1LjIiIGhlaWdodD0iMTgwLjYiIGNsYXNzPSJzdDEiLz4KCjwhLS0gVGV4dCAtLT4KPHRleHQgeD0iNTAlIiB5PSI1MCUiIGRvbWluYW50LWJhc2VsaW5lPSJtaWRkbGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGNsYXNzPSJzdDAiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSI3MiIgZm9udC13ZWlnaHQ9ImJvbGQiPmN1c3RvbTwvdGV4dD4KPC9zdmc+',
2845
2938
  };
2846
2939
 
2847
2940
  //
@@ -2876,10 +2969,14 @@ var script$1 = {
2876
2969
  type: Number,
2877
2970
  default: 1,
2878
2971
  },
2879
- maxShift: {
2972
+ maxShift: {
2880
2973
  type: Number,
2881
2974
  default: 20,
2882
2975
  },
2976
+ customGridSize: {
2977
+ type: Boolean,
2978
+ default: false,
2979
+ },
2883
2980
  },
2884
2981
  data() {
2885
2982
  return {
@@ -2891,7 +2988,8 @@ var script$1 = {
2891
2988
  date: null,
2892
2989
  },
2893
2990
  shiftFramesValue: this.shiftFrames,
2894
- items: [
2991
+
2992
+ /* items: [
2895
2993
  { text: '1x1', value: 1, image: GridImages['1x1'] },
2896
2994
  { text: '2x1', value: 2, image: GridImages['2x1'] },
2897
2995
  { text: '3x1', value: 3, image: GridImages['3x1'] },
@@ -2902,19 +3000,58 @@ var script$1 = {
2902
3000
  { text: '5x2', value: 8, image: GridImages['5x2'] },
2903
3001
  { text: '6x1', value: 9, image: GridImages['6x1'] },
2904
3002
  { text: '6x2', value: 10, image: GridImages['6x2'] },
2905
- ],
3003
+ {
3004
+ text: 'custom',
3005
+ value: 11,
3006
+ image: GridImages['custom'],
3007
+ },
3008
+ ], */
2906
3009
  debouncedShiftFrames: null,
2907
3010
  // NEW
2908
3011
  goToValue: '',
3012
+ customNumberOfRows: this.numberOfRows,
3013
+ customFramesPerRow: this.framesPerRow,
3014
+ showCustomInputs: false,
3015
+ isCustomMode: false,
2909
3016
  }
2910
3017
  },
2911
3018
  mounted() {
2912
3019
  this.debouncedShiftFrames = debounce(function () {
2913
3020
  this.$emit('change-shift-frames', parseInt(this.shiftFramesValue));
2914
3021
  }, 350);
3022
+ this.customNumberOfRows = this.numberOfRows;
3023
+ this.customFramesPerRow = this.framesPerRow;
3024
+ if (this.framesValue === 11) {
3025
+ this.isCustomMode = true;
3026
+ this.showCustomInputs = true;
3027
+ }
2915
3028
  this.toogleDialogs();
2916
3029
  },
2917
3030
  computed: {
3031
+ items() {
3032
+ const baseItems = [
3033
+ { text: '1x1', value: 1, image: GridImages['1x1'] },
3034
+ { text: '2x1', value: 2, image: GridImages['2x1'] },
3035
+ { text: '3x1', value: 3, image: GridImages['3x1'] },
3036
+ { text: '3x2', value: 4, image: GridImages['3x2'] },
3037
+ { text: '4x1', value: 5, image: GridImages['4x1'] },
3038
+ { text: '4x2', value: 6, image: GridImages['4x2'] },
3039
+ { text: '5x1', value: 7, image: GridImages['5x1'] },
3040
+ { text: '5x2', value: 8, image: GridImages['5x2'] },
3041
+ { text: '6x1', value: 9, image: GridImages['6x1'] },
3042
+ { text: '6x2', value: 10, image: GridImages['6x2'] },
3043
+ ];
3044
+
3045
+ if (this.customGridSize) {
3046
+ baseItems.push({
3047
+ text: 'custom',
3048
+ value: 11,
3049
+ image: GridImages['custom'],
3050
+ });
3051
+ }
3052
+
3053
+ return baseItems
3054
+ },
2918
3055
  isOpen() {
2919
3056
  return !!Object.keys(this.dialogsVisibility).find(
2920
3057
  (key) => this.dialogsVisibility[key]
@@ -2940,12 +3077,33 @@ var script$1 = {
2940
3077
  },
2941
3078
  framesValue: {
2942
3079
  get() {
2943
- return this.items.find(
2944
- (item) => item.text === `${this.framesPerRow}x${this.numberOfRows}`
2945
- ).value
3080
+ if (this.isCustomMode) {
3081
+ return 11
3082
+ }
3083
+ const preset = this.items.find(
3084
+ (item) =>
3085
+ item.value !== 11 &&
3086
+ item.text === `${this.framesPerRow}x${this.numberOfRows}`
3087
+ );
3088
+
3089
+ return preset ? preset.value : 11
2946
3090
  },
2947
3091
  set(value) {
2948
- this.$emit('set-frames-selection', value);
3092
+ if (parseInt(value) === 11) {
3093
+ this.isCustomMode = true;
3094
+ this.showCustomInputs = true;
3095
+
3096
+ this.$nextTick(() => {
3097
+ this.$emit('set-custom-grid-values', [
3098
+ parseInt(this.customNumberOfRows),
3099
+ parseInt(this.customFramesPerRow),
3100
+ ]);
3101
+ });
3102
+ } else {
3103
+ this.isCustomMode = false;
3104
+ this.showCustomInputs = false;
3105
+ this.$emit('set-frames-selection', value);
3106
+ }
2949
3107
  },
2950
3108
  },
2951
3109
  timeRules() {
@@ -3031,6 +3189,25 @@ var script$1 = {
3031
3189
  this.openBlocksDialog = false;
3032
3190
  this.$emit('goToBlockInterval', this.rangeBlocks);
3033
3191
  },
3192
+ checkIfCustomGrid() {
3193
+ const hasPreset = this.items.some(
3194
+ (item) =>
3195
+ item.value !== 11 &&
3196
+ item.text === `${this.framesPerRow}x${this.numberOfRows}`
3197
+ );
3198
+
3199
+ if (!hasPreset) {
3200
+ this.showCustomInputs = true;
3201
+ this.customNumberOfRows = this.numberOfRows;
3202
+ this.customFramesPerRow = this.framesPerRow;
3203
+ }
3204
+ },
3205
+ validateCustomInput(value, max = 10) {
3206
+ const num = parseInt(value);
3207
+ if (isNaN(num) || num < 1) return 1
3208
+ if (num > max) return max
3209
+ return num
3210
+ },
3034
3211
  },
3035
3212
  watch: {
3036
3213
  dialogsVisibility: {
@@ -3039,6 +3216,35 @@ var script$1 = {
3039
3216
  },
3040
3217
  deep: true,
3041
3218
  },
3219
+ customFramesPerRow(newVal) {
3220
+ if (this.isCustomMode && newVal && parseInt(newVal) > 0) {
3221
+ this.$emit('set-custom-grid-values', [
3222
+ parseInt(this.customNumberOfRows),
3223
+ parseInt(newVal),
3224
+ ]);
3225
+ }
3226
+ },
3227
+
3228
+ customNumberOfRows(newVal) {
3229
+ if (this.isCustomMode && newVal && parseInt(newVal) > 0) {
3230
+ this.$emit('set-custom-grid-values', [
3231
+ parseInt(newVal),
3232
+ parseInt(this.customFramesPerRow),
3233
+ ]);
3234
+ }
3235
+ },
3236
+
3237
+ numberOfRows(newVal) {
3238
+ if (!this.isCustomMode) {
3239
+ this.customNumberOfRows = newVal;
3240
+ }
3241
+ },
3242
+
3243
+ framesPerRow(newVal) {
3244
+ if (!this.isCustomMode) {
3245
+ this.customFramesPerRow = newVal;
3246
+ }
3247
+ },
3042
3248
  },
3043
3249
  };
3044
3250
 
@@ -3151,6 +3357,102 @@ var __vue_render__$1 = function () {
3151
3357
  0
3152
3358
  ),
3153
3359
  _vm._v(" "),
3360
+ _vm.showCustomInputs
3361
+ ? _c(
3362
+ "div",
3363
+ {
3364
+ staticStyle: {
3365
+ display: "flex",
3366
+ "justify-content": "center",
3367
+ "align-items": "center",
3368
+ color: "#333",
3369
+ gap: "8px",
3370
+ },
3371
+ },
3372
+ [
3373
+ _c("span", [
3374
+ _c("input", {
3375
+ directives: [
3376
+ {
3377
+ name: "model",
3378
+ rawName: "v-model.number",
3379
+ value: _vm.customFramesPerRow,
3380
+ expression: "customFramesPerRow",
3381
+ modifiers: { number: true },
3382
+ },
3383
+ ],
3384
+ staticStyle: {
3385
+ height: "30px",
3386
+ width: "50px",
3387
+ border: "0.1px solid #c2c9d6",
3388
+ "border-radius": "3px",
3389
+ padding: "3px",
3390
+ },
3391
+ attrs: {
3392
+ type: "number",
3393
+ min: "1",
3394
+ max: "15",
3395
+ placeholder: _vm.customFramesPerRow,
3396
+ },
3397
+ domProps: { value: _vm.customFramesPerRow },
3398
+ on: {
3399
+ input: function ($event) {
3400
+ if ($event.target.composing) {
3401
+ return
3402
+ }
3403
+ _vm.customFramesPerRow = _vm._n($event.target.value);
3404
+ },
3405
+ blur: function ($event) {
3406
+ return _vm.$forceUpdate()
3407
+ },
3408
+ },
3409
+ }),
3410
+ _vm._v("\n Frames por"),
3411
+ ]),
3412
+ _vm._v(" "),
3413
+ _c("span", [
3414
+ _c("input", {
3415
+ directives: [
3416
+ {
3417
+ name: "model",
3418
+ rawName: "v-model.number",
3419
+ value: _vm.customNumberOfRows,
3420
+ expression: "customNumberOfRows",
3421
+ modifiers: { number: true },
3422
+ },
3423
+ ],
3424
+ staticStyle: {
3425
+ height: "30px",
3426
+ width: "50px",
3427
+ border: "0.1px solid #c2c9d6",
3428
+ "border-radius": "3px",
3429
+ padding: "5px",
3430
+ },
3431
+ attrs: {
3432
+ type: "number",
3433
+ min: "1",
3434
+ max: "10",
3435
+ placeholder: _vm.customNumberOfRows,
3436
+ },
3437
+ domProps: { value: _vm.customNumberOfRows },
3438
+ on: {
3439
+ input: function ($event) {
3440
+ if ($event.target.composing) {
3441
+ return
3442
+ }
3443
+ _vm.customNumberOfRows = _vm._n($event.target.value);
3444
+ },
3445
+ blur: function ($event) {
3446
+ return _vm.$forceUpdate()
3447
+ },
3448
+ },
3449
+ }),
3450
+ _vm._v("\n Linhas"),
3451
+ ]),
3452
+ ]
3453
+ )
3454
+ : _vm._e(),
3455
+ _vm._v(" "),
3154
3456
  _c("div", { staticClass: "visualization-divider" }),
3155
3457
  _vm._v(" "),
3156
3458
  _c(
@@ -3730,11 +4032,11 @@ __vue_render__$1._withStripped = true;
3730
4032
  /* style */
3731
4033
  const __vue_inject_styles__$1 = function (inject) {
3732
4034
  if (!inject) return
3733
- inject("data-v-2212eda6_0", { source: "\ndialog[data-v-2212eda6] {\r\n max-width: 60vw;\r\n /* padding: 12px; */\r\n border: none;\r\n background: white;\r\n border-radius: 6px;\r\n box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);\r\n position: fixed;\r\n top: 50%;\r\n left: 50%;\r\n transform: translateY(-50%) translateX(-50%);\n}\n.visualization-row[data-v-2212eda6] {\r\n display: flex;\r\n flex-wrap: wrap;\r\n flex: 1 1 auto;\n}\n.visualization-col[data-v-2212eda6] {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\n}\r\n", map: {"version":3,"sources":["C:\\Workspace\\visualization\\src\\components\\Settings.vue"],"names":[],"mappings":";AAgjBA;EACA,eAAA;EACA,mBAAA;EACA,YAAA;EACA,iBAAA;EACA,kBAAA;EACA;mCACA;EACA,eAAA;EACA,QAAA;EACA,SAAA;EACA,4CAAA;AACA;AACA;EACA,aAAA;EACA,eAAA;EACA,cAAA;AACA;AAEA;EACA,aAAA;EACA,YAAA;EACA,eAAA;EACA,aAAA;AACA","file":"Settings.vue","sourcesContent":["<template>\r\n <div>\r\n <GlobalEvents v-if=\"isOpen\" @keydown.27=\"close\" @keydown.13=\"close\" />\r\n <GlobalEvents\r\n v-if=\"dialogsVisibility.frames\"\r\n @keydown.37=\"prevFormat\"\r\n @keydown.39=\"nextFormat\"\r\n />\r\n <!-- Formato da grelha -->\r\n <dialog ref=\"frames\">\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n padding: 5px;\r\n font-weight: bold;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n height: 40px;\r\n color: white;\r\n display: flex;\r\n justify-content: center;\r\n padding-top: 10px;\r\n \"\r\n >\r\n {{ $t('infoBar.gridForm') }}\r\n </div>\r\n <div class=\"visualization-row\" style=\"justify-content: center\">\r\n <div\r\n v-for=\"(item, index) in items\"\r\n :key=\"index\"\r\n class=\"visualization-col\"\r\n style=\"min-width: 200px; max-width: 200px\"\r\n >\r\n <img\r\n @click=\"() => (framesValue = item.value)\"\r\n :src=\"`data:image/svg+xml;base64,${item.image}`\"\r\n width=\"100%\"\r\n :style=\"framesValue !== item.value ? 'filter: grayscale(1)' : ''\"\r\n />\r\n </div>\r\n </div>\r\n <div class=\"visualization-divider\" />\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n display: flex;\r\n justify-content: center;\r\n margin-top: 10px;\r\n margin-bottom: 10px;\r\n \"\r\n >\r\n <button\r\n style=\"\r\n border-radius: 4px;\r\n height: 35px;\r\n width: 70px;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n color: white;\r\n \"\r\n @click=\"$emit('close', 'frames')\"\r\n >\r\n Ok\r\n </button>\r\n </div>\r\n </dialog>\r\n\r\n <!-- Frequencia das Imagens -->\r\n <dialog ref=\"secondsPerFrame\">\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n padding: 5px;\r\n font-weight: bold;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n height: 40px;\r\n color: white;\r\n display: flex;\r\n justify-content: center;\r\n padding-top: 10px;\r\n \"\r\n >\r\n {{ $t('infoBar.secondImage') + ' (1-' + maxSteps + ')' }}\r\n </div>\r\n\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n margin: 25px;\r\n display: flex;\r\n align-items: center;\r\n height: 60px;\r\n border-radius: 8px;\r\n padding: 0 20px;\r\n \"\r\n >\r\n <input\r\n ref=\"secondsPerFrameInput\"\r\n v-model.number=\"secondsPerFrameValue\"\r\n type=\"number\"\r\n step=\"1\"\r\n :max=\"maxSteps\"\r\n min=\"1\"\r\n style=\"\r\n height: 40px;\r\n width: 100px;\r\n padding: 5px 10px;\r\n font-size: 16px;\r\n border: 1px solid #ccc;\r\n border-radius: 4px;\r\n box-sizing: border-box;\r\n flex: 1;\r\n \"\r\n @input=\"validateInput\"\r\n />\r\n <span style=\"padding-left: 20px; font-size: 16px; color: #333\">\r\n {{ secondsPerFrame + ' s' }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"visualization-divider\" style=\"margin: 10px\" />\r\n <div\r\n class=\"visualization-row\"\r\n style=\"display: flex; justify-content: center; margin-top: 10px\"\r\n >\r\n <button\r\n style=\"\r\n border-radius: 4px;\r\n height: 35px;\r\n width: 70px;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n color: white;\r\n margin-bottom: 8px;\r\n \"\r\n @click=\"$emit('close', 'secondsPerFrame')\"\r\n >\r\n Ok\r\n </button>\r\n </div>\r\n </dialog>\r\n\r\n <!-- Go To -->\r\n <dialog ref=\"goTo\">\r\n <div\r\n style=\"\r\n padding: 5px;\r\n font-weight: bold;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n height: 35px;\r\n color: white;\r\n display: flex;\r\n justify-content: center;\r\n padding-top: 8px;\r\n \"\r\n >\r\n {{ $t('infoBar.goTo') }}\r\n </div>\r\n <div class=\"visualization-row\" style=\"margin: 25px; height: 20px\">\r\n <input\r\n v-model=\"goToValue\"\r\n type=\"text\"\r\n placeholder=\"hh:mm:ss\"\r\n v-mask=\"'##:##:##'\"\r\n style=\"\r\n height: 30px;\r\n width: 300px;\r\n border: 0.1px solid #c2c9d6;\r\n border-radius: 3px;\r\n padding: 5px;\r\n \"\r\n />\r\n </div>\r\n <div class=\"visualization-divider\" style=\"margin-top: 40px\" />\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n display: flex;\r\n justify-content: center;\r\n margin-top: 10px;\r\n margin-bottom: 10px;\r\n \"\r\n >\r\n <button\r\n style=\"\r\n border-radius: 4px;\r\n height: 35px;\r\n width: 70px;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n color: white;\r\n \"\r\n @click=\"\r\n () => {\r\n $emit('close', 'goTo')\r\n $emit('change-go-to', goToValue)\r\n goToValue = ''\r\n }\r\n \"\r\n >\r\n Ok\r\n </button>\r\n <GlobalEvents\r\n @keydown.13.prevent=\"\r\n () => {\r\n $emit('close', 'goTo')\r\n $emit('change-go-to', goToValue)\r\n goToValue = ''\r\n }\r\n \"\r\n />\r\n </div>\r\n </dialog>\r\n\r\n <!-- Velocidade Reprodução -->\r\n <GlobalEvents\r\n @keydown.107=\"changePlaybackRate(1)\"\r\n @keydown.109=\"changePlaybackRate(-1)\"\r\n />\r\n <dialog ref=\"playbackRate\">\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n padding: 5px;\r\n font-weight: bold;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n height: 35px;\r\n color: white;\r\n display: flex;\r\n justify-content: center;\r\n padding-top: 8px;\r\n \"\r\n >\r\n {{ $t('infoBar.playbackSpeed') }}\r\n </div>\r\n <div\r\n class=\"visualization-row\"\r\n style=\"margin: 25px; height: 20px; width: 380px\"\r\n >\r\n <input\r\n ref=\"playbackRateInput\"\r\n v-model=\"playbackRateValue\"\r\n type=\"range\"\r\n step=\"0.25\"\r\n max=\"3\"\r\n min=\"1\"\r\n style=\"height: 30px; width: 300px\"\r\n />\r\n <span\r\n style=\"padding-left: 20px; padding-right: 20px; font-size: 16px\"\r\n >{{ playbackRate + 'x' }}</span\r\n >\r\n </div>\r\n <div class=\"visualization-divider\" style=\"margin-top: 40px\" />\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n display: flex;\r\n justify-content: center;\r\n margin-top: 10px;\r\n margin-bottom: 10px;\r\n \"\r\n >\r\n <button\r\n @click=\"$emit('close', 'playbackRate')\"\r\n style=\"\r\n border-radius: 4px;\r\n height: 35px;\r\n width: 70px;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n color: white;\r\n \"\r\n >\r\n Ok\r\n </button>\r\n </div>\r\n </dialog>\r\n\r\n <!-- Deslocamento das Imagens -->\r\n <dialog ref=\"shiftFrames\">\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n padding: 5px;\r\n font-weight: bold;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n height: 40px;\r\n color: white;\r\n display: flex;\r\n justify-content: center;\r\n padding-top: 10px;\r\n \"\r\n >\r\n {{ `${$t('infoBar.shiftFrames')} (${maxShift * -1} - ${maxShift})` }}\r\n </div>\r\n\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n margin: 25px;\r\n display: flex;\r\n align-items: center;\r\n height: 60px;\r\n border-radius: 8px;\r\n padding: 0 20px;\r\n \"\r\n >\r\n <input\r\n ref=\"shiftFramesInput\"\r\n v-model.number=\"shiftFramesValue\"\r\n type=\"number\"\r\n step=\"1\"\r\n :max=\"maxShift\"\r\n :min=\"maxShift * -1\"\r\n style=\"\r\n height: 40px;\r\n width: 100px;\r\n padding: 5px 10px;\r\n font-size: 16px;\r\n border: 1px solid #ccc;\r\n border-radius: 4px;\r\n box-sizing: border-box;\r\n flex: 1;\r\n \"\r\n @input=\"validateShift\"\r\n />\r\n <span style=\"padding-left: 20px; font-size: 16px; color: #333\">\r\n {{ shiftFrames + ' s' }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"visualization-divider\" style=\"margin: 10px\" />\r\n <div\r\n class=\"visualization-row\"\r\n style=\"display: flex; justify-content: center; margin-top: 10px\"\r\n >\r\n <button\r\n style=\"\r\n border-radius: 4px;\r\n height: 35px;\r\n width: 70px;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n color: white;\r\n margin-bottom: 8px;\r\n \"\r\n @click=\"$emit('close', 'shiftFrames')\"\r\n >\r\n Ok\r\n </button>\r\n </div>\r\n </dialog>\r\n </div>\r\n</template>\r\n<script>\r\nimport GridImages from '../assets/grid/index.js'\r\nimport { debounce } from 'lodash'\r\n\r\nexport default {\r\n props: {\r\n dialogsVisibility: {\r\n type: Object,\r\n required: false,\r\n },\r\n playbackRate: {\r\n type: Number,\r\n required: true,\r\n },\r\n secondsPerFrame: {\r\n type: Number,\r\n required: true,\r\n },\r\n framesPerRow: {\r\n type: Number,\r\n required: true,\r\n },\r\n numberOfRows: {\r\n type: Number,\r\n required: true,\r\n },\r\n shiftFrames: {\r\n type: Number,\r\n required: true,\r\n },\r\n maxSteps: {\r\n type: Number,\r\n default: 1,\r\n },\r\n maxShift: {\r\n type: Number,\r\n default: 20,\r\n },\r\n },\r\n data() {\r\n return {\r\n openBlocksDialog: false,\r\n time: '',\r\n rangeBlocks: {\r\n ini: null,\r\n end: null,\r\n date: null,\r\n },\r\n shiftFramesValue: this.shiftFrames,\r\n items: [\r\n { text: '1x1', value: 1, image: GridImages['1x1'] },\r\n { text: '2x1', value: 2, image: GridImages['2x1'] },\r\n { text: '3x1', value: 3, image: GridImages['3x1'] },\r\n { text: '3x2', value: 4, image: GridImages['3x2'] },\r\n { text: '4x1', value: 5, image: GridImages['4x1'] },\r\n { text: '4x2', value: 6, image: GridImages['4x2'] },\r\n { text: '5x1', value: 7, image: GridImages['5x1'] },\r\n { text: '5x2', value: 8, image: GridImages['5x2'] },\r\n { text: '6x1', value: 9, image: GridImages['6x1'] },\r\n { text: '6x2', value: 10, image: GridImages['6x2'] },\r\n ],\r\n debouncedShiftFrames: null,\r\n // NEW\r\n goToValue: '',\r\n }\r\n },\r\n mounted() {\r\n this.debouncedShiftFrames = debounce(function () {\r\n this.$emit('change-shift-frames', parseInt(this.shiftFramesValue))\r\n }, 350)\r\n this.toogleDialogs()\r\n },\r\n computed: {\r\n isOpen() {\r\n return !!Object.keys(this.dialogsVisibility).find(\r\n (key) => this.dialogsVisibility[key]\r\n )\r\n },\r\n secondsPerFrameValue: {\r\n get() {\r\n return this.secondsPerFrame\r\n },\r\n set(val) {\r\n if (+val > 0 && +val <= this.maxSteps) {\r\n this.$emit('change-seconds-per-frame', parseInt(val))\r\n }\r\n },\r\n },\r\n playbackRateValue: {\r\n get() {\r\n return this.playbackRate\r\n },\r\n set(val) {\r\n this.$emit('change-playback-rate', parseFloat(val))\r\n },\r\n },\r\n framesValue: {\r\n get() {\r\n return this.items.find(\r\n (item) => item.text === `${this.framesPerRow}x${this.numberOfRows}`\r\n ).value\r\n },\r\n set(value) {\r\n this.$emit('set-frames-selection', value)\r\n },\r\n },\r\n timeRules() {\r\n return [\r\n (time) =>\r\n (time >= '02:30:00' && time <= '26:29:59') ||\r\n this.$i18n.t('form.mustBeBetween'),\r\n ]\r\n },\r\n },\r\n methods: {\r\n validateInput() {\r\n if (parseInt(this.$refs.secondsPerFrameInput.value) < 1) {\r\n this.$refs.secondsPerFrameInput.value = this.secondsPerFrameValue\r\n } else if (\r\n parseInt(this.$refs.secondsPerFrameInput.value) > this.maxSteps\r\n ) {\r\n this.$refs.secondsPerFrameInput.value = this.secondsPerFrameValue\r\n }\r\n },\r\n validateShift() {\r\n if (parseInt(this.shiftFramesValue) < this.maxShift * -1) {\r\n this.shiftFramesValue = this.shiftFrames\r\n } else if (parseInt(this.shiftFramesValue) > this.maxShift) {\r\n this.shiftFramesValue = this.shiftFrames\r\n }\r\n\r\n this.debouncedShiftFrames()\r\n },\r\n close() {\r\n const openDialog = Object.keys(this.dialogsVisibility).find(\r\n (key) => this.dialogsVisibility[key]\r\n )\r\n this.$emit('close', openDialog)\r\n },\r\n toogleDialogs() {\r\n for (const dialog of Object.values(this.$refs)) {\r\n dialog.close?.()\r\n }\r\n\r\n const openDialog = Object.keys(this.dialogsVisibility).find(\r\n (key) => this.dialogsVisibility[key]\r\n )\r\n\r\n if (openDialog) {\r\n this.$refs[openDialog].showModal()\r\n }\r\n },\r\n prevFormat() {\r\n if (this.items.find((format) => format.value === this.framesValue - 1)) {\r\n this.framesValue--\r\n }\r\n },\r\n nextFormat() {\r\n if (this.items.find((format) => format.value === this.framesValue + 1)) {\r\n this.framesValue++\r\n }\r\n },\r\n changePlaybackRate(direction = 1) {\r\n if (direction === 1) {\r\n this.$refs.playbackRateInput.stepUp()\r\n } else if (direction === -1) {\r\n this.$refs.playbackRateInput.stepDown()\r\n }\r\n this.playbackRateValue = this.$refs.playbackRateInput.value\r\n },\r\n closeBlocksDialog() {\r\n Object.entries(this.rangeBlocks).forEach(([key, value]) => {\r\n if (!value || key == 'date') return\r\n var res = value.replace(/\\D/g, '')\r\n if (res.length < 6) {\r\n for (let i = res.length; i < 6; i++) {\r\n res += '0'\r\n }\r\n }\r\n res.match(/.{1,2}/g)\r\n let a = res.substring(0, 2)\r\n let b = res.substring(2, 4)\r\n let c = res.substring(4, 6)\r\n this.rangeBlocks[key] = a + ':' + b + ':' + c\r\n })\r\n\r\n this.openBlocksDialog = false\r\n this.$emit('goToBlockInterval', this.rangeBlocks)\r\n },\r\n },\r\n watch: {\r\n dialogsVisibility: {\r\n handler() {\r\n this.toogleDialogs()\r\n },\r\n deep: true,\r\n },\r\n },\r\n}\r\n</script>\r\n<style scoped>\r\ndialog {\r\n max-width: 60vw;\r\n /* padding: 12px; */\r\n border: none;\r\n background: white;\r\n border-radius: 6px;\r\n box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);\r\n position: fixed;\r\n top: 50%;\r\n left: 50%;\r\n transform: translateY(-50%) translateX(-50%);\r\n}\r\n.visualization-row {\r\n display: flex;\r\n flex-wrap: wrap;\r\n flex: 1 1 auto;\r\n}\r\n\r\n.visualization-col {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\r\n}\r\n</style>\r\n"]}, media: undefined });
4035
+ inject("data-v-6d1063b7_0", { source: "\ndialog[data-v-6d1063b7] {\r\n max-width: 60vw;\r\n /* padding: 12px; */\r\n border: none;\r\n background: white;\r\n border-radius: 6px;\r\n box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);\r\n position: fixed;\r\n top: 50%;\r\n left: 50%;\r\n transform: translateY(-50%) translateX(-50%);\n}\n.visualization-row[data-v-6d1063b7] {\r\n display: flex;\r\n flex-wrap: wrap;\r\n flex: 1 1 auto;\n}\n.visualization-col[data-v-6d1063b7] {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\n}\r\n", map: {"version":3,"sources":["C:\\Workspace\\visualization\\src\\components\\Settings.vue"],"names":[],"mappings":";AAgrBA;EACA,eAAA;EACA,mBAAA;EACA,YAAA;EACA,iBAAA;EACA,kBAAA;EACA;mCACA;EACA,eAAA;EACA,QAAA;EACA,SAAA;EACA,4CAAA;AACA;AACA;EACA,aAAA;EACA,eAAA;EACA,cAAA;AACA;AAEA;EACA,aAAA;EACA,YAAA;EACA,eAAA;EACA,aAAA;AACA","file":"Settings.vue","sourcesContent":["<template>\r\n <div>\r\n <GlobalEvents v-if=\"isOpen\" @keydown.27=\"close\" @keydown.13=\"close\" />\r\n <GlobalEvents\r\n v-if=\"dialogsVisibility.frames\"\r\n @keydown.37=\"prevFormat\"\r\n @keydown.39=\"nextFormat\" />\r\n <!-- Formato da grelha -->\r\n <dialog ref=\"frames\">\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n padding: 5px;\r\n font-weight: bold;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n height: 40px;\r\n color: white;\r\n display: flex;\r\n justify-content: center;\r\n padding-top: 10px;\r\n \">\r\n {{ $t('infoBar.gridForm') }}\r\n </div>\r\n <div class=\"visualization-row\" style=\"justify-content: center\">\r\n <div\r\n v-for=\"(item, index) in items\"\r\n :key=\"index\"\r\n class=\"visualization-col\"\r\n style=\"min-width: 200px; max-width: 200px\">\r\n <img\r\n @click=\"() => (framesValue = item.value)\"\r\n :src=\"`data:image/svg+xml;base64,${item.image}`\"\r\n width=\"100%\"\r\n :style=\"framesValue !== item.value ? 'filter: grayscale(1)' : ''\" />\r\n </div>\r\n </div>\r\n <div\r\n v-if=\"showCustomInputs\"\r\n style=\"\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n color: #333;\r\n gap: 8px;\r\n \">\r\n <span>\r\n <input\r\n v-model.number=\"customFramesPerRow\"\r\n type=\"number\"\r\n min=\"1\"\r\n max=\"15\"\r\n :placeholder=\"customFramesPerRow\"\r\n style=\"\r\n height: 30px;\r\n width: 50px;\r\n border: 0.1px solid #c2c9d6;\r\n border-radius: 3px;\r\n padding: 3px;\r\n \" />\r\n Frames por</span\r\n >\r\n <span>\r\n <input\r\n v-model.number=\"customNumberOfRows\"\r\n type=\"number\"\r\n min=\"1\"\r\n max=\"10\"\r\n :placeholder=\"customNumberOfRows\"\r\n style=\"\r\n height: 30px;\r\n width: 50px;\r\n border: 0.1px solid #c2c9d6;\r\n border-radius: 3px;\r\n padding: 5px;\r\n \" />\r\n Linhas</span\r\n >\r\n </div>\r\n <div class=\"visualization-divider\" />\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n display: flex;\r\n justify-content: center;\r\n margin-top: 10px;\r\n margin-bottom: 10px;\r\n \">\r\n <button\r\n style=\"\r\n border-radius: 4px;\r\n height: 35px;\r\n width: 70px;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n color: white;\r\n \"\r\n @click=\"$emit('close', 'frames')\">\r\n Ok\r\n </button>\r\n </div>\r\n </dialog>\r\n\r\n <!-- Frequencia das Imagens -->\r\n <dialog ref=\"secondsPerFrame\">\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n padding: 5px;\r\n font-weight: bold;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n height: 40px;\r\n color: white;\r\n display: flex;\r\n justify-content: center;\r\n padding-top: 10px;\r\n \">\r\n {{ $t('infoBar.secondImage') + ' (1-' + maxSteps + ')' }}\r\n </div>\r\n\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n margin: 25px;\r\n display: flex;\r\n align-items: center;\r\n height: 60px;\r\n border-radius: 8px;\r\n padding: 0 20px;\r\n \">\r\n <input\r\n ref=\"secondsPerFrameInput\"\r\n v-model.number=\"secondsPerFrameValue\"\r\n type=\"number\"\r\n step=\"1\"\r\n :max=\"maxSteps\"\r\n min=\"1\"\r\n style=\"\r\n height: 40px;\r\n width: 100px;\r\n padding: 5px 10px;\r\n font-size: 16px;\r\n border: 1px solid #ccc;\r\n border-radius: 4px;\r\n box-sizing: border-box;\r\n flex: 1;\r\n \"\r\n @input=\"validateInput\" />\r\n <span style=\"padding-left: 20px; font-size: 16px; color: #333\">\r\n {{ secondsPerFrame + ' s' }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"visualization-divider\" style=\"margin: 10px\" />\r\n <div\r\n class=\"visualization-row\"\r\n style=\"display: flex; justify-content: center; margin-top: 10px\">\r\n <button\r\n style=\"\r\n border-radius: 4px;\r\n height: 35px;\r\n width: 70px;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n color: white;\r\n margin-bottom: 8px;\r\n \"\r\n @click=\"$emit('close', 'secondsPerFrame')\">\r\n Ok\r\n </button>\r\n </div>\r\n </dialog>\r\n\r\n <!-- Go To -->\r\n <dialog ref=\"goTo\">\r\n <div\r\n style=\"\r\n padding: 5px;\r\n font-weight: bold;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n height: 35px;\r\n color: white;\r\n display: flex;\r\n justify-content: center;\r\n padding-top: 8px;\r\n \">\r\n {{ $t('infoBar.goTo') }}\r\n </div>\r\n <div class=\"visualization-row\" style=\"margin: 25px; height: 20px\">\r\n <input\r\n v-model=\"goToValue\"\r\n type=\"text\"\r\n placeholder=\"hh:mm:ss\"\r\n v-mask=\"'##:##:##'\"\r\n style=\"\r\n height: 30px;\r\n width: 300px;\r\n border: 0.1px solid #c2c9d6;\r\n border-radius: 3px;\r\n padding: 5px;\r\n \" />\r\n </div>\r\n <div class=\"visualization-divider\" style=\"margin-top: 40px\" />\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n display: flex;\r\n justify-content: center;\r\n margin-top: 10px;\r\n margin-bottom: 10px;\r\n \">\r\n <button\r\n style=\"\r\n border-radius: 4px;\r\n height: 35px;\r\n width: 70px;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n color: white;\r\n \"\r\n @click=\"\r\n () => {\r\n $emit('close', 'goTo')\r\n $emit('change-go-to', goToValue)\r\n goToValue = ''\r\n }\r\n \">\r\n Ok\r\n </button>\r\n <GlobalEvents\r\n @keydown.13.prevent=\"\r\n () => {\r\n $emit('close', 'goTo')\r\n $emit('change-go-to', goToValue)\r\n goToValue = ''\r\n }\r\n \" />\r\n </div>\r\n </dialog>\r\n\r\n <!-- Velocidade Reprodução -->\r\n <GlobalEvents\r\n @keydown.107=\"changePlaybackRate(1)\"\r\n @keydown.109=\"changePlaybackRate(-1)\" />\r\n <dialog ref=\"playbackRate\">\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n padding: 5px;\r\n font-weight: bold;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n height: 35px;\r\n color: white;\r\n display: flex;\r\n justify-content: center;\r\n padding-top: 8px;\r\n \">\r\n {{ $t('infoBar.playbackSpeed') }}\r\n </div>\r\n <div\r\n class=\"visualization-row\"\r\n style=\"margin: 25px; height: 20px; width: 380px\">\r\n <input\r\n ref=\"playbackRateInput\"\r\n v-model=\"playbackRateValue\"\r\n type=\"range\"\r\n step=\"0.25\"\r\n max=\"3\"\r\n min=\"1\"\r\n style=\"height: 30px; width: 300px\" />\r\n <span\r\n style=\"padding-left: 20px; padding-right: 20px; font-size: 16px\"\r\n >{{ playbackRate + 'x' }}</span\r\n >\r\n </div>\r\n <div class=\"visualization-divider\" style=\"margin-top: 40px\" />\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n display: flex;\r\n justify-content: center;\r\n margin-top: 10px;\r\n margin-bottom: 10px;\r\n \">\r\n <button\r\n @click=\"$emit('close', 'playbackRate')\"\r\n style=\"\r\n border-radius: 4px;\r\n height: 35px;\r\n width: 70px;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n color: white;\r\n \">\r\n Ok\r\n </button>\r\n </div>\r\n </dialog>\r\n\r\n <!-- Deslocamento das Imagens -->\r\n <dialog ref=\"shiftFrames\">\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n padding: 5px;\r\n font-weight: bold;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n height: 40px;\r\n color: white;\r\n display: flex;\r\n justify-content: center;\r\n padding-top: 10px;\r\n \">\r\n {{ `${$t('infoBar.shiftFrames')} (${maxShift * -1} - ${maxShift})` }}\r\n </div>\r\n\r\n <div\r\n class=\"visualization-row\"\r\n style=\"\r\n margin: 25px;\r\n display: flex;\r\n align-items: center;\r\n height: 60px;\r\n border-radius: 8px;\r\n padding: 0 20px;\r\n \">\r\n <input\r\n ref=\"shiftFramesInput\"\r\n v-model.number=\"shiftFramesValue\"\r\n type=\"number\"\r\n step=\"1\"\r\n :max=\"maxShift\"\r\n :min=\"maxShift * -1\"\r\n style=\"\r\n height: 40px;\r\n width: 100px;\r\n padding: 5px 10px;\r\n font-size: 16px;\r\n border: 1px solid #ccc;\r\n border-radius: 4px;\r\n box-sizing: border-box;\r\n flex: 1;\r\n \"\r\n @input=\"validateShift\" />\r\n <span style=\"padding-left: 20px; font-size: 16px; color: #333\">\r\n {{ shiftFrames + ' s' }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"visualization-divider\" style=\"margin: 10px\" />\r\n <div\r\n class=\"visualization-row\"\r\n style=\"display: flex; justify-content: center; margin-top: 10px\">\r\n <button\r\n style=\"\r\n border-radius: 4px;\r\n height: 35px;\r\n width: 70px;\r\n background-color: var(--visualization-primary);\r\n border-color: var(--visualization-primary);\r\n color: white;\r\n margin-bottom: 8px;\r\n \"\r\n @click=\"$emit('close', 'shiftFrames')\">\r\n Ok\r\n </button>\r\n </div>\r\n </dialog>\r\n </div>\r\n</template>\r\n<script>\r\nimport GridImages from '../assets/grid/index.js'\r\nimport { debounce } from 'lodash'\r\n\r\nexport default {\r\n props: {\r\n dialogsVisibility: {\r\n type: Object,\r\n required: false,\r\n },\r\n playbackRate: {\r\n type: Number,\r\n required: true,\r\n },\r\n secondsPerFrame: {\r\n type: Number,\r\n required: true,\r\n },\r\n framesPerRow: {\r\n type: Number,\r\n required: true,\r\n },\r\n numberOfRows: {\r\n type: Number,\r\n required: true,\r\n },\r\n shiftFrames: {\r\n type: Number,\r\n required: true,\r\n },\r\n maxSteps: {\r\n type: Number,\r\n default: 1,\r\n },\r\n maxShift: { \r\n type: Number,\r\n default: 20,\r\n },\r\n customGridSize: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n },\r\n data() {\r\n return {\r\n openBlocksDialog: false,\r\n time: '',\r\n rangeBlocks: {\r\n ini: null,\r\n end: null,\r\n date: null,\r\n },\r\n shiftFramesValue: this.shiftFrames,\r\n\r\n /* items: [\r\n { text: '1x1', value: 1, image: GridImages['1x1'] },\r\n { text: '2x1', value: 2, image: GridImages['2x1'] },\r\n { text: '3x1', value: 3, image: GridImages['3x1'] },\r\n { text: '3x2', value: 4, image: GridImages['3x2'] },\r\n { text: '4x1', value: 5, image: GridImages['4x1'] },\r\n { text: '4x2', value: 6, image: GridImages['4x2'] },\r\n { text: '5x1', value: 7, image: GridImages['5x1'] },\r\n { text: '5x2', value: 8, image: GridImages['5x2'] },\r\n { text: '6x1', value: 9, image: GridImages['6x1'] },\r\n { text: '6x2', value: 10, image: GridImages['6x2'] },\r\n {\r\n text: 'custom',\r\n value: 11,\r\n image: GridImages['custom'],\r\n },\r\n ], */\r\n debouncedShiftFrames: null,\r\n // NEW\r\n goToValue: '',\r\n customNumberOfRows: this.numberOfRows,\r\n customFramesPerRow: this.framesPerRow,\r\n showCustomInputs: false,\r\n isCustomMode: false,\r\n }\r\n },\r\n mounted() {\r\n this.debouncedShiftFrames = debounce(function () {\r\n this.$emit('change-shift-frames', parseInt(this.shiftFramesValue))\r\n }, 350)\r\n this.customNumberOfRows = this.numberOfRows\r\n this.customFramesPerRow = this.framesPerRow\r\n if (this.framesValue === 11) {\r\n this.isCustomMode = true\r\n this.showCustomInputs = true\r\n }\r\n this.toogleDialogs()\r\n },\r\n computed: {\r\n items() {\r\n const baseItems = [\r\n { text: '1x1', value: 1, image: GridImages['1x1'] },\r\n { text: '2x1', value: 2, image: GridImages['2x1'] },\r\n { text: '3x1', value: 3, image: GridImages['3x1'] },\r\n { text: '3x2', value: 4, image: GridImages['3x2'] },\r\n { text: '4x1', value: 5, image: GridImages['4x1'] },\r\n { text: '4x2', value: 6, image: GridImages['4x2'] },\r\n { text: '5x1', value: 7, image: GridImages['5x1'] },\r\n { text: '5x2', value: 8, image: GridImages['5x2'] },\r\n { text: '6x1', value: 9, image: GridImages['6x1'] },\r\n { text: '6x2', value: 10, image: GridImages['6x2'] },\r\n ]\r\n\r\n if (this.customGridSize) {\r\n baseItems.push({\r\n text: 'custom',\r\n value: 11,\r\n image: GridImages['custom'],\r\n })\r\n }\r\n\r\n return baseItems\r\n },\r\n isOpen() {\r\n return !!Object.keys(this.dialogsVisibility).find(\r\n (key) => this.dialogsVisibility[key]\r\n )\r\n },\r\n secondsPerFrameValue: {\r\n get() {\r\n return this.secondsPerFrame\r\n },\r\n set(val) {\r\n if (+val > 0 && +val <= this.maxSteps) {\r\n this.$emit('change-seconds-per-frame', parseInt(val))\r\n }\r\n },\r\n },\r\n playbackRateValue: {\r\n get() {\r\n return this.playbackRate\r\n },\r\n set(val) {\r\n this.$emit('change-playback-rate', parseFloat(val))\r\n },\r\n },\r\n framesValue: {\r\n get() {\r\n if (this.isCustomMode) {\r\n return 11\r\n }\r\n const preset = this.items.find(\r\n (item) =>\r\n item.value !== 11 &&\r\n item.text === `${this.framesPerRow}x${this.numberOfRows}`\r\n )\r\n\r\n return preset ? preset.value : 11\r\n },\r\n set(value) {\r\n if (parseInt(value) === 11) {\r\n this.isCustomMode = true\r\n this.showCustomInputs = true\r\n\r\n this.$nextTick(() => {\r\n this.$emit('set-custom-grid-values', [\r\n parseInt(this.customNumberOfRows),\r\n parseInt(this.customFramesPerRow),\r\n ])\r\n })\r\n } else {\r\n this.isCustomMode = false\r\n this.showCustomInputs = false\r\n this.$emit('set-frames-selection', value)\r\n }\r\n },\r\n },\r\n timeRules() {\r\n return [\r\n (time) =>\r\n (time >= '02:30:00' && time <= '26:29:59') ||\r\n this.$i18n.t('form.mustBeBetween'),\r\n ]\r\n },\r\n },\r\n methods: {\r\n validateInput() {\r\n if (parseInt(this.$refs.secondsPerFrameInput.value) < 1) {\r\n this.$refs.secondsPerFrameInput.value = this.secondsPerFrameValue\r\n } else if (\r\n parseInt(this.$refs.secondsPerFrameInput.value) > this.maxSteps\r\n ) {\r\n this.$refs.secondsPerFrameInput.value = this.secondsPerFrameValue\r\n }\r\n },\r\n validateShift() {\r\n if (parseInt(this.shiftFramesValue) < this.maxShift * -1) {\r\n this.shiftFramesValue = this.shiftFrames\r\n } else if (parseInt(this.shiftFramesValue) > this.maxShift) {\r\n this.shiftFramesValue = this.shiftFrames\r\n }\r\n\r\n this.debouncedShiftFrames()\r\n },\r\n close() {\r\n const openDialog = Object.keys(this.dialogsVisibility).find(\r\n (key) => this.dialogsVisibility[key]\r\n )\r\n this.$emit('close', openDialog)\r\n },\r\n toogleDialogs() {\r\n for (const dialog of Object.values(this.$refs)) {\r\n dialog.close?.()\r\n }\r\n\r\n const openDialog = Object.keys(this.dialogsVisibility).find(\r\n (key) => this.dialogsVisibility[key]\r\n )\r\n\r\n if (openDialog) {\r\n this.$refs[openDialog].showModal()\r\n }\r\n },\r\n prevFormat() {\r\n if (this.items.find((format) => format.value === this.framesValue - 1)) {\r\n this.framesValue--\r\n }\r\n },\r\n nextFormat() {\r\n if (this.items.find((format) => format.value === this.framesValue + 1)) {\r\n this.framesValue++\r\n }\r\n },\r\n changePlaybackRate(direction = 1) {\r\n if (direction === 1) {\r\n this.$refs.playbackRateInput.stepUp()\r\n } else if (direction === -1) {\r\n this.$refs.playbackRateInput.stepDown()\r\n }\r\n this.playbackRateValue = this.$refs.playbackRateInput.value\r\n },\r\n closeBlocksDialog() {\r\n Object.entries(this.rangeBlocks).forEach(([key, value]) => {\r\n if (!value || key == 'date') return\r\n var res = value.replace(/\\D/g, '')\r\n if (res.length < 6) {\r\n for (let i = res.length; i < 6; i++) {\r\n res += '0'\r\n }\r\n }\r\n res.match(/.{1,2}/g)\r\n let a = res.substring(0, 2)\r\n let b = res.substring(2, 4)\r\n let c = res.substring(4, 6)\r\n this.rangeBlocks[key] = a + ':' + b + ':' + c\r\n })\r\n\r\n this.openBlocksDialog = false\r\n this.$emit('goToBlockInterval', this.rangeBlocks)\r\n },\r\n checkIfCustomGrid() {\r\n const hasPreset = this.items.some(\r\n (item) =>\r\n item.value !== 11 &&\r\n item.text === `${this.framesPerRow}x${this.numberOfRows}`\r\n )\r\n\r\n if (!hasPreset) {\r\n this.showCustomInputs = true\r\n this.customNumberOfRows = this.numberOfRows\r\n this.customFramesPerRow = this.framesPerRow\r\n }\r\n },\r\n validateCustomInput(value, max = 10) {\r\n const num = parseInt(value)\r\n if (isNaN(num) || num < 1) return 1\r\n if (num > max) return max\r\n return num\r\n },\r\n },\r\n watch: {\r\n dialogsVisibility: {\r\n handler() {\r\n this.toogleDialogs()\r\n },\r\n deep: true,\r\n },\r\n customFramesPerRow(newVal) {\r\n if (this.isCustomMode && newVal && parseInt(newVal) > 0) {\r\n this.$emit('set-custom-grid-values', [\r\n parseInt(this.customNumberOfRows),\r\n parseInt(newVal),\r\n ])\r\n }\r\n },\r\n\r\n customNumberOfRows(newVal) {\r\n if (this.isCustomMode && newVal && parseInt(newVal) > 0) {\r\n this.$emit('set-custom-grid-values', [\r\n parseInt(newVal),\r\n parseInt(this.customFramesPerRow),\r\n ])\r\n }\r\n },\r\n\r\n numberOfRows(newVal) {\r\n if (!this.isCustomMode) {\r\n this.customNumberOfRows = newVal\r\n }\r\n },\r\n\r\n framesPerRow(newVal) {\r\n if (!this.isCustomMode) {\r\n this.customFramesPerRow = newVal\r\n }\r\n },\r\n },\r\n}\r\n</script>\r\n<style scoped>\r\ndialog {\r\n max-width: 60vw;\r\n /* padding: 12px; */\r\n border: none;\r\n background: white;\r\n border-radius: 6px;\r\n box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);\r\n position: fixed;\r\n top: 50%;\r\n left: 50%;\r\n transform: translateY(-50%) translateX(-50%);\r\n}\r\n.visualization-row {\r\n display: flex;\r\n flex-wrap: wrap;\r\n flex: 1 1 auto;\r\n}\r\n\r\n.visualization-col {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\r\n}\r\n</style>\r\n"]}, media: undefined });
3734
4036
 
3735
4037
  };
3736
4038
  /* scoped */
3737
- const __vue_scope_id__$1 = "data-v-2212eda6";
4039
+ const __vue_scope_id__$1 = "data-v-6d1063b7";
3738
4040
  /* module identifier */
3739
4041
  const __vue_module_identifier__$1 = undefined;
3740
4042
  /* functional template */
@@ -3820,6 +4122,14 @@ var script = {
3820
4122
  type: Number,
3821
4123
  default: 1,
3822
4124
  },
4125
+ customGridSize: {
4126
+ type: Boolean,
4127
+ default: false,
4128
+ },
4129
+ showStretchFrame: {
4130
+ type: Boolean,
4131
+ default: false,
4132
+ },
3823
4133
  },
3824
4134
  components: {
3825
4135
  Frame: __vue_component__$5,
@@ -3879,6 +4189,8 @@ var script = {
3879
4189
  lastPrev: 0,
3880
4190
  shiftFrames: 0,
3881
4191
  aspectRatio: 11 / 9,
4192
+ showCustomInputs: false,
4193
+ stretchFrame: false,
3882
4194
  }
3883
4195
  },
3884
4196
  async created() {
@@ -3926,11 +4238,24 @@ var script = {
3926
4238
  framesPerRow: 6,
3927
4239
  numberOfRows: 2,
3928
4240
  },
4241
+ {
4242
+ //Custom (item 11)
4243
+ framesPerRow: 7,
4244
+ numberOfRows: 3,
4245
+ },
3929
4246
  ];
3930
4247
 
3931
- const storedOnDb = settings[parseInt(this.framesFormat) - 1];
3932
- this.framesPerRow = storedOnDb.framesPerRow;
3933
- this.numberOfRows = storedOnDb.numberOfRows;
4248
+ // Os valores custom são guardados no local storage e não na base de dados
4249
+ const customValues = JSON.parse(localStorage.getItem('customGridValues'));
4250
+
4251
+ if (this.framesFormat == '11' && !!customValues) {
4252
+ this.numberOfRows = customValues[0];
4253
+ this.framesPerRow = customValues[1];
4254
+ } else {
4255
+ const storedOnDb = settings[parseInt(this.framesFormat) - 1];
4256
+ this.framesPerRow = storedOnDb.framesPerRow;
4257
+ this.numberOfRows = storedOnDb.numberOfRows;
4258
+ }
3934
4259
 
3935
4260
  await this.createFramesInterface();
3936
4261
  this.$nextTick(this.resize);
@@ -4183,6 +4508,11 @@ var script = {
4183
4508
  framesPerRow: 6,
4184
4509
  numberOfRows: 2,
4185
4510
  },
4511
+ {
4512
+ //Custom (item 11)
4513
+ framesPerRow: 7,
4514
+ numberOfRows: 3,
4515
+ },
4186
4516
  ];
4187
4517
 
4188
4518
  const formatSelected = settings[selected - 1];
@@ -4194,6 +4524,15 @@ var script = {
4194
4524
  this.$nextTick(this.resize);
4195
4525
  this.$emit('frames-format-changed', selected);
4196
4526
  },
4527
+ async setCustomGridValues(customValues) {
4528
+ this.numberOfRows = customValues[0];
4529
+ this.framesPerRow = customValues[1];
4530
+ localStorage.setItem('customGridValues', JSON.stringify(customValues));
4531
+ await this.fInterface.changeSize(this.numberOfRows, this.framesPerRow);
4532
+ this.getFramesArray();
4533
+ this.$nextTick(this.resize);
4534
+ this.$emit('frames-format-changed', 11);
4535
+ },
4197
4536
  getFramesArray() {
4198
4537
  this.frames = this.fInterface.getFrames(Positions.current);
4199
4538
  this.nextFrames = this.fInterface.getFrames(Positions.next);
@@ -4261,10 +4600,9 @@ var script = {
4261
4600
  this.activeVideo = null;
4262
4601
  },
4263
4602
  getIndex(rowNumber, frameIndex, position) {
4264
- let from = this.framesPerRow * this.numberOfRows * position;
4265
- let till = this.framesPerRow * this.numberOfRows * (position + 1);
4266
-
4267
- return (from + till * (rowNumber - 1)) / rowNumber + frameIndex
4603
+ const baseOffset = this.framesPerRow * this.numberOfRows * position;
4604
+ const rowOffset = (rowNumber - 1) * this.framesPerRow;
4605
+ return baseOffset + rowOffset + frameIndex
4268
4606
  },
4269
4607
  getAudienceTime(frameTime, rowNumber, frameNumber, position) {
4270
4608
  if (!frameTime) {
@@ -4399,18 +4737,20 @@ var script = {
4399
4737
  }
4400
4738
  },
4401
4739
  arrowUp() {
4402
- if (
4403
- this.activeFrame - this.numberOfRows * this.framesPerRow >=
4404
- Math.round((this.numberOfRows * this.framesPerRow) / 2)
4405
- ) {
4740
+ const relativePosition =
4741
+ this.activeFrame - this.numberOfRows * this.framesPerRow;
4742
+ const currentRow = Math.floor(relativePosition / this.framesPerRow);
4743
+ if (currentRow > 0) {
4406
4744
  this.activeFrame -= this.framesPerRow;
4407
4745
  }
4408
4746
  },
4747
+
4409
4748
  arrowDown() {
4410
- if (
4411
- this.activeFrame - this.numberOfRows * this.framesPerRow <
4412
- Math.round((this.numberOfRows * this.framesPerRow) / 2)
4413
- ) {
4749
+ const relativePosition =
4750
+ this.activeFrame - this.numberOfRows * this.framesPerRow;
4751
+ const currentRow = Math.floor(relativePosition / this.framesPerRow);
4752
+
4753
+ if (currentRow < this.numberOfRows - 1) {
4414
4754
  this.activeFrame += this.framesPerRow;
4415
4755
  }
4416
4756
  },
@@ -4740,6 +5080,9 @@ var script = {
4740
5080
  }
4741
5081
  });
4742
5082
  },
5083
+ stretchFrame() {
5084
+ this.$nextTick(this.resize);
5085
+ },
4743
5086
  },
4744
5087
  };
4745
5088
 
@@ -5052,6 +5395,8 @@ var __vue_render__ = function () {
5052
5395
  "number-of-rows": _vm.numberOfRows,
5053
5396
  "max-steps": _vm.maxSteps,
5054
5397
  "shift-frames": _vm.shiftFrames,
5398
+ customGridSize: _vm.customGridSize,
5399
+ stretchFrames: _vm.stretchFrame,
5055
5400
  },
5056
5401
  on: {
5057
5402
  "change-playback-rate": function (value) {
@@ -5065,6 +5410,7 @@ var __vue_render__ = function () {
5065
5410
  return (_vm.shiftFrames = value)
5066
5411
  },
5067
5412
  "set-frames-selection": _vm.setFrameSelection,
5413
+ "set-custom-grid-values": _vm.setCustomGridValues,
5068
5414
  close: function (dialog) {
5069
5415
  return (_vm.dialogs[dialog] = false)
5070
5416
  },
@@ -5152,6 +5498,7 @@ var __vue_render__ = function () {
5152
5498
  "number-of-rows": _vm.numberOfRows,
5153
5499
  "hour-ini": _vm.hourIniSelected,
5154
5500
  "hour-end": _vm.hourEndSelected,
5501
+ "show-stretch-frame": _vm.showStretchFrame,
5155
5502
  },
5156
5503
  on: {
5157
5504
  "toogle-commands-visibility": _vm.toogleCommandsVisibility,
@@ -5159,6 +5506,9 @@ var __vue_render__ = function () {
5159
5506
  _vm.useCache = !_vm.useCache;
5160
5507
  },
5161
5508
  "change-server": _vm.changeServerClick,
5509
+ "update-stretch-frames": function (value) {
5510
+ return (_vm.stretchFrame = value)
5511
+ },
5162
5512
  },
5163
5513
  }),
5164
5514
  _vm._v(" "),
@@ -5168,7 +5518,7 @@ var __vue_render__ = function () {
5168
5518
  {
5169
5519
  key: "row-" + rowNumber,
5170
5520
  staticClass: "visualization-row",
5171
- staticStyle: { padding: "2px 12px" },
5521
+ staticStyle: { padding: "0px 4px" },
5172
5522
  attrs: { id: "row-" + rowNumber },
5173
5523
  },
5174
5524
  [
@@ -5221,7 +5571,13 @@ var __vue_render__ = function () {
5221
5571
  return _c(
5222
5572
  "div",
5223
5573
  {
5224
- key: "row-" + rowNumber + "-frame-" + frameNumber,
5574
+ key:
5575
+ "row-" +
5576
+ rowNumber +
5577
+ "-frame-" +
5578
+ frameNumber +
5579
+ "-" +
5580
+ frame.time,
5225
5581
  staticClass: "visualization-col",
5226
5582
  class: { loaderImg: !!frame.img },
5227
5583
  attrs: {
@@ -5306,6 +5662,7 @@ var __vue_render__ = function () {
5306
5662
  videoControls: _vm.videoControls,
5307
5663
  "playback-rate": _vm.playbackRate,
5308
5664
  "aspect-ratio": _vm.aspectRatio,
5665
+ stretchFrame: _vm.stretchFrame,
5309
5666
  },
5310
5667
  on: {
5311
5668
  startPlaying: _vm.startPlaying,
@@ -5336,11 +5693,11 @@ __vue_render__._withStripped = true;
5336
5693
  /* style */
5337
5694
  const __vue_inject_styles__ = function (inject) {
5338
5695
  if (!inject) return
5339
- inject("data-v-27fc3944_0", { source: "\n.visualization-row[data-v-27fc3944] {\r\n display: flex;\r\n flex-wrap: wrap;\r\n flex: 1 1 auto;\n}\n.visualization-col[data-v-27fc3944] {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\n}\n.visualization-divider[data-v-27fc3944] {\r\n display: block;\r\n flex: 1 1 100%;\r\n height: 0px;\r\n max-height: 0px;\r\n opacity: 1;\r\n transition: inherit;\r\n border-style: solid;\r\n border-width: thin 0 0 0;\r\n border-color: rgba(0, 0, 0, 0.12);\r\n margin: 0;\n}\n.visualization-divider.vertical[data-v-27fc3944] {\r\n align-self: stretch;\r\n border-width: 0 thin 0 0;\r\n display: inline-flex;\r\n height: inherit;\r\n margin-left: -1px;\r\n max-height: 100%;\r\n max-width: 0px;\r\n vertical-align: text-bottom;\r\n width: 0px;\n}\n.visualization-card[data-v-27fc3944] {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\r\n width: 100%;\r\n transition-property: box-shadow, opacity, -webkit-box-shadow;\r\n overflow-wrap: break-word;\r\n /*box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);*/\n}\n.visualization-justify-center[data-v-27fc3944],\r\n*[data-v-27fc3944] .visualization-justify-center {\r\n justify-content: center;\n}\n.visualization-align-center[data-v-27fc3944] {\r\n align-items: center;\n}\n#visualization-container[data-v-27fc3944] {\r\n max-width: 100% !important;\r\n margin: 0 auto !important;\r\n height: 100%;\r\n border-bottom: none;\n}\n#visualization-container > .card[data-v-27fc3944] {\r\n border-radius: 0 !important;\r\n font-size: 12px;\r\n width: 100%;\r\n box-shadow: none;\r\n height: 100%;\n}\n#command-bar[data-v-27fc3944],\r\n#info-bar[data-v-27fc3944] {\r\n background-color: #f5f5f5;\r\n box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);\n}\n#command-bar button[data-v-27fc3944] {\r\n width: 42px;\r\n height: 36px;\r\n border: none;\r\n background: none;\n}\n#command-bar button[data-v-27fc3944]:hover {\r\n cursor: pointer;\r\n background: rgba(0, 0, 0, 0.12);\n}\n#command-bar svg[data-v-27fc3944] {\r\n font-size: 16px;\n}\n#command-bar[data-v-27fc3944] {\r\n padding: 0 !important;\n}\n#info-bar[data-v-27fc3944] {\r\n padding: 4px;\r\n font-size: 14px;\r\n position: relative;\n}\n.settings-container[data-v-27fc3944] {\r\n position: absolute;\r\n right: 14px;\r\n top: 50%;\r\n transform: translateY(-50%);\n}\n.settings-container > *[data-v-27fc3944] {\r\n margin: 0 2px;\r\n cursor: pointer;\n}\n#info-bar svg[data-v-27fc3944] {\r\n font-size: 16px;\n}\n#info-bar .divider[data-v-27fc3944] {\r\n margin: 0 8px;\n}\nsvg[data-v-27fc3944]:focus {\r\n border: none;\n}\n.visualization-card[data-v-27fc3944] {\r\n border-left: 8px solid #eee;\n}\n.active-tab[data-v-27fc3944] {\r\n border-left: 8px solid var(--visualization-primary) !important;\r\n border-image-slice: 1;\n}\n[id^='frame-'][data-v-27fc3944] {\r\n padding: 1px;\r\n display: flex;\r\n flex-flow: column;\n}\n.tooltip[data-v-27fc3944] {\r\n display: block !important;\r\n z-index: 10000;\n}\n.tooltip .tooltip-inner[data-v-27fc3944] {\r\n background: var(--visualization-primary);\r\n color: white;\r\n border-radius: 16px;\r\n padding: 5px 10px 4px;\n}\n.tooltip .tooltip-arrow[data-v-27fc3944] {\r\n width: 0;\r\n height: 0;\r\n border-style: solid;\r\n position: absolute;\r\n margin: 5px;\r\n border-color: var(--visualization-primary);\r\n z-index: 1;\n}\n.tooltip[x-placement^='top'][data-v-27fc3944] {\r\n margin-bottom: 5px;\n}\n.tooltip[x-placement^='top'] .tooltip-arrow[data-v-27fc3944] {\r\n border-width: 5px 5px 0 5px;\r\n border-left-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n bottom: -5px;\r\n left: calc(50% - 5px);\r\n margin-top: 0;\r\n margin-bottom: 0;\n}\n.tooltip[x-placement^='bottom'][data-v-27fc3944] {\r\n margin-top: 5px;\n}\n.tooltip[x-placement^='bottom'] .tooltip-arrow[data-v-27fc3944] {\r\n border-width: 0 5px 5px 5px;\r\n border-left-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-top-color: transparent !important;\r\n top: -5px;\r\n left: calc(50% - 5px);\r\n margin-top: 0;\r\n margin-bottom: 0;\n}\n.tooltip[x-placement^='right'][data-v-27fc3944] {\r\n margin-left: 5px;\n}\n.tooltip[x-placement^='right'] .tooltip-arrow[data-v-27fc3944] {\r\n border-width: 5px 5px 5px 0;\r\n border-left-color: transparent !important;\r\n border-top-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n left: -5px;\r\n top: calc(50% - 5px);\r\n margin-left: 0;\r\n margin-right: 0;\n}\n.tooltip[x-placement^='left'][data-v-27fc3944] {\r\n margin-right: 5px;\n}\n.tooltip[x-placement^='left'] .tooltip-arrow[data-v-27fc3944] {\r\n border-width: 5px 0 5px 5px;\r\n border-top-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n right: -5px;\r\n top: calc(50% - 5px);\r\n margin-left: 0;\r\n margin-right: 0;\n}\n.tooltip.popover .popover-inner[data-v-27fc3944] {\r\n background: #f9f9f9;\r\n color: black;\r\n padding: 24px;\r\n border-radius: 5px;\r\n box-shadow: 0 5px 30px rgba(black, 0.1);\n}\n.tooltip.popover .popover-arrow[data-v-27fc3944] {\r\n border-color: #f9f9f9;\n}\n.tooltip[aria-hidden='true'][data-v-27fc3944] {\r\n visibility: hidden;\r\n opacity: 0;\r\n transition: opacity 0.15s, visibility 0.15s;\n}\n.tooltip[aria-hidden='false'][data-v-27fc3944] {\r\n visibility: visible;\r\n opacity: 1;\r\n transition: opacity 0.15s;\n}\r\n", map: {"version":3,"sources":["C:\\Workspace\\visualization\\src\\Visualization.vue"],"names":[],"mappings":";AAmvCA;EACA,aAAA;EACA,eAAA;EACA,cAAA;AACA;AAEA;EACA,aAAA;EACA,YAAA;EACA,eAAA;EACA,aAAA;AACA;AAEA;EACA,cAAA;EACA,cAAA;EACA,WAAA;EACA,eAAA;EACA,UAAA;EACA,mBAAA;EACA,mBAAA;EACA,wBAAA;EACA,iCAAA;EACA,SAAA;AACA;AAEA;EACA,mBAAA;EACA,wBAAA;EACA,oBAAA;EACA,eAAA;EACA,iBAAA;EACA,gBAAA;EACA,cAAA;EACA,2BAAA;EACA,UAAA;AACA;AAEA;EACA,aAAA;EACA,YAAA;EACA,eAAA;EACA,aAAA;EACA,WAAA;EACA,4DAAA;EACA,yBAAA;EACA;qCACA;AACA;AAEA;;EAEA,uBAAA;AACA;AAEA;EACA,mBAAA;AACA;AAEA;EACA,0BAAA;EACA,yBAAA;EACA,YAAA;EACA,mBAAA;AACA;AACA;EACA,2BAAA;EACA,eAAA;EACA,WAAA;EACA,gBAAA;EACA,YAAA;AACA;AAEA;;EAEA,yBAAA;EACA;mCACA;AACA;AACA;EACA,WAAA;EACA,YAAA;EACA,YAAA;EACA,gBAAA;AACA;AAEA;EACA,eAAA;EACA,+BAAA;AACA;AAEA;EACA,eAAA;AACA;AAEA;EACA,qBAAA;AACA;AAEA;EACA,YAAA;EACA,eAAA;EACA,kBAAA;AACA;AAEA;EACA,kBAAA;EACA,WAAA;EACA,QAAA;EACA,2BAAA;AACA;AAEA;EACA,aAAA;EACA,eAAA;AACA;AAEA;EACA,eAAA;AACA;AAEA;EACA,aAAA;AACA;AAEA;EACA,YAAA;AACA;AAEA;EACA,2BAAA;AACA;AAEA;EACA,8DAAA;EACA,qBAAA;AACA;AAEA;EACA,YAAA;EACA,aAAA;EACA,iBAAA;AACA;AAEA;EACA,yBAAA;EACA,cAAA;AACA;AAEA;EACA,wCAAA;EACA,YAAA;EACA,mBAAA;EACA,qBAAA;AACA;AAEA;EACA,QAAA;EACA,SAAA;EACA,mBAAA;EACA,kBAAA;EACA,WAAA;EACA,0CAAA;EACA,UAAA;AACA;AAEA;EACA,kBAAA;AACA;AAEA;EACA,2BAAA;EACA,yCAAA;EACA,0CAAA;EACA,2CAAA;EACA,YAAA;EACA,qBAAA;EACA,aAAA;EACA,gBAAA;AACA;AAEA;EACA,eAAA;AACA;AAEA;EACA,2BAAA;EACA,yCAAA;EACA,0CAAA;EACA,wCAAA;EACA,SAAA;EACA,qBAAA;EACA,aAAA;EACA,gBAAA;AACA;AAEA;EACA,gBAAA;AACA;AAEA;EACA,2BAAA;EACA,yCAAA;EACA,wCAAA;EACA,2CAAA;EACA,UAAA;EACA,oBAAA;EACA,cAAA;EACA,eAAA;AACA;AAEA;EACA,iBAAA;AACA;AAEA;EACA,2BAAA;EACA,wCAAA;EACA,0CAAA;EACA,2CAAA;EACA,WAAA;EACA,oBAAA;EACA,cAAA;EACA,eAAA;AACA;AAEA;EACA,mBAAA;EACA,YAAA;EACA,aAAA;EACA,kBAAA;EACA,uCAAA;AACA;AAEA;EACA,qBAAA;AACA;AAEA;EACA,kBAAA;EACA,UAAA;EACA,2CAAA;AACA;AAEA;EACA,mBAAA;EACA,UAAA;EACA,yBAAA;AACA","file":"Visualization.vue","sourcesContent":["<template>\r\n <div\r\n class=\"visualization-row\"\r\n id=\"visualization-container\"\r\n @click=\"framesClicked\"\r\n >\r\n <GlobalEvents\r\n v-if=\"!readOnly && canInsertTime && settingsClosed\"\r\n :filter=\"(event) => !event.shiftKey && !event.ctrlKey\"\r\n @keydown.45=\"insertTime\"\r\n />\r\n <GlobalEvents\r\n v-if=\"!readOnly && active && settingsClosed\"\r\n @keydown.83.prevent=\"setHourIni\"\r\n @keydown.69.prevent=\"setHourEnd\"\r\n />\r\n <GlobalEvents\r\n v-if=\"active && settingsClosed\"\r\n @keydown.left.prevent=\"arrowLeft\"\r\n @keydown.right.prevent=\"arrowRight\"\r\n @keydown.up.prevent=\"arrowUp\"\r\n @keydown.down.prevent=\"arrowDown\"\r\n @keydown.shift.page-down.prevent=\"nextLoopActivate\"\r\n @keydown.page-down.prevent=\"() => next()\"\r\n @keydown.page-up.prevent=\"() => prev()\"\r\n @keydown.shift.page-up.prevent=\"prevLoopActivate\"\r\n @keydown.36.prevent=\"goToFirstFrame\"\r\n @keydown.35.prevent=\"goToLastFrame\"\r\n @keydown.71.prevent=\"dialogs.goTo = true\"\r\n @keydown.73.prevent=\"dialogs.secondsPerFrame = true\"\r\n @keydown.76.prevent=\"dialogs.frames = true\"\r\n @keydown.49.97=\"() => (secondsPerFrame = 1)\"\r\n @keydown.50.98=\"() => (secondsPerFrame = 2)\"\r\n @keydown.51.99=\"() => (secondsPerFrame = 3)\"\r\n @keydown.52.100=\"() => (secondsPerFrame = 4)\"\r\n @keydown.53.101=\"() => (secondsPerFrame = 5)\"\r\n />\r\n <GlobalEvents\r\n v-if=\"prevLoop || nextLoop\"\r\n @keydown=\"breakLoop\"\r\n v-on:click=\"breakLoop\"\r\n />\r\n <settings\r\n v-if=\"active\"\r\n :dialogs-visibility=\"dialogs\"\r\n :playback-rate=\"playbackRate\"\r\n :seconds-per-frame=\"secondsPerFrame\"\r\n :frames-per-row=\"framesPerRow\"\r\n :number-of-rows=\"numberOfRows\"\r\n :max-steps=\"maxSteps\"\r\n :shift-frames=\"shiftFrames\"\r\n @change-playback-rate=\"(value) => (playbackRate = value)\"\r\n @change-go-to=\"changeHour\"\r\n @change-seconds-per-frame=\"(value) => (secondsPerFrame = value)\"\r\n @change-shift-frames=\"(value) => (shiftFrames = value)\"\r\n @set-frames-selection=\"setFrameSelection\"\r\n @close=\"(dialog) => (dialogs[dialog] = false)\"\r\n />\r\n <div\r\n :class=\"{ 'visualization-card': true, 'active-tab': active }\"\r\n style=\"width: 100%; padding: 0\"\r\n >\r\n <command-bar\r\n v-show=\"commandBarShow\"\r\n :read-only=\"readOnly\"\r\n :video-playing=\"videoPlaying\"\r\n :video-paused=\"paused\"\r\n :insert-time=\"canInsertTime\"\r\n :hour-ini-selected=\"!!hourIniSelected\"\r\n :hour-end-selected=\"!!hourEndSelected\"\r\n @prev-loop-activate=\"prevLoopActivate\"\r\n @next-loop-activate=\"nextLoopActivate\"\r\n @prev=\"prev\"\r\n @next=\"next\"\r\n @go-to=\"dialogs.goTo = true\"\r\n @open-frame-selection=\"dialogs.frames = true\"\r\n @open-frames-per-second=\"dialogs.secondsPerFrame = true\"\r\n @open-blocks=\"openBlocks\"\r\n @open-playback-rate=\"dialogs.playbackRate = true\"\r\n @play-or-pause=\"playOrPause\"\r\n @stop-playing=\"stopPlayingBar\"\r\n @set-hour-ini=\"setHourIni\"\r\n @set-hour-end=\"setHourEnd\"\r\n @insert-time=\"insertTime\"\r\n @shift-frames=\"dialogs.shiftFrames = true\"\r\n />\r\n <video-progress\r\n v-if=\"videoProgressBar\"\r\n v-show=\"videoPlaying\"\r\n :video-time=\"videoTime\"\r\n />\r\n <info-bar\r\n :playback-rate=\"playbackRate\"\r\n :seconds-per-frame=\"secondsPerFrame\"\r\n :commands-show=\"commandBarShow\"\r\n :cache=\"useCache\"\r\n :block-start-time=\"blockStartTime\"\r\n :video-total-duration=\"videoSliderTotalDuration\"\r\n :alternative-server=\"alternativeServer\"\r\n :frames-per-row=\"framesPerRow\"\r\n :number-of-rows=\"numberOfRows\"\r\n :hour-ini=\"hourIniSelected\"\r\n :hour-end=\"hourEndSelected\"\r\n @toogle-commands-visibility=\"toogleCommandsVisibility\"\r\n @toogle-cache=\"useCache = !useCache\"\r\n @change-server=\"changeServerClick\"\r\n />\r\n <div\r\n class=\"visualization-row\"\r\n v-for=\"rowNumber in numberOfRows\"\r\n :id=\"'row-' + rowNumber\"\r\n :key=\"'row-' + rowNumber\"\r\n style=\"padding: 2px 12px\"\r\n >\r\n <div\r\n v-for=\"(frame, frameNumber) in previousFrames\"\r\n :key=\"\r\n numberOfRows +\r\n '-' +\r\n framesPerRow +\r\n '-' +\r\n getIndex(rowNumber, frameNumber, Positions.previous)\r\n \"\r\n style=\"display: none\"\r\n >\r\n <span v-html=\"frame.img\" />\r\n </div>\r\n <div\r\n v-for=\"(frame, frameNumber) in nextFrames\"\r\n :key=\"\r\n numberOfRows +\r\n '-' +\r\n framesPerRow +\r\n '-' +\r\n getIndex(rowNumber, frameNumber, Positions.next)\r\n \"\r\n style=\"display: none\"\r\n >\r\n <span v-html=\"frame.img\" />\r\n </div>\r\n <div\r\n class=\"visualization-col\"\r\n v-for=\"(frame, frameNumber) in frames.slice(\r\n framesPerRow * (rowNumber - 1),\r\n framesPerRow * rowNumber\r\n )\"\r\n :key=\"'row-' + rowNumber + '-frame-' + frameNumber\"\r\n :id=\"`frame-${getIndex(rowNumber, frameNumber, Positions.current)}`\"\r\n :class=\"{ loaderImg: !!frame.img }\"\r\n @click=\"\r\n frame.time\r\n ? selectFrame(\r\n getIndex(rowNumber, frameNumber, Positions.current),\r\n frame\r\n )\r\n : null\r\n \"\r\n >\r\n <span :id=\"activeFrame ? 'aa' : 0\" style=\"text-align: center\">\r\n <b>\r\n {{\r\n getAudienceTime(\r\n frame.time,\r\n rowNumber,\r\n frameNumber,\r\n Positions.current\r\n )\r\n }}\r\n </b>\r\n </span>\r\n\r\n <frame\r\n ref=\"frames\"\r\n :frame=\"frame\"\r\n :index=\"getIndex(rowNumber, frameNumber, Positions.current)\"\r\n :grid-settings=\"{ numberOfRows, framesPerRow }\"\r\n :initialTime=\"frame.time === hourIniSelected\"\r\n :endTime=\"frame.time === hourEndSelected\"\r\n :betweenTime=\"\r\n frame.time > hourIniSelected && frame.time < hourEndSelected\r\n \"\r\n :active=\"\r\n getIndex(rowNumber, frameNumber, Positions.current) ===\r\n activeFrame\r\n \"\r\n :activeTab=\"active\"\r\n :videoUrl=\"fInterface ? fInterface.getVideoUrl(frame) : ''\"\r\n :videoControls=\"videoControls\"\r\n @startPlaying=\"startPlaying\"\r\n @stopPlaying=\"stopPlaying\"\r\n @playPauseStatus=\"changePlayPause\"\r\n @updateSlider=\"updateSlider\"\r\n :playback-rate=\"playbackRate\"\r\n :aspect-ratio=\"aspectRatio\"\r\n style=\"margin: 0 auto\"\r\n ></frame>\r\n </div>\r\n </div>\r\n </div>\r\n <!-- <settings\r\n ref=\"settings2\"\r\n :active=\"active\"\r\n @goToTime=\"changeHour\"\r\n @goToBlockInterval=\"changeBlockInterval\"\r\n @setSplitTime=\"setSplitTime\"\r\n @setFrameSelection=\"setFrameSelection\"\r\n @setPlaybackRate=\"\r\n (rate) => {\r\n playbackRate = rate\r\n }\r\n \"\r\n >\r\n </settings> -->\r\n <!-- <v-dialog v-model=\"dialog\" width=\"500\">\r\n <div class=\"card\">\r\n <div class=\"card\"-title class=\"text-h5 grey lighten-2\">\r\n {{ ' Último bloco disponível até: ' }}\r\n <v-btn\r\n @click=\"goToStartBlock\"\r\n class=\"ml-2\"\r\n dark\r\n color=\"success\"\r\n depressed\r\n >\r\n <v-icon left> fa-clock </v-icon>\r\n {{ timeLastBlock }}\r\n </v-btn>\r\n <v-spacer></v-spacer>\r\n <v-btn color=\"error\" fab small class=\"ml-5\" @click=\"dialog = false\">\r\n <v-icon dark> fa fa-xmark </v-icon>\r\n </v-btn>\r\n </div-title>\r\n </div>\r\n </v-dialog>\r\n <Help :media=\"media\" @close=\"media = null\" />\r\n <v-dialog\r\n v-if=\"userMultiTabsGrid\"\r\n v-model=\"userMultiTabsGridsModel\"\r\n persistent\r\n width=\"60%\"\r\n >\r\n <div class=\"card\">\r\n <div class=\"card\"-title class=\"warning text-h5\" primary-title>\r\n <div class=\"row\" class=\"ma-0\" justify=\"center\" align=\"center\">\r\n <v-icon dark left style=\"font-size: 24px !important\">\r\n fa fa-exclamation-triangle\r\n </v-icon>\r\n <div style=\"color: white\">{{ $t('form.alert') }}</div>\r\n </div>\r\n </div-title>\r\n <div class=\"card\"-text class=\"justify-center pa-6 grey lighten-2\">\r\n <h3>\r\n {{ $t('alerts.userMultiTabsGrid') }}\r\n </h3>\r\n </div-text>\r\n <hr class=\"divider\" class=\"grey lighten-1\"></span>\r\n <div class=\"card\"-actions class=\"grey lighten-2 justify-center\">\r\n <v-btn color=\"error\" ml-5 @click=\"userMultiTabsGrid = false\">\r\n <v-icon left color=\"white\">fa fa-times</v-icon>\r\n {{ $t('form.close') }}\r\n </v-btn>\r\n </div-actions>\r\n </div>\r\n </v-dialog> -->\r\n </div>\r\n</template>\r\n<script>\r\nimport Frame from './components/Frame.vue'\r\nimport FramesInterface from './utils/FramesInterface.js'\r\nimport FramesService from './services/FramesService.js'\r\n\r\nimport Commands from './components/Commands.vue'\r\nimport Infos from './components/Infos.vue'\r\nimport VideoProgress from './components/VideoProgress.vue'\r\nimport Settings from './components/Settings.vue'\r\n\r\nconst Positions = Object.freeze({\r\n previous: 0,\r\n current: 1,\r\n next: 2,\r\n})\r\n\r\nexport default {\r\n name: 'visualization-container',\r\n props: {\r\n value: {\r\n type: Boolean,\r\n required: true,\r\n },\r\n date: {\r\n type: String,\r\n required: true,\r\n },\r\n channel: {\r\n type: Number,\r\n required: true,\r\n },\r\n startAudienceTime: {\r\n type: String,\r\n required: true,\r\n },\r\n endAudienceTime: {\r\n type: String,\r\n required: true,\r\n },\r\n videoProgressBar: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n jumpOnInsert: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n removeSelectionOnInsert: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n framesFormat: {\r\n type: [Number, String],\r\n default: 7,\r\n },\r\n maxSize: {\r\n type: Number,\r\n },\r\n videoControls: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n readOnly: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n maxSteps: {\r\n type: Number,\r\n default: 1,\r\n },\r\n },\r\n components: {\r\n Frame,\r\n CommandBar: Commands,\r\n InfoBar: Infos,\r\n VideoProgress,\r\n Settings,\r\n // Help,\r\n },\r\n data() {\r\n return {\r\n Positions,\r\n updatingChannel: null,\r\n dialog: false,\r\n timeLastBlock: null,\r\n alternativeServer: false,\r\n useCache: true,\r\n numberOfRows: 1,\r\n framesPerRow: 5,\r\n secondsPerFrame: 1,\r\n fInterface: null,\r\n velocity: 1,\r\n frames: [],\r\n previousFrames: [],\r\n nextFrames: [],\r\n channelCode: 0,\r\n videoPlaying: false,\r\n activeFrame: null,\r\n activeVideo: null,\r\n videoTime: 0,\r\n videoTotalTime: null,\r\n progressVideoDrag: false,\r\n hourIniSelected: false,\r\n hourEndSelected: false,\r\n canInsertTime: false,\r\n lastHeight: 0,\r\n loopInterval: null,\r\n nextLoop: false,\r\n prevLoop: false,\r\n videoSliderTotalDuration: 900,\r\n blockStartTime: null,\r\n media: null,\r\n changeServer: false,\r\n userMultiTabsGrid: false,\r\n userMultiTabsGridsModel: true,\r\n playbackRate: 1,\r\n paused: false,\r\n commandBarShow: true,\r\n dialogs: {\r\n playbackRate: false,\r\n goTo: false,\r\n secondsPerFrame: false,\r\n frames: false,\r\n shiftFrames: false,\r\n },\r\n lastNext: 0,\r\n lastPrev: 0,\r\n shiftFrames: 0,\r\n aspectRatio: 11 / 9,\r\n }\r\n },\r\n async created() {\r\n this.changeServer = this.serverOfFrames === 'alternative'\r\n this.alternativeServer = this.serverOfFrames === 'alternative'\r\n\r\n const settings = [\r\n {\r\n framesPerRow: 1,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 2,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 3,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 3,\r\n numberOfRows: 2,\r\n },\r\n {\r\n framesPerRow: 4,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 4,\r\n numberOfRows: 2,\r\n },\r\n {\r\n framesPerRow: 5,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 5,\r\n numberOfRows: 2,\r\n },\r\n {\r\n framesPerRow: 6,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 6,\r\n numberOfRows: 2,\r\n },\r\n ]\r\n\r\n const storedOnDb = settings[parseInt(this.framesFormat) - 1]\r\n this.framesPerRow = storedOnDb.framesPerRow\r\n this.numberOfRows = storedOnDb.numberOfRows\r\n\r\n await this.createFramesInterface()\r\n this.$nextTick(this.resize)\r\n },\r\n methods: {\r\n stopVideoPlaying(array) {\r\n for (const frame of array || this.$refs.frames) {\r\n if (\r\n frame.videoStatus === frame.Status.playing ||\r\n frame.videoStatus === frame.Status.paused\r\n ) {\r\n frame.stop(false)\r\n }\r\n }\r\n this.activeVideo = null\r\n },\r\n toogleCommandsVisibility() {\r\n this.commandBarShow = !this.commandBarShow\r\n this.$nextTick(this.resize)\r\n },\r\n framesClicked(e) {\r\n if (e.target.parentNode.id != 'insert') {\r\n this.active = true\r\n }\r\n },\r\n async goToStartBlock() {\r\n try {\r\n const d = new Date()\r\n let timestamp = Date.UTC(\r\n d.getFullYear(),\r\n d.getMonth(),\r\n d.getDate(),\r\n d.getHours(),\r\n d.getMinutes(),\r\n d.getSeconds()\r\n )\r\n\r\n const response = (\r\n await FramesService.getNextAvailableBlock({\r\n channel: this.channel,\r\n time: timestamp / 1000,\r\n })\r\n ).data\r\n\r\n this.dialog = false\r\n this.changeHour(this.convertToAudienceTime(response.data.start, ':'))\r\n } catch (err) {\r\n // console.error(err)\r\n }\r\n },\r\n async checkAvailableBlock() {\r\n try {\r\n const d = new Date()\r\n let timestamp = Date.UTC(\r\n d.getFullYear(),\r\n d.getMonth(),\r\n d.getDate(),\r\n d.getHours(),\r\n d.getMinutes(),\r\n d.getSeconds()\r\n )\r\n\r\n const response = (\r\n await FramesService.getNextAvailableBlock({\r\n channel: this.channel,\r\n time: timestamp / 1000,\r\n })\r\n ).data\r\n\r\n this.timeLastBlock = this.convertToAudienceTime(response.data.end, ':')\r\n this.dialog = true\r\n if (!response.status) {\r\n this.timeLastBlock = 'N/D'\r\n }\r\n } catch (err) {\r\n // console.error(err)\r\n }\r\n },\r\n updateSlider(videoStartTime, time) {\r\n // * atualizar slider se estiver fora do range definido previamente\r\n if (\r\n time < this.blockStartTime ||\r\n time > this.blockStartTime ||\r\n videoStartTime > this.blockStartTime + this.videoSliderTotalDuration\r\n ) {\r\n this.blockStartTime = videoStartTime\r\n this.videoSliderTotalDuration = 900\r\n }\r\n },\r\n nextLoopActivate() {\r\n this.breakLoop()\r\n this.loopInterval = setInterval(\r\n () => this.next({ ignoreTime: true }),\r\n this.swapImagesDelay\r\n )\r\n setTimeout(() => {\r\n this.nextLoop = true\r\n }, 0)\r\n },\r\n prevLoopActivate() {\r\n this.breakLoop()\r\n this.loopInterval = setInterval(\r\n () => this.prev({ ignoreTime: true }),\r\n this.swapImagesDelay\r\n )\r\n setTimeout(() => {\r\n this.prevLoop = true\r\n }, 0)\r\n },\r\n breakLoop() {\r\n clearInterval(this.loopInterval)\r\n this.loopInterval = null\r\n this.nextLoop = false\r\n this.prevLoop = false\r\n },\r\n changePlayPause(status) {\r\n this.paused = !status\r\n },\r\n resize(height = this.lastHeight) {\r\n this.lastHeight = height\r\n if (this.$refs.frames) {\r\n for (let frame of this.$refs.frames) {\r\n frame.resize(height)\r\n }\r\n }\r\n this.$emit('resized')\r\n },\r\n async goToFirstFrame() {\r\n let frames = this.$refs.frames\r\n\r\n let audienceTime = null\r\n if (frames.length > 0) {\r\n let frame = frames[0].frame\r\n audienceTime = this.getAudienceTime(frame.time, 0, 0, 0)\r\n }\r\n if (audienceTime) {\r\n const [hours, minutes, seconds] = audienceTime.split(':')\r\n const totalSeconds =\r\n parseInt(hours) * 3600 + parseInt(minutes) * 60 + parseInt(seconds)\r\n if (totalSeconds >= 9000)\r\n this.changeHour(this.getLastFirtsBlockTime(audienceTime, true))\r\n else this.changeHour(this.getLastFirtsBlockTime('02:30:00', true))\r\n }\r\n },\r\n async goToLastFrame() {\r\n let frames = this.$refs.frames\r\n let audienceTime = null\r\n if (frames.length > 0) {\r\n let frame = frames[0].frame\r\n\r\n audienceTime = this.getAudienceTime(frame.time, 0, 0, 0)\r\n }\r\n if (audienceTime) {\r\n this.changeHour(this.getLastFirtsBlockTime(audienceTime))\r\n }\r\n },\r\n getLastFirtsBlockTime(time, first = false) {\r\n if (time.indexOf(':') !== -1) {\r\n time = time.replace(/:/g, '')\r\n }\r\n let h, m, newTime\r\n const t = time.match(/.{1,2}/g)\r\n if (t[0] && t[1]) {\r\n h = parseInt(t[0])\r\n m = parseInt(t[1])\r\n }\r\n if (h < 26) {\r\n if (m < 15)\r\n if (first) newTime = t[0] + ':00:00'\r\n else newTime = t[0] + ':14:59'\r\n else if (m < 30)\r\n if (first) newTime = t[0] + ':15:00'\r\n else newTime = t[0] + ':29:59'\r\n else if (m < 45)\r\n if (first) newTime = t[0] + ':30:00'\r\n else newTime = t[0] + ':44:59'\r\n else if (first) newTime = t[0] + ':45:00'\r\n else newTime = t[0] + ':59:59'\r\n } else {\r\n if (m < 15)\r\n if (first) newTime = '26:00:00'\r\n else newTime = '26:14:59'\r\n else {\r\n if (first) newTime = '26:15:00'\r\n else newTime = '26:29:59'\r\n }\r\n }\r\n return newTime\r\n },\r\n openBlocks() {\r\n this.$refs.settings2?.openBlocks()\r\n },\r\n playOrPause() {\r\n const array = this.$refs.frames.filter((fc) => !!fc.active)\r\n if (array.length === 1) {\r\n const frame = array[0]\r\n frame.playOrPause(this.playbackRate)\r\n }\r\n },\r\n stopPlayingBar() {\r\n for (let ref of this.$refs.frames) {\r\n if (\r\n ref.videoStatus === ref.Status.playing ||\r\n ref.videoStatus === ref.Status.paused\r\n ) {\r\n ref.stop(false)\r\n }\r\n }\r\n },\r\n async setFrameSelection(selected) {\r\n this.frames = this.loadingArray\r\n const settings = [\r\n {\r\n framesPerRow: 1,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 2,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 3,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 3,\r\n numberOfRows: 2,\r\n },\r\n {\r\n framesPerRow: 4,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 4,\r\n numberOfRows: 2,\r\n },\r\n {\r\n framesPerRow: 5,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 5,\r\n numberOfRows: 2,\r\n },\r\n {\r\n framesPerRow: 6,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 6,\r\n numberOfRows: 2,\r\n },\r\n ]\r\n\r\n const formatSelected = settings[selected - 1]\r\n this.framesPerRow = formatSelected.framesPerRow\r\n this.numberOfRows = formatSelected.numberOfRows\r\n\r\n await this.fInterface.changeSize(this.numberOfRows, this.framesPerRow)\r\n this.getFramesArray()\r\n this.$nextTick(this.resize)\r\n this.$emit('frames-format-changed', selected)\r\n },\r\n getFramesArray() {\r\n this.frames = this.fInterface.getFrames(Positions.current)\r\n this.nextFrames = this.fInterface.getFrames(Positions.next)\r\n this.previousFrames = this.fInterface.getFrames(Positions.previous)\r\n\r\n const div = document.createElement('div')\r\n div.innerHTML = this.frames[0].image\r\n const newAspectRatio =\r\n div.getElementsByTagName('img')[0]?.naturalWidth /\r\n div.getElementsByTagName('img')[0]?.naturalHeight\r\n\r\n this.aspectRatio = isNaN(newAspectRatio)\r\n ? this.aspectRatio\r\n : newAspectRatio\r\n\r\n this.$nextTick(this.resize)\r\n\r\n const frame = this.frames.find((f) => f.blockStart)\r\n if (frame && this.alternativeServer) {\r\n this.$emit(\r\n 'new-block',\r\n frame.title?.match(/[0-9]{3}\\/(?:[0-9]+_?)+/)[0]\r\n )\r\n }\r\n },\r\n async createFramesInterface(startTime = this.startAudienceTime) {\r\n this.frames = this.loadingArray\r\n // let ch = this.channel\r\n // let associationTMP = {\r\n // 1735073: 1,\r\n // 1735074: 139,\r\n // 1735075: 3,\r\n // 1735076: 132,\r\n // }\r\n // //\r\n // this.channelCode = associationTMP[ch] ? associationTMP[ch] : ch\r\n\r\n const t = startTime.match(/.{1,2}/g)\r\n const d = this.getDateParts()\r\n const time = Date.UTC(d.year, d.month, d.day, t[0], t[1], t[2]) / 1000\r\n // * iniciar slider\r\n this.blockStartTime = time\r\n this.fInterface = await new FramesInterface(\r\n this.channel,\r\n this.numberOfRows,\r\n this.framesPerRow,\r\n time,\r\n this.startAudienceTime,\r\n this.useCache,\r\n this.shiftFrames\r\n )\r\n await this.fInterface.init()\r\n\r\n this.getFramesArray()\r\n\r\n const div = document.createElement('div')\r\n div.innerHTML = this.frames[0].image\r\n\r\n this.aspectRatio =\r\n div.getElementsByTagName('img')[0].naturalWidth /\r\n div.getElementsByTagName('img')[0].naturalHeight\r\n\r\n this.activeFrame = this.getIndex(1, 0, Positions.current)\r\n\r\n this.activeVideo = null\r\n },\r\n getIndex(rowNumber, frameIndex, position) {\r\n let from = this.framesPerRow * this.numberOfRows * position\r\n let till = this.framesPerRow * this.numberOfRows * (position + 1)\r\n\r\n return (from + till * (rowNumber - 1)) / rowNumber + frameIndex\r\n },\r\n getAudienceTime(frameTime, rowNumber, frameNumber, position) {\r\n if (!frameTime) {\r\n return 'Loading...'\r\n } else if (\r\n this.getIndex(rowNumber, frameNumber, position) === this.activeVideo\r\n ) {\r\n return this.convertToAudienceTime(this.videoTime)\r\n } else {\r\n return this.convertToAudienceTime(frameTime)\r\n }\r\n },\r\n dateInUtc(miliSeconds) {\r\n var date = new Date(miliSeconds)\r\n var utc = new Date(\r\n date.getUTCFullYear(),\r\n date.getUTCMonth(),\r\n date.getUTCDate(),\r\n date.getUTCHours(),\r\n date.getUTCMinutes(),\r\n date.getUTCSeconds()\r\n )\r\n return utc\r\n },\r\n convertToAudienceTime(time, separator = ':') {\r\n const d = this.getDateParts()\r\n const limit = Date.UTC(d.year, d.month, d.day, 23, 59, 59) / 1000\r\n\r\n let hour = this.dateInUtc(time * 1000)\r\n .toTimeString()\r\n .split(' ')[0]\r\n .split(':')\r\n .map(Number)\r\n\r\n if (time > limit && time <= limit + this.startAudienceSeconds) {\r\n hour[0] = 24 + hour[0]\r\n }\r\n return hour\r\n .map((part) => (part > 9 ? part.toString() : '0' + part))\r\n .join(separator)\r\n },\r\n getDateParts(date = this.date) {\r\n const data = /(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})/.exec(\r\n date\r\n )?.groups\r\n if (data) {\r\n return {\r\n year: parseInt(data.year),\r\n month: parseInt(data.month) - 1,\r\n day: parseInt(data.day),\r\n }\r\n }\r\n return {\r\n year: null,\r\n month: null,\r\n day: null,\r\n }\r\n },\r\n selectFrame(index, frame) {\r\n const d = this.getDateParts()\r\n const limit = Date.UTC(d.year, d.month, d.day, 23, 59, 59) / 1000\r\n const frameTime = frame?.time\r\n\r\n if (frameTime - (this.startAudienceSeconds + limit) <= 0) {\r\n if (this.hourIniSelected === true) {\r\n this.hourIniSelected = frameTime\r\n\r\n if (\r\n this.hourEndSelected &&\r\n this.hourIniSelected > this.hourEndSelected\r\n ) {\r\n this.hourEndSelected = false\r\n }\r\n } else if (this.hourEndSelected === true) {\r\n if (frameTime > this.hourIniSelected) {\r\n this.hourEndSelected = frameTime\r\n this.canInsertTime = true\r\n } else {\r\n this.hourEndSelected = false\r\n }\r\n }\r\n }\r\n\r\n if (this.activeFrame !== index) {\r\n // ? Se clicar no frame diferente de onde está a dar play, faz pausa\r\n const array = this.$refs.frames.filter(\r\n (fc) => fc.videoStatus === fc.Status.playing\r\n )\r\n if (array.length === 1) {\r\n const frame = array[0]\r\n frame.playOrPause()\r\n }\r\n this.activeVideo = null\r\n this.activeFrame = index\r\n }\r\n },\r\n setHourIni() {\r\n this.canInsertTime = true\r\n this.hourIniSelected = true\r\n document.getElementById(`frame-${this.activeFrame}`).click()\r\n this.$emit('setHourIni', {\r\n hour_ini: this.hourIniSelected\r\n ? this.convertToAudienceTime(this.hourIniSelected, '')\r\n : null,\r\n })\r\n },\r\n setHourEnd() {\r\n this.canInsertTime = true\r\n this.hourEndSelected = true\r\n document.getElementById(`frame-${this.activeFrame}`).click()\r\n },\r\n //* Navegação\r\n arrowRight() {\r\n if (this.checkLimitRight(false)) {\r\n if (\r\n this.activeFrame ===\r\n this.numberOfRows * this.framesPerRow * 2 - 1\r\n ) {\r\n this.next()\r\n } else {\r\n this.activeFrame++\r\n }\r\n }\r\n },\r\n arrowLeft() {\r\n if (this.checkLimitLeft(false)) {\r\n if (this.activeFrame === this.numberOfRows * this.framesPerRow) {\r\n this.prev({ stayOnLast: true })\r\n } else {\r\n this.activeFrame--\r\n }\r\n }\r\n },\r\n arrowUp() {\r\n if (\r\n this.activeFrame - this.numberOfRows * this.framesPerRow >=\r\n Math.round((this.numberOfRows * this.framesPerRow) / 2)\r\n ) {\r\n this.activeFrame -= this.framesPerRow\r\n }\r\n },\r\n arrowDown() {\r\n if (\r\n this.activeFrame - this.numberOfRows * this.framesPerRow <\r\n Math.round((this.numberOfRows * this.framesPerRow) / 2)\r\n ) {\r\n this.activeFrame += this.framesPerRow\r\n }\r\n },\r\n checkLimitRight(value) {\r\n const hours = this.endAudienceTime.match(/.{1,2}/g)\r\n const d = this.getDateParts()\r\n const high = Date.UTC(\r\n d.year,\r\n d.month,\r\n d.day,\r\n hours[0],\r\n parseInt(hours[1]) + 30,\r\n hours[2]\r\n )\r\n\r\n if (value) {\r\n return (\r\n high >\r\n (this.fInterface.getCurrentTime() +\r\n this.numberOfRows * this.framesPerRow -\r\n 1) *\r\n 1000\r\n )\r\n } else {\r\n return high > this.fInterface.getCurrentTime() * 1000\r\n }\r\n },\r\n checkLimitLeft(value) {\r\n const hours = this.startAudienceTime.match(/.{1,2}/g)\r\n const d = this.getDateParts()\r\n const low = Date.UTC(d.year, d.month, d.day, hours[0], hours[1], hours[2])\r\n\r\n if (value) {\r\n return low <= (this.fInterface.getCurrentTime() - 1) * 1000\r\n } else {\r\n return (\r\n low <\r\n (this.fInterface.getCurrentTime() +\r\n this.activeFrame -\r\n this.numberOfRows * this.framesPerRow) *\r\n 1000\r\n )\r\n }\r\n },\r\n async next(config = {}) {\r\n if (\r\n (config.ignoreTime ||\r\n Date.now() - this.lastNext > this.swapImagesDelay) &&\r\n this.checkLimitRight(true) &&\r\n !this.navigationPending\r\n ) {\r\n this.navigationPending = true\r\n this.stopVideoPlaying()\r\n\r\n this.navigationPending = await new Promise((resolve) => {\r\n this.fInterface\r\n .loadNextFrames()\r\n .then(() => {\r\n this.activeFrame = this.getIndex(1, 0, Positions.current)\r\n\r\n this.getFramesArray()\r\n this.lastNext = Date.now()\r\n resolve(false)\r\n })\r\n .catch(() => {\r\n resolve(false)\r\n })\r\n })\r\n } else {\r\n // console.error('next blocked')\r\n }\r\n },\r\n async prev(config = {}) {\r\n if (\r\n (config.ignoreTime ||\r\n Date.now() - this.lastPrev > this.swapImagesDelay) &&\r\n this.checkLimitLeft(true) &&\r\n !this.navigationPending\r\n ) {\r\n this.navigationPending = true\r\n this.stopVideoPlaying()\r\n\r\n this.navigationPending = await new Promise((resolve) => {\r\n this.fInterface\r\n .loadPrevFrames()\r\n .then(() => {\r\n if (config.stayOnLast) {\r\n this.activeFrame = this.getIndex(\r\n this.numberOfRows,\r\n this.framesPerRow - 1,\r\n Positions.current\r\n )\r\n } else {\r\n this.activeFrame = this.getIndex(1, 0, Positions.current)\r\n }\r\n\r\n this.getFramesArray()\r\n this.lastPrev = Date.now()\r\n resolve(false)\r\n })\r\n .catch(() => {\r\n resolve(false)\r\n })\r\n })\r\n } else {\r\n // console.error('prev blocked')\r\n }\r\n },\r\n async setStartTime(time) {\r\n if (time.indexOf(':') !== -1) {\r\n time = time.replace(/:/g, '')\r\n }\r\n const t = time.match(/.{1,2}/g)\r\n const d = this.getDateParts()\r\n const setTime = Date.UTC(d.year, d.month, d.day, t[0], t[1], t[2]) / 1000\r\n // this.frames = this.loadingArray\r\n\r\n await this.fInterface.changeTime(setTime)\r\n\r\n this.getFramesArray()\r\n\r\n this.activeFrame = this.getIndex(1, 0, Positions.current)\r\n\r\n this.activeVideo = null\r\n\r\n return true\r\n },\r\n hourToTimeStamp(time) {\r\n if (time.indexOf(':') !== -1) {\r\n time = time.replace(/:/g, '')\r\n }\r\n const t = time.match(/.{1,2}/g)\r\n const d = this.getDateParts()\r\n const setTime = Date.UTC(d.year, d.month, d.day, t[0], t[1], t[2]) / 1000\r\n\r\n return setTime\r\n },\r\n changeHour(value) {\r\n if (value) {\r\n return new Promise((resolve) => {\r\n setTimeout(async () => {\r\n this.stopVideoPlaying()\r\n\r\n await this.setStartTime(value, true)\r\n resolve()\r\n }, 0)\r\n })\r\n }\r\n },\r\n changeBlockInterval(value) {\r\n this.changeHour(value.ini)\r\n let time_ini, time_end\r\n time_ini = this.hourToTimeStamp(value.ini)\r\n time_end = this.hourToTimeStamp(value.end)\r\n this.videoSliderTotalDuration = time_end - time_ini\r\n this.$refs.frames[0].changeSettings(time_ini)\r\n this.blockStartTime = time_ini\r\n },\r\n //eslint-disable-next-line\r\n async updateVideoTime(index, videoTime) {\r\n this.activeVideo = index\r\n this.videoTime = videoTime\r\n },\r\n //eslint-disable-next-line\r\n updateVideoStatus(currentTime) {\r\n if (!this.progressVideoDrag) {\r\n // ESTA FUNÇÃO PASSOU PARA DENTRO DOS COMMANDS\r\n // this.updateProgress(null, currentTime)\r\n }\r\n },\r\n async startPlaying(frame, totalTime) {\r\n const array = this.$refs.frames.filter(\r\n (fc) => fc.frame.time !== frame.time\r\n )\r\n this.stopVideoPlaying(array)\r\n\r\n this.videoTotalTime = totalTime\r\n this.videoPlaying = true\r\n },\r\n stopPlaying() {\r\n this.videoTotalTime = null\r\n this.videoPlaying = false\r\n this.paused = false\r\n },\r\n insertTime() {\r\n this.$emit('timeToInsert', {\r\n channel: this.channel,\r\n hour_ini: this.hourIniSelected\r\n ? this.convertToAudienceTime(this.hourIniSelected, '')\r\n : null,\r\n hour_end: this.hourEndSelected\r\n ? this.convertToAudienceTime(this.hourEndSelected, '')\r\n : null,\r\n force: false,\r\n })\r\n\r\n if (this.jumpOnInsert) {\r\n this.changeHour(\r\n this.convertToAudienceTime(\r\n this.hourEndSelected || this.hourIniSelected\r\n )\r\n ).then(() => {\r\n this.activeFrame = this.getIndex(1, 1, Positions.current)\r\n })\r\n }\r\n\r\n if (this.removeSelectionOnInsert) {\r\n this.hourIniSelected = null\r\n this.hourEndSelected = null\r\n this.canInsertTime = false\r\n }\r\n },\r\n insertTimeForce() {\r\n this.$emit('timeToInsert', {\r\n channel: this.channel,\r\n hour_ini: this.hourIniSelected\r\n ? this.convertToAudienceTime(this.hourIniSelected, '')\r\n : null,\r\n hour_end: this.hourEndSelected\r\n ? this.convertToAudienceTime(this.hourEndSelected, '')\r\n : null,\r\n force: true,\r\n })\r\n\r\n if (this.removeSelectionOnInsert) {\r\n this.hourIniSelected = null\r\n this.hourEndSelected = null\r\n this.canInsertTime = false\r\n }\r\n },\r\n async getChannelMedia() {\r\n // this.media = (await ChannelService.show(this.channel)).data.MEDIA\r\n },\r\n async changeServerClick() {\r\n this.changeServer = !this.changeServer\r\n this.alternativeServer = this.changeServer\r\n\r\n sessionStorage.setItem(\r\n 'server',\r\n this.changeServer ? 'alternative' : 'default'\r\n )\r\n\r\n await this.createFramesInterface(\r\n this.convertToAudienceTime(\r\n this.$refs.frames.find((frame) => frame.index === this.activeFrame)\r\n .frame.time,\r\n ''\r\n )\r\n )\r\n\r\n this.$nextTick(this.resize)\r\n },\r\n },\r\n computed: {\r\n swapImagesDelay() {\r\n return 0\r\n // return this.numberOfRows * this.framesPerRow * 15\r\n },\r\n active: {\r\n get() {\r\n return this.value\r\n },\r\n set(value) {\r\n this.$emit('input', value)\r\n },\r\n },\r\n settingsClosed() {\r\n return !Object.values(this.dialogs).find((v) => v)\r\n },\r\n startAudienceSeconds() {\r\n const t = this.startAudienceTime.match(/.{1,2}/g)\r\n return parseInt(t[0] * 3600 + t[1] * 60 + t[2])\r\n },\r\n loadingArray() {\r\n return Array.from(Array(this.numberOfRows * this.framesPerRow).keys())\r\n },\r\n serverOfFrames() {\r\n return sessionStorage.getItem('server')\r\n },\r\n },\r\n beforeDestroy() {\r\n sessionStorage.setItem('server', 'default')\r\n },\r\n watch: {\r\n async secondsPerFrame() {\r\n const activeF =\r\n this.frames[this.activeFrame - this.numberOfRows * this.framesPerRow]\r\n\r\n if (activeF) {\r\n this.changeHour(this.getAudienceTime(activeF.time, 0, 0, 0))\r\n this.fInterface.setCurrentStep(this.secondsPerFrame)\r\n await this.fInterface.loadFrames()\r\n this.getFramesArray()\r\n }\r\n },\r\n async shiftFrames() {\r\n this.createFramesInterface()\r\n },\r\n framesFormat(value) {\r\n this.setFrameSelection(value)\r\n },\r\n active() {\r\n // ? sempre que trocamos de tabs dar reset as horas selected\r\n if (this.removeSelectionOnInsert) {\r\n this.hourIniSelected = false\r\n this.hourEndSelected = false\r\n }\r\n },\r\n useCache() {\r\n this.createFramesInterface()\r\n },\r\n hourIniSelected(value) {\r\n if (value) {\r\n sessionStorage.setItem(\r\n 'currentTimeFrames',\r\n this.convertToAudienceTime(this.hourIniSelected, '')\r\n )\r\n } else {\r\n sessionStorage.removeItem('currentTimeFrames')\r\n }\r\n },\r\n activeFrame(value) {\r\n if (value) {\r\n this.stopPlayingBar()\r\n }\r\n },\r\n channel() {\r\n this.updatingChannel = new Promise((resolve, reject) => {\r\n try {\r\n this.createFramesInterface()\r\n resolve(true)\r\n } catch (err) {\r\n reject(err)\r\n }\r\n })\r\n },\r\n },\r\n}\r\n</script>\r\n<style scoped>\r\n.visualization-row {\r\n display: flex;\r\n flex-wrap: wrap;\r\n flex: 1 1 auto;\r\n}\r\n\r\n.visualization-col {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\r\n}\r\n\r\n.visualization-divider {\r\n display: block;\r\n flex: 1 1 100%;\r\n height: 0px;\r\n max-height: 0px;\r\n opacity: 1;\r\n transition: inherit;\r\n border-style: solid;\r\n border-width: thin 0 0 0;\r\n border-color: rgba(0, 0, 0, 0.12);\r\n margin: 0;\r\n}\r\n\r\n.visualization-divider.vertical {\r\n align-self: stretch;\r\n border-width: 0 thin 0 0;\r\n display: inline-flex;\r\n height: inherit;\r\n margin-left: -1px;\r\n max-height: 100%;\r\n max-width: 0px;\r\n vertical-align: text-bottom;\r\n width: 0px;\r\n}\r\n\r\n.visualization-card {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\r\n width: 100%;\r\n transition-property: box-shadow, opacity, -webkit-box-shadow;\r\n overflow-wrap: break-word;\r\n /*box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);*/\r\n}\r\n\r\n.visualization-justify-center,\r\n* >>> .visualization-justify-center {\r\n justify-content: center;\r\n}\r\n\r\n.visualization-align-center {\r\n align-items: center;\r\n}\r\n\r\n#visualization-container {\r\n max-width: 100% !important;\r\n margin: 0 auto !important;\r\n height: 100%;\r\n border-bottom: none;\r\n}\r\n#visualization-container > .card {\r\n border-radius: 0 !important;\r\n font-size: 12px;\r\n width: 100%;\r\n box-shadow: none;\r\n height: 100%;\r\n}\r\n\r\n#command-bar,\r\n#info-bar {\r\n background-color: #f5f5f5;\r\n box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);\r\n}\r\n#command-bar button {\r\n width: 42px;\r\n height: 36px;\r\n border: none;\r\n background: none;\r\n}\r\n\r\n#command-bar button:hover {\r\n cursor: pointer;\r\n background: rgba(0, 0, 0, 0.12);\r\n}\r\n\r\n#command-bar svg {\r\n font-size: 16px;\r\n}\r\n\r\n#command-bar {\r\n padding: 0 !important;\r\n}\r\n\r\n#info-bar {\r\n padding: 4px;\r\n font-size: 14px;\r\n position: relative;\r\n}\r\n\r\n.settings-container {\r\n position: absolute;\r\n right: 14px;\r\n top: 50%;\r\n transform: translateY(-50%);\r\n}\r\n\r\n.settings-container > * {\r\n margin: 0 2px;\r\n cursor: pointer;\r\n}\r\n\r\n#info-bar svg {\r\n font-size: 16px;\r\n}\r\n\r\n#info-bar .divider {\r\n margin: 0 8px;\r\n}\r\n\r\nsvg:focus {\r\n border: none;\r\n}\r\n\r\n.visualization-card {\r\n border-left: 8px solid #eee;\r\n}\r\n\r\n.active-tab {\r\n border-left: 8px solid var(--visualization-primary) !important;\r\n border-image-slice: 1;\r\n}\r\n\r\n[id^='frame-'] {\r\n padding: 1px;\r\n display: flex;\r\n flex-flow: column;\r\n}\r\n\r\n.tooltip {\r\n display: block !important;\r\n z-index: 10000;\r\n}\r\n\r\n.tooltip .tooltip-inner {\r\n background: var(--visualization-primary);\r\n color: white;\r\n border-radius: 16px;\r\n padding: 5px 10px 4px;\r\n}\r\n\r\n.tooltip .tooltip-arrow {\r\n width: 0;\r\n height: 0;\r\n border-style: solid;\r\n position: absolute;\r\n margin: 5px;\r\n border-color: var(--visualization-primary);\r\n z-index: 1;\r\n}\r\n\r\n.tooltip[x-placement^='top'] {\r\n margin-bottom: 5px;\r\n}\r\n\r\n.tooltip[x-placement^='top'] .tooltip-arrow {\r\n border-width: 5px 5px 0 5px;\r\n border-left-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n bottom: -5px;\r\n left: calc(50% - 5px);\r\n margin-top: 0;\r\n margin-bottom: 0;\r\n}\r\n\r\n.tooltip[x-placement^='bottom'] {\r\n margin-top: 5px;\r\n}\r\n\r\n.tooltip[x-placement^='bottom'] .tooltip-arrow {\r\n border-width: 0 5px 5px 5px;\r\n border-left-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-top-color: transparent !important;\r\n top: -5px;\r\n left: calc(50% - 5px);\r\n margin-top: 0;\r\n margin-bottom: 0;\r\n}\r\n\r\n.tooltip[x-placement^='right'] {\r\n margin-left: 5px;\r\n}\r\n\r\n.tooltip[x-placement^='right'] .tooltip-arrow {\r\n border-width: 5px 5px 5px 0;\r\n border-left-color: transparent !important;\r\n border-top-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n left: -5px;\r\n top: calc(50% - 5px);\r\n margin-left: 0;\r\n margin-right: 0;\r\n}\r\n\r\n.tooltip[x-placement^='left'] {\r\n margin-right: 5px;\r\n}\r\n\r\n.tooltip[x-placement^='left'] .tooltip-arrow {\r\n border-width: 5px 0 5px 5px;\r\n border-top-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n right: -5px;\r\n top: calc(50% - 5px);\r\n margin-left: 0;\r\n margin-right: 0;\r\n}\r\n\r\n.tooltip.popover .popover-inner {\r\n background: #f9f9f9;\r\n color: black;\r\n padding: 24px;\r\n border-radius: 5px;\r\n box-shadow: 0 5px 30px rgba(black, 0.1);\r\n}\r\n\r\n.tooltip.popover .popover-arrow {\r\n border-color: #f9f9f9;\r\n}\r\n\r\n.tooltip[aria-hidden='true'] {\r\n visibility: hidden;\r\n opacity: 0;\r\n transition: opacity 0.15s, visibility 0.15s;\r\n}\r\n\r\n.tooltip[aria-hidden='false'] {\r\n visibility: visible;\r\n opacity: 1;\r\n transition: opacity 0.15s;\r\n}\r\n</style>\r\n"]}, media: undefined });
5696
+ inject("data-v-a861684a_0", { source: "\n.visualization-row[data-v-a861684a] {\r\n display: flex;\r\n flex-wrap: wrap;\r\n flex: 1 1 auto;\n}\n.visualization-col[data-v-a861684a] {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 5px;\n}\n.visualization-divider[data-v-a861684a] {\r\n display: block;\r\n flex: 1 1 100%;\r\n height: 0px;\r\n max-height: 0px;\r\n opacity: 1;\r\n transition: inherit;\r\n border-style: solid;\r\n border-width: thin 0 0 0;\r\n border-color: rgba(0, 0, 0, 0.12);\r\n margin: 0;\n}\n.visualization-divider.vertical[data-v-a861684a] {\r\n align-self: stretch;\r\n border-width: 0 thin 0 0;\r\n display: inline-flex;\r\n height: inherit;\r\n margin-left: -1px;\r\n max-height: 100%;\r\n max-width: 0px;\r\n vertical-align: text-bottom;\r\n width: 0px;\n}\n.visualization-card[data-v-a861684a] {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\r\n width: 100%;\r\n transition-property: box-shadow, opacity, -webkit-box-shadow;\r\n overflow-wrap: break-word;\r\n /*box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);*/\n}\n.visualization-justify-center[data-v-a861684a],\r\n*[data-v-a861684a] .visualization-justify-center {\r\n justify-content: center;\n}\n.visualization-align-center[data-v-a861684a] {\r\n align-items: center;\n}\n#visualization-container[data-v-a861684a] {\r\n max-width: 100% !important;\r\n margin: 0 auto !important;\r\n height: 100%;\r\n border-bottom: none;\n}\n#visualization-container > .card[data-v-a861684a] {\r\n border-radius: 0 !important;\r\n font-size: 12px;\r\n width: 100%;\r\n box-shadow: none;\r\n height: 100%;\n}\n#command-bar[data-v-a861684a],\r\n#info-bar[data-v-a861684a] {\r\n background-color: #f5f5f5;\r\n box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);\n}\n#command-bar button[data-v-a861684a] {\r\n width: 42px;\r\n height: 36px;\r\n border: none;\r\n background: none;\n}\n#command-bar button[data-v-a861684a]:hover {\r\n cursor: pointer;\r\n background: rgba(0, 0, 0, 0.12);\n}\n#command-bar svg[data-v-a861684a] {\r\n font-size: 16px;\n}\n#command-bar[data-v-a861684a] {\r\n padding: 0 !important;\n}\n#info-bar[data-v-a861684a] {\r\n padding: 4px;\r\n font-size: 14px;\r\n position: relative;\n}\n.settings-container[data-v-a861684a] {\r\n position: absolute;\r\n right: 14px;\r\n top: 50%;\r\n transform: translateY(-50%);\n}\n.settings-container > *[data-v-a861684a] {\r\n margin: 0 2px;\r\n cursor: pointer;\n}\n#info-bar svg[data-v-a861684a] {\r\n font-size: 16px;\n}\n#info-bar .divider[data-v-a861684a] {\r\n margin: 0 8px;\n}\nsvg[data-v-a861684a]:focus {\r\n border: none;\n}\n.visualization-card[data-v-a861684a] {\r\n border-left: 8px solid #eee;\n}\n.active-tab[data-v-a861684a] {\r\n border-left: 8px solid var(--visualization-primary) !important;\r\n border-image-slice: 1;\n}\n[id^='frame-'][data-v-a861684a] {\r\n padding: 1px;\r\n display: flex;\r\n flex-flow: column;\n}\n.tooltip[data-v-a861684a] {\r\n display: block !important;\r\n z-index: 10000;\n}\n.tooltip .tooltip-inner[data-v-a861684a] {\r\n background: var(--visualization-primary);\r\n color: white;\r\n border-radius: 16px;\r\n padding: 5px 10px 4px;\n}\n.tooltip .tooltip-arrow[data-v-a861684a] {\r\n width: 0;\r\n height: 0;\r\n border-style: solid;\r\n position: absolute;\r\n margin: 5px;\r\n border-color: var(--visualization-primary);\r\n z-index: 1;\n}\n.tooltip[x-placement^='top'][data-v-a861684a] {\r\n margin-bottom: 5px;\n}\n.tooltip[x-placement^='top'] .tooltip-arrow[data-v-a861684a] {\r\n border-width: 5px 5px 0 5px;\r\n border-left-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n bottom: -5px;\r\n left: calc(50% - 5px);\r\n margin-top: 0;\r\n margin-bottom: 0;\n}\n.tooltip[x-placement^='bottom'][data-v-a861684a] {\r\n margin-top: 5px;\n}\n.tooltip[x-placement^='bottom'] .tooltip-arrow[data-v-a861684a] {\r\n border-width: 0 5px 5px 5px;\r\n border-left-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-top-color: transparent !important;\r\n top: -5px;\r\n left: calc(50% - 5px);\r\n margin-top: 0;\r\n margin-bottom: 0;\n}\n.tooltip[x-placement^='right'][data-v-a861684a] {\r\n margin-left: 5px;\n}\n.tooltip[x-placement^='right'] .tooltip-arrow[data-v-a861684a] {\r\n border-width: 5px 5px 5px 0;\r\n border-left-color: transparent !important;\r\n border-top-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n left: -5px;\r\n top: calc(50% - 5px);\r\n margin-left: 0;\r\n margin-right: 0;\n}\n.tooltip[x-placement^='left'][data-v-a861684a] {\r\n margin-right: 5px;\n}\n.tooltip[x-placement^='left'] .tooltip-arrow[data-v-a861684a] {\r\n border-width: 5px 0 5px 5px;\r\n border-top-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n right: -5px;\r\n top: calc(50% - 5px);\r\n margin-left: 0;\r\n margin-right: 0;\n}\n.tooltip.popover .popover-inner[data-v-a861684a] {\r\n background: #f9f9f9;\r\n color: black;\r\n padding: 24px;\r\n border-radius: 5px;\r\n box-shadow: 0 5px 30px rgba(black, 0.1);\n}\n.tooltip.popover .popover-arrow[data-v-a861684a] {\r\n border-color: #f9f9f9;\n}\n.tooltip[aria-hidden='true'][data-v-a861684a] {\r\n visibility: hidden;\r\n opacity: 0;\r\n transition: opacity 0.15s, visibility 0.15s;\n}\n.tooltip[aria-hidden='false'][data-v-a861684a] {\r\n visibility: visible;\r\n opacity: 1;\r\n transition: opacity 0.15s;\n}\n.custom-frametime[data-v-a861684a] {\r\n font-size: smaller;\n}\r\n", map: {"version":3,"sources":["C:\\Workspace\\visualization\\src\\Visualization.vue"],"names":[],"mappings":";AAmxCA;EACA,aAAA;EACA,eAAA;EACA,cAAA;AACA;AAEA;EACA,aAAA;EACA,YAAA;EACA,eAAA;EACA,YAAA;AACA;AAEA;EACA,cAAA;EACA,cAAA;EACA,WAAA;EACA,eAAA;EACA,UAAA;EACA,mBAAA;EACA,mBAAA;EACA,wBAAA;EACA,iCAAA;EACA,SAAA;AACA;AAEA;EACA,mBAAA;EACA,wBAAA;EACA,oBAAA;EACA,eAAA;EACA,iBAAA;EACA,gBAAA;EACA,cAAA;EACA,2BAAA;EACA,UAAA;AACA;AAEA;EACA,aAAA;EACA,YAAA;EACA,eAAA;EACA,aAAA;EACA,WAAA;EACA,4DAAA;EACA,yBAAA;EACA;qCACA;AACA;AAEA;;EAEA,uBAAA;AACA;AAEA;EACA,mBAAA;AACA;AAEA;EACA,0BAAA;EACA,yBAAA;EACA,YAAA;EACA,mBAAA;AACA;AACA;EACA,2BAAA;EACA,eAAA;EACA,WAAA;EACA,gBAAA;EACA,YAAA;AACA;AAEA;;EAEA,yBAAA;EACA;mCACA;AACA;AACA;EACA,WAAA;EACA,YAAA;EACA,YAAA;EACA,gBAAA;AACA;AAEA;EACA,eAAA;EACA,+BAAA;AACA;AAEA;EACA,eAAA;AACA;AAEA;EACA,qBAAA;AACA;AAEA;EACA,YAAA;EACA,eAAA;EACA,kBAAA;AACA;AAEA;EACA,kBAAA;EACA,WAAA;EACA,QAAA;EACA,2BAAA;AACA;AAEA;EACA,aAAA;EACA,eAAA;AACA;AAEA;EACA,eAAA;AACA;AAEA;EACA,aAAA;AACA;AAEA;EACA,YAAA;AACA;AAEA;EACA,2BAAA;AACA;AAEA;EACA,8DAAA;EACA,qBAAA;AACA;AAEA;EACA,YAAA;EACA,aAAA;EACA,iBAAA;AACA;AAEA;EACA,yBAAA;EACA,cAAA;AACA;AAEA;EACA,wCAAA;EACA,YAAA;EACA,mBAAA;EACA,qBAAA;AACA;AAEA;EACA,QAAA;EACA,SAAA;EACA,mBAAA;EACA,kBAAA;EACA,WAAA;EACA,0CAAA;EACA,UAAA;AACA;AAEA;EACA,kBAAA;AACA;AAEA;EACA,2BAAA;EACA,yCAAA;EACA,0CAAA;EACA,2CAAA;EACA,YAAA;EACA,qBAAA;EACA,aAAA;EACA,gBAAA;AACA;AAEA;EACA,eAAA;AACA;AAEA;EACA,2BAAA;EACA,yCAAA;EACA,0CAAA;EACA,wCAAA;EACA,SAAA;EACA,qBAAA;EACA,aAAA;EACA,gBAAA;AACA;AAEA;EACA,gBAAA;AACA;AAEA;EACA,2BAAA;EACA,yCAAA;EACA,wCAAA;EACA,2CAAA;EACA,UAAA;EACA,oBAAA;EACA,cAAA;EACA,eAAA;AACA;AAEA;EACA,iBAAA;AACA;AAEA;EACA,2BAAA;EACA,wCAAA;EACA,0CAAA;EACA,2CAAA;EACA,WAAA;EACA,oBAAA;EACA,cAAA;EACA,eAAA;AACA;AAEA;EACA,mBAAA;EACA,YAAA;EACA,aAAA;EACA,kBAAA;EACA,uCAAA;AACA;AAEA;EACA,qBAAA;AACA;AAEA;EACA,kBAAA;EACA,UAAA;EACA,2CAAA;AACA;AAEA;EACA,mBAAA;EACA,UAAA;EACA,yBAAA;AACA;AAEA;EACA,kBAAA;AACA","file":"Visualization.vue","sourcesContent":["<template>\r\n <div\r\n class=\"visualization-row\"\r\n id=\"visualization-container\"\r\n @click=\"framesClicked\">\r\n <GlobalEvents\r\n v-if=\"!readOnly && canInsertTime && settingsClosed\"\r\n :filter=\"(event) => !event.shiftKey && !event.ctrlKey\"\r\n @keydown.45=\"insertTime\" />\r\n <GlobalEvents\r\n v-if=\"!readOnly && active && settingsClosed\"\r\n @keydown.83.prevent=\"setHourIni\"\r\n @keydown.69.prevent=\"setHourEnd\" />\r\n <GlobalEvents\r\n v-if=\"active && settingsClosed\"\r\n @keydown.left.prevent=\"arrowLeft\"\r\n @keydown.right.prevent=\"arrowRight\"\r\n @keydown.up.prevent=\"arrowUp\"\r\n @keydown.down.prevent=\"arrowDown\"\r\n @keydown.shift.page-down.prevent=\"nextLoopActivate\"\r\n @keydown.page-down.prevent=\"() => next()\"\r\n @keydown.page-up.prevent=\"() => prev()\"\r\n @keydown.shift.page-up.prevent=\"prevLoopActivate\"\r\n @keydown.36.prevent=\"goToFirstFrame\"\r\n @keydown.35.prevent=\"goToLastFrame\"\r\n @keydown.71.prevent=\"dialogs.goTo = true\"\r\n @keydown.73.prevent=\"dialogs.secondsPerFrame = true\"\r\n @keydown.76.prevent=\"dialogs.frames = true\"\r\n @keydown.49.97=\"() => (secondsPerFrame = 1)\"\r\n @keydown.50.98=\"() => (secondsPerFrame = 2)\"\r\n @keydown.51.99=\"() => (secondsPerFrame = 3)\"\r\n @keydown.52.100=\"() => (secondsPerFrame = 4)\"\r\n @keydown.53.101=\"() => (secondsPerFrame = 5)\" />\r\n <GlobalEvents\r\n v-if=\"prevLoop || nextLoop\"\r\n @keydown=\"breakLoop\"\r\n v-on:click=\"breakLoop\" />\r\n <settings\r\n v-if=\"active\"\r\n :dialogs-visibility=\"dialogs\"\r\n :playback-rate=\"playbackRate\"\r\n :seconds-per-frame=\"secondsPerFrame\"\r\n :frames-per-row=\"framesPerRow\"\r\n :number-of-rows=\"numberOfRows\"\r\n :max-steps=\"maxSteps\"\r\n :shift-frames=\"shiftFrames\"\r\n :customGridSize=\"customGridSize\"\r\n :stretchFrames=\"stretchFrame\"\r\n @change-playback-rate=\"(value) => (playbackRate = value)\"\r\n @change-go-to=\"changeHour\"\r\n @change-seconds-per-frame=\"(value) => (secondsPerFrame = value)\"\r\n @change-shift-frames=\"(value) => (shiftFrames = value)\"\r\n @set-frames-selection=\"setFrameSelection\"\r\n @set-custom-grid-values=\"setCustomGridValues\"\r\n @close=\"(dialog) => (dialogs[dialog] = false)\" />\r\n <div\r\n :class=\"{ 'visualization-card': true, 'active-tab': active }\"\r\n style=\"width: 100%; padding: 0\">\r\n <command-bar\r\n v-show=\"commandBarShow\"\r\n :read-only=\"readOnly\"\r\n :video-playing=\"videoPlaying\"\r\n :video-paused=\"paused\"\r\n :insert-time=\"canInsertTime\"\r\n :hour-ini-selected=\"!!hourIniSelected\"\r\n :hour-end-selected=\"!!hourEndSelected\"\r\n @prev-loop-activate=\"prevLoopActivate\"\r\n @next-loop-activate=\"nextLoopActivate\"\r\n @prev=\"prev\"\r\n @next=\"next\"\r\n @go-to=\"dialogs.goTo = true\"\r\n @open-frame-selection=\"dialogs.frames = true\"\r\n @open-frames-per-second=\"dialogs.secondsPerFrame = true\"\r\n @open-blocks=\"openBlocks\"\r\n @open-playback-rate=\"dialogs.playbackRate = true\"\r\n @play-or-pause=\"playOrPause\"\r\n @stop-playing=\"stopPlayingBar\"\r\n @set-hour-ini=\"setHourIni\"\r\n @set-hour-end=\"setHourEnd\"\r\n @insert-time=\"insertTime\"\r\n @shift-frames=\"dialogs.shiftFrames = true\" />\r\n <video-progress\r\n v-if=\"videoProgressBar\"\r\n v-show=\"videoPlaying\"\r\n :video-time=\"videoTime\" />\r\n <info-bar\r\n :playback-rate=\"playbackRate\"\r\n :seconds-per-frame=\"secondsPerFrame\"\r\n :commands-show=\"commandBarShow\"\r\n :cache=\"useCache\"\r\n :block-start-time=\"blockStartTime\"\r\n :video-total-duration=\"videoSliderTotalDuration\"\r\n :alternative-server=\"alternativeServer\"\r\n :frames-per-row=\"framesPerRow\"\r\n :number-of-rows=\"numberOfRows\"\r\n :hour-ini=\"hourIniSelected\"\r\n :hour-end=\"hourEndSelected\"\r\n :show-stretch-frame=\"showStretchFrame\"\r\n @toogle-commands-visibility=\"toogleCommandsVisibility\"\r\n @toogle-cache=\"useCache = !useCache\"\r\n @change-server=\"changeServerClick\"\r\n @update-stretch-frames=\"(value) => (stretchFrame = value)\" />\r\n <div\r\n class=\"visualization-row\"\r\n v-for=\"rowNumber in numberOfRows\"\r\n :id=\"'row-' + rowNumber\"\r\n :key=\"'row-' + rowNumber\"\r\n style=\"padding: 0px 4px\">\r\n <div\r\n v-for=\"(frame, frameNumber) in previousFrames\"\r\n :key=\"\r\n numberOfRows +\r\n '-' +\r\n framesPerRow +\r\n '-' +\r\n getIndex(rowNumber, frameNumber, Positions.previous)\r\n \"\r\n style=\"display: none\">\r\n <span v-html=\"frame.img\" />\r\n </div>\r\n <div\r\n v-for=\"(frame, frameNumber) in nextFrames\"\r\n :key=\"\r\n numberOfRows +\r\n '-' +\r\n framesPerRow +\r\n '-' +\r\n getIndex(rowNumber, frameNumber, Positions.next)\r\n \"\r\n style=\"display: none\">\r\n <span v-html=\"frame.img\" />\r\n </div>\r\n <div\r\n class=\"visualization-col\"\r\n v-for=\"(frame, frameNumber) in frames.slice(\r\n framesPerRow * (rowNumber - 1),\r\n framesPerRow * rowNumber\r\n )\"\r\n :key=\"'row-' + rowNumber + '-frame-' + frameNumber + '-' + frame.time\"\r\n :id=\"`frame-${getIndex(rowNumber, frameNumber, Positions.current)}`\"\r\n :class=\"{ loaderImg: !!frame.img }\"\r\n @click=\"\r\n frame.time\r\n ? selectFrame(\r\n getIndex(rowNumber, frameNumber, Positions.current),\r\n frame\r\n )\r\n : null\r\n \">\r\n <span :id=\"activeFrame ? 'aa' : 0\" style=\"text-align: center\">\r\n <b>\r\n {{\r\n getAudienceTime(\r\n frame.time,\r\n rowNumber,\r\n frameNumber,\r\n Positions.current\r\n )\r\n }}\r\n </b>\r\n </span>\r\n\r\n <frame\r\n ref=\"frames\"\r\n :frame=\"frame\"\r\n :index=\"getIndex(rowNumber, frameNumber, Positions.current)\"\r\n :grid-settings=\"{ numberOfRows, framesPerRow }\"\r\n :initialTime=\"frame.time === hourIniSelected\"\r\n :endTime=\"frame.time === hourEndSelected\"\r\n :betweenTime=\"\r\n frame.time > hourIniSelected && frame.time < hourEndSelected\r\n \"\r\n :active=\"\r\n getIndex(rowNumber, frameNumber, Positions.current) ===\r\n activeFrame\r\n \"\r\n :activeTab=\"active\"\r\n :videoUrl=\"fInterface ? fInterface.getVideoUrl(frame) : ''\"\r\n :videoControls=\"videoControls\"\r\n @startPlaying=\"startPlaying\"\r\n @stopPlaying=\"stopPlaying\"\r\n @playPauseStatus=\"changePlayPause\"\r\n @updateSlider=\"updateSlider\"\r\n :playback-rate=\"playbackRate\"\r\n :aspect-ratio=\"aspectRatio\"\r\n :stretchFrame=\"stretchFrame\"\r\n style=\"margin: 0 auto\"></frame>\r\n </div>\r\n </div>\r\n </div>\r\n <!-- <settings\r\n ref=\"settings2\"\r\n :active=\"active\"\r\n @goToTime=\"changeHour\"\r\n @goToBlockInterval=\"changeBlockInterval\"\r\n @setSplitTime=\"setSplitTime\"\r\n @setFrameSelection=\"setFrameSelection\"\r\n @setPlaybackRate=\"\r\n (rate) => {\r\n playbackRate = rate\r\n }\r\n \"\r\n >\r\n </settings> -->\r\n <!-- <v-dialog v-model=\"dialog\" width=\"500\">\r\n <div class=\"card\">\r\n <div class=\"card\"-title class=\"text-h5 grey lighten-2\">\r\n {{ ' Último bloco disponível até: ' }}\r\n <v-btn\r\n @click=\"goToStartBlock\"\r\n class=\"ml-2\"\r\n dark\r\n color=\"success\"\r\n depressed\r\n >\r\n <v-icon left> fa-clock </v-icon>\r\n {{ timeLastBlock }}\r\n </v-btn>\r\n <v-spacer></v-spacer>\r\n <v-btn color=\"error\" fab small class=\"ml-5\" @click=\"dialog = false\">\r\n <v-icon dark> fa fa-xmark </v-icon>\r\n </v-btn>\r\n </div-title>\r\n </div>\r\n </v-dialog>\r\n <Help :media=\"media\" @close=\"media = null\" />\r\n <v-dialog\r\n v-if=\"userMultiTabsGrid\"\r\n v-model=\"userMultiTabsGridsModel\"\r\n persistent\r\n width=\"60%\"\r\n >\r\n <div class=\"card\">\r\n <div class=\"card\"-title class=\"warning text-h5\" primary-title>\r\n <div class=\"row\" class=\"ma-0\" justify=\"center\" align=\"center\">\r\n <v-icon dark left style=\"font-size: 24px !important\">\r\n fa fa-exclamation-triangle\r\n </v-icon>\r\n <div style=\"color: white\">{{ $t('form.alert') }}</div>\r\n </div>\r\n </div-title>\r\n <div class=\"card\"-text class=\"justify-center pa-6 grey lighten-2\">\r\n <h3>\r\n {{ $t('alerts.userMultiTabsGrid') }}\r\n </h3>\r\n </div-text>\r\n <hr class=\"divider\" class=\"grey lighten-1\"></span>\r\n <div class=\"card\"-actions class=\"grey lighten-2 justify-center\">\r\n <v-btn color=\"error\" ml-5 @click=\"userMultiTabsGrid = false\">\r\n <v-icon left color=\"white\">fa fa-times</v-icon>\r\n {{ $t('form.close') }}\r\n </v-btn>\r\n </div-actions>\r\n </div>\r\n </v-dialog> -->\r\n </div>\r\n</template>\r\n<script>\r\nimport Frame from './components/Frame.vue'\r\nimport FramesInterface from './utils/FramesInterface.js'\r\nimport FramesService from './services/FramesService.js'\r\n\r\nimport Commands from './components/Commands.vue'\r\nimport Infos from './components/Infos.vue'\r\nimport VideoProgress from './components/VideoProgress.vue'\r\nimport Settings from './components/Settings.vue'\r\n\r\nconst Positions = Object.freeze({\r\n previous: 0,\r\n current: 1,\r\n next: 2,\r\n})\r\n\r\nexport default {\r\n name: 'visualization-container',\r\n props: {\r\n value: {\r\n type: Boolean,\r\n required: true,\r\n },\r\n date: {\r\n type: String,\r\n required: true,\r\n },\r\n channel: {\r\n type: Number,\r\n required: true,\r\n },\r\n startAudienceTime: {\r\n type: String,\r\n required: true,\r\n },\r\n endAudienceTime: {\r\n type: String,\r\n required: true,\r\n },\r\n videoProgressBar: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n jumpOnInsert: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n removeSelectionOnInsert: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n framesFormat: {\r\n type: [Number, String],\r\n default: 7,\r\n },\r\n maxSize: {\r\n type: Number,\r\n },\r\n videoControls: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n readOnly: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n maxSteps: {\r\n type: Number,\r\n default: 1,\r\n },\r\n customGridSize: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n showStretchFrame: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n },\r\n components: {\r\n Frame,\r\n CommandBar: Commands,\r\n InfoBar: Infos,\r\n VideoProgress,\r\n Settings,\r\n // Help,\r\n },\r\n data() {\r\n return {\r\n Positions,\r\n updatingChannel: null,\r\n dialog: false,\r\n timeLastBlock: null,\r\n alternativeServer: false,\r\n useCache: true,\r\n numberOfRows: 1,\r\n framesPerRow: 5,\r\n secondsPerFrame: 1,\r\n fInterface: null,\r\n velocity: 1,\r\n frames: [],\r\n previousFrames: [],\r\n nextFrames: [],\r\n channelCode: 0,\r\n videoPlaying: false,\r\n activeFrame: null,\r\n activeVideo: null,\r\n videoTime: 0,\r\n videoTotalTime: null,\r\n progressVideoDrag: false,\r\n hourIniSelected: false,\r\n hourEndSelected: false,\r\n canInsertTime: false,\r\n lastHeight: 0,\r\n loopInterval: null,\r\n nextLoop: false,\r\n prevLoop: false,\r\n videoSliderTotalDuration: 900,\r\n blockStartTime: null,\r\n media: null,\r\n changeServer: false,\r\n userMultiTabsGrid: false,\r\n userMultiTabsGridsModel: true,\r\n playbackRate: 1,\r\n paused: false,\r\n commandBarShow: true,\r\n dialogs: {\r\n playbackRate: false,\r\n goTo: false,\r\n secondsPerFrame: false,\r\n frames: false,\r\n shiftFrames: false,\r\n },\r\n lastNext: 0,\r\n lastPrev: 0,\r\n shiftFrames: 0,\r\n aspectRatio: 11 / 9,\r\n showCustomInputs: false,\r\n stretchFrame: false,\r\n }\r\n },\r\n async created() {\r\n this.changeServer = this.serverOfFrames === 'alternative'\r\n this.alternativeServer = this.serverOfFrames === 'alternative'\r\n\r\n const settings = [\r\n {\r\n framesPerRow: 1,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 2,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 3,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 3,\r\n numberOfRows: 2,\r\n },\r\n {\r\n framesPerRow: 4,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 4,\r\n numberOfRows: 2,\r\n },\r\n {\r\n framesPerRow: 5,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 5,\r\n numberOfRows: 2,\r\n },\r\n {\r\n framesPerRow: 6,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 6,\r\n numberOfRows: 2,\r\n },\r\n {\r\n //Custom (item 11)\r\n framesPerRow: 7,\r\n numberOfRows: 3,\r\n },\r\n ]\r\n\r\n // Os valores custom são guardados no local storage e não na base de dados\r\n const customValues = JSON.parse(localStorage.getItem('customGridValues'))\r\n\r\n if (this.framesFormat == '11' && !!customValues) {\r\n this.numberOfRows = customValues[0]\r\n this.framesPerRow = customValues[1]\r\n } else {\r\n const storedOnDb = settings[parseInt(this.framesFormat) - 1]\r\n this.framesPerRow = storedOnDb.framesPerRow\r\n this.numberOfRows = storedOnDb.numberOfRows\r\n }\r\n\r\n await this.createFramesInterface()\r\n this.$nextTick(this.resize)\r\n },\r\n methods: {\r\n stopVideoPlaying(array) {\r\n for (const frame of array || this.$refs.frames) {\r\n if (\r\n frame.videoStatus === frame.Status.playing ||\r\n frame.videoStatus === frame.Status.paused\r\n ) {\r\n frame.stop(false)\r\n }\r\n }\r\n this.activeVideo = null\r\n },\r\n toogleCommandsVisibility() {\r\n this.commandBarShow = !this.commandBarShow\r\n this.$nextTick(this.resize)\r\n },\r\n framesClicked(e) {\r\n if (e.target.parentNode.id != 'insert') {\r\n this.active = true\r\n }\r\n },\r\n async goToStartBlock() {\r\n try {\r\n const d = new Date()\r\n let timestamp = Date.UTC(\r\n d.getFullYear(),\r\n d.getMonth(),\r\n d.getDate(),\r\n d.getHours(),\r\n d.getMinutes(),\r\n d.getSeconds()\r\n )\r\n\r\n const response = (\r\n await FramesService.getNextAvailableBlock({\r\n channel: this.channel,\r\n time: timestamp / 1000,\r\n })\r\n ).data\r\n\r\n this.dialog = false\r\n this.changeHour(this.convertToAudienceTime(response.data.start, ':'))\r\n } catch (err) {\r\n // console.error(err)\r\n }\r\n },\r\n async checkAvailableBlock() {\r\n try {\r\n const d = new Date()\r\n let timestamp = Date.UTC(\r\n d.getFullYear(),\r\n d.getMonth(),\r\n d.getDate(),\r\n d.getHours(),\r\n d.getMinutes(),\r\n d.getSeconds()\r\n )\r\n\r\n const response = (\r\n await FramesService.getNextAvailableBlock({\r\n channel: this.channel,\r\n time: timestamp / 1000,\r\n })\r\n ).data\r\n\r\n this.timeLastBlock = this.convertToAudienceTime(response.data.end, ':')\r\n this.dialog = true\r\n if (!response.status) {\r\n this.timeLastBlock = 'N/D'\r\n }\r\n } catch (err) {\r\n // console.error(err)\r\n }\r\n },\r\n updateSlider(videoStartTime, time) {\r\n // * atualizar slider se estiver fora do range definido previamente\r\n if (\r\n time < this.blockStartTime ||\r\n time > this.blockStartTime ||\r\n videoStartTime > this.blockStartTime + this.videoSliderTotalDuration\r\n ) {\r\n this.blockStartTime = videoStartTime\r\n this.videoSliderTotalDuration = 900\r\n }\r\n },\r\n nextLoopActivate() {\r\n this.breakLoop()\r\n this.loopInterval = setInterval(\r\n () => this.next({ ignoreTime: true }),\r\n this.swapImagesDelay\r\n )\r\n setTimeout(() => {\r\n this.nextLoop = true\r\n }, 0)\r\n },\r\n prevLoopActivate() {\r\n this.breakLoop()\r\n this.loopInterval = setInterval(\r\n () => this.prev({ ignoreTime: true }),\r\n this.swapImagesDelay\r\n )\r\n setTimeout(() => {\r\n this.prevLoop = true\r\n }, 0)\r\n },\r\n breakLoop() {\r\n clearInterval(this.loopInterval)\r\n this.loopInterval = null\r\n this.nextLoop = false\r\n this.prevLoop = false\r\n },\r\n changePlayPause(status) {\r\n this.paused = !status\r\n },\r\n resize(height = this.lastHeight) {\r\n this.lastHeight = height\r\n if (this.$refs.frames) {\r\n for (let frame of this.$refs.frames) {\r\n frame.resize(height)\r\n }\r\n }\r\n this.$emit('resized')\r\n },\r\n async goToFirstFrame() {\r\n let frames = this.$refs.frames\r\n\r\n let audienceTime = null\r\n if (frames.length > 0) {\r\n let frame = frames[0].frame\r\n audienceTime = this.getAudienceTime(frame.time, 0, 0, 0)\r\n }\r\n if (audienceTime) {\r\n const [hours, minutes, seconds] = audienceTime.split(':')\r\n const totalSeconds =\r\n parseInt(hours) * 3600 + parseInt(minutes) * 60 + parseInt(seconds)\r\n if (totalSeconds >= 9000)\r\n this.changeHour(this.getLastFirtsBlockTime(audienceTime, true))\r\n else this.changeHour(this.getLastFirtsBlockTime('02:30:00', true))\r\n }\r\n },\r\n async goToLastFrame() {\r\n let frames = this.$refs.frames\r\n let audienceTime = null\r\n if (frames.length > 0) {\r\n let frame = frames[0].frame\r\n\r\n audienceTime = this.getAudienceTime(frame.time, 0, 0, 0)\r\n }\r\n if (audienceTime) {\r\n this.changeHour(this.getLastFirtsBlockTime(audienceTime))\r\n }\r\n },\r\n getLastFirtsBlockTime(time, first = false) {\r\n if (time.indexOf(':') !== -1) {\r\n time = time.replace(/:/g, '')\r\n }\r\n let h, m, newTime\r\n const t = time.match(/.{1,2}/g)\r\n if (t[0] && t[1]) {\r\n h = parseInt(t[0])\r\n m = parseInt(t[1])\r\n }\r\n if (h < 26) {\r\n if (m < 15)\r\n if (first) newTime = t[0] + ':00:00'\r\n else newTime = t[0] + ':14:59'\r\n else if (m < 30)\r\n if (first) newTime = t[0] + ':15:00'\r\n else newTime = t[0] + ':29:59'\r\n else if (m < 45)\r\n if (first) newTime = t[0] + ':30:00'\r\n else newTime = t[0] + ':44:59'\r\n else if (first) newTime = t[0] + ':45:00'\r\n else newTime = t[0] + ':59:59'\r\n } else {\r\n if (m < 15)\r\n if (first) newTime = '26:00:00'\r\n else newTime = '26:14:59'\r\n else {\r\n if (first) newTime = '26:15:00'\r\n else newTime = '26:29:59'\r\n }\r\n }\r\n return newTime\r\n },\r\n openBlocks() {\r\n this.$refs.settings2?.openBlocks()\r\n },\r\n playOrPause() {\r\n const array = this.$refs.frames.filter((fc) => !!fc.active)\r\n if (array.length === 1) {\r\n const frame = array[0]\r\n frame.playOrPause(this.playbackRate)\r\n }\r\n },\r\n stopPlayingBar() {\r\n for (let ref of this.$refs.frames) {\r\n if (\r\n ref.videoStatus === ref.Status.playing ||\r\n ref.videoStatus === ref.Status.paused\r\n ) {\r\n ref.stop(false)\r\n }\r\n }\r\n },\r\n async setFrameSelection(selected) {\r\n this.frames = this.loadingArray\r\n const settings = [\r\n {\r\n framesPerRow: 1,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 2,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 3,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 3,\r\n numberOfRows: 2,\r\n },\r\n {\r\n framesPerRow: 4,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 4,\r\n numberOfRows: 2,\r\n },\r\n {\r\n framesPerRow: 5,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 5,\r\n numberOfRows: 2,\r\n },\r\n {\r\n framesPerRow: 6,\r\n numberOfRows: 1,\r\n },\r\n {\r\n framesPerRow: 6,\r\n numberOfRows: 2,\r\n },\r\n {\r\n //Custom (item 11)\r\n framesPerRow: 7,\r\n numberOfRows: 3,\r\n },\r\n ]\r\n\r\n const formatSelected = settings[selected - 1]\r\n this.framesPerRow = formatSelected.framesPerRow\r\n this.numberOfRows = formatSelected.numberOfRows\r\n\r\n await this.fInterface.changeSize(this.numberOfRows, this.framesPerRow)\r\n this.getFramesArray()\r\n this.$nextTick(this.resize)\r\n this.$emit('frames-format-changed', selected)\r\n },\r\n async setCustomGridValues(customValues) {\r\n this.numberOfRows = customValues[0]\r\n this.framesPerRow = customValues[1]\r\n localStorage.setItem('customGridValues', JSON.stringify(customValues))\r\n await this.fInterface.changeSize(this.numberOfRows, this.framesPerRow)\r\n this.getFramesArray()\r\n this.$nextTick(this.resize)\r\n this.$emit('frames-format-changed', 11)\r\n },\r\n getFramesArray() {\r\n this.frames = this.fInterface.getFrames(Positions.current)\r\n this.nextFrames = this.fInterface.getFrames(Positions.next)\r\n this.previousFrames = this.fInterface.getFrames(Positions.previous)\r\n\r\n const div = document.createElement('div')\r\n div.innerHTML = this.frames[0].image\r\n const newAspectRatio =\r\n div.getElementsByTagName('img')[0]?.naturalWidth /\r\n div.getElementsByTagName('img')[0]?.naturalHeight\r\n\r\n this.aspectRatio = isNaN(newAspectRatio)\r\n ? this.aspectRatio\r\n : newAspectRatio\r\n\r\n this.$nextTick(this.resize)\r\n\r\n const frame = this.frames.find((f) => f.blockStart)\r\n if (frame && this.alternativeServer) {\r\n this.$emit(\r\n 'new-block',\r\n frame.title?.match(/[0-9]{3}\\/(?:[0-9]+_?)+/)[0]\r\n )\r\n }\r\n },\r\n async createFramesInterface(startTime = this.startAudienceTime) {\r\n this.frames = this.loadingArray\r\n // let ch = this.channel\r\n // let associationTMP = {\r\n // 1735073: 1,\r\n // 1735074: 139,\r\n // 1735075: 3,\r\n // 1735076: 132,\r\n // }\r\n // //\r\n // this.channelCode = associationTMP[ch] ? associationTMP[ch] : ch\r\n\r\n const t = startTime.match(/.{1,2}/g)\r\n const d = this.getDateParts()\r\n const time = Date.UTC(d.year, d.month, d.day, t[0], t[1], t[2]) / 1000\r\n // * iniciar slider\r\n this.blockStartTime = time\r\n this.fInterface = await new FramesInterface(\r\n this.channel,\r\n this.numberOfRows,\r\n this.framesPerRow,\r\n time,\r\n this.startAudienceTime,\r\n this.useCache,\r\n this.shiftFrames\r\n )\r\n await this.fInterface.init()\r\n\r\n this.getFramesArray()\r\n\r\n const div = document.createElement('div')\r\n div.innerHTML = this.frames[0].image\r\n\r\n this.aspectRatio =\r\n div.getElementsByTagName('img')[0].naturalWidth /\r\n div.getElementsByTagName('img')[0].naturalHeight\r\n\r\n this.activeFrame = this.getIndex(1, 0, Positions.current)\r\n\r\n this.activeVideo = null\r\n },\r\n getIndex(rowNumber, frameIndex, position) {\r\n const baseOffset = this.framesPerRow * this.numberOfRows * position\r\n const rowOffset = (rowNumber - 1) * this.framesPerRow\r\n return baseOffset + rowOffset + frameIndex\r\n },\r\n getAudienceTime(frameTime, rowNumber, frameNumber, position) {\r\n if (!frameTime) {\r\n return 'Loading...'\r\n } else if (\r\n this.getIndex(rowNumber, frameNumber, position) === this.activeVideo\r\n ) {\r\n return this.convertToAudienceTime(this.videoTime)\r\n } else {\r\n return this.convertToAudienceTime(frameTime)\r\n }\r\n },\r\n dateInUtc(miliSeconds) {\r\n var date = new Date(miliSeconds)\r\n var utc = new Date(\r\n date.getUTCFullYear(),\r\n date.getUTCMonth(),\r\n date.getUTCDate(),\r\n date.getUTCHours(),\r\n date.getUTCMinutes(),\r\n date.getUTCSeconds()\r\n )\r\n return utc\r\n },\r\n convertToAudienceTime(time, separator = ':') {\r\n const d = this.getDateParts()\r\n const limit = Date.UTC(d.year, d.month, d.day, 23, 59, 59) / 1000\r\n\r\n let hour = this.dateInUtc(time * 1000)\r\n .toTimeString()\r\n .split(' ')[0]\r\n .split(':')\r\n .map(Number)\r\n\r\n if (time > limit && time <= limit + this.startAudienceSeconds) {\r\n hour[0] = 24 + hour[0]\r\n }\r\n return hour\r\n .map((part) => (part > 9 ? part.toString() : '0' + part))\r\n .join(separator)\r\n },\r\n getDateParts(date = this.date) {\r\n const data = /(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})/.exec(\r\n date\r\n )?.groups\r\n if (data) {\r\n return {\r\n year: parseInt(data.year),\r\n month: parseInt(data.month) - 1,\r\n day: parseInt(data.day),\r\n }\r\n }\r\n return {\r\n year: null,\r\n month: null,\r\n day: null,\r\n }\r\n },\r\n selectFrame(index, frame) {\r\n const d = this.getDateParts()\r\n const limit = Date.UTC(d.year, d.month, d.day, 23, 59, 59) / 1000\r\n const frameTime = frame?.time\r\n\r\n if (frameTime - (this.startAudienceSeconds + limit) <= 0) {\r\n if (this.hourIniSelected === true) {\r\n this.hourIniSelected = frameTime\r\n\r\n if (\r\n this.hourEndSelected &&\r\n this.hourIniSelected > this.hourEndSelected\r\n ) {\r\n this.hourEndSelected = false\r\n }\r\n } else if (this.hourEndSelected === true) {\r\n if (frameTime > this.hourIniSelected) {\r\n this.hourEndSelected = frameTime\r\n this.canInsertTime = true\r\n } else {\r\n this.hourEndSelected = false\r\n }\r\n }\r\n }\r\n\r\n if (this.activeFrame !== index) {\r\n // ? Se clicar no frame diferente de onde está a dar play, faz pausa\r\n const array = this.$refs.frames.filter(\r\n (fc) => fc.videoStatus === fc.Status.playing\r\n )\r\n if (array.length === 1) {\r\n const frame = array[0]\r\n frame.playOrPause()\r\n }\r\n this.activeVideo = null\r\n this.activeFrame = index\r\n }\r\n },\r\n setHourIni() {\r\n this.canInsertTime = true\r\n this.hourIniSelected = true\r\n document.getElementById(`frame-${this.activeFrame}`).click()\r\n this.$emit('setHourIni', {\r\n hour_ini: this.hourIniSelected\r\n ? this.convertToAudienceTime(this.hourIniSelected, '')\r\n : null,\r\n })\r\n },\r\n setHourEnd() {\r\n this.canInsertTime = true\r\n this.hourEndSelected = true\r\n document.getElementById(`frame-${this.activeFrame}`).click()\r\n },\r\n //* Navegação\r\n arrowRight() {\r\n if (this.checkLimitRight(false)) {\r\n if (\r\n this.activeFrame ===\r\n this.numberOfRows * this.framesPerRow * 2 - 1\r\n ) {\r\n this.next()\r\n } else {\r\n this.activeFrame++\r\n }\r\n }\r\n },\r\n arrowLeft() {\r\n if (this.checkLimitLeft(false)) {\r\n if (this.activeFrame === this.numberOfRows * this.framesPerRow) {\r\n this.prev({ stayOnLast: true })\r\n } else {\r\n this.activeFrame--\r\n }\r\n }\r\n },\r\n arrowUp() {\r\n const relativePosition =\r\n this.activeFrame - this.numberOfRows * this.framesPerRow\r\n const currentRow = Math.floor(relativePosition / this.framesPerRow)\r\n if (currentRow > 0) {\r\n this.activeFrame -= this.framesPerRow\r\n }\r\n },\r\n\r\n arrowDown() {\r\n const relativePosition =\r\n this.activeFrame - this.numberOfRows * this.framesPerRow\r\n const currentRow = Math.floor(relativePosition / this.framesPerRow)\r\n\r\n if (currentRow < this.numberOfRows - 1) {\r\n this.activeFrame += this.framesPerRow\r\n }\r\n },\r\n checkLimitRight(value) {\r\n const hours = this.endAudienceTime.match(/.{1,2}/g)\r\n const d = this.getDateParts()\r\n const high = Date.UTC(\r\n d.year,\r\n d.month,\r\n d.day,\r\n hours[0],\r\n parseInt(hours[1]) + 30,\r\n hours[2]\r\n )\r\n\r\n if (value) {\r\n return (\r\n high >\r\n (this.fInterface.getCurrentTime() +\r\n this.numberOfRows * this.framesPerRow -\r\n 1) *\r\n 1000\r\n )\r\n } else {\r\n return high > this.fInterface.getCurrentTime() * 1000\r\n }\r\n },\r\n checkLimitLeft(value) {\r\n const hours = this.startAudienceTime.match(/.{1,2}/g)\r\n const d = this.getDateParts()\r\n const low = Date.UTC(d.year, d.month, d.day, hours[0], hours[1], hours[2])\r\n\r\n if (value) {\r\n return low <= (this.fInterface.getCurrentTime() - 1) * 1000\r\n } else {\r\n return (\r\n low <\r\n (this.fInterface.getCurrentTime() +\r\n this.activeFrame -\r\n this.numberOfRows * this.framesPerRow) *\r\n 1000\r\n )\r\n }\r\n },\r\n async next(config = {}) {\r\n if (\r\n (config.ignoreTime ||\r\n Date.now() - this.lastNext > this.swapImagesDelay) &&\r\n this.checkLimitRight(true) &&\r\n !this.navigationPending\r\n ) {\r\n this.navigationPending = true\r\n this.stopVideoPlaying()\r\n\r\n this.navigationPending = await new Promise((resolve) => {\r\n this.fInterface\r\n .loadNextFrames()\r\n .then(() => {\r\n this.activeFrame = this.getIndex(1, 0, Positions.current)\r\n\r\n this.getFramesArray()\r\n this.lastNext = Date.now()\r\n resolve(false)\r\n })\r\n .catch(() => {\r\n resolve(false)\r\n })\r\n })\r\n } else {\r\n // console.error('next blocked')\r\n }\r\n },\r\n async prev(config = {}) {\r\n if (\r\n (config.ignoreTime ||\r\n Date.now() - this.lastPrev > this.swapImagesDelay) &&\r\n this.checkLimitLeft(true) &&\r\n !this.navigationPending\r\n ) {\r\n this.navigationPending = true\r\n this.stopVideoPlaying()\r\n\r\n this.navigationPending = await new Promise((resolve) => {\r\n this.fInterface\r\n .loadPrevFrames()\r\n .then(() => {\r\n if (config.stayOnLast) {\r\n this.activeFrame = this.getIndex(\r\n this.numberOfRows,\r\n this.framesPerRow - 1,\r\n Positions.current\r\n )\r\n } else {\r\n this.activeFrame = this.getIndex(1, 0, Positions.current)\r\n }\r\n\r\n this.getFramesArray()\r\n this.lastPrev = Date.now()\r\n resolve(false)\r\n })\r\n .catch(() => {\r\n resolve(false)\r\n })\r\n })\r\n } else {\r\n // console.error('prev blocked')\r\n }\r\n },\r\n async setStartTime(time) {\r\n if (time.indexOf(':') !== -1) {\r\n time = time.replace(/:/g, '')\r\n }\r\n const t = time.match(/.{1,2}/g)\r\n const d = this.getDateParts()\r\n const setTime = Date.UTC(d.year, d.month, d.day, t[0], t[1], t[2]) / 1000\r\n // this.frames = this.loadingArray\r\n\r\n await this.fInterface.changeTime(setTime)\r\n\r\n this.getFramesArray()\r\n\r\n this.activeFrame = this.getIndex(1, 0, Positions.current)\r\n\r\n this.activeVideo = null\r\n\r\n return true\r\n },\r\n hourToTimeStamp(time) {\r\n if (time.indexOf(':') !== -1) {\r\n time = time.replace(/:/g, '')\r\n }\r\n const t = time.match(/.{1,2}/g)\r\n const d = this.getDateParts()\r\n const setTime = Date.UTC(d.year, d.month, d.day, t[0], t[1], t[2]) / 1000\r\n\r\n return setTime\r\n },\r\n changeHour(value) {\r\n if (value) {\r\n return new Promise((resolve) => {\r\n setTimeout(async () => {\r\n this.stopVideoPlaying()\r\n\r\n await this.setStartTime(value, true)\r\n resolve()\r\n }, 0)\r\n })\r\n }\r\n },\r\n changeBlockInterval(value) {\r\n this.changeHour(value.ini)\r\n let time_ini, time_end\r\n time_ini = this.hourToTimeStamp(value.ini)\r\n time_end = this.hourToTimeStamp(value.end)\r\n this.videoSliderTotalDuration = time_end - time_ini\r\n this.$refs.frames[0].changeSettings(time_ini)\r\n this.blockStartTime = time_ini\r\n },\r\n //eslint-disable-next-line\r\n async updateVideoTime(index, videoTime) {\r\n this.activeVideo = index\r\n this.videoTime = videoTime\r\n },\r\n //eslint-disable-next-line\r\n updateVideoStatus(currentTime) {\r\n if (!this.progressVideoDrag) {\r\n // ESTA FUNÇÃO PASSOU PARA DENTRO DOS COMMANDS\r\n // this.updateProgress(null, currentTime)\r\n }\r\n },\r\n async startPlaying(frame, totalTime) {\r\n const array = this.$refs.frames.filter(\r\n (fc) => fc.frame.time !== frame.time\r\n )\r\n this.stopVideoPlaying(array)\r\n\r\n this.videoTotalTime = totalTime\r\n this.videoPlaying = true\r\n },\r\n stopPlaying() {\r\n this.videoTotalTime = null\r\n this.videoPlaying = false\r\n this.paused = false\r\n },\r\n insertTime() {\r\n this.$emit('timeToInsert', {\r\n channel: this.channel,\r\n hour_ini: this.hourIniSelected\r\n ? this.convertToAudienceTime(this.hourIniSelected, '')\r\n : null,\r\n hour_end: this.hourEndSelected\r\n ? this.convertToAudienceTime(this.hourEndSelected, '')\r\n : null,\r\n force: false,\r\n })\r\n\r\n if (this.jumpOnInsert) {\r\n this.changeHour(\r\n this.convertToAudienceTime(\r\n this.hourEndSelected || this.hourIniSelected\r\n )\r\n ).then(() => {\r\n this.activeFrame = this.getIndex(1, 1, Positions.current)\r\n })\r\n }\r\n\r\n if (this.removeSelectionOnInsert) {\r\n this.hourIniSelected = null\r\n this.hourEndSelected = null\r\n this.canInsertTime = false\r\n }\r\n },\r\n insertTimeForce() {\r\n this.$emit('timeToInsert', {\r\n channel: this.channel,\r\n hour_ini: this.hourIniSelected\r\n ? this.convertToAudienceTime(this.hourIniSelected, '')\r\n : null,\r\n hour_end: this.hourEndSelected\r\n ? this.convertToAudienceTime(this.hourEndSelected, '')\r\n : null,\r\n force: true,\r\n })\r\n\r\n if (this.removeSelectionOnInsert) {\r\n this.hourIniSelected = null\r\n this.hourEndSelected = null\r\n this.canInsertTime = false\r\n }\r\n },\r\n async getChannelMedia() {\r\n // this.media = (await ChannelService.show(this.channel)).data.MEDIA\r\n },\r\n async changeServerClick() {\r\n this.changeServer = !this.changeServer\r\n this.alternativeServer = this.changeServer\r\n\r\n sessionStorage.setItem(\r\n 'server',\r\n this.changeServer ? 'alternative' : 'default'\r\n )\r\n\r\n await this.createFramesInterface(\r\n this.convertToAudienceTime(\r\n this.$refs.frames.find((frame) => frame.index === this.activeFrame)\r\n .frame.time,\r\n ''\r\n )\r\n )\r\n\r\n this.$nextTick(this.resize)\r\n },\r\n },\r\n computed: {\r\n swapImagesDelay() {\r\n return 0\r\n // return this.numberOfRows * this.framesPerRow * 15\r\n },\r\n active: {\r\n get() {\r\n return this.value\r\n },\r\n set(value) {\r\n this.$emit('input', value)\r\n },\r\n },\r\n settingsClosed() {\r\n return !Object.values(this.dialogs).find((v) => v)\r\n },\r\n startAudienceSeconds() {\r\n const t = this.startAudienceTime.match(/.{1,2}/g)\r\n return parseInt(t[0] * 3600 + t[1] * 60 + t[2])\r\n },\r\n loadingArray() {\r\n return Array.from(Array(this.numberOfRows * this.framesPerRow).keys())\r\n },\r\n serverOfFrames() {\r\n return sessionStorage.getItem('server')\r\n },\r\n },\r\n beforeDestroy() {\r\n sessionStorage.setItem('server', 'default')\r\n },\r\n watch: {\r\n async secondsPerFrame() {\r\n const activeF =\r\n this.frames[this.activeFrame - this.numberOfRows * this.framesPerRow]\r\n\r\n if (activeF) {\r\n this.changeHour(this.getAudienceTime(activeF.time, 0, 0, 0))\r\n this.fInterface.setCurrentStep(this.secondsPerFrame)\r\n await this.fInterface.loadFrames()\r\n this.getFramesArray()\r\n }\r\n },\r\n async shiftFrames() {\r\n this.createFramesInterface()\r\n },\r\n framesFormat(value) {\r\n this.setFrameSelection(value)\r\n },\r\n active() {\r\n // ? sempre que trocamos de tabs dar reset as horas selected\r\n if (this.removeSelectionOnInsert) {\r\n this.hourIniSelected = false\r\n this.hourEndSelected = false\r\n }\r\n },\r\n useCache() {\r\n this.createFramesInterface()\r\n },\r\n hourIniSelected(value) {\r\n if (value) {\r\n sessionStorage.setItem(\r\n 'currentTimeFrames',\r\n this.convertToAudienceTime(this.hourIniSelected, '')\r\n )\r\n } else {\r\n sessionStorage.removeItem('currentTimeFrames')\r\n }\r\n },\r\n activeFrame(value) {\r\n if (value) {\r\n this.stopPlayingBar()\r\n }\r\n },\r\n channel() {\r\n this.updatingChannel = new Promise((resolve, reject) => {\r\n try {\r\n this.createFramesInterface()\r\n resolve(true)\r\n } catch (err) {\r\n reject(err)\r\n }\r\n })\r\n },\r\n stretchFrame() {\r\n this.$nextTick(this.resize)\r\n },\r\n },\r\n}\r\n</script>\r\n<style scoped>\r\n.visualization-row {\r\n display: flex;\r\n flex-wrap: wrap;\r\n flex: 1 1 auto;\r\n}\r\n\r\n.visualization-col {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 5px;\r\n}\r\n\r\n.visualization-divider {\r\n display: block;\r\n flex: 1 1 100%;\r\n height: 0px;\r\n max-height: 0px;\r\n opacity: 1;\r\n transition: inherit;\r\n border-style: solid;\r\n border-width: thin 0 0 0;\r\n border-color: rgba(0, 0, 0, 0.12);\r\n margin: 0;\r\n}\r\n\r\n.visualization-divider.vertical {\r\n align-self: stretch;\r\n border-width: 0 thin 0 0;\r\n display: inline-flex;\r\n height: inherit;\r\n margin-left: -1px;\r\n max-height: 100%;\r\n max-width: 0px;\r\n vertical-align: text-bottom;\r\n width: 0px;\r\n}\r\n\r\n.visualization-card {\r\n flex-basis: 0;\r\n flex-grow: 1;\r\n max-width: 100%;\r\n padding: 12px;\r\n width: 100%;\r\n transition-property: box-shadow, opacity, -webkit-box-shadow;\r\n overflow-wrap: break-word;\r\n /*box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);*/\r\n}\r\n\r\n.visualization-justify-center,\r\n* >>> .visualization-justify-center {\r\n justify-content: center;\r\n}\r\n\r\n.visualization-align-center {\r\n align-items: center;\r\n}\r\n\r\n#visualization-container {\r\n max-width: 100% !important;\r\n margin: 0 auto !important;\r\n height: 100%;\r\n border-bottom: none;\r\n}\r\n#visualization-container > .card {\r\n border-radius: 0 !important;\r\n font-size: 12px;\r\n width: 100%;\r\n box-shadow: none;\r\n height: 100%;\r\n}\r\n\r\n#command-bar,\r\n#info-bar {\r\n background-color: #f5f5f5;\r\n box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),\r\n 0 1px 5px 0 rgba(0, 0, 0, 0.12);\r\n}\r\n#command-bar button {\r\n width: 42px;\r\n height: 36px;\r\n border: none;\r\n background: none;\r\n}\r\n\r\n#command-bar button:hover {\r\n cursor: pointer;\r\n background: rgba(0, 0, 0, 0.12);\r\n}\r\n\r\n#command-bar svg {\r\n font-size: 16px;\r\n}\r\n\r\n#command-bar {\r\n padding: 0 !important;\r\n}\r\n\r\n#info-bar {\r\n padding: 4px;\r\n font-size: 14px;\r\n position: relative;\r\n}\r\n\r\n.settings-container {\r\n position: absolute;\r\n right: 14px;\r\n top: 50%;\r\n transform: translateY(-50%);\r\n}\r\n\r\n.settings-container > * {\r\n margin: 0 2px;\r\n cursor: pointer;\r\n}\r\n\r\n#info-bar svg {\r\n font-size: 16px;\r\n}\r\n\r\n#info-bar .divider {\r\n margin: 0 8px;\r\n}\r\n\r\nsvg:focus {\r\n border: none;\r\n}\r\n\r\n.visualization-card {\r\n border-left: 8px solid #eee;\r\n}\r\n\r\n.active-tab {\r\n border-left: 8px solid var(--visualization-primary) !important;\r\n border-image-slice: 1;\r\n}\r\n\r\n[id^='frame-'] {\r\n padding: 1px;\r\n display: flex;\r\n flex-flow: column;\r\n}\r\n\r\n.tooltip {\r\n display: block !important;\r\n z-index: 10000;\r\n}\r\n\r\n.tooltip .tooltip-inner {\r\n background: var(--visualization-primary);\r\n color: white;\r\n border-radius: 16px;\r\n padding: 5px 10px 4px;\r\n}\r\n\r\n.tooltip .tooltip-arrow {\r\n width: 0;\r\n height: 0;\r\n border-style: solid;\r\n position: absolute;\r\n margin: 5px;\r\n border-color: var(--visualization-primary);\r\n z-index: 1;\r\n}\r\n\r\n.tooltip[x-placement^='top'] {\r\n margin-bottom: 5px;\r\n}\r\n\r\n.tooltip[x-placement^='top'] .tooltip-arrow {\r\n border-width: 5px 5px 0 5px;\r\n border-left-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n bottom: -5px;\r\n left: calc(50% - 5px);\r\n margin-top: 0;\r\n margin-bottom: 0;\r\n}\r\n\r\n.tooltip[x-placement^='bottom'] {\r\n margin-top: 5px;\r\n}\r\n\r\n.tooltip[x-placement^='bottom'] .tooltip-arrow {\r\n border-width: 0 5px 5px 5px;\r\n border-left-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-top-color: transparent !important;\r\n top: -5px;\r\n left: calc(50% - 5px);\r\n margin-top: 0;\r\n margin-bottom: 0;\r\n}\r\n\r\n.tooltip[x-placement^='right'] {\r\n margin-left: 5px;\r\n}\r\n\r\n.tooltip[x-placement^='right'] .tooltip-arrow {\r\n border-width: 5px 5px 5px 0;\r\n border-left-color: transparent !important;\r\n border-top-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n left: -5px;\r\n top: calc(50% - 5px);\r\n margin-left: 0;\r\n margin-right: 0;\r\n}\r\n\r\n.tooltip[x-placement^='left'] {\r\n margin-right: 5px;\r\n}\r\n\r\n.tooltip[x-placement^='left'] .tooltip-arrow {\r\n border-width: 5px 0 5px 5px;\r\n border-top-color: transparent !important;\r\n border-right-color: transparent !important;\r\n border-bottom-color: transparent !important;\r\n right: -5px;\r\n top: calc(50% - 5px);\r\n margin-left: 0;\r\n margin-right: 0;\r\n}\r\n\r\n.tooltip.popover .popover-inner {\r\n background: #f9f9f9;\r\n color: black;\r\n padding: 24px;\r\n border-radius: 5px;\r\n box-shadow: 0 5px 30px rgba(black, 0.1);\r\n}\r\n\r\n.tooltip.popover .popover-arrow {\r\n border-color: #f9f9f9;\r\n}\r\n\r\n.tooltip[aria-hidden='true'] {\r\n visibility: hidden;\r\n opacity: 0;\r\n transition: opacity 0.15s, visibility 0.15s;\r\n}\r\n\r\n.tooltip[aria-hidden='false'] {\r\n visibility: visible;\r\n opacity: 1;\r\n transition: opacity 0.15s;\r\n}\r\n\r\n.custom-frametime {\r\n font-size: smaller;\r\n}\r\n</style>\r\n"]}, media: undefined });
5340
5697
 
5341
5698
  };
5342
5699
  /* scoped */
5343
- const __vue_scope_id__ = "data-v-27fc3944";
5700
+ const __vue_scope_id__ = "data-v-a861684a";
5344
5701
  /* module identifier */
5345
5702
  const __vue_module_identifier__ = undefined;
5346
5703
  /* functional template */