Skip to content

Commit e2d7ef2

Browse files
committed
Add overflow option to drawText() API
Originally requested here: geongeorge/Canvas-Txt#83 And fix proposed here: geongeorge/Canvas-Txt#94 By default, text overflows. Set to `false` to clip the text to the specified box.
1 parent a56c1c6 commit e2d7ef2

File tree

5 files changed

+58
-27
lines changed

5 files changed

+58
-27
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## UNRELEASED
9+
10+
### Added
11+
12+
- New `overflow?: boolean` config parameter for `drawText()` API: True (default) to allow overflow; false to clip text to box.
13+
814
## v1.0.0
915

1016
- First official release 🎉

CONTRIBUTING.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,16 @@ Run `npm test`, the Docs app, and the Node demo and manually verify your changes
4141

4242
## Pull requests
4343

44-
Always include a new bullet point in the [CHANGELOG](./CHANGELOG.md) under the __UNRELEASED__ heading at the very top.
44+
Always include a new bullet point (CD, Change Description) in the [CHANGELOG](./CHANGELOG.md) under the __UNRELEASED__ heading at the very top, linking to the issue being addressed when applicable, typically ending your CD with `([#123](https://github.com/stefcameron/text-to-canvas/issues/123))`
4545

46-
Include your change description in one of the following subsections under "UNRELEASED":
46+
Include your CD in one of the following subsections under "UNRELEASED":
4747

48-
> If an "UNRELEASED" heading doesn't exist, please add one!
48+
> If an `## UNRELEASED` heading doesn't exist, please add one!
4949
50-
- "Breaking": If your change alters an existing API/type in a way that is not backward-compatible, or makes use of a Web API that doesn't yet have wide browser support.
50+
- `### Breaking`: If your change alters an existing API/type in a way that is not backward-compatible, or makes use of a Web API that doesn't yet have wide browser support.
5151
- __AVOID__ this type of change as best as possible.
52-
- "Added": If your change adds a new feature without breaking anything pre-existing.
53-
- "Changed": If your change alters existing behavior without breaking anything pre-existing, including bug fixes.
52+
- `### Added`: If your change adds a new feature without breaking anything pre-existing.
53+
- `### Changed`: If your change alters existing behavior without breaking anything pre-existing, including bug fixes.
5454
- If you're fixing a bug, try to start your change description with, "Fixed ..."
55-
- Always link to the issue being addressed when applicable, typically ending your change description with `([#123](https://github.com/stefcameron/text-to-canvas/issues/123))`
5655

5756
And please fill-out the pull request template when prompted!

