|
|
@@ -3,6 +3,7 @@
|
|
|
<script>
|
|
|
import fabric from '../PictureEditor/js/fabric-adapter'
|
|
|
import tpl from './tpl/index'
|
|
|
+import fontConfig from '../PictureEditor/mixin/edit/module/font.json'
|
|
|
import viewMixins from '@/views/components/PictureEditor/mixin/view/index'
|
|
|
import actionsMixins from '@/views/components/PictureEditor/mixin/actions/index'
|
|
|
import layerMixins from '@/views/components/PictureEditor/mixin/layer/index'
|
|
|
@@ -261,19 +262,161 @@ export default {
|
|
|
const jsonData = typeof this.this_canvas.canvas_json === 'string'
|
|
|
? this.this_canvas.canvas_json
|
|
|
: JSON.stringify(this.this_canvas.canvas_json)
|
|
|
- this.fcanvas.loadFromJSON(jsonData, () => {
|
|
|
- // 如果是加载模板,调用专门的初始化函数
|
|
|
- if(this.hasLoadedTpl){
|
|
|
- this.setTpl()
|
|
|
- }
|
|
|
- this.fcanvas.renderAll()
|
|
|
- hydrateCanvas()
|
|
|
+
|
|
|
+ // 先预加载字体,再加载模板
|
|
|
+ this.preloadFontsForCanvasJson(jsonData).then(() => {
|
|
|
+ this.fcanvas.loadFromJSON(jsonData, () => {
|
|
|
+ // 字体加载完成后,确保文字对象的字体属性正确设置
|
|
|
+ this.ensureTextObjectsFonts()
|
|
|
+
|
|
|
+ // 如果是加载模板,调用专门的初始化函数
|
|
|
+ if(this.hasLoadedTpl){
|
|
|
+ this.setTpl()
|
|
|
+ }
|
|
|
+
|
|
|
+ this.fcanvas.renderAll()
|
|
|
+ hydrateCanvas()
|
|
|
+ })
|
|
|
+ }).catch((error) => {
|
|
|
+ console.warn('字体预加载失败,继续加载模板:', error)
|
|
|
+ // 即使字体加载失败,也要继续加载模板
|
|
|
+ this.fcanvas.loadFromJSON(jsonData, () => {
|
|
|
+ if(this.hasLoadedTpl){
|
|
|
+ this.setTpl()
|
|
|
+ }
|
|
|
+ this.fcanvas.renderAll()
|
|
|
+ hydrateCanvas()
|
|
|
+ })
|
|
|
})
|
|
|
}else{
|
|
|
hydrateCanvas()
|
|
|
}
|
|
|
|
|
|
},
|
|
|
+ // 预加载 canvas JSON 中的字体(在loadFromJSON之前调用)
|
|
|
+ async preloadFontsForCanvasJson(jsonData) {
|
|
|
+ try {
|
|
|
+ const json = typeof jsonData === 'string' ? JSON.parse(jsonData) : jsonData
|
|
|
+ const textObjects = (json.objects || []).filter(obj =>
|
|
|
+ (obj.type === 'textbox' || obj.type === 'text') && obj.fontFamily
|
|
|
+ )
|
|
|
+
|
|
|
+ const fontPromises = []
|
|
|
+ const fontSet = new Set()
|
|
|
+
|
|
|
+ for (const obj of textObjects) {
|
|
|
+ const fontFamily = obj.fontFamily
|
|
|
+ if (fontFamily && fontFamily !== 'Arial' && !fontSet.has(fontFamily)) {
|
|
|
+ fontSet.add(fontFamily)
|
|
|
+ // 检查字体是否在fontConfig中
|
|
|
+ const fontInfo = fontConfig.find(f => f.fontFamily === fontFamily || f.name === fontFamily)
|
|
|
+ if (fontInfo && fontInfo.src) {
|
|
|
+ console.log('预加载字体:', fontFamily, fontInfo.src)
|
|
|
+ fontPromises.push(this.loadFontForObject(fontFamily, fontInfo.src))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 并发加载所有字体
|
|
|
+ if (fontPromises.length > 0) {
|
|
|
+ console.log(`开始预加载 ${fontPromises.length} 个字体...`)
|
|
|
+ await Promise.all(fontPromises)
|
|
|
+ console.log('Canvas JSON 字体预加载完成')
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.warn('预加载Canvas JSON字体失败:', error)
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 预加载模板中所有文字对象的字体(在loadFromJSON之后调用,用于处理动态添加的对象)
|
|
|
+ async preloadFontsForTemplate() {
|
|
|
+ if (!this.fcanvas) return
|
|
|
+
|
|
|
+ const textObjects = this.fcanvas.getObjects().filter(obj =>
|
|
|
+ (obj.type === 'textbox' || obj.type === 'text') && obj.fontFamily
|
|
|
+ )
|
|
|
+
|
|
|
+ const fontPromises = []
|
|
|
+ const fontSet = new Set()
|
|
|
+
|
|
|
+ for (const obj of textObjects) {
|
|
|
+ const fontFamily = obj.fontFamily
|
|
|
+ if (fontFamily && fontFamily !== 'Arial' && !fontSet.has(fontFamily)) {
|
|
|
+ fontSet.add(fontFamily)
|
|
|
+ // 检查字体是否在fontConfig中
|
|
|
+ const fontInfo = fontConfig.find(f => f.fontFamily === fontFamily || f.name === fontFamily)
|
|
|
+ if (fontInfo && fontInfo.src) {
|
|
|
+ fontPromises.push(this.loadFontForObject(fontFamily, fontInfo.src))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 并发加载所有字体
|
|
|
+ try {
|
|
|
+ await Promise.all(fontPromises)
|
|
|
+ console.log('模板字体预加载完成')
|
|
|
+ } catch (error) {
|
|
|
+ console.warn('模板字体预加载失败:', error)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 为单个对象加载字体
|
|
|
+ async loadFontForObject(fontFamily, fontUrl) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ if (this.checkFont(fontFamily)) {
|
|
|
+ return resolve(true)
|
|
|
+ }
|
|
|
+
|
|
|
+ const fontFace = new FontFace(fontFamily, `url(${fontUrl})`)
|
|
|
+ fontFace.load().then(loadedFace => {
|
|
|
+ document.fonts.add(loadedFace)
|
|
|
+ console.log('字体加载成功:', fontFamily)
|
|
|
+ resolve(true)
|
|
|
+ }).catch(error => {
|
|
|
+ console.warn('字体加载失败:', fontFamily, error)
|
|
|
+ reject(error)
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // 检查字体是否已加载
|
|
|
+ checkFont(fontName) {
|
|
|
+ const values = document.fonts.values()
|
|
|
+ let item = values.next()
|
|
|
+ while (!item.done) {
|
|
|
+ const fontFace = item.value
|
|
|
+ if (fontFace.family === fontName) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ item = values.next()
|
|
|
+ }
|
|
|
+ return false
|
|
|
+ },
|
|
|
+ // 确保文字对象的字体属性正确设置
|
|
|
+ ensureTextObjectsFonts() {
|
|
|
+ if (!this.fcanvas) return
|
|
|
+
|
|
|
+ const textObjects = this.fcanvas.getObjects().filter(obj =>
|
|
|
+ (obj.type === 'textbox' || obj.type === 'text') && obj.fontFamily
|
|
|
+ )
|
|
|
+
|
|
|
+ textObjects.forEach(obj => {
|
|
|
+ const fontFamily = obj.fontFamily
|
|
|
+ if (fontFamily && fontFamily !== 'Arial') {
|
|
|
+ // 重新设置字体,确保字体生效
|
|
|
+ obj.set({
|
|
|
+ fontFamily: fontFamily,
|
|
|
+ dirty: true // 标记为需要重新渲染
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 确保其他字体属性也正确设置
|
|
|
+ if (!obj.fontSize || obj.fontSize <= 0) obj.fontSize = 16
|
|
|
+ if (!obj.fill) obj.fill = '#000000'
|
|
|
+ if (obj.fontWeight === undefined) obj.fontWeight = 'normal'
|
|
|
+ if (obj.fontStyle === undefined) obj.fontStyle = 'normal'
|
|
|
+ if (obj.textAlign === undefined) obj.textAlign = 'left'
|
|
|
+ })
|
|
|
+ },
|
|
|
addCanvas(){
|
|
|
|
|
|
this.canvasForm.type = 'add'
|