add ttf viewer
This commit is contained in:
parent
76e1a51bfd
commit
917d134698
10
css/ttf.css
10
css/ttf.css
@ -78,10 +78,16 @@ html {
|
||||
font-family: 'fonteditor';
|
||||
src: url('../font/iconfont.ttf') format('truetype');
|
||||
}
|
||||
.project-list dd {
|
||||
.project .project-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
.project .project-list {
|
||||
line-height: 20px;
|
||||
}
|
||||
.project .project-list div {
|
||||
padding-left: 10px;
|
||||
}
|
||||
.project-list dd:hover {
|
||||
.project .project-list div:hover {
|
||||
color: red;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
|
24
css/ttf.less
24
css/ttf.less
@ -4,18 +4,28 @@
|
||||
@import './util.less';
|
||||
@import './ico.less';
|
||||
|
||||
.project-list {
|
||||
dd {
|
||||
padding-left: 10px;
|
||||
|
||||
.project {
|
||||
.project-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
dd:hover {
|
||||
color: red;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
.project-list {
|
||||
line-height: 20px;
|
||||
|
||||
div {
|
||||
padding-left: 10px;
|
||||
}
|
||||
div:hover {
|
||||
color: red;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.glyf-list {
|
||||
>.glyf-item {
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
BIN
font/empty.ttf
Normal file
BIN
font/empty.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
src/fonteditor/data/empty.json
Normal file
1
src/fonteditor/data/empty.json
Normal file
@ -0,0 +1 @@
|
||||
{"version":1,"numTables":12,"searchRenge":128,"entrySelector":3,"rengeShift":64,"head":{"version":1,"fontRevision":1,"checkSumAdjustment":369537602,"magickNumber":1594834165,"flags":11,"unitsPerEm":1024,"created":"2014-12-06T22:05:19.000Z","modified":"2014-12-06T22:20:03.000Z","xMin":34,"yMin":0,"xMax":306,"yMax":682,"macStyle":0,"lowestRecPPEM":8,"fontDirectionHint":2,"indexToLocFormat":0,"glyphDataFormat":0},"glyf":[{"contours":[[{"x":34,"y":0,"onCurve":true},{"x":34,"y":682,"onCurve":true},{"x":306,"y":682,"onCurve":true},{"x":306,"y":0,"onCurve":true}],[{"x":68,"y":34,"onCurve":true},{"x":272,"y":34,"onCurve":true},{"x":272,"y":648,"onCurve":true},{"x":68,"y":648,"onCurve":true}]],"xMin":34,"yMin":0,"xMax":306,"yMax":682,"advanceWidth":374,"leftSideBearing":34,"name":".notdef"}],"cmap":{},"name":{"fontFamily":"fonteditor","fontSubFamily":"Medium","uniqueSubFamily":"FontEditor 1.0 : fonteditor : 6-10-2014","fullName":"fonteditor","version":"Version 1.0 ; ttfautohint (v0.94) -l 8 -r 50 -G 200 -x 14 -w \"G\" -f -s","postScriptName":"fonteditor"},"hhea":{"version":1,"ascent":812,"descent":-212,"lineGap":92,"advanceWidthMax":374,"minLeftSideBearing":34,"minRightSideBearing":68,"xMaxExtent":306,"caretSlopeRise":1,"caretSlopeRun":0,"caretOffset":0,"reserved0":0,"reserved1":0,"reserved2":0,"reserved3":0,"metricDataFormat":0,"numOfLongHorMetrics":1},"post":{"italicAngle":0,"postoints":65411,"underlinePosition":50,"underlineThickness":0,"isFixedPitch":0,"minMemType42":0,"maxMemType42":0,"minMemType1":0,"maxMemType1":1,"format":2},"OS/2":{"version":4,"xAvgCharWidth":1031,"usWeightClass":400,"usWidthClass":5,"fsType":0,"ySubscriptXSize":665,"ySubscriptYSize":716,"ySubscriptXOffset":0,"ySubscriptYOffset":143,"ySuperscriptXSize":665,"ySuperscriptYSize":716,"ySuperscriptXOffset":0,"ySuperscriptYOffset":491,"yStrikeoutSize":51,"yStrikeoutPosition":265,"sFamilyClass":0,"bFamilyType":2,"bSerifStyle":0,"bWeight":6,"bProportion":3,"bContrast":0,"bStrokeVariation":0,"bArmStyle":0,"bLetterform":0,"bMidline":0,"bXHeight":0,"ulUnicodeRange1":1,"ulUnicodeRange2":268435456,"ulUnicodeRange3":0,"ulUnicodeRange4":0,"achVendID":"PfEd","fsSelection":192,"usFirstCharIndex":0,"usLastCharIndex":0,"sTypoAscender":812,"sTypoDescender":-212,"sTypoLineGap":92,"usWinAscent":812,"usWinDescent":212,"ulCodePageRange1":1,"ulCodePageRange2":0,"sxHeight":792,"sCapHeight":0,"usDefaultChar":0,"usBreakChar":32,"usMaxContext":1}}
|
@ -19,21 +19,7 @@ define(
|
||||
*/
|
||||
data: {},
|
||||
|
||||
/**
|
||||
* loading动画
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
loading: {
|
||||
|
||||
show: function(text) {
|
||||
$('#loading').html(text || '正在加载...').show();
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
$('#loading').hide();
|
||||
}
|
||||
}
|
||||
loading: require('./widget/loading')
|
||||
};
|
||||
|
||||
return program;
|
||||
|
@ -9,132 +9,53 @@
|
||||
define(
|
||||
function(require) {
|
||||
|
||||
var GLYFViewer = require('../widget/glyfviewer');
|
||||
var loader = require('../widget/loader');
|
||||
var exporter = require('../widget/exporter');
|
||||
var project = require('../widget/project');
|
||||
var ProjectViewer = require('../widget/projectviewer');
|
||||
var ttfmanager = require('../widget/ttfmanager');
|
||||
var program = require('../program');
|
||||
var TTFReader = require('ttf/ttfreader');
|
||||
var glyf2svg = require('ttf/util/glyf2svg');
|
||||
var svg2ttfobject = require('ttf/svg2ttfobject');
|
||||
var string = require('common/string');
|
||||
var pathAdjust = require('graphics/pathAdjust');
|
||||
var TTFWriter = require('ttf/ttfwriter');
|
||||
var ttf2woff = require('ttf/ttf2woff');
|
||||
var woff2ttf = require('ttf/woff2ttf');
|
||||
var ttf2base64 = require('ttf/ttf2base64');
|
||||
var woff2base64 = require('ttf/woff2base64');
|
||||
|
||||
var woffOptions = {
|
||||
inflate: require('inflate').inflate
|
||||
};
|
||||
|
||||
var GLYF_ITEM_TPL = ''
|
||||
+ '<div data-index="${index}" class="glyf-item ${modify}">'
|
||||
+ '<svg class="glyf" viewbox="0 0 ${unitsPerEm} ${unitsPerEm}"><g transform="scale(1, -1) translate(0, -${descent}) scale(0.95, 0.95) "><path class="path" ${d}/></g></svg>'
|
||||
+ '<div class="unicode" title="${unicode}">${unicode}</div><div class="name" title="${name}">${name}</div>'
|
||||
+ '</div>';
|
||||
|
||||
|
||||
var actions = {
|
||||
new: function() {
|
||||
if (program.data.ttf && !window.confirm('是否放弃保存当前项目?')) {
|
||||
return;
|
||||
}
|
||||
newEmpty();
|
||||
},
|
||||
open: function() {
|
||||
$('#font-import').click();
|
||||
},
|
||||
svg: function() {
|
||||
import: function() {
|
||||
$('#font-import').click();
|
||||
},
|
||||
export: function() {
|
||||
//$(this).attr('href', '#');
|
||||
},
|
||||
save: function() {
|
||||
saveProj();
|
||||
}
|
||||
};
|
||||
|
||||
// 显示glyf
|
||||
function showGLYF(ttf) {
|
||||
var unitsPerEm = ttf.head.unitsPerEm;
|
||||
var descent = unitsPerEm + ttf.hhea.descent;
|
||||
var glyfStr = '', d = '';
|
||||
ttf.glyf.forEach(function(glyf, index) {
|
||||
var g = {
|
||||
index: index,
|
||||
modify: glyf.modify,
|
||||
unitsPerEm: unitsPerEm,
|
||||
descent: descent,
|
||||
unicode: (glyf.unicode || []).map(function(u) {
|
||||
return '$' + u.toString(16).toUpperCase();
|
||||
}).join(','),
|
||||
name: glyf.name
|
||||
};
|
||||
|
||||
if (d = glyf2svg(glyf, ttf)) {
|
||||
g.d = 'd="'+ d +'"';
|
||||
// 保存项目
|
||||
function saveProj() {
|
||||
if (program.data.ttf) {
|
||||
var name = '';
|
||||
if(name = window.prompt('请输入项目名称:')) {
|
||||
var list = project.add(string.encodeHTML(name), program.data.ttf);
|
||||
program.projectViewer.show(list);
|
||||
}
|
||||
|
||||
glyfStr += string.format(GLYF_ITEM_TPL, g);
|
||||
});
|
||||
|
||||
$('#glyf-list').get(0).innerHTML = glyfStr;
|
||||
}
|
||||
}
|
||||
|
||||
// 加载ttf
|
||||
function loadSFNT(file, type) {
|
||||
program.loading.show();
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function(e) {
|
||||
var buffer = e.target.result;
|
||||
|
||||
if (type == 'woff') {
|
||||
buffer = woff2ttf(buffer, woffOptions);
|
||||
}
|
||||
|
||||
var ttfReader = new TTFReader();
|
||||
program.data.ttf = ttfReader.read(buffer);
|
||||
showGLYF(program.data.ttf);
|
||||
ttfReader.dispose();
|
||||
fileReader = null;
|
||||
program.loading.hide();
|
||||
}
|
||||
|
||||
fileReader.onerror = function(e) {
|
||||
program.loading.hide();
|
||||
alert('读取文件出错!');
|
||||
fileReader = null;
|
||||
};
|
||||
fileReader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
// 加载svg
|
||||
function loadSVG(file) {
|
||||
program.loading.show();
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function(e) {
|
||||
var buffer = e.target.result;
|
||||
var imported = svg2ttfobject(buffer);
|
||||
var ttf = program.data.ttf;
|
||||
var scale = 1;
|
||||
|
||||
// 对导入的轮廓进行缩放处理
|
||||
if (imported.head.unitsPerEm && imported.head.unitsPerEm != ttf.head.unitsPerEm) {
|
||||
scale = ttf.head.unitsPerEm / imported.head.unitsPerEm;
|
||||
}
|
||||
|
||||
imported.glyf.forEach(function(g) {
|
||||
if (g.contours && g.contours.length) {
|
||||
if (scale !== 1) {
|
||||
g.contours.forEach(function(contour) {
|
||||
pathAdjust(contour, scale, scale);
|
||||
});
|
||||
}
|
||||
g.modify = 'new';
|
||||
ttf.glyf.push(g);
|
||||
}
|
||||
});
|
||||
|
||||
showGLYF(program.data.ttf);
|
||||
fileReader = null;
|
||||
program.loading.hide();
|
||||
}
|
||||
|
||||
fileReader.onerror = function(e) {
|
||||
program.loading.hide();
|
||||
alert('读取文件出错!');
|
||||
fileReader = null;
|
||||
};
|
||||
fileReader.readAsText(file);
|
||||
// 新建空白
|
||||
function newEmpty() {
|
||||
$.getJSON('./src/fonteditor/data/empty.json', function(imported) {
|
||||
program.data.ttf = imported;
|
||||
program.viewer.show(imported);
|
||||
})
|
||||
}
|
||||
|
||||
// 打开文件
|
||||
@ -143,41 +64,45 @@ define(
|
||||
|
||||
if (program.action == 'open' && file.name.match(/(\.ttf|\.woff)$/)) {
|
||||
program.data.file = file.name;
|
||||
loadSFNT(file, file.name.slice(file.name.lastIndexOf('.') + 1));
|
||||
loader.load(file, {
|
||||
type: file.name.slice(file.name.lastIndexOf('.') + 1),
|
||||
success: function(imported) {
|
||||
program.data.ttf = imported;
|
||||
program.viewer.show(imported);
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (program.action == 'svg' && file.name.match(/\.svg$/)) {
|
||||
else if (program.action == 'import' && file.name.match(/(\.ttf|\.woff|\.svg)$/)) {
|
||||
if (program.data.ttf) {
|
||||
loadSVG(file);
|
||||
}
|
||||
else {
|
||||
alert('没有要编辑的文件!');
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
alert('无法识别文件类型!');
|
||||
}
|
||||
|
||||
e.target.value = '';
|
||||
}
|
||||
|
||||
function exportTTF(e) {
|
||||
function exportFile(e) {
|
||||
var ttf = program.data.ttf;
|
||||
if (ttf) {
|
||||
var buffer = new TTFWriter().write(ttf);
|
||||
var target = $(e.target);
|
||||
target.attr('download', (ttf.name.fontFamily || 'export') + '.ttf');
|
||||
target.attr('href', ttf2base64(buffer));
|
||||
exporter.export(ttf, {
|
||||
type: target.attr('data-type'),
|
||||
target: target
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function exportWOFF(e) {
|
||||
var ttf = program.data.ttf;
|
||||
if (ttf) {
|
||||
var buffer = ttf2woff(new TTFWriter().write(ttf));
|
||||
e.target.download = (ttf.name.fontFamily || 'export') + '.woff';
|
||||
e.target.href = ttf2base64(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
// 绑定组件
|
||||
function bindEvent() {
|
||||
$('.navbar').delegate('[data-action]', 'click', function(e) {
|
||||
@ -188,8 +113,9 @@ define(
|
||||
}
|
||||
});
|
||||
|
||||
$('#export-btn').on('mouseup', exportTTF);
|
||||
$('#export-btn-woff').on('mouseup', exportWOFF);
|
||||
$('#export-btn').on('mouseup', exportFile);
|
||||
$('#export-btn-woff').on('mouseup', exportFile);
|
||||
$('#export-btn-svg').on('mouseup', exportFile);
|
||||
|
||||
document.getElementById('font-import').addEventListener('change', onUpFile);
|
||||
}
|
||||
@ -201,6 +127,22 @@ define(
|
||||
*/
|
||||
init: function () {
|
||||
bindEvent();
|
||||
|
||||
program.viewer = new GLYFViewer($('#glyf-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('是否放弃保存当前项目?')) {
|
||||
return;
|
||||
}
|
||||
program.data.ttf = imported;
|
||||
program.viewer.show(imported);
|
||||
}
|
||||
});
|
||||
program.projectViewer.show(project.items());
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
77
src/fonteditor/widget/exporter.js
Normal file
77
src/fonteditor/widget/exporter.js
Normal file
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* @file exporter.js
|
||||
* @author mengke01
|
||||
* @date
|
||||
* @description
|
||||
* 导出器
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function(require) {
|
||||
|
||||
var TTFWriter = require('ttf/ttfwriter');
|
||||
var ttf2woff = require('ttf/ttf2woff');
|
||||
var ttf2svg = require('ttf/ttf2svg');
|
||||
var ttf2base64 = require('ttf/ttf2base64');
|
||||
var woff2base64 = require('ttf/woff2base64');
|
||||
var svg2base64 = require('ttf/svg2base64');
|
||||
|
||||
/**
|
||||
* 导出SFNT结构字体
|
||||
*
|
||||
* @param {Object} ttf ttf字体结构
|
||||
* @param {Object} options 参数
|
||||
* @param {Object} options.type 文件类型
|
||||
* @param {Object} options.fileName 文件名
|
||||
* @param {Function} options.success 成功回调
|
||||
* @param {Function} options.error 失败回调
|
||||
*
|
||||
* @return {HTMLElement} 导出按钮
|
||||
*/
|
||||
function exportFile(ttf, options) {
|
||||
|
||||
if (ttf) {
|
||||
var base64Str = '';
|
||||
if (options.type == 'woff') {
|
||||
var buffer = ttf2woff(new TTFWriter().write(ttf));
|
||||
base64Str = woff2base64(buffer);
|
||||
}
|
||||
else if(options.type == 'svg') {
|
||||
base64Str = svg2base64(ttf2svg(ttf));
|
||||
}
|
||||
else {
|
||||
buffer = new TTFWriter().write(ttf);
|
||||
base64Str = ttf2base64(buffer);
|
||||
options.type == 'ttf';
|
||||
}
|
||||
|
||||
var target = $(options.target);
|
||||
target.attr('download', (options.fileName || ttf.name.fontFamily || 'export') + '.' + options.type);
|
||||
target.attr('href', base64Str);
|
||||
options.success && options.success(base64Str);
|
||||
}
|
||||
|
||||
return options.target;
|
||||
}
|
||||
|
||||
|
||||
var exporter = {
|
||||
|
||||
/**
|
||||
* 导出SFNT结构字体
|
||||
*
|
||||
* @param {Object} ttf ttf字体结构
|
||||
* @param {Object} options 参数
|
||||
* @param {Object} options.type 文件类型
|
||||
* @param {Object} options.fileName 文件名
|
||||
* @param {Function} options.success 成功回调
|
||||
* @param {Function} options.error 失败回调
|
||||
*
|
||||
* @return {HTMLElement} 导出按钮
|
||||
*/
|
||||
export: exportFile
|
||||
};
|
||||
return exporter;
|
||||
}
|
||||
);
|
69
src/fonteditor/widget/glyfviewer.js
Normal file
69
src/fonteditor/widget/glyfviewer.js
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @file glyflist.js
|
||||
* @author mengke01
|
||||
* @date
|
||||
* @description
|
||||
* glyf 查看器
|
||||
*/
|
||||
|
||||
define(
|
||||
function(require) {
|
||||
var glyf2svg = require('ttf/util/glyf2svg');
|
||||
var string = require('common/string');
|
||||
|
||||
var GLYF_ITEM_TPL = ''
|
||||
+ '<div data-index="${index}" class="glyf-item ${compound} ${modify}">'
|
||||
+ '<svg class="glyf" viewbox="0 0 ${unitsPerEm} ${unitsPerEm}"><g transform="scale(1, -1) translate(0, -${descent}) scale(0.95, 0.95) "><path class="path" ${d}/></g></svg>'
|
||||
+ '<div class="unicode" title="${unicode}">${unicode}</div><div class="name" title="${name}">${name}</div>'
|
||||
+ '</div>';
|
||||
|
||||
|
||||
// 显示glyf
|
||||
function showGLYF(ttf) {
|
||||
var unitsPerEm = ttf.head.unitsPerEm;
|
||||
var descent = unitsPerEm + ttf.hhea.descent;
|
||||
var glyfStr = '', d = '';
|
||||
ttf.glyf.forEach(function(glyf, index) {
|
||||
var g = {
|
||||
index: index,
|
||||
compound: glyf.compound ? 'compound' : '',
|
||||
modify: glyf.modify,
|
||||
unitsPerEm: unitsPerEm,
|
||||
descent: descent,
|
||||
unicode: (glyf.unicode || []).map(function(u) {
|
||||
return '$' + u.toString(16).toUpperCase();
|
||||
}).join(','),
|
||||
name: glyf.name
|
||||
};
|
||||
|
||||
if (d = glyf2svg(glyf, ttf)) {
|
||||
g.d = 'd="'+ d +'"';
|
||||
}
|
||||
|
||||
glyfStr += string.format(GLYF_ITEM_TPL, g);
|
||||
});
|
||||
|
||||
this.main.html(glyfStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* glyf查看器
|
||||
*
|
||||
* @constructor
|
||||
* @param {HTMLElement} main 主元素
|
||||
* @param {Object} options 参数
|
||||
*/
|
||||
function GlyfViewer(main, options) {
|
||||
this.options = options || {};
|
||||
this.main = $(main);
|
||||
}
|
||||
|
||||
GlyfViewer.prototype.show = function(ttf) {
|
||||
showGLYF.call(this, ttf);
|
||||
};
|
||||
|
||||
require('common/observable').mixin(GlyfViewer.prototype);
|
||||
|
||||
return GlyfViewer;
|
||||
}
|
||||
);
|
119
src/fonteditor/widget/loader.js
Normal file
119
src/fonteditor/widget/loader.js
Normal file
@ -0,0 +1,119 @@
|
||||
/**
|
||||
* @file loader.js
|
||||
* @author mengke01
|
||||
* @date
|
||||
* @description
|
||||
* 加载器
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function(require) {
|
||||
|
||||
var TTFReader = require('ttf/ttfreader');
|
||||
var woff2ttf = require('ttf/woff2ttf');
|
||||
var svg2ttfobject = require('ttf/svg2ttfobject');
|
||||
|
||||
var loading = require('./loading');
|
||||
|
||||
var woffOptions = {
|
||||
inflate: require('inflate').inflate
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 加载sfnt结构字体
|
||||
*
|
||||
* @param {File} file file对象
|
||||
* @param {Object} options 参数
|
||||
* @param {Object} options.type 文件类型
|
||||
* @param {Function} options.success 成功回调
|
||||
* @param {Function} options.error 失败回调
|
||||
*/
|
||||
function loadSFNT(file, options) {
|
||||
loading.show();
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function(e) {
|
||||
var buffer = e.target.result;
|
||||
|
||||
if (options.type == 'woff') {
|
||||
buffer = woff2ttf(buffer, woffOptions);
|
||||
}
|
||||
|
||||
var ttfReader = new TTFReader();
|
||||
var ttf = ttfReader.read(buffer);
|
||||
ttfReader.dispose();
|
||||
fileReader = null;
|
||||
loading.hide();
|
||||
options.success && options.success(ttf);
|
||||
}
|
||||
|
||||
fileReader.onerror = function(e) {
|
||||
loading.hide();
|
||||
fileReader = null;
|
||||
alert('读取文件出错!');
|
||||
options.error && options.error(e);
|
||||
};
|
||||
fileReader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载svg结构字体
|
||||
*
|
||||
* @param {File} file file对象
|
||||
* @param {Object} options 参数
|
||||
* @param {Function} options.success 成功回调
|
||||
* @param {Function} options.error 失败回调
|
||||
*/
|
||||
function loadSVG(file, options) {
|
||||
|
||||
loading.show();
|
||||
var fileReader = new FileReader();
|
||||
|
||||
fileReader.onload = function(e) {
|
||||
var buffer = e.target.result;
|
||||
var imported = svg2ttfobject(buffer);
|
||||
fileReader = null;
|
||||
loading.hide();
|
||||
options.success && options.success(imported);
|
||||
};
|
||||
|
||||
fileReader.onerror = function(e) {
|
||||
loading.hide();
|
||||
fileReader = null;
|
||||
alert('读取文件出错!');
|
||||
options.error && options.error(e);
|
||||
};
|
||||
fileReader.readAsText(file);
|
||||
}
|
||||
|
||||
|
||||
var loader = {
|
||||
|
||||
/**
|
||||
* 加载字体
|
||||
*
|
||||
* @param {File} file file对象
|
||||
* @param {Object} options 参数
|
||||
* @param {Object} options.type 文件类型
|
||||
* @param {Function} options.success 成功回调
|
||||
* @param {Function} options.error 失败回调
|
||||
*/
|
||||
load: function(file, options) {
|
||||
if (options.type == 'svg') {
|
||||
loadSVG(file, options);
|
||||
}
|
||||
else if (options.type == 'ttf' || options.type == 'woff'){
|
||||
loadSFNT(file, options);
|
||||
}
|
||||
else {
|
||||
options.error && options.error({
|
||||
message: '不支持的文件类型'
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return loader;
|
||||
}
|
||||
);
|
31
src/fonteditor/widget/loading.js
Normal file
31
src/fonteditor/widget/loading.js
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @file loading.js
|
||||
* @author mengke01
|
||||
* @date
|
||||
* @description
|
||||
* loading 对象
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function(require) {
|
||||
|
||||
/**
|
||||
* 提示
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var loading = {
|
||||
|
||||
show: function(text) {
|
||||
$('#loading').html(text || '正在加载...').show();
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
$('#loading').hide();
|
||||
}
|
||||
};
|
||||
|
||||
return loading;
|
||||
}
|
||||
);
|
97
src/fonteditor/widget/project.js
Normal file
97
src/fonteditor/widget/project.js
Normal file
@ -0,0 +1,97 @@
|
||||
/**
|
||||
* @file project.js
|
||||
* @author mengke01
|
||||
* @date
|
||||
* @description
|
||||
* 项目管理方法,使用localStorage存储
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function(require) {
|
||||
|
||||
var storage = window.localStorage || window.sessionStorate;
|
||||
|
||||
var project = {
|
||||
|
||||
/**
|
||||
* 获取现有项目列表
|
||||
*
|
||||
* @return {Array} 现有项目列表
|
||||
*/
|
||||
items: function() {
|
||||
var list = storage.getItem('project-list');
|
||||
return list ? JSON.parse(list) : [];
|
||||
},
|
||||
|
||||
/**
|
||||
* 添加一个项目
|
||||
*
|
||||
* @param {string} projectName 项目名称
|
||||
* @param {Object} ttf ttfObject
|
||||
* @return {Array} 现有项目列表
|
||||
*/
|
||||
add: function(projectName, ttf) {
|
||||
var list = this.items();
|
||||
var id = Date.now();
|
||||
list.push({
|
||||
name: projectName,
|
||||
id: id
|
||||
});
|
||||
storage.setItem('project-list', JSON.stringify(list));
|
||||
storage.setItem(id, JSON.stringify(ttf));
|
||||
return list;
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除一个项目
|
||||
*
|
||||
* @param {string} projectName 项目名称
|
||||
* @return {Array} 现有项目列表
|
||||
*/
|
||||
remove: function(projectName) {
|
||||
var list = this.items();
|
||||
for(var i = list.length - 1; i >= 0; i--) {
|
||||
if (list[i].name == projectName) {
|
||||
storage.removeItem(list[i].id);
|
||||
list.splice(i, 1);
|
||||
}
|
||||
}
|
||||
storage.setItem('project-list', JSON.stringify(list));
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取一个项目
|
||||
*
|
||||
* @param {string} projectName 项目名称
|
||||
* @return {Object=} 项目对象
|
||||
*/
|
||||
get: function(projectName) {
|
||||
var list = this.items();
|
||||
for(var i = 0, l = list.length; i < l ; i++) {
|
||||
if (list[i].name == projectName) {
|
||||
var item = storage.getItem(list[i].id);
|
||||
if (item) {
|
||||
return JSON.parse(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* 清空项目组
|
||||
*/
|
||||
clear: function() {
|
||||
var list = this.items();
|
||||
list.forEach(function(item) {
|
||||
storage.removeItem(item.id);
|
||||
});
|
||||
storage.removeItem('project-list');
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return project;
|
||||
}
|
||||
);
|
45
src/fonteditor/widget/projectviewer.js
Normal file
45
src/fonteditor/widget/projectviewer.js
Normal file
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @file projectViewer.js
|
||||
* @author mengke01
|
||||
* @date
|
||||
* @description
|
||||
* 项目浏览器
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function(require) {
|
||||
|
||||
/**
|
||||
* 项目查看器
|
||||
*
|
||||
* @constructor
|
||||
* @param {HTMLElement} main 主元素
|
||||
* @param {Object} options 参数
|
||||
*/
|
||||
function ProjectViewer(main, options) {
|
||||
this.options = options || {};
|
||||
this.main = $(main);
|
||||
|
||||
var me = this;
|
||||
this.main.delegate('[data-name]', 'click', function(e) {
|
||||
me.fire('open', {
|
||||
projectName: $(this).attr('data-name')
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ProjectViewer.prototype.show = function(projects) {
|
||||
var str = '';
|
||||
(projects || []).forEach(function(proj) {
|
||||
str += '<div data-name="'+ proj.name +'" data-id="'+ proj.id +'"><a href="javascript:;">'+ proj.name +'</a></div>';
|
||||
});
|
||||
|
||||
this.main.html(str);
|
||||
};
|
||||
|
||||
require('common/observable').mixin(ProjectViewer.prototype);
|
||||
|
||||
return ProjectViewer;
|
||||
}
|
||||
);
|
58
src/fonteditor/widget/ttfmanager.js
Normal file
58
src/fonteditor/widget/ttfmanager.js
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @file ttf.js
|
||||
* @author mengke01
|
||||
* @date
|
||||
* @description
|
||||
* ttf相关操作类
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function(require) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
return manager;
|
||||
}
|
||||
);
|
27
src/main.js
27
src/main.js
@ -1,27 +0,0 @@
|
||||
/**
|
||||
* @file main.js
|
||||
* @author mengke01
|
||||
* @date
|
||||
* @description
|
||||
* 主函数入口
|
||||
*/
|
||||
|
||||
|
||||
define(
|
||||
function(require) {
|
||||
|
||||
var entry = {
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
init: function () {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
entry.init();
|
||||
|
||||
return entry;
|
||||
}
|
||||
);
|
@ -174,7 +174,7 @@ define(
|
||||
else if (cmd === 'L') {
|
||||
|
||||
// 这里可能会连续绘制,最后一个是终点
|
||||
var q = 0, ql = segment.args.length - 2, px = 0, py = 0;
|
||||
var q = 0, ql = segment.args.length, px = 0, py = 0;
|
||||
|
||||
if (relative) {
|
||||
px = prevX;
|
||||
@ -189,6 +189,8 @@ define(
|
||||
});
|
||||
}
|
||||
|
||||
ql = segment.args.length - 2;
|
||||
|
||||
if (relative) {
|
||||
prevX += segment.args[ql];
|
||||
prevY += segment.args[ql + 1];
|
||||
@ -197,12 +199,6 @@ define(
|
||||
prevX = segment.args[ql];
|
||||
prevY = segment.args[ql + 1];
|
||||
}
|
||||
|
||||
contour.push({
|
||||
x: prevX,
|
||||
y: prevY,
|
||||
onCurve: true
|
||||
});
|
||||
}
|
||||
// 二次贝塞尔
|
||||
else if (cmd === 'Q') {
|
||||
|
30
ttf.html
30
ttf.html
@ -8,26 +8,28 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="navbar navbar-inverse" role="navigation">
|
||||
<section class="navbar navbar-inverse" role="navigation">
|
||||
<button data-action="new" type="button" class="btn btn-primary btn-sm">新建</button>
|
||||
<button data-action="open" type="button" class="btn btn-primary btn-sm">打开</button>
|
||||
<button data-action="svg" type="button" class="btn btn-primary btn-sm">导入svg</button>
|
||||
<a id="export-btn" href="#" data-action="export" class="btn btn-primary btn-sm">导出ttf</a>
|
||||
<a id="export-btn-woff" href="#" data-action="export" class="btn btn-primary btn-sm">导出woff</a>
|
||||
<button data-action="import" type="button" class="btn btn-primary btn-sm">导入</button>
|
||||
<a id="export-btn" href="javascript:void(0)" data-action="export" data-type="ttf" class="btn btn-primary btn-sm">导出ttf</a>
|
||||
<a id="export-btn-woff" href="javascript:void(0)" data-action="export" data-type="woff" class="btn btn-primary btn-sm">导出woff</a>
|
||||
<a id="export-btn-svg" href="javascript:void(0)" data-action="export" data-type="svg" class="btn btn-primary btn-sm">导出svg</a>
|
||||
<button data-action="save" type="button" class="btn btn-primary btn-sm">保存</button>
|
||||
<button data-action="setting" type="button" class="btn btn-primary btn-sm">设置</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="sidebar">
|
||||
<dl class="project-list">
|
||||
<dt>项目列表</dt>
|
||||
<dd>baiduhealth.ttf</dd>
|
||||
<dd>baiduhealth1.ttf</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="main">
|
||||
<section class="sidebar">
|
||||
<div class="project">
|
||||
<div class="project-title">项目列表</div>
|
||||
<div id="project-list" class="project-list"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="main">
|
||||
<div id="glyf-list" class="glyf-list">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div id="loading" class="loading">正在加载...</div>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user