corrective scaling using Raphael free transform plugin - svg

I'm using Raphael Free Transform plugin to enable scaling, dragging and rotating.
In this particular scenario I want to devote one handle for resizing and another one for rotating, hence scale option is set only on axis x. I want to compensate scaling on y axis by correcting it on function callback to avoid 'image' distortions.
I would like to enable user to re-size raphael set using one handle and rotate raphael set using another one. Also, I would like to persist all transformation caused by scaling so it is not lost once user attempt o drag the objects.
var ft = paper.freeTransform(tmp, { scale: ['axisX'], rotate: ['axisY'] }, cbFreeTransform);
function cbFreeTransform(s, e) {
if (e.toString() == 'scale end') {
for (var i = 0, l = tmp.length; i < l; i++) {
var itm = tmp[i];
itm.scale(1, s.attrs.scale.x);
}
}
}
Here is fiddle: jsFiddle
Any help appreciated .

Found the solution in doing following:
On 'Scale End' event I've assigned x scale factor to y scale factor and call free transform apply method. That seems to work.
var ft = paper.freeTransform(tmp, { scale: ['axisX'], rotate: ['axisY'] }, cbFreeTransform);
function cbFreeTransform(s, e) {
if (e.toString() == 'scale end') {
ft.attrs.scale.y = s.attrs.scale.x;
ft.apply();
}
}

Related

Positioning the borderless window in neutralino.js

Is there any way we can position the borderless window in the file neutralino.config.json?
like : "borderless": { ...args }
or any other ways?
Now it just starts at somewhere random and cannot be moved
You can call Neutralino.window.move(x,y) in your javascript. (0,0) is the (leftmost,top) of the screen. You can find other window functions at https://neutralino.js.org/docs/api/window.
As an extension of your question, and like Klauss A's instinct suggests, you can call Neutralino.window.setDraggableRegion('id-of-element') where id-of-element is, as the name suggests, an id of an element in your html. Then, when you click and drag that element, Neutralino will automatically call Neutralino.window.move(x,y). setDraggableRegion() is not in the docs, but you can see it in the tutorial they made on YouTube, and it is still in the code.
The thing is, how Neutralino does this is by posting a message to the server, which adds quite a bit of delay, causing the drag to stutter. Here is the relevant code snippet in a prettified version of the neutralino.js file:
...
t.move = function(e, t) {
return r.request({
url: "window.move",
type: r.RequestType.POST,
isNativeMethod: !0,
data: {
x: e,
y: t
}
})
}, t.setDraggableRegion = function(e) {
return new Promise(((t, i) => {
let r = document.getElementById(e),
o = 0,
u = 0;
function s(e) {
return n(this, void 0, void 0, (function*() {
yield Neutralino.window.move(e.screenX - o, e.screenY - u)
}))
}
r || i(`Unable to find dom element: #${e}`), r.addEventListener("mousedown", (e => {
o = e.clientX, u = e.clientY, r.addEventListener("mousemove", s)
})), r.addEventListener("mouseup", (() => {
r.removeEventListener("mousemove", s)
})), t()
}))
}
...
I suspected this formulation of adding to the lag, since function* is a generator, and thus is inherently untrustworthy (citation needed). I re-wrote it in plain javascript, and reduced some of the lag. It still stutters, just not as much.
var dragging = false, posX, posY;
var draggableElement = document.getElementById('id-of-element');
draggableElement.onmousedown = function (e) {
posX = e.pageX, posY = e.pageY;
dragging = true;
}
draggableElement.onmouseup = function (e) {
dragging = false;
}
document.onmousemove = function (e) {
if (dragging) Neutralino.window.move(e.screenX - posX, e.screenY - posY);
}
I hope this helps. I was digging around in all this because the caption bar (aka, title bar) of the window is different from my system's color theme. I thought, "maybe I'll create my own title bar in HTML, with CSS styling to match my app." But due to the stuttering issues, I find it is better to have a natively-draggable title bar that doesn't match anything. I'm still digging around in the Neutralino C++ code to see if I could modify it and add a non-client rendering message handler (on Windows), to color the title bar the same as my app and still have nice smooth dragging. That way it would look "borderless" but still be movable.
I am having the same problem. My naive instinct is telling me that probably could be a way to create a custom element bar and use a function upon click& drag to move the window around.
Moving Windows in Neutralino is Quite Simple.
You can use the Neutralino.window API to move the windows.
Example:
Neutralino.window.move(x, y);
here x and y are the Coordinates on which our window will move to.
Note the this moves the window from the Top Left Corner of the window.
I have made this Neutralino Template - NeutralinoJS App With Custom Titlebar which might be useful if you are making a custom titlebar for your application.

PhaserJS: After Rotation of camera dragging a Sprite gives strange coords

