I am using Ariutta's svg-pan-zoom with svg.js. I have disabled the native Arriuta doubleclick functionality and have tried adding my own, which ultimately consists of a pan adjustment and an animation.
Usually this works fine, but sometimes when I load my page the doubleclick function acts strangely. According to my debugging, it looks like sometimes when my app loads, the doubleclick function I wrote is called twice for each doubleclick. This causes the animation to behave strangely, and there seems to be no consistent basis for when this issue arises. Restarting my server sometimes works, and sometimes doesn't. I pretty much just have to continue reloading my page until the issue goes away.
My initial thoughts are that maybe there is something off in the load order of my files, and sometimes things load out of order. Currently investigating this. My other thought was that maybe this has something to do with the svg.js animation library or my trying to replace the native double-click function in arriuta's plugin. Thoughts?
myApp.service('AnimatorService', function(){
this.dblClickBehavior = function(svgCanvas, zoom){
$('.node').dblclick(function(){
// get pan
pan = zoom.getPan();
// get screen width and height
var sizes = zoom.getSizes();
var centerX = (sizes.width)/2;
var centerY = (sizes.height)/2;
// get center position of svg object double clicked
var x0 = this.instance.first().attr('cx');
var y0 = this.instance.first().attr('cy');
//determine the correct pan value necessary to center the svg
panAdjustX = centerX - x0*sizes.realZoom;
panAdjustY = centerY - y0*sizes.realZoom;
//center the svg object by adjust pan
zoom.pan({'x' :centerX - x0*sizes.realZoom, 'y' : centerY - y0*sizes.realZoom});
//simple animation on the object
this.instance.first().animate().radius(centerX);
});
}
});
When it behaves correctly, the svg image centers and then grows. When it behaves incorrectly, it centers and then shrinks into nothingness.
You tagged svg.js so I will give an svg.js answer. There is a plugin svg.panZoom.js now which can be used to easily implement the functionality you want:
var canvas = SVG('container').viewbox(0,0,1000,1000)
canvas.image('https://www.zooroyal.de/magazin/wp-content/uploads/2017/05/cat-2783601_1920.jpg', 1000, 1000)
.attr('preserveAspectRatio', 'none')
canvas.on('dblclick', function(e) {
var p = this.point(e.pageX, e.pageY)
var zoomLvl = 3
// zoom into point p to zoomLvl
canvas.animate().zoom(zoomLvl, p)
})
Here is a fiddle: https://jsfiddle.net/Fuzzy/95t6oL8y/5/
When you want to be able to panZoom your svg, too. Just add a call to canvas.panZoom()
Related
I noticed that in pixi.js version 1.3, as seen in this example, stacking sprites, then click and drag only drags the top most sprite.
bunny.mousedown = bunny.touchstart = function(data)
{
// data.originalEvent.preventDefault()
// store a refference to the data
// The reason for this is because of multitouch
// we want to track the movement of this particular touch
this.data = data;
this.alpha = 0.9;
this.dragging = true;
this.sx = this.data.getLocalPosition(bunny).x * bunny.scale.x;
this.sy = this.data.getLocalPosition(bunny).y * bunny.scale.y;
};
http://jsfiddle.net/dirkk0/cXfpq/
In version 3.0.3, as seen in this example, the same code causes all the sprites under the mouse to be dragged.
http://jsfiddle.net/9tnaa31z/5/
Is there a way to get only the top most sprite or a way to get a list of all the sprites (in the order rendered)?
I think there may have been a bug in the 3.0.3 version of PIXI. I just tried it out with the latest 3.0.5 and it works as expected i.e. it drags only the top-most Sprite.
Update the External Resources in your fiddle with this latest version of Pixi.js and it should work.
Reference: https://cdnjs.com/libraries/pixi.js.
I need your help. I'm working on the project where necessary to implement a circular slider with draggable button-control by it. I decided to use this jQuery-Knob slider. it's great but I need to add button that could be possible to set styles and be dragged
I made a decision to add div element through javascript and then tie native Jquery Knob params of dragging to it.
Here what I have done
And here is my code
function addBtnControl(self) {
// cache variables
var button = document.getElementById('knob-ctrl'),
cx = 22*self.scale,
cy = 20*self.scale,
a = self.arc(self.cv),
start = xyOnArc(self.xy-cx, self.xy-cy, self.radius/self.scale, a.s);
// check if pointer-events are supported
// if not than use fallback btn ctrl for IE
App.config.Modernizr.addTest('csspointerevents',function(){
return 'pointerEvents' in document.documentElement.style;
});
if (App.config.Modernizr.csspointerevents) {
self.cursorExt = 0;
button.style.left = start.x + "px";
button.style.top = start.y + "px";
}
function xyOnArc(cx, cy, radius, radianAngleX) {
var x = cx + radius * Math.cos(radianAngleX);
var y = cy + radius * Math.sin(radianAngleX);
return ({
x: x,
y: y
});
}
}
// init Button Ctrl
addBtnControl(this);
I dynamically added a button and borrowed params that must be enough to make a well-suited draggable control but I've been doing something wrong because if I scale a browser or just open on another screen size it looks like this
So something wrong with the functions and params that passed to it.
Actually jQuery knob was using Canvas, so adding external layers with it makes more complex.
Alternatively i suggest to use the jQuery roundSlider plugin which is similar to knob, but it constructs based on the div elements only. So you can make any custom appearances as per your wish.
For more details check the demos and documentation page.
Check this demo from jsFiddle which is similar to your requirement.
Screenshot of the Output:
I have figured out a nice effect from application that needs several UI elements but also requires as much screen space as possible.
Idea of the effect is, that the UI buttons almost dissapear as soon as you move the mouse too away from them.
I have made a jsFiddle in case you'd like to see it.
It's quite simple:
window.addEventListener("mousemove", function(e) {
var rect = element.getBoundingClientRect();
//Measuring distance from top-left corner of the div
var top = rect.top+(rect.bottom-rect.top)/2;
var left = rect.left+(rect.right-rect.left)/2;
//Mouse position
var x = e.clientX;
var y = e.clientY;
//Thank pythagoras for this
var distance = Math.sqrt(Math.pow(x-left, 2)+Math.pow(y-top, 2));
//Brightness in interval <1, 0.1>
var brightness = Math.min(1, Math.max(0.1, 100/distance));
element.style.opacity = brightness+"";
});
This jsFiddle was also supposed to demonstrate problem I have - but it runs unexpectedly smoothly.
The problem is, that the browsers seem to buffer the CSS changes if they are too frequent. This is a very smart performance strategy but in my case it quite breaks the effect.
I have also uploaded test script here. In Google Chrome, buffering appeared to be so strong (and unsynchronized), that the buttons sometimes flickered.
Should I implement some frame-skip so that the browser buffer is not initiated by the animation effect?
My buttons have their bottom border cut off. If you'd know why this happens, please let me know in comments
I am working on some image viewing tools in KineticJS. I have a rotate tool. When you move the mouse over an image, a line appears from the centre of the image to the mouse position, and then when you click and move, the line follows and the image rotates around that point, in sync with the line. This works great.
My issue is, I have the following set up:
Canvas->
Stage->
Layer->
GroupA->
GroupB->
Image
This is because I draw tabs for options on GroupA and regard it as a container for the image. GroupB is used because I flip GroupB to flip the image ( and down the track, any objects like Text and Paths that I add to the image ), so that it flips but stays in place. This all works well. I am also hoping when I offer zoom, to zoom groupb and thus zoom anything drawn on the image, but for groupA to create clipping and continue to support drag buttons, etc.
The object I am rotating, is GroupA. Here is the method I call to set up rotation:
this.init = function(control)
{
console.log("Initing rotate for : " + control.id());
RotateTool.isMouseDown = false;
RotateTool.startRot = isNaN(control.getRotationDeg()) ? 0 : control.getRotationDeg();
RotateTool.lastAngle = control.parent.rotation() / RotateTool.factor;
RotateTool.startAngle = control.parent.rotation();
this.image = control.parent;
var center = this.getCentrePoint();
RotateTool.middleX = this.image.getAbsolutePosition().x + center.x;
RotateTool.middleY = this.image.getAbsolutePosition().y + center.y;
this.image.x(this.image.x() + center.x - this.image.offsetX());
this.image.y(this.image.y() + center.y - this.image.offsetY());
this.image.offsetX(center.x);
this.image.offsetY(center.y);
}
getCentrePoint is a method that uses trig to get the size of the image, based on the rotation. As I draw a line to the centre of the image, I can tell it's working well, to start with. I've also stepped in to it and it always returns values only slightly higher than the actual width and height, they always look like they should be about what I'd expect, for the angle of the image.
Here is the code I use on mouse move to rotate the image:
this.layerMouseMove = function (evt, layer)
{
if (RotateTool.isRotating == false)
return;
if (!Util.isNull(this.image) && !Util.isNull(this.line))
{
if (Item.moving && !RotateTool.isRotating)
{
console.log("layer mousemove item moving");
RotateTool.layerMouseUp(evt, layer);
}
else
{
var pt = this.translatePoint(evt.x, evt.y);
var x = pt.x;
var y = pt.y;
var end = this.getPoint(x, y, .8);
RotateTool.line.points([this.middleX, this.middleY, end.x, end.y]);
RotateTool.line.parent.draw();
RotateTool.sign.x(x - 20);
RotateTool.sign.y(y - 20);
var angle = Util.findAngle({ x: RotateTool.startX, y: RotateTool.startY }, { x: x, y: y }, { x: RotateTool.middleX, y: RotateTool.middleY });
var newRot = (angle) + RotateTool.startAngle;
RotateTool.image.rotation(newRot);
console.log(newRot);
}
}
}
Much of this code is ephemeral, it's maintaining the line ( which is 80% of the length from the centre to my mouse, as I also show a rotate icon, over the mouse.
Sorry for the long windedness, I'm trying to make sure I am clear, and that it's obvious that I've done a lot of work before asking for help.
So, here is my issue. After I've rotated a few times, when I click again, the 'centre' point that the line draws to, is way off the bottom right of my screen, and if I set a break point, sure enough, the absolute position of my groups are no longer in sync. This seems to me like my rotation has moved the image in the manner I hoped, but moved my group off screen. When I set offsetX and offsetY, do I need to also set it on all the children ? But, it's the bottom child I can see, and the top group I set those things on, so I don't really understand how this is happening.
I do notice my image jumps a few pixels when I move the mouse over it ( which is when the init method is called ) so I feel like perhaps I am just out slightly somewhere, and it's causing this flow on effect. I've done some more testing, and my image always jumps slightly up and to the right when I move the mouse over it, and the rotate tool continues to work reliably, so long as I don't move the mouse over the image again, causing my init method to call. It seems like every time this is called, is when it breaks. So, I could just call it once, but I'd have to associate the data with the image then, for the simple reason that once I have many images, I'll need to change my data as my selected image changes. Either way, I'd prefer to understand and resolve the issue, than just hide it.
Any help appreciated.
I implemented a simple draggable world map for a game but the performance differs when using different browsers - which is kinda obvious. I used 256x256 pixle tiles and the script dynamically renders the number to fill the whole window plus borders.
Prototype: http://mt111102.students.fhstp.ac.at/draggable/game.html
Currently I'm doing it simply by setting the top and left style attributes on mousemove. Heres a snippet:
mouseDown : function(e) {
Map.myPreventDefault(e);
dx = map.offsetLeft - e.clientX;
dy = map.offsetTop - e.clientY;
map.addEventListener('mousemove', Map.divMove, false);
},
divMove : function(e) {
Map.myPreventDefault(e);
map.style.position = "absolute";
map.style.cursor = "move";
map.style.left = e.clientX + dx + "px";
map.style.top = e.clientY + dy + "px";
}
Later when dragging to the borders I'm gonna load new tiles with XHR and delete old ones on the other end to retain performance so that the wrapper doesn't get to big.
My question is: Would it be more performant by using CSS translate instead of just setting the top and left attributes? And do you guys have any tips how to make it smoother?
In Firefox the prototype works almost perfectly smooth but in Webkit browsers like Chrome it doesn't look very good - it lags a bit. I just wonder how Google Maps managed it to work in every modern browser with the same smoothness.
A CSS transform, especially with a Z value (which will load the transform into the GPU), will almost always be faster and smoother - especially on devices like iPads, but elsewhere as well.
For more details you can check out this tutorial on GPU acceleration:
http://creativejs.com/2011/12/day-2-gpu-accelerate-your-dom-elements/