diff --git a/css/bootstrap.less b/css/bootstrap.less new file mode 100644 index 0000000..1811d91 --- /dev/null +++ b/css/bootstrap.less @@ -0,0 +1,44 @@ + +// overwrite bootstrap themes + + +.modal-dialog { + margin-top: 100px; +} + +.modal-header { + padding-top: 6px; + padding-bottom: 6px; + background: #327EC0; + color: #FFF; + .close { + margin-top: 3px; + } + + .modal-title { + font-size: 14px; + line-height: 25px; + } +} + +.modal-footer { + padding-top: 10px; + padding-bottom: 10px; +} + +.modal-body { + min-height: 100px; +} + +.modal-content { + border-color: rgba(0,0,0,.5); + -webkit-box-shadow: 0 2px 4px rgba(0,0,0,.2); + box-shadow: 0 2px 4px rgba(0,0,0,.2); + overflow: hidden; +} + +.dropdown-menu { + a { + cursor: pointer; + } +} \ No newline at end of file diff --git a/css/common.css b/css/common.css index 03bb674..5cc9f70 100644 --- a/css/common.css +++ b/css/common.css @@ -1,3 +1,35 @@ +.modal-dialog { + margin-top: 100px; +} +.modal-header { + padding-top: 6px; + padding-bottom: 6px; + background: #327EC0; + color: #FFF; +} +.modal-header .close { + margin-top: 3px; +} +.modal-header .modal-title { + font-size: 14px; + line-height: 25px; +} +.modal-footer { + padding-top: 10px; + padding-bottom: 10px; +} +.modal-body { + min-height: 100px; +} +.modal-content { + border-color: rgba(0, 0, 0, 0.5); + -webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + overflow: hidden; +} +.dropdown-menu a { + cursor: pointer; +} body, html { margin: 0; @@ -28,6 +60,7 @@ html { border-radius: 0; margin: 0; position: fixed; + z-index: 10; width: 100%; top: 0; } @@ -35,7 +68,7 @@ html { margin-right: 10px; margin-top: 10px; } -.navbar .btn:first-child { +.navbar > .btn:first-child { margin-left: 10px; } #export-btn { @@ -74,3 +107,11 @@ html { text-align: center; display: none; } +.selection-range { + position: absolute; + z-index: 6; + display: none; + border: 1px solid #CCC; + background: rgba(222, 222, 222, 0.5); + pointer-events: none; +} diff --git a/css/common.less b/css/common.less index 407b1e7..b9ea818 100644 --- a/css/common.less +++ b/css/common.less @@ -1,4 +1,6 @@ +@import './bootstrap.less'; + body, html { margin: 0; padding: 0; @@ -35,6 +37,7 @@ body, html { border-radius: 0; margin: 0; position: fixed; + z-index: 10; width: 100%; top: 0; @@ -43,7 +46,7 @@ body, html { margin-top: 10px; } - .btn:first-child { + >.btn:first-child { margin-left: 10px; } } @@ -88,4 +91,14 @@ body, html { line-height: 24px; text-align: center; display: none; +} + + +.selection-range { + position: absolute; + z-index: 6; + display: none; + border: 1px solid #CCC; + background: rgba(222, 222, 222, 0.5); + pointer-events: none; } \ No newline at end of file diff --git a/css/ico.css b/css/ico.css index 04229be..a7532cc 100644 --- a/css/ico.css +++ b/css/ico.css @@ -2,3 +2,23 @@ font-family: 'fonteditor'; src: url('../font/iconfont.ttf') format('truetype'); } +.i-edit, +.i-del { + display: inline-block; + font-family: 'fonteditor'; + font-size: 12px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -webkit-text-stroke-width: 0.1px; +} +.i-edit:hover, +.i-del:hover { + cursor: pointer; + color: blue; +} +.i-edit:before { + content: '\e605'; +} +.i-del:before { + content: '\e611'; +} diff --git a/css/ico.less b/css/ico.less index 3f51604..00948e8 100644 --- a/css/ico.less +++ b/css/ico.less @@ -6,3 +6,25 @@ src: url('../font/iconfont.ttf') format('truetype'); } +.i-edit, +.i-del { + display: inline-block; + font-family: 'fonteditor'; + font-size: 12px; + font-style:normal; + -webkit-font-smoothing: antialiased; + -webkit-text-stroke-width: 0.1px; + + &:hover { + cursor: pointer; + color: blue; + } +} + +.i-edit:before { + content: '\e605'; +} + +.i-del:before { + content: '\e611'; +} \ No newline at end of file diff --git a/css/ttf.css b/css/ttf.css index c8ce816..d18a35e 100644 --- a/css/ttf.css +++ b/css/ttf.css @@ -1,3 +1,35 @@ +.modal-dialog { + margin-top: 100px; +} +.modal-header { + padding-top: 6px; + padding-bottom: 6px; + background: #327EC0; + color: #FFF; +} +.modal-header .close { + margin-top: 3px; +} +.modal-header .modal-title { + font-size: 14px; + line-height: 25px; +} +.modal-footer { + padding-top: 10px; + padding-bottom: 10px; +} +.modal-body { + min-height: 100px; +} +.modal-content { + border-color: rgba(0, 0, 0, 0.5); + -webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); + overflow: hidden; +} +.dropdown-menu a { + cursor: pointer; +} body, html { margin: 0; @@ -28,6 +60,7 @@ html { border-radius: 0; margin: 0; position: fixed; + z-index: 10; width: 100%; top: 0; } @@ -35,7 +68,7 @@ html { margin-right: 10px; margin-top: 10px; } -.navbar .btn:first-child { +.navbar > .btn:first-child { margin-left: 10px; } #export-btn { @@ -74,26 +107,64 @@ html { text-align: center; display: none; } +.selection-range { + position: absolute; + z-index: 6; + display: none; + border: 1px solid #CCC; + background: rgba(222, 222, 222, 0.5); + pointer-events: none; +} @font-face { font-family: 'fonteditor'; src: url('../font/iconfont.ttf') format('truetype'); } +.i-edit, +.i-del { + display: inline-block; + font-family: 'fonteditor'; + font-size: 12px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -webkit-text-stroke-width: 0.1px; +} +.i-edit:hover, +.i-del:hover { + cursor: pointer; + color: blue; +} +.i-edit:before { + content: '\e605'; +} +.i-del:before { + content: '\e611'; +} .project .project-title { font-weight: bold; } .project .project-list { - line-height: 20px; + line-height: 24px; } .project .project-list div { - padding-left: 10px; + padding: 0 10px; } .project .project-list div:hover { - color: red; - text-decoration: underline; - cursor: pointer; + background: #EFEFEF; +} +.project .project-list div:hover .i-del { + display: block; +} +.project .project-list .i-del { + float: right; + display: none; +} +.glyf-list { + padding-bottom: 40px; + overflow: hidden; } .glyf-list > .glyf-item { float: left; + position: relative; margin: 10px; width: 86px; border: 1px solid #CCC; @@ -123,12 +194,34 @@ html { .glyf-list > .glyf-item .glyf .path { fill: green; } +.glyf-list > .glyf-item .i-del, +.glyf-list > .glyf-item .i-edit { + position: absolute; + right: 2px; + display: none; +} +.glyf-list > .glyf-item .i-edit { + right: 20px; +} .glyf-list > .glyf-item:hover { background: #EFEFEF; } .glyf-list > .glyf-item:hover .path { fill: darkgreen; } +.glyf-list > .glyf-item:hover .i-del, +.glyf-list > .glyf-item:hover .i-edit { + display: block; +} +.glyf-list > .compound .path { + fill: lightgreen!important; +} .glyf-list > .new .path { fill: blue!important; } +.glyf-list > .selected { + background: #EBFFC2!important; +} +.glyf-list.no-hover .glyf-item { + pointer-events: none; +} diff --git a/css/ttf.less b/css/ttf.less index e00836e..d86c2d8 100644 --- a/css/ttf.less +++ b/css/ttf.less @@ -10,15 +10,23 @@ font-weight: bold; } .project-list { - line-height: 20px; + line-height: 24px; div { - padding-left: 10px; + padding: 0 10px; } + div:hover { - color: red; - text-decoration: underline; - cursor: pointer; + background: #EFEFEF; + + .i-del { + display: block; + } + } + + .i-del { + float: right; + display: none; } } } @@ -27,9 +35,13 @@ .glyf-list { + padding-bottom: 40px; + overflow: hidden; + >.glyf-item { float: left; + position: relative; margin: 10px; width: 86px; border: 1px solid #CCC; @@ -59,6 +71,17 @@ fill: green; } } + + .i-del, + .i-edit { + position: absolute; + right: 2px; + display: none; + } + + .i-edit { + right: 20px; + } } >.glyf-item:hover { @@ -66,6 +89,17 @@ .path { fill: darkgreen; } + + .i-del, + .i-edit { + display: block; + } + } + + >.compound { + .path { + fill: lightgreen!important; + } } >.new { @@ -73,4 +107,15 @@ fill: blue!important; } } + + >.selected { + background: #EBFFC2!important; + } } + + +.glyf-list.no-hover { + .glyf-item { + pointer-events: none; + } +} \ No newline at end of file diff --git a/font/iconfont.ttf b/font/iconfont.ttf index 8d03301..e178ff5 100644 Binary files a/font/iconfont.ttf and b/font/iconfont.ttf differ diff --git a/src/fonteditor/dialog/setting-unicode.js b/src/fonteditor/dialog/setting-unicode.js new file mode 100644 index 0000000..0c340d1 --- /dev/null +++ b/src/fonteditor/dialog/setting-unicode.js @@ -0,0 +1,45 @@ +/** + * @file setting-unicode.js + * @author mengke01 + * @date + * @description + * 设置代码点 + */ + +define( + function(require) { + + var tpl = '' + + '
' + + '
' + + '
' + + '' + + '' + + '
' + + '' + + '
' + + '
'; + + return require('./setting').derive({ + + getTpl: function() { + return tpl; + }, + onConfirm: function() { + var unicode = $('#setting-text-unicode').val(); + if (unicode.match(/^\$[A-E0-9]+$/i)) { + this.fire('change', { + unicode: unicode + }); + } + else { + alert('代码点设置不正确'); + return false; + } + } + }); + } +); diff --git a/src/fonteditor/dialog/setting.js b/src/fonteditor/dialog/setting.js new file mode 100644 index 0000000..5fc0359 --- /dev/null +++ b/src/fonteditor/dialog/setting.js @@ -0,0 +1,104 @@ +/** + * @file setting.js + * @author mengke01 + * @date + * @description + * 设置框 + */ + + +define( + function(require) { + var lang = require('common/lang'); + var observable = require('common/observable'); + + /** + * 设置框函数 + * + * @constructor + */ + function Setting() { + } + + /** + * 初始化绑定事件 + */ + Setting.prototype.preInit = function() { + var dlg = $('#model-dialog'); + dlg.find('.modal-title').html(this.title); + dlg.find('.modal-body').html(this.getTpl()); + + dlg.on('hidden.bs.modal', lang.bind(function (e) { + if (dlg) { + this.un(); + dlg.off('hidden.bs.modal'); + dlg.find('.btn-confirm').off('click'); + dlg = null; + } + }, this)); + + dlg.find('.btn-confirm').on('click', lang.bind(function() { + if (false !== this.onConfirm()) { + dlg.modal('hide'); + } + }, this)); + }; + + /** + * 获取模板 + * + * @return {string} 模板字符串 + */ + Setting.prototype.getTpl = function() { + return ''; + }; + + /** + * 确定事件 + * + * @return {boolean=} 是否关闭对话框 + */ + Setting.prototype.onConfirm = function() { + }; + + /** + * 显示 + */ + Setting.prototype.show = function() { + $('#model-dialog').modal('show'); + return this; + }; + + /** + * 注销 + */ + Setting.prototype.dispose = function() { + $('#model-dialog').modal('hide'); + }; + + + /** + * 派生一个setting + * + * @param {Object} proto 原型函数 + * @return {Function} 派生类 + */ + Setting.derive = function(proto) { + + function Class() { + Setting.apply(this, arguments); + this.preInit(); + this.initialize && this.initialize(); + } + + Class.prototype = new Setting(); + Class.prototype.constructor = Setting; + lang.extend(Class.prototype, proto); + observable.mixin(Class.prototype); + + return Class; + }; + + return Setting; + } +); diff --git a/src/fonteditor/ttf/main.js b/src/fonteditor/ttf/main.js index 9a7d9ae..c366af5 100644 --- a/src/fonteditor/ttf/main.js +++ b/src/fonteditor/ttf/main.js @@ -14,37 +14,72 @@ define( var exporter = require('../widget/exporter'); var project = require('../widget/project'); var ProjectViewer = require('../widget/projectviewer'); - var ttfmanager = require('../widget/ttfmanager'); + var TTFManager = require('../widget/ttfmanager'); var program = require('../program'); var string = require('common/string'); + var setting = { + 'unicode': require('../dialog/setting-unicode') + } + var actions = { - new: function() { - if (program.data.ttf && !window.confirm('是否放弃保存当前项目?')) { + 'new': function() { + if (program.ttfmanager.get() && !window.confirm('是否放弃保存当前项目?')) { return; } newEmpty(); - }, - open: function() { + }, + 'open': function() { $('#font-import').click(); }, - import: function() { + + 'import': function() { $('#font-import').click(); }, - export: function() { + + 'export': function() { }, - save: function() { + + 'save': function() { saveProj(); + }, + + 'add-new': function() { + program.ttfmanager.addglyf({ + name: '', + unicode:[] + }); + }, + + 'setting-unicode': function(e) { + var dlg = new setting.unicode(); + + dlg.on('change', function(e) { + // 此处延迟处理 + setTimeout(function(){ + setUnicode(e.unicode); + }, 20); + }); + + dlg.show(); } }; + // 设置unicode + function setUnicode(unicode) { + if (program.ttfmanager.get()) { + var glyfList = program.viewer.getSelected(); + program.ttfmanager.setUnicode(unicode, glyfList); + } + + } // 保存项目 function saveProj() { - if (program.data.ttf) { + if (program.ttfmanager.get()) { var name = ''; if(name = window.prompt('请输入项目名称:')) { - var list = project.add(string.encodeHTML(name), program.data.ttf); + var list = project.add(string.encodeHTML(name), program.ttfmanager.get()); program.projectViewer.show(list); } } @@ -53,8 +88,7 @@ define( // 新建空白 function newEmpty() { $.getJSON('./src/fonteditor/data/empty.json', function(imported) { - program.data.ttf = imported; - program.viewer.show(imported); + program.ttfmanager.set(imported); }) } @@ -63,23 +97,20 @@ define( var file = e.target.files[0]; if (program.action == 'open' && file.name.match(/(\.ttf|\.woff)$/)) { - program.data.file = file.name; loader.load(file, { type: file.name.slice(file.name.lastIndexOf('.') + 1), success: function(imported) { - program.data.ttf = imported; - program.viewer.show(imported); + program.ttfmanager.set(imported); } }); } else if (program.action == 'import' && file.name.match(/(\.ttf|\.woff|\.svg)$/)) { - if (program.data.ttf) { + if (program.ttfmanager.get()) { loader.load(file, { type: file.name.slice(file.name.lastIndexOf('.') + 1), success: function(imported) { if (imported.glyf.length) { - ttfmanager.combine(program.data.ttf, imported, {scale: true}); - program.viewer.show(program.data.ttf); + program.ttfmanager.combine(imported, {scale: true}); } } }); @@ -93,10 +124,9 @@ define( } function exportFile(e) { - var ttf = program.data.ttf; - if (ttf) { + if (program.ttfmanager.get()) { var target = $(e.target); - exporter.export(ttf, { + exporter.export(program.ttfmanager.get(), { type: target.attr('data-type'), target: target }); @@ -128,21 +158,39 @@ define( init: function () { bindEvent(); + // 查看器 program.viewer = new GLYFViewer($('#glyf-list')); + program.viewer.on('del', function(e) { + if (e.list) { + program.ttfmanager.delglyf(e.list); + } + }); + + // 项目管理 program.projectViewer = new ProjectViewer($('#project-list')); program.projectViewer.on('open', function(e) { var imported = project.get(e.projectName); if (imported) { - if (program.data.ttf && !window.confirm('是否放弃保存当前项目?')) { + if (program.ttfmanager.get() && !window.confirm('是否放弃保存当前项目?')) { return; } - program.data.ttf = imported; - program.viewer.show(imported); + program.ttfmanager.set(imported); + } + }); + program.projectViewer.on('del', function(e) { + if (e.projectName && window.confirm('是否删除项目?')) { + program.projectViewer.show(project.remove(e.projectName)); } }); program.projectViewer.show(project.items()); + // ttf管理 + program.ttfmanager = new TTFManager(); + program.ttfmanager.on('change', function(e) { + program.viewer.show(e.ttf); + }); + } }; diff --git a/src/fonteditor/widget/glyfviewer.js b/src/fonteditor/widget/glyfviewer.js index d2a1377..802c3e4 100644 --- a/src/fonteditor/widget/glyfviewer.js +++ b/src/fonteditor/widget/glyfviewer.js @@ -10,11 +10,15 @@ define( function(require) { var glyf2svg = require('ttf/util/glyf2svg'); var string = require('common/string'); - + var lang = require('common/lang'); + var MouseCapture = require('render/capture/Mouse'); + var isBoundingBoxCross = require('graphics/isBoundingBoxCross'); + var GLYF_ITEM_TPL = '' + '
' + + '' + '' - + '
${unicode}
${name}
' + + '
${unicode}
${name}
' + '
'; @@ -46,6 +50,28 @@ define( this.main.html(glyfStr); } + + // 点击item + function clickItem(e) { + $(this).toggleClass('selected'); + } + + // 点击item + function clickAction(e) { + e.stopPropagation(); + var target = $(e.target); + var action = target.attr('data-action'); + + if (action == 'del' && !window.confirm('确定删除字形么?')) { + return; + } + + var selected = [+target.parent().attr('data-index')]; + this.fire(action, { + list: selected + }); + } + /** * glyf查看器 * @@ -56,12 +82,129 @@ define( function GlyfViewer(main, options) { this.options = options || {}; this.main = $(main); + + this.main.delegate('[data-index]', 'click', clickItem) + .delegate('[data-action]', 'click', lang.bind(clickAction, this)); + + + var me = this; + // 绑定键盘事件 + me.listener = function(e) { + + // 删除 + if (46 === e.keyCode) { + e.stopPropagation(); + var selected = me.getSelected(); + if (selected.length) { + me.fire('del', { + list: selected + }); + } + } + // 取消选中 + else if (27 === e.keyCode) { + me.main.children().removeClass('selected'); + } + + }; + + + $(document.body).on('click', function(e) { + var focused = me.main.get(0) === e.target || me.main.get(0).contains(e.target); + if (focused && !me.listening) { + document.body.addEventListener('keyup', me.listener,false); + me.listening = true; + } + else if (!focused){ + document.body.removeEventListener('keyup', me.listener); + me.listening = false; + } + }); + + // 选择范围内元素 + function selectRangeItem(bound, toggle, remove) { + me.main.children().each(function(i, element) { + var item = $(element); + var pos = item.offset(); + var b = { + x: pos.left, + y: pos.top, + width: item.width(), + height: item.height() + } + if (3 === isBoundingBoxCross(bound, b)) { + if (toggle) { + item.toggleClass('selected'); + } + else if (remove) { + item.removeClass('selected') + } + else { + item.addClass('selected') + } + } + }); + } + + + me.capture = new MouseCapture(me.main.get(0), { + events: { + dblclick: false, + mousewheel: false, + mouseover: false, + mouseout: false + } + }); + + me.capture.on('dragstart', function(e) { + $('#selection-range').show(); + me.main.addClass('no-hover'); + me.startX = e.originEvent.pageX; + me.startY = e.originEvent.pageY; + }); + + var dragging = function(e) { + var x = e.originEvent.pageX; + var y = e.originEvent.pageY; + $('#selection-range').css({ + left: Math.min(me.startX, x), + top: Math.min(me.startY, y), + width: Math.abs(me.startX - x), + height: Math.abs(me.startY - y) + }); + }; + me.capture.on('drag', dragging); + + me.capture.on('dragend', function(e) { + $('#selection-range').hide(); + me.main.removeClass('no-hover'); + + var x = e.originEvent.pageX; + var y = e.originEvent.pageY; + var pos = me.main.offset(); + + selectRangeItem.call(me, { + x: Math.min(me.startX, x), + y: Math.min(me.startY, y), + width: Math.abs(me.startX - x), + height: Math.abs(me.startY - y) + }, e.ctrlKey, e.shiftKey); + }); + } GlyfViewer.prototype.show = function(ttf) { showGLYF.call(this, ttf); }; + GlyfViewer.prototype.getSelected = function() { + var selected = []; + this.main.find('.selected').each(function(index, item) { + selected.push(+item.getAttribute('data-index')); + }); + return selected; + }; + require('common/observable').mixin(GlyfViewer.prototype); return GlyfViewer; diff --git a/src/fonteditor/widget/project.js b/src/fonteditor/widget/project.js index e3f1038..f995204 100644 --- a/src/fonteditor/widget/project.js +++ b/src/fonteditor/widget/project.js @@ -33,11 +33,22 @@ define( */ add: function(projectName, ttf) { var list = this.items(); - var id = Date.now(); - list.push({ - name: projectName, - id: id + var exist = list.filter(function(l) { + return l.name == projectName; }); + + var id; + if (exist.length) { + id = exist[0].id; + } + else { + id = Date.now(); + list.push({ + name: projectName, + id: id + }); + } + storage.setItem('project-list', JSON.stringify(list)); storage.setItem(id, JSON.stringify(ttf)); return list; @@ -58,6 +69,8 @@ define( } } storage.setItem('project-list', JSON.stringify(list)); + + return list; }, /** diff --git a/src/fonteditor/widget/projectviewer.js b/src/fonteditor/widget/projectviewer.js index a6f1cc2..4cce994 100644 --- a/src/fonteditor/widget/projectviewer.js +++ b/src/fonteditor/widget/projectviewer.js @@ -22,7 +22,18 @@ define( this.main = $(main); var me = this; - this.main.delegate('[data-name]', 'click', function(e) { + + me.main.delegate('[data-action]', 'click', function(e) { + e.stopPropagation(); + var the = $(this); + me.fire(the.attr('data-action'), { + projectName: the.parent().attr('data-name') + }); + }); + + me.main.delegate('[data-name]', 'click', function(e) { + e.preventDefault(); + e.stopPropagation(); me.fire('open', { projectName: $(this).attr('data-name') }); @@ -32,7 +43,7 @@ define( ProjectViewer.prototype.show = function(projects) { var str = ''; (projects || []).forEach(function(proj) { - str += '
'+ proj.name +'
'; + str += '
'+ proj.name +'
'; }); this.main.html(str); diff --git a/src/fonteditor/widget/ttfmanager.js b/src/fonteditor/widget/ttfmanager.js index 278f7f1..5d84e80 100644 --- a/src/fonteditor/widget/ttfmanager.js +++ b/src/fonteditor/widget/ttfmanager.js @@ -10,49 +10,193 @@ define( function(require) { + var postName = require('ttf/enum/postName'); var pathAdjust = require('graphics/pathAdjust'); - var manager = { - /** - * 合并两个ttfObject,此处仅合并简单字形 - * - * @param {Object} ttf ttfObject - * @param {Object} imported ttfObject - * @param {Object} options 参数选项 - * @param {boolean} options.scale 是否自动缩放 - * - * @return {Object} 合并后的ttfObject - */ - combine: function(ttf, imported, options) { - options = options || {}; - // 调整glyf以适应打开的文件 - var scale = 1; - // 对导入的轮廓进行缩放处理 - if (options.scale && imported.head.unitsPerEm && imported.head.unitsPerEm != ttf.head.unitsPerEm) { - scale = ttf.head.unitsPerEm / imported.head.unitsPerEm; - } + /** + * 合并两个ttfObject,此处仅合并简单字形 + * + * @param {Object} ttf ttfObject + * @param {Object} imported ttfObject + * @param {Object} options 参数选项 + * @param {boolean} options.scale 是否自动缩放 + * + * @return {Object} 合并后的ttfObject + */ + function combine(ttf, imported, options) { + options = options || {}; - imported.glyf.filter(function(g, index) { - - return g.contours && g.contours.length //简单轮廓 - && g.name != '.notdef' && g.name != '.null' && g.name != 'nonmarkingreturn'; // 非预定义字形 - - }).forEach(function(g) { - if (scale !== 1) { - g.contours.forEach(function(contour) { - pathAdjust(contour, scale, scale); - }); - } - g.modify = 'new'; - ttf.glyf.push(g); - }); - - return ttf; + // 调整glyf以适应打开的文件 + var scale = 1; + // 对导入的轮廓进行缩放处理 + if (options.scale && imported.head.unitsPerEm && imported.head.unitsPerEm != ttf.head.unitsPerEm) { + scale = ttf.head.unitsPerEm / imported.head.unitsPerEm; } + + imported.glyf.filter(function(g, index) { + return g.contours && g.contours.length //简单轮廓 + && g.name != '.notdef' && g.name != '.null' && g.name != 'nonmarkingreturn'; // 非预定义字形 + + }).forEach(function(g) { + if (scale !== 1) { + g.contours.forEach(function(contour) { + pathAdjust(contour, scale, scale); + }); + } + g.modify = 'new'; + ttf.glyf.push(g); + }); + + return ttf; + } + + /** + * 构造函数 + * + * @constructor + * @param {ttfObject} ttf ttf对象 + */ + function Manager(ttf) { + this.ttf = ttf; + } + + /** + * 设置ttf + * + * @param {ttfObject} ttf ttf对象 + * @return {this} + */ + Manager.prototype.set = function(ttf) { + + if (this.ttf !== ttf) { + this.ttf = ttf; + this.fire('change', { + ttf: this.ttf + }); + } + + return this; }; - return manager; + /** + * 获取ttf对象 + * + * @return {ttfObject} ttf ttf对象 + */ + Manager.prototype.get = function() { + return this.ttf; + }; + + /** + * 添加glyf + * + * @param {Object} glyf glyf对象 + * + * @return {this} + */ + Manager.prototype.addglyf = function(glyf) { + this.ttf.glyf.push(glyf); + this.fire('change', { + ttf: this.ttf + }); + return this; + }; + + /** + * 合并两个ttfObject,此处仅合并简单字形 + * + * @param {Object} imported ttfObject + * @param {Object} options 参数选项 + * @param {boolean} options.scale 是否自动缩放 + * + * @return {this} + */ + Manager.prototype.combine = function(imported, options) { + combine(this.ttf, imported, options); + this.fire('change', { + ttf: this.ttf + }); + return this; + }; + + + /** + * 删除指定字形 + * + * @param {Array} indexList 索引列表 + * @return {this} + */ + Manager.prototype.delglyf = function(indexList) { + var glyf = this.ttf.glyf, count = 0; + for(var i = glyf.length - 1; i >= 0; i--) { + if (indexList.indexOf(i) >= 0) { + glyf.splice(i, 1); + count++; + } + } + + if (count) { + this.fire('change', { + ttf: this.ttf + }); + } + + return this; + }; + + + /** + * 设置unicode代码 + * + * @param {string} unicode unicode代码 + * @param {Array} indexList 索引列表 + * @return {this} + */ + Manager.prototype.setUnicode = function(unicode, indexList) { + var glyf = this.ttf.glyf, list; + if (indexList && indexList.length) { + list = indexList.map(function(item) { + return glyf[item]; + }); + } + else { + list = glyf; + } + + list = list.filter(function(g) { + return g.name != '.notdef' && g.name != '.null' && g.name != 'nonmarkingreturn'; + }); + + if (list.length) { + + unicode = Number('0x' + unicode.slice(1)); + + list.forEach(function(g) { + g.unicode = [unicode]; + g.name = unicode - 29 < 258 ? postName[unicode - 29] : 'uni' + unicode.toString(16).toUpperCase(); + unicode++; + }); + + this.fire('change', { + ttf: this.ttf + }); + } + + return this; + }; + + /** + * 注销 + */ + Manager.prototype.dispose = function() { + this.un(); + delete this.ttf; + }; + + require('common/observable').mixin(Manager.prototype); + + return Manager; } ); diff --git a/src/graphics/isBoundingBoxCross.js b/src/graphics/isBoundingBoxCross.js index 4915723..1f2c2f9 100644 --- a/src/graphics/isBoundingBoxCross.js +++ b/src/graphics/isBoundingBoxCross.js @@ -21,7 +21,7 @@ define( * @return {number} 包含关系 * * 2 : b2 包含 b1 - * 3 : b2 包含 b3 + * 3 : b1 包含 b2 * 1 : 有交点 */ function isBoundingBoxCross(b1, b2) { diff --git a/src/render/capture/Mouse.js b/src/render/capture/Mouse.js index 6e3db00..378244a 100644 --- a/src/render/capture/Mouse.js +++ b/src/render/capture/Mouse.js @@ -48,7 +48,8 @@ define( ctrlKey: e.ctrlKey, metaKey: e.metaKey, altKey: e.altKey, - shiftKey: e.shiftKey + shiftKey: e.shiftKey, + originEvent: e }; } @@ -73,12 +74,13 @@ define( */ function mousedown(e) { - prevent(e); if(false === this.events.mousedown) { return; } + prevent(e); + var event = getEvent(e); this.startX = event.x; @@ -117,12 +119,13 @@ define( * @param {Object} e 事件参数 */ function mousemove(e) { - prevent(e); if(false === this.events.mousemove) { return; } + prevent(e); + var event = getEvent(e); this.fire('move', event); @@ -155,12 +158,13 @@ define( */ function mouseup(e) { - prevent(e); if(false === this.events.mouseup) { return; } + prevent(e); + var event = getEvent(e); event.time = Date.now() - this.startTime; @@ -193,12 +197,12 @@ define( */ function mousewheel(e) { - prevent(e); - if(false === this.events.mousewheel) { return; } + prevent(e); + var delta = 0; if (e.wheelDelta) { delta = e.wheelDelta / 120; @@ -220,10 +224,13 @@ define( * @param {Object} e 事件参数 */ function mouseover(e) { - prevent(e); + if(false === this.events.mouseover) { return; } + + prevent(e); + this.fire('over'); } @@ -233,10 +240,13 @@ define( * @param {Object} e 事件参数 */ function mouseout(e) { - prevent(e); + if(false === this.events.mouseout) { return; } + + prevent(e); + this.fire('out'); } diff --git a/ttf.html b/ttf.html index 803f726..6f30d26 100644 --- a/ttf.html +++ b/ttf.html @@ -12,11 +12,39 @@ - 导出ttf - 导出woff - 导出svg - - + +
+ + + +
+ + 导出ttf + 导出woff + 导出svg + + + +
+ + + + +
+ +
正在加载...
+ + + + @@ -47,6 +94,6 @@ define('jquery', $); require(['fonteditor/ttf/main']) -
+
\ No newline at end of file