From 1e8f87ef1150341c92eabc3392e49b0e31393e5c Mon Sep 17 00:00:00 2001 From: zk-phi Date: Wed, 7 Feb 2024 12:04:57 +0900 Subject: [PATCH] Add feature to configure position of outlines --- src/components/cards/TextSource.vue | 9 ++ src/components/formblocks/OutlineBlock.vue | 111 +++++++++++++++------ src/components/inputs/Field.stories.js | 21 ++++ src/components/inputs/Field.vue | 24 +++++ src/utils/textimage.ts | 35 ++++++- 5 files changed, 166 insertions(+), 34 deletions(-) create mode 100644 src/components/inputs/Field.stories.js create mode 100644 src/components/inputs/Field.vue diff --git a/src/components/cards/TextSource.vue b/src/components/cards/TextSource.vue index a62c8629..1c15466e 100644 --- a/src/components/cards/TextSource.vue +++ b/src/components/cards/TextSource.vue @@ -59,6 +59,9 @@ export default defineComponent({ color: "#ffda00", gradient: [] as ColorStop[], outlines: [] as string[], + outlineThickness: 8, + outlineX: 0, + outlineY: 0, font: fonts[0].fonts[0].value, /* advanced */ lineSpacing: 0.05, @@ -117,6 +120,9 @@ export default defineComponent({ this.conf.align, Number(this.conf.lineSpacing), this.absoluteOutlines, + this.conf.outlineThickness, + this.conf.outlineX, + this.conf.outlineY, this.absoluteGradient, Number(this.conf.padding), ); @@ -204,6 +210,9 @@ export default defineComponent({ :show-details="showDetails" /> diff --git a/src/components/formblocks/OutlineBlock.vue b/src/components/formblocks/OutlineBlock.vue index 680dd05e..beaebf16 100644 --- a/src/components/formblocks/OutlineBlock.vue +++ b/src/components/formblocks/OutlineBlock.vue @@ -2,7 +2,9 @@ import { defineComponent, PropType } from "vue"; import Button from "../inputs/Button.vue"; import ToggleButton from "../inputs/ToggleButton.vue"; +import Slider from "../inputs/Slider.vue"; import Fieldset from "../inputs/Fieldset.vue"; +import Checkbox from "../inputs/Checkbox.vue"; import ColorSample from "../global/ColorSample.vue"; import Space from "../global/Space.vue"; import OutlineItemBlock from "./OutlineItemBlock.vue"; @@ -12,15 +14,18 @@ type OutlineOption = { value: string, absColor: string }; export default defineComponent({ components: { - ToggleButton, ColorSample, OutlineItemBlock, Fieldset, Button, Space, + ToggleButton, ColorSample, OutlineItemBlock, Fieldset, Button, Space, Slider, Checkbox, }, props: { modelValue: { type: Array as PropType, required: true }, + thickness: { type: Number, required: true }, + posX: { type: Number, required: true }, + posY: { type: Number, required: true }, baseColor: { type: String, required: true }, showDetails: { type: Boolean, required: true }, }, emits: [ - "update:modelValue", + "update:modelValue", "update:thickness", "update:posX", "update:posY", ], computed: { options(): OutlineOption[] { @@ -46,36 +51,84 @@ export default defineComponent({ remove(ix: number): void { this.$emit("update:modelValue", this.modelValue.filter((_, i) => i !== ix)); }, + toggle3D(): void { + if (this.posX === 0 && this.posY === 0) { + this.$emit("update:thickness", 4); + this.$emit("update:posX", -0.9); + this.$emit("update:posY", -0.9); + } else { + this.$emit("update:thickness", 8); + this.$emit("update:posX", 0); + this.$emit("update:posY", 0); + } + } }, }); diff --git a/src/components/inputs/Field.stories.js b/src/components/inputs/Field.stories.js new file mode 100644 index 00000000..599ba883 --- /dev/null +++ b/src/components/inputs/Field.stories.js @@ -0,0 +1,21 @@ +import Field from "./Field.vue"; +import Input from "./Input.vue"; + +export default { + title: "molecules/inputs/Field", + component: Field, +}; + +export const Base = (args) => ({ + components: { Field, Input }, + data: () => ({ + ...args, + value: "", + }), + template: ` + + + + `, +}); +Base.args = { label: "ほげほげ" }; diff --git a/src/components/inputs/Field.vue b/src/components/inputs/Field.vue new file mode 100644 index 00000000..3f3f59b5 --- /dev/null +++ b/src/components/inputs/Field.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/utils/textimage.ts b/src/utils/textimage.ts index 04cde8de..915218e4 100644 --- a/src/utils/textimage.ts +++ b/src/utils/textimage.ts @@ -9,6 +9,9 @@ const makeTextImageSingleLine = ( font: string, fontHeight: number, outlineColors: string[], + outlineThickness: number, + outlineX: number, + outlineY: number, gradient: GradientColorStop[], ): HTMLCanvasElement => { const canvas = document.createElement("canvas"); @@ -24,12 +27,17 @@ const makeTextImageSingleLine = ( ctx.textBaseline = "top"; ctx.lineJoin = "round"; - const margin = fontHeight * 0.025; + const margin = fontHeight * 0.1; + const outlineTotalThickness = outlineThickness * (outlineColors.length - 1); for (let i = outlineColors.length - 1; i >= 0; i -= 1) { ctx.strokeStyle = outlineColors[i]; - ctx.lineWidth = (i + 1) * 8; - ctx.strokeText(line, margin, margin); + ctx.lineWidth = (i + 1) * outlineThickness; + ctx.strokeText( + line, + margin + outlineX * (outlineTotalThickness - ctx.lineWidth) * 0.5, + margin + outlineY * (outlineTotalThickness - ctx.lineWidth) * 0.5, + ); } if (gradient.length) { @@ -41,7 +49,11 @@ const makeTextImageSingleLine = ( } else { ctx.fillStyle = color; } - ctx.fillText(line, margin, margin); + ctx.fillText( + line, + margin + outlineX * outlineTotalThickness * 0.5, + margin + outlineY * outlineTotalThickness * 0.5, + ); return shrinkCanvas(canvas); }; @@ -55,6 +67,9 @@ export const makeTextImage = ( align: string, lineSpacing: number, outlineColors: string[], + outlineThickness: number, + outlineX: number, + outlineY: number, gradient: GradientColorStop[], padding: number, ): HTMLCanvasElement => { @@ -62,7 +77,17 @@ export const makeTextImage = ( const paddingPixels = Math.round(padding * fontHeight); const images = text.split("\n").map((line) => ( - makeTextImageSingleLine(line, color, font, fontHeight, outlineColors, gradient) + makeTextImageSingleLine( + line, + color, + font, + fontHeight, + outlineColors, + outlineThickness, + outlineX, + outlineY, + gradient, + ) )); const lineWidths = images.map((canvas) => canvas.width); const maxWidth = Math.max.apply(null, lineWidths);