I'm working on a simple AR effect for Facebook in Spark AR studio using JavaScript. I have two 3D objects in the scene and I want to switch between them on button click.
So, for example, I have two buttons, and when I click on the first button I want to show the first 3D object (and hide another one). And vice versa - when I click on the second button I want to show the second 3D object and hide the first one.
I can see some examples of how can I access the object in the scene through the script, but I didn't find yet an example of how to create or use buttons in Spark AR.
Is there any easy "drag-and-drop" way to create a button and assign a function to it (like in Unity)? Or should I create an image of the button on the canvas in the scene, use JavaScript to "find" it, detect if the finger touch was made over this image and trigger a function this way?
There is no easy "drag-and-drop" way to create a button and assign a function to it.
You will need to create an image of the button on the canvas in the scene, use Javascript to "find" it, detect if the finger touch was made over this image and trigger a function this way. Here is example code:
var Scene = require('Scene');
var TouchGestures = require('TouchGestures');
var myBtn = Scene.root.find('button');
TouchGestures.onTap(myBtn).subscribe(function() {
//do stuff here
});
Also do not forget to enable the Tap Gesture in your project capabilities settings.
There is also the Native UI Picker that you can make use of:
https://developers.facebook.com/docs/ar-studio/docs/native-ui
(I'm not sure if this was available at the time the question was posted, I'm new to the game)
This is more "drag-and-drop" in that you don't have to create and place the buttons, just assign textures to fill them in, and then you can write a script to do whatever you want when the user selects a button.
Related
I'm currently working on a canvas built with fabric.js.
I have three objects on a canvas:
First, that cannot be selected/resized/replaced
Second ,that behave the same as the first one
And a third one, which can be replaced/selected etc.
My problem is that when I multiselect them (by using my mouse),
they all became capable of resizing/replacing etc.
My question is:
How can I disable grouping them together, so that the first two objects cannot be select?
I have already tried canvas.selection = false - but this option disables the whole canvas.
To disable the ability to click and drag in order to select multiple objects you can simply add a key:value pair in the options of the fabric.Canvas initialization...
let canvas = new fabric.Canvas("some_id_attribute_value",{selection: false});
The specific key value is selection:false and "some_id_attribute_value" is whatever you specified as the id of the canvas element(basic canvas init step).
I was also having this problem, hope this helps!
I don't know if I follow your question but each object has a selectable property.
Perhaps that will help?
selectable :Boolean
When set to false, an object can not be selected
for modification (using either point-click-based or group-based
selection). But events still fire on it.
http://fabricjs.com/docs/fabric.Object.html#selectable
I am attempting to mimic the the functionality one would see using the Waze LiveMap (https://www.waze.com/livemap) in Cesium. When a point is clicked, it is converted to a marker with an icon.
I've attempted a few different things with varying levels of success and I'm at my wits end. Does anyone have a good suggestion as to how I can proceed?
There are a couple different ways of doing this, some high-level and some lower-level. The high-level one is easiest so I'll start there. The Cesium Viewer fires an event called selectedEntityChanged when its own selection changes, and you can wire that up to toggle billboard show flags on and off.
Here's a demo. For this demo, I took the original map pins demo and added some lines of code: I turned off the show flags for all the billboards at the start, I added points to stand in for the now-hidden billboards, and I added the following block of code to toggle the billboard show flags when selected, like this:
var lastSelectedPin;
viewer.selectedEntityChanged.addEventListener(function(newEntity) {
if (lastSelectedPin && lastSelectedPin.billboard) {
lastSelectedPin.billboard.show = false;
}
lastSelectedPin = newEntity;
if (lastSelectedPin && lastSelectedPin.billboard) {
lastSelectedPin.billboard.show = true;
}
});
This uses Cesium Viewer's own selection system, but toggles the billboard show flag to appear when selected and disappear when de-selected.
Alternatively, you can dig into Cesium's lower levels for finer control, but there will be a longer learning curve. The Picking Demo shows off several types of picking operations, including scene.pick, scene.drillPick, and camera.pickEllipsoid, which offer various ways to detect what contents exist at a particular screen location. Often these functions are called in response to mouse movements or clicks, or touch/pointer events, to see what the user is interacting with.
I am having an issue with reusing the same button within an HTML5 canvas. The button needs to be reused over the course of several separate frames as well as several times within the same frame.
The button works correctly with the first use:
this.button_13.addEventListener("click", fl_ClickToGoToAndStopAtFrame_24.bind(this));
function fl_ClickToGoToAndStopAtFrame_24()
{
this.gotoAndStop(72);
}
At frame 72, I reuse the same button symbol with a new instance name. Unfortunately, this button does not work:
this.button_14.addEventListener("click", fl_ClickToGoToAndStopAtFrame_25.bind(this));
function fl_ClickToGoToAndStopAtFrame_25()
{
this.gotoAndStop(78);
}
Clicking this second button shows the button states, but will not advance the user to frame 78.
*If the 2nd button exists on the timeline for frame 72 only, it is not present in the published result at all. If the 2nd button exists on frame 72-77, the button is present but not functional.
Any ideas?
Try to do this
this.button_13.removeEventListener("click", fl_ClickToGoToAndStopAtFrame_24.bind(this));
before creating the second event listener.
You have two options here.
Put your separate button instances on different layers.
Create one button instance on its own layer, have a script set the button's visible property (true/false) as needed, and modify your click handler to react based on the value of this.currentFrame.
Animate CC (2015.2 for me at the time of this writing) seems to generate its HTML 5 script output with animation in mind. When you have like object instances on multiple frames on the same layer, instead of creating a new instance of that object, it re-purposes the instance from a prior frame.
e.g. I create a dynamic text box named "myText" on frame 1. On frame 2, I create another dynamic text box and name it "myOtherText". When I publish and look at the script, the script calls Tween.to() first to place the "myText" object on the canvas and give it its appearance and position, then chains another .to() call to make myText look like myOtherText. Under the hood, myOtherText simply doesn't exist.
Creating another layer forces Animate to create the instances explicitly in CreateJS. However, if you have a lot of buttons, that could end up making a ton of layers and making your timeline look messy. I'd recommend option 1 if you only have a couple button instances, but for the latter case, option 2 may be the way to go.
Create a new layer. Name it whatever you want, like "button layer".
This layer will have only one keyframe.
Place your button instance on this layer. For continuity's sake, let's name it button_13.
Bind a tick handler to the root MovieClip (i.e. this) to handle whether the button should appear or not.
var tickHandler = function () {
switch (this.currentFrame) {
//Add case statements for each frame you want the button to appear on
//Remember, frame indexes in CJS are 0-based!
case 12: case 13:
this.button_13.visible = true;
break;
default:
this.button_13.visible = false;
}
}.bind(this);
this.removeEventListener('tick', tickHandler); //Make sure not to double-bind
this.addEventListener('tick', tickHandler);
Bind a click handler to the button that will gotoAndStop on a frame dependent on the current frame.
var clickHandler = function () {
switch (this.currentFrame) {
//Add case statements for each frame that should have a jump
//Remember, frame indexes in CJS are 0-based!
case 12:
this.gotoAndStop(72);
break;
case 13:
this.gotoAndStop(78);
break;
}
}.bind(this) //Proxy the handler, as done above.
this.button_13.removeEventListener('click', tickHandler); //Make sure not to double-bind
this.button_13.addEventListener('click', tickHandler);
Place both of those scripts onto frame 1 of your movie.
I haven't tested this myself as presented, but it should accomplish what you're looking for.
The solution is to move the instance on another layer. In that way, two different instances can be used in different images with different scripts and different names.
I am able to select object programatically using fabricjs. However, it does not behave like when one selects an object using mouse click. On a mouse click, the object comes under focus, and one can, for example, drag it. However, on programatic selection, I cannot immediately move an object. An example jsfiddle:
http://jsfiddle.net/ThzXM/1/
Programmatic selection:
canvas.setActiveObject(canvas.item(0));
What I would like to ultimately achieve is this: on clicking a button, a new rectangle is added to canvas, which the user can move around before placing it on canvas - without requiring extra clicks. Is it possible to do this in a cross-browser compatible way? (I know in some browsers I can fire a mouseclick event but most disallow it.)
You have to do this. Don´t forget to call setCoords() to update the bounding box of your object.
// Set the active element
canvas.setActiveObject(canvas.item(0));
// Set left, o right,or angle... check documentation.
//Don´t forget to call setCoords() after changes.
canvas.item(0).setLeft(80).setCoords();
//Then render the canvas
canvas.renderAll()
I have multiple instances of codemirror running on my page. Some are hidden and you can move between them using tabs. What I would like to do is be able to set the focus based on the container.
At some point the instance was initiated like this:
var cmInstance = CodeMirror(target, options());
So I would either like to be able to get the instance that was initiated on that container by using the container, something like:
cm = target.getCodeMirror();
or perhaps set the focus based on the container, something like:
target.setFocus();
Is anything like this possible or should I rather keep a record of individual instances in an array or something?
Okay so I opted to track my instances of codemirror in an array and address them based on an ID that I keep track of and link to the target. Once I have my instance I can just set focus using the codemirror method cmInstance.focus();
Currently I feel this is the best solution.