feat: draw ts 改造

This commit is contained in:
tackchen 2020-12-14 17:53:39 +08:00
parent 19d5f2ae40
commit 3f4a143038
31 changed files with 955 additions and 726 deletions

886
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,9 @@
import cnchar from '../src/main/index';
// import cnchar from '../src/main/index';
import cnchar from '../src/main/ts/index';
import '../src/plugin/order';
import '../src/plugin/trad';
import '../src/plugin/poly';
import '../src/plugin/draw';
import '../src/plugin/draw/ts';
import '../src/plugin/idiom';
import '../src/plugin/xhy';
import '../src/plugin/radical';

2
src/main/index.d.ts vendored
View File

@ -1,5 +1,3 @@
import './extend';
declare type spellArg = 'array' | 'low' | 'up' | 'first' | 'poly' | 'tone' | 'simple' | 'trad';
declare type strokeArg = 'letter' | 'shape' | 'count' | 'name' | 'detail' | 'array' | 'order' | 'simple' | 'trad';
declare type spellToWordArg = 'poly' | 'alltone' | 'array' | 'simple' | 'trad';

View File

@ -1,9 +1,9 @@
import {CnCharInterface} from './types';
import {ICnChar} from './types';
let _cnchar: CnCharInterface;
let _cnchar: ICnChar;
const toneCodes: Array<number> = [];
export function initToneCodes (__cnchar: CnCharInterface): void {
export function initToneCodes (__cnchar: ICnChar): void {
_cnchar = __cnchar;
'aoeiuvn'.split('').forEach(item => {
const code = item.charCodeAt(0);

View File

@ -5,6 +5,7 @@ import infoDict from './dict/info-dict.json';
import {mapJson} from './util';
import {transformTone, spell, arg, shapeSpell, stroke} from './tool';
import {Json, ITransformReturn} from './types/common';
import {ISetIntoJson} from './types/tool';
const strokeDict = originStrokeDict as Json<string>;
// 设置多音字默认拼音
@ -16,24 +17,18 @@ export function setSpellDefault (word: string | Json<string>, spell?: string): v
isSpell: true
});
}
export function setIntoJson ({
export const setIntoJson: ISetIntoJson = ({
target,
key,
value,
isSpell = false
} : {
target: Json<string>,
key: string | Json<string>,
value?: string,
isSpell: boolean
}): void {
isSpell = false,
}): void => {
mapJson(key, value, (k, v) => {
if (k && v) {
target[k] = isSpell ? shapeSpell(v) : v;
}
});
}
};
function setIntoSpellBase (
dict: Json<string>,

5
src/main/ts/index.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
import {ICnChar} from './types/index';
declare const cnchar: ICnChar;
export default cnchar;

View File

@ -9,7 +9,7 @@ import {setSpellDefault, setIntoJson, setSpell, setStrokeCount} from './config';
import {initSpellToWord, spellToWord, spellInfo} from './spellToWord';
import {initStrokeToWord, strokeToWord} from './strokeToWord';
import {compareSpell, sortSpell, compareStroke, sortStroke, initSort} from './sort';
import {CnCharInterface, SpellArg, StrokeArg} from './types';
import {ICnChar, SpellArg, StrokeArg} from './types';
import {IPlugin} from './types/common';
function _spell (...args: Array<string>): string | Array<string> {
@ -28,7 +28,7 @@ function initStrProto () {
};
}
const cnchar: CnCharInterface = {
const cnchar: ICnChar = {
version,
spell: _spell,
stroke: _stroke,

5
src/main/ts/package-lock.json generated Normal file
View File

@ -0,0 +1,5 @@
{
"name": "cnchar",
"version": "2.2.8",
"lockfileVersion": 1
}

29
src/main/ts/package.json Normal file
View File

@ -0,0 +1,29 @@
{
"name": "cnchar",
"version": "2.2.8",
"description": "功能全面、多端支持的汉字拼音笔画js库支持多音字、繁体字、火星文",
"main": "index.js",
"scripts": {},
"unpkg": "cnchar.min.js",
"jsdelivr": "cnchar.min.js",
"typings": "index.d.ts",
"repository": {
"type": "git",
"url": "git+https://github.com/theajack/cnchar.git"
},
"keywords": [
"汉字拼音",
"汉字笔画数",
"汉字笔画顺序",
"繁体字",
"火星文",
"js库",
"theajack"
],
"author": "theajack",
"license": "MIT",
"bugs": {
"url": "https://github.com/theajack/cnchar/issues"
},
"homepage": "https://www.theajack.com/cnchar/"
}

View File

@ -1,7 +1,7 @@
import {initToneCodes, getCharCode} from './compareSpell';
import {CnCharInterface, CompareType, SortSpellArg} from './types';
import {ICnChar, CompareType, SortSpellArg, SpellArg} from './types';
let _cnchar: CnCharInterface;
let _cnchar: ICnChar;
const arg:{
[prop in SortSpellArg]: SortSpellArg
@ -10,7 +10,7 @@ const arg:{
'desc': 'desc',
};
export function initSort (__cnchar: CnCharInterface) {
export function initSort (__cnchar: ICnChar) {
_cnchar = __cnchar;
initToneCodes(__cnchar);
}
@ -25,7 +25,7 @@ const TYPE:{
};
function pretreat (spell: string, tone: boolean): string {
const arr: Array<spellArg> = ['low'];
const arr: Array<SpellArg> = ['low'];
if (tone) {arr.push('tone');}
if (_cnchar.isCnChar(spell)) {
return _cnchar.spell(spell, ...arr) as string;

View File

@ -1,18 +1,19 @@
import originDict from './dict/spell-dict-jian.json';
import {initial as initialDict} from './dict/info-dict.json';
import {CnCharInterface, CncharToolInterface, ToneType, TypeValueObject, SpellToWordArg} from './types/index';
import {SpellInfoInterface, Json, spellInfoReturnInterface} from './types/common';
import {ICnChar, ToneType, TypeValueObject, SpellToWordArg} from './types/index';
import {ICncharTool} from './types/tool';
import {ISpellInfo, Json, ISpellInfoReturn} from './types/common';
const dict = originDict as Json<string>;
const arg: {
[prop in SpellToWordArg]: SpellToWordArg
} = {simple: 'simple', trad: 'trad', poly: 'poly', alltone: 'alltone', array: 'array'};
let _: CncharToolInterface;// 工具方法
let _: ICncharTool;// 工具方法
// 获取拼音信息 spell,tone,index,initial,final
export const spellInfo = ((spell: string): spellInfoReturnInterface => {
export const spellInfo = ((spell: string): ISpellInfoReturn => {
spell = spell.toLowerCase();
const info = _.removeTone(spell, false);
if (info.index === -1) {
@ -37,9 +38,9 @@ export const spellInfo = ((spell: string): spellInfoReturnInterface => {
initial,
final,
};
}) as unknown as SpellInfoInterface;
}) as unknown as ISpellInfo;
export function initSpellToWord (cnchar: CnCharInterface): void {
export function initSpellToWord (cnchar: ICnChar): void {
_ = cnchar._;
spellInfo.tones = _.tones.split('');
spellInfo.initials = initialDict;

View File

@ -1,12 +1,13 @@
import dict from './dict/stroke-count-jian.json';
import {Json} from './types/common';
import {CnCharInterface, CncharToolInterface, StrokeToWordArg, TypeValueObject} from './types/index';
import {ICnChar, StrokeToWordArg, TypeValueObject} from './types/index';
import {ICncharTool} from './types/tool';
const arg: {
[prop in StrokeToWordArg]: StrokeToWordArg
} = {simple: 'simple', trad: 'trad', array: 'array'};
let _: CncharToolInterface;// 工具方法
let _: ICncharTool;// 工具方法
export function initStrokeToWord (cnchar: CnCharInterface): void {
export function initStrokeToWord (cnchar: ICnChar): void {
cnchar.strokeToWord = strokeToWord;
cnchar.type.strokeToWord = arg as TypeValueObject;
_ = cnchar._;

View File

@ -1,17 +1,17 @@
import {spellInfo} from './spellToWord';
import {_warn, isCnChar, has} from './util';
import defultDict from './dict/spell-default.json';
import {AllArgs, CnCharInterface, TypeProp, ToneType, SpellArg, StrokeArg, TypeValueObject} from './types/index';
import {AllArgs, ICnChar, TypeProp, ToneType, SpellArg, StrokeArg, TypeValueObject} from './types/index';
import {Json, ITransformReturn} from './types/common';
import {TSpellArg, IDealUpLowFirst, IRemoveTone, IFunc, ICheckArgs, ITransformTone} from './types/tool';
const defDict = defultDict as Json<string>;
export const tones: string = 'āáǎàōóǒòēéěèīíǐìūúǔùǖǘǚǜ*ńňǹ'; // * 表示n的一声
const noTones: string = 'aoeiuün';
export const arg: {
[prop in SpellArg]: SpellArg
} = {
export const arg: TSpellArg = {
array: 'array',
low: 'low',
up: 'up',
@ -22,8 +22,8 @@ export const arg: {
trad: 'trad',
};
let _cnchar: CnCharInterface;
export function initCnchar (cnchar: CnCharInterface): void {
let _cnchar: ICnChar;
export function initCnchar (cnchar: ICnChar): void {
_cnchar = cnchar;
}
@ -95,10 +95,10 @@ export function spell (dict: Json<string>, originArgs: Array<string>): string |
return result;
}
export function dealUpLowFirst (
export const dealUpLowFirst: IDealUpLowFirst = (
res: Array<Array<string>> | Array<string>,
args: Array<SpellArg>
): void {
): void => {
if (_cnchar._.poly) {
dealResCase(res, low);
// 当启用了 多音词时 需要强制默认小写
@ -112,7 +112,7 @@ export function dealUpLowFirst (
} else if (!has(args, arg.low)) {
dealResCase(res, upFirst);
}
}
};
function dealResCase (
res: Array<Array<string>> | Array<string>,
@ -175,9 +175,9 @@ function getSpell (
// tone=false : 根据有音调的拼音获得无音调的拼音和音调
// tone=true : 返回原拼音
export function removeTone (spell: string, tone: boolean): {
export const removeTone: IRemoveTone = (spell: string, tone: boolean): {
spell: string, tone?: ToneType, index?: number
} {
} => {
if (tone) {
return {spell};
}
@ -192,7 +192,7 @@ export function removeTone (spell: string, tone: boolean): {
}
}
return {spell, tone: 0, index: -1};
}
};
function setTone (spell: string, index: number, tone: ToneType): string {
if (tone === 0) { // 轻声
@ -233,13 +233,13 @@ export function stroke (
}
return strokes;
}
export function sumStroke (strs: Array<number>): number {
export const sumStroke: IFunc<number, Array<number>> = (strs: Array<number>): number => {
let sum: number = 0;
strs.forEach(function (c) {
sum += c;
});
return sum;
}
};
// spell 所有参数 ["array", "low", "up", "first", "poly", "tone", "simple"]
// simple 禁用繁体字
@ -247,11 +247,11 @@ export function sumStroke (strs: Array<number>): number {
// stroke 所有参数 ["letter", "shape", "count", "name", "detail", "array", "order", "simple"]
//
let _hasCheck: boolean = false;
export function checkArgs (
export const checkArgs: ICheckArgs = (
type: TypeProp,
args: Array<AllArgs>,
jumpNext?: boolean
): void {
): void => {
if (!_cnchar.check) {
return;
}
@ -337,7 +337,7 @@ export function checkArgs (
warnArgs(useless, '无效', type, args);
warnArgs(ignore, '被忽略', type, args);
warnArgs(redunt, '冗余', type, args);
}
};
function warnArgs (
arr: Array<AllArgs>,
txt: string,
@ -366,11 +366,11 @@ export function shapeSpell (spell: string): string {
// lv2 => {spell:'lü', tone: 2, index: 2, isTrans: true}
// lǘ => {spell:'lü', tone: 2, index: 2, isTrans: false}
// needTone = true: lv2 => {spell:'lǘ', tone: 2, index: 2, isTrans: true}
export function transformTone (
export const transformTone: ITransformTone = (
spell: string,
needTone: boolean = false,
type: 'low' | 'up' = 'low'
): ITransformReturn {
): ITransformReturn => {
if (spell.indexOf('v') !== -1) {
spell = spell.replace('v', 'ü');
}
@ -402,4 +402,4 @@ export function transformTone (
spell = spell.toUpperCase();
}
return {spell, tone, index, isTrans};
}
};

View File

@ -1,10 +1,10 @@
import {CnCharInterface, ToneType} from '.';
import {ICnChar, ToneType} from '.';
export declare interface Json<T = any> {
[prop: string]: T
}
export declare interface spellInfoReturnInterface {
export declare interface ISpellInfoReturn {
spell: string;
initial: string;
final: string;
@ -12,8 +12,8 @@ export declare interface spellInfoReturnInterface {
index: number;
}
export declare interface SpellInfoInterface extends Function {
(spell: string): spellInfoReturnInterface;
export declare interface ISpellInfo extends Function {
(spell: string): ISpellInfoReturn;
tones: Array<string>,
initials: Array<string>
}
@ -26,13 +26,20 @@ export declare interface ITransformReturn {
}
export declare interface IPlugin {
(cnchar: CnCharInterface): void;
init?(cnchar: CnCharInterface): void;
(cnchar: ICnChar): void;
init?(cnchar: ICnChar): void;
}
export declare interface ConvertInterface {
simpleToSpark(sentence: string): string;
simpleToTrad(sentence: string): string;
sparkToSimple(sentence: string): string;
sparkToTrad(sentence: string): string;
tradToSimple(sentence: string): string;
tradToSpark(sentence: string): string;
}
declare global {
interface Window {
cnchar: CnCharInterface,
CnChar: CnCharInterface,
cnchar: ICnChar,
CnChar: ICnChar,
}
}

View File

@ -1,13 +1,4 @@
import './extend';
import {has, _throw, _warn, isCnChar, mapJson} from '../util';
import {
arg, removeTone, tones, checkArgs, transformTone,
sumStroke, dealUpLowFirst
} from '../tool';
import {ConvertInterface} from '../../../plugin/trad/index';
import {Json} from './common';
import {setIntoJson} from '../config';
import {ICncharTool} from './tool';
export declare type SpellArg = 'array' | 'low' | 'up' | 'first' | 'poly' | 'tone' | 'simple' | 'trad';
export declare type StrokeArg = 'letter' | 'shape' | 'count' | 'name' | 'detail' | 'array' | 'order' | 'simple' | 'trad';
@ -26,7 +17,7 @@ export declare type ToneType = 0 | 1 | 2 | 3 | 4;
export declare type CompareType = 'more' | 'less' | 'even' | 'error';
export declare interface spellInfoReturnInterface {
export declare interface ISpellInfoReturn {
spell: string;
initial: string;
final: string;
@ -34,43 +25,22 @@ export declare interface spellInfoReturnInterface {
index: number;
}
export declare interface CncharToolInterface {
arg: typeof arg,
has: typeof has,
_throw: typeof _throw,
tones: typeof tones,
setIntoJson: typeof setIntoJson,
_warn: typeof _warn,
dealUpLowFirst: typeof dealUpLowFirst,
removeTone: typeof removeTone,
sumStroke: typeof sumStroke,
isCnChar: typeof isCnChar,
checkArgs: typeof checkArgs,
transformTone: typeof transformTone,
convert?: ConvertInterface, //
dict: {
getTradOrders?(): Json<string>;
getTradCount?(): Json<string>;
},
mapJson: typeof mapJson,
poly?: boolean,
}
export declare type TypeProp = 'spell' | 'stroke' | 'spellToWord' | 'strokeToWord' | 'orderToWord' | 'idiom' | 'xhy' | 'radical';
export declare type TypeValueObject = {
[prop in AllArgs]?: AllArgs;
};
export declare interface CnCharInterface {
[x: string]: any;
spell(sentence: string, ...args: Array<SpellArg>): string | Array<any>;
stroke(sentence: string, ...args: Array<StrokeArg>): number | Array<any>;
declare interface ISpell {(sentence: string, ...args: Array<SpellArg>): string | Array<any>;}
declare interface IStroke {(sentence: string, ...args: Array<StrokeArg>): number | Array<any>;}
export declare interface ICnChar {
spell: ISpell;
stroke: IStroke;
use(...plugins: Array<Function>): void;
spellToWord(spell: string, ...args: Array<SpellToWordArg>): string | Array<string>;
strokeToWord(stroke: number, ...args: Array<StrokeToWordArg>): string | Array<string>;
spellInfo: {
(spell: string): spellInfoReturnInterface;
(spell: string): ISpellInfoReturn;
tones: Array<string>;
initials: Array<string>;
};
@ -101,9 +71,13 @@ export declare interface CnCharInterface {
setStrokeCount(json: {[key: string]: number}): void;
shapeSpell(spell: string): string;
_: CncharToolInterface;
_: ICncharTool;
_origin: {
spell: ISpell;
stroke: IStroke;
};
}
declare const cnchar: CnCharInterface;
declare const cnchar: ICnChar;
export default cnchar;

77
src/main/ts/types/tool.d.ts vendored Normal file
View File

@ -0,0 +1,77 @@
import {Json, ConvertInterface, ITransformReturn} from './common';
import {AllArgs, SpellArg, ToneType, TypeProp} from '.';
export declare interface ISetIntoJson {
(option: {
target: Json<string>,
key: string | Json<string>,
value?: string,
isSpell: boolean
}): void
}
export declare type TSpellArg = {
[prop in SpellArg]: SpellArg
}
export declare interface IHas {(args: Array<AllArgs>, name: AllArgs): boolean;}
export declare interface IFunc<T = void, A = string> {(arg: A): T;}
export declare interface IDealUpLowFirst {
(
res: Array<Array<string>> | Array<string>,
args: Array<SpellArg>
): void;
}
export declare interface IRemoveTone {
(spell: string, tone: boolean): {spell: string, tone?: ToneType, index?: number};
}
export declare interface IMapJson {
(
key: Json | string,
value: undefined | any,
cb: (key: string, value: any) => void
): void;
}
export declare interface ICheckArgs {
(
type: TypeProp,
args: Array<AllArgs>,
jumpNext?: boolean
): void;
}
export declare interface ITransformTone {
(
spell: string,
needTone?: boolean,
type?: 'low' | 'up'
): ITransformReturn;
}
export declare interface ICncharTool {
arg: TSpellArg;
has: IHas;
_throw: IFunc<never>;
tones: string;
setIntoJson: ISetIntoJson;
_warn: IFunc;
dealUpLowFirst: IDealUpLowFirst;
removeTone: IRemoveTone;
sumStroke: IFunc<number, Array<number>>;
isCnChar: IFunc<boolean>;
checkArgs: ICheckArgs;
transformTone: ITransformTone;
convert?: ConvertInterface;
dict: {
getTradOrders?(): Json<string>;
getTradCount?(): Json<string>;
};
mapJson: IMapJson;
poly?: boolean;
}

View File

@ -1,12 +1,13 @@
import infoDict from './dict/info-dict.json';
import {AllArgs} from './types';
import {Json} from './types/common';
import {IHas, IFunc, IMapJson} from './types/tool';
export function mapJson (
export const mapJson: IMapJson = (
key: Json | string,
value: undefined | any,
cb: (key: string, value: any) => void
): void {
): void => {
if (typeof key === 'object') {
for (const k in key) {
cb(k, key[k]);
@ -14,16 +15,16 @@ export function mapJson (
return;
}
cb(key, value);
}
};
export function isCnChar (word: string): boolean {
export const isCnChar: IFunc<boolean> = (word: string): boolean => {
const unicode: number = word.charCodeAt(0);
return unicode >= 19968 && unicode <= 40869;
}
};
export function has (args: Array<AllArgs>, name: AllArgs): boolean {
export const has: IHas = (args: Array<AllArgs>, name: AllArgs): boolean => {
return args.indexOf(name) !== -1;
}
};
export function isPolyWord (word: string): boolean {
if (word === '') {
@ -38,11 +39,12 @@ export function isPolyWord (word: string): boolean {
return infoDict.polyWord.indexOf(word) !== -1;
}
export function _throw (err: string): never {
export const _throw: IFunc<never> = (err: string): never => {
throw new Error('CnChar Error:' + err);
}
export function _warn (err: string): void {
console.warn('CnChar Warning:' + err);
}
};
export const _warn: IFunc<void> = (info: string): void => {
console.warn('CnChar Warning:' + info);
};

View File

@ -67,6 +67,7 @@ function merge (type, args) {
const json = {};
for (const key in args) {
const arg = args[key];
debugger;
for (const k in arg) {
if (!isUd(arg[k])) {
json[k] = arg[k];

View File

@ -32,15 +32,15 @@ declare interface DrawOption {
clear?: boolean; // 绘制前是否清空容器 默认为true
style?: { // 样式类
backgroundColor?: string, // 默认为#fff
showOutline?: boolean;//: true,
showCharacter?: boolean;//: true,
currentColor?: string;//: '#b44', // 仅在stroke模式下有效
length?: number;//: 60,
padding?: number;//: 5, // 数值, 默认 20。 画布的汉字和边缘之间的填充
outlineColor?: string;//: '#ddd', // 十六进制字符, 默认 '#DDD'。
strokeColor?: string;//: '#555', // 十六进制字符, 默认 '#555'。绘制每个笔划的颜色。
radicalColor?: string;//: null, // 十六进制字符, 默认 null。 如果存在偏旁部首数据,则在笔划中绘制偏旁部首的颜色。 如果没有设置,激光将绘制与其他笔划相同的颜色。
strokeFadeDuration?: number; //400
showOutline?: boolean;// : true,
showCharacter?: boolean;// : true,
currentColor?: string;// : '#b44', // 仅在stroke模式下有效
length?: number;// : 60,
padding?: number;// : 5, // 数值, 默认 20。 画布的汉字和边缘之间的填充
outlineColor?: string;// : '#ddd', // 十六进制字符, 默认 '#DDD'。
strokeColor?: string;// : '#555', // 十六进制字符, 默认 '#555'。绘制每个笔划的颜色。
radicalColor?: string;// : null, // 十六进制字符, 默认 null。 如果存在偏旁部首数据,则在笔划中绘制偏旁部首的颜色。 如果没有设置,激光将绘制与其他笔划相同的颜色。
strokeFadeDuration?: number; // 400
},
line?: { // 背景线条类
lineStraight?: boolean;// : true,

View File

@ -1,18 +1,20 @@
import {IDrawOption, IDrawClassOption, TDrawType, TTestStatusType} from './types/common';
import {Json} from 'cnchar/types/common';
export const TYPE = {
export const TYPE: Json<TDrawType> = {
NORMAL: 'normal',
ANIMATION: 'animation',
STROKE: 'stroke',
TEST: 'test'
};
export const TEST_STATUS = {
export const TEST_STATUS: Json<TTestStatusType> = {
MISTAKE: 'mistake',
CORRECT: 'correct',
COMPLETE: 'complete'
};
const DrawOption = {
export const DrawOption: IDrawOption = {
showOutline: true,
showCharacter: true,
currentColor: '#b44',
@ -64,9 +66,8 @@ function isUd (v: any): boolean {
return typeof v === 'undefined';
}
// 使用npm link配置本地开发目录
export function merge (type, args) {
const json = {};
export function merge (type: TDrawType, args: IDrawClassOption): IDrawOption {
const json: IDrawOption = {};
for (const key in args) {
const arg = args[key];
for (const k in arg) {
@ -83,7 +84,7 @@ export function merge (type, args) {
return json;
}
function checkTypeDefault (type, args, json) {
function checkTypeDefault (type: IDrawOption, args: IDrawClassOption, json: IDrawOption): void {
if (type === TYPE.ANIMATION) {
if (!args.animation || isUd(args.animation.showCharacter)) {
json.showCharacter = false;
@ -93,7 +94,7 @@ function checkTypeDefault (type, args, json) {
}
}
function check (json, attrs) {
function check (json: IDrawOption, attrs?: Array<string>): IDrawOption {
attrs = attrs || Object.keys(DrawOption);
attrs.forEach(attr => {
if (isUd(json[attr])) {

3
src/plugin/draw/ts/hanzi-writer.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
import HanziWriter from './types/hanzi-writer';
export default HanziWriter;

View File

@ -1,100 +1,8 @@
declare type DrawType = 'normal' | 'animation' | 'stroke' | 'test';
declare type TestStatusType = 'mistake' | 'correct' | 'complete';
declare class Writer {
constructor();
option: object;
el: HTMLElement;
type: DrawType;
text: Array<string>;
writer: Array<object>;
animateStart():void;
}
declare interface TestStatus {
index: number,
status: TestStatusType,
data: {
character: string;
totalMistakes: number;// 到目前为止在测验期间犯的总错误。
strokeNum?: number;// 当前笔画数。
mistakesOnStroke?: number;// 到目前为止用户绘制此笔划所犯的错误数。
strokesRemaining?: number;// 测验完成前剩余的笔画数。
drawnPath?: {
pathString: string;
points: Array<{x:number;y:number}>
};// 对象包含用户绘制的 pathString ,用于评分的分数。
}
}
declare interface DrawOption {
el?: string | HTMLElement; // 绘制的容器支持选择器或dom若是不填会在body后append一个dom作为容器
type?: DrawType; // 绘制模式默认为normal
clear?: boolean; // 绘制前是否清空容器 默认为true
style?: { // 样式类
backgroundColor?: string, // 默认为#fff
showOutline?: boolean;// : true,
showCharacter?: boolean;// : true,
currentColor?: string;// : '#b44', // 仅在stroke模式下有效
length?: number;// : 60,
padding?: number;// : 5, // 数值, 默认 20。 画布的汉字和边缘之间的填充
outlineColor?: string;// : '#ddd', // 十六进制字符, 默认 '#DDD'。
strokeColor?: string;// : '#555', // 十六进制字符, 默认 '#555'。绘制每个笔划的颜色。
radicalColor?: string;// : null, // 十六进制字符, 默认 null。 如果存在偏旁部首数据,则在笔划中绘制偏旁部首的颜色。 如果没有设置,激光将绘制与其他笔划相同的颜色。
strokeFadeDuration?: number; // 400
},
line?: { // 背景线条类
lineStraight?: boolean;// : true,
lineCross?: boolean;// : true,
lineWidth?: number;// : 1,
lineColor?: string;// : '#ddd',
lineDash?: boolean;// : true,
border?: boolean;// : true,
borderWidth?: number;// : 1,
borderColor?: string;// : '#ccc',
borderDash?: boolean;// : false,
},
animation?: {
strokeAnimationSpeed?: number;// : 1, // 数值, 默认 1。 绘制每个笔划的速度必须大于0。增加此数字可以更快地绘制笔划减少绘制笔划的速度更慢。
delayBetweenStrokes?: number;// : 1000, // 数值, 默认 1000。 动画进行中每个笔画之间的间隔时间(以毫秒为单位)。
delayBetweenLoops?: number;// : 200, // 数值, 默认 2000。 循环动画时每个动画循环之间的时间(以毫秒为单位)。
autoAnimate?: boolean;// : true,
animateComplete?: Function;// : () => {},
stepByStep?: boolean;// : true,
loopAnimate?: boolean;// : false,
},
test?: {
strokeHighlightSpeed?: number;// : 20, // 数值, 默认 20。 在测验中给出提示时突出显示每个笔划的速度必须大于0。增加此数字以突出显示更快减少以突出显示更慢。
highlightColor?: number;// : '#aaf', // 十六进制字符, 默认 '#AAF'。 用于在测验中突出显示的颜色。
drawingColor?: number;// : '#333', // 十六进制字符, 默认 '#333'。 测验期间绘制的线条颜色。
drawingWidth?: number;// : 4, // 数值, 默认 4。 进行测验时绘制的线条宽度。
showHintAfterMisses?: number;// : 3, // 整数, 默认 3 中风高亮提示之前的未命中数被给予用户。 设置为 false 以禁用。 创建测验时也可以设置此项。
highlightOnComplete?: number;// : true, // 布尔值, 默认 true。 控制当用户完成绘制整个字符时,测验是否会短暂突出显示字符。 创建测验时也可以设置此项。
highlightCompleteColor?: number;// : null, // 十六进制字符, 默认 null。 在测验中突出显示字符时使用的颜色。 如果未设置则将使用highlightColor。 仅当highlightOnComplete为true时才相关。
onTestStatus?(args: TestStatus):void;// : null, // ({index, status, data})=>{}
}
}
export declare interface Draw {
(text:string, option?:DrawOption):Writer;
TYPE: {
ANIMATION: 'animation',
NORMAL: 'normal',
STROKE: 'stroke',
TEST: 'test'
},
TEST_STATUS: {
MISTAKE: 'mistake',
CORRECT: 'correct',
COMPLETE: 'complete'
}
}
declare const draw: Draw;
import {IDraw} from './types/common';
declare const draw: IDraw;
declare module 'cnchar' {
interface CnCharStatic {
draw: Draw;
draw: IDraw;
}
}
export default draw;

View File

@ -1,9 +1,11 @@
// powerd by hanzi-writer v2.2.2
require('./promise-polyfill');
const draw = require('./writer');
import {ICnChar} from 'cnchar/types';
import './promise-polyfill';
import {IDraw} from './types/common';
import draw from './writer';
function main (cnchar) {
export default function main (cnchar: ICnChar & {draw?: IDraw}): void {
if (cnchar.plugins.indexOf('draw') !== -1) {
return;
}
@ -11,7 +13,7 @@ function main (cnchar) {
cnchar.draw = draw;
}
function init (cnchar) {
function init (cnchar?: ICnChar): void {
if (typeof window === 'object') {
window.CncharDraw = draw;
}
@ -24,6 +26,4 @@ function init (cnchar) {
draw.init = init;
init();
module.exports = draw;
init();

View File

@ -1,6 +1,6 @@
/* eslint-disable no-unused-vars */
import {IBuildLineStr} from './types/common';
function buildLinesStr ({
export function buildLinesStr ({
width,
lineStraight,
lineCross,
@ -11,7 +11,10 @@ function buildLinesStr ({
borderWidth,
borderColor,
borderDash,
}) {
}: IBuildLineStr): {
lineHTML: string,
border: string
} {
let str = '';
let attr = '';
if (lineDash) {
@ -34,6 +37,4 @@ function buildLinesStr ({
_border = `${borderWidth}px ${borderDash ? 'dashed' : 'solid'} ${borderColor}`;
}
return {lineHTML: str, border: _border};
}
module.exports = {buildLinesStr};
}

View File

@ -1,8 +1,10 @@
const HanziWriter = require('./hanzi-writer');
import HanziWriter from './hanzi-writer';
import {Writer} from './writer';
import {ICloneSvg, IDrawOption} from './types/common';
function stroke (writer, cloneSvg) {
export function stroke (writer: Writer, cloneSvg: ICloneSvg): void {
writer.text.forEach((s) => {
const target = document.createElement('div');
const target: HTMLElement = document.createElement('div');
writer.el.appendChild(target);
HanziWriter.loadCharacterData(s).then(function (charData) {
for (var i = 0; i < charData.strokes.length; i++) {
@ -21,13 +23,29 @@ function stroke (writer, cloneSvg) {
}
function renderFanningStrokes ({option, target, strokes, radStrokes, cloneSvg, current, width}) {
function renderFanningStrokes ({
option,
target,
strokes,
radStrokes,
cloneSvg,
current,
width
}: {
option: IDrawOption;
target: HTMLElement,
strokes: Array<string>;
radStrokes: Array<number>;
cloneSvg: ICloneSvg,
current: number;
width: number;
}): void {
const radicalColor = (radStrokes.length > 0 && option.radicalColor) ? option.radicalColor : null;
var svg = cloneSvg(option);
const svg = cloneSvg(option);
target.appendChild(svg);
var group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
const group: SVGGElement = document.createElementNS('http://www.w3.org/2000/svg', 'g');
var transformData = HanziWriter.getScalingTransform(width, width, option.padding);
const transformData = HanziWriter.getScalingTransform(width, width, option.padding);
group.setAttributeNS(null, 'transform', transformData.transform);
svg.appendChild(group);
for (let i = 0; i <= current; i++) {
@ -46,12 +64,10 @@ function renderFanningStrokes ({option, target, strokes, radStrokes, cloneSvg, c
}
}
function renderPath (strokePath, group, color) {
var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
function renderPath (strokePath: string, group: SVGGElement, color: string): void {
const path: SVGPathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
path.setAttributeNS(null, 'd', strokePath);
// style the character paths
path.style.fill = color;
group.appendChild(path);
}
module.exports = {stroke};
}

118
src/plugin/draw/ts/types/common.d.ts vendored Normal file
View File

@ -0,0 +1,118 @@
import {IWriter} from './index';
import {Json} from 'cnchar/types/common';
import {ICnChar} from 'cnchar/types';
export declare type TDrawType = 'normal' | 'animation' | 'stroke' | 'test';
export declare type TTestStatusType = 'mistake' | 'correct' | 'complete';
export declare interface ITestStatusData {
character: string;
totalMistakes: number;// 到目前为止在测验期间犯的总错误。
strokeNum?: number;// 当前笔画数。
mistakesOnStroke?: number;// 到目前为止用户绘制此笔划所犯的错误数。
strokesRemaining?: number;// 测验完成前剩余的笔画数。
drawnPath?: {
pathString: string;
points: Array<{x:number;y:number}>;
};// 对象包含用户绘制的 pathString ,用于评分的分数。
}
declare interface ITestStatus {
index: number;
status: TTestStatusType;
data: ITestStatusData;
}
export declare interface IDrawStyleOption { // 样式类
backgroundColor?: string, // 默认为#fff
showOutline?: boolean;// : true,
showCharacter?: boolean;// : true,
currentColor?: string;// : '#b44', // 仅在stroke模式下有效
length?: number;// : 60,
padding?: number;// : 5, // 数值, 默认 20。 画布的汉字和边缘之间的填充
outlineColor?: string;// : '#ddd', // 十六进制字符, 默认 '#DDD'。
strokeColor?: string;// : '#555', // 十六进制字符, 默认 '#555'。绘制每个笔划的颜色。
radicalColor?: string;// : null, // 十六进制字符, 默认 null。 如果存在偏旁部首数据,则在笔划中绘制偏旁部首的颜色。 如果没有设置,激光将绘制与其他笔划相同的颜色。
strokeFadeDuration?: number; // 400
}
export declare interface IDrawLineOption { // 背景线条类
lineStraight?: boolean;// : true,
lineCross?: boolean;// : true,
lineWidth?: number;// : 1,
lineColor?: string;// : '#ddd',
lineDash?: boolean;// : true,
border?: boolean;// : true,
borderWidth?: number;// : 1,
borderColor?: string;// : '#ccc',
borderDash?: boolean;// : false,
}
export declare interface IDrawAnimationOption {
strokeAnimationSpeed?: number;// : 1, // 数值, 默认 1。 绘制每个笔划的速度必须大于0。增加此数字可以更快地绘制笔划减少绘制笔划的速度更慢。
delayBetweenStrokes?: number;// : 1000, // 数值, 默认 1000。 动画进行中每个笔画之间的间隔时间(以毫秒为单位)。
delayBetweenLoops?: number;// : 200, // 数值, 默认 2000。 循环动画时每个动画循环之间的时间(以毫秒为单位)。
autoAnimate?: boolean;// : true,
animateComplete?: Function;// : () => {},
stepByStep?: boolean;// : true,
loopAnimate?: boolean;// : false,
showCharacter?: boolean;// : true,
}
export declare interface IDrawTestOption {
strokeHighlightSpeed?: number;// : 20, // 数值, 默认 20。 在测验中给出提示时突出显示每个笔划的速度必须大于0。增加此数字以突出显示更快减少以突出显示更慢。
highlightColor?: string;// : '#aaf', // 十六进制字符, 默认 '#AAF'。 用于在测验中突出显示的颜色。
drawingColor?: string;// : '#333', // 十六进制字符, 默认 '#333'。 测验期间绘制的线条颜色。
drawingWidth?: number;// : 4, // 数值, 默认 4。 进行测验时绘制的线条宽度。
showHintAfterMisses?: number;// : 3, // 整数, 默认 3 中风高亮提示之前的未命中数被给予用户。 设置为 false 以禁用。 创建测验时也可以设置此项。
highlightOnComplete?: boolean;// : true, // 布尔值, 默认 true。 控制当用户完成绘制整个字符时,测验是否会短暂突出显示字符。 创建测验时也可以设置此项。
highlightCompleteColor?: number;// : null, // 十六进制字符, 默认 null。 在测验中突出显示字符时使用的颜色。 如果未设置则将使用highlightColor。 仅当highlightOnComplete为true时才相关。
onTestStatus?(args: ITestStatus):void;// : null, // ({index, status, data})=>{}
}
export declare interface IDrawClassOption {
el?: string | HTMLElement; // 绘制的容器支持选择器或dom若是不填会在body后append一个dom作为容器
type?: TDrawType; // 绘制模式默认为normal
clear?: boolean; // 绘制前是否清空容器 默认为true
style?: IDrawStyleOption;
line?: IDrawLineOption;
animation?: IDrawAnimationOption;
test?: IDrawTestOption;
}
export declare interface IDrawStrokeOption {
}
export declare interface IDrawOption extends IDrawStyleOption, IDrawLineOption, IDrawAnimationOption, IDrawTestOption {
clear?: boolean;
width?: number;
height?: number;
text?: string;
}
export declare interface IBuildLineStr extends IDrawLineOption {
width: number;
}
export declare interface ICloneSvg{
(option: IDrawOption): Node;
}
export declare interface IDraw {
(text: string, options: IDrawOption): IWriter;
TYPE: Json<TDrawType>;
TEST_STATUS: Json<TTestStatusType>;
init?(cnchar?: ICnChar): void;
}
declare global {
interface Window {
CncharDraw: IDraw,
}
}
declare module 'cnchar' {
interface ICnChar {
draw: IDraw;
}
}

View File

@ -0,0 +1,24 @@
import {IDrawOption, ITestStatusData} from './common';
declare type TDrawType = 'normal' | 'animation' | 'stroke' | 'test';
declare interface ICharData {
strokes: Array<string>;
radStrokes: Array<number>;
medians: Array<Array<Array<number>>>;
}
export default class HanziWriter {
quiz(options: {
onMistake (strokeData: ITestStatusData): void;
onCorrectStroke (strokeData: ITestStatusData): void;
onComplete (strokeData: ITestStatusData): void;
}): void;
hideCharacter(): void;
animateCharacter(option: {
onComplete(): void;
}): void;
static create(node: Node, text: string, option: IDrawOption): HanziWriter;
static loadCharacterData(str: string): Promise<ICharData>;
static getScalingTransform(width: number, height: number, padding: number);
}

35
src/plugin/draw/ts/types/index.d.ts vendored Normal file
View File

@ -0,0 +1,35 @@
import {
IDrawAnimationOption,
IDrawLineOption,
IDrawStyleOption,
IDrawTestOption,
IDrawStrokeOption,
IDrawOption,
TDrawType,
} from './common';
import HanziWriter from './hanzi-writer';
export declare interface IWriterOption {
el?: string | HTMLElement;
text?: string;
clear?: boolean;
type?: TDrawType;
style?: IDrawStyleOption,
line?: IDrawLineOption,
animation?: IDrawAnimationOption,
stroke?: IDrawStrokeOption,
test?: IDrawTestOption,
}
export declare interface IWriter {
option: IDrawOption;
el: HTMLElement;
type: TDrawType;
text: Array<string>;
writers: Array<HanziWriter>;
init (): void;
animate (complete: Function): void;
animateStart(): void;
loopAnimate(): void;
_animateSingle (index: number, complete: Function): void;
_animateStep (index: number, complete: Function): void;
}

View File

@ -1,10 +1,9 @@
function isCnChar (word) {
export function isCnChar (word: string): boolean {
const unicode = word.charCodeAt(0);
return unicode >= 19968 && unicode <= 40869;
}
function pickCnChar (text) {
export function pickCnChar (text: string): string {
let v = '';
for (let i = 0; i < text.length; i++) {
if (isCnChar(text[i])) {
@ -12,8 +11,4 @@ function pickCnChar (text) {
}
}
return v;
}
module.exports = {
isCnChar, pickCnChar
};
}

View File

@ -1,8 +1,21 @@
const HanziWriter = require('./hanzi-writer');
const {TYPE, merge, TEST_STATUS} = require('./default-option');
const {pickCnChar} = require('./util');
const {buildLinesStr} = require('./line');
const {stroke} = require('./stroke');
import HanziWriter from './hanzi-writer';
import {TYPE, merge, TEST_STATUS} from './default-option';
import {pickCnChar} from './util';
import {buildLinesStr} from './line';
import {stroke} from './stroke';
import {IWriter, IWriterOption} from './types/index';
import {
TDrawType,
IDrawOption,
IDrawStyleOption,
IDrawAnimationOption,
IDrawLineOption,
IDrawTestOption,
IDrawStrokeOption,
IBuildLineStr,
ICloneSvg,
IDraw
} from './types/common';
const document = (typeof window === 'object') ? (window.document || null) : null;
@ -13,7 +26,13 @@ const svg = (() => {
return document.createElementNS('http://www.w3.org/2000/svg', 'svg');
})();
class Writer {
export class Writer implements IWriter {
option: IDrawOption;
el: HTMLElement;
type: TDrawType;
text: Array<string>;
writers: Array<HanziWriter>;
animateStart: () => void;
constructor ({
el = 'cnchar-draw',
text = '',
@ -24,18 +43,28 @@ class Writer {
animation = {},
stroke = {},
test = {},
}) {
}: IWriterOption) {
this.type = type;
this.writers = [];
this.text = text.split('');
const opts = {style, line};
const opts: {
style: IDrawStyleOption;
line: IDrawLineOption;
animation?: IDrawAnimationOption;
test?: IDrawTestOption;
stroke?: IDrawStrokeOption;
} = {style, line};
switch (type) {
case TYPE.ANIMATION: opts.animation = animation; break;
case TYPE.STROKE: opts.stroke = stroke; break;
case TYPE.TEST: opts.test = test; break;
}
this.option = merge(type, opts);
this.el = typeof el === 'string' ? document.querySelector(el) : el;
if (typeof el === 'string') {
this.el = document.querySelector(el) || document.body;
} else {
this.el = el;
}
if (this.el && clear) {
this.el.innerHTML = '';
}
@ -45,12 +74,12 @@ class Writer {
}
this.init();
}
init () {
const {lineHTML, border} = buildLinesStr(this.option);
const cloneSvg = (option) => {
const node = svg.cloneNode();
node.setAttribute('width', this.option.width);
node.setAttribute('height', this.option.height);
init (): void {
const {lineHTML, border} = buildLinesStr(this.option as IBuildLineStr);
const cloneSvg: ICloneSvg = (option: IDrawOption) => {
const node = svg.cloneNode() as HTMLElement;
node.setAttribute('width', this.option.width.toString());
node.setAttribute('height', this.option.height.toString());
if (border) {
node.style.border = border;
}
@ -93,10 +122,10 @@ class Writer {
this.el.addEventListener('click', start, false);
}
} else if (this.type === TYPE.TEST) {
let opt = () => {return {};};
let opt: Function;
const fn = this.option.onTestStatus;
if (typeof fn === 'function') {
opt = (index) => {
opt = (index: number) => {
return {
onMistake (strokeData) {
fn({index, status: TEST_STATUS.MISTAKE, data: strokeData});
@ -109,6 +138,8 @@ class Writer {
}
};
};
} else {
opt = () => {return {};};
}
this.writers.forEach((writer, index) => {
writer.quiz(opt(index));
@ -116,7 +147,7 @@ class Writer {
}
}
}
animate (complete) {
animate (complete: Function) {
const opt = this.option;
if (opt.stepByStep) { // 汉字之间连续绘制
if (opt.showCharacter === false) {
@ -147,18 +178,18 @@ class Writer {
});
}
// animate单个汉字
_animateSingle (i, complete) {
if (i >= this.writers.length) {
_animateSingle (index: number, complete: Function): void {
if (index >= this.writers.length) {
complete(true);
return;
}
this.writers[i].animateCharacter({
this.writers[index].animateCharacter({
onComplete: () => {
complete(false);
}
});
}
_animateStep (index, complete) {
_animateStep (index: number, complete: Function): void {
this._animateSingle(index, (end) => {
if (!end) {
setTimeout(() => {
@ -171,8 +202,7 @@ class Writer {
}
}
// eslint-disable-next-line no-unused-vars
function draw (text = '', options = {}) {
const draw: IDraw = (text: string = '', options: IDrawOption = {}): IWriter => {
if (typeof window === 'undefined') {
console.error('Draw 方法仅支持在浏览器环境下使用');
return null;
@ -184,7 +214,9 @@ function draw (text = '', options = {}) {
options.text = text;
return new Writer(options);
};
draw.TYPE = TYPE;
draw.TEST_STATUS = TEST_STATUS;
draw.init = null;
module.exports = draw;
export default draw;