diff --git a/README.md b/README.md
index 00112db..cbd8859 100644
--- a/README.md
+++ b/README.md
@@ -57,6 +57,7 @@ npm run lint
# TODO / Roadmap
* Render service should use the tool-options-text debounce on first font load to ensure font is present on document load
+* Render service should measure total text bounding box upfront and scale resulting bitmap (can be done after render)
* Try very wide Dropbox image on MB Air with space + pan in bottom right area. Won't work.
* Restoring positions of documents with positioned rotated objects is not accurate
* Issue with drawing mask on mirrored content
diff --git a/src/components/modal/modal.vue b/src/components/modal/modal.vue
index fe2d48b..ae3d486 100644
--- a/src/components/modal/modal.vue
+++ b/src/components/modal/modal.vue
@@ -66,7 +66,7 @@ export default {
}
.actions {
- position: fixed;
+ position: absolute;
bottom: 0;
left: 0;
width: 100%;
@@ -79,6 +79,10 @@ export default {
flex: 1;
margin: $spacing-small;
}
+
+ @include mobile() {
+ position: fixed;
+ }
}
@include large() {
diff --git a/src/components/options-panel/tool-options-text/messages.json b/src/components/options-panel/tool-options-text/messages.json
index e33e7ad..23ef5a6 100644
--- a/src/components/options-panel/tool-options-text/messages.json
+++ b/src/components/options-panel/tool-options-text/messages.json
@@ -3,6 +3,8 @@
"text": "Text",
"font": "Font",
"size": "Size",
+ "lineHeight": "Line height",
+ "spacing": "Letter spacing",
"color": "Color"
}
}
diff --git a/src/components/options-panel/tool-options-text/tool-options-text.vue b/src/components/options-panel/tool-options-text/tool-options-text.vue
index 19d9591..a0862f5 100644
--- a/src/components/options-panel/tool-options-text/tool-options-text.vue
+++ b/src/components/options-panel/tool-options-text/tool-options-text.vue
@@ -48,6 +48,15 @@
:tooltip="'none'"
/>
+
+
+
+
({
internalText: "",
renderPending: false,
+ layerId: null,
}),
computed: {
...mapGetters([
@@ -108,7 +118,7 @@ export default {
this.renderPending = false;
this.updateLayer({
index: this.activeLayerIndex,
- opts: { text: { value: this.text, size: this.size, font: this.font, color: this.color } },
+ opts: this.formatOpts({ value })
});
}, 75 );
}
@@ -117,10 +127,21 @@ export default {
get() {
return this.activeLayer.text?.size;
},
- set( value ) {
+ set( size ) {
this.updateLayer({
index: this.activeLayerIndex,
- opts: { text: { value: this.text, size: value, font: this.font, color: this.color } },
+ opts: this.formatOpts({ size })
+ });
+ }
+ },
+ lineHeight: {
+ get() {
+ return this.activeLayer.text?.lineHeight;
+ },
+ set( lineHeight ) {
+ this.updateLayer({
+ index: this.activeLayerIndex,
+ opts: this.formatOpts({ lineHeight }),
});
}
},
@@ -128,10 +149,10 @@ export default {
get() {
return this.activeLayer.text?.color;
},
- set( value ) {
+ set( color ) {
this.updateLayer({
index: this.activeLayerIndex,
- opts: { text: { value: this.text, size: this.size, font: this.font, color: value } },
+ opts: this.formatOpts({ color })
});
}
},
@@ -139,11 +160,11 @@ export default {
get() {
return this.activeLayer.text?.font;
},
- async set( value ) {
- const fromCache = await loadGoogleFont( value );
+ async set( font ) {
+ const fromCache = await loadGoogleFont( font );
this.updateLayer({
index: this.activeLayerIndex,
- opts: { text: { value: this.text, size: this.size, font: value, color: this.color } },
+ opts: this.formatOpts({ font })
});
// on first load, font is not immediately available for rendering
if ( !fromCache ) {
@@ -158,7 +179,10 @@ export default {
activeLayer: {
immediate: true,
handler( layer ) {
- this.internalText = layer.text?.value;
+ if ( this.layerId !== layer.id ) {
+ this.internalText = layer.text?.value;
+ this.layerId = layer.id;
+ }
}
},
},
@@ -178,6 +202,18 @@ export default {
handleBlur() {
KeyboardService.setSuspended( false );
},
+ formatOpts( textOpts = {} ) {
+ return {
+ text: {
+ value: this.text,
+ size: this.size,
+ lineHeight: this.lineHeight,
+ font: this.font,
+ color: this.color,
+ ...textOpts,
+ }
+ };
+ },
},
};
diff --git a/src/factories/text-factory.js b/src/factories/text-factory.js
index 55674cf..eb440b5 100644
--- a/src/factories/text-factory.js
+++ b/src/factories/text-factory.js
@@ -23,9 +23,18 @@
import { googleFonts } from "@/services/font-service";
const TextFactory = {
- create({ font = googleFonts[ 0 ], value = "", size = 16, color = "red" } = {}) {
+ create({
+ font = googleFonts[ 0 ],
+ value = "",
+ size = 16,
+ lineHeight = 0,
+ spacing = 0,
+ color = "red"
+ } = {}) {
return {
font,
+ lineHeight,
+ spacing,
value,
size,
color,
@@ -41,6 +50,8 @@ const TextFactory = {
f: text.font,
v: text.value,
s: text.size,
+ l: text.lineHeight,
+ p: text.spacing,
c: text.color,
};
},
@@ -54,6 +65,8 @@ const TextFactory = {
font: text.f,
value: text.v,
size: text.s,
+ lineHeight: text.l,
+ spacing: text.p,
color: text.c,
});
}
diff --git a/src/services/render-service.js b/src/services/render-service.js
index 14b334c..e61d629 100644
--- a/src/services/render-service.js
+++ b/src/services/render-service.js
@@ -157,12 +157,12 @@ const renderText = async layer => {
sourceCtx.fillStyle = text.color;
const lines = text.value.split( "\n" );
- const lineHeight = text.size;
+ const lineHeight = text.lineHeight ? text.lineHeight : text.size;
let y = 0;
lines.forEach(( line, index ) => {
- const textMetrics = sourceCtx.measureText( line );
- y = lineHeight + index * lineHeight;
- y += Math.abs( textMetrics[ "actualBoundingBoxDescent" ]);
+ //const textMetrics = sourceCtx.measureText( line );
+ y = lineHeight + ( index * lineHeight );
+ //y += Math.abs( textMetrics[ "actualBoundingBoxDescent" ]);
sourceCtx.fillText( line, 0, y );
});
};
diff --git a/src/styles/component.scss b/src/styles/component.scss
index 1932058..5d54f79 100644
--- a/src/styles/component.scss
+++ b/src/styles/component.scss
@@ -20,7 +20,7 @@
@include large() {
padding: $spacing-medium;
- height: calc(100% - $heading-height);
+ height: calc(100% - #{$heading-height});
}
@include mobile() {
padding: $spacing-xsmall $spacing-small;
diff --git a/tests/unit/factories/text-factory.spec.js b/tests/unit/factories/text-factory.spec.js
index 89f80c7..dec7ea7 100644
--- a/tests/unit/factories/text-factory.spec.js
+++ b/tests/unit/factories/text-factory.spec.js
@@ -7,6 +7,8 @@ describe( "Text factory", () => {
const text = TextFactory.create();
expect( text ).toEqual({
size: expect.any( Number ),
+ lineHeight: expect.any( Number ),
+ spacing: 0,
value: "",
font: googleFonts[ 0 ],
color: "red",
@@ -16,12 +18,16 @@ describe( "Text factory", () => {
it( "should be able to create a Text structure from given arguments", () => {
const text = TextFactory.create({
size: 10,
+ lineHeight: 30,
+ spacing: 50,
font: "Helvetica",
value: "Foo bar baz",
color: "#FF00AE"
});
expect( text ).toEqual({
size: 10,
+ lineHeight: 30,
+ spacing: 50,
font: "Helvetica",
value: "Foo bar baz",
color: "#FF00AE"
@@ -33,6 +39,8 @@ describe( "Text factory", () => {
it( "should do so without data loss", async () => {
const text = TextFactory.create({
size: 10,
+ lineHeight: 40,
+ spacing: 10,
font: "Helvetica",
value: "Foo bar baz",
color: "#FFF"