Skip to content

Commit

Permalink
feat: implement basic vertical alignment
Browse files Browse the repository at this point in the history
  • Loading branch information
romgere committed Oct 5, 2023
1 parent 7b81f0d commit bce9537
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 7 deletions.
24 changes: 20 additions & 4 deletions app/components/settings-form/settings.hbs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<fieldset class="uk-fieldset">

<label class="uk-form-label" for="text-content">
{{t "text_settings.type"}}
</label>
<Ui::TypeSelect
<Ui::TypeSelect
@value={{@model.type}}
@onChange={{this.changeType}}
data-test-settings-type
Expand All @@ -21,7 +21,7 @@
@debounce={{250}}
data-test-settings-text
/>
{{else}}
{{else}}
<Ui::Input
id="text-content"
class="uk-input"
Expand Down Expand Up @@ -52,6 +52,22 @@
</div>
{{/if}}

<div class="uk-margin">
<label class="uk-form-label" for="text-alignment">
{{t "text_settings.valignment"}}
</label>
<Ui::RadioGroup
@radioName="text-alignment"
@options={{this.vAlignmentOptions}}
@checked={{@model.vAlignment}}
@onChange={{fn (mut @model.vAlignment)}}
class="uk-grid-small uk-child-width-auto uk-grid"
data-test-settings-text-valignment
as |align|>
{{t (concat "valignment." align)}}
</Ui::RadioGroup>
</div>

<div class="uk-margin">
<label class="uk-form-label" for="text-size">
{{t "text_settings.size"}}
Expand All @@ -71,7 +87,7 @@
</div>

<div class="uk-margin">

<label class="uk-form-label" for="text-height">
{{t "text_settings.height"}}
</label>
Expand Down
6 changes: 6 additions & 0 deletions app/components/settings-form/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export default class SettingsFormTextSettings extends Component<SettingsFormText
}

alignmentOptions = ['left', 'center', 'right'];
vAlignmentOptions = ['default', 'top', 'bottom'];

@action
setInt(props: 'size' | 'height' | 'spacing' | 'vSpacing', value: string) {
Expand All @@ -47,5 +48,10 @@ export default class SettingsFormTextSettings extends Component<SettingsFormText
if (!this.enableMultiline) {
this.args.model.text = this.args.model.text.split('\n').join(' ');
}

// Force switch to bottom align when type is changed to vertical text
if (type === ModelType.VerticalTextWithSupport) {
this.args.model.vAlignment = 'bottom';
}
}
}
1 change: 1 addition & 0 deletions app/config/environment.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ declare const config: {
spacing: number;
vSpacing: number;
alignment: 'left' | 'center' | 'right';
vAlignment: 'default' | 'top' | 'bottom';
type: ModelType;
supportHeight: number;
supportBorderRadius: number;
Expand Down
5 changes: 5 additions & 0 deletions app/models/text-maker-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Handle,
ModelType,
TextMakerAlignment,
TextMakerVerticalAlignment,
} from 'text2stl/services/text-maker';
import { tracked } from '@glimmer/tracking';
import config from 'text2stl/config/environment';
Expand Down Expand Up @@ -104,6 +105,7 @@ export default class TextMakerSettings implements TextMakerParameters, QPSeriali
@tracked spacing?: number;
@tracked vSpacing?: number;
@tracked alignment: TextMakerAlignment;
@tracked vAlignment: TextMakerVerticalAlignment;
@tracked type: ModelType;
@tracked supportHeight?: number;
@tracked supportBorderRadius?: number;
Expand All @@ -119,6 +121,7 @@ export default class TextMakerSettings implements TextMakerParameters, QPSeriali
this.spacing = args.spacing ?? textMakerDefault.spacing;
this.vSpacing = args.vSpacing ?? textMakerDefault.vSpacing;
this.alignment = args.alignment ?? textMakerDefault.alignment;
this.vAlignment = args.vAlignment ?? textMakerDefault.vAlignment;
this.type = args.type ?? textMakerDefault.type;
this.supportHeight = args.supportHeight ?? textMakerDefault.supportHeight;
this.supportBorderRadius = args.supportBorderRadius ?? textMakerDefault.supportBorderRadius;
Expand All @@ -141,6 +144,7 @@ export default class TextMakerSettings implements TextMakerParameters, QPSeriali
spacing: this.spacing,
vSpacing: this.vSpacing,
alignment: this.alignment,
vAlignment: this.vAlignment,
type: this.type,
supportHeight: this.supportHeight,
supportBorderRadius: this.supportBorderRadius,
Expand All @@ -164,6 +168,7 @@ export default class TextMakerSettings implements TextMakerParameters, QPSeriali
this.spacing = v.spacing;
this.vSpacing = v.vSpacing;
this.alignment = v.alignment;
this.vAlignment = v.vAlignment;
this.type = v.type;
this.supportHeight = v.supportHeight;
this.supportBorderRadius = v.supportBorderRadius;
Expand Down
48 changes: 46 additions & 2 deletions app/services/text-maker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const {
} = config;

