Skip to content

Commit

Permalink
Add feature to configure position of outlines
Browse files Browse the repository at this point in the history
  • Loading branch information
zk-phi committed Feb 7, 2024
1 parent 8e189d5 commit 1e8f87e
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 34 deletions.
9 changes: 9 additions & 0 deletions src/components/cards/TextSource.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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),
);
Expand Down Expand Up @@ -204,6 +210,9 @@ export default defineComponent({
:show-details="showDetails" />
<OutlineBlock
v-model="conf.outlines"
v-model:thickness="conf.outlineThickness"
v-model:posX="conf.outlineX"
v-model:posY="conf.outlineY"
:base-color="conf.color"
:show-details="showDetails" />
</Space>
Expand Down
111 changes: 82 additions & 29 deletions src/components/formblocks/OutlineBlock.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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<string[]>, 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[] {
Expand All @@ -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);
}
}

Check failure on line 64 in src/components/formblocks/OutlineBlock.vue

View workflow job for this annotation

GitHub Actions / lint-js

Missing trailing comma
},
});
</script>

<template>
<Fieldset v-if="!showDetails" label="アウトライン">
<Space small>
<ToggleButton
v-for="option in options"
:key="option.value"
name="アウトライン"
:model-value="modelValue"
size="smallIcon"
:value="option.value"
@update:model-value="$emit('update:modelValue', $event)">
<ColorSample :color="option.absColor" />
</ToggleButton>
</Space>
</Fieldset>
<Fieldset v-else label="アウトライン">
<Space vertical full>
<OutlineItemBlock
v-for="(color, ix) in modelValue"
:key="ix"
:model-value="absColors[ix]"
@update:model-value="update(ix, $event)"
@remove="remove(ix) " />
<Button type="dashed" name="アウトライン (追加)" block @click="add">
+ アウトラインを追加
</Button>
</Space>
</Fieldset>
<Space v-if="!showDetails" vertical full>
<Fieldset v-if="!showDetails" label="アウトライン">
<Space small>
<ToggleButton
v-for="option in options"
:key="option.value"
name="アウトライン"
:model-value="modelValue"
size="smallIcon"
:value="option.value"
@update:model-value="$emit('update:modelValue', $event)">
<ColorSample :color="option.absColor" />
</ToggleButton>
</Space>
</Fieldset>
<Checkbox
name="立体感"
:model-value="posX !== 0 || posY !== 0"
@update:model-value="toggle3D">
{{ "立体感" }}
</Checkbox>
</Space>
<Space v-else vertical full xlarge>
<Fieldset label="アウトライン">
<Space vertical full>
<OutlineItemBlock
v-for="(color, ix) in modelValue"
:key="ix"
:model-value="absColors[ix]"
@update:model-value="update(ix, $event)"
@remove="remove(ix) " />
<Button type="dashed" name="アウトライン (追加)" block @click="add">
+ アウトラインを追加
</Button>
</Space>
</Fieldset>
<Fieldset label="アウトライン太さ">
<Slider
:model-value="thickness"
block
:min="2"
:max="12"
:step="1"
@update:model-value="$emit('update:thickness', $event)" />
</Fieldset>
<Fieldset label="アウトライン位置 (横)">
<Slider
:model-value="posX"
block
:min="-1"
:max="1"
:step="0.1"
@update:model-value="$emit('update:posX', $event)" />
</Fieldset>
<Fieldset label="アウトライン位置 (縦)">
<Slider
:model-value="posY"
block
:min="-1"
:max="1"
:step="0.1"
@update:model-value="$emit('update:posY', $event)" />
</Fieldset>
</Space>
</template>
21 changes: 21 additions & 0 deletions src/components/inputs/Field.stories.js
Original file line number Diff line number Diff line change
@@ -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: `
<Field :label="label">
<Input v-model="value" />
</Field>
`,
});
Base.args = { label: "ほげほげ" };
24 changes: 24 additions & 0 deletions src/components/inputs/Field.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
props: {
label: { type: String, required: true },
},
});
</script>

<template>
<label class="title">{{ label }}</label>
<slot />
</template>

<style scoped>
.title {
display: block;
margin-right: var(--spacingMedium);
font-size: var(--fontSizeMedium);
line-height: 1;
color: var(--fg);
}
</style>
35 changes: 30 additions & 5 deletions src/utils/textimage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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) {
Expand All @@ -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);
};
Expand All @@ -55,14 +67,27 @@ export const makeTextImage = (
align: string,
lineSpacing: number,
outlineColors: string[],
outlineThickness: number,
outlineX: number,
outlineY: number,
gradient: GradientColorStop[],
padding: number,
): HTMLCanvasElement => {
const lineSpacingPixels = Math.round(lineSpacing * fontHeight);
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);
Expand Down

0 comments on commit 1e8f87e

Please sign in to comment.