I have set up a small plunkr demonstrating what problem I am working on. After a line is created in drawing mode, it is not able to be selected with 'point-click' after exiting drawing mode, only 'group-selection'. I want objects (not just lines) to be unselectable during drawing, then selectable afterwards. I have tried to create all lines with selectable: false then after exiting drawing mode,
canvas.forEachObject(function(o){
o.selectable=true;
canvas.renderAll()
})
but that does not work either. Thanks in advance.
You need to use setCoords() function in order to select line.
Update you mouse:up event like this:
canvas.on('mouse:up', function(o){
isDown = false;
line.setCoords();
});
Please see when to use setCoords().
Related
I have been playing with custom filters in Fabric JS. But I just don't know how to undo anything done. Seems the pixels get overwritten by the process, which is fine, but how do I go back to the orginal? The code project starter is here:
https://github.com/pixolith/fabricjs-async-web-worker-filters
So, in the custom filter, the results are placed into the canvas as follows:
imageDataArray.forEach( function( data ) {
cacheCtx.putImageData( data.data, 0, data.blocks );
} );
That shows the processed image in the render. But I don't understand how to "get back" the original. I have tried this before the processing:
var obj = canvas.getActiveObject();
var originalSource = obj._originalElement.currentSrc; // restore the original since filters trash the canvas
obj.filters[index] = filter;
obj.applyFilters(canvas.renderAll.bind(canvas));
But it does not "get it back". I really don't wish to reload the image each time as they can be large at times. Any help appreciated.
As you noted obj._originalElement is the ORIGINAL element of the image you first loaded. No reason to reload it at all, you have it there. Ready to be smashed on canvas.
So just do obj.element = obj._originalElement and you are back to original after a canvas.renderAll();
I'm using Fabric.js and need to call a function after renderAll has fully completed. This seems like simple functionality that would exist, but my searches, documentation reading, etc. has come up empty. If anyone has a solution, I'd greatly appreciate it.
canvas.deactivateAll().renderAll();
// I need a save function called here, after the above has completed
I've tried binding to the after:render method of the canvas, but that gets called with each object, rather than all objects.
canvas.on('after:render', function() {
// call the save function here
});
I suppose what I could do is count the number of canvas objects, then increment a counter on the after:render method, then check to see if the counter === the number of objects, and if it does, then call the save function. That seems rather convoluted to me though.
(As more background, in case there is another way to achieve what I need, I need to save a canvas image, but first need to deselect all objects so the image isn't saved with the handles showing.)
I found a solution using the deactivateAllWithDispatch method, which fires the selection:cleared listener event. In that event function, I'm executing the deactivateCallback method if it's set.
canvas.on('selection:cleared', function() {
if (deactivateCallback) {
executeCallbackFunction(renderCallback, window);
deactivateCallback = null;
}
});
deactivateCallback = callback;
canvas.deactivateAllWithDispatch();
(note: the executeCallbackFunction in the above code isn't directly related to the answer, and just executes a function that has been passed in as a string)
So what you need is to deactivate all elements. I don't know why canvas.deactivateAll() isn't ok. Does this jsFiddle help you.
I'm attempting to update the stop elements in an SVG linearGradient using D3.js. You can see my working fiddle here: http://jsfiddle.net/nrabinowitz/C85R8/
I'm using the standard D3 pattern of data-join, enter, update, exit, like so:
var stops = d3.select('#myGradient').selectAll('stops')
.data(data);
stops.enter().append('stop');
stops
.attr('offset', function(d) { return d[0]; })
.attr('stop-color', function(d) { return d[1]; });
stops.exit().remove();
This works fine for the initial creation of the stops. However, when I try to update, the .selectAll('stops') function doesn't seem to find the created elements. In the fiddle, when I inspect the SVG, I see two sets of stop elements after the update (which fails to update the gradient).
For comparison, running almost exactly the same code with text elements works perfectly.
Why won't the code properly select existing stop elements on update? Is this a bug in d3.select or Sizzle.js?
You've typed 'stops' instead of 'stop'. If you fix the line as shown it will work as intended.
var stops = d3.select('#myGradient').selectAll('stop')
.data(data);
Your code selects nothing and then appends two extra (ignored) gradient stops. The exit then removes nothing as nothing was selected leaving the two original valid stops and two stops which do nothing.
I'm trying to modify the scrollbar colors for jscrollpane.
This didn't work for me:
$('a.athlete_popup_content').click(function(){
$('#box_on_top').append($content); //.athlete class is within $content
$('.athlete').jScrollPane({autoReinitialise: true});
$('.jspVerticalBar').css('width', '10px');
$('.jspTrack').css('background','lightgrey');
$('.jspDrag').css('background','black');
$('.athlete').jScrollPane({autoReinitialise: true});
});
i tried placing athlete class both before and after... it doesn't do anything... also, the second time this runs, the scrollbar doesn't appear at all.
any help?
-=update=-
For the issue where it does not appear correctly the second time, I had to destroy the jsp on close and it started working.
var element = $('.athlete').jScrollPane();
var api = element.data('jsp');
api.destroy();
I was unable to get the colors to work.
I am including the .css initially, but want to change the colors on load. I wasn't able to figure out this issue so I just modified the .css
Thanks!
Your code es working perfectly, as you can see here. If you are calling jScrollPane() on a click event then the tags you are trying to reach (.jspVerticalBar, .jspTrack, .jspDrag) are created after css() calls, then you should use .on() to attach those calls to the event.
Hi I am totally confused with CGAffineTransform animations. All I want to do is move a sprite from a position on the right to a position on the left. When it has stopped I want to "reset" it i.e. move it back to where it started. If the app exits (with multitasking) I want to reset the position again on start and repeat the animation.
This is what I am using to make the animation..
[UIImageView animateWithDuration:1.5
delay:0.0
options:(UIViewAnimationOptionAllowUserInteraction |
UIViewAnimationOptionCurveLinear
)
animations:^(void){
ufo.transform = CGAffineTransformTranslate(ufo.transform, -270, 100);
}
completion:^(BOOL finished){
if(finished){
NSLog(#"ufo finished");
[self ufoAnimationDidStop];
}
}];
As I understand it the CGAffineTransforms just visually makes the sprite look like it's moved but doesn't actually move it. Therefore when I try and "reset" the position using
ufo.center = CGPointMake(355, 70);
it doesn't do anything.
I do have something working, if I call
ufo.transform = CGAffineTransformTranslate(ufo.transform, 270, -100);
it resets. The problem is if I exit the app half way through the animation then when it restarts it doesn't necessarily start from the beginning and it doesn't go the the right place, it basically goes crazy!
Is there a way to just remove any transforms applied to it? I'm considering just using a timer but this seems silly when this method should work. I;ve been struggling with this for some time so any help would be much appreciated.
Thanks
Applying a transform to a view doesn't actually change the center or the bounds of the view; it just changes the way the view is shown on the screen. You want to set your transform back to CGAffineTransformIdentity to ensure that it looks like "normal." You can set it to that before you start your animation and set it to what you want it to animate to.