diff --git a/src/app/components/fabric-post/fabric-post.component.ts b/src/app/components/fabric-post/fabric-post.component.ts index df0f295c..74b8b326 100644 --- a/src/app/components/fabric-post/fabric-post.component.ts +++ b/src/app/components/fabric-post/fabric-post.component.ts @@ -1,108 +1,148 @@ import { Component, Inject } from '@angular/core'; import { fabric } from 'fabric'; -import { POST_DEFAULT_BORDER, POST_DEFAULT_BORDER_THICKNESS } from 'src/app/utils/constants'; +import { + POST_DEFAULT_BORDER, + POST_DEFAULT_BORDER_THICKNESS, +} from 'src/app/utils/constants'; +import { FabricUtils } from 'src/app/utils/FabricUtils'; -const AUTHOR_OFFSET = 65 -const DESC_OFFSET = 80 -const CONTENT_EXTRA_HEIGHT = 55 +const AUTHOR_OFFSET = 65; +const DESC_OFFSET = 80; +const CONTENT_EXTRA_HEIGHT = 55; @Component({ selector: 'app-fabric-post', templateUrl: './fabric-post.component.html', - styleUrls: ['./fabric-post.component.scss'] + styleUrls: ['./fabric-post.component.scss'], }) export class FabricPostComponent extends fabric.Group { + constructor( + @Inject(Object) options: any, + ) { + var fabricUtils: FabricUtils = new FabricUtils(); + var title = new fabric.Textbox( + fabricUtils.wrapCanvasText(options.title, 140, 0), + { + name: 'title', + width: 280, + left: 18, + top: 60, + fontSize: 18, + fontWeight: 'bold', + fontFamily: 'Helvetica', + fill: '#000000', + splitByGrapheme: true, + } + ); - constructor(@Inject(Object) options:any) { - var title = new fabric.Textbox(options.title, { - name: 'title', - width: 280, - left: 18, - top: 60, - fontSize: 18, - fontWeight: 'bold', - fontFamily: 'Helvetica', - fill: '#000000', - splitByGrapheme: true - }); - - var author = new fabric.Textbox(options.author, { - name: 'author', - width: 300, - left: 18, - top: title.getScaledHeight() + AUTHOR_OFFSET, - fontSize: 13, - fontFamily: 'Helvetica', - fill: '#555555', - splitByGrapheme: true, - }); + var author = new fabric.Textbox( + fabricUtils.wrapCanvasText(options.author, 200, 0), + { + name: 'author', + width: 300, + left: 18, + top: title.getScaledHeight() + AUTHOR_OFFSET, + fontSize: 13, + fontFamily: 'Helvetica', + fill: '#555555', + splitByGrapheme: true, + } + ); - var desc = new fabric.Textbox(options.desc.length > 200 ? options.desc.substr(0, 200) + '...' : options.desc, { - name: 'desc', - width: 300, - left: 18, - top: author.getScaledHeight() + title.getScaledHeight() + DESC_OFFSET, - fontSize: 15, - fontFamily: 'Helvetica', - fill: '#000000', - splitByGrapheme: true - }); + var desc = new fabric.Textbox( + fabricUtils.wrapCanvasText( + options.desc.length > 200 + ? options.desc.substr(0, 200) + '...' + : options.desc, + 200, + 0 + ), + { + name: 'desc', + width: 300, + left: 18, + top: author.getScaledHeight() + title.getScaledHeight() + DESC_OFFSET, + fontSize: 15, + fontFamily: 'Helvetica', + fill: '#000000', + splitByGrapheme: true, + } + ); var commentButton = new fabric.Textbox('💬', { name: 'comment', width: 55, - top: title.getScaledHeight() + author.getScaledHeight() + desc.getScaledHeight() + 90, - left: 170 , + top: + title.getScaledHeight() + + author.getScaledHeight() + + desc.getScaledHeight() + + 90, + left: 170, fontSize: 20, fontFamily: 'Helvetica', fill: '#000000', splitByGrapheme: true, - opacity:0 + opacity: 0, }); var commentCount = new fabric.Textbox('0', { name: 'commentCount', width: 55, - top: title.getScaledHeight() + author.getScaledHeight() + desc.getScaledHeight() + 90, + top: + title.getScaledHeight() + + author.getScaledHeight() + + desc.getScaledHeight() + + 90, left: (commentButton.left ?? 0) + 28, fontSize: 20, fontFamily: 'Helvetica', fill: '#555555', splitByGrapheme: true, - opacity:0 + opacity: 0, }); - + var likeButton = new fabric.Textbox('👍🏼', { name: 'like', width: 55, - top: title.getScaledHeight() + author.getScaledHeight() + desc.getScaledHeight() + 90, - left: (commentCount.left??0) +45, + top: + title.getScaledHeight() + + author.getScaledHeight() + + desc.getScaledHeight() + + 90, + left: (commentCount.left ?? 0) + 45, fontSize: 20, fontFamily: 'Helvetica', fill: '#000000', - splitByGrapheme: true + splitByGrapheme: true, }); var likeCount = new fabric.Textbox('0', { name: 'likeCount', width: 55, - top: title.getScaledHeight() + author.getScaledHeight() + desc.getScaledHeight() + 90, + top: + title.getScaledHeight() + + author.getScaledHeight() + + desc.getScaledHeight() + + 90, left: (likeButton.left ?? 0) + 28, fontSize: 20, fontFamily: 'Helvetica', fill: '#555555', - splitByGrapheme: true + splitByGrapheme: true, }); - - var content = new fabric.Rect({ name: 'content', top: 40, width: 330, - height: title.getScaledHeight() + author.getScaledHeight() + desc.getScaledHeight() + commentButton.getScaledHeight() + CONTENT_EXTRA_HEIGHT, + height: + title.getScaledHeight() + + author.getScaledHeight() + + desc.getScaledHeight() + + commentButton.getScaledHeight() + + CONTENT_EXTRA_HEIGHT, fill: options.color, - rx: 20, + rx: 20, ry: 20, strokeWidth: options.strokeWidth ?? POST_DEFAULT_BORDER_THICKNESS, stroke: options.stroke ?? POST_DEFAULT_BORDER, @@ -110,8 +150,8 @@ export class FabricPostComponent extends fabric.Group { const groupOptions = { name: 'post', - left: options.left - (330 / 2), - top: options.top - ((content.height ?? 0) / 2), + left: options.left - 330 / 2, + top: options.top - (content.height ?? 0) / 2, hasControls: false, transparentCorners: false, cornerSize: 7, @@ -123,8 +163,20 @@ export class FabricPostComponent extends fabric.Group { tags: options.tags, subTargetCheck: true, authorID: options.authorID, - } + }; - super([content, title, author, desc, likeButton, likeCount, commentButton, commentCount], groupOptions); - }; -} \ No newline at end of file + super( + [ + content, + title, + author, + desc, + likeButton, + likeCount, + commentButton, + commentCount, + ], + groupOptions + ); + } +} diff --git a/src/app/utils/FabricUtils.ts b/src/app/utils/FabricUtils.ts index 66342223..261ec063 100644 --- a/src/app/utils/FabricUtils.ts +++ b/src/app/utils/FabricUtils.ts @@ -25,6 +25,62 @@ export class FabricUtils { this._canvas = surface; } + wrapCanvasText(t, maxW, maxH) { + this._canvas = new fabric.Canvas('c'); + if (typeof maxH === 'undefined') { + maxH = 0; + } + var words = t.split(' '); + var formatted = ''; + var context = this._canvas?.getContext(); + context.font = t.fontSize + 'px ' + t.fontFamily; + var currentLine = ''; + + for (var n = 0; n < words.length; n++) { + var isNewLine = currentLine == ''; + var testOverlap = currentLine + ' ' + words[n]; + + // are we over width? + var w = context.measureText(testOverlap).width; + + if (w < maxW) { + // if not, keep adding words + currentLine += words[n] + ' '; + formatted += words[n] += ' '; + } else { + // if this hits, we got a word that need to be hypenated + if (isNewLine) { + var wordOverlap = ''; + + // test word length until its over maxW + for (var i = 0; i < words[n].length; ++i) { + wordOverlap += words[n].charAt(i); + var withHypeh = wordOverlap + '-'; + + if (context.measureText(withHypeh).width >= maxW) { + // add hyphen when splitting a word + withHypeh = wordOverlap.substr(0, wordOverlap.length - 2) + '-'; + // update current word with remainder + words[n] = words[n].substr( + wordOverlap.length - 1, + words[n].length + ); + formatted += withHypeh; // add hypenated word + break; + } + } + } + n--; // restart cycle + formatted += '\n'; + currentLine = ''; + } + } + + formatted = formatted.substr(0, formatted.length - 1); + console.log(formatted); + return formatted; + } + setField(obj, key, value) { obj.set(key, value); fabric.util.object.extend(obj, { [key]: value });