Pixi js - need to make clickable background - javascript

I need to be able to click on background, and get the position of the click.
I tried adding an event listener to stage like this
app.stage.interactive = true;
app.stage.on('click', function(){
console.log('hello');
})
but it works only if i click on element inside the stage, not the background itself.
Do i need to make a sprite as a background, if so, how do i set its background color and make sure it stays under all the other elements?

The stage is a PIXI.Container, which means it's basically an empty node that can hold children. It doesn't have dimensions of its own, and so when the interaction manager goes to hit-test your click, it isn't detected.
Your suggestion of adding a background sprite is probably the simplest solution. You can add one like so:
// Create the background sprite with a basic white texture
let bg = new PIXI.Sprite(PIXI.Texture.WHITE);
// Set it to fill the screen
bg.width = app.screen.width;
bg.height = app.screen.height;
// Tint it to whatever color you want, here red
bg.tint = 0xff0000;
// Add a click handler
bg.interactive = true;
bg.on('click', function(){
console.log('hello');
});
// Add it to the stage as the first object
app.stage.addChild(bg);
// Now add anything else you want on your stage
...
PixiJS renders objects in order, so if you add your background sprite as the first child of the app's stage, it will be rendered behind all other content. When hit-testing a click, it will be the last object tested, and so will catch a click on the background of the stage. Note that to "block" clicks, other objects will need to be set to interactive = true, even if they don't have a click handler attached!

A possible solution would be to add an event on app's view.
app.renderer.view.addEventListener('click', function(e) {
console.log(e);
});

Related

Mouse click through top image

