first version

This commit is contained in:
2020-10-05 20:26:29 +08:00
parent fdcd2f5042
commit ff12497673
17 changed files with 1811 additions and 0 deletions
+124
View File
@@ -0,0 +1,124 @@
# TextFrame
[中文版](https://github.com/mattuylee/text-frame) | [English](https://github.com/mattuylee/text-frame/docs/en/README-EN.md)
A javascript tool to split long text into frames, with typesetting prohibition processed and unicode full support.
## Introduction
It's difficute to compute how many characters a DOM element can show, because diffrent User Agents have diffrent typesetting rules. So for that, we have to draw text on a canvas with our own rules to know how to split text into several text frames, since we can compute character width through [CanvasRenderingContext2D.measureText()](https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D/measureText).
refering to [W3C draft](https://www.w3.org/TR/2020/WD-clreq-20201001/#prohibition_rules_for_line_start_end) for Chinese typesetting, following are my rules:
### Prohibition Rules for Line Start
| Punctuation Name | The Punctuation Marks |
| ---- | ------ |
| Pause or Stop | 、,..。:;!? |
| Closing Quotation | '"」』”’ |
| Closing Parentheses | )]})】〗〕]} |
| Closing Angle Brackets | 》〉 |
| Connectors | ~~— |
| Interpuncts | ·.‧•・ |
| Solidi | / |
### Prohibition Rules for Line End
| Punctuation Name | The Punctuation Marks |
| ---- | ------ |
| Opening Quotation | 「『“‘ |
| opening Parentheses | ([{(【〖〔[〔 |
| Opening Angle Brackets | 《〈 |
| Solidi | / |
### Prohibition Rules for Unbreakable Marks
| Name | Mark |
| ---- | ------ |
| Em dash and long dash | ── |
| Ellipsis | …… |
This library take the above as default rules, but it can be configued with [options](https://mattuylee.github.io/text-frame/en/options.md).
Here is an online [demo](https://mattuylee.github.io/text-frame/en/example.html).
## Usage
Browser environment is required, and [canvas support](https://caniuse.com/?search=canvas) is needed. This library CANNOT work under web worker.
### API
```typescript
// compute text frames
function computeTextFrames(options: FrameOptions): TextFrame[];
// render text frame
function renderFrame(context: CanvasRenderingContext2D, frame: TextFrame, clear: boolean): void;
```
### npm
`npm install @mattuy/text-frame --save`
### ES2015 & CommonJS
```javascript
// cjs
// const { computeTextFrames, renderFrame } = require('@mattuy/text-frame');
// or esm
import { computeTextFrames, renderFrame } from '@mattuy/text-frame/esm';
const frames = computeTextFrames({
viewWidth: 320,
viewHeight: 640,
fontSize: 16,
margin: 8,
color: '#000',
fragments: [
{
color: 'green',
fontSize: 20,
margin: 32,
textAlign: 'center',
text: "Caption"
},
{
textIndent: 32,
fontFamily: 'serif',
margin: { bottom: 32 },
marginCollapse: true,
textAlign: 'justify',
text: "This is a multi-line text. Pass your text paragraph as this."
}
]
});
const canvas = document.createElement('canvas');
canvas.style.width = '320px';
canvas.style.height = '640px';
document.body.append(canvas);
renderFrame(canvas.getContext('2d'), frames[0], true);
```
### Globally Script
```html
<script src="text-frame/dist/umd/text-frame-min.js"></script>
<script>
const frames = TextFrame.computeTextFrames({
// ...options
});
console.log(frames)
// ...render
</script>
```
Option reference sits [here](https://mattuylee.github.io/text-frame/en/options.md).
## Build from Source
* clone the repo
`git clone https://github.com/mattuylee/text-frame.git`
* install dependences
`cd text-frame`
`npm install`
### Distribution
`npm run dist`
### Start a demo serve
`npm run example`
### Debug
Run `npm run debug`, then open `example/index.html` in your browser, rollup will watch your code changes and automatically rebuild.
## Licence
MIT
+130
View File
@@ -0,0 +1,130 @@
# Options
## API Signature
```typescript
export function computeTextFrames(options: FrameOptions): TextFrame[];
export function renderFrame(context: CanvasRenderingContext2D, frame: TextFrame, clear: boolean): void;
```
## FrameOptions
### viewWidth
* Type: `number`
* Default: `300`
* Description: view width, must equal to canvas.style.width, but be numeric
### viewHeight
* Type: `number`
* Default: `150`
* Description: view height
### canvasWidth
* Type: `number`
* Default: compute with `viewWidth`
* Description: canvas.widthdefault is `viewWidth * window.devicePixelRatio`
### canvasHeight
* Type: `number`
* Default: 根据`viewHeight`计算。
* Description: canvas.height is `viewHeight * window.devicePixelRatio`
### margin
* Type: `number | { left?: number, right?: number, top?: number, bottom?: number }`
* Default: `0`
* Description: margin for **frame**
### lineStartProhibitedMarks
* Type: `string`
* Default: `、,..。:;!?'"」』”’)]})】〗〕]}》〉–~~—·.‧•・//`
* Description: prohibition characters for line start
### lineEndProhibitedMarks
* Type: `string`
* Default: `「『“‘([{(【〖〔[〔《〈/`
* Description: prohibition characters for line end
### unbreakableRule
* Type: `RegExp`
* Default: `/──|……|[\w\d]+/`
* Description: unbreakable marks. If not empty, must be a RegExp instance. Marks match the rule will not be split into diffrent lines
### fragments
* Type: `FragmentOptions[]`
* Default: `null`
* Description: text fragments, typically one paragraph one fragment
## FrameOptions & FragmentOptions
Options for both frame and fragment. Fragment option will inhirit from frame option if it's empty except `margin`.
### fontFamily
* Type: `string`
* Default: `serif`
* Description: font family
### fontSize
* Type: `number`
* Default: `16`
* Description: font size
### fontWeight
* Type: `string | number`
* Default: `16`
* Description: font weight, refer CSS `font-weight`
### color
* Type: `string`
* Default: `#000000`
* Description: font color
### lineHeight
* Type: `number`
* Default: 1.5 * `fontSize`
* Description: line height
### textIndent
* Type: `number`
* Default: `0`
* Description: text indentation for first line of fragment. interal new line of a fragment is not processed
### textAlign
* Type: `'center' | 'start' | 'end' | 'left' | 'right' | 'justify'`
* Default: `start`
* Description: text alignment, refer CSS `text-align`
### textAlignLast
* Type: `'center' | 'start' | 'end' | 'left' | 'right' | 'justify'`
* Default: `start`
* Description: when `textAlign` is `justify`, how the last line is aligned. internal new line of a fragment is also processed. refer CSS `text-align-last`
### rtl
* Type: `boolean`
* Default: `false`
* Description: if true, draw text from right to left
### trim
* Type: `boolean`
* Default: `false`
* Description: if true, trim white characters of text of a fragment
### marginCollapse
* Type: `boolean`
* Default: `true`
* Description: if true, the margin-top a fragment is the max of its own and the previous one. if `marginCollapse` of the previous fragment is `false`, margin of current fragment will not collapse
### noHeadMargin
* Type: `boolean`
* Default: `false`
* Description: ignore margin-top if a fragment is on the top of a frame
## FragmentOptions
### margin
* Type: `number | { left?: number, right?: number, top?: number, bottom?: number }`
* Default: `0`
* Description: margin of a **fragment**
### text
* Type: `string`
* Default: `''`
* Description: text content of a fragment
View File
+129
View File
@@ -0,0 +1,129 @@
# 配置项
## 导出函数原型
```typescript
export function computeTextFrames(options: FrameOptions): TextFrame[];
export function renderFrame(context: CanvasRenderingContext2D, frame: TextFrame): void;
```
## FrameOptions
### viewWidth
* 类型: `number`
* 默认值: `300`
* 说明: 指定视图宽度,用于计算`canvasWidth`。除非显式提供`canvasWidth`参数,否则必须提供此参数。`viewWidth`应与要实际绘制文本的canvas的css宽度相等。
### viewHeight
* 类型: `number`
* 默认值: `150`
* 说明:指定视图高度。
### canvasWidth
* 类型: `number`
* 默认值: 根据`viewWidth`计算。
* 说明: canvas画布宽度,对应canvas.width,默认为`viewWidth * window.devicePixelRatio`
### canvasHeight
* 类型: `number`
* 默认值: 根据`viewHeight`计算。
* 说明: canvas画布高度,对应canvas.height。
### margin
* 类型: `number | { left?: number, right?: number, top?: number, bottom?: number }`
* 默认值: `0`
* 说明: 每个分页(frame)的边距。注意,虽然`FragmentOptions`也有margin配置项,但二者并不是继承关系,而是作用于不同的对象:页面(frame)和文本段落(fragment)。
### lineStartProhibitedMarks
* 类型: `string`
* 默认值: `、,..。:;!?'"」』”’)]})】〗〕]}》〉–~~—·.‧•・//`
* 说明: 禁止出现在行首的字符。
### lineEndProhibitedMarks
* 类型: `string`
* 默认值: `「『“‘([{(【〖〔[〔《〈/`
* 说明: 禁止出现在行尾的字符。
### unbreakableRule
* 类型: `RegExp`
* 默认值: `/──|……|[\w\d]+/`
* 说明: 符号分离禁则规则。如果提供,必须为正则表达式,正则表达式匹配则该认为该组合不能被拆分到新行,默认为破折号,省略号,和英文字母、数字组合。
### fragments
* 类型: `FragmentOptions[]`
* 默认值: `null`
* 说明: 文本段落数组。必须提供此参数。
## FrameOptions & FragmentOptions
以下配置项既可以在`FrameOptions`中指定,也可以在`FragmentOptions`中指定。当`FragmentOptions`未指定相关参数时,将继承`FrameOptions`的配置(再次强调,`margin`并不会继承)。
### fontFamily
* 类型: `string`
* 默认值: `serif`
* 说明: 字体名称。
### fontSize
* 类型: `number`
* 默认值: `16`
* 说明: 字体大小。
### fontWeight
* 类型: `string | number`
* 默认值: `16`
* 说明: 字体粗细。参考CSS `font-weight`
### color
* 类型: `string`
* 默认值: `#000000`
* 说明: 字体颜色。
### lineHeight
* 类型: `number`
* 默认值: 1.5倍`fontSize`
* 说明: 行高。
### textIndent
* 类型: `number`
* 默认值: `0`
* 说明: 首行缩进。注意,对于每一个文本段落,仅首行缩进,即使文本段落中有换行符,新行也不会缩进。参考word中的软回车。若要分段落应提供多个文本段落。
### textAlign
* 类型: `'center' | 'start' | 'end' | 'left' | 'right' | 'justify'`
* 默认值: `start`
* 说明: 文本对齐方式。参考CSS `text-align`
### textAlignLast
* 类型: `'center' | 'start' | 'end' | 'left' | 'right' | 'justify'`
* 默认值: `start`
* 说明: 当`textAlign``justify`时(两端对齐),段落最后一行的对齐方式。注意,这里的最后一行包括文本片段内部的换行符前的最后一行。参考CSS `text-align-last`
### rtl
* 类型: `boolean`
* 默认值: `false`
* 说明: 是否从右到左渲染。
### trim
* 类型: `boolean`
* 默认值: `false`
* 说明: 是否自动删除文本片段首尾的空白符。注意,文本片段内部换行后行首尾空白符不会被清除。
### marginCollapse
* 类型: `boolean`
* 默认值: `true`
* 说明: 文本片段的上边距是否与前一文本片段的下边距折叠。注意,如果相邻的任一文本片段`marginCollapse`为false,则不会发生边距折叠。
### noHeadMargin
* 类型: `boolean`
* 默认值: `false`
* 说明: 当一个文本片段正好开始于一个空的页面时,是否忽略其上边距。
## FragmentOptions
### margin
* 类型: `number | { left?: number, right?: number, top?: number, bottom?: number }`
* 默认值: `0`
* 说明: 文本片段的边距。注意,此配置项不继承于`FrameOptions``margin`选项。
### text
* 类型: `string`
* 默认值: `''`
* 说明: 该文本段落要绘制的文本内容。