Trying to create speech bubble with handle in FabricJS

匆匆过客 提交于 2021-01-27 22:13:03

问题


I'm trying to create a speech bubble with FabricJS to integrate into a WordPress plugin to (hopefully) release for free that helps people annotate images, I found the original bubble here on SO here: speech buble html5 canvas js but I'm having a few issues and am a little unsure as to how to go about solving them (I'll keep trying and post a solution here just in case).

fabric.speechBubble = fabric.util.createClass(fabric.Object, fabric.Observable, {

    type: 'speechBubble',

    initialize: function(options) {
        options || (options = {});
        this.callSuper('initialize', options);
        this.set('width', options.width || 200);
        this.set('height', options.height || 100);
        this.set('left', options.left || 100);
        this.set('top', options.top || 100);
        this.set('radius', options.radius || 20);
        this.set('pointerX', options.pointerX || this.left + 300);
        this.set('pointerY', options.pointerY || this.top + 300);
    },

    toObject: function() {
        return fabric.util.object.extend(this.callSuper('toObject'), {
            pointerX : this.get('pointerX'),
            pointerY : this.get('pointerY'),
        });
    },

    _render: function (ctx) {

        //this.callSuper('_render', ctx);

        var r = this.left + this.width;
        var b = this.top + this.height;

        if ( this.pointerY < this.top || this.pointerY > this.top + this.height ) {
            var con1 = Math.min(Math.max(this.left + this.radius, this.pointerX - 10),r-this.radius-20);
            var con2 = Math.min(Math.max(this.left + this.radius + 20,this.pointerX + 10),r-this.radius);
        }
        else {
            var con1 = Math.min(Math.max(this.top + this.radius, this.pointerY - 10),b-this.radius-20);
            var con2 = Math.min(Math.max(this.top + this.radius + 20, this.pointerY + 10),b-this.radius);
        }

        var dir;

        if ( this.pointerY < this.top ) dir = 2;
        if ( this.pointerY > this.top) dir = 3;
        if ( this.pointerX < this.left && this.pointerY >= this.top && this.pointerY <=b ) dir = 0;
        if ( this.pointerX > this.left && this.pointerY >= this.top && this.pointerY <=b ) dir = 1;
        if ( this.pointerX >= this.left && this.pointerX <= r && this.pointerY >= this.top && this.pointerY <= b) dir = -1;

        ctx.beginPath();
        ctx.save();

        console.log(dir);

        ctx.strokeStyle = "red";
        ctx.lineWidth = "3";
        ctx.fillStyle = "white";

        ctx.moveTo(this.left + this.radius, this.top);

        if(dir == 2){
            ctx.lineTo(con1,this.top);
            ctx.lineTo(this.pointerX,this.pointerY);
            ctx.lineTo(con2,this.top);
            ctx.lineTo(r-this.radius,this.top);
        }
        else ctx.lineTo(r-this.radius,this.top);
        ctx.quadraticCurveTo(r,this.top,r,this.top+this.radius);

        if(dir == 1){
            ctx.lineTo(r,con1);
            ctx.lineTo(this.pointerX,this.pointerY);
            ctx.lineTo(r,con2);
            ctx.lineTo(r,b-this.radius);
        }
        else ctx.lineTo(r,b-this.radius);
        ctx.quadraticCurveTo(r, b, r - this.radius, b);

        if(dir==3){
            ctx.lineTo(con2,b);
            ctx.lineTo(this.pointerX,this.pointerY);
            ctx.lineTo(con1,b);
            ctx.lineTo(this.left+this.radius,b);
        }
        else ctx.lineTo(this.left+this.radius,b);
        ctx.quadraticCurveTo(this.left, b, this.left, b-this.radius);

        if(dir==0){
            ctx.lineTo(this.left,con2);
            ctx.lineTo(this.pointerX,this.pointerY);
            ctx.lineTo(this.left,con1);
            ctx.lineTo(this.left,this.top+this.radius);
        }
        else ctx.lineTo(this.left,this.top+this.radius);
        ctx.quadraticCurveTo(this.left, this.top, this.left+this.radius, this.top);

        ctx.stroke();
        ctx.restore();
        this._renderFill(ctx);
        this._renderStroke(ctx);
    }
});

Here is a JSFiddle of what I have now: http://jsfiddle.net/xu2nzjv2/7/

My first thing is when I add the bubble to the canvas the selection area is way off in the top left - that happens even when the pointer is pointing down left or right. I would also like to know if there is a way to lock the position of the pointer somehow unless it specifically is dragged like in the Stackoverflow canvas shape above.

The second thing is I was wondering if there was a way to make the point draggable like it is now but also be able to move the entire bubble. This part might not be too hard once I have the bounding/selection box thing working since I figure I can just make a tool so that if it is clicked then the canvas is only listening for the repositioning of the pointer.

Any help is super super appreciated!


回答1:


There's a pretty cool library called ComicBubbles that I just found. I've linked you to their third demo which showcases the movable handle. Hopefully this helps.



来源:https://stackoverflow.com/questions/38838510/trying-to-create-speech-bubble-with-handle-in-fabricjs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!