src/docs/AppCanvas.vue

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const initialConfig = {
1919
vAlign: 'middle',
2020
justify: false,
2121
debug: false,
22+
overflow: true,
2223
};
2324
2425
const config = reactive(cloneDeep(initialConfig));
@@ -52,6 +53,7 @@ function renderText() {
5253
vAlign: config.vAlign,
5354
justify: config.justify,
5455
debug: config.debug,
56+
overflow: config.overflow,
5557
// currently not configurable in demo UI
5658
fontFamily: 'Times New Roman, serif',
5759
fontSize: 24,
@@ -163,9 +165,10 @@ onMounted(() => {
163165
size="small"
164166
/>
165167
</div>
168+
166169
<br />
167-
<el-row>
168-
<el-col :span="12">
170+
<el-row :gutter="12">
171+
<el-col :span="8">
169172
<el-form-item label="Horizontal Align">
170173
<el-select v-model="config.align" placeholder="Align">
171174
<el-option label="Center" value="center" />
@@ -174,7 +177,7 @@ onMounted(() => {
174177
</el-select>
175178
</el-form-item>
176179
</el-col>
177-
<el-col :span="12">
180+
<el-col :span="8">
178181
<el-form-item label="Vertical Align">
179182
<el-select v-model="config.vAlign" placeholder="vAlign">
180183
<el-option label="Middle" value="middle" />
@@ -183,12 +186,15 @@ onMounted(() => {
183186
</el-select>
184187
</el-form-item>
185188
</el-col>
189+
<el-col :span="8">
190+
<el-checkbox v-model="config.justify" label="Justify" />
191+
</el-col>
186192
</el-row>
187193
<br />
188194

189-
<el-row>
195+
<el-row :gutter="12">
190196
<el-col :span="12">
191-
<el-checkbox v-model="config.justify" label="Justify Text" />
197+
<el-checkbox v-model="config.overflow" label="Overflow" />
192198
</el-col>
193199
<el-col :span="12">
194200
<el-checkbox v-model="config.debug" label="Debug mode" />

src/lib/index.ts

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ const drawText = (
2222
fontWeight: config.fontWeight,
2323
});
2424

25+
const {
26+
width: boxWidth,
27+
height: boxHeight,
28+
x: boxX = 0,
29+
y: boxY = 0,
30+
} = config;
31+
2532
const {
2633
lines: richLines,
2734
height: totalHeight,
@@ -33,8 +40,8 @@ const drawText = (
3340
inferWhitespace: Array.isArray(text)
3441
? config.inferWhitespace === undefined || config.inferWhitespace
3542
: undefined, // ignore since `text` is a string; we assume it already has all the whitespace it needs
36-
x: config.x || 0,
37-
y: config.y || 0,
43+
x: boxX,
44+
y: boxY,
3845
width: config.width,
3946
height: config.height,
4047
align: config.align,
@@ -49,6 +56,12 @@ const drawText = (
4956
ctx.font = getTextStyle(baseFormat);
5057
ctx.fillStyle = baseFormat.fontColor || DEFAULT_FONT_COLOR;
5158

59+
if (config.overflow === false) {
60+
ctx.beginPath();
61+
ctx.rect(boxX, boxY, boxWidth, boxHeight);
62+
ctx.clip(); // part of saved context state
63+
}
64+
5265
richLines.forEach((line) => {
5366
line.forEach((pw) => {
5467
if (!pw.isWhitespace) {
@@ -71,40 +84,39 @@ const drawText = (
7184
});
7285

7386
if (config.debug) {
74-
const { width, height, x = 0, y = 0 } = config;
75-
const xEnd = x + width;
76-
const yEnd = y + height;
87+
const xEnd = boxX + boxWidth;
88+
const yEnd = boxY + boxHeight;
7789

7890
let textAnchor: number;
7991
if (config.align === 'right') {
8092
textAnchor = xEnd;
8193
} else if (config.align === 'left') {
82-
textAnchor = x;
94+
textAnchor = boxX;
8395
} else {
84-
textAnchor = x + width / 2;
96+
textAnchor = boxX + boxWidth / 2;
8597
}
8698

87-
let debugY = y;
99+
let debugY = boxY;
88100
if (config.vAlign === 'bottom') {
89101
debugY = yEnd;
90102
} else if (config.vAlign === 'middle') {
91-
debugY = y + height / 2;
103+
debugY = boxY + boxHeight / 2;
92104
}
93105

94106
const debugColor = '#0C8CE9';
95107

96108
// Text box
97109
ctx.lineWidth = 1;
98110
ctx.strokeStyle = debugColor;
99-
ctx.strokeRect(x, y, width, height);
111+
ctx.strokeRect(boxX, boxY, boxWidth, boxHeight);
100112

101113
ctx.lineWidth = 1;
102114

103115
if (!config.align || config.align === 'center') {
104116
// Horizontal Center
105117
ctx.strokeStyle = debugColor;
106118
ctx.beginPath();
107-
ctx.moveTo(textAnchor, y);
119+
ctx.moveTo(textAnchor, boxY);
108120
ctx.lineTo(textAnchor, yEnd);
109121
ctx.stroke();
110122
}
@@ -113,7 +125,7 @@ const drawText = (
113125
// Vertical Center
114126
ctx.strokeStyle = debugColor;
115127
ctx.beginPath();
116-
ctx.moveTo(x, debugY);
128+
ctx.moveTo(boxX, debugY);
117129
ctx.lineTo(xEnd, debugY);
118130
ctx.stroke();
119131
}

src/lib/model.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,6 @@ export interface DrawTextConfig extends TextFormat {
105105
justify?: boolean;
106106

107107
/**
108-
* __NOTE:__ Applies only if `text`, given to `drawText()`, is a `Word[]`. Ignored if it's
109-
* a `string`.
110-
*
111108
* True indicates `text` is a `Word` array that contains _mostly_ visible words and
112109
* whitespace should be inferred _unless a word is whitespace (e.g. a new line or tab)_, based
113110
* on the context's general text formatting style (i.e. every space will use the font style set
@@ -116,11 +113,22 @@ export interface DrawTextConfig extends TextFormat {
116113
* as Words with `text="\n"`).
117114
*
118115
* False indicates that `words` contains its own whitespace and it shouldn't be inferred.
116+
*
117+
* ❗️ Applies only if `text`, given to `drawText()`, is a `Word[]`. Ignored if it's
118+
* a `string`.
119119
*/
120120
inferWhitespace?: boolean;
121121

122122
/** True if debug lines should be rendered behind the text. */
123123
debug?: boolean;
124+
125+
/**
126+
* True (default) if the text should overflow the box's boundaries when it's either too
127+
* tall or too wide to fit.
128+
*
129+
* False if the text should be clipped to the box's boundaries.
130+
*/
131+
overflow?: boolean;
124132
}
125133

126134
export interface BaseSplitProps {

0 commit comments

Comments
 (0)