add editor viewer
This commit is contained in:
@@ -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;
|
||||
|
||||
5
css/common/def.less
Normal file
5
css/common/def.less
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
|
||||
// 头部高度
|
||||
@top-height: 50px;
|
||||
35
css/common/editor.less
Normal file
35
css/common/editor.less
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
6
css/main.less
Normal file
6
css/main.less
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
@import './ttf.less';
|
||||
|
||||
|
||||
@import './common/editor.less';
|
||||
@@ -35,9 +35,8 @@
|
||||
|
||||
|
||||
.glyf-list {
|
||||
padding-bottom: 1000000px;
|
||||
margin-bottom: -1000000px;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
|
||||
>.glyf-item {
|
||||
|
||||
|
||||
120
index.html
Normal file
120
index.html
Normal file
@@ -0,0 +1,120 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>FontEditor字体编辑器</title>
|
||||
<link rel="stylesheet" type="text/css" href="./dep/bootstrap/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="./css/main.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<section class="navbar navbar-inverse" role="navigation">
|
||||
<button data-action="new" type="button" class="btn btn-primary btn-sm" title="新建ttf字体文件">新建</button>
|
||||
<button data-action="open" type="button" class="btn btn-primary btn-sm" title="打开ttf,woff格式字体文件">打开</button>
|
||||
<button data-action="import" type="button" class="btn btn-primary btn-sm" title="导入ttf,woff,svg格式字体文件">导入</button>
|
||||
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown">
|
||||
插入
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li data-action="add-new"><a>新字形</a></li>
|
||||
<li data-action="add-online"><a>在线字体</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<a id="export-btn" href="#" data-action="export" data-type="ttf" class="btn btn-success btn-sm">导出ttf</a>
|
||||
<a id="export-btn-woff" href="#" data-action="export" data-type="woff" class="btn btn-success btn-sm">导出woff</a>
|
||||
<a id="export-btn-svg" href="#" data-action="export" data-type="svg" class="btn btn-success btn-sm">导出svg</a>
|
||||
|
||||
<button data-action="save" type="button" class="btn btn-warning btn-sm">保存项目</button>
|
||||
|
||||
<div class="btn-group">
|
||||
|
||||
<button type="button" class="btn btn-info btn-sm dropdown-toggle" data-toggle="dropdown">
|
||||
设置
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a data-action="setting-unicode">代码点</a></li>
|
||||
<li><a data-action="setting-name">字体信息</a></li>
|
||||
<li><a data-action="setting-adjust-pos">调整位置</a></li>
|
||||
<li><a data-action="setting-adjust-glyf">调整字形</a></li>
|
||||
<li><a data-action="setting-metrics">调整字体度量</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="btn-group">
|
||||
|
||||
<button type="button" class="btn btn-success btn-sm dropdown-toggle" data-toggle="dropdown">
|
||||
预览
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a data-format="ttf" data-action="preview">ttf字体</a></li>
|
||||
<li><a data-format="woff" data-action="preview">woff字体</a></li>
|
||||
<li><a data-format="svg" data-action="preview">svg字体</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<section class="sidebar">
|
||||
<div class="project">
|
||||
<div class="project-title">项目列表</div>
|
||||
<div id="project-list" class="project-list"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="main editing">
|
||||
<div id="glyf-list" class="glyf-list">
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="editor" oncontextMenu="return false">
|
||||
<div id="glyf-editor" class="glyf-editor"></div>
|
||||
</section>
|
||||
|
||||
<div id="selection-range" class="selection-range"></div>
|
||||
<div id="loading" class="loading"><span>正在加载...</span></div>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal" id="model-dialog" tabindex="-1" role="dialog" aria-labelledby="model-label" aria-hidden="true" data-backdrop="false">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">关闭</span></button>
|
||||
<h4 class="modal-title" id="model-label">设置</h4>
|
||||
</div>
|
||||
<div class="modal-body"></div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">取消</button>
|
||||
<button type="button" class="btn btn-primary btn-sm btn-confirm">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script src="./dep/esl.js"></script>
|
||||
<script src="./dep/jquery.min.js"></script>
|
||||
<script src="./dep/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script>
|
||||
require.config({
|
||||
baseUrl: './src',
|
||||
paths: {
|
||||
deflate: '../dep/pako_deflate.min',
|
||||
inflate: '../dep/pako_inflate.min',
|
||||
utpl: '../dep/utpl.min'
|
||||
}
|
||||
});
|
||||
define('jquery', $);
|
||||
require(['fonteditor/main'])
|
||||
</script>
|
||||
<form id="font-form" style="width:0px;height:0px;overflow:hidden;"><input id="font-import" type="file"></form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -143,6 +143,15 @@ define(
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* 是否改变过
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
Editor.prototype.isChanged = function() {
|
||||
return !this.history.atFirst();
|
||||
};
|
||||
|
||||
/**
|
||||
* 从剪切板中获取
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
117
src/fonteditor/main.js
Normal file
117
src/fonteditor/main.js
Normal file
@@ -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;
|
||||
}
|
||||
);
|
||||
@@ -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 '是否放弃保存当前项目?';
|
||||
|
||||
59
src/fonteditor/widget/glyfeditor.js
Normal file
59
src/fonteditor/widget/glyfeditor.js
Normal file
@@ -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;
|
||||
}
|
||||
);
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file glyflist.js
|
||||
* @file GLYFViewer.js
|
||||
* @author mengke01
|
||||
* @date
|
||||
* @description
|
||||
@@ -15,6 +15,7 @@ define(
|
||||
|
||||
var GLYF_ITEM_TPL = ''
|
||||
+ '<div data-index="${index}" class="glyf-item ${compound} ${modify} ${selected}">'
|
||||
+ '<i data-action="edit" class="i-edit" title="编辑"></i>'
|
||||
+ '<i data-action="del" class="i-del" title="删除"></i>'
|
||||
+ '<svg class="glyf" viewbox="0 0 ${unitsPerEm} ${unitsPerEm}">'
|
||||
+ '<g transform="scale(1, -1) translate(0, -${descent}) scale(0.95, 0.95) ">'
|
||||
@@ -27,8 +28,7 @@ define(
|
||||
var keyMap = {
|
||||
46: 'del',
|
||||
67: 'copy',
|
||||
88: 'cut',
|
||||
86: 'paste'
|
||||
88: 'cut'
|
||||
};
|
||||
|
||||
// 显示glyf
|
||||
@@ -120,62 +120,47 @@ define(
|
||||
function downlistener(e) {
|
||||
var me = this;
|
||||
|
||||
if (e.keyCode >= 112 && e.keyCode <= 119 && e.keyCode !== 116) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
me.fire('function', {
|
||||
keyCode: e.keyCode
|
||||
});
|
||||
}
|
||||
// 保存
|
||||
if (83 === e.keyCode && e.ctrlKey) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
me.fire('save');
|
||||
}
|
||||
// 处理其他事件,需要focus
|
||||
else {
|
||||
if (me.listening) {
|
||||
// 阻止ctrl+A默认事件
|
||||
if (65 === e.keyCode && e.ctrlKey) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
me.main.children().addClass('selected');
|
||||
}
|
||||
// 撤销
|
||||
else if(e.keyCode == 90 && e.ctrlKey) {
|
||||
e.stopPropagation();
|
||||
me.fire('undo');
|
||||
}
|
||||
// 重做
|
||||
else if(e.keyCode == 89 && e.ctrlKey) {
|
||||
e.stopPropagation();
|
||||
me.fire('redo');
|
||||
}
|
||||
// 取消选中
|
||||
else if (27 === e.keyCode) {
|
||||
e.stopPropagation();
|
||||
if (me.listening) {
|
||||
// 阻止ctrl+A默认事件
|
||||
if (65 === e.keyCode && e.ctrlKey) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
me.main.children().addClass('selected');
|
||||
}
|
||||
// 撤销
|
||||
else if(e.keyCode == 90 && e.ctrlKey) {
|
||||
e.stopPropagation();
|
||||
me.fire('undo');
|
||||
}
|
||||
// 重做
|
||||
else if(e.keyCode == 89 && e.ctrlKey) {
|
||||
e.stopPropagation();
|
||||
me.fire('redo');
|
||||
}
|
||||
// 取消选中
|
||||
else if (27 === e.keyCode) {
|
||||
e.stopPropagation();
|
||||
me.clearSelected();
|
||||
}
|
||||
// 其他操作
|
||||
else if (keyMap[e.keyCode] && (e.keyCode == 46 || e.ctrlKey)) {
|
||||
e.stopPropagation();
|
||||
var selected = me.getSelected();
|
||||
|
||||
// 取消选中的glyf
|
||||
if (e.keyCode == 46 || e.keyCode == 88) {
|
||||
me.clearSelected();
|
||||
}
|
||||
// 其他操作
|
||||
else if (keyMap[e.keyCode] && (e.keyCode == 46 || e.ctrlKey)) {
|
||||
e.stopPropagation();
|
||||
var selected = me.getSelected();
|
||||
|
||||
// 取消选中的glyf
|
||||
if (e.keyCode == 46 || e.keyCode == 88) {
|
||||
me.clearSelected();
|
||||
}
|
||||
|
||||
// 粘贴和有选择的操作需要发事件
|
||||
if (e.keyCode == 86 || selected.length) {
|
||||
me.fire(keyMap[e.keyCode], {
|
||||
list: selected
|
||||
});
|
||||
}
|
||||
// 粘贴和有选择的操作需要发事件
|
||||
if (selected.length) {
|
||||
me.fire(keyMap[e.keyCode], {
|
||||
list: selected
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,7 +170,7 @@ define(
|
||||
* @param {HTMLElement} main 主元素
|
||||
* @param {Object} options 参数
|
||||
*/
|
||||
function GlyfViewer(main, options) {
|
||||
function GLYFViewer(main, options) {
|
||||
this.options = options || {};
|
||||
this.main = $(main);
|
||||
|
||||
@@ -196,11 +181,6 @@ define(
|
||||
var me = this;
|
||||
me.downlistener = lang.bind(downlistener, this);
|
||||
|
||||
$(document.body).on('click', function(e) {
|
||||
var focused = me.main.get(0) === e.target || me.main.get(0).contains(e.target);
|
||||
focused ? me.focus() : me.blur();
|
||||
});
|
||||
|
||||
me.capture = new MouseCapture(me.main.get(0), {
|
||||
events: {
|
||||
dblclick: false,
|
||||
@@ -249,7 +229,7 @@ define(
|
||||
/**
|
||||
* 获取焦点
|
||||
*/
|
||||
GlyfViewer.prototype.focus = function() {
|
||||
GLYFViewer.prototype.focus = function() {
|
||||
if (!this.listening) {
|
||||
this.listening = true;
|
||||
document.body.addEventListener('keydown', this.downlistener);
|
||||
@@ -259,10 +239,10 @@ define(
|
||||
/**
|
||||
* 失去焦点
|
||||
*/
|
||||
GlyfViewer.prototype.blur = function() {
|
||||
GLYFViewer.prototype.blur = function() {
|
||||
if (this.listening) {
|
||||
this.listening = false;
|
||||
document.body.addEventListener('keydown', this.downlistener);
|
||||
document.body.removeEventListener('keydown', this.downlistener);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -272,7 +252,7 @@ define(
|
||||
* @param {Object} ttf ttfObject
|
||||
* @param {Array?} selectedList 选中的列表
|
||||
*/
|
||||
GlyfViewer.prototype.show = function(ttf, selectedList) {
|
||||
GLYFViewer.prototype.show = function(ttf, selectedList) {
|
||||
showGLYF.call(this, ttf, selectedList);
|
||||
};
|
||||
|
||||
@@ -281,7 +261,7 @@ define(
|
||||
*
|
||||
* @return {Array} 选中的indexList
|
||||
*/
|
||||
GlyfViewer.prototype.getSelected = function() {
|
||||
GLYFViewer.prototype.getSelected = function() {
|
||||
var selected = [];
|
||||
this.main.find('.selected').each(function(index, item) {
|
||||
selected.push(+item.getAttribute('data-index'));
|
||||
@@ -292,14 +272,14 @@ define(
|
||||
/**
|
||||
* 清除选中列表
|
||||
*/
|
||||
GlyfViewer.prototype.clearSelected = function() {
|
||||
GLYFViewer.prototype.clearSelected = function() {
|
||||
this.main.children().removeClass('selected');
|
||||
};
|
||||
|
||||
/**
|
||||
* 设置选中的列表
|
||||
*/
|
||||
GlyfViewer.prototype.setSelected = function(selectedList) {
|
||||
GLYFViewer.prototype.setSelected = function(selectedList) {
|
||||
if (selectedList && 0 !== selectedList.length) {
|
||||
var selectedHash = {};
|
||||
|
||||
@@ -315,8 +295,8 @@ define(
|
||||
}
|
||||
};
|
||||
|
||||
require('common/observable').mixin(GlyfViewer.prototype);
|
||||
require('common/observable').mixin(GLYFViewer.prototype);
|
||||
|
||||
return GlyfViewer;
|
||||
return GLYFViewer;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -10,8 +10,76 @@
|
||||
define(
|
||||
function(require) {
|
||||
|
||||
var observable = require('common/observable');
|
||||
|
||||
|
||||
// 绑定click事件
|
||||
function bindClick(components) {
|
||||
var me = this;
|
||||
document.body.addEventListener('click', function(e) {
|
||||
|
||||
// 监听查看器
|
||||
if (components.viewer === e.target || components.viewer.contains(e.target)) {
|
||||
me.viewer.focus();
|
||||
}
|
||||
else {
|
||||
me.viewer.blur();
|
||||
}
|
||||
|
||||
// 监听编辑器
|
||||
if (components.editor) {
|
||||
if (components.editor === e.target || components.editor.contains(e.target)) {
|
||||
me.editor.focus();
|
||||
}
|
||||
else {
|
||||
me.editor.blur();
|
||||
}
|
||||
}
|
||||
|
||||
}, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定键盘事件
|
||||
*/
|
||||
function bindKey() {
|
||||
var me = this;
|
||||
|
||||
document.body.addEventListener('keydown', function(e) {
|
||||
|
||||
// 功能键
|
||||
if (e.keyCode >= 112 && e.keyCode <= 119 && e.keyCode !== 116) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
me.fire('function', {
|
||||
keyCode: e.keyCode
|
||||
});
|
||||
}
|
||||
// 保存
|
||||
else if (83 === e.keyCode && e.ctrlKey) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
me.fire('save');
|
||||
}
|
||||
// 粘贴
|
||||
else if ((e.keyCode == 86 && e.ctrlKey)) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
me.fire('paste');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var program = {
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
init: function(components) {
|
||||
bindClick.call(this, components);
|
||||
bindKey.call(this, components);
|
||||
},
|
||||
|
||||
/**
|
||||
* 暂存对象
|
||||
*
|
||||
@@ -30,6 +98,8 @@ define(
|
||||
loading: require('./loading')
|
||||
};
|
||||
|
||||
observable.mixin(program);
|
||||
|
||||
return program;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -208,7 +208,7 @@ define(
|
||||
*
|
||||
*/
|
||||
Render.prototype.focus = function() {
|
||||
this.capture.start();
|
||||
//this.capture.start();
|
||||
this.keyCapture.start();
|
||||
};
|
||||
|
||||
@@ -217,7 +217,7 @@ define(
|
||||
*
|
||||
*/
|
||||
Render.prototype.blur = function() {
|
||||
this.capture.stop();
|
||||
//this.capture.stop();
|
||||
this.keyCapture.stop();
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user