export type TextMakerAlignment = 'left' | 'center' | 'right';
export type TextMakerVerticalAlignment = 'default' | 'top' | 'bottom';

export type SupportPadding = {
top: number;
Expand All @@ -37,6 +38,7 @@ export interface TextMakerParameters {
spacing?: number;
vSpacing?: number;
alignment?: TextMakerAlignment;
vAlignment?: TextMakerVerticalAlignment;
type?: ModelType;
supportHeight?: number;
supportPadding?: SupportPadding;
Expand Down Expand Up @@ -209,12 +211,16 @@ export default class TextMakerService extends Service {
const vSpacing = params.vSpacing !== undefined ? params.vSpacing : textMakerDefault.vSpacing;
const alignment =
params.alignment !== undefined ? params.alignment : textMakerDefault.alignment;
const vAlignment =
params.vAlignment !== undefined ? params.vAlignment : textMakerDefault.vAlignment;

const scale = (1 / font.unitsPerEm) * size;

const glyphShapes: SingleGlyphDef[] = [];
// to handle alignment
const linesWidth: number[] = [];
const linesMaxY: { maxY: number; minY: number }[] = [];
const linesGlyphInfos: Array<Array<{ height: number; maxY: number; minY: number }>> = [];
const bounds = {
min: { x: Number.MAX_SAFE_INTEGER, y: Number.MAX_SAFE_INTEGER },
max: { x: 0, y: 0 },
Expand All @@ -227,12 +233,28 @@ export default class TextMakerService extends Service {
for (const lineText of lines) {
let dx = 0;
let lineMaxX = 0;
const lineMaxY = { minY: Number.MAX_SAFE_INTEGER, maxY: -Number.MAX_SAFE_INTEGER };
const lineGlyphInfos: { height: number; maxY: number; minY: number }[] = [];

font.forEachGlyph(lineText, 0, 0, size, undefined, (glyph, x, y) => {
x += dx;
dx += spacing;
const glyphBounds = glyph.getBoundingBox();

lineMaxX = x + glyphBounds.x2 * scale;
const glyphHeight = (glyphBounds.y2 - glyphBounds.y1) * scale;

const minY = Math.min(glyphBounds.y1, glyphBounds.y2) * scale;
const maxY = Math.max(glyphBounds.y1, glyphBounds.y2) * scale;

lineMaxY.maxY = Math.max(lineMaxY.maxY, maxY);
lineMaxY.minY = Math.min(lineMaxY.minY, minY);

lineGlyphInfos.push({
height: glyphHeight,
maxY,
minY,
});

bounds.min.x = Math.min(bounds.min.x, x + glyphBounds.x1 * scale);
bounds.min.y = Math.min(bounds.min.y, y - dy + glyphBounds.y1 * scale);
Expand All @@ -244,11 +266,13 @@ export default class TextMakerService extends Service {

// Keep this for each line to handle alignment
linesWidth.push(lineMaxX);
linesMaxY.push(lineMaxY);
linesGlyphInfos.push(lineGlyphInfos);
}

const linesAlignOffset = linesWidth.map(() => 0);

// Handle alignment (now we know all line size)
// Handle horizontal alignment (now we know all line size)
if (alignment !== 'left') {
const maxWidth = Math.max(...linesWidth);

Expand All @@ -264,11 +288,23 @@ export default class TextMakerService extends Service {
for (const lineIndex in lines) {
const lineText = lines[lineIndex];
let dx = 0;
let glyphIndex = 0;

// Iterate on text char to generate a Geometry for each
font.forEachGlyph(lineText, 0, 0, size, undefined, (glyph, x, y) => {
x += dx + linesAlignOffset[lineIndex];

if (vAlignment !== 'default') {
const lineMaxY = linesMaxY[lineIndex];
const glyphInfo = linesGlyphInfos[lineIndex][glyphIndex];

if (vAlignment === 'bottom' && lineMaxY.minY !== glyphInfo.minY) {
y += lineMaxY.minY - glyphInfo.minY;
} else if (vAlignment === 'top' && lineMaxY.maxY !== glyphInfo.maxY) {
y += lineMaxY.maxY - glyphInfo.maxY;
}
}

glyphShapes.push(
this.glyphToShapes(
font.outlinesFormat,
Expand All @@ -279,6 +315,7 @@ export default class TextMakerService extends Service {
),
);
dx += spacing;
glyphIndex++;
});

dy += size + vSpacing;
Expand Down Expand Up @@ -313,6 +350,9 @@ export default class TextMakerService extends Service {
const textDepth =
params.height !== undefined && params.height >= 0 ? params.height : textMakerDefault.height;

const vAlignment =
params.vAlignment !== undefined ? params.vAlignment : textMakerDefault.vAlignment;

const plyghsDef = this.stringToGlyhpsDef(params, font);
let supportShape: THREE.Shape | undefined = undefined;

Expand Down Expand Up @@ -445,13 +485,17 @@ export default class TextMakerService extends Service {
),
);
} else if (type === ModelType.VerticalTextWithSupport) {
// Ensure bottom of the text is touching the support
const verticalOffset = vAlignment === 'bottom' ? Math.min(0, plyghsDef.bounds.min.y) : 0;

// Rotate & move text
textGeometry.applyMatrix4(new THREE.Matrix4().makeRotationX(Math.PI / 2));
textGeometry.applyMatrix4(
new THREE.Matrix4().makeTranslation(
supportPadding.left,
supportPadding.bottom + size.z * 2,
supportDepth,

supportDepth - verticalOffset,
),
);
}
Expand Down
1 change: 1 addition & 0 deletions config/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ module.exports = function (environment) {
spacing: 2,
vSpacing: 0,
alignment: 'center',
vAlignment: 'default',
type: 2,
supportHeight: 5,
supportBorderRadius: 5,
Expand Down
8 changes: 7 additions & 1 deletion tests/integration/components/settings-form/settings-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ module('Integration | Component | settings-form/settings', function (hooks) {
await fillIn('[data-test-settings-spacing]', '789');
assert.strictEqual(model.spacing, 789, 'model.spacing was updated');

assert
.dom(`[data-test-settings-text-valignment] input[type="radio"][value="${model.vAlignment}"]`)
.isChecked('current textAlignment radio is checked');
await click('[data-test-settings-text-valignment] input[type="radio"][value="bottom"]');
assert.strictEqual(model.vAlignment, 'bottom', 'model.vAlignment was updated');

assert
.dom('[data-test-settings-supportHeight]')
.doesNotExist('supportHeight field is not displayed when model.type is text only');
Expand Down Expand Up @@ -108,7 +114,7 @@ module('Integration | Component | settings-form/settings', function (hooks) {
assert.dom('[data-test-settings-text-alignment]').exists();
assert
.dom(`[data-test-settings-text-alignment] input[type="radio"][value="${model.alignment}"]`)
.hasValue('center', 'current textAlignment radio is checked');
.isChecked('current textAlignment radio is checked');
await click('[data-test-settings-text-alignment] input[type="radio"][value="right"]');
assert.strictEqual(model.alignment, 'right', 'model.alignment was updated');

Expand Down
5 changes: 5 additions & 0 deletions translations/en-us.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ text_settings:
supportHeight: Support height
supportPadding: Support spacing
alignment: Text alignment
valignment: Text vertical alignement
supportBorderRadius: Border radius
handleSettings:
label: Handle settings
Expand All @@ -75,6 +76,10 @@ alignment:
left: Left
center: Center
right: Right
valignment:
default: Default
top: Top
bottom: Bottom
directions:
top: Top
bottom: Bottom
Expand Down
5 changes: 5 additions & 0 deletions translations/fr-fr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ text_settings:
supportHeight: Hauteur du support
supportPadding: Espacement du support
alignment: Alignement du texte
valignment: Alignement vertical du texte
supportBorderRadius: Rayon des coins
handleSettings:
label: Option d'accroche
Expand All @@ -72,6 +73,10 @@ alignment:
left: Gauche
center: Centré
right: Droite
valignment:
default: Auto
top: Haut
bottom: Bas
directions:
top: Haut
bottom: Bas
Expand Down

0 comments on commit bce9537

Please sign in to comment.