Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change custom actions for each different type of object (Image/Circle/Text/etc...) #28

Closed
craziduezi opened this issue Jan 2, 2017 · 7 comments

Comments

@craziduezi
Copy link

craziduezi commented Jan 2, 2017

Hi there, great customisation extension for fabricjs! I had a quick question though. I'm originally setting the customised options when I initiate the canvas. Giving the objects all the same customised controls. The issue is that when I add an image (new fabric.Image) and try to change the controls; I'm able to set the custom icons for the Image but the actions still is inherited from the general settings.

img.customiseCornerIcons({
    settings: {
        borderColor: 'black',
        cornerSize: 25,
        cornerShape: 'rect',
        cornerBackgroundColor: 'black',
        cornerPadding: 10
    },
    br: {
        icon: '/upload/fabric-svgs/up.svg'
    }
});

img.customiseControls({
    br: {
        action: function( e, target ) {
            console.log(e, target);
        }
     }
});`

The actual error I'm receiving from console is "Uncaught TypeError: img.customizeControls is not a function".

*note - This note from your README.md

fabric.Object.prototype.customiseCornerIcons
fabric.Canvas.prototype.customiseControls

It makes me think it's just a general setting and would need to extended to each individual object. Anyways I appreciate the help in advance and again love the extension!

@MDSLKTR
Copy link
Contributor

MDSLKTR commented Jan 2, 2017

Hey there, thank you for taking the time to write this up. The general problem here is that in the fabric.js core the corner actions, as you correctly stated, inherit from the fabric.Canvas prototype which basicly means there is no way to define these for each individual object without some serious shifting of functions which in my opinion would be very hard task to do and to maintain in the future. I am generally up to any PRs and suggestions concerning this but i do not have the time currently to make this happen on my own.

Simon

@craziduezi
Copy link
Author

craziduezi commented Jan 2, 2017

No worries I understand the time issue; I'm sure it's possible to just dynamically change it each time an object is selected and/or added. Could possibly set the function '.customiseControls()' on the 'object:added object:selected' events and just declare the type when adding the object originally. I'll try to see if I can get a jsfiddle up later when I'm free'd up. Logically makes sense but guess we'll see in a bit. Thanks for the prompt response @MDSLKTR.

@craziduezi
Copy link
Author

craziduezi commented Jan 2, 2017

@MDSLKTR It seems to be working if you get time check out the jsFiddle.
jsFiddle - Dynamically changing customised control actions
It doesn't seem to cause performance/UEX issues but I will implement that into my project and see how it handles with multiple objects and types. However, I see your extension being applicable in many other ways through controlling each type of object uniquely and I'll try to expand on that. Cheers!

@MDSLKTR
Copy link
Contributor

MDSLKTR commented Jan 2, 2017

@craziduezi Hey again, this is actually a very clever workaround binding this to an event handler. If there are no issues performance-wise i would like to add this tipp to the docs since a real change of core behaviour is unlikely from my part in the near future. This should be good enough to satisfy most use cases. Great stuff.

@craziduezi
Copy link
Author

craziduezi commented Jan 3, 2017

Thank you! So, this is the initial setup I had to use but I found a small issue when overwriting.
I had to overwrite the 'scaleX / scaleY' icons with blank.svg to overwrite the icon that I had set for the previous selected object type; otherwise they would maintain the previous object type's icon.
As well as for actions can not be left blank for overwriting, they must be declared as the original scaleX/scaleY/scale actions.
So it seems required to re-declare all the corners on each overwriting through the 'object:selected' event.

function iniCanvas(){

	// basic settings
	fabric.Canvas.prototype.customiseControls( {
		tr: {
			action: 'scale',
			cursor: 'ne-resize'
		},
		mt: {
			action: 'scaleY',
			cursor: 'n-resize'
		},
		ml: {
			action: 'scaleX',
			cursor: 'w-resize'
		},
		bm: {
			action: 'scaleY',
			cursor: 'n-resize'
		},
		br: {
			action: 'remove',
			cursor: 'no-drop'
		},
		bl: {
			action: 'moveDown',
			cursor: 'pointer'
		},
		tl: {
			action: 'moveUp',
			cursor: 'pointer'
		},
		mr: {
			action: 'changeColor',
			cursor: 'pointer'
		},
		mtr: {
			action: 'rotate',
			cursor: 'pointer'
		}
	} );

	// basic settings
	fabric.Object.prototype.customiseCornerIcons( {
		settings: {
			borderColor: '#0094dd',
			cornerSize: 28,
			cornerShape: 'rect',
			cornerBackgroundColor: 'rgba(91, 192, 222, 0.75)'
		},
		tr: {
			icon: '/upload/fabric-svgs/resize.svg'
		},
		mt: {
			icon: '/upload/fabric-svgs/blank.svg'
		},
		ml: {
			icon: '/upload/fabric-svgs/blank.svg'
		},
		mb: {
			icon: '/upload/fabric-svgs/blank.svg'
		},
		br: {
			icon: '/upload/fabric-svgs/remove.svg'
		},
		bl: {
			icon: '/upload/fabric-svgs/layer_down.svg'
		},
		tl: {
			icon: '/upload/fabric-svgs/layer_up.svg'
		},
		mr: {
			icon: '/upload/fabric-svgs/pallete.svg'
		},
		mtr: {
			icon: '/upload/fabric-svgs/rotate.svg'
		}
	} );

}

...

Lastly, the 'object:selected' listener. This will handle the change and default icon/actions of activeObject or activeGroup independently.

canvas.on('object:selected', function(e) {
  var activeObject = canvas.getActiveObject(),
    activeGroup = canvas.getActiveGroup();
  //Check if single object or group
  	if(activeObject){
    var type = activeObject.get('type');
    }else{
    var type = "no_string";
    }
    if (type == "polygon" || type == "i-text" || type == "triangle" || type == "rect" || type == "circle" || type == "path" || activeGroup != undefined){

//set Default Icon/Actions (also this will be settings for activeGroup)
//fabric.Canvas.prototype.customiseControls( { } );
//fabric.Object.prototype.customiseCornerIcons( { } );

  }else{

//set Icon/Actions for object.type = 'image' 
//fabric.Canvas.prototype.customiseControls( { } );
//fabric.Object.prototype.customiseCornerIcons( { } );
    }

//Not sure if this is necessary, calling for performance. 
canvas.renderAll();

});  //END OF ON OBJECT SELECT EVENT

BTW, not sure where to put this but I created an extra useful action for the extension. Thought somebody could get some use out of it.

       /**
        * Custom change color object action
        * @private
        * @param {Event} e Event object
        * @param {fabric.Object} target
        */
      _changeColor: function(e, target) {
          var _this = this;
         
         //Dynamically create / append / click (optional)
          var input = '<input id="changeColor" type="color" style="display:none"/>';
          $("body").append(input);

         //OR directly call a static input from the page

          $("#changeColor").click();
          $("#changeColor").on("input", function() {

              var activeObject = _this.getActiveObject(),
                  activeGroup = _this.getActiveGroup();
              if (activeObject) {

              	   if(activeObject.type != "path"){
                       activeObject.fill = color;
              	   }else{
              	       activeObject.stroke = color;
              	   }

                  _this.discardActiveObject(activeObject);
              } else if (activeGroup) {
                  var objectsInGroup = activeGroup.getObjects();
                  _this.discardActiveGroup();
                  objectsInGroup.forEach(function(object) {
                      object.fill = color;
                      _this.discardActiveObject(object);

                  });
              }

              _this.renderAll();

          });



      },

Then referenced the action 'changeColor' to the '_changeColor' function

            if ( action === 'changeColor' ) {
                this._changeColor( e, target );

            }

use as:

    		fabric.Canvas.prototype.customiseControls( {
		tr: {
			action: 'changeColor',
			cursor: 'pointer'
		},
                ...

@craziduezi craziduezi reopened this Jan 3, 2017
@craziduezi
Copy link
Author

Accidentally closed / I think that's about all we can do with it for now anyways. Thanks again @MDSLKTR

@MDSLKTR
Copy link
Contributor

MDSLKTR commented Jan 6, 2017

@craziduezi Yeah i think so too, this is a great reference, i will update the docs with this link and close for now, great work!

https://github.com/pixolith/fabricjs-customise-controls-extension/blob/gh-pages/README.md#note-on-having-custom-control-actions-for-each-object

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants