diff --git a/build.sh b/build.sh
index d0f901d..935627d 100644
--- a/build.sh
+++ b/build.sh
@@ -22,10 +22,15 @@ build_asset() {
# 移动文件到指定目录
move_asset() {
mv ./release/src ./release/$version
+
cat ./release/index.html | sed -e "s#'\.\/src'#'./$version'#g" > ./release/index.html.tmp
mv ./release/index.html.tmp ./release/index.html
+
cat ./release/index-en.html | sed -e "s#'\.\/src'#'./$version'#g" > ./release/index-en.html.tmp
mv ./release/index-en.html.tmp ./release/index-en.html
+
+ cat ./release/editor.html | sed -e "s#'\.\/src'#'./$version'#g" > ./release/editor.html.tmp
+ mv ./release/editor.html.tmp ./release/editor.html
}
build_index
diff --git a/css/editor.css b/css/editor.css
new file mode 100644
index 0000000..9f35bcc
--- /dev/null
+++ b/css/editor.css
@@ -0,0 +1,333 @@
+html,
+body {
+ height: 100%;
+}
+/**
+ * @file 重置样式
+ * @author mengke01(kekee000@gmail.com)
+ */
+* {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+blockquote,
+body,
+button,
+dd,
+dl,
+dt,
+fieldset,
+form,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+hr,
+input,
+legend,
+li,
+ol,
+p,
+pre,
+td,
+textarea,
+th,
+ul {
+ margin: 0;
+ padding: 0;
+}
+body,
+button,
+input,
+select,
+textarea {
+ font: 12px/1.5 tahoma, arial, sans-serif;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-size: 100%;
+}
+address,
+cite,
+dfn,
+em,
+var {
+ font-style: normal;
+}
+code,
+kbd,
+pre,
+samp {
+ font-family: courier new, courier, monospace;
+}
+small {
+ font-size: 12px;
+}
+ol,
+ul {
+ list-style: none;
+}
+a {
+ text-decoration: none;
+}
+a:hover {
+ text-decoration: underline;
+}
+legend {
+ color: #000;
+}
+fieldset,
+img {
+ border: 0;
+}
+button,
+input,
+select,
+textarea {
+ font-size: 100%;
+}
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+@font-face {
+ font-family: 'fonteditor';
+ src: url('../../font/fonteditor.ttf') format('truetype');
+}
+.ico {
+ display: inline-block;
+}
+.ico:before,
+.ico:after {
+ font-family: 'fonteditor';
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -webkit-text-stroke-width: 0.1px;
+}
+.i-leave:before {
+ content: '\e00c';
+}
+.i-edit,
+.i-del,
+.i-leave {
+ font-size: 12px;
+}
+.i-edit:hover,
+.i-del:hover,
+.i-leave:hover {
+ cursor: pointer;
+ color: #4A90E2;
+}
+.i-edit,
+.i-del {
+ color: #76abe9;
+}
+.i-edit:before {
+ content: '\e021';
+}
+.i-del:before {
+ content: '\e020';
+}
+.i-github:before {
+ content: '\e01e';
+}
+.i-help:before {
+ content: '\e016';
+}
+.i-new:before {
+ content: '\e019';
+}
+.i-open:before {
+ content: '\e01A';
+}
+.i-add:before {
+ content: '\e003';
+}
+.i-undo:before {
+ content: '\e001';
+}
+.i-redo:before {
+ content: '\e002';
+}
+.i-down:before {
+ content: '\e00e';
+}
+.i-left:before {
+ content: '\e00a';
+}
+.i-ttf:before {
+ content: '\e00f';
+}
+.i-woff:before {
+ content: '\e010';
+}
+.i-zip:before {
+ content: '\e011';
+}
+.i-save:before {
+ content: '\e022';
+}
+.i-upshape:before {
+ content: '\e014';
+}
+.i-downshape:before {
+ content: '\e00b';
+}
+.i-reversepoints:before {
+ content: '\e00d';
+}
+.i-alignleft:before {
+ content: '\e006';
+}
+.i-aligncenter:before {
+ content: '\e004';
+}
+.i-alignright:before {
+ content: '\e007';
+}
+.i-aligntop:before {
+ content: '\e008';
+}
+.i-alignmiddle:before {
+ content: '\e005';
+}
+.i-aligndescent:before {
+ content: '\e009';
+}
+.i-alignbaseline:before {
+ content: '\e009';
+}
+.i-rotateleft:before {
+ content: '\e01c';
+}
+.i-rotateright:before {
+ content: '\e01d';
+}
+.i-flip:before {
+ content: '\e013';
+}
+.i-mirror:before {
+ content: '\e012';
+}
+.i-splitshapes:before {
+ content: '\e024';
+}
+.i-joinshapes:before {
+ content: '\e025';
+}
+.i-intersectshapes:before {
+ content: '\e026';
+}
+.i-tangencyshapes:before {
+ content: '\e027';
+}
+.i-rangemode:before {
+ content: '\e029';
+}
+.i-pointmode:before {
+ content: '\e028';
+}
+.glyf-editor {
+ width: 100%;
+ height: 100%;
+ font-size: 12px;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ display: none;
+}
+.glyf-editor .marker-x,
+.glyf-editor .marker-y {
+ position: absolute;
+ width: 0;
+ height: 0;
+ z-index: 60;
+ pointer-events: none;
+}
+.glyf-editor .marker-x {
+ width: 20px;
+ border-top: 1px dashed #000;
+}
+.glyf-editor .marker-y {
+ height: 20px;
+ border-left: 1px dashed #000;
+}
+.editor-contextmenu {
+ color: #333;
+ width: 150px;
+ border: 1px solid #999;
+ background: #FEFEFE;
+ line-height: 24px;
+ padding: 0 4px;
+ box-shadow: 1px 1px 1px #CCC;
+ position: absolute;
+}
+.editor-contextmenu li {
+ padding-left: 4px;
+ cursor: pointer;
+ border-bottom: 1px solid #CCC;
+}
+.editor-contextmenu li > ul {
+ display: none;
+ color: #333;
+ width: 150px;
+ border: 1px solid #999;
+ background: #FEFEFE;
+ line-height: 24px;
+ padding: 0 4px;
+ box-shadow: 1px 1px 1px #CCC;
+ position: absolute;
+ margin-left: 130px;
+}
+.editor-contextmenu > li[data-sub] {
+ color: #4A90E2;
+}
+.editor-contextmenu > li[data-sub]:after {
+ content: '>';
+ margin-right: 10px;
+ float: right;
+ font-family: 'Simsun';
+}
+.editor-contextmenu li[data-tag="selected"] {
+ display: inline-block;
+ display: block;
+}
+.editor-contextmenu li[data-tag="selected"]:before,
+.editor-contextmenu li[data-tag="selected"]:after {
+ font-family: 'fonteditor';
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -webkit-text-stroke-width: 0.1px;
+}
+.editor-contextmenu li[data-tag="selected"]:after {
+ content: '\e01f';
+}
+.editor-contextmenu li[data-tag="selected"]:after {
+ float: right;
+ margin-right: 4px;
+ color: #4A90E2;
+}
+.editor-contextmenu li:hover {
+ background: #EEE;
+}
+.editor-contextmenu li:hover > ul {
+ display: block;
+}
+.editor-contextmenu li:last-child {
+ border-bottom: none;
+}
+.editor-panel {
+ width: 100%;
+ height: 100%;
+ font-size: 12px;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+}
diff --git a/css/editor.less b/css/editor.less
new file mode 100644
index 0000000..5e901e1
--- /dev/null
+++ b/css/editor.less
@@ -0,0 +1,18 @@
+html,
+body {
+ height: 100%;
+}
+
+@import './widget/reset.less';
+@import './widget/ico.less';
+@import './widget/glyf-editor.less';
+
+
+.editor-panel {
+ width: 100%;
+ height: 100%;
+ font-size: 12px;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+}
diff --git a/demo/editor-iframe.html b/demo/editor-iframe.html
new file mode 100644
index 0000000..3340837
--- /dev/null
+++ b/demo/editor-iframe.html
@@ -0,0 +1,37 @@
+
+
+
+
+ 测试editor远程调用
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/js/editor-iframe.js b/demo/js/editor-iframe.js
new file mode 100644
index 0000000..4e3fd39
--- /dev/null
+++ b/demo/js/editor-iframe.js
@@ -0,0 +1,155 @@
+/**
+ * @file iframe 调用编辑器
+ * @author mengke01(kekee000@gmail.com)
+ */
+
+
+define(function (require) {
+
+ /**
+ * 用于远程 editor 编辑器接口,由于使用postMessage进行跨域调用,
+ * 这里接口都采用异步化
+ *
+ * @param {Object} options 参数
+ * @param {jQuery|HTMLElement} options.main 主元素,iframe对象或者jquery对象
+ * @param {string=} options.url editor接口
+ */
+ function Editor(options) {
+ this.main = $(options.main);
+ this.url = options.url || '../editor.html';
+ this.key = 'editor-' + Math.random();
+ // 给 editor页面传递 key id,以便于通信的时候根据key来进行通信
+ this.onMessage = $.proxy(this.onMessage, this);
+ this.readyList = [];
+
+ // 注册默认监听的事件
+ this.events = {
+ load: function () {
+ var me = this;
+ this.readyList.forEach(function (promise) {
+ promise.resolve(me);
+ });
+ this.readyList = null;
+ this.loaded = true;
+ }
+ };
+
+ var url = this.url + (this.url.indexOf('?') >= 0 ? '&' : '?') + 'key=' + this.key;
+ var frame = this.main[0];
+ frame.src = url;
+ window.addEventListener('message', this.onMessage);
+ }
+
+ /**
+ * 编辑器准备就绪时的事件
+ *
+ * @return {Promise}
+ */
+ Editor.prototype.ready = function () {
+ var promise = $.Deferred();
+ if (this.loaded) {
+ promise.resolve(this);
+ }
+ else {
+ this.readyList.push(promise);
+ }
+ return promise;
+ };
+
+ /**
+ * 设置字体格式
+ *
+ * @param {Object} font 字体格式
+ * @return {Promise}
+ */
+ Editor.prototype.setFont = function (font) {
+ return this.postMessage('setFont', [font]);
+ };
+
+ /**
+ * 获取字体格式
+ *
+ * @return {Promise}
+ */
+ Editor.prototype.getFont = function () {
+ return this.postMessage('getFont');
+ };
+
+ /**
+ * 执行命令
+ *
+ * @param {string} name 命令
+ * @param {Array?} args 命令参数列表
+ * @return {Promise}
+ */
+ Editor.prototype.execCommand = function () {
+ return this.postMessage('execCommand', [].slice.call(arguments));
+ };
+
+ /**
+ * 获取editor对象,用来进行同域时候的精细化调用
+ *
+ * @return {Editor}
+ */
+ Editor.prototype.getEditor = function () {
+ return this.main[0].contentWindow.editor;
+ };
+
+ Editor.prototype.postMessage = function (name, args) {
+ var stamp = Date.now();
+ if (this.events[stamp]) {
+ throw new Error('call proxy function to quickly:' + name);
+ }
+
+ this.events[stamp] = $.Deferred();
+ this.main[0].contentWindow.postMessage({
+ key: this.key,
+ name: name,
+ stamp: stamp,
+ data: args || null
+ }, '*');
+ return this.events[stamp];
+ };
+
+ Editor.prototype.onMessage = function (e) {
+ if (e.data.key === this.key) {
+ var name = e.data.name;
+ var data = e.data.data;
+ var stamp = e.data.stamp;
+ if (stamp && this.events[stamp]) {
+ this.events[stamp].resolve(data);
+ delete this.events[stamp];
+ }
+ else if (this.events[name]) {
+ this.events[name].call(this, data)
+ }
+ }
+ };
+
+ Editor.prototype.dispose = function () {
+ this.main.remove();
+ this.events = this.main = null;
+ };
+
+
+
+ var shape_baidu = require('demo/../data/contours-5');
+ var editor = new Editor({
+ main: '.editor-frame'
+ })
+
+
+ editor.ready().then(function (editor) {
+ editor.setFont(shape_baidu).then(function () {
+ editor.execCommand('rescale', 0.5)
+ })
+ })
+
+ $('#get-font').on('click', function () {
+ editor.getFont().then(function (data) {
+ console.log(data)
+ })
+ })
+
+ return {};
+});
diff --git a/editor.html b/editor.html
new file mode 100644
index 0000000..0971c71
--- /dev/null
+++ b/editor.html
@@ -0,0 +1,33 @@
+
+
+
+
+ Editor
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/edp-build-config.js b/edp-build-config.js
index 9515a23..40f558d 100644
--- a/edp-build-config.js
+++ b/edp-build-config.js
@@ -11,6 +11,7 @@ exports.getProcessors = function () {
new LessCompiler({
files: [
'css/main.less',
+ 'css/editor.less',
'css/preview.less'
],
entryFiles: []
@@ -30,7 +31,8 @@ exports.getProcessors = function () {
new ModuleCompiler( {
files: [
- 'src/fonteditor/main.js'
+ 'src/fonteditor/main.js',
+ 'src/fonteditor/editor.js'
],
configFile: './module.conf'
}),
@@ -39,6 +41,7 @@ exports.getProcessors = function () {
new JsCompressor({
files: [
'src/fonteditor/main.js',
+ 'src/fonteditor/editor.js',
'dep/**/*.js',
'!dep/**/*.min.js',
]
diff --git a/module.conf b/module.conf
index 6e2b49d..df8f590 100644
--- a/module.conf
+++ b/module.conf
@@ -13,6 +13,7 @@
}
],
"combine": {
- "fonteditor/main": 1
+ "fonteditor/main": 1,
+ "fonteditor/editor": 1
}
}
diff --git a/src/editor/command/editor.js b/src/editor/command/editor.js
index dcb8844..e9b286c 100644
--- a/src/editor/command/editor.js
+++ b/src/editor/command/editor.js
@@ -17,10 +17,10 @@ define(
/**
* 重置缩放
*/
- rescale: function () {
+ rescale: function (scale) {
this.coverLayer.clearShapes();
var size = this.render.getSize();
- var scale = 512 / this.options.unitsPerEm;
+ scale = scale || (512 / this.options.unitsPerEm);
this.render.scaleTo(scale, {
x: size.width / 2,
@@ -130,14 +130,16 @@ define(
rightSideBearing = (this.rightSideBearing.p0.x - box.x - box.width) / scale;
}
- this.fire('setting:font', {
- setting: {
- leftSideBearing: Math.round(leftSideBearing),
- rightSideBearing: Math.round(rightSideBearing || 0),
- unicode: this.font.unicode,
- name: this.font.name
- }
- });
+ if (this.font) {
+ this.fire('setting:font', {
+ setting: {
+ leftSideBearing: Math.round(leftSideBearing),
+ rightSideBearing: Math.round(rightSideBearing || 0),
+ unicode: this.font.unicode,
+ name: this.font.name
+ }
+ });
+ }
}
};
}
diff --git a/src/editor/command/transform.js b/src/editor/command/transform.js
index 4ee1f04..b08dc96 100644
--- a/src/editor/command/transform.js
+++ b/src/editor/command/transform.js
@@ -58,6 +58,7 @@ define(
* @return {boolean} `false`或者`undefined`
*/
rotateleft: function (shapes) {
+ shapes = shapes || (this.currentGroup && this.currentGroup.shapes);
return support.rotate.call(this, shapes, -Math.PI / 2);
},
@@ -68,6 +69,7 @@ define(
* @return {boolean} `false`或者`undefined`
*/
rotateright: function (shapes) {
+ shapes = shapes || (this.currentGroup && this.currentGroup.shapes);
return support.rotate.call(this, shapes, Math.PI / 2);
},
@@ -78,7 +80,7 @@ define(
* @return {boolean} `false`或者`undefined`
*/
flipshapes: function (shapes) {
-
+ shapes = shapes || (this.currentGroup && this.currentGroup.shapes);
if (!shapes || !shapes.length) {
return false;
}
@@ -97,7 +99,7 @@ define(
* @return {boolean} `false`或者`undefined`
*/
mirrorshapes: function (shapes) {
-
+ shapes = shapes || (this.currentGroup && this.currentGroup.shapes);
if (!shapes || !shapes.length) {
return false;
}
diff --git a/src/editor/controller/initRender.js b/src/editor/controller/initRender.js
index f491ed7..760d759 100644
--- a/src/editor/controller/initRender.js
+++ b/src/editor/controller/initRender.js
@@ -43,7 +43,7 @@ define(
this.fire('save');
break;
default:
- this.execCommand(e.command, e);
+ this.execCommand(e.command);
}
}
diff --git a/src/editor/mode/shapes.js b/src/editor/mode/shapes.js
index 5d76d8c..ae94201 100644
--- a/src/editor/mode/shapes.js
+++ b/src/editor/mode/shapes.js
@@ -69,7 +69,7 @@ define(
default:
// 是否编辑器支持
if (this.supportCommand(command)) {
- this.execCommand(command, e);
+ this.execCommand(command);
}
}
}
diff --git a/src/fonteditor/editor.js b/src/fonteditor/editor.js
new file mode 100644
index 0000000..03e2708
--- /dev/null
+++ b/src/fonteditor/editor.js
@@ -0,0 +1,88 @@
+/**
+ * @file 编辑器导出接口,用于编辑字形相关的矢量图形
+ * @author mengke01(kekee000@gmail.com)
+ */
+
+define(function (require) {
+ var editor = require('../editor/main');
+ var options = require('../editor/options');
+ var commandList = require('../editor/menu/commandList');
+
+ // 用来做跨域通信的密钥
+ var EDITOR_KEY = require('../common/lang').parseQuery(location.search.slice(1)).key || 'fonteditor';
+
+ /**
+ * 向引用方外部发送事件
+ * @param {string} name 名称
+ * @param {Object} data 数据
+ * @param {number} stamp 某次通信的信标,用以区分多次事件
+ */
+ function fireEvent(name, data, stamp) {
+ parent.postMessage({
+ key: EDITOR_KEY,
+ name: name,
+ stamp: stamp,
+ data: data || null
+ }, '*');
+ return this;
+ }
+
+ function onMessage() {
+ window.addEventListener('message', function (e) {
+ if (!e.data.key === EDITOR_KEY) {
+ return;
+ }
+
+ var name = e.data.name;
+ var args = e.data.data;
+ if (typeof window.editor[name] === 'function') {
+ var data = window.editor[name].apply(window.editor, args);
+ if (e.data.stamp) {
+ fireEvent(name, data === window.editor ? null : data, e.data.stamp);
+ }
+ }
+ });
+ }
+
+ function removeCommandMenu(name, menu) {
+ for (var i = menu.length - 1; i >= 0; i--) {
+ if (menu[i].name === name) {
+ menu.splice(i, 1);
+ return true;
+ }
+ else if (menu[i].items) {
+ if (removeCommandMenu(name, menu[i].items)) {
+ return true
+ }
+ }
+ }
+ return false;
+ }
+
+ function initEditor() {
+ removeCommandMenu('fontsetting', commandList.editor)
+ removeCommandMenu('save', commandList.editor)
+ removeCommandMenu('moresetting', commandList.editor)
+
+ options.editor.unitsPerEm = 1024;
+ options.editor.axis.metrics = {
+ ascent: 812, // 上升
+ descent: -212, // 下降
+ xHeight: 400, // x高度
+ capHeight: 700 // 大写字母高度
+ };
+ var context = editor.create($('#editor-panel').get(0), options);
+ return context;
+ }
+
+ function main() {
+ onMessage();
+ var context = initEditor();
+ context.focus();
+ window.editor = context;
+ fireEvent('load');
+ }
+ main();
+
+ return {};
+});