Basically the problem is that after you rotate the camera, the points that are given as arguments in the callback for dragging are not what I expected. I'm guessing I have to Rotate the given points also but I just couldn't.
Can Someone explain what is going on, is this some kind of bug or what should I do in order the sprite to follow the mouse cursor?
Easiest way to explain the problem is to reproduce it:
1) Go to Phaser Example Runner
2) Copy- Paste this code:
var config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
scene: {
preload: preload,
create: create
}
};
var game = new Phaser.Game(config);
function preload ()
{
this.load.image('eye', 'assets/pics/lance-overdose-loader-eye.png');
}
function create ()
{
var image = this.add.sprite(200, 300, 'eye').setInteractive();
this.cameras.main.setRotation(Math.PI);
image.on('pointerover', function () {
this.setTint(0x00ff00);
});
image.on('pointerout', function () {
this.clearTint();
});
this.input.setDraggable(image);
this.input.on('dragstart', function (pointer, gameObject) {
gameObject.setTint(0xff0000);
});
this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
console.log(`x: ${dragX}, y: ${dragY}`);
gameObject.x = dragX;
gameObject.y = dragY;
});
this.input.on('dragend', function (pointer, gameObject) {
gameObject.clearTint();
});
}
3) Open the console, drag around the Eye and look at what coordinates are given.
4) If you remove line 24 (the rotation of the camera) Everything works as expected.
(The example is taken from Phaser 3 Official examples and a bit changed for the bug)
According to Phaser's API Documentation on the setRotation() method, the rotation given in radians applies to everything rendered by the camera. Unfortunately, your pointer isn't rendered by the camera so it doesn't get the same rotated coordinates. Not sure if this is a bug with the library or just a poorly documented exception, but I believe there is a workaround.
Create 2 variables to hold an initial position and a final position:
var image = this.add.sprite(200, 300, 'eye').setInteractive();
var initial = [];
var final = [];
Populate the initial position in your .on('dragstart') method:
this.input.on('dragstart', function (pointer, gameObject) {
initial = [
gameObject.x,
gameObject.y,
pointer.x,
pointer.y
];
gameObject.setTint(0xff0000);
});
Then, populate the final variable in your .on('drag') method:
this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
final = [
gameObject.x, // not necessary but keeping for variable shape consistency
gameObject.y, // not necessary but keeping for variable shape consistency
pointer.x,
pointer.y
];
gameObject.x = initial[0] + (initial[2] - final[2]);
gameObject.y = initial[1] + (initial[3] - final[3]);
});
All we're doing here is keeping track of the change in pointer position and mimicking that change in our gameObject.

How to improve canvas fabric.js performance with large number of Objects