I created two shapes with image as source using createjs(img1 and img2 at same position but z index is different). one image is on top of another image i.e. img2 on img1 in canvas. and image below has click event i.e. img1 has click event which work fine. but when i enable img2(not having any click event) on img1 than mouse click event work through top image. if add click event to img2 than it work properly. is that compulsory to add click event to each image to avoid click through images.
CODE:
[function test(){
var btnContainer=new createjs.Container();
btnContainer.mouseChildren=true;
var shape = new createjs.Shape();
shape.graphics.clear().beginBitmapFill(loader.getResult("play-btn")).drawRect(0,0,291,98);//"no-repeat"
shape.x=shape.y=200;
shape.mouseEnabled =true;
shape.addEventListener("click", playClick);
var shape1 = new createjs.Shape();
shape1.graphics.clear().beginBitmapFill(loader.getResult("play-btn")).drawRect(0,0,291,98);//"no-repeat"
shape1.x=shape1.y=250;
shape1.mouseEnabled =true;
shape1.addEventListener("click", playClickShape1);
btnContainer.addChild(shape,shape1);
gameStage.AddChildWidget(btnContainer);
}
function playClick(event)
{
console.log("\[playClick\] Start");
ReadXMLFile();
}
function playClickShape1(event)
{
console.log("\[playClickShape1\] Start");
}
If some image is overlaying other content which as click handler, it won't be registered as the top one will be blocking clicks. It won't propagate clicks to the bottom of the site. Try adding pointer-events:none css rule to the top image that you don't want registering click events, and the one on the bottom should be clickable.
The answer from #Sebastian is correct for DOM elements (with the CSS solution).
If both images are bitmaps in Canvas (via EaselJS), then a similar limitation exists. Anything with a "click" event will block clicks on elements below. Unlike HTML though, if there is no mouse event on an element, it will not block mouse events (basically it has pointer-events:none by default.
If you want to determine if a click happened on any element (regardless of layering), you could listen for clicks on the stage, and use getObjectsUnderPoint() to determine what was clicked, and you could check if either (or both) were clicked that way.
stage.on("stagemouseup", function(event) {
var objs = stage.getObjectsUnderPoint(event.stageX, event.stageY);
for (var i=0, l=objs.length; i<l; i++) {
var obj = objs[i];
if (obj == firstElement || obj == secondElement) { doSomething(); break; }
}
);
Docs:
https://createjs.com/docs/easeljs/classes/Container.html#method_getObjectsUnderPoint

easeljs mouse events on disabled stage curosr

In my simple application i need to hide original cursor stage.cursor = 'none'; stage.enableMouseOver(), than i replace it with my own image
Than i register listener on stagemousemove event:
myBitmap.x = stage.mouseX;
myBitmap.y = stage.mouseY;
After this action i loose access to listen mouse events on other stage objects:
//nothing happen on mouse over
someBitmap.on('mouseover', function() { console.log(1) });
Is there any possible solutions, expect check every time hitTests on my objects inside stage mouse events?
Fixed by setting up cursor: none in my css rules and removing stage.cursor = 'none'from js. Thanks #Andew for example.

d3.js: click equivalent of mouseout

What I mean by a click equivalent of mouseout is that I'd like a way to click on an element to change some attribute then have it change back when I click on anything but that element. Toggling this attribute change with hovering is easy because you change things based on mouseover and mouseout, but I'm unsure of how to do the same based on the click event.
So what I have is an svg element with circles on it, which display a red outline when they're clicked on. I know enough to be able to make only one circle appear selected at a time, but I don't know how to deselect all nodes when I click on a part of the svg that isn't a circle. If this isn't clear enough, I can create a jsfiddle to demonstrate what I have so far.
I have a working knowledge of selections from reading many examples, but can't seem to figure out what approach I should take to achieve this.
You could use d3.dispatch to set up some custom event handling. Sometimes separating out distinct behaviors from the rest of your layout code helps to keep things organized.
You might want one function to unhighlight all of the clickable circles, and another to toggle a single circle. Then when the svg is clicked, you can decide whether to unhighlight all based on whether a circle was clicked or not.
In other words...
When a circle is clicked, toggle it.
When the svg document is clicked, and the click is not on a circle, unhighlight all circles.
Then you can set up separate dispatch events for the two processes. This is nice because then these become reusable behaviors. If for example, you later want to add a button to unhighlight all circles, or want to highlight a circle when it's moused over, you can call the same dispatch functions.
var dispatch = d3.dispatch('unhighlightAll','toggleSingle')
// remove the `highlighted` class on all circles
.on('unhighlightAll', function() {
d3.selectAll('.clickable-circle').classed('highlighted', false);
})
// toggle the `highlighted` class on element `el`
.on('toggleSingle', function(el) {
d3.select(el).classed('highlighted', function() {
return !d3.select(el).classed('highlighted');
});
});
Finally, you call the dispatch functions from your click handlers:
svg.on('click', function() {
// do nothing if a clickable circle is clicked
if (d3.select(d3.event.target).classed('clickable-circle')) {
return;
} else {
// otherwise unhighlight all circles
dispatch.unhighlightAll();
}
});
circles.on('click', function() {
dispatch.toggleSingle(this);
});
Then all that's left is to decide how to display the highlighted class, and handle that in your css.
Here's a demo JSBin
--EDIT--
I just realized that since you're trying to mimic mouseout, you probably don't want multi-select. You'd just need to change the toggleSingle function a bit:
dispatch.on('toggleSingle', function(el) {
// store state of current element
var highlighted = d3.select(el).classed('highlighted');
// unhighlight all
dispatch.unhighlightAll();
// set opposite of stored state
d3.select(el).classed('highlighted', !highlighted);
});
And here's the updated JSBin.
Add a click handler on the SVG. In that click handler, first deselect all circles. Then, check the event target via d3.event; if it is a circle, select it. Pseudocode-ish description:
svg.on('click', function() {
circles.classed('selected', false);
var target = /* get event target */;
if (/* target is circle */) {
target.classed('selected', true);
}
});
Jshanley's answer is great and is probably better in most cases, but I ended up modifying it a bit:
svg.selectAll("dot").data(datasource).enter() //you probably have your own thing here
.on("mousedown", function(d) {
d3.selectAll("circle") //this selects all of the elements you want to deselect by html tag (here its "circle")
.style("fill", "black"); //default color of unselected elements, here its black
d3.select(this) //select the element that's just been clicked
.style("fill", "orange"); //orange is the color of currently selected element
});
This works as long as the default style on all elements is applied before the style of the selected element.

jVectorMap generates a 100x100 when display object is initially hidden

So I'm having a problem generating my jVectorMap.
The map itself sits inside a very custom drop down menu that I have created and this is where I suspect the problem is.
When I mouseover my menu item to open up the drop down which contains the map the actual svg starts out with a forced dimension of 100px x 100px.
What I have tried to do a number of workarounds wher I call the "map.setSize()" either on the mouseclick event of the dropdown as well as the mouseover event of the container itself. The problem here is my dropdown is not subject to a click event but shows on the mouseover event. However, at the point of the mouseover event the actual container for the map hasn't loaded so I'm still stuck with a 100px x 100px svg.
To get around this I've put an event on the mouseover event of the container itself but this isn't great either as it then requires the user to move his mouse over the container before it actually shows the map, something I don't want to happen.
Is there a way of getting the map built inside a div which is invisible before my menu event occurs?
For an example of my problem I've created this at jsfiddle http://jsfiddle.net/AEup9/
You will notice that when you hover over the "Show Map" menu item (the only item) the drop down is blank except for the topic headers until you move the mouse over the actual drop down itself which then reloads the map. I then keep the map there by using my "loaded" variable created before my mouseover event and a force map.setSize() inside the same event:
var loaded = false;
$('#aamap').mouseover(function () {
if (!loaded) {
(function () {
map = new jvm.WorldMap({
map: 'za_mill_en',
container: $('#southafrica-map'),
backgroundColor: '#cbd9f5',
initial: {
fill: 'white'
},
series: {
regions: [{
attribute: 'stroke'
}]
}
});
loaded = true;
})();
}
map.setSize();
});
This is my rough work around but not what I really want as I want the map to show up first time.
Can anyone help me here?
Edit: I finally decided to NOT go ahead with using jvectormap due to this issue. Instead I opted to use jqvmap which is to some degree a fork of jvectormap, however the issues experienced with jvectormap were no longer a problem.
I met this issue as well.
To solve that problem we need to run an updateSize method on a map object when container of our map becomes visible. First, to get the map object we need to use this command:
$('#world-map').vectorMap('get', 'mapObject') and when execute updateSize on it, like:
var map = $('#world-map').vectorMap('get', 'mapObject');
map.updateSize();
or in a shorter form:
$('#world-map').vectorMap('get', 'mapObject').updateSize();

change cursor property with javascript

i have coded a simple javascipt that when the user clicks sth, to do some stuff. I also want that the cursor to be changed, so i added this
<script>
$(document).ready(function() {
$(".targetClass").click(function () {
$('#loaderImage').show();
//this is the line i add
$('.container').css('cursor','wait');
});
});
</script>
And it works. But if i take the cursor on a link the cursor will change again to "pointer" value. What i have to do so the cursor, after the click remain to wait value (even i put it on any element of the page)? Thx!!
here is the solution to your problem.
create a class with pointer wait and add it to button/link also while clicking on it.
$(document).ready(function() {
$(".targetClass").click(function () {
//$('#loaderImage').show();
//this is the line i add
$('.container').css('cursor','wait');
$(this).addClass('cursor');
});
});
.cursor{
cursor:wait;
}
Just ADD this below CODE EXAMPLE HERE.
(1) If all a links shows busy.
$('.container, a').css('cursor','wait');
(2) If all a links within CONTAINER shows busy.
$('.container, .container a').css('cursor','wait');
(3) If all a links within whole(DOM) page shows busy.
$('*').css('cursor','wait');
EXAMPLE HERE.
Every element within the container will overwrite the cursor wait with it's default behaviour. You would have to set cursor wait to all elements.
$('*').css('cursor','wait');
You can use:
$('*').css('cursor','auto');
to set everything to default again.
Or possibly better:
$('*').css('cursor','');
to reset to the previous cursor state, therefore not overriding other cursor changes.
add the following to the function:
$(document).css('cursor','wait');

Categories

Resources