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.
Related
I have a pixi.js html canvas with thousands of objects on it and I want the user to be able to zoom into it with the usual rectangular selection area. The brute force way to implement this would be to draw the rectangle on each mouse move and rerender the whole stage. But this seems like a waste of CPU. Plus this is so common in user interfaces, that I suspect that there is already some function in pixi.js or a plugin that solves this.
If there is no plugin: If I could save the whole buffer to some 2nd buffer when the user presses the mouse button, I could draw the rectangle on top, and on every mouse move, copy back the 2nd buffer to the primary buffer before drawing the rectangle. This would mean that I didn't have to redraw everything on every mouse move. But I don't think that one can clone the current buffer to some named secondary buffer.
Another alternative would be to move a rectangular DOM object on top of the canvas, but then I am afraid that the current pixel position will be hard to relate to the pixi.js / html5 canvas pixels.
Is there a better way? Or some plugin / search engine keyword that I'm missing? How would you implement a rubber band in html canvas or pixi.js ?
I ended up solving this with a separate DOM object that is moved over the canvas. The solution also requires the new interaction manager in PIXI 4, that offers a single callback for any mouse movement over the canvas.
In the following, I assume that the canvas is placed at canvasLeft and canvasTop pixels with CSS.
$(document.body).append("<div style='position:absolute; display:none; border: 1px solid black' id='tpSelectBox'></div>");
renderer = new PIXI.CanvasRenderer(0, 0, opt);
// setup the mouse zooming callbacks
renderer.plugins.interaction.on('mousedown', function(ev) {
mouseDownX = ev.data.global.x;
mouseDownY = ev.data.global.y; $("#tpSelectBox").css({left:mouseDownX+canvasLeft, top:mouseDownY+canvasTop}).show();
});
renderer.plugins.interaction.on('mousemove', function(ev) {
if (mouseDownX == null)
return;
var x = ev.data.global.x;
var y = ev.data.global.y;
var selectWidth = Math.abs(x - mouseDownX);
var selectHeight = Math.abs(y - mouseDownY);
var minX = Math.min(ev.data.global.x, mouseDownX);
var minY = Math.min(ev.data.global.y, mouseDownY);
var posCss = {
"left":minX+canvasLeft,
"top":minY+canvasTop,
"width":selectWidth,
"height":selectHeight
};
$("#tpSelectBox").css(posCss);
});
renderer.plugins.interaction.on('mouseup', function(ev) {
$("#tpSelectBox").hide();
mouseDownX = null;
mouseDownY = null;
$("#tpSelectBox").css({"width":0, "height":0});
});
For older version of PIXI, here is an example of pan/zoom without a rectangle
https://github.com/Arduinology/Pixi-Pan-and-Zoom/blob/master/js/functions.js
In May 2015, the Interaction Manager got extended to allow easier pan/zoom handling https://github.com/pixijs/pixi.js/issues/1825 which is what I'm using here.
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()
Trying to binb hammerJs multi-touch into my current kineticJs 5.1 codes, found tips, but my puzzle pieces does not rotate at all, and my pieces are kinetic shape, why?
var startRotate = 0;
var hammertime = Hammer(piecesArray[i][j].shape);
hammertime.on("transformstart", function(e) {
startRotate = piecesArray[i][j].shape.rotation();
}).on("transformstart", function(e) {
piecesArray[i][j].shape.rotation(startRotate + e.gesture.rotation);
layer.draw();
});
my fiddle : http://jsfiddle.net/e70n2693/20/
This example is for KineticJS v5.1.0 and HammerJS v1.0.7
You have to apply Hammer instance on Kinetic.Node instance, not on Image object.
var hammertime = Hammer(piecesArray[i][j].shape);
hammertime.on("transformstart", function(e) {
this.startRatation = this.rotation();
}).on("transform", function(e) {
this.rotation((this.startRatation || 0) + e.gesture.rotation);
this.getLayer().draw();
});
http://jsfiddle.net/e70n2693/30/
Note: I think it is better to set another center for shape via offset.
use the latest version of hammer.js v2.0.
check out the getting started guide.
"The pinch and rotate gestures are disabled by default, enable it by"
hammertime.get('pinch').set({ enable: true });
hammertime.get('rotate').set({ enable: true });
Here's an updated jsfiddle. I couldn't test it though, i can't make a rotate gesture, hope it works.
Edit:
The problem is, Hammer(imageObj, options); api expects imageObj to be an html element, in your case it's a kinetic shape. I don't know if you can get the html elements for each kinetic shapes. If not, you can listen to rotation on the .kinetic-container canvas element. So the rotation gesture is performed on the whole canvas, and you have to keep track of the last touched kinetic shape so you can rotate it.
I've setup a refactored jsfiddle, showing the ideas i mentioned, however i couldn't manage to rotate the shape using kinetic, i hope this will fix your problem, again i couldn't test it for rotate but it works for tap.
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'm working on a 2d canvas-based app using EaselJS where the user can move indefinitely on the xy-plane by dragging the background. Think google maps, except the background is a repeating tile.
The code for the movement is very simple and looks something like this:
// container - the createjs.Container being panned
// background - a createjs.Shape child of container, on which the
// background is drawn
background.onPress = function(evt) {
var x = evt.stageX, y = evt.stageY;
evt.onMouseMove = function(evt) {
// the canvas is positioned in the center of the window, so the apparent
// movement works by changing the registration point of the container in
// the opposite direction.
container.regX -= evt.stageX - x;
container.regY -= evt.stageY - y;
x = evt.stageX;
y = evt.stageY;
stage.update();
};
evt.onMouseUp = function(evt) {
// Here the background would be redrawn based on the new container coords.
// However the issue occurs even before the mouse is released.
background.redraw();
stage.update();
};
};
All works as expected until reaching 32678px (2^15) on either axis. What occurs is different in different browsers, but the point where it first happens is the same.
In Firefox, it will suddenly shift a large chunk of pixels (~100) rather than 1. It will then happen again at 65538 (2^16+2), perhaps more after that, but I haven't witnessed it. After the trouble points, the drag will continue smoothly, as expected, but remaining shifted.
In Chrome, the effect is more dramatic. The drawing breaks and results in repeated ~100px wide "stripes" of the background across the page at 32768, and does not correct itself on redraw.
Oddly, the numbers in EaselJS don't reflect the issue. The only change in the container's transform matrix is the tx or ty incrementing by 1. No other matrices change. It seems as though EaselJS is getting all the numbers right.
Can anyone shed any light this issue?
Edit:
I worked around this problem by redrawing parts of the container using a calculated regX/regY, rather than attempting to translate very large regX/regY coords on the canvas.
This question may be related
What is the maximum size for an HTML canvas?
From what I gather browsers use short int to store canvas sizes with 32,767 being the maximum possible value.
Links possibly related to your issue,
Mozilla - HTML5 Canvas slow/out of memory
https://stackoverflow.com/a/12535564/149636