diff --git a/VERSION b/VERSION index 437459cd94c9fa59d82c61c0bc8aa36e293b735e..e70b4523ae7ffe8aa3cac8ecd1b093fba5a98737 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.5.0 +2.6.0 diff --git a/frontend/src/assets/previews/angle_event_left.png b/frontend/src/assets/previews/angle_event_left.png new file mode 100644 index 0000000000000000000000000000000000000000..6aabcb3a2aba29522187a708258c424d2977462d Binary files /dev/null and b/frontend/src/assets/previews/angle_event_left.png differ diff --git a/frontend/src/assets/previews/angle_event_right.png b/frontend/src/assets/previews/angle_event_right.png new file mode 100644 index 0000000000000000000000000000000000000000..abd170a0feec49d6369601b4b2f328625676280b Binary files /dev/null and b/frontend/src/assets/previews/angle_event_right.png differ diff --git a/frontend/src/assets/previews/right_event.png b/frontend/src/assets/previews/right_event.png new file mode 100644 index 0000000000000000000000000000000000000000..870239374842dbd6c96635709a9fedb891e77514 Binary files /dev/null and b/frontend/src/assets/previews/right_event.png differ diff --git a/frontend/src/assets/template/angle_event_left/bg_black.png b/frontend/src/assets/template/angle_event_left/bg_black.png new file mode 100644 index 0000000000000000000000000000000000000000..2f7ffa7a8dc2aa42169f1491439a18997873ad08 Binary files /dev/null and b/frontend/src/assets/template/angle_event_left/bg_black.png differ diff --git a/frontend/src/assets/template/angle_event_left/bg_white.png b/frontend/src/assets/template/angle_event_left/bg_white.png new file mode 100644 index 0000000000000000000000000000000000000000..27b875f739d07593783384ceb6d04eadfb9f5063 Binary files /dev/null and b/frontend/src/assets/template/angle_event_left/bg_white.png differ diff --git a/frontend/src/assets/template/angle_event_right/bg_black.png b/frontend/src/assets/template/angle_event_right/bg_black.png new file mode 100644 index 0000000000000000000000000000000000000000..293cf58051391a81d6fb56033c448472ad3c1cc7 Binary files /dev/null and b/frontend/src/assets/template/angle_event_right/bg_black.png differ diff --git a/frontend/src/assets/template/angle_event_right/bg_white.png b/frontend/src/assets/template/angle_event_right/bg_white.png new file mode 100644 index 0000000000000000000000000000000000000000..d0cd27641481a74033ef60238837781c09e81ce3 Binary files /dev/null and b/frontend/src/assets/template/angle_event_right/bg_white.png differ diff --git a/frontend/src/assets/template/right_event/bg_black.png b/frontend/src/assets/template/right_event/bg_black.png new file mode 100644 index 0000000000000000000000000000000000000000..dd2f852308d2dc4e76ec4e41f5110af6f11bba5f Binary files /dev/null and b/frontend/src/assets/template/right_event/bg_black.png differ diff --git a/frontend/src/assets/template/right_event/bg_white.png b/frontend/src/assets/template/right_event/bg_white.png new file mode 100644 index 0000000000000000000000000000000000000000..59ac94f650c0cbcd1065ac4a34ca72645cef72e1 Binary files /dev/null and b/frontend/src/assets/template/right_event/bg_white.png differ diff --git a/frontend/src/templates.js b/frontend/src/templates.js index 78c2d7ac0608f9a2af8dad8c21ce656ccfa463e2..b4b84e1bd7545ef8c01687fb86db3027735191b9 100644 --- a/frontend/src/templates.js +++ b/frontend/src/templates.js @@ -9,6 +9,9 @@ import twitterBannerImage from "./assets/previews/twitter_banner.png"; import posterImage from "./assets/previews/poster.png"; import regionalSuccessImage from "./assets/previews/regional_success.png"; import baseEventImage from "./assets/previews/base_event.png"; +import rightEventImage from "./assets/previews/right_event.png"; +import angleEventRightImage from "./assets/previews/angle_event_right.png"; +import angleEventLeftImage from "./assets/previews/angle_event_left.png"; const TEMPLATES = { basic_photo_banner: { @@ -105,12 +108,39 @@ const TEMPLATES = { }, }, base_event: { - name: "Událost - pouze text", + name: "Událost - pouze text, vprostřed", image: baseEventImage, path: "/base-event", component: () => import("./views/base_event/BaseEvent.vue"), meta: { - title: "Událost - pouze text", + title: "Událost - pouze text, vprostřed", + }, + }, + right_event: { + name: "Událost - pouze text, vpravo", + image: rightEventImage, + path: "/right-event", + component: () => import("./views/right_event/RightEvent.vue"), + meta: { + title: "Událost - pouze text, vpravo", + }, + }, + angle_event_right: { + name: "Událost - pruh pod úhlem, vpravo", + image: angleEventRightImage, + path: "/angle-event-right", + component: () => import("./views/angle_event_right/AngleEventRight.vue"), + meta: { + title: "Událost - pruh pod úhlem, vpravo", + }, + }, + angle_event_left: { + name: "Událost - pruh pod úhlem, vlevo", + image: angleEventLeftImage, + path: "/angle-event-left", + component: () => import("./views/angle_event_left/AngleEventLeft.vue"), + meta: { + title: "Událost - pruh pod úhlem, vlevo", }, }, }; diff --git a/frontend/src/views/angle_event_left/AngleEventLeft.vue b/frontend/src/views/angle_event_left/AngleEventLeft.vue new file mode 100644 index 0000000000000000000000000000000000000000..b5c4a7ababf5e74bfdab83bed7a8c14473776a98 --- /dev/null +++ b/frontend/src/views/angle_event_left/AngleEventLeft.vue @@ -0,0 +1,171 @@ +<script setup> +import { watch, ref } from "vue"; + +import COLORS from "../../colors"; +import TEMPLATES from "../../templates"; +import DEFAULT_CONTRACTOR from "../../contractors"; +import { + loadFonts, + loadCanvasStorage, + setCanvasStorage, + updateAutoRedrawStorage, +} from "../../utils"; + +import Canvas from "../../components/canvas/Canvas.vue"; +import redraw from "./canvas"; + +import Navbar from "../../components/Navbar.vue"; +import MainContainer from "../../components/MainContainer.vue"; +import LongTextInput from "../../components/inputs/text/LongTextInput.vue"; +import ShortTextInput from "../../components/inputs/text/ShortTextInput.vue"; +import MultipleColorPicker from "../../components/inputs/colors/MultipleColorPicker.vue"; +import ReloadButton from "../../components/reload/ReloadButton.vue"; +import AutoReloadCheckbox from "../../components/reload/AutoReloadCheckbox.vue"; +</script> + +<script> +await loadFonts(["12px Bebas Neue", "12px Roboto Condensed"]); + +export default { + components: { + Canvas, + Navbar, + MainContainer, + LongTextInput, + ShortTextInput, + MultipleColorPicker, + AutoReloadCheckbox, + ReloadButton, + }, + data() { + const predefinedColors = { + blackBackground: { + name: "Černé pozadí, bílý text", + colors: { + background: COLORS.black, + mainText: COLORS.white, + highlightedText: COLORS.black, + highlight: COLORS.yellow1, + contractedByText: COLORS.gray1, + }, + }, + whiteBackground: { + name: "Bílé pozadí, černý text", + colors: { + background: COLORS.white, + mainText: COLORS.black, + highlightedText: COLORS.black, + highlight: COLORS.yellow1, + contractedByText: COLORS.gray1, + }, + }, + }; + + return { + mainText: null, + contractedBy: DEFAULT_CONTRACTOR, + gradientHeightMultiplier: 1, + colorLabels: { + background: "Pozadí", + }, + predefinedColors: predefinedColors, + colors: predefinedColors.blackBackground.colors, + autoRedraw: false, + }; + }, + async created() { + await loadCanvasStorage(this); + }, + methods: { + async reloadCanvasProperties() { + const canvasProperties = { + mainText: this.mainText, + contractedBy: this.contractedBy, + colors: this.colors, + }; + + await this.$refs.canvas.redraw(canvasProperties); + + delete canvasProperties.colors; + setCanvasStorage(canvasProperties); + }, + }, + mounted() { + this.$watch( + (vm) => [vm.mainText, vm.contractedBy, vm.colors], + async (value) => { + if (this.autoRedraw) { + await this.reloadCanvasProperties(); + } + }, + { + immediate: true, + deep: true, + }, + ); + + this.$watch( + (vm) => [vm.autoRedraw], + async (value) => { + updateAutoRedrawStorage(this.autoRedraw); + + if (this.autoRedraw) { + await this.reloadCanvasProperties(); + } + }, + ); + }, +}; +</script> + +<template> + <header> + <Navbar :defaultTemplate="TEMPLATES.angle_event_left"></Navbar> + </header> + <main> + <MainContainer> + <template v-slot:left> + <Canvas + ref="canvas" + :redrawFunction="redraw" + width="1702" + height="630" + /> + </template> + + <template v-slot:right> + <ReloadButton :parentRefs="$refs" @click="reloadCanvasProperties" /> + <AutoReloadCheckbox v-model="autoRedraw" /> + <LongTextInput + name="Text" + v-model="mainText" + :important="true" + :highlightable="true" + zIndex="9" + /> + + <MultipleColorPicker + name="Barvy" + v-model="colors" + :important="false" + :colorLabels="colorLabels" + :predefinedColors="predefinedColors" + :defaultPredefinedColors="predefinedColors.blackBackground" + zIndex="5" + ></MultipleColorPicker> + + <ShortTextInput + name="Zadavatel a zpracovatel" + v-model="contractedBy" + :defaultValue="DEFAULT_CONTRACTOR" + :important="false" + zIndex="4" + /> + </template> + </MainContainer> + </main> +</template> + +<style> +@import "vue-select/dist/vue-select.css"; +</style> diff --git a/frontend/src/views/angle_event_left/canvas.js b/frontend/src/views/angle_event_left/canvas.js new file mode 100644 index 0000000000000000000000000000000000000000..3e3268917e6a8bccd4d6992de6cdba4cff5401b7 --- /dev/null +++ b/frontend/src/views/angle_event_left/canvas.js @@ -0,0 +1,141 @@ +import { fabric } from "fabric"; +import { + clearObjects, + sortObjects, + transformHighlightedText, + checkTextBoxHeight, +} from "../../components/canvas/utils"; +import COLORS from "../../colors"; +import { PaddedHighlightingTextbox } from "../../components/canvas/textbox"; + +import bgImageSourceBlack from "../../assets/template/angle_event_left/bg_black.png"; +import bgImageSourceWhite from "../../assets/template/angle_event_left/bg_white.png"; + +let mainImage = null; +let contractedByTextbox = null; +let previousColor = null; +let mainTextBox = null; + +const redraw = async (canvas, options) => { + clearObjects([contractedByTextbox, mainTextBox], canvas); + + const contractedByTextSize = Math.ceil(canvas.height * 0.035); + const contractedByTextMaxWidth = Math.ceil(canvas.width * 0.9); + const contractedByTextBottomMargin = Math.ceil(canvas.width * 0.02); + const contractedByTextSideMargin = Math.ceil(canvas.width * 0.03); + + const textMarginLeft = Math.ceil(canvas.width * 0.54); + const textMarginRight = Math.ceil(canvas.width * 0.15); + + let mainTextMarginTop = Math.ceil(canvas.height * 0.185); + const mainTextBackgroundMarginTop = Math.ceil(canvas.height * 0.14); + const mainTextSize = Math.ceil(canvas.height * 0.22); + const mainTextHeightLimit = Math.ceil(mainTextSize * 2.2); + const mainTextLineHeight = 0.85; + + canvas.preserveObjectStacking = true; + + /* BEGIN Main image render */ + + if (previousColor !== options.colors.background || mainImage === null) { + if (mainImage !== null) { + canvas.remove(mainImage); + } + + const image = new Image(); + + const imageLoadPromise = new Promise((resolve) => { + image.onload = () => { + resolve(); + }; + + if (options.colors.background.value === COLORS.black.value) { + image.src = bgImageSourceBlack; + } else { + image.src = bgImageSourceWhite; + } + }); + await imageLoadPromise; + + mainImage = new fabric.Image(image, { + left: 0, + top: 0, + zIndex: 0, + selectable: false, + }); + + mainImage.scaleToWidth(canvas.width); + + canvas.add(mainImage); + + previousColor = options.colors.background; + } + + /* END Main image render */ + + if (options.mainText !== null) { + /* BEGIN Name text render */ + + const mainTextWidth = canvas.width - textMarginLeft - textMarginRight; + + const highlightedData = transformHighlightedText( + options.mainText, + mainTextSize, + mainTextWidth, + "Bebas Neue", + options.colors.highlight.value, + options.colors.highlightedText.value, + { padWhenDiacritics: true }, + ); + + mainTextBox = new PaddedHighlightingTextbox(highlightedData.text, { + width: canvas.width, + left: textMarginLeft, + textAlign: "left", + fontFamily: "Bebas Neue", + fontSize: mainTextSize, + lineHeight: mainTextLineHeight, + fill: options.colors.mainText.value, + styles: highlightedData.styles, + selectable: false, + highlightPadding: canvas.height * 0.003, + zIndex: 10, + }); + + checkTextBoxHeight(mainTextBox, 3); + + canvas.add(mainTextBox); + + mainTextBox.top = mainTextMarginTop - highlightedData.paddingBottom; + + canvas.renderAll(); + + /* END Main text render */ + } + + /* BEGIN Contracted by render */ + + if (options.contractedBy !== null) { + contractedByTextbox = new fabric.Textbox(options.contractedBy, { + left: contractedByTextSideMargin, + top: canvas.height - contractedByTextBottomMargin - contractedByTextSize, + width: contractedByTextMaxWidth, + fontFamily: "Roboto Condensed", + fontSize: contractedByTextSize, + textAlign: "left", + fill: options.colors.contractedByText.value, + selectable: false, + zIndex: 10, + }); + + checkTextBoxHeight(contractedByTextbox, 1); + + canvas.add(contractedByTextbox); + } + + /* END Contracted by render */ + + sortObjects(canvas); +}; + +export default redraw; diff --git a/frontend/src/views/angle_event_right/AngleEventRight.vue b/frontend/src/views/angle_event_right/AngleEventRight.vue new file mode 100644 index 0000000000000000000000000000000000000000..a63a96869d42c643c8d0f0ef0cb65b322a7c63e1 --- /dev/null +++ b/frontend/src/views/angle_event_right/AngleEventRight.vue @@ -0,0 +1,171 @@ +<script setup> +import { watch, ref } from "vue"; + +import COLORS from "../../colors"; +import TEMPLATES from "../../templates"; +import DEFAULT_CONTRACTOR from "../../contractors"; +import { + loadFonts, + loadCanvasStorage, + setCanvasStorage, + updateAutoRedrawStorage, +} from "../../utils"; + +import Canvas from "../../components/canvas/Canvas.vue"; +import redraw from "./canvas"; + +import Navbar from "../../components/Navbar.vue"; +import MainContainer from "../../components/MainContainer.vue"; +import LongTextInput from "../../components/inputs/text/LongTextInput.vue"; +import ShortTextInput from "../../components/inputs/text/ShortTextInput.vue"; +import MultipleColorPicker from "../../components/inputs/colors/MultipleColorPicker.vue"; +import ReloadButton from "../../components/reload/ReloadButton.vue"; +import AutoReloadCheckbox from "../../components/reload/AutoReloadCheckbox.vue"; +</script> + +<script> +await loadFonts(["12px Bebas Neue", "12px Roboto Condensed"]); + +export default { + components: { + Canvas, + Navbar, + MainContainer, + LongTextInput, + ShortTextInput, + MultipleColorPicker, + AutoReloadCheckbox, + ReloadButton, + }, + data() { + const predefinedColors = { + blackBackground: { + name: "Černé pozadí, bílý text", + colors: { + background: COLORS.black, + mainText: COLORS.white, + highlightedText: COLORS.black, + highlight: COLORS.yellow1, + contractedByText: COLORS.gray1, + }, + }, + whiteBackground: { + name: "Bílé pozadí, černý text", + colors: { + background: COLORS.white, + mainText: COLORS.black, + highlightedText: COLORS.black, + highlight: COLORS.yellow1, + contractedByText: COLORS.gray1, + }, + }, + }; + + return { + mainText: null, + contractedBy: DEFAULT_CONTRACTOR, + gradientHeightMultiplier: 1, + colorLabels: { + background: "Pozadí", + }, + predefinedColors: predefinedColors, + colors: predefinedColors.blackBackground.colors, + autoRedraw: false, + }; + }, + async created() { + await loadCanvasStorage(this); + }, + methods: { + async reloadCanvasProperties() { + const canvasProperties = { + mainText: this.mainText, + contractedBy: this.contractedBy, + colors: this.colors, + }; + + await this.$refs.canvas.redraw(canvasProperties); + + delete canvasProperties.colors; + setCanvasStorage(canvasProperties); + }, + }, + mounted() { + this.$watch( + (vm) => [vm.mainText, vm.contractedBy, vm.colors], + async (value) => { + if (this.autoRedraw) { + await this.reloadCanvasProperties(); + } + }, + { + immediate: true, + deep: true, + }, + ); + + this.$watch( + (vm) => [vm.autoRedraw], + async (value) => { + updateAutoRedrawStorage(this.autoRedraw); + + if (this.autoRedraw) { + await this.reloadCanvasProperties(); + } + }, + ); + }, +}; +</script> + +<template> + <header> + <Navbar :defaultTemplate="TEMPLATES.angle_event_right"></Navbar> + </header> + <main> + <MainContainer> + <template v-slot:left> + <Canvas + ref="canvas" + :redrawFunction="redraw" + width="1702" + height="630" + /> + </template> + + <template v-slot:right> + <ReloadButton :parentRefs="$refs" @click="reloadCanvasProperties" /> + <AutoReloadCheckbox v-model="autoRedraw" /> + <LongTextInput + name="Text" + v-model="mainText" + :important="true" + :highlightable="true" + zIndex="9" + /> + + <MultipleColorPicker + name="Barvy" + v-model="colors" + :important="false" + :colorLabels="colorLabels" + :predefinedColors="predefinedColors" + :defaultPredefinedColors="predefinedColors.blackBackground" + zIndex="5" + ></MultipleColorPicker> + + <ShortTextInput + name="Zadavatel a zpracovatel" + v-model="contractedBy" + :defaultValue="DEFAULT_CONTRACTOR" + :important="false" + zIndex="4" + /> + </template> + </MainContainer> + </main> +</template> + +<style> +@import "vue-select/dist/vue-select.css"; +</style> diff --git a/frontend/src/views/angle_event_right/canvas.js b/frontend/src/views/angle_event_right/canvas.js new file mode 100644 index 0000000000000000000000000000000000000000..c4eba342c747d75223cefa65ee2599532359aa48 --- /dev/null +++ b/frontend/src/views/angle_event_right/canvas.js @@ -0,0 +1,141 @@ +import { fabric } from "fabric"; +import { + clearObjects, + sortObjects, + transformHighlightedText, + checkTextBoxHeight, +} from "../../components/canvas/utils"; +import COLORS from "../../colors"; +import { PaddedHighlightingTextbox } from "../../components/canvas/textbox"; + +import bgImageSourceBlack from "../../assets/template/angle_event_right/bg_black.png"; +import bgImageSourceWhite from "../../assets/template/angle_event_right/bg_white.png"; + +let mainImage = null; +let contractedByTextbox = null; +let previousColor = null; +let mainTextBox = null; + +const redraw = async (canvas, options) => { + clearObjects([contractedByTextbox, mainTextBox], canvas); + + const contractedByTextSize = Math.ceil(canvas.height * 0.035); + const contractedByTextMaxWidth = Math.ceil(canvas.width * 0.9); + const contractedByTextBottomMargin = Math.ceil(canvas.width * 0.02); + const contractedByTextSideMargin = Math.ceil(canvas.width * 0.03); + + const textMarginLeft = Math.ceil(canvas.width * 0.52); + const textMarginRight = Math.ceil(canvas.width * 0.1); + + let mainTextMarginTop = Math.ceil(canvas.height * 0.185); + const mainTextBackgroundMarginTop = Math.ceil(canvas.height * 0.14); + const mainTextSize = Math.ceil(canvas.height * 0.22); + const mainTextHeightLimit = Math.ceil(mainTextSize * 2.2); + const mainTextLineHeight = 0.85; + + canvas.preserveObjectStacking = true; + + /* BEGIN Main image render */ + + if (previousColor !== options.colors.background || mainImage === null) { + if (mainImage !== null) { + canvas.remove(mainImage); + } + + const image = new Image(); + + const imageLoadPromise = new Promise((resolve) => { + image.onload = () => { + resolve(); + }; + + if (options.colors.background.value === COLORS.black.value) { + image.src = bgImageSourceBlack; + } else { + image.src = bgImageSourceWhite; + } + }); + await imageLoadPromise; + + mainImage = new fabric.Image(image, { + left: 0, + top: 0, + zIndex: 0, + selectable: false, + }); + + mainImage.scaleToWidth(canvas.width); + + canvas.add(mainImage); + + previousColor = options.colors.background; + } + + /* END Main image render */ + + if (options.mainText !== null) { + /* BEGIN Name text render */ + + const mainTextWidth = canvas.width - textMarginLeft - textMarginRight; + + const highlightedData = transformHighlightedText( + options.mainText, + mainTextSize, + mainTextWidth, + "Bebas Neue", + options.colors.highlight.value, + options.colors.highlightedText.value, + { padWhenDiacritics: true }, + ); + + mainTextBox = new PaddedHighlightingTextbox(highlightedData.text, { + width: canvas.width, + left: textMarginLeft, + textAlign: "left", + fontFamily: "Bebas Neue", + fontSize: mainTextSize, + lineHeight: mainTextLineHeight, + fill: options.colors.mainText.value, + styles: highlightedData.styles, + selectable: false, + highlightPadding: canvas.height * 0.003, + zIndex: 10, + }); + + checkTextBoxHeight(mainTextBox, 3); + + canvas.add(mainTextBox); + + mainTextBox.top = mainTextMarginTop - highlightedData.paddingBottom; + + canvas.renderAll(); + + /* END Main text render */ + } + + /* BEGIN Contracted by render */ + + if (options.contractedBy !== null) { + contractedByTextbox = new fabric.Textbox(options.contractedBy, { + left: contractedByTextSideMargin, + top: canvas.height - contractedByTextBottomMargin - contractedByTextSize, + width: contractedByTextMaxWidth, + fontFamily: "Roboto Condensed", + fontSize: contractedByTextSize, + textAlign: "left", + fill: options.colors.contractedByText.value, + selectable: false, + zIndex: 10, + }); + + checkTextBoxHeight(contractedByTextbox, 1); + + canvas.add(contractedByTextbox); + } + + /* END Contracted by render */ + + sortObjects(canvas); +}; + +export default redraw; diff --git a/frontend/src/views/base_event/BaseEvent.vue b/frontend/src/views/base_event/BaseEvent.vue index 2e08d2890301fdff3f99f2960dd86c0f8f347da5..44a4ee8c6a4abd575cb95a64625ef6b4a93c6818 100644 --- a/frontend/src/views/base_event/BaseEvent.vue +++ b/frontend/src/views/base_event/BaseEvent.vue @@ -150,7 +150,7 @@ export default { :important="false" :colorLabels="colorLabels" :predefinedColors="predefinedColors" - :defaultPredefinedColors="predefinedColors.base" + :defaultPredefinedColors="predefinedColors.blackBackground" zIndex="5" ></MultipleColorPicker> diff --git a/frontend/src/views/base_event/canvas.js b/frontend/src/views/base_event/canvas.js index cf40ff72d14e63a935824483ff28b63276f165b2..b6adcaa6bbd9addddfd2c1738ab84d3502c96e99 100644 --- a/frontend/src/views/base_event/canvas.js +++ b/frontend/src/views/base_event/canvas.js @@ -37,7 +37,7 @@ const redraw = async (canvas, options) => { /* BEGIN Main image render */ - if (previousColor !== options.colors.background) { + if (previousColor !== options.colors.background || mainImage === null) { if (mainImage !== null) { canvas.remove(mainImage); } diff --git a/frontend/src/views/right_event/RightEvent.vue b/frontend/src/views/right_event/RightEvent.vue new file mode 100644 index 0000000000000000000000000000000000000000..1a47a42c34705e6728664caa017d13e60e021bbf --- /dev/null +++ b/frontend/src/views/right_event/RightEvent.vue @@ -0,0 +1,171 @@ +<script setup> +import { watch, ref } from "vue"; + +import COLORS from "../../colors"; +import TEMPLATES from "../../templates"; +import DEFAULT_CONTRACTOR from "../../contractors"; +import { + loadFonts, + loadCanvasStorage, + setCanvasStorage, + updateAutoRedrawStorage, +} from "../../utils"; + +import Canvas from "../../components/canvas/Canvas.vue"; +import redraw from "./canvas"; + +import Navbar from "../../components/Navbar.vue"; +import MainContainer from "../../components/MainContainer.vue"; +import LongTextInput from "../../components/inputs/text/LongTextInput.vue"; +import ShortTextInput from "../../components/inputs/text/ShortTextInput.vue"; +import MultipleColorPicker from "../../components/inputs/colors/MultipleColorPicker.vue"; +import ReloadButton from "../../components/reload/ReloadButton.vue"; +import AutoReloadCheckbox from "../../components/reload/AutoReloadCheckbox.vue"; +</script> + +<script> +await loadFonts(["12px Bebas Neue", "12px Roboto Condensed"]); + +export default { + components: { + Canvas, + Navbar, + MainContainer, + LongTextInput, + ShortTextInput, + MultipleColorPicker, + AutoReloadCheckbox, + ReloadButton, + }, + data() { + const predefinedColors = { + blackBackground: { + name: "Černé pozadí, bílý text", + colors: { + background: COLORS.black, + mainText: COLORS.white, + highlightedText: COLORS.black, + highlight: COLORS.yellow1, + contractedByText: COLORS.gray1, + }, + }, + whiteBackground: { + name: "Bílé pozadí, černý text", + colors: { + background: COLORS.white, + mainText: COLORS.black, + highlightedText: COLORS.black, + highlight: COLORS.yellow1, + contractedByText: COLORS.gray1, + }, + }, + }; + + return { + mainText: null, + contractedBy: DEFAULT_CONTRACTOR, + gradientHeightMultiplier: 1, + colorLabels: { + background: "Pozadí", + }, + predefinedColors: predefinedColors, + colors: predefinedColors.blackBackground.colors, + autoRedraw: false, + }; + }, + async created() { + await loadCanvasStorage(this); + }, + methods: { + async reloadCanvasProperties() { + const canvasProperties = { + mainText: this.mainText, + contractedBy: this.contractedBy, + colors: this.colors, + }; + + await this.$refs.canvas.redraw(canvasProperties); + + delete canvasProperties.colors; + setCanvasStorage(canvasProperties); + }, + }, + mounted() { + this.$watch( + (vm) => [vm.mainText, vm.contractedBy, vm.colors], + async (value) => { + if (this.autoRedraw) { + await this.reloadCanvasProperties(); + } + }, + { + immediate: true, + deep: true, + }, + ); + + this.$watch( + (vm) => [vm.autoRedraw], + async (value) => { + updateAutoRedrawStorage(this.autoRedraw); + + if (this.autoRedraw) { + await this.reloadCanvasProperties(); + } + }, + ); + }, +}; +</script> + +<template> + <header> + <Navbar :defaultTemplate="TEMPLATES.right_event"></Navbar> + </header> + <main> + <MainContainer> + <template v-slot:left> + <Canvas + ref="canvas" + :redrawFunction="redraw" + width="1702" + height="630" + /> + </template> + + <template v-slot:right> + <ReloadButton :parentRefs="$refs" @click="reloadCanvasProperties" /> + <AutoReloadCheckbox v-model="autoRedraw" /> + <LongTextInput + name="Text" + v-model="mainText" + :important="true" + :highlightable="true" + zIndex="9" + /> + + <MultipleColorPicker + name="Barvy" + v-model="colors" + :important="false" + :colorLabels="colorLabels" + :predefinedColors="predefinedColors" + :defaultPredefinedColors="predefinedColors.blackBackground" + zIndex="5" + ></MultipleColorPicker> + + <ShortTextInput + name="Zadavatel a zpracovatel" + v-model="contractedBy" + :defaultValue="DEFAULT_CONTRACTOR" + :important="false" + zIndex="4" + /> + </template> + </MainContainer> + </main> +</template> + +<style> +@import "vue-select/dist/vue-select.css"; +</style> diff --git a/frontend/src/views/right_event/canvas.js b/frontend/src/views/right_event/canvas.js new file mode 100644 index 0000000000000000000000000000000000000000..d6c6998e4a4002d7f58f5d0bd040ed8aef8be425 --- /dev/null +++ b/frontend/src/views/right_event/canvas.js @@ -0,0 +1,148 @@ +import { fabric } from "fabric"; +import { + clearObjects, + sortObjects, + transformHighlightedText, + checkTextBoxHeight, +} from "../../components/canvas/utils"; +import COLORS from "../../colors"; +import { PaddedHighlightingTextbox } from "../../components/canvas/textbox"; + +import bgImageSourceBlack from "../../assets/template/right_event/bg_black.png"; +import bgImageSourceWhite from "../../assets/template/right_event/bg_white.png"; + +let mainImage = null; +let contractedByTextbox = null; +let previousColor = null; +let mainTextBox = null; + +const redraw = async (canvas, options) => { + clearObjects([contractedByTextbox, mainTextBox], canvas); + + const contractedByTextSize = Math.ceil(canvas.height * 0.035); + const contractedByTextMaxWidth = Math.ceil(canvas.width * 0.9); + const contractedByTextBottomMargin = Math.ceil(canvas.width * 0.02); + const contractedByTextSideMargin = Math.ceil(canvas.width * 0.03); + + const textMarginLeft = Math.ceil(canvas.width * 0.53); + const textMarginRight = Math.ceil(canvas.width * 0.1); + + let mainTextMarginBottom = Math.ceil(canvas.height * 0.36); + const mainTextBackgroundMarginTop = Math.ceil(canvas.height * 0.14); + const mainTextSize = Math.ceil(canvas.height * 0.13); + const mainTextHeightLimit = Math.ceil(mainTextSize * 2.2); + const mainTextLineHeight = 0.85; + + canvas.preserveObjectStacking = true; + + /* BEGIN Main image render */ + + if (previousColor !== options.colors.background || mainImage === null) { + if (mainImage !== null) { + canvas.remove(mainImage); + } + + const image = new Image(); + + const imageLoadPromise = new Promise((resolve) => { + image.onload = () => { + resolve(); + }; + + if (options.colors.background.value === COLORS.black.value) { + image.src = bgImageSourceBlack; + } else { + image.src = bgImageSourceWhite; + } + }); + await imageLoadPromise; + + mainImage = new fabric.Image(image, { + left: 0, + top: 0, + zIndex: 0, + selectable: false, + }); + + mainImage.scaleToWidth(canvas.width); + + canvas.add(mainImage); + + previousColor = options.colors.background; + } + + /* END Main image render */ + + if (options.mainText !== null) { + /* BEGIN Name text render */ + + const mainTextWidth = canvas.width - textMarginLeft - textMarginRight; + + const highlightedData = transformHighlightedText( + options.mainText, + mainTextSize, + mainTextWidth, + "Bebas Neue", + options.colors.highlight.value, + options.colors.highlightedText.value, + { padWhenDiacritics: true }, + ); + + mainTextBox = new PaddedHighlightingTextbox(highlightedData.text, { + width: canvas.width, + left: textMarginLeft, + textAlign: "left", + fontFamily: "Bebas Neue", + fontSize: mainTextSize, + lineHeight: mainTextLineHeight, + fill: options.colors.mainText.value, + styles: highlightedData.styles, + selectable: false, + highlightPadding: canvas.height * 0.003, + zIndex: 10, + }); + + checkTextBoxHeight(mainTextBox, 2); + + canvas.add(mainTextBox); + + let mainTextBoxTop = + canvas.height - mainTextBox.height - mainTextMarginBottom; + + if (mainTextBox.textLines.length === 1) { + mainTextBoxTop -= mainTextSize / 2; + } + + mainTextBox.top = mainTextBoxTop - highlightedData.paddingBottom; + + canvas.renderAll(); + + /* END Main text render */ + } + + /* BEGIN Contracted by render */ + + if (options.contractedBy !== null) { + contractedByTextbox = new fabric.Textbox(options.contractedBy, { + left: contractedByTextSideMargin, + top: canvas.height - contractedByTextBottomMargin - contractedByTextSize, + width: contractedByTextMaxWidth, + fontFamily: "Roboto Condensed", + fontSize: contractedByTextSize, + textAlign: "left", + fill: options.colors.contractedByText.value, + selectable: false, + zIndex: 10, + }); + + checkTextBoxHeight(contractedByTextbox, 1); + + canvas.add(contractedByTextbox); + } + + /* END Contracted by render */ + + sortObjects(canvas); +}; + +export default redraw;