├── .babelrc
├── .fecsignore
├── .fecsrc
├── .gitignore
├── LICENSE
├── README.md
├── README.zh-CN.md
├── build.sh
├── build
├── i18n.en-us.js
├── i18n.zh-cn.js
├── index-loader.js
└── tpl-loader.js
├── config
├── webpack.demo.js
├── webpack.dev.js
└── webpack.prod.js
├── css
├── editor.less
├── img
│ ├── logo@1x.png
│ └── logo@2x.png
├── main.less
├── preview.lesstpl
└── widget
│ ├── bootstrap-overwrite.less
│ ├── common.less
│ ├── def.less
│ ├── dialog.less
│ ├── editor.less
│ ├── glyf-download-dialog.less
│ ├── glyf-editor.less
│ ├── glyf-list.less
│ ├── glyf-spliter.less
│ ├── ico.less
│ ├── import-pic-dialog.less
│ ├── loading.less
│ ├── page.less
│ ├── project.less
│ ├── reset.less
│ └── util.less
├── demo
├── bezierSegmentCross.html
├── bezierSplit.html
├── boundSegmentCross.html
├── canvasFindBreakPoint.html
├── contoursCombine.html
├── css
│ ├── editor.css
│ ├── editor.less
│ ├── editortest.css
│ ├── editortest.less
│ ├── render.less
│ └── reset.less
├── data
│ ├── baiduHealth.json
│ ├── compound-glyf.js
│ ├── contours-1.js
│ ├── contours-10.js
│ ├── contours-11.js
│ ├── contours-12.js
│ ├── contours-2.js
│ ├── contours-3.js
│ ├── contours-4.js
│ ├── contours-5.js
│ ├── contours-6.js
│ ├── contours-7.js
│ ├── contours-8.js
│ ├── contours-9.js
│ ├── contours.js
│ ├── iconfont.json
│ ├── image-contours-circle.js
│ ├── image-contours0.js
│ ├── image-contours1.js
│ ├── image-contours10.js
│ ├── image-contours11.js
│ ├── image-contours12.js
│ ├── image-contours13.js
│ ├── image-contours14.js
│ ├── image-contours15.js
│ ├── image-contours2.js
│ ├── image-contours3.js
│ ├── image-contours4.js
│ ├── image-contours5.js
│ ├── image-contours6.js
│ ├── image-contours7.js
│ ├── image-contours8.js
│ ├── image-contours9.js
│ ├── shape-baidu.js
│ └── shape-bdjk.js
├── datastore.html
├── editor-iframe.html
├── editor.html
├── editortest.html
├── findBreakPoints.html
├── fitContours.html
├── fitCurve.html
├── fitImage.html
├── index.html
├── js
│ ├── bezierSegmentCross.js
│ ├── bezierSplit.js
│ ├── boundSegmentCross.js
│ ├── canvasFindBreakPoint.js
│ ├── contoursCombine.js
│ ├── datastore.js
│ ├── editor-iframe.js
│ ├── editor.js
│ ├── editortest.js
│ ├── findBreakPoints.js
│ ├── fitContours.js
│ ├── fitCurve.js
│ ├── fitImage.js
│ ├── math.js
│ ├── paper-boolean.js
│ ├── procImage.js
│ ├── quadraticBezier.js
│ ├── quadraticBezierCross.js
│ ├── reducePoints.js
│ ├── render.js
│ └── segmentCross.js
├── math.html
├── paper-boolean.html
├── procImage.html
├── quadraticBezierCross.html
├── reducePoints.html
├── render.html
├── segmentCross.html
├── sync
│ ├── example-ascii.html
│ ├── example.html
│ ├── font.php
│ ├── icon.css
│ └── page.css
└── test
│ ├── a.gif
│ ├── add.bmp
│ ├── add.jpg
│ ├── china.svg
│ ├── circle.gif
│ ├── circle.jpg
│ ├── cl.gif
│ ├── cur.jpg
│ ├── ecomfe.png
│ ├── oval.gif
│ ├── qgqc.jpg
│ ├── question.png
│ ├── sjx.jpg
│ ├── tiger.svg
│ └── unicodenames.xlsx
├── dep
├── bootstrap
│ ├── css
│ │ └── bootstrap.min.css
│ └── js
│ │ └── bootstrap.min.js
├── favicon.ico
├── hidpi-canvas.js
├── jqColorPicker.min.js
├── jquery.min.js
├── jszip
│ └── jszip.min.js
├── pako_deflate.min.js
├── pako_inflate.min.js
├── paper-full.js
├── utpl.min.js
└── woff2
│ └── woff2.wasm
├── editor.tpl
├── empty.html
├── font
├── fonteditor.eot
├── fonteditor.svg
├── fonteditor.ttf
└── fonteditor.woff
├── fonteditor-zh.jpg
├── fonteditor.jpg
├── index.tpl
├── package.json
├── php
└── readOnline.php
├── proxy.html
├── src
├── common
│ ├── DataStore.js
│ ├── I18n.js
│ ├── ajaxFile.js
│ ├── getPixelRatio.js
│ ├── lang.js
│ ├── observable.js
│ └── string.js
├── editor
│ ├── Editor.js
│ ├── command
│ │ ├── align.js
│ │ ├── commandSupport.js
│ │ ├── editor.js
│ │ ├── join.js
│ │ ├── referenceline.js
│ │ ├── setSelectedCommand.js
│ │ ├── shape.js
│ │ ├── support.js
│ │ └── transform.js
│ ├── controller
│ │ ├── index.js
│ │ ├── initAxis.js
│ │ ├── initBinder.js
│ │ ├── initFont.js
│ │ ├── initLayer.js
│ │ ├── initRender.js
│ │ └── initSetting.js
│ ├── group
│ │ ├── BoundControl.js
│ │ ├── ShapesGroup.js
│ │ ├── getRotateMatrix.js
│ │ ├── getScaleMatrix.js
│ │ ├── moveTransform.js
│ │ ├── rotateTransform.js
│ │ └── scaleTransform.js
│ ├── i18n
│ │ ├── en-us.js
│ │ ├── i18n.js
│ │ └── zh-cn.js
│ ├── main.js
│ ├── menu
│ │ ├── commandList.js
│ │ ├── editor.js
│ │ ├── point.js
│ │ ├── shape.js
│ │ └── shapes.js
│ ├── mode
│ │ ├── addpath.js
│ │ ├── addshapes.js
│ │ ├── bound.js
│ │ ├── pan.js
│ │ ├── point.js
│ │ ├── range.js
│ │ ├── referenceline.js
│ │ ├── shapes.js
│ │ ├── split.js
│ │ └── support.js
│ ├── options.js
│ ├── shapes
│ │ ├── arrow.js
│ │ ├── circle.js
│ │ ├── drop.js
│ │ ├── du.js
│ │ ├── heart.js
│ │ ├── rect.js
│ │ ├── roundrect.js
│ │ ├── star.js
│ │ ├── support.js
│ │ ├── tel.js
│ │ └── triangle.js
│ ├── util
│ │ ├── cursor.js
│ │ └── getFontHash.js
│ └── widget
│ │ ├── ContextMenu.js
│ │ ├── GraduationMarker.js
│ │ ├── History.js
│ │ ├── Sorption.js
│ │ └── clipboard.js
├── fonteditor
│ ├── config.js
│ ├── controller
│ │ ├── actions.js
│ │ └── default.js
│ ├── data
│ │ └── online-font.js
│ ├── dialog
│ │ ├── colorpicker.js
│ │ ├── font-online.js
│ │ ├── font-url.js
│ │ ├── glyf-download.js
│ │ ├── setting-adjust-glyf.js
│ │ ├── setting-adjust-pos.js
│ │ ├── setting-editor.js
│ │ ├── setting-find-glyf.js
│ │ ├── setting-glyf.js
│ │ ├── setting-ie.js
│ │ ├── setting-import-pic.js
│ │ ├── setting-metrics.js
│ │ ├── setting-name.js
│ │ ├── setting-sync.js
│ │ ├── setting-unicode.js
│ │ ├── setting.js
│ │ └── support.js
│ ├── editor.js
│ ├── i18n
│ │ ├── en-us
│ │ │ ├── dialog.js
│ │ │ ├── editor.js
│ │ │ └── message.js
│ │ ├── i18n.js
│ │ └── zh-cn
│ │ │ ├── dialog.js
│ │ │ ├── editor.js
│ │ │ └── message.js
│ ├── index.js
│ ├── menu
│ │ ├── editor.js
│ │ └── viewer.js
│ ├── setting
│ │ ├── editor.js
│ │ ├── ie.js
│ │ └── support.js
│ ├── template
│ │ ├── dialog
│ │ │ ├── glyf-download.tpl
│ │ │ ├── setting-adjust-glyf.tpl
│ │ │ ├── setting-adjust-pos.tpl
│ │ │ ├── setting-editor.tpl
│ │ │ ├── setting-glyf.tpl
│ │ │ ├── setting-ie.tpl
│ │ │ ├── setting-import-pic.tpl
│ │ │ ├── setting-metrics.tpl
│ │ │ ├── setting-name.tpl
│ │ │ └── setting-sync.tpl
│ │ ├── export-render.js
│ │ ├── export
│ │ │ ├── icon-css.tpl
│ │ │ ├── icon-example.tpl
│ │ │ ├── preview-ttf.tpl
│ │ │ └── symbol-example.tpl
│ │ └── preview-render.js
│ └── widget
│ │ ├── DragSelector.js
│ │ ├── GLYFEditor.js
│ │ ├── Pager.js
│ │ ├── ProjectViewer.js
│ │ ├── Spliter.js
│ │ ├── SyncForm.js
│ │ ├── TTFManager.js
│ │ ├── Toolbar.js
│ │ ├── exporter.js
│ │ ├── glyfviewer
│ │ ├── GLYFViewer.js
│ │ ├── binder.js
│ │ └── render.js
│ │ ├── loader.js
│ │ ├── loading.js
│ │ ├── previewer.js
│ │ ├── program.js
│ │ ├── project.js
│ │ ├── settingmanager.js
│ │ ├── sync-status.js
│ │ ├── sync.js
│ │ └── util
│ │ ├── download.js
│ │ ├── glyf2svgfile.js
│ │ └── resolvettf.js
├── graphics
│ ├── boundAdjust.js
│ ├── computeBoundingBox.js
│ ├── image
│ │ ├── ContourPointsProcessor.js
│ │ ├── ImageProcessor.js
│ │ ├── contour
│ │ │ ├── douglasPeuckerReducePoints.js
│ │ │ ├── findBreakPoints.js
│ │ │ ├── findContours.js
│ │ │ ├── fitBezier.js
│ │ │ ├── fitContour.js
│ │ │ ├── fitCurve.js
│ │ │ ├── fitOval.js
│ │ │ ├── reducePoints.js
│ │ │ └── smooth.js
│ │ ├── filter
│ │ │ ├── binarize.js
│ │ │ ├── blur.js
│ │ │ ├── brightness.js
│ │ │ ├── close.js
│ │ │ ├── dilate.js
│ │ │ ├── erode.js
│ │ │ ├── gaussBlur.js
│ │ │ ├── gray.js
│ │ │ ├── open.js
│ │ │ ├── reverse.js
│ │ │ └── sharp.js
│ │ └── util
│ │ │ ├── cloneContours.js
│ │ │ ├── cloneImage.js
│ │ │ ├── de.js
│ │ │ ├── filteringImage.js
│ │ │ ├── getHistogram.js
│ │ │ ├── getThreshold.js
│ │ │ └── threshold.js
│ ├── isBezierCross.js
│ ├── isBezierLineCross.js
│ ├── isBezierRayCross.js
│ ├── isBezierSegmentCross.js
│ ├── isBoundingBoxCross.js
│ ├── isBoundingBoxSegmentCross.js
│ ├── isInsidePath.js
│ ├── isInsidePolygon.js
│ ├── isOnPath.js
│ ├── isPathCross.js
│ ├── isSegmentCross.js
│ ├── isSegmentRayCross.js
│ ├── join
│ │ ├── getJoint.js
│ │ └── getPathJoint.js
│ ├── matrix.js
│ ├── path
│ │ └── circle.js
│ ├── pathAdjust.js
│ ├── pathBoolean.js
│ ├── pathCeil.js
│ ├── pathIterator.js
│ ├── pathRotate.js
│ ├── pathSkew.js
│ ├── pathSplitBySegment.js
│ ├── pathTransform.js
│ ├── pathUtil.js
│ ├── pathsUtil.js
│ ├── reducePath.js
│ ├── util.js
│ └── vector.js
├── math
│ ├── bezierCubeEquation.js
│ ├── bezierCubic2Q2.js
│ ├── bezierQ2Equation.js
│ ├── bezierQ2Split.js
│ ├── bezierQ4Equation.js
│ ├── cubeEquation.js
│ ├── getAngle.js
│ ├── getBezierQ2Point.js
│ ├── getBezierQ2T.js
│ ├── quadraticEquation.js
│ └── quarticEquation.js
└── render
│ ├── Camera.js
│ ├── Controller.js
│ ├── Layer.js
│ ├── Painter.js
│ ├── Render.js
│ ├── capture
│ ├── Keyboard.js
│ ├── Mouse.js
│ └── Resize.js
│ ├── main.js
│ ├── shape
│ ├── Axis.js
│ ├── BezierCurve.js
│ ├── Circle.js
│ ├── CirclePoint.js
│ ├── Font.js
│ ├── Glyf.js
│ ├── Graduation.js
│ ├── GridArrow.js
│ ├── Line.js
│ ├── Path.js
│ ├── Point.js
│ ├── Polygon.js
│ ├── Rect.js
│ ├── Shape.js
│ ├── Text.js
│ └── support.js
│ └── util
│ ├── dashedLineTo.js
│ ├── drawAxis.js
│ ├── drawGraduation.js
│ ├── drawPath.js
│ ├── guid.js
│ └── selectShape.js
└── test
└── spec
├── graphics
├── isSegmentCross.spec.js
└── vector.spec.js
└── math
└── getBezierQ2T.spec.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@babel/preset-env"
4 | ],
5 | "plugins": [
6 | [
7 | "module-resolver",
8 | {
9 | "alias": {
10 | "graphics": "./src/graphics",
11 | "math": "./src/math",
12 | "fonteditor-core": "./node_modules/fonteditor-core/lib"
13 | }
14 | }
15 | ]
16 | ]
17 | }
--------------------------------------------------------------------------------
/.fecsignore:
--------------------------------------------------------------------------------
1 | src/fonteditor/template/dialog/*
2 | src/fonteditor/template/export/*
3 | src/editor/shapes/*
4 | src/ttf/data/*
5 | build/*
6 | css/*
7 | demo/*
8 | dep/*
9 | font/*
10 | node_modules
11 | release
12 | test
13 | index.html
14 | index-en.html
15 | empty.html
16 | edp-build-config.js
17 | edp-build-config-node.js
18 | edp-webserver-config.js
19 |
--------------------------------------------------------------------------------
/.fecsrc:
--------------------------------------------------------------------------------
1 | {
2 | "eslint": {
3 | "env": {
4 | "node": true,
5 | "browser": true
6 | },
7 |
8 | "rules": {
9 | "no-console": 0,
10 | "fecs-max-statements": 0,
11 | "max-params": 0,
12 | "max-depth": 0,
13 | "fecs-camelcase": 0
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.seed
2 | *.log
3 | *.csv
4 | *.dat
5 | *.out
6 | *.pid
7 | *.gz
8 | *.tmp
9 | .DS_Store
10 | pids
11 | logs
12 | results
13 | release
14 | npm-debug.log
15 | node_modules
16 | css/common/*.css
17 | demo/sync/*.ttf
18 | demo/sync/*.woff
19 | demo/sync/*.eot
20 | demo/sync/*.svg
21 |
22 | dep/fonteditor-core
23 |
24 | dist
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 ecomfe
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Fonteditor Online Font Editor
2 | ==========
3 |
4 | [English](./README.md) | [中文](./README.zh-CN.md)
5 |
6 | Use `Fonteditor` to edit, transform, preview fonts.
7 |
8 | Support ttf, woff, woff2, otf, svg font, eot import and edit online.
9 |
10 | [English Version](https://kekee000.github.io/fonteditor/index-en.html)
11 |
12 |
13 | 
14 |
15 | ### Dev:
16 |
17 | ```
18 | npm install && npm run dev
19 | ```
20 |
21 | * Main entry template is `index.tpl`, using `index.tpl` to generate `index.html` and `index-en.html`.
22 | * Jszip 3.0 api has changed, currently use lower version of jszip.
23 |
24 | ### Build:
25 |
26 | ```
27 | npm run build
28 | ```
29 |
30 | ### Test:
31 |
32 | ```
33 | npm run test
34 | ```
35 |
36 | ### Demo:
37 |
38 | ```
39 | npm run demo
40 | ```
41 |
42 | ### Relative
43 |
44 | + Fonteditor Core Lib: [fonteditor-core](https://github.com/kekee000/fonteditor-core)
45 | + fontmin: [fontmin](https://github.com/ecomfe/fontmin)
46 |
47 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | cd $(dirname $0)
3 | [ -d ./dist ] && rm -r dist
4 |
5 | npm run prod
6 |
7 | cp -r dep dist
8 | cp -r font dist
9 | cp empty.html proxy.html dist
10 | echo 'build to `dist` done'
--------------------------------------------------------------------------------
/build/i18n.en-us.js:
--------------------------------------------------------------------------------
1 | module.exports = exports = {
2 | lang: 'en-us',
3 | newglyph: 'New Glyph',
4 | undo: 'Undo',
5 | redo: 'Redo',
6 | import: 'Import',
7 | import_svg: 'Import svg',
8 | import_svg_title: 'Import svg font or svg file',
9 | import_pic: 'Import Image',
10 | import_pic_title: 'Import image with glyph',
11 | import_font: 'Import Font',
12 | import_font_title: 'Import ttf,woff,eot,otf font',
13 | export_ttf: 'Export ttf',
14 | export_woff: 'Export woff',
15 | export_woff2: 'Export woff2',
16 | export_zip: 'Export zip file, including ttf,woff,woff2,eot,svg font and examples.',
17 | save_proj: 'Save Project',
18 | onlinefont: 'Open Online Font',
19 | fonturl: 'Open Font from URL',
20 | tool: 'Tools',
21 | gen_glyph_name: 'Generate Glyph Name',
22 | clear_glyph_name: 'Clear Glyph Name',
23 | optimize_glyph: 'Optimize Glyph',
24 | sort_glyf: 'Sort Glyph by Unicode',
25 | compound2simple: 'Composite Glyph to Simple Glyph',
26 | preview: 'Preview',
27 | preview_ttf: 'ttf Font',
28 | preview_woff: 'woff Font',
29 | preview_woff2: 'woff2 Font',
30 | preview_svg: 'svg Font(Only safari)',
31 | preview_eot: 'eot Font(Only IE)',
32 | new_font: 'New',
33 | new_font_title: 'new font',
34 | open_font: 'Open',
35 | open_font_title: 'Open ttf,woff,eot,otf format font file',
36 | project_list: 'Project List',
37 | close_editor: 'Click or press `F2` to close glyph editor',
38 | metrics: 'Metrics',
39 | editor_setting: 'Editor Setting',
40 | import_and_export: 'Import and Export',
41 | setting: 'Setting',
42 | help: 'Help',
43 | confirm: 'Confirm',
44 | cancel: 'Cancel',
45 | fontinfo: 'Font Info',
46 | syncfromserver: 'Sync Font From Server'
47 | };
48 |
--------------------------------------------------------------------------------
/build/i18n.zh-cn.js:
--------------------------------------------------------------------------------
1 | module.exports = exports = {
2 | lang: 'zh-cn',
3 | newglyph: '新字形',
4 | undo: '撤销',
5 | redo: '重做',
6 | import: '导入',
7 | import_svg: '导入svg',
8 | import_svg_title: '导入svg格式字体文件',
9 | import_pic: '导入图片',
10 | import_pic_title: '导入包含字形的图片',
11 | import_font: '导入字体文件',
12 | import_font_title: '导入ttf,woff,eot,otf格式字体文件',
13 | export_ttf: '导出ttf',
14 | export_woff: '导出woff',
15 | export_woff2: '导出woff2',
16 | export_zip: '导出zip,包含ttf,woff,woff2,eot,svg等格式字体和icon示例',
17 | save_proj: '保存项目',
18 | onlinefont: '加载线上字体',
19 | fonturl: '从URL加载字体',
20 | tool: '工具',
21 | gen_glyph_name: '生成字形名称',
22 | clear_glyph_name: '清除字形名称',
23 | optimize_glyph: '优化字体',
24 | sort_glyf: '按代码点进行排序',
25 | compound2simple: '复合字形转简单字形',
26 | preview: '预览',
27 | preview_ttf: 'ttf字体',
28 | preview_woff: 'woff字体',
29 | preview_woff2: 'woff2字体',
30 | preview_svg: 'svg字体(仅safari)',
31 | preview_eot: 'eot字体(仅IE)',
32 | new_font: '新建',
33 | new_font_title: '新建ttf字体文件',
34 | open_font: '打开',
35 | open_font_title: '打开ttf,woff,eot,otf格式字体文件',
36 | project_list: '项目列表',
37 | close_editor: '点击或者按`F2`键关闭编辑器',
38 | metrics: '字体度量',
39 | editor_setting: '编辑器设置',
40 | import_and_export: '导入和导出',
41 | setting: '设置',
42 | help: '帮助',
43 | confirm: '确定',
44 | cancel: '取消',
45 | fontinfo: '字体信息',
46 | syncfromserver: '从服务器同步字体'
47 | };
48 |
--------------------------------------------------------------------------------
/build/index-loader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 编译首页文件,编译为中文版和英文版
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | /**
7 | * 字符串格式化,支持如 ${xxx.xxx} 的语法
8 | * @param {string} source 模板字符串
9 | * @param {Object} data 数据
10 | * @return {string} 格式化后字符串
11 | */
12 | function format(source, data) {
13 | return source.replace(/\$\{([\w.]+)\}/g, function ($0, $1) {
14 | let ref = $1.split('.');
15 | let refObject = data;
16 | let level;
17 |
18 | while (refObject != null && (level = ref.shift())) {
19 | refObject = refObject[level];
20 | }
21 |
22 | return refObject != null ? refObject : '';
23 | });
24 | }
25 |
26 |
27 | module.exports = function main(tpl) {
28 | let language = String(this.resource).match(/\?en-us/) ? 'en-us' : 'zh-cn';
29 | let i18n = {};
30 | i18n.lang = require('./i18n.' + language);
31 | let fileContent = format(tpl, i18n);
32 | return 'module.exports=' + JSON.stringify(fileContent);
33 | };
34 |
--------------------------------------------------------------------------------
/build/tpl-loader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 编译首页文件,编译为中文版和英文版
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | module.exports = function main(tpl) {
7 | return 'module.exports=' + JSON.stringify(tpl);
8 | };
9 |
--------------------------------------------------------------------------------
/css/editor.less:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | }
5 |
6 | @import './widget/reset.less';
7 | @import './widget/ico.less';
8 | @import './widget/glyf-editor.less';
9 |
10 |
11 | .editor-panel {
12 | width: 100%;
13 | height: 100%;
14 | font-size: 12px;
15 | -webkit-user-select: none;
16 | -moz-user-select: none;
17 | -ms-user-select: none;
18 | }
19 |
--------------------------------------------------------------------------------
/css/img/logo@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/css/img/logo@1x.png
--------------------------------------------------------------------------------
/css/img/logo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/css/img/logo@2x.png
--------------------------------------------------------------------------------
/css/main.less:
--------------------------------------------------------------------------------
1 | @import './widget/util.less';
2 | @import './widget/common.less';
3 | @import './widget/page.less';
4 |
5 | @import './widget/loading.less';
6 | @import './widget/project.less';
7 | @import './widget/glyf-list.less';
8 | @import './widget/glyf-spliter.less';
9 | @import './widget/editor.less';
10 | @import './widget/glyf-editor.less';
11 | @import './widget/dialog.less';
12 | @import './widget/import-pic-dialog.less';
13 | @import './widget/glyf-download-dialog.less';
14 |
--------------------------------------------------------------------------------
/css/preview.lesstpl:
--------------------------------------------------------------------------------
1 | @import './widget/reset.less';
2 |
3 | .main {
4 | padding:30px 100px;
5 |
6 | h1 {
7 | font-size:36px;
8 | color:#333;
9 | text-align:left;
10 | margin-bottom:30px;
11 | border-bottom:1px solid #eee
12 | }
13 | }
14 |
15 | .helps {
16 | margin-top:40px;
17 |
18 | pre {
19 | padding:20px;
20 | margin:10px 0;
21 | border:solid 1px #e7e1cd;
22 | background-color:#fffdef;
23 | overflow:auto
24 | }
25 | }
26 |
27 | .iconfont-list {
28 | overflow: hidden;
29 |
30 | li {
31 | float:left;
32 | width:100px;
33 | height:150px;
34 | text-align:center
35 | }
36 |
37 | .icon {
38 | font-size:42px;
39 | line-height:100px;
40 | margin:10px 0;
41 | color:#333;
42 | font-style: normal;
43 | -webkit-transition:font-size .25s ease-out 0s;
44 | -moz-transition:font-size .25s ease-out 0s;
45 | transition:font-size .25s ease-out 0s;
46 | }
47 |
48 | .icon:hover {
49 | font-size:100px
50 | }
51 |
52 | .code {
53 | color: green;
54 | font-weight: bold;
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/css/widget/common.less:
--------------------------------------------------------------------------------
1 | // 页面背景样式定义
2 | @import './reset.less';
3 | @import './bootstrap-overwrite.less';
4 | @import './def.less';
5 | @import './ico.less';
6 |
7 | body,
8 | html {
9 | margin: 0;
10 | padding: 0;
11 | font-size: 13px;
12 | height: 100%;
13 | }
14 |
15 | // scroll bar
16 | ::-webkit-scrollbar {
17 | width: 12px;
18 | height: 12px;
19 | }
20 |
21 | ::-webkit-scrollbar-track,
22 | ::-webkit-scrollbar-thumb {
23 | border-radius: 999px;
24 | border: 1px solid transparent;
25 | }
26 |
27 | ::-webkit-scrollbar-track {
28 | box-shadow: 1px 1px 5px rgba(0,0,0,.2) inset;
29 | }
30 |
31 | ::-webkit-scrollbar-thumb {
32 | min-height: 20px;
33 | background-clip: content-box;
34 | box-shadow: 0 0 0 5px rgba(0,0,0,.2) inset;
35 | }
36 |
37 | ::-webkit-scrollbar-corner {
38 | background: transparent;
39 | }
40 |
--------------------------------------------------------------------------------
/css/widget/def.less:
--------------------------------------------------------------------------------
1 |
2 | // 头部高度
3 | @top-height: 50px;
4 |
5 | // 菜单组高度
6 | @command-groups-height: 40px;
--------------------------------------------------------------------------------
/css/widget/dialog.less:
--------------------------------------------------------------------------------
1 | // 对话框样式
2 |
3 | .modal {
4 | background: -webkit-radial-gradient(center, circle contain, rgba(255,255,255,0.6) 0%, rgba(0,0,0,0.6) 100%);
5 | }
6 |
7 | .modal-dialog {
8 | margin-top: 100px;
9 |
10 | hr {
11 | margin-top: 0;
12 | }
13 | }
14 |
15 | .modal-header {
16 | padding-top: 6px;
17 | padding-bottom: 6px;
18 | background: #fff;
19 | color: #202430;
20 | .close {
21 | margin-top: 3px;
22 | }
23 |
24 | .modal-title {
25 | font-size: 14px;
26 | line-height: 25px;
27 | }
28 | }
29 |
30 |
31 |
32 | .modal-body {
33 | min-height: 100px;
34 | padding-bottom: 5px;
35 | background: #F8F9F9;
36 | }
37 |
38 | .modal-content {
39 | border-radius: 0;
40 | border-color: rgba(0,0,0,.5);
41 | -webkit-box-shadow: 0 2px 4px rgba(0,0,0,.2);
42 | box-shadow: 0 2px 4px rgba(0,0,0,.2);
43 | overflow: hidden;
44 | }
45 |
46 | .modal-footer {
47 | border-top: 0;
48 | background: #F8F9F9;
49 | padding-top: 10px;
50 | padding-bottom: 10px;
51 |
52 | .btn-default {
53 | border-radius: 0;
54 | color: #FFF;
55 | background: #738089;
56 | }
57 |
58 | .btn-primary {
59 | border-radius: 0;
60 | background: #4A90E2;
61 | }
62 | }
63 |
64 | .setting-metrics {
65 | .modal-dialog {
66 | width: 800px;
67 | }
68 | .panose-inline {
69 | margin-bottom: -15px;
70 | .input-group {
71 | width: 100%;
72 | }
73 | }
74 |
75 | }
76 |
77 |
78 | .list-font-online {
79 | max-height: 400px;
80 | overflow: auto;
81 | }
82 |
--------------------------------------------------------------------------------
/css/widget/glyf-download-dialog.less:
--------------------------------------------------------------------------------
1 | // 字形下载对话框
2 | .glyf-download-dialog {
3 |
4 | .field-margin {
5 | margin-left: 15px;
6 | }
7 |
8 | .color-picker {
9 | width: 25px;
10 | height: 25px;
11 | }
12 |
13 | .preview-panel {
14 | height: 360px;
15 | text-align: center;
16 | overflow: auto;
17 | position: relative;
18 |
19 | >canvas {
20 | position: absolute;
21 | top: 50%;
22 | left: 50%;
23 | transform: translate(-50%, -50%);
24 | }
25 | }
26 |
27 | .glyf-download-btn {
28 | text-align: center;
29 |
30 | .btn-flat {
31 | padding: 10px 15px;
32 | }
33 |
34 | .field-margin {
35 | margin-left: 30px;
36 | }
37 | }
38 | }
39 |
40 | // color picker 样式
41 | .cp-color-picker {
42 | z-index: 10000;
43 | }
44 |
--------------------------------------------------------------------------------
/css/widget/glyf-spliter.less:
--------------------------------------------------------------------------------
1 | .main .spliter {
2 | position: absolute;
3 | height: 80%;
4 | width: 6px;
5 | }
6 |
--------------------------------------------------------------------------------
/css/widget/import-pic-dialog.less:
--------------------------------------------------------------------------------
1 | // 导入图片对话框
2 | .import-pic-dialog {
3 | .modal-dialog {
4 | width: 960px;
5 | }
6 |
7 | .modal-body {
8 | padding-bottom: 0;
9 | }
10 |
11 | .preview-panel {
12 | background: #FFF;
13 | margin-bottom: 15px;
14 |
15 | .canvas-left,
16 | .canvas-right {
17 | display: inline-block;
18 | width: 50%;
19 | height: 420px;
20 | overflow: auto;
21 | }
22 |
23 | .canvas-left {
24 | border-right: 1px solid #BAC1CB;
25 | }
26 |
27 | &.fitpanel {
28 | canvas {
29 | max-width: 100%;
30 | max-height: 99%;
31 | }
32 | }
33 |
34 | &.showleft {
35 | .canvas-left {
36 | width: 100%;
37 | border-right: none;
38 | display: inline-block;
39 | }
40 | .canvas-right {
41 | display: none;
42 | }
43 | }
44 |
45 | &.showright {
46 | .canvas-right {
47 | width: 100%;
48 | display: inline-block;
49 | }
50 | .canvas-left {
51 | display: none;
52 | }
53 | }
54 | }
55 |
56 | .import-pic-url {
57 | position: absolute;
58 | margin-top: 30px;
59 | background: #4A90E2;
60 | padding: 10px 10px 0;
61 | border-bottom-left-radius: 5px;
62 | border-bottom-right-radius: 5px;
63 | display: none;
64 |
65 | &.show-url {
66 | display: block;
67 | }
68 | }
69 | }
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/css/widget/loading.less:
--------------------------------------------------------------------------------
1 | // loading 动画
2 | .loading {
3 | position: fixed;
4 | left: 50%;
5 | top: 30%;
6 | width: 200px;
7 | margin-left: -100px;
8 | line-height: 24px;
9 | text-align: center;
10 | z-index: 10000;
11 | display: none;
12 |
13 | span {
14 | display: inline-block;
15 | padding: 0 6px;
16 | background: rgba(84, 114, 93, 0.9);
17 | color: #FFF;
18 | border: 1px solid #DDD;
19 | }
20 | }
21 |
22 | .loading[data-status="error"] {
23 | span {
24 | color: red;
25 | background: rgba(236, 234, 69, 0.9);
26 | }
27 | }
28 |
29 | .loading[data-status="warn"] {
30 | span {
31 | color: #FF8722;
32 | background: rgba(255, 255, 255, 0.9);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/css/widget/project.less:
--------------------------------------------------------------------------------
1 | // 项目模块相关样式
2 | .project-btns {
3 | margin: 0 15px;
4 | padding: 10px 0;
5 | border-bottom: #353D45 1px solid;
6 |
7 | .btn {
8 | padding-left: 10px;
9 | padding-right: 12px;
10 | }
11 |
12 | .btn:last-child {
13 | margin-left: 10px;
14 | }
15 | }
16 |
17 | .project {
18 | .project-title {
19 | font-weight: bold;
20 | color: #6F7D88;
21 | padding-left: 15px;
22 | line-height: 32px;
23 | }
24 |
25 | .project-list {
26 | dl {
27 | padding: 0 10px 0 15px;
28 | cursor: pointer;
29 |
30 | dt {
31 | line-height: 28px;
32 | font-weight: normal;
33 | color: #9EB0C0;
34 | }
35 |
36 | dd {
37 | display: none;
38 | line-height: 28px;
39 | color: #6F7D88;
40 | span {
41 | margin-right: 10px;
42 | &:hover {
43 | text-decoration: underline;
44 | }
45 | }
46 | }
47 | }
48 |
49 | dl:hover {
50 | background: lighten(#323842, 10%);
51 | dt {
52 | color: #FFF;
53 | }
54 | }
55 |
56 | dl.selected {
57 | background: #323842;
58 | dd {
59 | display: block;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/css/widget/reset.less:
--------------------------------------------------------------------------------
1 | // 重置样式
2 |
3 | * {
4 | margin:0;
5 | padding:0;
6 | list-style:none
7 | }
8 | blockquote,
9 | body,
10 | button,
11 | dd,
12 | dl,
13 | dt,
14 | fieldset,
15 | form,
16 | h1,
17 | h2,
18 | h3,
19 | h4,
20 | h5,
21 | h6,
22 | hr,
23 | input,
24 | legend,
25 | li,
26 | ol,
27 | p,
28 | pre,
29 | td,
30 | textarea,
31 | th,
32 | ul {
33 | margin:0;
34 | padding:0
35 | }
36 | body,
37 | button,
38 | input,
39 | select,
40 | textarea {
41 | font:12px/1.5 tahoma,arial,sans-serif
42 | }
43 | h1,
44 | h2,
45 | h3,
46 | h4,
47 | h5,
48 | h6 {
49 | font-size:100%
50 | }
51 | address,
52 | cite,
53 | dfn,
54 | em,
55 | var {
56 | font-style:normal
57 | }
58 | code,
59 | kbd,
60 | pre,
61 | samp {
62 | font-family:courier new,courier,monospace
63 | }
64 | small {
65 | font-size:12px
66 | }
67 | ol,ul {
68 | list-style:none
69 | }
70 | a {
71 | text-decoration:none
72 | }
73 | a:hover {
74 | text-decoration:underline
75 | }
76 | legend {
77 | color:#000
78 | }
79 | fieldset,
80 | img {
81 | border:0
82 | }
83 | button,
84 | input,
85 | select,
86 | textarea {
87 | font-size:100%
88 | }
89 |
90 | table {
91 | border-collapse:collapse;
92 | border-spacing:0
93 | }
94 |
--------------------------------------------------------------------------------
/css/widget/util.less:
--------------------------------------------------------------------------------
1 |
2 | .ellipsis() {
3 | overflow: hidden;
4 | text-overflow: ellipsis;
5 | white-space: nowrap;
6 | }
7 |
8 | .ellipsis(@width) when (@width > 0px) {
9 | width: @width;
10 | overflow: hidden;
11 | text-overflow: ellipsis;
12 | white-space: nowrap;
13 | }
14 |
15 | // 各种渐变
16 | .gradient-horizontal(@startColor: #555, @endColor: #333) {
17 | background-color: @endColor;
18 | background-image: -moz-linear-gradient(left, @startColor, @endColor); // FF 3.6+
19 | background-image: -webkit-gradient(linear, 0 0, 100% 0, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+
20 | background-image: -webkit-linear-gradient(left, @startColor, @endColor); // Safari 5.1+, Chrome 10+
21 | background-image: -o-linear-gradient(left, @startColor, @endColor); // Opera 11.10
22 | background-image: linear-gradient(to right, @startColor, @endColor); // Standard, IE10
23 | background-repeat: repeat-x;
24 | }
25 | .gradient-vertical(@startColor: #555, @endColor: #333) {
26 | background-color: @endColor;
27 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+
28 | background-image: -webkit-linear-gradient(top, @startColor, @endColor); // Safari 5.1+, Chrome 10+
29 | background-image: -moz-linear-gradient(top, @startColor, @endColor); // FF 3.6+
30 | background-image: linear-gradient(to bottom, @startColor, @endColor); // Standard, IE10
31 | background-repeat: repeat-x;
32 | }
33 | .gradient-directional(@startColor: #555, @endColor: #333, @deg: 45deg) {
34 | background-color: @endColor;
35 | background-repeat: repeat-x;
36 | background-image: -webkit-linear-gradient(@deg, @startColor, @endColor); // Safari 5.1+, Chrome 10+
37 | background-image: -moz-linear-gradient(@deg, @startColor, @endColor); // FF 3.6+
38 | background-image: linear-gradient(@deg, @startColor, @endColor); // Standard, IE10
39 | }
40 |
--------------------------------------------------------------------------------
/demo/bezierSegmentCross.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 二次贝塞尔曲线绘制
6 |
7 |
8 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/demo/bezierSplit.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 贝塞尔分割
6 |
7 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/demo/boundSegmentCross.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | bound和线段相交
6 |
7 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/demo/canvasFindBreakPoint.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | canvas查找关键点
6 |
7 |
34 |
35 |
36 |
37 |
38 | 灰度阈值:
39 |
40 |
41 |
42 | 高斯平滑:
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/demo/contoursCombine.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 测试editor combine
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/demo/css/editor.less:
--------------------------------------------------------------------------------
1 | @import './reset.less';
2 | @import '../../css/widget/ico.less';
3 | @import '../../css/widget/glyf-editor.less';
4 |
5 | body, html {
6 | height: 100%;
7 | }
8 |
9 | #render-view {
10 | font-size: 12px;
11 | width: 100%;
12 | height: 100%;
13 | position: relative;
14 | -webkit-text-size-adjust: none;
15 | display: block;
16 | }
17 |
--------------------------------------------------------------------------------
/demo/css/editortest.less:
--------------------------------------------------------------------------------
1 | @import './editor.less';
2 |
3 | .pan-left {
4 | float: left;
5 | width: 180px;
6 | background: #ECECEC;
7 | }
8 |
9 | #glyf-list {
10 | a {
11 | display: block;
12 | line-height: 24px;
13 | }
14 | }
15 |
16 | #render-view {
17 | margin-left: 200px;
18 | width: auto;
19 | }
20 |
--------------------------------------------------------------------------------
/demo/css/render.less:
--------------------------------------------------------------------------------
1 | @import './reset.less';
2 |
3 | body, html {
4 | height: 100%;
5 | }
6 |
7 | #render-view {
8 | width: 100%;
9 | height: 100%;
10 | min-height: 600px;
11 | position: relative;
12 | -webkit-text-size-adjust: none;
13 | }
14 |
--------------------------------------------------------------------------------
/demo/css/reset.less:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | }
5 | ul {
6 | list-style: none;
7 | }
8 | a {
9 | color: #03C;
10 | text-decoration: none;
11 | }
12 | a:hover {
13 | text-decoration: underline;
14 | }
15 |
16 | .hide {
17 | display: none;
18 | }
--------------------------------------------------------------------------------
/demo/data/contours-1.js:
--------------------------------------------------------------------------------
1 | module.exports = {"name":"uniE016","unicode":[57366],"xMin":146,"xMax":573,"yMin":119,"yMax":546,"leftSideBearing":146,"advanceWidth":926,"contours":[[{"x":146,"y":490,"onCurve":true},{"x":146,"y":518},{"x":165,"y":531,"onCurve":true},{"x":177,"y":543},{"x":202,"y":546,"onCurve":true},{"x":517,"y":546,"onCurve":true},{"x":542,"y":543},{"x":561,"y":531,"onCurve":true},{"x":573,"y":518},{"x":573,"y":490,"onCurve":true},{"x":573,"y":175,"onCurve":true},{"x":573,"y":153},{"x":561,"y":138,"onCurve":true},{"x":542,"y":125},{"x":517,"y":119,"onCurve":true},{"x":202,"y":119,"onCurve":true},{"x":177,"y":125},{"x":165,"y":138,"onCurve":true},{"x":146,"y":153},{"x":146,"y":175,"onCurve":true},{"x":146,"y":490,"onCurve":true}]]};
2 |
--------------------------------------------------------------------------------
/demo/data/contours-10.js:
--------------------------------------------------------------------------------
1 | module.exports = {"xMin":99,"yMin":129,"xMax":243,"yMax":327,"unicode":[57357],"advanceWidth":633,"leftSideBearing":99,"name":"uniE00D","contours":[[{"x":186,"y":298},{"x":213,"y":289},{"x":232,"y":273},{"x":243,"y":251},{"x":243,"y":227},{"x":232,"y":206},{"x":213,"y":190},{"x":186,"y":181},{"x":157,"y":181},{"x":130,"y":190},{"x":111,"y":206},{"x":99,"y":227},{"x":99,"y":251},{"x":111,"y":273},{"x":130,"y":289},{"x":157,"y":298}],[{"x":99,"y":327,"onCurve":true},{"x":243,"y":327,"onCurve":true},{"x":243,"y":129,"onCurve":true},{"x":99,"y":129,"onCurve":true}]]};
2 |
--------------------------------------------------------------------------------
/demo/data/contours-11.js:
--------------------------------------------------------------------------------
1 | module.exports = {"xMin":25,"xMax":586,"yMin":137,"yMax":588,"advanceWidth":530,"unicode":[57395],"name":"uniE033","leftSideBearing":25,"contours":[[{"x":25,"y":137,"onCurve":true},{"x":333,"y":588},{"x":277,"y":221,"onCurve":true},{"x":586,"y":194,"onCurve":true}],[{"x":186,"y":280,"onCurve":true},{"x":422,"y":249,"onCurve":true},{"x":25,"y":192,"onCurve":true}]]}
2 |
--------------------------------------------------------------------------------
/demo/data/contours-12.js:
--------------------------------------------------------------------------------
1 | module.exports = {"xMin":98,"xMax":420,"yMin":149,"yMax":424,"advanceWidth":530,"unicode":[57395],"name":"uniE033","leftSideBearing":98,"contours":[[{"x":98,"y":424,"onCurve":true},{"x":348,"y":424,"onCurve":true},{"x":348,"y":235,"onCurve":true},{"x":98,"y":235,"onCurve":true}],[{"x":170,"y":338,"onCurve":true},{"x":420,"y":338,"onCurve":true},{"x":420,"y":149,"onCurve":true},{"x":170,"y":149,"onCurve":true}]]};
2 |
--------------------------------------------------------------------------------
/demo/data/contours-2.js:
--------------------------------------------------------------------------------
1 | module.exports = {"xMin":26,"yMin":-80,"xMax":601,"yMax":263,"unicode":[57357],"advanceWidth":633,"leftSideBearing":26,"name":"uniE00D","contours":[[{"x":394,"y":138},{"x":339,"y":5},{"x":164,"y":263},{"x":79,"y":165,"onCurve":true},{"x":286,"y":4,"onCurve":true},{"x":385,"y":-80},{"x":422,"y":83},{"x":422,"y":158},{"x":369,"y":211},{"x":295,"y":211}],[{"x":597,"y":61,"onCurve":true},{"x":597,"y":62},{"x":595,"y":63},{"x":594,"y":64,"onCurve":true},{"x":586,"y":78},{"x":572,"y":84,"onCurve":true},{"x":459,"y":177},{"x":312,"y":177,"onCurve":true},{"x":163,"y":177},{"x":49,"y":81,"onCurve":true},{"x":42,"y":76},{"x":37,"y":70,"onCurve":true},{"x":36,"y":69},{"x":33,"y":66},{"x":33,"y":65,"onCurve":true},{"x":26,"y":53},{"x":26,"y":39,"onCurve":true},{"x":26,"y":19},{"x":55,"y":-10},{"x":75,"y":-10,"onCurve":true},{"x":91,"y":-10},{"x":105,"y":0,"onCurve":true},{"x":193,"y":80},{"x":312,"y":80,"onCurve":true},{"x":435,"y":80},{"x":524,"y":-4,"onCurve":true},{"x":526,"y":-2,"onCurve":true},{"x":538,"y":-10},{"x":552,"y":-10,"onCurve":true},{"x":573,"y":-10},{"x":601,"y":19},{"x":601,"y":39,"onCurve":true},{"x":601,"y":50},{"x":596,"y":60,"onCurve":true}]]};
2 |
--------------------------------------------------------------------------------
/demo/data/contours-3.js:
--------------------------------------------------------------------------------
1 | module.exports = {"xMin":41,"yMin":53,"xMax":748,"yMax":563,"unicode":[57357],"advanceWidth":633,"leftSideBearing":41,"name":"uniE00D","contours":[[{"x":241,"y":276,"onCurve":true},{"x":744,"y":563},{"x":150,"y":102,"onCurve":true}],[{"x":237,"y":325,"onCurve":true},{"x":748,"y":53},{"x":41,"y":309,"onCurve":true}]]}
2 |
--------------------------------------------------------------------------------
/demo/data/contours-4.js:
--------------------------------------------------------------------------------
1 | module.exports = {"xMin":63,"yMin":176,"xMax":278,"yMax":406,"unicode":[57357],"advanceWidth":633,"leftSideBearing":63,"name":"uniE00D","contours":[[{"x":198,"y":176},{"x":214,"y":243},{"x":187,"y":337},{"x":131,"y":404},{"x":79,"y":404},{"x":63,"y":337},{"x":90,"y":243},{"x":146,"y":176}],[{"x":197,"y":177},{"x":247,"y":244},{"x":278,"y":339},{"x":272,"y":406},{"x":231,"y":406},{"x":181,"y":339},{"x":150,"y":244},{"x":156,"y":177}]]}
2 |
--------------------------------------------------------------------------------
/demo/data/contours-5.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = {"xMin":66,"yMin":22,"xMax":500,"yMax":430,"unicode":[57357],"advanceWidth":633,"leftSideBearing":66,"name":"uniE00D","contours":[[{"x":226,"y":255},{"x":272,"y":301},{"x":272,"y":367},{"x":226,"y":413},{"x":160,"y":413},{"x":114,"y":367},{"x":114,"y":301},{"x":160,"y":255}],[{"x":431,"y":242},{"x":486,"y":297},{"x":486,"y":375},{"x":431,"y":430},{"x":353,"y":430},{"x":298,"y":375},{"x":298,"y":297},{"x":353,"y":242}],[{"x":196,"y":22},{"x":250,"y":76},{"x":250,"y":152},{"x":196,"y":206},{"x":119,"y":206},{"x":66,"y":152},{"x":66,"y":76},{"x":119,"y":22}],[{"x":178,"y":340,"onCurve":true},{"x":423,"y":340,"onCurve":true},{"x":423,"y":113,"onCurve":true},{"x":178,"y":113,"onCurve":true}],[{"x":446,"y":28},{"x":500,"y":82},{"x":500,"y":158},{"x":446,"y":212},{"x":369,"y":212},{"x":316,"y":158},{"x":316,"y":82},{"x":369,"y":28}]]}
--------------------------------------------------------------------------------
/demo/data/contours-6.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = {"xMin":55,"yMin":-7,"xMax":494,"yMax":430,"unicode":[57357],"advanceWidth":633,"leftSideBearing":55,"name":"uniE00D","contours":[[{"x":319,"y":259},{"x":342,"y":282,"onCurve":true},{"x":365,"y":305},{"x":365,"y":338,"onCurve":true},{"x":365,"y":371},{"x":342,"y":394,"onCurve":true},{"x":319,"y":417},{"x":286,"y":417,"onCurve":true},{"x":253,"y":417},{"x":230,"y":394,"onCurve":true},{"x":207,"y":371},{"x":207,"y":338,"onCurve":true},{"x":207,"y":305},{"x":230,"y":282,"onCurve":true},{"x":253,"y":259},{"x":286,"y":259,"onCurve":true}],[{"x":431,"y":242},{"x":459,"y":270,"onCurve":true},{"x":486,"y":297},{"x":486,"y":336,"onCurve":true},{"x":486,"y":375},{"x":459,"y":403,"onCurve":true},{"x":431,"y":430},{"x":392,"y":430,"onCurve":true},{"x":353,"y":430},{"x":326,"y":403,"onCurve":true},{"x":298,"y":375},{"x":298,"y":336,"onCurve":true},{"x":298,"y":297},{"x":326,"y":270,"onCurve":true},{"x":353,"y":242},{"x":392,"y":242,"onCurve":true}],[{"x":185,"y":6},{"x":212,"y":33,"onCurve":true},{"x":239,"y":60},{"x":239,"y":98,"onCurve":true},{"x":239,"y":136},{"x":212,"y":163,"onCurve":true},{"x":185,"y":190},{"x":147,"y":190,"onCurve":true},{"x":108,"y":190},{"x":82,"y":163,"onCurve":true},{"x":55,"y":136},{"x":55,"y":98,"onCurve":true},{"x":55,"y":60},{"x":82,"y":33,"onCurve":true},{"x":108,"y":6},{"x":147,"y":6,"onCurve":true}],[{"x":178,"y":340,"onCurve":true},{"x":423,"y":340,"onCurve":true},{"x":423,"y":113,"onCurve":true},{"x":178,"y":113,"onCurve":true}],[{"x":435,"y":-7},{"x":465,"y":23,"onCurve":true},{"x":494,"y":52},{"x":494,"y":94,"onCurve":true},{"x":494,"y":135},{"x":465,"y":165,"onCurve":true},{"x":435,"y":194},{"x":393,"y":194,"onCurve":true},{"x":351,"y":194},{"x":322,"y":165,"onCurve":true},{"x":293,"y":135},{"x":293,"y":94,"onCurve":true},{"x":293,"y":52},{"x":322,"y":23,"onCurve":true},{"x":351,"y":-7},{"x":393,"y":-7,"onCurve":true}]]}
3 |
--------------------------------------------------------------------------------
/demo/data/contours-7.js:
--------------------------------------------------------------------------------
1 | module.exports = {"xMin":-21,"yMin":176,"xMax":355,"yMax":407,"unicode":[57357],"advanceWidth":633,"leftSideBearing":-21,"name":"uniE00D","contours":[[{"x":198,"y":176},{"x":206,"y":210,"onCurve":true},{"x":214,"y":243},{"x":201,"y":290,"onCurve":true},{"x":187,"y":337},{"x":159,"y":371,"onCurve":true},{"x":131,"y":404},{"x":105,"y":404,"onCurve":true},{"x":79,"y":404},{"x":71,"y":371,"onCurve":true},{"x":63,"y":337},{"x":77,"y":290,"onCurve":true},{"x":90,"y":243},{"x":118,"y":210,"onCurve":true},{"x":146,"y":176},{"x":172,"y":176,"onCurve":true}],[{"x":128,"y":178},{"x":153,"y":212,"onCurve":true},{"x":178,"y":245},{"x":194,"y":293,"onCurve":true},{"x":209,"y":340},{"x":206,"y":374,"onCurve":true},{"x":203,"y":407},{"x":183,"y":407,"onCurve":true},{"x":162,"y":407},{"x":137,"y":374,"onCurve":true},{"x":112,"y":340},{"x":97,"y":293,"onCurve":true},{"x":81,"y":245},{"x":84,"y":212,"onCurve":true},{"x":87,"y":178},{"x":108,"y":178,"onCurve":true}],[{"x":245,"y":265},{"x":355,"y":286},{"x":355,"y":315},{"x":245,"y":336},{"x":88,"y":336},{"x":-21,"y":315},{"x":-21,"y":286},{"x":88,"y":265}]]}
2 |
--------------------------------------------------------------------------------
/demo/data/contours-8.js:
--------------------------------------------------------------------------------
1 | module.exports = {"xMin":0,"yMin":0,"xMax":286,"yMax":266,"unicode":[58932],"advanceWidth":1024,"leftSideBearing":0,"name":"uniE634","contours":[[{"x":0,"y":81,"onCurve":true},{"x":0,"y":220,"onCurve":true},{"x":0,"y":230},{"x":8,"y":247},{"x":22,"y":260},{"x":41,"y":266},{"x":51,"y":266,"onCurve":true},{"x":237,"y":266,"onCurve":true},{"x":249,"y":266},{"x":266,"y":259},{"x":279,"y":247},{"x":286,"y":232},{"x":286,"y":224,"onCurve":true},{"x":286,"y":81,"onCurve":true}],[{"x":286,"y":185,"onCurve":true,"index0":13,"index1":13},{"x":286,"y":43,"onCurve":true,"index0":0,"index1":0},{"x":286,"y":34},{"x":279,"y":19},{"x":266,"y":7},{"x":249,"y":0},{"x":237,"y":0,"onCurve":true,"index0":6,"index1":6},{"x":51,"y":0,"onCurve":true,"index0":6,"index1":6},{"x":41,"y":0},{"x":22,"y":7},{"x":8,"y":19},{"x":0,"y":36},{"x":0,"y":47,"onCurve":true,"index0":12,"index1":12},{"x":0,"y":185,"onCurve":true,"index0":13,"index1":13}]]}
2 |
--------------------------------------------------------------------------------
/demo/data/contours-9.js:
--------------------------------------------------------------------------------
1 | module.exports = {"xMin":26,"yMin":-80,"xMax":601,"yMax":248,"unicode":[57357],"advanceWidth":633,"leftSideBearing":26,"name":"uniE00D","contours":[[{"x":225,"y":168,"onCurve":true},{"x":151,"y":248},{"x":79,"y":165,"onCurve":true},{"x":123,"y":131,"onCurve":true},{"x":84,"y":111},{"x":49,"y":81,"onCurve":true},{"x":42,"y":76},{"x":37,"y":70,"onCurve":true},{"x":36,"y":69},{"x":33,"y":66},{"x":33,"y":65,"onCurve":true},{"x":26,"y":53},{"x":26,"y":39,"onCurve":true},{"x":26,"y":19},{"x":55,"y":-10},{"x":75,"y":-10,"onCurve":true},{"x":91,"y":-10},{"x":105,"y":0,"onCurve":true},{"x":153,"y":43},{"x":210,"y":63,"onCurve":true},{"x":286,"y":4,"onCurve":true},{"x":385,"y":-80},{"x":404,"y":2,"onCurve":true},{"x":411,"y":36},{"x":416,"y":63,"onCurve":true},{"x":475,"y":42},{"x":524,"y":-4,"onCurve":true},{"x":526,"y":-2,"onCurve":true},{"x":538,"y":-10},{"x":552,"y":-10,"onCurve":true},{"x":573,"y":-10},{"x":601,"y":19},{"x":601,"y":39,"onCurve":true},{"x":601,"y":50},{"x":596,"y":60,"onCurve":true},{"x":597,"y":61,"onCurve":true},{"x":597,"y":62},{"x":595,"y":63},{"x":594,"y":64,"onCurve":true},{"x":586,"y":78},{"x":572,"y":84,"onCurve":true},{"x":498,"y":145},{"x":410,"y":166,"onCurve":true},{"x":404,"y":176},{"x":396,"y":185,"onCurve":true},{"x":369,"y":211},{"x":332,"y":211,"onCurve":true},{"x":296,"y":211},{"x":343,"y":176,"onCurve":true},{"x":327,"y":177},{"x":312,"y":177,"onCurve":true},{"x":267,"y":177}]]};
2 |
--------------------------------------------------------------------------------
/demo/data/contours.js:
--------------------------------------------------------------------------------
1 | module.exports = {"xMin":0,"yMin":-32,"xMax":512,"yMax":561,"unicode":[57358],"advanceWidth":512,"leftSideBearing":0,"name":"uniE00E","contours":[[{"x":362,"y":480},{"x":150,"y":480},{"x":0,"y":330},{"x":0,"y":118},{"x":150,"y":-32},{"x":362,"y":-32},{"x":512,"y":118},{"x":512,"y":330}],[{"x":376,"y":379,"onCurve":true},{"x":381,"y":374},{"x":381,"y":358},{"x":376,"y":353,"onCurve":true},{"x":367,"y":344,"onCurve":true},{"x":361,"y":339},{"x":346,"y":339},{"x":341,"y":344,"onCurve":true},{"x":270,"y":415,"onCurve":true},{"x":199,"y":345,"onCurve":true},{"x":194,"y":339},{"x":179,"y":339},{"x":173,"y":345,"onCurve":true},{"x":164,"y":353,"onCurve":true},{"x":159,"y":359},{"x":159,"y":374},{"x":164,"y":379,"onCurve":true},{"x":235,"y":450,"onCurve":true},{"x":164,"y":521,"onCurve":true},{"x":159,"y":526},{"x":159,"y":542},{"x":164,"y":547,"onCurve":true},{"x":173,"y":556,"onCurve":true},{"x":178,"y":561},{"x":193,"y":561},{"x":199,"y":556,"onCurve":true},{"x":270,"y":485,"onCurve":true},{"x":341,"y":556,"onCurve":true},{"x":346,"y":561},{"x":362,"y":561},{"x":367,"y":556,"onCurve":true},{"x":376,"y":547,"onCurve":true},{"x":381,"y":542},{"x":381,"y":526},{"x":376,"y":521,"onCurve":true},{"x":305,"y":450,"onCurve":true}]]};
2 |
--------------------------------------------------------------------------------
/demo/datastore.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 测试editor
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/demo/editor-iframe.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 测试editor远程调用
6 |
7 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/demo/editor.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 测试editor
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/demo/editortest.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 测试editor
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
21 |
25 |
26 |
27 |
28 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/demo/findBreakPoints.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 查找拐点
6 |
7 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/demo/fitContours.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | canvas读取图片
6 |
7 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/demo/fitCurve.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 三次bezier曲线拟合
6 |
7 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/demo/fitImage.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | canvas拟合图像
6 |
7 |
8 |
26 |
27 |
28 |
29 |
30 | 灰度阈值:
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | demo首页
6 |
7 |
8 |
9 | demo列表
10 |
11 | bezierSegmentCross
12 | bezierSplit
13 | boundSegmentCross
14 | CanvasFindBreakPoint
15 | contoursCombine
16 | editor-iframe
17 | editor
18 | editortest
19 | fitContours
20 | findBreakPoints
21 | fitCurve
22 | fitImage
23 | procImage
24 | quadraticBezierCross
25 | reducePoints
26 | render
27 | math
28 | segmentCross
29 |
30 |
31 |
--------------------------------------------------------------------------------
/demo/js/contoursCombine.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file contoursCombine.js
3 | * @author mengke01
4 | * @date
5 | * @description
6 | * 路径合并,求交
7 | */
8 |
9 | import lang from 'common/lang';
10 | import editor from 'editor/main';
11 | const shape_baidu = require('../data/contours-2');
12 |
13 | let currentEditor;
14 |
15 | const entry = {
16 |
17 | /**
18 | * 初始化
19 | */
20 | init() {
21 | let clonedShape = lang.clone(shape_baidu);
22 |
23 | window.editor = currentEditor = editor.create($('#render-view').get(0));
24 | currentEditor.setFont(clonedShape);
25 | let jointLayer = currentEditor.fontLayer;
26 | let paths = currentEditor.fontLayer.shapes.map(function (shape) {
27 | return shape.points;
28 | });
29 | }
30 | };
31 |
32 | entry.init();
33 |
--------------------------------------------------------------------------------
/demo/js/datastore.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 测试DataStore
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import DataStore from 'common/DataStore';
7 |
8 |
9 | const entry = {
10 |
11 | /**
12 | * 初始化
13 | */
14 | init() {
15 |
16 | let store = new DataStore({
17 | name: 'test',
18 | storeName: 'test-project'
19 | });
20 |
21 | store.open(function (e) {
22 |
23 | store.add(1001, 'sssss', function () {
24 | store.clear();
25 | store.close();
26 | });
27 |
28 | }, function (e) {
29 | console.log(e);
30 | });
31 |
32 | let store1 = new DataStore({
33 | name: 'test',
34 | storeName: 'test-project-1'
35 | });
36 |
37 | store1.open(function () {
38 | store.removeStore('test-project-1');
39 | store.close();
40 | });
41 | }
42 | };
43 |
44 | entry.init();
45 |
--------------------------------------------------------------------------------
/demo/js/editor.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file render.js
3 | * @author mengke01
4 | * @date
5 | * @description
6 | * editor 组件测试
7 | */
8 |
9 | import editor from 'editor/main';
10 | const shape_baidu = require('../data/contours-1');
11 |
12 | let currentEditor;
13 | const entry = {
14 |
15 | /**
16 | * 初始化
17 | */
18 | init() {
19 | currentEditor = editor.create($('#render-view').get(0));
20 | window.editor = currentEditor.setFont(shape_baidu);
21 | //currentEditor.blur();
22 |
23 | }
24 | };
25 |
26 | entry.init();
--------------------------------------------------------------------------------
/demo/js/fitContours.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 寻找关键点
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import fitContour from 'graphics/image/contour/fitContour';
7 | import drawPath from 'render/util/drawPath';
8 | import pathUtil from 'graphics/pathUtil';
9 |
10 | const data = require('../data/image-contours5');
11 | const entry = {
12 |
13 | /**
14 | * 初始化
15 | */
16 | init() {
17 |
18 | let html = '';
19 | let contours = [];
20 | data.forEach(function (points) {
21 |
22 | points.forEach(function (p) {
23 | html += '';
24 | });
25 |
26 | points = pathUtil.scale(points, 2);
27 | contours.push(pathUtil.scale(fitContour(points, 2), 0.5));
28 | points = pathUtil.scale(points, 0.5);
29 | });
30 |
31 |
32 | $('#points').html(html);
33 |
34 | html = '';
35 |
36 | let ctx = $('#canvas').get(0).getContext('2d');
37 | ctx.strokeStyle = 'pink';
38 |
39 | contours.forEach(function (contour) {
40 | for (let i = 0, l = contour.length; i < l; i++) {
41 | html += '';
42 | }
43 | drawPath(ctx, contour);
44 | });
45 |
46 | ctx.stroke();
47 | $('#points-break').html(html);
48 | }
49 | };
50 |
51 | entry.init();
52 |
--------------------------------------------------------------------------------
/demo/js/math.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file math.js
3 | * @author mengke01
4 | * @date
5 | * @description
6 | * 方程运算
7 | */
8 |
9 | import quadraticEquation from 'math/quadraticEquation';
10 | import cubeEquation from 'math/cubeEquation';
11 | import quarticEquation from 'math/quarticEquation';
12 |
13 | import bezierQ2Equation from 'math/bezierQ2Equation';
14 | import bezierCubeEquation from 'math/bezierCubeEquation';
15 | import bezierQ4Equation from 'math/bezierQ4Equation';
16 |
17 | const entry = {
18 |
19 | /**
20 | * 初始化
21 | */
22 | init() {
23 |
24 | console.log(quadraticEquation(1, 0, 1));
25 | console.log(bezierQ2Equation(1, 0, 1));
26 | console.log('--------------------------------');
27 | console.log(quadraticEquation(1, -2, 1));
28 | console.log(bezierQ2Equation(1, -2, 1));
29 | console.log('--------------------------------');
30 |
31 |
32 |
33 |
34 | console.log(cubeEquation(1, 0, 0, 1));
35 | console.log(bezierCubeEquation(1, 0, 0, 1));
36 | console.log('--------------------------------');
37 | console.log(cubeEquation(1, 0, 0, -1));
38 | console.log(bezierCubeEquation(1, 0, 0, -1));
39 | console.log('--------------------------------');
40 |
41 |
42 |
43 |
44 | console.log(quarticEquation(1, 0, 0, 0, 1));
45 | console.log(bezierQ4Equation(1, 0, 0, 0, 1));
46 | console.log('--------------------------------');
47 | console.log(quarticEquation(1, 0, 0, 0, -1));
48 | console.log(bezierQ4Equation(1, 0, 0, 0, -1));
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | }
62 | };
63 |
64 | entry.init();
--------------------------------------------------------------------------------
/demo/js/reducePoints.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 寻找关键点
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import reducePoints from 'graphics/image/contour/douglasPeuckerReducePoints';
7 | import pathUtil from 'graphics/pathUtil';
8 |
9 | const data = require('../data/image-contours10');
10 |
11 | const entry = {
12 |
13 | /**
14 | * 初始化
15 | */
16 | init() {
17 | let breakPoints = [];
18 | let html = '';
19 |
20 | data.forEach(function(c) {
21 | c.splice(c.length - 1, 1);
22 | });
23 |
24 | data.forEach(function (contour) {
25 | contour.forEach(function(p) {
26 | html += '';
27 | });
28 | });
29 |
30 | $('#points').html(html);
31 |
32 | data.forEach(function (contour) {
33 | pathUtil.scale(contour, 2);
34 | let points = reducePoints(contour, 0, contour.length - 1, 2);
35 | if (points) {
36 | points.forEach(function (p) {
37 | breakPoints.push(p);
38 | });
39 | }
40 | pathUtil.scale(contour, 0.5);
41 | });
42 |
43 |
44 | html = '';
45 | for (let i = 0, l = breakPoints.length; i < l; i++) {
46 | let c = "break";
47 | if (breakPoints[i].tangency) {
48 | c = 'tangency';
49 | }
50 | else if(breakPoints[i].inflexion) {
51 | c = 'inflexion';
52 | }
53 | let width = '';
54 | if (breakPoints[i].right == 1) {
55 | width = 'width: 4px;height: 4px';
56 | }
57 | html += '';
58 | }
59 |
60 | $('#points-break').html(html);
61 | }
62 | };
63 |
64 | entry.init();
65 |
--------------------------------------------------------------------------------
/demo/math.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 测试math函数
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/demo/paper-boolean.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | paperjs path boolean操作
6 |
7 |
8 |
21 |
22 |
23 |
27 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/demo/quadraticBezierCross.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 二次贝塞尔求交
6 |
7 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/demo/reducePoints.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 消减中间点
6 |
7 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/demo/render.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 测试render
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/demo/segmentCross.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 线段相交
6 |
7 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/demo/sync/icon.css:
--------------------------------------------------------------------------------
1 | /**
2 | * @file icon.css
3 | */
4 |
5 | @font-face {
6 | font-family: "fonteditor";
7 | src: url("fonteditor.eot"); /* IE9 */
8 | src: url("fonteditor.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */
9 | url("fonteditor.woff") format("woff"), /* chrome、firefox */
10 | url("fonteditor.ttf") format("truetype"), /* chrome、firefox、opera、Safari, Android, iOS 4.2+ */
11 | url("fonteditor.svg#uxfonteditor") format("svg"); /* iOS 4.1- */
12 | }
13 |
14 | .icon {
15 | font-family: "fonteditor";
16 | speak: none;
17 | font-style: normal;
18 | font-weight: normal;
19 | font-variant: normal;
20 | text-transform: none;
21 | line-height: 1;
22 | -webkit-font-smoothing: antialiased;
23 | -moz-osx-font-smoothing: grayscale;
24 | }
25 |
--------------------------------------------------------------------------------
/demo/test/a.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/demo/test/a.gif
--------------------------------------------------------------------------------
/demo/test/add.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/demo/test/add.bmp
--------------------------------------------------------------------------------
/demo/test/add.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/demo/test/add.jpg
--------------------------------------------------------------------------------
/demo/test/circle.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/demo/test/circle.gif
--------------------------------------------------------------------------------
/demo/test/circle.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/demo/test/circle.jpg
--------------------------------------------------------------------------------
/demo/test/cl.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/demo/test/cl.gif
--------------------------------------------------------------------------------
/demo/test/cur.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/demo/test/cur.jpg
--------------------------------------------------------------------------------
/demo/test/ecomfe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/demo/test/ecomfe.png
--------------------------------------------------------------------------------
/demo/test/oval.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/demo/test/oval.gif
--------------------------------------------------------------------------------
/demo/test/qgqc.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/demo/test/qgqc.jpg
--------------------------------------------------------------------------------
/demo/test/question.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/demo/test/question.png
--------------------------------------------------------------------------------
/demo/test/sjx.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/demo/test/sjx.jpg
--------------------------------------------------------------------------------
/demo/test/unicodenames.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/demo/test/unicodenames.xlsx
--------------------------------------------------------------------------------
/dep/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/dep/favicon.ico
--------------------------------------------------------------------------------
/dep/woff2/woff2.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/dep/woff2/woff2.wasm
--------------------------------------------------------------------------------
/editor.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Editor
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/empty.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | fonteditor
6 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/font/fonteditor.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/font/fonteditor.eot
--------------------------------------------------------------------------------
/font/fonteditor.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/font/fonteditor.ttf
--------------------------------------------------------------------------------
/font/fonteditor.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/font/fonteditor.woff
--------------------------------------------------------------------------------
/fonteditor-zh.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/fonteditor-zh.jpg
--------------------------------------------------------------------------------
/fonteditor.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ecomfe/fonteditor/dd7cc302bb3a742ca5821d9f3103a4fcdfdf6588/fonteditor.jpg
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fonteditor",
3 | "version": "2.3.0",
4 | "repository": {
5 | "type": "git",
6 | "url": "git://github.com/ecomfe/fonteditor.git"
7 | },
8 | "bugs": {
9 | "url": "https://github.com/ecomfe/fonteditor/issues"
10 | },
11 | "author": "kekee000",
12 | "contributors": [
13 | {
14 | "email": "kekee000@gmail.com",
15 | "name": "kekee000"
16 | },
17 | {
18 | "email": "junmer@foxmail.com",
19 | "name": "junmer"
20 | }
21 | ],
22 | "description": "ttf to woff, woff2, svg, eot convert, ttf adjust",
23 | "scripts": {
24 | "start": "npm run dev",
25 | "dev": "webpack-dev-server --open --config ./config/webpack.dev.js",
26 | "demo": "webpack-dev-server --open --config ./config/webpack.demo.js",
27 | "prod": "webpack --production --config ./config/webpack.prod.js",
28 | "test": "./node_modules/.bin/mocha --require @babel/register test/spec/*.spec.js test/spec/**/*.spec.js",
29 | "build": "sh build.sh",
30 | "lint": "fecs ./src --reporter=baidu --rules"
31 | },
32 | "devDependencies": {
33 | "@babel/cli": "^7.20.7",
34 | "@babel/core": "^7.20.12",
35 | "@babel/preset-env": "^7.20.2",
36 | "@babel/register": "^7.18.9",
37 | "babel-plugin-module-resolver": "^4.1.0",
38 | "css-loader": "^3.2.0",
39 | "file-loader": "^4.2.0",
40 | "fonteditor-core": "^2.3.2",
41 | "html-webpack-plugin": "^3.2.0",
42 | "less": "^2.0.0",
43 | "less-loader": "^5.0.0",
44 | "mini-css-extract-plugin": "^0.8.0",
45 | "mocha": "^6.2.2",
46 | "optimize-css-assets-webpack-plugin": "^5.0.3",
47 | "style-loader": "^1.0.0",
48 | "to-string-loader": "^1.1.5",
49 | "url-loader": "^2.2.0",
50 | "webpack": "^4.41.1",
51 | "webpack-cli": "^3.3.9",
52 | "webpack-dev-server": "^3.8.2"
53 | },
54 | "homepage": "https://github.com/ecomfe/fonteditor",
55 | "keywords": [
56 | "font",
57 | "ttf",
58 | "woff",
59 | "woff2",
60 | "svg",
61 | "eot"
62 | ],
63 | "license": "MIT"
64 | }
65 |
--------------------------------------------------------------------------------
/php/readOnline.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | proxy
6 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/common/I18n.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 用于国际化的字符串管理类
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | export {default} from 'fonteditor-core/common/I18n';
7 |
--------------------------------------------------------------------------------
/src/common/ajaxFile.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file ajax获取文本数据
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 | export {default} from 'fonteditor-core/common/ajaxFile';
6 |
--------------------------------------------------------------------------------
/src/common/getPixelRatio.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 获取当前设备的像素比率
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | const pixelRatio = (function (context) {
7 | let backingStore = context.backingStorePixelRatio
8 | || context.webkitBackingStorePixelRatio
9 | || context.mozBackingStorePixelRatio
10 | || context.msBackingStorePixelRatio
11 | || context.oBackingStorePixelRatio
12 | || context.backingStorePixelRatio
13 | || 1;
14 |
15 | return (window.devicePixelRatio || 1) / backingStore;
16 | })(HTMLCanvasElement.prototype);
17 |
18 | export default pixelRatio;
19 |
--------------------------------------------------------------------------------
/src/common/lang.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 语言相关函数
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import {
7 | clone,
8 | overwrite,
9 | debounce,
10 | throttle,
11 | equals
12 | } from 'fonteditor-core/common/lang';
13 |
14 | export default {
15 | clone,
16 | overwrite,
17 | debounce,
18 | throttle,
19 | equals,
20 | parseQuery(querystring) {
21 | let query = querystring.split('&')
22 | .map(function (item) {
23 | item = item.split('=');
24 | return [item[0], decodeURIComponent(item[1])];
25 | })
26 | .reduce(function (query, item) {
27 | query[item[0]] = item[1];
28 | return query;
29 | }, {});
30 | return query;
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/src/common/string.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 字符串相关的函数
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 | export {default} from 'fonteditor-core/common/string';
6 |
--------------------------------------------------------------------------------
/src/editor/command/commandSupport.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 命令相关配置项目,用来配置命令执行前或者执行后的动作
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | export default {
7 | // 支持历史记录的命令列表
8 | history: {
9 | alignshapes: true,
10 | verticalalignshapes: true,
11 | horizontalalignshapes: true,
12 | joinshapes: true,
13 | intersectshapes: true,
14 | tangencyshapes: true,
15 | splitshapes: true,
16 | removeshapes: true,
17 | reversepoints: true,
18 | topshape: true,
19 | bottomshape: true,
20 | upshape: true,
21 | downshape: true,
22 | cutshapes: true,
23 | pasteshapes: true,
24 | addshapes: true,
25 | rotateleft: true,
26 | rotateright: true,
27 | flipshapes: true,
28 | mirrorshapes: true
29 | }
30 | };
31 |
32 |
--------------------------------------------------------------------------------
/src/editor/command/setSelectedCommand.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 设置选中的命令
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | /**
7 | * 设置选中的命令
8 | *
9 | * @param {Array} commandList 命令列表
10 | * @param {string} command 命令路径,支持二级路径
11 | * @param {boolean} selected 是否被选中
12 | * @return {boolean} 是否找到command
13 | */
14 | export default function setSelectedCommand(commandList, command, selected) {
15 | let path = command.split('.');
16 | for (let i = 0, l = commandList.length; i < l; i++) {
17 | if (commandList[i].name === path[0]) {
18 | if (!commandList[i].items) {
19 | commandList[i].selected = !!selected;
20 | return true;
21 | }
22 | else if (path[1]) {
23 | let items = commandList[i].items;
24 | for (let j = 0, ll = items.length; j < ll; j++) {
25 | if (items[j].name === path[1]) {
26 | items[j].selected = !!selected;
27 | return true;
28 | }
29 | }
30 | }
31 | }
32 | }
33 |
34 | return false;
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/src/editor/command/support.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 支持的命令列表
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import shape from './shape';
7 | import transform from './transform';
8 | import align from './align';
9 | import join from './join';
10 | import referenceline from './referenceline';
11 | import editor from './editor';
12 |
13 | export default {
14 | ...shape,
15 | ...transform,
16 | ...align,
17 | ...join,
18 | ...referenceline,
19 | ...shape,
20 | ...editor
21 | };
22 |
--------------------------------------------------------------------------------
/src/editor/controller/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file index
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import initSetting from './initSetting';
7 | import initFont from './initFont';
8 | import initRender from './initRender';
9 | import initLayer from './initLayer';
10 | import initAxis from './initAxis';
11 | import initBinder from './initBinder';
12 |
13 | // 默认editor的初始化函数列表,这里应该是按照特定顺序执行的函数集合
14 | export default [
15 | initSetting,
16 | initFont,
17 | initRender,
18 | initLayer,
19 | initAxis,
20 | initBinder
21 | ];
22 |
--------------------------------------------------------------------------------
/src/editor/controller/initBinder.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 初始化绑定器
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import commandSupport from '../command/commandSupport';
7 |
8 | /**
9 | * 初始化绑定器
10 | */
11 | export default function () {
12 | let me = this;
13 | // 保存历史记录
14 | me.on('change', function () {
15 | me.history.add(me.getShapes());
16 | });
17 |
18 | me.on('command', function (e) {
19 | if (false !== e.result && commandSupport.history[e.command]) {
20 | me.fire('change');
21 | }
22 | });
23 | }
24 |
--------------------------------------------------------------------------------
/src/editor/controller/initLayer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file Editor的layer初始化
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | /**
7 | * 初始化层
8 | */
9 | export default function initLayer() {
10 |
11 | this.axisLayer = this.render.addLayer('axis', {
12 | level: 10,
13 | fill: false
14 | });
15 |
16 | this.fontLayer = this.render.addLayer('font', Object.assign({
17 | level: 20,
18 | lineWidth: 1,
19 | strokeColor: '#999',
20 | fillColor: '#555',
21 | strokeSeparate: false
22 | }, this.options.fontLayer));
23 |
24 | this.coverLayer = this.render.addLayer('cover', Object.assign({
25 | level: 30,
26 | fill: false,
27 | strokeColor: this.options.coverLayer.strokeColor,
28 | fillColor: this.options.coverLayer.fillColor
29 | }, this.options.coverLayer));
30 |
31 | this.referenceLineLayer = this.render.addLayer('referenceline', {
32 | level: 40,
33 | fill: false,
34 | strokeColor: this.options.referenceline.style.strokeColor
35 | });
36 |
37 |
38 | this.graduationLayer = this.render.addLayer('graduation', {
39 | level: 50,
40 | fill: false,
41 | disabled: true
42 | });
43 | }
44 |
--------------------------------------------------------------------------------
/src/editor/controller/initSetting.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 初始化Editor设置
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import setSelectedCommand from '../command/setSelectedCommand';
7 | import commandList from '../menu/commandList';
8 | import lang from 'common/lang';
9 |
10 | function initSetting(options) {
11 |
12 | // 设置菜单选中状态
13 |
14 | setSelectedCommand(
15 | commandList.editor, 'setting.gridsorption',
16 | !!options.sorption.enableGrid
17 | );
18 |
19 | setSelectedCommand(
20 | commandList.editor, 'setting.shapesorption',
21 | !!options.sorption.enableShape
22 | );
23 |
24 | setSelectedCommand(
25 | commandList.editor, 'setting.showgrid',
26 | !!options.axis.showGrid
27 | );
28 | }
29 |
30 | /**
31 | * 设置选项
32 | *
33 | * @param {Object} options 选项
34 | * @param {Object} options.sorption 吸附设置
35 | * @param {Object} options.axis 坐标设置
36 | * @see editor/options
37 | */
38 | function setOptions(options) {
39 |
40 | this.execCommand('gridsorption', options.sorption.enableGrid);
41 | this.execCommand('shapesorption', options.sorption.enableShape);
42 | this.execCommand('showgrid', options.axis.showGrid);
43 |
44 | this.fontLayer.options.fill = !!options.fontLayer.fill;
45 | this.fontLayer.options.fillColor = options.fontLayer.fillColor;
46 | this.fontLayer.options.strokeColor = options.fontLayer.strokeColor;
47 | this.fontLayer.refresh();
48 |
49 | this.axis.gapColor = options.axis.gapColor;
50 | this.axis.metricsColor = options.axis.metricsColor;
51 | this.axis.emColor = options.axis.emColor;
52 | this.axis.graduation.gap = options.axis.graduation.gap || 100;
53 | this.axisLayer.refresh();
54 | this.graduationLayer.refresh();
55 | lang.overwrite(this.options, options);
56 | }
57 |
58 | export default function () {
59 | initSetting.call(this, this.options);
60 | this.setOptions = setOptions;
61 | }
62 |
--------------------------------------------------------------------------------
/src/editor/group/rotateTransform.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 旋转变换
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import getRotateMatrix from './getRotateMatrix';
7 | import pathRotate from 'graphics/pathRotate';
8 | import pathSkew from 'graphics/pathSkew';
9 | import lang from 'common/lang';
10 |
11 | /**
12 | * 旋转变换
13 | *
14 | * @param {Object} point 参考点
15 | * @param {Camera} camera 镜头对象
16 | */
17 | export default function rotateTransform(point, camera) {
18 |
19 | let matrix = getRotateMatrix(point.pos, this.bound, camera);
20 |
21 | let transformer = point.pos <= 4 ? pathRotate : pathSkew;
22 |
23 | // 更新shape
24 | let shapes = this.shapes;
25 |
26 | this.coverShapes.forEach(function (coverShape, index) {
27 | let shape = lang.clone(shapes[index]);
28 | transformer(shape.points, matrix[2], matrix[0], matrix[1]);
29 | Object.assign(coverShape, shape);
30 |
31 | });
32 |
33 |
34 | // 更新边界
35 | let coverLayer = this.editor.coverLayer;
36 | let boundShape = coverLayer.getShape('bound');
37 | let bound = this.bound;
38 | boundShape.points = transformer(
39 | [
40 | {x: bound.x, y: bound.y},
41 | {x: bound.x + bound.width, y: bound.y},
42 | {x: bound.x + bound.width, y: bound.y + bound.height},
43 | {x: bound.x, y: bound.y + bound.height}
44 | ],
45 | matrix[2], matrix[0], matrix[1]
46 | );
47 |
48 | // 更新中心点
49 | let boundCenter = coverLayer.getShape('boundcenter');
50 | if (!boundCenter) {
51 | boundCenter = {
52 | type: 'cpoint',
53 | id: 'boundcenter',
54 | x: bound.x + bound.width / 2,
55 | y: bound.y + bound.height / 2
56 | };
57 | coverLayer.addShape(boundCenter);
58 | }
59 | boundCenter.x = (boundShape.points[0].x + boundShape.points[2].x) / 2;
60 | boundCenter.y = (boundShape.points[0].y + boundShape.points[2].y) / 2;
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/editor/i18n/i18n.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 语言字符串管理
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import I18n from 'common/I18n';
7 | import zhcn from './zh-cn';
8 | import enus from './en-us';
9 |
10 | export default new I18n(
11 | [
12 | ['zh-cn', zhcn],
13 | ['en-us', enus]
14 | ],
15 | window.language
16 | );
17 |
--------------------------------------------------------------------------------
/src/editor/i18n/zh-cn.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file zh-cn
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | export default {
7 | copy: '复制',
8 | paste: '粘贴',
9 | cut: '剪切',
10 | del: '删除',
11 | save: '保存',
12 | undo: '撤销',
13 | redo: '重做',
14 | rangemode: '轮廓模式',
15 | pointmode: '点模式',
16 | order: '顺序',
17 | upshape: '上移一层',
18 | downshape: '下移一层',
19 | reversepoints: '改变方向',
20 | topshape: '置前',
21 | bottomshape: '置后',
22 | align: '水平方向',
23 | alignleft: '左对齐',
24 | aligncenter: '居中对齐',
25 | alignright: '右对齐',
26 | verticalalign: '垂直方向',
27 | alignshapes: '对齐形状',
28 | aligntop: '顶端对齐',
29 | alignmiddle: '垂直居中对齐',
30 | aligndescent: '底端对齐',
31 | alignbaseline: '基线对齐',
32 | rotateleft: '向左旋转',
33 | rotateright: '向右旋转',
34 | transform: '变换',
35 | flip: '翻转',
36 | mirror: '镜像',
37 | splitshapes: '切割轮廓',
38 | joinshapes: '结合',
39 | intersectshapes: '相交',
40 | tangencyshapes: '相切',
41 | removeshapes: '删除轮廓',
42 | adjustpos: '调整位置',
43 | adjustglyf: '调整字形',
44 | addpath: '添加路径',
45 | addshapes: '添加形状',
46 | circle: '圆',
47 | rect: '矩形',
48 | roundrect: '圆角矩形',
49 | star: '五角星',
50 | arrow: '箭头',
51 | triangle: '三角形',
52 | heart: '心形',
53 | tel: '电话',
54 | drop: '水滴',
55 | du: '度图标',
56 | setting: '设置',
57 | gridsorption: '吸附到网格线',
58 | shapesorption: '吸附到轮廓',
59 | showgrid: '显示网格',
60 | moresetting: '更多..',
61 | addreferenceline: '添加参考线',
62 | clearreferenceline: '清除参考线',
63 | addboundreferenceline: '添加边界参考线',
64 | rescale: '重置缩放',
65 | fontsetting: '字形信息',
66 | addpoint: '添加点',
67 | removepoint: '删除点',
68 | oncurve: '在曲线上',
69 | offcurve: '远离曲线',
70 | asstart: '作为开始点'
71 | };
72 |
--------------------------------------------------------------------------------
/src/editor/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 编辑器主函数
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import render from 'render/main';
7 | import Editor from './Editor';
8 | import defaultOptions from './options';
9 |
10 | export default {
11 |
12 | /**
13 | * 创建一个编辑器
14 | *
15 | * @param {HTMLElement} main 主控区域
16 | * @param {Object} options 创建参数
17 | * @param {Object} options.controller 控制器函数
18 | *
19 | * @return {Render} render对象
20 | */
21 | create(main, options) {
22 |
23 | if (!main) {
24 | throw 'need main element';
25 | }
26 |
27 | options = Object.assign({}, defaultOptions, options);
28 |
29 | let editor = new Editor(main, options.editor);
30 | let opt = options.render || {};
31 |
32 | opt.controller = editor;
33 | render.create(main, opt);
34 | return editor;
35 | }
36 | };
37 |
38 |
--------------------------------------------------------------------------------
/src/editor/menu/commandList.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 命令集合
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import point from './point';
7 | import shape from './shape';
8 | import shapes from './shapes';
9 | import editor from './editor';
10 |
11 | export default {
12 | point,
13 | shape,
14 | shapes,
15 | editor
16 | };
17 |
--------------------------------------------------------------------------------
/src/editor/menu/point.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 点相关命令
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 | import i18n from '../i18n/i18n';
6 | export default [
7 | {
8 | name: 'add',
9 | title: i18n.lang.addpoint
10 | },
11 | {
12 | name: 'remove',
13 | title: i18n.lang.removepoint
14 | },
15 | {
16 | name: 'onCurve',
17 | title: i18n.lang.oncurve
18 | },
19 | {
20 | name: 'offCurve',
21 | title: i18n.lang.offcurve
22 | },
23 | {
24 | name: 'asStart',
25 | title: i18n.lang.asstart
26 | }
27 | ];
28 |
--------------------------------------------------------------------------------
/src/editor/mode/bound.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 默认模式
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import selectShape from 'render/util/selectShape';
7 | import referenceline from './referenceline';
8 | export default {
9 |
10 |
11 | down(e) {
12 | if (1 === e.which) {
13 |
14 | // 是否在边界拉出参考线
15 | if (e.x <= 20 || e.y <= 20) {
16 | this.setMode('referenceline', referenceline.newLine, e.x, e.y);
17 | return;
18 | }
19 |
20 | // 字体模式
21 | let result = this.fontLayer.getShapeIn(e);
22 | if (result) {
23 | let shape = selectShape(result, e);
24 | this.setMode('shapes', [shape], 'bound');
25 | return;
26 | }
27 |
28 | // 参考线模式
29 | result = this.referenceLineLayer.getShapeIn(e);
30 | if (result) {
31 | let line = result[0];
32 | this.setMode('referenceline', referenceline.dragLine, line, e);
33 | return;
34 | }
35 |
36 | this.setMode('range');
37 | }
38 | },
39 |
40 |
41 | keydown(e) {
42 | if (e.keyCode === 32) {
43 | this.setMode('pan');
44 | }
45 | else if (e.keyCode === 65 && e.ctrlKey) {
46 | this.setMode('shapes', this.fontLayer.shapes.slice());
47 | }
48 | }
49 | };
50 |
51 |
--------------------------------------------------------------------------------
/src/editor/mode/pan.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 区域查看模式
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | export default {
7 |
8 | drag(e) {
9 | if (1 === e.which) {
10 | let camera = this.render.camera;
11 | this.render.move(camera.mx, camera.my);
12 | this.render.refresh();
13 | }
14 | },
15 |
16 | keyup(e) {
17 | if (e.keyCode === 32) {
18 | this.setMode('bound');
19 | }
20 | },
21 |
22 |
23 | begin() {
24 | this.render.setCursor('pointer');
25 | },
26 |
27 |
28 | end() {
29 | this.render.setCursor('default');
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/src/editor/mode/split.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 轮廓切割模式
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | export default {
7 |
8 | down(e) {
9 | if (1 === e.which) {
10 | this.coverLayer.clearShapes();
11 | this.splitLine = this.coverLayer.addShape({
12 | type: 'line',
13 | p0: {
14 | x: e.x,
15 | y: e.y
16 | },
17 | p1: {
18 | x: e.x,
19 | y: e.y
20 | }
21 | });
22 | }
23 | },
24 |
25 |
26 | move(e) {
27 | if (1 === e.which) {
28 | if (this.splitLine) {
29 | this.splitLine.p1.x = e.x;
30 | this.splitLine.p1.y = e.y;
31 | if (e.shiftKey) {
32 | this.splitLine.p1.y = this.splitLine.p0.y;
33 | }
34 |
35 | if (e.altKey) {
36 | this.splitLine.p1.x = this.splitLine.p0.x;
37 | }
38 |
39 | this.coverLayer.refresh();
40 | }
41 | }
42 | },
43 |
44 |
45 | up(e) {
46 | if (1 === e.which) {
47 | if (this.splitLine) {
48 | let p0 = this.splitLine.p0;
49 | let p1 = this.splitLine.p1;
50 | // 对shape进行多选
51 | if (Math.abs(p0.x - p1.x) >= 20 || Math.abs(p0.y - p1.y) >= 20) {
52 | if (false !== this.execCommand('splitshapes', p0, p1)) {
53 | return;
54 | }
55 | }
56 | }
57 |
58 | this.setMode();
59 | }
60 | },
61 |
62 | begin() {
63 | },
64 |
65 | end() {
66 | delete this.splitLine;
67 | this.coverLayer.clearShapes();
68 | this.coverLayer.refresh();
69 | }
70 | };
71 |
72 |
--------------------------------------------------------------------------------
/src/editor/mode/support.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 编辑器支持的模式集合
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import point from './point';
7 | import range from './range';
8 | import pan from './pan';
9 | import bound from './bound';
10 | import shapes from './shapes';
11 | import addshapes from './addshapes';
12 | import addpath from './addpath';
13 | import split from './split';
14 | import referenceline from './referenceline';
15 |
16 |
17 | export default {
18 | point,
19 | range,
20 | pan,
21 | 'default': bound,
22 | shapes,
23 | addshapes,
24 | addpath,
25 | split,
26 | referenceline
27 | };
28 |
--------------------------------------------------------------------------------
/src/editor/shapes/arrow.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable*/
2 | export default [[{"x":1,"y":380,"onCurve":true},{"x":1,"y":423},{"x":43,"y":453},{"x":88,"y":453,"onCurve":true},{"x":109,"y":453},{"x":197,"y":452},{"x":296,"y":452},{"x":390,"y":451},{"x":418,"y":451,"onCurve":true},{"x":457,"y":450},{"x":502,"y":465},{"x":502,"y":493,"onCurve":true},{"x":502,"y":513},{"x":505,"y":570},{"x":505,"y":590,"onCurve":true},{"x":506,"y":626},{"x":545,"y":646},{"x":575,"y":621,"onCurve":true},{"x":605,"y":596},{"x":687,"y":529},{"x":775,"y":458},{"x":859,"y":390},{"x":892,"y":364,"onCurve":true},{"x":922,"y":339},{"x":923,"y":295},{"x":894,"y":272,"onCurve":true},{"x":864,"y":247},{"x":783,"y":184},{"x":696,"y":116},{"x":612,"y":50},{"x":580,"y":24,"onCurve":true},{"x":544,"y":-5},{"x":498,"y":10},{"x":499,"y":47,"onCurve":true},{"x":499,"y":71,"onCurve":true},{"x":499,"y":101,"onCurve":true},{"x":499,"y":116},{"x":498,"y":146},{"x":498,"y":158,"onCurve":true},{"x":498,"y":184},{"x":467,"y":197},{"x":440,"y":197,"onCurve":true},{"x":411,"y":197},{"x":314,"y":198},{"x":210,"y":198},{"x":112,"y":199},{"x":81,"y":199,"onCurve":true},{"x":68,"y":199},{"x":39,"y":204},{"x":15,"y":219},{"x":1,"y":246},{"x":1,"y":270,"onCurve":true},{"x":1,"y":297},{"x":0,"y":349}]];
3 |
--------------------------------------------------------------------------------
/src/editor/shapes/circle.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable*/
2 | export default [[{"x":383,"y":0},{"x":207,"y":75},{"x":75,"y":208},{"x":0,"y":384},{"x":0,"y":583},{"x":75,"y":760},{"x":207,"y":891},{"x":383,"y":966},{"x":582,"y":966},{"x":758,"y":891},{"x":890,"y":760},{"x":965,"y":583},{"x":965,"y":384},{"x":890,"y":208},{"x":758,"y":75},{"x":582,"y":0}]];
3 |
--------------------------------------------------------------------------------
/src/editor/shapes/drop.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable*/
2 | export default [[{"x":731,"y":526},{"x":674,"y":443,"onCurve":true},{"x":669,"y":437},{"x":589,"y":332},{"x":525,"y":242},{"x":446,"y":102},{"x":426,"y":41,"onCurve":true},{"x":421,"y":22},{"x":384,"y":0},{"x":347,"y":0},{"x":311,"y":22},{"x":305,"y":41,"onCurve":true},{"x":285,"y":102},{"x":206,"y":242},{"x":142,"y":332},{"x":62,"y":437},{"x":57,"y":443,"onCurve":true},{"x":0,"y":528},{"x":0,"y":621,"onCurve":true},{"x":0,"y":759},{"x":214,"y":953},{"x":517,"y":953},{"x":731,"y":759},{"x":731,"y":621,"onCurve":true}]];
3 |
--------------------------------------------------------------------------------
/src/editor/shapes/heart.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable*/
2 | export default [[{"x":578,"y":965},{"x":546,"y":965},{"x":535,"y":953,"onCurve":true},{"x":143,"y":576,"onCurve":true},{"x":137,"y":570},{"x":116,"y":549},{"x":68,"y":488},{"x":29,"y":425},{"x":0,"y":337},{"x":0,"y":295,"onCurve":true},{"x":0,"y":156},{"x":159,"y":0},{"x":300,"y":0,"onCurve":true},{"x":340,"y":0},{"x":419,"y":27},{"x":490,"y":74},{"x":539,"y":114},{"x":562,"y":137,"onCurve":true},{"x":585,"y":114},{"x":634,"y":74},{"x":705,"y":27},{"x":786,"y":0},{"x":824,"y":0,"onCurve":true},{"x":965,"y":0},{"x":1124,"y":156},{"x":1124,"y":295,"onCurve":true},{"x":1124,"y":433},{"x":981,"y":576,"onCurve":true},{"x":589,"y":953,"onCurve":true}]];
3 |
--------------------------------------------------------------------------------
/src/editor/shapes/rect.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable*/
2 | export default [[{"x":0,"y":0,"onCurve":true},{"x":200,"y":0,"onCurve":true},{"x":200,"y":200,"onCurve":true},{"x":0,"y":200,"onCurve":true}]];
3 |
--------------------------------------------------------------------------------
/src/editor/shapes/roundrect.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable*/
2 | export default [[{"x":615,"y":573,"onCurve":true},{"x":615,"y":591},{"x":591,"y":615},{"x":573,"y":615,"onCurve":true},{"x":42,"y":615,"onCurve":true},{"x":24,"y":615},{"x":14,"y":601,"onCurve":true},{"x":0,"y":591},{"x":0,"y":573,"onCurve":true},{"x":0,"y":42,"onCurve":true},{"x":0,"y":24},{"x":14,"y":14,"onCurve":true},{"x":24,"y":0},{"x":42,"y":0,"onCurve":true},{"x":573,"y":0,"onCurve":true},{"x":591,"y":0},{"x":601,"y":14,"onCurve":true},{"x":615,"y":24},{"x":615,"y":42,"onCurve":true},{"x":615,"y":573,"onCurve":true}]];
3 |
--------------------------------------------------------------------------------
/src/editor/shapes/star.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable*/
2 | export default [[{"x":756,"y":610,"onCurve":true},{"x":1009,"y":364,"onCurve":true},{"x":660,"y":315,"onCurve":true},{"x":504,"y":0,"onCurve":true},{"x":348,"y":315,"onCurve":true},{"x":0,"y":364,"onCurve":true},{"x":252,"y":610,"onCurve":true},{"x":193,"y":958,"onCurve":true},{"x":504,"y":793,"onCurve":true},{"x":815,"y":958,"onCurve":true}]];
3 |
--------------------------------------------------------------------------------
/src/editor/shapes/support.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 支持的自选形状
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import circle from './circle';
7 | import rect from './rect';
8 | import roundrect from './roundrect';
9 | import arrow from './arrow';
10 | import star from './star';
11 | import triangle from './triangle';
12 | import heart from './heart';
13 | import tel from './tel';
14 | import du from './du';
15 | import drop from './drop';
16 |
17 | export default {
18 | circle,
19 | rect,
20 | roundrect,
21 | arrow,
22 | star,
23 | triangle,
24 | heart,
25 | tel,
26 | du,
27 | drop
28 | };
29 |
--------------------------------------------------------------------------------
/src/editor/shapes/tel.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable*/
2 | export default [[{"x":91,"y":42,"onCurve":true},{"x":116,"y":26},{"x":154,"y":14,"onCurve":true},{"x":191,"y":0},{"x":200,"y":0,"onCurve":true},{"x":209,"y":7},{"x":225,"y":56,"onCurve":true},{"x":244,"y":102},{"x":258,"y":139,"onCurve":true},{"x":279,"y":193},{"x":323,"y":269},{"x":318,"y":285},{"x":297,"y":309,"onCurve":true},{"x":277,"y":332},{"x":232,"y":362},{"x":230,"y":385,"onCurve":true},{"x":223,"y":413},{"x":258,"y":480,"onCurve":true},{"x":293,"y":545},{"x":355,"y":610,"onCurve":true},{"x":423,"y":668},{"x":478,"y":694,"onCurve":true},{"x":536,"y":717},{"x":569,"y":719,"onCurve":true},{"x":580,"y":719},{"x":634,"y":663},{"x":655,"y":636,"onCurve":true},{"x":657,"y":631},{"x":692,"y":647,"onCurve":true},{"x":722,"y":666},{"x":782,"y":701,"onCurve":true},{"x":843,"y":738},{"x":887,"y":768,"onCurve":true},{"x":928,"y":796},{"x":933,"y":803,"onCurve":true},{"x":931,"y":835},{"x":882,"y":877,"onCurve":true},{"x":831,"y":921},{"x":780,"y":942,"onCurve":true},{"x":736,"y":960},{"x":634,"y":949},{"x":546,"y":916,"onCurve":true},{"x":441,"y":882},{"x":121,"y":612},{"x":45,"y":422,"onCurve":true},{"x":-11,"y":258},{"x":3,"y":186,"onCurve":true},{"x":14,"y":111},{"x":45,"y":84,"onCurve":true},{"x":56,"y":67},{"x":68,"y":58,"onCurve":true},{"x":77,"y":46}]];
3 |
--------------------------------------------------------------------------------
/src/editor/shapes/triangle.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable*/
2 | export default [[{"x":25,"y":871,"onCurve":true},{"x":431,"y":465,"onCurve":true},{"x":442,"y":454},{"x":442,"y":425},{"x":431,"y":414,"onCurve":true},{"x":25,"y":8,"onCurve":true},{"x":14,"y":-3},{"x":0,"y":4},{"x":0,"y":19,"onCurve":true},{"x":0,"y":860,"onCurve":true},{"x":0,"y":875},{"x":14,"y":882}]];
3 |
--------------------------------------------------------------------------------
/src/editor/util/cursor.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 光标集合
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | export default {
7 | scale: {
8 | 1: 'nw-resize',
9 | 2: 'ne-resize',
10 | 3: 'se-resize',
11 | 4: 'sw-resize',
12 | 5: 's-resize',
13 | 6: 'e-resize',
14 | 7: 'n-resize',
15 | 8: 'w-resize'
16 | },
17 | rotate: {
18 | 1: 'pointer',
19 | 2: 'pointer',
20 | 3: 'pointer',
21 | 4: 'pointer',
22 | 5: 'e-resize',
23 | 6: 's-resize',
24 | 7: 'w-resize',
25 | 8: 'n-resize'
26 | }
27 | };
28 |
--------------------------------------------------------------------------------
/src/editor/util/getFontHash.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 获取font的hashcode
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | /**
7 | * 获取font的hashcode用于比较font是否被编辑过
8 | *
9 | * @param {Object} font font结构
10 | * @param {Array} font.contours 轮廓数组
11 | * @param {Array} font.unicode unicode编码点
12 | * @param {number} font.advanceWidth 推荐宽度
13 | * @param {number} font.xMin xMin
14 | * @param {number} font.xMax xMax
15 | * @param {number} font.yMin yMin
16 | * @param {number} font.yMax yMax
17 | *
18 | * @return {number} hashcode
19 | */
20 | export default function getFontHash(font) {
21 |
22 | let splice = Array.prototype.splice;
23 | let sequence = [
24 | font.advanceWidth || 0
25 | ];
26 |
27 | // contours
28 | if (font.contours && font.contours.length) {
29 | font.contours.forEach(function (contour) {
30 | contour.forEach(function (p) {
31 | sequence.push(p.x);
32 | sequence.push(p.y);
33 | sequence.push(p.onCurve ? 1 : 0);
34 | });
35 | });
36 | }
37 |
38 | if (font.unicode && font.unicode.length) {
39 | splice.apply(sequence, [sequence.length, 0].concat(font.unicode));
40 | }
41 |
42 | if (font.name && font.name.length) {
43 | splice.apply(
44 | sequence,
45 | [sequence.length, 0].concat(font.name.split('').map(function (c) {
46 | return c.charCodeAt(0);
47 | }))
48 | );
49 | }
50 |
51 | // 使用BKDR算法计算哈希
52 | // http://www.cnblogs.com/uvsjoh/archive/2012/03/27/2420120.html
53 | let hash = 0;
54 | for (let i = 0, l = sequence.length; i < l; i++) {
55 | hash = 0x7FFFFFFF & (hash * 131 + sequence[i]);
56 | }
57 |
58 | return hash;
59 | }
60 |
--------------------------------------------------------------------------------
/src/editor/widget/GraduationMarker.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 刻度指示
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | export default class GraduationMarker {
7 |
8 | /**
9 | * 刻度指示
10 | *
11 | * @constructor
12 | * @param {HTMLElement} main 主元素
13 | * @param {Object} options 选项参数
14 | */
15 | constructor(main, options) {
16 | options = options || {};
17 | let xAxis = document.createElement('div');
18 | xAxis.className = 'marker-x';
19 | let yAxis = document.createElement('div');
20 | yAxis.className = 'marker-y';
21 |
22 | if (options.thickness) {
23 | xAxis.style.width = options.thickness + 'px';
24 | yAxis.style.height = options.thickness + 'px';
25 | }
26 |
27 | main.appendChild(this.xAxis = xAxis);
28 | main.appendChild(this.yAxis = yAxis);
29 | }
30 |
31 | /**
32 | * 显示坐标
33 | *
34 | * @param {number} x x坐标
35 | * @param {number} y y坐标
36 | */
37 | moveTo(x, y) {
38 | this.xAxis.style.top = y + 'px';
39 | this.yAxis.style.left = x + 'px';
40 | }
41 |
42 | /**
43 | * 注销
44 | */
45 | dispose() {
46 | this.xAxis.parentNode.removeChild(this.xAxis);
47 | this.yAxis.parentNode.removeChild(this.yAxis);
48 | this.xAxis = this.yAxis = null;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/editor/widget/clipboard.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 剪切板
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | const storage = window.localStorage;
7 | const storageName = 'clipboard.default';
8 |
9 | export default {
10 |
11 | /**
12 | * 设置clipboard
13 | *
14 | * @param {Object} data 设置的数据
15 | * @param {string} type 数据类型
16 | */
17 | set(data, type) {
18 | storage.setItem(storageName, JSON.stringify({
19 | type: type || -9999,
20 | data: data
21 | }));
22 | },
23 |
24 | /**
25 | * 获取clipboard
26 | *
27 | * @param {string} type 数据类型
28 | * @return {?Object}
29 | */
30 | get(type) {
31 | let data = storage.getItem(storageName);
32 | if (null !== data) {
33 | data = JSON.parse(data);
34 | if (data.type === type) {
35 | // storage.removeItem(storageName);
36 | return data.data;
37 | }
38 | }
39 |
40 | return null;
41 | },
42 |
43 | /**
44 | * 清空
45 | */
46 | clear() {
47 | storage.removeItem(storageName);
48 | }
49 | };
50 |
--------------------------------------------------------------------------------
/src/fonteditor/config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 相关配置
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | export default {
7 | // 在线地址读取接口
8 | readOnline: location.hostname.indexOf('baidu.com') >= 0
9 | ? '/font/proxy?type=${0}&url=${1}'
10 | : './php/readOnline.php?type=${0}&file=${1}',
11 |
12 | // 用于form同步的代理页面地址
13 | proxyUrl: (function () {
14 | let a = document.createElement('a');
15 | a.href = 'proxy.html';
16 | return a.href;
17 | })()
18 | };
19 |
--------------------------------------------------------------------------------
/src/fonteditor/dialog/colorpicker.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 颜色选择器
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | const defaultOptions = {
7 | customBG: '#222',
8 | margin: '5px -2px 0',
9 | doRender: 'div div',
10 | cssAddon: // could also be in a css file instead
11 | '.cp-color-picker{border:1px solid #999; padding:10px 10px 0;'
12 | + 'background:#eee; overflow:visible; border-radius:3px;}'
13 | + '.cp-color-picker:after{content:""; display:block; '
14 | + 'position:absolute; top:-15px; left:12px; border:8px solid #eee;'
15 | + 'border-color: transparent transparent #eee}'
16 | // simulate border...
17 | + '.cp-color-picker:before{content:""; display:block; '
18 | + 'position:absolute; top:-16px; left:12px; border:8px solid #eee;'
19 | + 'border-color: transparent transparent #999}'
20 | + '.cp-xy-slider:active {cursor:none;}'
21 | + '.cp-xy-slider{border:1px solid #999; margin-bottom:10px;}'
22 | + '.cp-xy-cursor{width:12px; height:12px; margin:-6px}'
23 | + '.cp-z-slider{margin-left:10px; border:1px solid #999;}'
24 | + '.cp-z-cursor{border-width:5px; margin-top:-5px;}'
25 | + '.cp-color-picker .cp-alpha{margin:10px 0 0; height:6px; border-radius:6px;'
26 | + 'overflow:visible; border:1px solid #999; box-sizing:border-box;'
27 | + 'background: linear-gradient(to right, rgba(238,238,238,1) 0%,rgba(238,238,238,0) 100%);}'
28 | + '.cp-color-picker .cp-alpha{margin:10px 0}'
29 | + '.cp-alpha-cursor{background: #eee; border-radius: 100%;'
30 | + 'width:14px; height:14px; margin:-5px -7px; border:1px solid #666!important;'
31 | + 'box-shadow:inset -2px -4px 3px #ccc}',
32 | renderCallback(e, toggle) {
33 | if (false === toggle) {
34 | this.$trigger.trigger('change');
35 | }
36 | }
37 | };
38 |
39 |
40 | export default {
41 | show(element, options) {
42 | let picker = $(element).colorPicker($.extend({}, defaultOptions, options));
43 | return picker;
44 | }
45 | };
46 |
--------------------------------------------------------------------------------
/src/fonteditor/dialog/font-online.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 在线字体列表
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import string from 'common/string';
7 | import i18n from '../i18n/i18n';
8 | import setting from './setting';
9 | import onlineList from '../data/online-font';
10 |
11 | export default setting.derive({
12 |
13 | title: i18n.lang.dialog_onlinefont,
14 | nofooter: true,
15 |
16 | getTpl() {
17 |
18 | let str = '';
29 |
30 | return str;
31 | },
32 |
33 | set() {
34 | let me = this;
35 | let dialog = this.getDialog();
36 | dialog.find('.list-group').on('click', '.list-group-item', function (e) {
37 | e.preventDefault();
38 | e.stopPropagation();
39 | let url = $(this).attr('data-url');
40 | dialog.find('.list-group').off('click', '.list-group-item');
41 | me.options.onChange && me.options.onChange.call(this, decodeURIComponent(url));
42 | $('#model-dialog').modal('hide');
43 | });
44 | }
45 | });
46 |
--------------------------------------------------------------------------------
/src/fonteditor/dialog/font-url.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 读取线上字体
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import i18n from '../i18n/i18n';
7 | import setting from './setting';
8 |
9 | const tpl = ''
10 | + ''
11 | + '' + i18n.lang.dialog_fonturl + ''
12 | + ''
13 | + '
';
14 |
15 | export default setting.derive({
16 |
17 | title: i18n.lang.dialog_fonturl,
18 |
19 | getTpl() {
20 | return tpl;
21 | },
22 |
23 | validate() {
24 | let setting = this.getFields();
25 | if (setting.url) {
26 | return setting.url;
27 | }
28 | }
29 | });
30 |
31 |
--------------------------------------------------------------------------------
/src/fonteditor/dialog/setting-adjust-glyf.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 设置调整字形
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import i18n from '../i18n/i18n';
7 | import setting from './setting';
8 |
9 | export default setting.derive({
10 |
11 | title: i18n.lang.dialog_adjust_glyph,
12 |
13 | getTpl() {
14 | return require('../template/dialog/setting-adjust-glyf.tpl');
15 | },
16 |
17 | set(setting) {
18 | this.setFields(setting || {});
19 | },
20 |
21 | validate() {
22 | let setting = this.getFields();
23 |
24 | if (setting.reverse === undefined
25 | && setting.mirror === undefined
26 | && setting.scale === undefined
27 | && setting.ajdustToEmBox === undefined
28 | ) {
29 | alert(i18n.lang.dialog_no_input);
30 | return false;
31 | }
32 | return setting;
33 | }
34 |
35 | });
36 |
--------------------------------------------------------------------------------
/src/fonteditor/dialog/setting-adjust-pos.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 设置自动调整字形位置
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 | import i18n from '../i18n/i18n';
6 | import setting from './setting';
7 |
8 | export default setting.derive({
9 |
10 | title: i18n.lang.dialog_adjust_pos,
11 |
12 | getTpl() {
13 | return require('../template/dialog/setting-adjust-pos.tpl');
14 | },
15 |
16 | set(setting) {
17 | this.setFields(setting || {});
18 | },
19 |
20 | validate() {
21 | let setting = this.getFields();
22 |
23 | if (setting.leftSideBearing === undefined
24 | && setting.rightSideBearing === undefined
25 | && setting.verticalAlign === undefined
26 | ) {
27 | alert(i18n.lang.dialog_no_input);
28 | return false;
29 | }
30 |
31 | return setting;
32 | }
33 |
34 | });
35 |
36 |
--------------------------------------------------------------------------------
/src/fonteditor/dialog/setting-editor.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 编辑器设置选项
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 |
7 | import i18n from '../i18n/i18n';
8 | import setting from './setting';
9 | import lang from 'common/lang';
10 | import program from '../widget/program';
11 |
12 | export default setting.derive({
13 |
14 | title: i18n.lang.dialog_editor_setting,
15 |
16 | getTpl() {
17 | return require('../template/dialog/setting-editor.tpl');
18 | },
19 |
20 | set(setting) {
21 | this.setting = lang.clone(setting);
22 | this.setFields(this.setting);
23 | let me = this;
24 | $('#setting-editor-default').on('click', function (e) {
25 | e.preventDefault();
26 | me.setting = program.setting.getDefault('editor');
27 | me.setFields(me.setting);
28 | me.oldSetting = null;
29 | });
30 | },
31 | onDispose() {
32 | $('#setting-editor-default').off('click');
33 | },
34 | validate() {
35 | return this.getFields(lang.clone(this.setting));
36 | }
37 |
38 | });
39 |
--------------------------------------------------------------------------------
/src/fonteditor/dialog/setting-glyf.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 设置自动调整字形位置
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import i18n from '../i18n/i18n';
7 | import setting from './setting';
8 | import stringUtil from 'fonteditor-core/ttf/util/string';
9 | const unicodeREG = /^(?:\$[A-F0-9]+)(?:\,\$[A-F0-9]+)*$/gi;
10 |
11 | export default setting.derive({
12 |
13 | title: i18n.lang.dialog_glyph_info,
14 |
15 | getTpl() {
16 | return require('../template/dialog/setting-glyf.tpl');
17 | },
18 |
19 | set(setting) {
20 | $('#setting-glyf-unicode').on('blur', function (e) {
21 | let val = $(this).val();
22 | let ctlGlyfName = $('#setting-glyf-name');
23 | if (!ctlGlyfName.val()) {
24 | if (val.match(unicodeREG)) {
25 | val = Number('0x' + val.split(',')[0].slice(1));
26 | }
27 | else if (val) {
28 | val = val.charCodeAt(0);
29 | }
30 | ctlGlyfName.val(stringUtil.getUnicodeName(val));
31 | }
32 | });
33 | this.setFields(setting || {});
34 | },
35 | onDispose() {
36 | $('#setting-glyf-unicode').off('blur');
37 | },
38 | validate() {
39 |
40 | let setting = this.getFields();
41 |
42 | if (setting.leftSideBearing === undefined
43 | && setting.rightSideBearing === undefined
44 | && setting.unicode === undefined
45 | && setting.name === undefined
46 | ) {
47 | alert(i18n.lang.dialog_no_input);
48 | return false;
49 | }
50 |
51 | return setting;
52 | }
53 | });
54 |
--------------------------------------------------------------------------------
/src/fonteditor/dialog/setting-ie.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 导入和导出设置选项
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import i18n from '../i18n/i18n';
7 | import setting from './setting';
8 |
9 | import tpl from '../template/dialog/setting-ie.tpl';
10 | import lang from 'common/lang';
11 | import program from '../widget/program';
12 |
13 | export default setting.derive({
14 |
15 | title: i18n.lang.dialog_import_and_export,
16 |
17 | getTpl() {
18 | return tpl;
19 | },
20 |
21 | set(setting) {
22 | this.setting = lang.clone(setting);
23 | this.setFields(this.setting);
24 | let me = this;
25 | $('#setting-ie-default').on('click', function (e) {
26 | e.preventDefault();
27 | me.setting = program.setting.getDefault('ie');
28 | me.setFields(me.setting);
29 | me.oldSetting = null;
30 | });
31 | },
32 | onDispose() {
33 | $('#setting-ie-default').off('click');
34 | },
35 | validate() {
36 | let setting = this.getFields(lang.clone(this.setting));
37 | return setting;
38 | }
39 |
40 | });
41 |
--------------------------------------------------------------------------------
/src/fonteditor/dialog/setting-name.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 设置字体命名信息
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import i18n from '../i18n/i18n';
7 | import setting from './setting';
8 |
9 | export default setting.derive({
10 |
11 | title: i18n.lang.fontinfo,
12 |
13 | getTpl() {
14 | return require('../template/dialog/setting-name.tpl');
15 | },
16 |
17 | set(setting) {
18 | this.setFields(setting);
19 | },
20 |
21 | validate() {
22 | let setting = this.getFields();
23 | return setting;
24 | }
25 | });
26 |
--------------------------------------------------------------------------------
/src/fonteditor/dialog/setting-sync.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 同步字体设置
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import i18n from '../i18n/i18n';
7 | import setting from './setting';
8 |
9 | export default setting.derive({
10 |
11 | title: i18n.lang.syncfont,
12 |
13 | getTpl() {
14 | return require('../template/dialog/setting-sync.tpl');
15 | },
16 |
17 | set(setting) {
18 | this.setFields(setting || {});
19 | this.newProject = setting.newProject;
20 | let me = this;
21 | $('#setting-sync-cancel').on('click', function () {
22 | me.hide(0);
23 | });
24 | },
25 |
26 | onDispose() {
27 | $('#setting-sync-cancel').off('click');
28 | },
29 |
30 | validate() {
31 | let setting = this.getFields();
32 |
33 | if (!setting.name) {
34 | alert(i18n.lang.dialog_alert_set_sync_name);
35 | return false;
36 | }
37 |
38 | if (!setting.url && !setting.pushUrl) {
39 | alert(i18n.lang.dialog_alert_set_url_or_syncurl);
40 | return false;
41 | }
42 |
43 | if (this.newProject && !setting.url) {
44 | alert(i18n.lang.dialog_alert_set_sync_url);
45 | return false;
46 | }
47 |
48 | if (!setting.woff && !setting.ttf && !setting.svg && !setting.eot) {
49 | alert(i18n.lang.dialog_alert_set_filetype);
50 | return false;
51 | }
52 |
53 | return setting;
54 | }
55 | });
56 |
--------------------------------------------------------------------------------
/src/fonteditor/dialog/setting-unicode.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 设置代码点
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import i18n from '../i18n/i18n';
7 | import setting from './setting';
8 |
9 | const tpl = ''
10 | + ''
23 | + '';
31 |
32 | export default setting.derive({
33 |
34 | title: i18n.lang.dialog_unicode_set,
35 |
36 | getTpl() {
37 | return tpl;
38 | },
39 |
40 | validate() {
41 | let unicode = $('#setting-text-unicode').val();
42 | if (unicode.match(/^\$[A-F0-9]+$/i)) {
43 | return (this.setting = {
44 | unicode: unicode,
45 | isGenerateName: $('#setting-text-unicode-name').is(':checked')
46 | });
47 | }
48 |
49 | alert('代码点设置不正确');
50 | return false;
51 | }
52 | });
53 |
--------------------------------------------------------------------------------
/src/fonteditor/dialog/support.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 支持的设置项目
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import unicode from '../dialog/setting-unicode';
7 | import name from '../dialog/setting-name';
8 | import adjustpos from '../dialog/setting-adjust-pos';
9 | import adjustglyf from '../dialog/setting-adjust-glyf';
10 | import metrics from '../dialog/setting-metrics';
11 | import online from '../dialog/font-online';
12 | import url from '../dialog/font-url';
13 | import glyf from '../dialog/setting-glyf';
14 | import editor from '../dialog/setting-editor';
15 | import findglyf from '../dialog/setting-find-glyf';
16 | import ie from '../dialog/setting-ie';
17 | import importpic from '../dialog/setting-import-pic';
18 | import sync from '../dialog/setting-sync';
19 | import glyfdownload from '../dialog/glyf-download';
20 |
21 | export default {
22 | unicode,
23 | name,
24 | 'adjust-pos': adjustpos,
25 | 'adjust-glyf': adjustglyf,
26 | metrics,
27 | online,
28 | url,
29 | glyf,
30 | editor,
31 | 'find-glyf': findglyf,
32 | ie,
33 | 'import-pic': importpic,
34 | sync,
35 | 'glyf-download': glyfdownload
36 | };
37 |
--------------------------------------------------------------------------------
/src/fonteditor/i18n/i18n.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 语言字符串管理
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 |
7 | import I18n from 'common/I18n';
8 |
9 | import zhcneditor from './zh-cn/editor';
10 | import enuseditor from './en-us/editor';
11 |
12 | import zhcnmessage from './zh-cn/message';
13 | import enusmessage from './en-us/message';
14 |
15 | import zhcndialog from './zh-cn/dialog';
16 | import enusdialog from './en-us/dialog';
17 |
18 | export default new I18n(
19 | [
20 | ['zh-cn', zhcneditor],
21 | ['en-us', enuseditor],
22 |
23 | ['zh-cn', zhcnmessage],
24 | ['en-us', enusmessage],
25 |
26 | ['zh-cn', zhcndialog],
27 | ['en-us', enusdialog]
28 | ],
29 | window.language
30 | );
31 |
--------------------------------------------------------------------------------
/src/fonteditor/i18n/zh-cn/editor.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file editor.js
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | export default {
7 | glyph_name: '命名',
8 | left_side_bearing: '左边距',
9 | right_side_bearing: '右边距',
10 | baseline_offset: '基线偏移',
11 | flip: '翻转',
12 | mirror: '镜像',
13 |
14 | scale: '按比例缩放',
15 | findglyf: '查找字形',
16 | downloadglyf: '导出字形',
17 | setunicode: '设置代码点',
18 | del: '删除',
19 | edit: '编辑',
20 | resume: '恢复',
21 | prevpage: '上一页',
22 | nextpage: '下一页',
23 | gotopage: '转到',
24 |
25 | saveas: '另存为',
26 | sync: '同步',
27 | syncfont: '同步字体',
28 | cancelsync: '取消同步',
29 | autosync: '自动同步',
30 | fonttype: '字体类型',
31 | remoteurl: '远程地址',
32 | fontname: '字体名称',
33 | fontinfo: '字体信息',
34 | ascent: '上升',
35 | descent: '下降',
36 | linegap: '行间距',
37 | usWinAscent: 'win上升',
38 | usWinDescent: 'win下降',
39 | calc: '计算',
40 | sTypoAscender: 'typo上升',
41 | sTypoDescender: 'typo下降',
42 | sTypoLineGap: 'typo间距',
43 | sxHeight: 'x高度',
44 | sCapHeight: '大写H高度',
45 | yStrikeoutPosition: '删除线位置',
46 | yStrikeoutSize: '删除线厚度',
47 | underlinePosition: '下划线位置',
48 | underlineThickness: '下划线厚度',
49 | ySubscriptXSize: '下标水平',
50 | ySubscriptYSize: '下标垂直',
51 | ySubscriptXOffset: '下标X偏移',
52 | ySubscriptYOffset: '下标Y偏移',
53 | ySuperscriptXSize: '上标水平',
54 | ySuperscriptYSize: '上标垂直',
55 | ySuperscriptXOffset: '上标X偏移',
56 | ySuperscriptYOffset: '上标Y偏移',
57 | achVendID: '供应商ID',
58 | usWeightClass: '粗细',
59 | usWidthClass: '宽度',
60 | panose: 'panose',
61 |
62 | fontFamily: '字体家族',
63 | fontSubFamily: '子字体家族',
64 | fullName: '完整字体名',
65 | uniqueSubFamily: '唯一字体识别名',
66 | version: '版本',
67 | postScriptName: 'PostScript名称',
68 | unitsPerEm: 'em框大小',
69 | lowestRecPPEM: '最小可读尺寸',
70 | created: '创建日期',
71 | modified: '修改日期',
72 | setting: '设置',
73 | help: '帮助',
74 | confirm: '确定',
75 | cancel: '取消',
76 | pushurl: '推送地址'
77 | };
78 |
--------------------------------------------------------------------------------
/src/fonteditor/i18n/zh-cn/message.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 消息提示
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | export default {
7 | msg_not_support_file_type: '不支持的文件类型!',
8 | msg_loading_pic: '正在加载图片...',
9 | msg_read_pic_error: '读取图片失败...',
10 | msg_processing: '正在处理...',
11 | msg_input_pic_url: '请输入图片URL!',
12 | msg_no_glyph_to_import: '没有找到可导入的字形!',
13 | msg_error_read_file: '读取文件出错!',
14 | msg_loading: '正在加载...',
15 | msg_confirm_del_proj: '是否删除项目?',
16 | msg_not_set_sync_info: '没有设置同步信息!',
17 | msg_no_sync_font: '没有要同步的字体!',
18 | msg_repeat_unicode: '重复的unicode代码点,字形序号:',
19 | msg_confirm_del_glyph: '确定删除字形么?',
20 | msg_read_file_error: '加载文件错误!',
21 | msg_syncing: '正在同步...',
22 | msg_sync_success: '同步成功...',
23 | msg_sync_failed: '同步失败:',
24 | msg_confirm_save_proj: '是否放弃保存当前编辑的项目?',
25 | msg_save_success: '保存成功...',
26 | msg_save_failed: '保存失败...',
27 | msg_input_proj_name: '请输入项目名称:',
28 | msg_confirm_gen_names: '生成的字形名称会覆盖原来的名称,确定生成?',
29 | msg_not_support_compound_glyf: '暂不支持复合字形!',
30 | msg_transform_compound_glyf: '是否转换复合字形为简单字形?',
31 | msg_confirm_save_glyph: '是否放弃保存当前编辑的字形?',
32 | msg_no_related_glhph: '未找到相关字形!',
33 | msg_error_open_proj: '打开项目失败,是否删除项目?',
34 | msg_error_del_proj: '删除项目失败,请刷新页面后删除!',
35 | msg_no_sort_glyf: '没有要排序的字形!',
36 | msg_has_compound_glyf_sort: '包含复合字形,无法进行排序',
37 |
38 |
39 | preview_title: '预览{%=fontFormat%}格式字体',
40 | preview_first_step: '第一步:使用font-face声明字体',
41 | preview_second_step: '第二步:定义使用{%=fontFamily%}的样式',
42 | preview_third_step: '第三步:挑选相应图标并获取字体编码,应用于页面',
43 |
44 | msg_error_sync_font: '无法获取同步字体!',
45 | msg_error_sync_font_address: '字体同步地址不可用!',
46 | msg_has_new_font_version: '字体`${fontName}`有新版本,是否同步新版本?',
47 | msg_error_sync_font_version: '同步新版本出错!'
48 | };
49 |
--------------------------------------------------------------------------------
/src/fonteditor/menu/viewer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file glyf列表相关命令
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import ei18n from 'editor/i18n/i18n';
7 | import i18n from '../i18n/i18n';
8 | export default [
9 | {
10 | name: 'copy',
11 | title: ei18n.lang.copy,
12 | quickKey: 'C',
13 | disabled: true
14 | },
15 | {
16 | name: 'cut',
17 | title: ei18n.lang.cut,
18 | quickKey: 'X'
19 | },
20 | {
21 | name: 'paste',
22 | title: ei18n.lang.paste,
23 | quickKey: 'V'
24 | },
25 | {
26 | name: 'del',
27 | title: ei18n.lang.del,
28 | quickKey: 'D',
29 | disabled: true
30 | },
31 | {
32 | type: 'split'
33 | },
34 | {
35 | name: 'adjust-pos',
36 | title: ei18n.lang.adjustpos
37 | },
38 | {
39 | name: 'adjust-glyf',
40 | title: ei18n.lang.adjustglyf
41 | },
42 | {
43 | name: 'setting-font',
44 | title: ei18n.lang.fontsetting,
45 | disabled: true
46 | },
47 | {
48 | type: 'split'
49 | },
50 | {
51 | name: 'find-glyf',
52 | title: i18n.lang.findglyf
53 | },
54 | {
55 | name: 'download-glyf',
56 | title: i18n.lang.downloadglyf
57 | },
58 | {
59 | type: 'split'
60 | },
61 | {
62 | name: 'setting-unicode',
63 | title: i18n.lang.setunicode
64 | },
65 | {
66 | name: 'setting-sync',
67 | title: i18n.lang.syncfont
68 | }
69 | ];
70 |
--------------------------------------------------------------------------------
/src/fonteditor/setting/editor.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 默认的FontEditor设置
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import editorOptions from 'editor/options';
7 | const editorDefault = editorOptions.editor;
8 |
9 | export default{
10 |
11 | saveSetting: true, // 是否保存setting
12 |
13 | // 查看器选项
14 | viewer: {
15 | color: '', // 查看器颜色
16 | shapeSize: 'normal', // 字形大小
17 | pageSize: 100 // 翻页大小
18 | },
19 |
20 | // 编辑器选项
21 | // see : editor/options.editor
22 | editor: {
23 | sorption: {
24 | enableGrid: false,
25 | enableShape: true
26 | },
27 | fontLayer: {
28 | strokeColor: editorDefault.fontLayer.strokeColor,
29 | fill: true,
30 | fillColor: editorDefault.fontLayer.fillColor
31 | },
32 | referenceline: {
33 | style: {
34 | strokeColor: editorDefault.referenceline.style.strokeColor
35 | }
36 | },
37 | axis: {
38 | showGrid: true,
39 | gapColor: editorDefault.axis.gapColor,
40 | metricsColor: editorDefault.axis.metricsColor,
41 | graduation: {
42 | gap: editorDefault.axis.graduation.gap
43 | }
44 | }
45 | }
46 | };
47 |
--------------------------------------------------------------------------------
/src/fonteditor/setting/ie.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 导入和导出设置
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | export default {
7 |
8 | 'saveSetting': true, // 是否保存setting
9 |
10 | // 导入
11 | 'import': {
12 | combinePath: true // 导入svg文件时合并`path`标签
13 | },
14 |
15 | // 导出
16 | 'export': {
17 | saveWithGlyfName: true // 导出字体时保存字形的名字
18 | }
19 | };
20 |
--------------------------------------------------------------------------------
/src/fonteditor/setting/support.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 支持的setting集合
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import editor from './editor';
7 | import ie from './ie';
8 |
9 | export default {
10 | editor,
11 | ie
12 | };
13 |
--------------------------------------------------------------------------------
/src/fonteditor/template/dialog/glyf-download.tpl:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
27 |
28 |
--------------------------------------------------------------------------------
/src/fonteditor/template/dialog/setting-adjust-glyf.tpl:
--------------------------------------------------------------------------------
1 |
9 |
17 |
23 |
39 |
--------------------------------------------------------------------------------
/src/fonteditor/template/dialog/setting-adjust-pos.tpl:
--------------------------------------------------------------------------------
1 |
7 |
13 |
19 |
--------------------------------------------------------------------------------
/src/fonteditor/template/dialog/setting-glyf.tpl:
--------------------------------------------------------------------------------
1 |
8 |
14 |
20 |
26 |
--------------------------------------------------------------------------------
/src/fonteditor/template/dialog/setting-ie.tpl:
--------------------------------------------------------------------------------
1 |
11 |
12 |
22 |
23 |
30 |
--------------------------------------------------------------------------------
/src/fonteditor/template/export-render.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file html渲染器
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import utpl from 'utpl';
7 | import previewTpl from 'css/preview.lesstpl';
8 | let fontExampleRender = null; // 图标示例渲染器
9 | let fontCssRender = null; // 图标css渲染器
10 | let symbolExampleRender = null; // symbol渲染器
11 |
12 | export default {
13 |
14 | /**
15 | * 渲染图标示例
16 | *
17 | * @param {Object} iconData 图标数据
18 | * @return {string} html片段
19 | */
20 | renderFontExample(iconData) {
21 | fontExampleRender = fontExampleRender || utpl.template(require('./export/icon-example.tpl'));
22 | return fontExampleRender(iconData);
23 | },
24 |
25 | /**
26 | * 渲染symbol图标示例
27 | *
28 | * @param {Object} iconData 图标数据
29 | * @return {string} html片段
30 | */
31 | renderSymbolExample(iconData) {
32 | symbolExampleRender = symbolExampleRender || utpl.template(require('./export/symbol-example.tpl'));
33 | return symbolExampleRender(iconData);
34 | },
35 |
36 | /**
37 | * 渲染图标css
38 | *
39 | * @param {Object} iconData 图标数据
40 | * @return {string} html片段
41 | */
42 | renderFontCss(iconData) {
43 | fontCssRender = fontCssRender || utpl.template(require('./export/icon-css.tpl'));
44 | return fontCssRender(iconData);
45 | },
46 |
47 | /**
48 | * 渲染预览css
49 | *
50 | * @return {string} html片段
51 | */
52 | renderPreviewCss() {
53 | return previewTpl.toString();
54 | }
55 | };
56 |
--------------------------------------------------------------------------------
/src/fonteditor/template/export/icon-css.tpl:
--------------------------------------------------------------------------------
1 | /**
2 | * @file icon.css
3 | */
4 |
5 | @font-face {
6 | font-family: "{%=fontFamily%}";
7 | src: url("{%=fontFamily%}.eot"); /* IE9 */
8 | src: url("{%=fontFamily%}.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */
9 | url("{%=fontFamily%}.woff2") format("woff2"), /* chrome、firefox、opera、Safari, Android, iOS */
10 | url("{%=fontFamily%}.woff") format("woff"), /* chrome、firefox */
11 | url("{%=fontFamily%}.ttf") format("truetype"), /* chrome、firefox、opera、Safari, Android, iOS 4.2+ */
12 | url("{%=fontFamily%}.svg#uxfonteditor") format("svg"); /* iOS 4.1- */
13 | }
14 |
15 |
16 | .{%=iconPrefix%} {
17 | font-family: "{%=fontFamily%}" !important;
18 | speak: none;
19 | font-style: normal;
20 | font-weight: normal;
21 | font-variant: normal;
22 | text-transform: none;
23 | line-height: 1;
24 | -webkit-font-smoothing: antialiased;
25 | -moz-osx-font-smoothing: grayscale;
26 | }
27 |
28 | {% _.each(glyfList, function(glyf) { %}
29 | .icon-{%=glyf.name%}:before {
30 | content: "{%=glyf.codeName%}";
31 | }
32 | {% }); %}
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/fonteditor/template/export/icon-example.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | icon example
6 |
7 |
8 |
9 |
10 |
11 |
{%=fontFamily%} example
12 |
13 | {%_.each(glyfList, function(glyf) {%}
14 | -
15 |
16 |
{%=glyf.codeName%}
17 | {%=glyf.name%}
18 |
19 | {%});%}
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/fonteditor/template/export/symbol-example.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | symbol example
6 |
7 |
19 |
20 |
21 |
22 | {%=symbolText%}
23 |
24 |
{%=fontFamily%} symbol example
25 |
26 | {%_.each(glyfList, function(glyf) {%}
27 | -
28 |
29 |
symbol
30 | {%=glyf.id%}
31 |
32 | {%});%}
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/fonteditor/template/preview-render.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 预览渲染器
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 |
7 | import string from 'common/string';
8 | import i18n from '../i18n/i18n';
9 | import utpl from 'utpl';
10 | import exportRender from './export-render';
11 | let previewRender = null; // 预览渲染器
12 |
13 | export default {
14 |
15 | /**
16 | * 渲染预览页面
17 | *
18 | * @param {Object} data 预览页渲染数据
19 | * @param {Object} data.fontData 字体数据
20 | * @param {Object} data.fontFormat 字体格式
21 | *
22 | * @return {string} html片段
23 | */
24 | renderPreview(data) {
25 | data.previewCss = exportRender.renderPreviewCss();
26 | let tpl = string.format(require('./export/preview-ttf.tpl'), i18n);
27 | previewRender = previewRender || utpl.template(tpl);
28 | return previewRender(data);
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/src/fonteditor/widget/loading.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 加载提示组件
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import i18n from '../i18n/i18n';
7 |
8 | /**
9 | * 提示
10 | *
11 | * @type {Object}
12 | */
13 | const loading = {
14 |
15 | /**
16 | * 显示提示框
17 | *
18 | * @param {string} text 显示文字
19 | * @param {number} duration 显示时间
20 | * @param {string} status 显示的状态
21 | * @return {this}
22 | */
23 | show(text, duration, status) {
24 |
25 | clearTimeout(this.showtimer);
26 | let loading = $('#loading');
27 | loading.attr('data-status', status || '')
28 | .find('span')
29 | .html(text || i18n.lang.msg_loading);
30 | loading.show();
31 |
32 | if (duration) {
33 | this.showtimer = setTimeout(this.hide, duration);
34 | }
35 |
36 | return this;
37 | },
38 |
39 | /**
40 | * 显示错误提示框
41 | *
42 | * @param {string} text 显示文字
43 | * @param {number} duration 显示时间
44 | * @return {this}
45 | */
46 | error(text, duration) {
47 | this.show(text, duration, 'error');
48 | return this;
49 | },
50 |
51 | /**
52 | * 显示警告提示框
53 | *
54 | * @param {string} text 显示文字
55 | * @param {number} duration 显示时间
56 | * @return {this}
57 | */
58 | warn(text, duration) {
59 | this.show(text, duration, 'warn');
60 | return this;
61 | },
62 |
63 | /**
64 | * 隐藏
65 | */
66 | hide() {
67 | $('#loading').hide();
68 | }
69 | };
70 |
71 | export default loading;
--------------------------------------------------------------------------------
/src/fonteditor/widget/sync-status.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 同步状态集合
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | export default {
7 | // 1 ~ 512 用来记录当前同步的状态,如是否支持拉取更新,是否支持推送
8 | serviceNotAvailable: 0x1, // 服务不可用
9 | pullNoResponse: 0x2, // 拉取不响应
10 | pushNoResponse: 0x4, // 推送不响应
11 |
12 | // 1000 以上,解析相关
13 | parseDataError: 1001, // 解析数据错误
14 | parseFontError: 1002, // 解析字体错误
15 | noHasNew: 1003, // 无更新记录
16 | cancelSync: 1004 // 取消更新记录
17 | };
18 |
--------------------------------------------------------------------------------
/src/fonteditor/widget/util/download.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file chrome下载
3 | * 由于浏览器限制,需要注意调用的时候需要在一次交互内,例如`click`等
4 | *
5 | * @author mengke01(kekee000@gmail.com)
6 | */
7 |
8 | /**
9 | * chrome下载
10 | *
11 | * @param {string} fileName 文件名
12 | * @param {string} base64Str base64字符串
13 | */
14 | export default function download(fileName, base64Str) {
15 | let a = document.createElement('a');
16 | a.download = fileName;
17 | a.href = base64Str;
18 | a.addEventListener('click', function () {
19 | a.remove();
20 | });
21 | document.body.appendChild(a);
22 | if (a.click) {
23 | a.click();
24 | }
25 | else {
26 | let event = document.createEvent('MouseEvents');
27 | event.initMouseEvent('click',
28 | true, true, document.defaultView,
29 | 0, 0, 0, 0, 0,
30 | false, false, false, false,
31 | 0, null
32 | );
33 | a.dispatchEvent(event);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/fonteditor/widget/util/resolvettf.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 根据选项调整 ttfObject
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 |
7 | import program from '../program';
8 |
9 | /**
10 | * 根据选项调整 ttfObject,主要调整 post,head 等信息
11 | *
12 | * @param {Object} ttfObject ttf对象
13 | * @param {Object} options 参数选项
14 | * @return {Object} ttf对象
15 | */
16 | export default function resolvettf(ttfObject, options = {}) {
17 | let exportSetting = program.setting.get('ie');
18 | // 强制设置post表信息
19 | ttfObject.post = ttfObject.post || {};
20 | if (exportSetting && exportSetting.export.saveWithGlyfName) {
21 | ttfObject.post.format = 2;
22 | }
23 | else {
24 | ttfObject.post.format = 3;
25 | }
26 |
27 | return ttfObject;
28 | }
29 |
--------------------------------------------------------------------------------
/src/graphics/boundAdjust.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 对bound对象进行缩放和平移
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | /**
7 | * 对bound坐标进行调整
8 | *
9 | * @param {Object} bound bound数据结构 {x,y,width,height}
10 | * @param {number} scaleX x缩放比例
11 | * @param {number} scaleY y缩放比例
12 | * @param {number} offsetX x偏移
13 | * @param {number} offsetY y偏移
14 | *
15 | * @return {number} bound数据结构
16 | */
17 | export default function boundAdjust(bound, scaleX, scaleY, offsetX, offsetY) {
18 |
19 | scaleX = scaleX === undefined ? 1 : scaleX;
20 | scaleY = scaleY === undefined ? 1 : scaleY;
21 | let x = offsetX || 0;
22 | let y = offsetY || 0;
23 |
24 | bound.x = scaleX * (bound.x + x);
25 | bound.y = scaleY * (bound.y + y);
26 | bound.width = scaleX * bound.width;
27 | bound.height = scaleY * bound.height;
28 |
29 | return bound;
30 | }
31 |
--------------------------------------------------------------------------------
/src/graphics/computeBoundingBox.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 计算曲线包围盒
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import {
7 |
8 | computeBounding,
9 | quadraticBezier,
10 | computePath,
11 | computePathBox
12 | } from 'fonteditor-core/graphics/computeBoundingBox';
13 | export default {
14 | computeBounding,
15 | quadraticBezier,
16 | computePath,
17 | computePathBox
18 | };
19 |
--------------------------------------------------------------------------------
/src/graphics/image/contour/douglasPeuckerReducePoints.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 消减非必要的点
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import vector from 'graphics/vector';
7 |
8 | const THRESHOLD_DEFAULT = 1; // 默认消减点的阈值
9 |
10 | function reduce(contour, firstIndex, lastIndex, threshold, splitArray) {
11 |
12 | if (lastIndex - firstIndex < 3) {
13 | return;
14 | }
15 |
16 | let start = contour[firstIndex];
17 | let end = contour[lastIndex];
18 | let splitIndex = -1;
19 | let maxDistance = 0;
20 | for (let i = firstIndex + 1; i < lastIndex; i++) {
21 | let dist = vector.getDist(start, end, contour[i]);
22 | if (dist > maxDistance) {
23 | maxDistance = dist;
24 | splitIndex = i;
25 | }
26 | }
27 |
28 | if (maxDistance > threshold) {
29 | splitArray.push(splitIndex);
30 | reduce(contour, firstIndex, splitIndex, threshold, splitArray);
31 | reduce(contour, splitIndex, lastIndex, threshold, splitArray);
32 | }
33 | }
34 |
35 |
36 | /**
37 | * 消减非必要的点
38 | *
39 | * @param {Array} contour 轮廓点集
40 | * @param {number} firstIndex 起始索引
41 | * @param {number} lastIndex 结束索引
42 | * @param {number} scale 缩放级别
43 | * @param {number} threshold 消减阈值
44 | * @return {Array} 消减后的点集
45 | */
46 | export default function reducePoint(contour, firstIndex = 0, lastIndex, scale, threshold) {
47 | lastIndex = lastIndex || contour.length - 1;
48 | threshold = threshold || THRESHOLD_DEFAULT * (scale || 1);
49 | let splitArray = [];
50 |
51 | reduce(contour, firstIndex, lastIndex, threshold, splitArray);
52 |
53 | if (splitArray.length) {
54 | splitArray.unshift(firstIndex);
55 | splitArray = splitArray.map(function (index) {
56 | contour[index].contourIndex = index;
57 | return contour[index];
58 | });
59 |
60 | splitArray.sort(function (a, b) {
61 | return a.contourIndex - b.contourIndex;
62 | });
63 | return splitArray;
64 | }
65 |
66 | return contour;
67 | }
68 |
--------------------------------------------------------------------------------
/src/graphics/image/contour/fitOval.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 拟合圆
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 |
7 | import pathUtil from 'graphics/pathUtil';
8 | import computeBoundingBox from 'graphics/computeBoundingBox';
9 | import pathAdjust from 'graphics/pathAdjust';
10 | import circlePath from 'graphics/path/circle';
11 | import lang from 'common/lang';
12 |
13 | /**
14 | * 拟合椭圆
15 | *
16 | * @param {Array} points 轮廓
17 | * @return {Object} bound
18 | */
19 | export default function fitOval(points) {
20 | let b = computeBoundingBox.computeBounding(points);
21 | let bound = computeBoundingBox.computePath(circlePath);
22 | let scaleX = b.width / bound.width;
23 | let scaleY = b.height / bound.height;
24 | let contour = lang.clone(circlePath);
25 | pathAdjust(contour, scaleX, scaleY);
26 | pathAdjust(contour, 1, 1, b.x - bound.x, b.y - bound.y);
27 | return pathUtil.isClockWise(points) === -1 ? contour : contour.reverse();
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/src/graphics/image/contour/smooth.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 平滑轮廓
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | /**
7 | * 平滑图像轮廓
8 | * @param {Array} contour 轮廓点集
9 | * @param {number} smooth 平滑边界
10 | * @return {Array} 平滑后轮廓
11 | */
12 | export default function smooth(contour, smooth) {
13 |
14 | smooth = Math.floor((smooth || 2) / 2);
15 | let div = smooth * 2 + 1;
16 |
17 | for (let i = 0, l = contour.length; i < l; i++) {
18 | let p = contour[i];
19 | let xAvg = p.x;
20 | let yAvg = p.y;
21 | let index;
22 | for (let j = 0; j < smooth; j++) {
23 | index = (i + l - j) % l;
24 | xAvg += contour[index].x;
25 | yAvg += contour[index].y;
26 |
27 | index = (i + l + j) % l;
28 | xAvg += contour[index].x;
29 | yAvg += contour[index].y;
30 | }
31 | p.x = Math.floor(xAvg / div);
32 | p.y = Math.floor(yAvg / div);
33 | }
34 |
35 | return contour;
36 | }
37 |
--------------------------------------------------------------------------------
/src/graphics/image/filter/binarize.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 对图像进行二值化
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | /**
7 | * 二值化图像数据
8 | *
9 | * @param {Object} imageData 图像数据
10 | * @param {number} threshold 阈值
11 | * @return {Array} 二值化后的数据
12 | */
13 | export default function binarize(imageData, threshold) {
14 |
15 | threshold = threshold || 200;
16 | let width = imageData.width;
17 | let height = imageData.height;
18 | let data = imageData.data;
19 |
20 | for (let y = 0, row = 0; y < height; y++) {
21 | row = y * width;
22 | for (let x = 0; x < width; x++) {
23 | data[row + x] = data[row + x] < threshold ? 0 : 255;
24 | }
25 | }
26 |
27 | imageData.binarize = true;
28 |
29 | return imageData;
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/src/graphics/image/filter/blur.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 图像模糊
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import filteringImage from '../util/filteringImage';
7 |
8 | function getMatrix(radius) {
9 | let matrix = [];
10 | // 均值滤波
11 | let size = Math.pow(2 * radius + 1, 2);
12 | let value = 1 / size;
13 |
14 | for (let i = 0; i < size; i++) {
15 | matrix[i] = value;
16 | }
17 |
18 | return matrix;
19 | }
20 |
21 | /**
22 | * 灰度图像模糊
23 | *
24 | * @param {Object} imageData 图像数据
25 | * @param {number} radius 取样区域半径, 正数, 可选, 默认为 3
26 | *
27 | * @return {Object}
28 | */
29 | export default function blur(imageData, radius) {
30 |
31 | radius = Math.floor((radius || 3) / 2);
32 |
33 | let data = imageData.data;
34 | let width = imageData.width;
35 | let height = imageData.height;
36 | let matrix = getMatrix(radius);
37 |
38 | imageData.data = filteringImage(data, width, height, radius, matrix);
39 | return imageData;
40 | }
41 |
--------------------------------------------------------------------------------
/src/graphics/image/filter/brightness.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 亮度对比度计算
3 | * @author mengke01(kekee000@gmail.com)
4 | *
5 | * @reference
6 | * https://github.com/AlloyTeam/AlloyImage
7 | */
8 |
9 | /**
10 | * 调节图像亮度对比度
11 | *
12 | * @param {Object} imageData 图像数据
13 | * @param {string} brightness 亮度 -50 ~ 50
14 | * @param {number} contrast 对比度 -50 ~ 50
15 | * @return {Object} 调整后图像
16 | */
17 | export default function brightness(imageData, brightness, contrast) {
18 |
19 | brightness = brightness || 0;
20 | contrast = contrast || 0;
21 |
22 | let data = imageData.data;
23 | let b = brightness / 50; // -1 , 1
24 | let c = contrast / 50; // -1 , 1
25 | let k = Math.tan((45 + 44 * c) * Math.PI / 180);
26 |
27 | for (let i = 0, l = data.length; i < l; i++) {
28 | data[i] = Math.floor((data[i] - 127.5 * (1 - b)) * k + 127.5 * (1 + b));
29 | }
30 |
31 | return imageData;
32 | }
33 |
--------------------------------------------------------------------------------
/src/graphics/image/filter/close.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 二值图像开运算
3 | * 先膨胀后腐蚀的过程称为闭运算。用来填充物体内细小空洞、
4 | * 连接邻近物体、平滑其边界的同时并不明显改变其面积
5 | * @author mengke01(kekee000@gmail.com)
6 | */
7 |
8 | import dilate from './dilate';
9 | import erode from './erode';
10 |
11 | export default function close(imageData, mode, radius) {
12 | return erode(dilate(imageData, mode, radius));
13 | }
14 |
--------------------------------------------------------------------------------
/src/graphics/image/filter/dilate.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 对二值图像进行膨胀
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import {execute} from '../util/de';
7 |
8 | export default function dilate(imageData, mode, radius) {
9 | return execute(imageData, 'dilate', mode, radius);
10 | }
11 |
--------------------------------------------------------------------------------
/src/graphics/image/filter/erode.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 对二值图像进行腐蚀
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import {execute} from '../util/de';
7 |
8 | export default function erode(imageData, mode, radius) {
9 | return execute(imageData, 'erode', mode, radius);
10 | }
11 |
--------------------------------------------------------------------------------
/src/graphics/image/filter/gaussBlur.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 高斯模糊
3 | * @author mengke01(kekee000@gmail.com)
4 | *
5 | * http://www.ruanyifeng.com/blog/2012/11/gaussian_blur.html
6 | * @reference
7 | * https://github.com/AlloyTeam/AlloyImage
8 | */
9 |
10 |
11 | import filteringImage from '../util/filteringImage';
12 |
13 | function getGaussMatrix(radius, sigma) {
14 | let gaussMatrix = [];
15 | let gaussSum = 0;
16 | let a = 1 / (2 * Math.PI * sigma * sigma);
17 | let b = -1 / (2 * sigma * sigma);
18 | let x;
19 | let y;
20 | let k;
21 |
22 | // 生成高斯矩阵
23 | for (k = 0, x = -radius; x <= radius; x++) {
24 | for (y = -radius; y <= radius; y++) {
25 | let g = a * Math.exp(b * (x * x + y * y));
26 | gaussMatrix[k++] = g;
27 | gaussSum += g;
28 | }
29 | }
30 |
31 | // 归一化, 保证高斯矩阵的值在[0,1]之间
32 | for (k = 0, x = -radius; x <= radius; x++) {
33 | for (y = -radius; y <= radius; y++) {
34 | gaussMatrix[k++] /= gaussSum;
35 | }
36 | }
37 |
38 | return gaussMatrix;
39 | }
40 |
41 | /**
42 | * 灰度图像高斯模糊
43 | *
44 | * @param {Object} imageData 图像数据
45 | * @param {number} radius 取样区域半径, 正数, 可选, 默认为 3
46 | * @param {number} sigma 标准方差, 可选, 默认取值为 1.5
47 | *
48 | * @return {Object}
49 | */
50 | export default function gaussBlur(imageData, radius, sigma) {
51 |
52 | radius = Math.floor((radius || 3) / 2);
53 |
54 | let data = imageData.data;
55 | let width = imageData.width;
56 | let height = imageData.height;
57 | let matrix = getGaussMatrix(radius, sigma || 1.5);
58 |
59 | imageData.data = filteringImage(data, width, height, radius, matrix);
60 |
61 | return imageData;
62 | }
63 |
--------------------------------------------------------------------------------
/src/graphics/image/filter/gray.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 对图像进行灰度化处理
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | /**
7 | * 对图像进行灰度化处理
8 | *
9 | * @param {Object} imageData 图像数据
10 | * @param {boolean} reverse 是否反转图像
11 | *
12 | * @return {Object} 处理后的数据
13 | */
14 | export default function grayImage(imageData, reverse) {
15 |
16 | let width = imageData.width;
17 | let height = imageData.height;
18 | let line = 0;
19 | let data = imageData.data;
20 | let newData = [];
21 |
22 | for (let y = 0; y < height; y++) {
23 | line = y * width;
24 | for (let x = 0; x < width; x++) {
25 | let idx = (x + line) * 4;
26 | let gray = 255;
27 | if (data[idx + 3] < 25) {
28 | gray = 255;
29 | }
30 | else {
31 | let r = data[idx + 0];
32 | let g = data[idx + 1];
33 | let b = data[idx + 2];
34 | gray = Math.floor(0.299 * r + 0.587 * g + 0.114 * b);
35 | }
36 | newData[x + line] = reverse ? 255 - gray : gray;
37 | }
38 | }
39 |
40 | return {
41 | width: width,
42 | height: height,
43 | gray: true,
44 | data: newData
45 | };
46 | }
47 |
--------------------------------------------------------------------------------
/src/graphics/image/filter/open.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 二值图像开运算
3 | * 先腐蚀后膨胀的过程称为开运算。用来消除小物体、
4 | * 在纤细点处分离物体、平滑较大物体的边界的同时并不明显改变其面积
5 | * @author mengke01(kekee000@gmail.com)
6 | */
7 |
8 | import dilate from './dilate';
9 | import erode from './erode';
10 |
11 | export default function (imageData, mode, radius) {
12 | return dilate(erode(imageData, mode, radius));
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/src/graphics/image/filter/reverse.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 反转图像
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | /**
7 | * 调节图像亮度对比度
8 | *
9 | * @param {Object} imageData 图像数据
10 | * @return {Object} 调整后图像
11 | */
12 | export default function reverse(imageData) {
13 | let data = imageData.data;
14 | for (let i = 0, l = data.length; i < l; i++) {
15 | data[i] = 255 - data[i];
16 | }
17 |
18 | return imageData;
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/src/graphics/image/filter/sharp.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 图像锐化滤镜
3 | * @author mengke01(kekee000@gmail.com)
4 | *
5 | * @reference
6 | * http://dsqiu.iteye.com/blog/1638589
7 | * https://github.com/AlloyTeam/AlloyImage
8 | */
9 |
10 | /**
11 | * 灰度图像锐化
12 | * @param {Object} imageData 图像数据
13 | * @param {number} lamta 锐化参数
14 | * @return {Object} 处理后图像
15 | */
16 | export default function sharp(imageData, lamta = 0.6) {
17 | let width = imageData.width;
18 | let height = imageData.height;
19 | let data = imageData.data;
20 | for (let line = 0, y = 1; y < height; y++) {
21 | line = y * width;
22 | for (let x = 1; x < width; x++) {
23 | let idx = x + line;
24 | // 当前点减去 左侧三个像素点的平均值
25 | let delta = data[idx] - (data[idx - 1] + data[idx - width] + data[idx - width - 1]) / 3;
26 | data[idx] += Math.floor(delta * lamta);
27 | }
28 | }
29 |
30 | return imageData;
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/graphics/image/util/cloneContours.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 克隆轮廓数组
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | /**
7 | * 克隆轮廓点集
8 | *
9 | * @param {Array} contours 轮廓点集
10 | * @return {Array} 克隆后的点集
11 | */
12 | export default function cloneContours(contours) {
13 | let newContours = [];
14 | contours.forEach(function (contour) {
15 | let newContour = [];
16 | contour.forEach(function (p) {
17 | newContour.push({
18 | x: p.x,
19 | y: p.y,
20 | onCurve: !!p.onCurve
21 | });
22 | });
23 | });
24 |
25 | return newContours;
26 | }
27 |
--------------------------------------------------------------------------------
/src/graphics/image/util/cloneImage.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 克隆一个图像对象
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 |
7 | export default function (imageData) {
8 | return {
9 | width: imageData.width,
10 | height: imageData.height,
11 | gray: imageData.gray,
12 | binarize: imageData.binarize,
13 | data: imageData.data.slice(0)
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/src/graphics/image/util/filteringImage.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 图像滤波函数
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | /**
7 | * 滤波函数
8 | *
9 | * @param {Array} data 图像数据
10 | * @param {number} width 宽度
11 | * @param {number} height 高度
12 | * @param {number} radius 半径
13 | * @param {Array} matrix 滤波矩阵
14 | *
15 | * @return {Array} 滤波后数据
16 | */
17 | export default function filteringImage(data, width, height, radius, matrix) {
18 | let x;
19 | let y;
20 | let i;
21 | let j;
22 | let k;
23 | let value;
24 | let posX;
25 | let posY;
26 |
27 | for (y = 0; y < height; y++) {
28 | for (x = 0; x < width; x++) {
29 | value = 0;
30 | for (k = 0, i = -radius; i <= radius; i++) {
31 | for (j = -radius; j <= radius; j++) {
32 | posX = x + i;
33 |
34 | if (posX < 0 || posX >= width) {
35 | posX = x - i;
36 | }
37 |
38 | posY = y + j;
39 | if (posY < 0 || posY >= height) {
40 | posY = y - j;
41 | }
42 |
43 | value += data[posX + posY * width] * matrix[k++];
44 | }
45 | }
46 |
47 | data[x + y * width] = Math.floor(value);
48 | }
49 | }
50 |
51 | return data;
52 | }
53 |
--------------------------------------------------------------------------------
/src/graphics/image/util/getHistogram.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 获取灰度图像的直方图信息
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 |
7 | /**
8 | * 获取图像的灰度分布信息
9 | *
10 | * @param {Object} imageData 图像数据
11 | * @return {Array} 灰度统计信息
12 | */
13 | export default function getHistogram(imageData) {
14 | let histogram = [];
15 | let i = 0;
16 | let l = 256;
17 | for (; i < l; i++) {
18 | histogram[i] = 0;
19 | }
20 |
21 | let data = imageData.data;
22 | for (i = 0, l = data.length; i < l; i++) {
23 | histogram[data[i]]++;
24 | }
25 |
26 | return histogram;
27 | }
28 |
--------------------------------------------------------------------------------
/src/graphics/image/util/getThreshold.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 获取二值化阈值
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import thresholdTypes from './threshold';
7 |
8 |
9 | /**
10 | * 获取图像的二值阈值
11 | *
12 | * @param {Array} histogram 灰度分布数组
13 | * @param {string} thresholdType 阈值类型
14 | * @return {number} 阈值
15 | */
16 | export default function getThreshold(histogram, thresholdType) {
17 | let thrFunction = thresholdTypes[thresholdType] || thresholdTypes.mean;
18 | return thrFunction(histogram);
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/src/graphics/isBezierLineCross.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file 判断贝塞尔曲线与直线相交
3 | * @author mengke01(kekee000@gmail.com)
4 | */
5 |
6 | import bezierQ2Equation from '../math/bezierQ2Equation';
7 | import {ceilPoint} from './util';
8 |
9 | /**
10 | * 判断贝塞尔曲线与直线相交
11 | *
12 | * @param {Object} p0 起点
13 | * @param {Object} p1 控制点
14 | * @param {Object} p2 终点
15 | * @param {Object} s0 直线点1
16 | * @param {Object} s1 直线点2
17 | * @return {Array.