diff --git a/css/common/common.less b/css/common/common.less
index 5695b48..07a92b6 100644
--- a/css/common/common.less
+++ b/css/common/common.less
@@ -1,6 +1,8 @@
@import './bootstrap.less';
+@import './def.less';
+
body, html {
margin: 0;
padding: 0;
@@ -10,14 +12,14 @@ body, html {
// scroll bar
::-webkit-scrollbar {
- width: 14px;
- height: 14px;
+ width: 12px;
+ height: 12px;
}
::-webkit-scrollbar-track,
::-webkit-scrollbar-thumb {
border-radius: 999px;
- border: 5px solid transparent;
+ border: 1px solid transparent;
}
::-webkit-scrollbar-track {
@@ -70,7 +72,7 @@ body, html {
.sidebar {
position: fixed;
width: 200px;
- top: 50px;
+ top: @top-height;
bottom: 0;
background: #FCFCFC;
padding: 4px;
@@ -79,11 +81,15 @@ body, html {
.main {
margin-left: 200px;
- padding: 4px;
- padding-top: 50px;
+ padding: 4px 0 4px 10px;
+ padding-top: @top-height;
height: 100%;
}
+.main.editing {
+ margin-left: 70%;
+}
+
// loading 动画
.loading {
position: fixed;
@@ -105,6 +111,15 @@ body, html {
}
+.editor {
+ position: fixed;
+ width: 70%;
+ top: @top-height;
+ bottom: 0;
+ z-index: 1;
+ background: #FEFEFE;
+ border-right: 1px solid #DDD;
+}
.selection-range {
position: absolute;
diff --git a/css/common/def.less b/css/common/def.less
new file mode 100644
index 0000000..74650bc
--- /dev/null
+++ b/css/common/def.less
@@ -0,0 +1,5 @@
+
+
+
+// 头部高度
+@top-height: 50px;
\ No newline at end of file
diff --git a/css/common/editor.less b/css/common/editor.less
new file mode 100644
index 0000000..ecf9a2f
--- /dev/null
+++ b/css/common/editor.less
@@ -0,0 +1,35 @@
+
+// 编辑器样式集合
+
+.glyf-editor {
+
+ width: 100%;
+ height: 100%;
+ font-size: 12px;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+
+ .editor-contextmenu {
+
+ width: 120px;
+ border: 1px solid #999;
+ background: #FEFEFE;
+ line-height: 24px;
+ padding: 0 4px;
+ box-shadow: 1px 1px 1px #CCC;
+
+ div {
+ padding-left: 10px;
+ cursor: pointer;
+ border-bottom: 1px solid #CCC;
+ }
+
+ div:hover {
+ background: #EEE;
+ }
+
+ div:last-child {
+ border-bottom: none;
+ }
+ }
+}
\ No newline at end of file
diff --git a/css/common/ico.less b/css/common/ico.less
index 7e682f4..00948e8 100644
--- a/css/common/ico.less
+++ b/css/common/ico.less
@@ -3,7 +3,7 @@
// fontface
@font-face {
font-family: 'fonteditor';
- src: url('../../font/iconfont.ttf') format('truetype');
+ src: url('../font/iconfont.ttf') format('truetype');
}
.i-edit,
diff --git a/css/main.less b/css/main.less
new file mode 100644
index 0000000..f91fb4e
--- /dev/null
+++ b/css/main.less
@@ -0,0 +1,6 @@
+
+
+@import './ttf.less';
+
+
+@import './common/editor.less';
\ No newline at end of file
diff --git a/css/ttf.less b/css/ttf.less
index da9c5d7..4c02554 100644
--- a/css/ttf.less
+++ b/css/ttf.less
@@ -35,9 +35,8 @@
.glyf-list {
- padding-bottom: 1000000px;
- margin-bottom: -1000000px;
- overflow: hidden;
+ height: 100%;
+ overflow: auto;
>.glyf-item {
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..f3262d5
--- /dev/null
+++ b/index.html
@@ -0,0 +1,120 @@
+
+
+
+
+ FontEditor字体编辑器
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 导出ttf
+ 导出woff
+ 导出svg
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 正在加载...
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/editor/Editor.js b/src/editor/Editor.js
index 0a5782a..c735052 100644
--- a/src/editor/Editor.js
+++ b/src/editor/Editor.js
@@ -143,6 +143,15 @@ define(
return this;
};
+ /**
+ * 是否改变过
+ *
+ * @return {boolean}
+ */
+ Editor.prototype.isChanged = function() {
+ return !this.history.atFirst();
+ };
+
/**
* 从剪切板中获取
*
diff --git a/src/editor/controller/initFont.js b/src/editor/controller/initFont.js
index 9f01add..00bafc1 100644
--- a/src/editor/controller/initFont.js
+++ b/src/editor/controller/initFont.js
@@ -25,23 +25,18 @@ define(
var contours = font.contours;
var originX = this.axis.x;
var originY = this.axis.y;
- var scale = this.render.camera.scale;
+
// 不需要在此保存contours
delete font.contours;
font.rightSideBearing = font.advanceWidth - font.xMax;
this.font = font;
- // 重置历史
- this.history.reset();
- this.history.add(lang.clone(contours));
-
// 设置字形
var shapes = contours.map(function(contour) {
- var shape = {};
- pathAdjust(contour, scale, -scale);
- shape.points = pathAdjust(contour, 1, 1, originX, originY);
- return shape;
+ return {
+ points: contour
+ };
});
var fontLayer = this.fontLayer;
@@ -50,6 +45,18 @@ define(
shapes.forEach(function(shape) {
fontLayer.addShape('path', shape);
});
+
+ // 重置历史
+ this.history.reset();
+ this.history.add(lang.clone(shapes));
+
+ // 设置缩放
+ var scale = this.render.camera.scale;
+ shapes.forEach(function(shape) {
+ pathAdjust(shape.points, scale, -scale);
+ pathAdjust(shape.points, 1, 1, originX, originY);
+ });
+
fontLayer.refresh();
// 设置参考线
@@ -67,7 +74,7 @@ define(
* @return {this}
*/
function setShapes(shapes) {
- var origin = this.render.getLayer('axis').shapes[0];
+ var origin = this.axis;
var scale = this.render.camera.scale;
var fontLayer = this.fontLayer;
@@ -124,14 +131,14 @@ define(
font.name = font.name || '';
var shapes = this.getShapes();
- shapes.forEach(function(g) {
+ var contours = lang.clone(shapes.map(function(shape) {
+ return shape.points;
+ })).forEach(function(g) {
pathCeil(g);
});
// 设置边界
- var box = computeBoundingBox.computePathBox.apply(null, shapes.map(function(shape) {
- return shape.points;
- }));
+ var box = computeBoundingBox.computePathBox.apply(null, contours);
font.xMin = box.x;
font.yMin = box.y;
@@ -141,7 +148,7 @@ define(
font.advanceWidth = font.xMax + font.rightSideBearing;
delete font.advanceWidth;
- font.contours = shapes;
+ font.contours = contours;
return font;
}
diff --git a/src/fonteditor/main.js b/src/fonteditor/main.js
new file mode 100644
index 0000000..fa0ec65
--- /dev/null
+++ b/src/fonteditor/main.js
@@ -0,0 +1,117 @@
+/**
+ * @file main.js
+ * @author mengke01
+ * @date
+ * @description
+ * ttf管理器
+ */
+
+define(
+ function(require) {
+
+ var GLYFViewer = require('./widget/glyfviewer');
+ var GLYFEditor = require('./widget/glyfeditor');
+ var ProjectViewer = require('./widget/projectviewer');
+ var TTFManager = require('./widget/ttfmanager');
+ var program = require('./widget/program');
+ var controller = require('./widget/controller/default');
+ var actions = require('./widget/actions');
+
+ // 打开文件
+ function onUpFile(e) {
+ var file = e.target.files[0];
+
+ if (program.data.action == 'open' && file.name.match(/(\.ttf|\.woff)$/i)) {
+ program.loader.load(file, {
+ type: file.name.slice(file.name.lastIndexOf('.') + 1).toLowerCase(),
+ success: function(imported) {
+ program.viewer.clearSelected();
+ program.ttfManager.set(imported);
+ program.data.projectName = null;
+ }
+ });
+ }
+ else if (program.data.action == 'import' && file.name.match(/(\.ttf|\.woff|\.svg)$/i)) {
+ if (program.ttfManager.get()) {
+ program.loader.load(file, {
+ type: file.name.slice(file.name.lastIndexOf('.') + 1).toLowerCase(),
+ success: function(imported) {
+ if (imported.glyf.length) {
+ program.ttfManager.merge(imported, {scale: true});
+ }
+ }
+ });
+ }
+ }
+ else {
+ alert('无法识别文件类型!');
+ }
+
+ e.target.value = '';
+ }
+
+ // 绑定组件
+ function bindEvent() {
+ $('.navbar').delegate('[data-action]', 'click', function(e) {
+ var action = $(this).attr('data-action');
+ if (actions[action]) {
+ program.data.action = action;
+ actions[action].call(this, e);
+ }
+ });
+
+ $('#export-btn').on('mouseup', actions['export-file']);
+ $('#export-btn-woff').on('mouseup', actions['export-file']);
+ $('#export-btn-svg').on('mouseup', actions['export-file']);
+
+ document.getElementById('font-import').addEventListener('change', onUpFile);
+ }
+
+ var entry = {
+
+ /**
+ * 初始化
+ */
+ init: function () {
+ bindEvent();
+
+ // glyf查看器
+ program.viewer = new GLYFViewer($('#glyf-list'));
+
+ // 字体查看器
+ program.editor = new GLYFEditor($('#glyf-editor'));
+
+ // 项目管理
+ program.project = require('./widget/project');
+ program.projectViewer = new ProjectViewer($('#project-list'));
+
+ // ttf管理
+ program.ttfManager = new TTFManager();
+
+ // 导入导出器
+ program.loader = require('./widget/loader');
+ program.exporter = require('./widget/exporter');
+
+ // 预览器
+ program.previewer = require('./widget/previewer');
+
+ controller.init(program);
+
+ // 加载项目
+ program.projectViewer.show(program.project.items());
+
+
+ // for test
+ $.getJSON('./demo/js/baiduHealth.json', function(ttf) {
+ program.ttfManager.set(ttf);
+ program.viewer.focus();
+ });
+
+ }
+ };
+
+ entry.init();
+
+ return entry;
+ }
+);
\ No newline at end of file
diff --git a/src/fonteditor/widget/controller/default.js b/src/fonteditor/widget/controller/default.js
index 5c3f823..a9d34f8 100644
--- a/src/fonteditor/widget/controller/default.js
+++ b/src/fonteditor/widget/controller/default.js
@@ -9,7 +9,7 @@
define(
function(require) {
-
+ var lang = require('common/lang');
var clipboard = require('../clipboard');
var string = require('common/string');
@@ -21,10 +21,22 @@ define(
* @param {Object} program 项目组件
*/
init: function(program) {
+
program.viewer.on('del', function(e) {
if (e.list) {
program.ttfManager.removeGlyf(e.list);
}
+ }).on('edit', function(e) {
+ $('.main').addClass('editing');
+ $('.editor').addClass('editing');
+ var list = program.ttfManager.getGlyf(e.list);
+ if (list[0].compound) {
+ alert('暂不支持复合字形!');
+ }
+ else {
+ program.editor.show(lang.clone(list[0]));
+ }
+
}).on('copy', function(e) {
var list = program.ttfManager.getGlyf(e.list);
clipboard.set(list, 'glyf');
@@ -32,37 +44,10 @@ define(
var list = program.ttfManager.getGlyf(e.list);
clipboard.set(list, 'glyf');
program.ttfManager.removeGlyf(e.list);
- }).on('paste', function(e) {
- var glyfList = clipboard.get('glyf');
- if (glyfList && glyfList.length) {
- program.ttfManager.appendGlyf(glyfList, program.viewer.getSelected());
- }
}).on('undo', function(e) {
program.ttfManager.undo();
}).on('redo', function(e) {
program.ttfManager.redo();
- }).on('save', function(e) {
- // 保存项目
- if (program.ttfManager.get()) {
- if (program.data.projectName) {
- program.project.add(program.data.projectName, program.ttfManager.get());
- program.ttfManager.setState('new');
- program.loading.show('保存成功..', 400);
- }
- else {
- var name = '';
- if ((name = window.prompt('请输入项目名称:'))) {
- name = string.encodeHTML(name);
- var list = program.project.add(name, program.ttfManager.get());
- program.projectViewer.show(list);
- program.data.projectName = name;
- program.ttfManager.setState('new');
- program.loading.show('保存成功..', 400);
- }
- }
- }
-
-
});
program.projectViewer.on('open', function(e) {
@@ -87,6 +72,39 @@ define(
program.viewer.focus();
});
+
+ program.on('save', function(e) {
+ // 保存项目
+ if (program.ttfManager.get()) {
+ if (program.data.projectName) {
+ program.project.add(program.data.projectName, program.ttfManager.get());
+ program.ttfManager.setState('new');
+ program.loading.show('保存成功..', 400);
+ }
+ else {
+ var name = '';
+ if ((name = window.prompt('请输入项目名称:'))) {
+ name = string.encodeHTML(name);
+ var list = program.project.add(name, program.ttfManager.get());
+ program.projectViewer.show(list);
+ program.data.projectName = name;
+ program.ttfManager.setState('new');
+ program.loading.show('保存成功..', 400);
+ }
+ }
+ }
+ }).on('paste', function(e) {
+ var glyfList = clipboard.get('glyf');
+ if (glyfList && glyfList.length) {
+ program.ttfManager.appendGlyf(glyfList, program.viewer.getSelected());
+ }
+ });
+
+ program.init({
+ viewer: program.viewer.main.get(0),
+ editor: program.editor.main.get(0)
+ });
+
window.onbeforeunload = function() {
if (program.ttfManager.isChanged()) {
return '是否放弃保存当前项目?';
diff --git a/src/fonteditor/widget/glyfeditor.js b/src/fonteditor/widget/glyfeditor.js
new file mode 100644
index 0000000..f31e567
--- /dev/null
+++ b/src/fonteditor/widget/glyfeditor.js
@@ -0,0 +1,59 @@
+/**
+ * @file GLYFEditor.js
+ * @author mengke01
+ * @date
+ * @description
+ * 编辑器组件
+ */
+
+
+define(
+ function(require) {
+
+ var editor = require('editor/main');
+
+
+ /**
+ * font查看器
+ *
+ * @constructor
+ * @param {HTMLElement} main 主元素
+ * @param {Object} options 参数
+ */
+ function GLYFEditor(main, options) {
+ this.main = $(main);
+ this.options = options || {};
+ }
+
+ GLYFEditor.prototype.show = function(font) {
+ if (!this.editor) {
+ this.editor = editor.create(this.main.get(0));
+ }
+ this.main.show();
+ if (font) {
+ this.editor.setFont(font);
+ }
+ this.editor.focus();
+ this.editing = true;
+ };
+
+ GLYFEditor.prototype.hide = function() {
+ this.editor.blur();
+ this.main.hide();
+ this.editing = false;
+ };
+
+ GLYFEditor.prototype.isEditing = function() {
+ return this.editing;
+ };
+
+ // 导出editor的函数
+ ['focus', 'blur', 'setFont', 'getFont', 'setShapes', 'getShapes'].forEach(function(fn) {
+ GLYFEditor.prototype[fn] = function() {
+ return this.editor ? this.editor[fn].apply(this.editor, arguments) : undefined;
+ };
+ });
+
+ return GLYFEditor;
+ }
+);
diff --git a/src/fonteditor/widget/glyfviewer.js b/src/fonteditor/widget/glyfviewer.js
index 7830a67..ab66913 100644
--- a/src/fonteditor/widget/glyfviewer.js
+++ b/src/fonteditor/widget/glyfviewer.js
@@ -1,5 +1,5 @@
/**
- * @file glyflist.js
+ * @file GLYFViewer.js
* @author mengke01
* @date
* @description
@@ -15,6 +15,7 @@ define(
var GLYF_ITEM_TPL = ''
+ ''
+ + ''
+ ''
+ '