I need make an App that has about 30k Objects, a user can Pan, Zoom or "Select on click" any of those objects.
Fabric.js Canvas is being used
I have done the same using SVG's and the svg-pan-zoom plugin (no Canvas Element) with better results
Problem: there is a significant Lag while Zooming, Panning or Object on Click
will removing Fabric.js improve performance?
will switching to WebGL improve performance?
Have tried Fabric specific options
fabric.Object.prototype.objectCaching = false;
fabric.Object.prototype.statefullCache = false;
fabric.Object.prototype.noScaleCache = true;
fabric.Object.prototype.needsItsOwnCache = false;
UPDATE
Heres the updated Fiddle
for reference :
canvas-vs-svg-vs-div Stackoverflow
Stackoverflow
Don't Render in IO EVENTS!
Though not a complete fix to the update speed this answer will about double the interaction speed.
A common, almost standard, mistake made with mouse and event interaction with the canvas (and DOM) is to delegate rendering to mouse/touch events. This is very bad practice as mouse events fire at much higher rates than the display can display. It becomes worse when your rendering time is high as you queue up mouse events (pseudo render events) and do a re render for every movement of the mouse
Note blocking code will stop mouse events but as soon as the engine is idle the mouse will start firing at full rate again.
Use the mouse events just to get the mouse state. Use an animation loop that is synced to the display to render only when needed and there is time available. Things like the wheel and mouse movement deltas should be recorded cumulatively.
mouse.dx += event.movementX;
mouse.dy += event.movementY;
mouse.wheel += event.wheelDelta;
And consume them in the main render loop...
function update(){
// ... code to use mouse
// consume deltas
mouse.x = mouse.y = mouse.wheel = 0;
...this ensures that the mouse state is accurately followed when you may have many mouse events between render updates.
Example, separating events from rendering.
Change you code in the fiddle you provided to the following, on my machine it about doubled the rendering speed (which is still very slow).
// from just after the function applyZoom replace all the code
var mouse = { // holds the mouse state
x : 0,
y : 0,
down : false,
w : 0,
delta : new fabric.Point(0,0),
}
// event just track mouse state
function zoom(e) {
if(e != null) { e.preventDefault() }
var evt=window.event || e;
mouse.x = e.offsetX;
mouse.y = e.offsetY;
mouse.w += evt.detail? evt.detail*(-120) : evt.wheelDelta;
return false;
}
canvas.on('mouse:up', function (e) { mouse.down = false });
canvas.on('mouse:out', function (e) { mouse.down = false });
canvas.on('mouse:down', function (e) { mouse.down = true });
canvas.on('mouse:move', function(e) {
if (e && e.e) {
mouse.delta.x += e.e.movementX;
mouse.delta.y += e.e.movementY;
}
});
// main animation loop
function update(){
if(mouse.w !== 0){ // if the wheel has moved do zoom
var curZoom = canvas.getZoom();
canvas.zoomToPoint(
{ x : mouse.x, y: mouse.y },
canvas.getZoom() + mouse.w / 4000
);
mouse.w = 0; // consume wheel delta
}else if(mouse.down) { // if mouse button down
canvas.relativePan(mouse.delta);
}
// consume mouse delta
mouse.delta.x = 0;
mouse.delta.y = 0;
requestAnimationFrame(update);
}
requestAnimationFrame(update);

Recalculate points in an SVG path when first or last point changes

I have built a graph with D3.js based on this example of a force-directed graph, but rather than having straight lines between the nodes I am creating curved lines using SVG path elements. The data structure for an individual link includes a source and target which represent the nodes to which the link is connected. Also the link data structure also contains a line element which contains an array of points defining the path. The data structure for a link looks like this:
{
id:4,
type:"link",
fixed:true,
source: {
id:1,
name: "A",
type:"node",
x:226,
y:190,
fixed:1,
index:0,
weight:1,
},
target: {
id:2,
name: "B",
type:"node",
x:910,
y:85,
fixed:1,
index:1,
weight:1,
},
line:[{x:387, y:69}, {x:541.5, y:179}, {x:696, y:179}]
}
Now in my on tick event handler I have the current x and y co-ordinates for for nodes A and B by means of the references d.source.x, d.source.y and d.target.x, d.target.y. I also have the initial position of node A (first element of d.line) and of node B (last element of d.line). What I am trying to do is to recalculate the points in between the first and last points based on the changes made to the positions of nodes A and B.
Here is my on tick event handler:
force.on("tick", function() {
svg.selectAll("g.node").attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
svg.selectAll("g.link .line").attr("d", function(d) {
var xOffset = 0, // Want to calculate this
yOffset = 0; // Want to calculate this
var line = [ ];
for (var i=0; i<d.line.length; i++) {
if (i==0) {
line[line.length] = { x : d.source.x, y: d.source.y }
}
else if (i==d.line.length-1) {
line[line.length] = { x : d.target.x, y: d.target.y }
}
else {
line[line.length] = { x: d.line[i].x + xOffset, y: d.line[i].y + yOffset }
}
}
return self.lineGenerator(line);
})
});
Not offsetting the x and y co-ordinates for the points in the middle of the path results in these points staying static when nodes A or B are dragged. Can anyone explain how to go about calculating xOffset and yOffset so that the path will correctly move/rotate when the nodes are dragged? Or if anyone knows of a better (read "easier"!) way of accomplishing this with D3.js then please let me know.
UPDATE:
Here is my line generator code in the chart constructor:
this.lineGenerator = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("cardinal");
Let me explain the problem with some images, hopefully they will make the problem that I am having clearer. It is not a matter of the lines being linear, my lines are curved by the line generator, but when I drag a node, I want the curve to drag as well. So all the points on the line must update to reflect the change made to the position of the node. In other words the path must not get distorted by the nodes being moved.
So, in pictures; given this situation:
If I drag node B down and to the left, I want to see something like this:
(Note that this was rotated with image editting software, hence the background is also rotated)
Instead I am getting something like this:
Note how the one intermediary point in the line has stayed static when node B was moved, causing the curve to distort. This is what I am trying to avoid happening.
Hopefully this makes the problem clearer.

Is it possible to animate filter in Fabric.js?

Is it possible to animate the images filter in Fabric.js? Such as a "pixelate" filter.
I solved it in the same way like the demo.
Unfortunately filters aren't able to be animated - they need too much processing time.
Here's my Code:
image = ... //Image, where the filter should be applied
var filter = new fabric.Image.filters.RemoveWhite({
threshold: 0,
distance: 140
});
image.filters.push(filter);
image.applyFilters(canvas.renderAll.bind(canvas));
animate(image,1, 400); //Start the Animation
function animate(image,value, stop){
value += ((stop-value)*0.02); //Change the threshold-value
if (image.filters[0]) {
image.filters[0]['threshold'] = value;
console.log(value);
image.applyFilters(canvas.renderAll.bind(canvas)); //Start creating the new image
if(value<stop-100){
setTimeout(function(){act(image,value,stop);},1);
}
}
}
I know the code isn't the most efficient one, but it works. And you can see that Animating filters consumes too much time.
(I tested it with a 1920x1080px image, maybe you can use it with smaller images)
Here is a updated version for the brightness filter
var brightnessValue = 0.9;
var brightnessFilter = new fabric.Image.filters.Brightness({
brightness: brightnessValue
});
fabricImage.filters.push(brightnessFilter);
fabric.util.requestAnimFrame(function brightnessFilterAnimation() {
brightnessValue = brightnessValue - 0.04;
brightnessFilter.brightness = brightnessValue;
fabricImage.applyFilters();
if (brightnessValue > 0) {
fabric.util.requestAnimFrame(brightnessFilterAnimation);
}
});

Resources