babylonjs - how do i move or scale an imported mesh out of its scope? - babylonjs

failed attempts
here are some forced attempts to do it, inside BABYLON.SceneLoader.ImportMesh...{ newMeshes[0].position.x=10; } it works using the local item newMeshes[0], but out of this nothing works.

This is because the variable newMeshes is only defined inside the callback function. If you want to get the variable outside of the function you need it to be defined in the global scope. To do this simply declare a variable before ImportMesh is called and inside of ImportMesh's callback function set that variable to newMeshes[0] like this:
var meshisin = BABYLON.AbstractMesh;
// Define the variable in the global scope.
var skullMesh;
meshisin = BABYLON.SceneLoader.ImportMesh("", "scenes/", "skull.babylon", scene, function (newMeshes) {
skullMesh = newMeshes[0];
});
Then you can change the position of the mesh with: skullMesh.position.x = 10;.
But since it takes say 1 second to load the mesh you delay using the mesh until it's loaded with a setTimeout like this:
setTimeout(function() {
skullMesh.position.x = 10;
}, 1000);
All in all your code would become:
var meshisin = BABYLON.AbstractMesh;
// Define the variable in the global scope.
var skullMesh;
meshisin = BABYLON.SceneLoader.ImportMesh("", "scenes/", "skull.babylon", scene, function (newMeshes) {
skullMesh = newMeshes[0];
});
setTimeout(function() {
skullMesh.position.x = 10;
}, 1000);
PS: It's generally not a good idea to post code in images.

Related

An object property of type function

I have an InterstitialAd QML object (QtQuick 2, QT 5.13) with onClosed event that is triggered with the interstitial ad is closed. I tried to show the interstitial ad before starting new game with the following QML code:
InterstitialAd {
id: iAd
property variant handlerFunc
onClosed: {
if (handlerFunc) {
handlerFunc
handlerFunc = null
}
}
}
function resetGameWithAd()
{
iAd.handlerFunc = Qt.binding(function() {
console.log("AdTest: calling resetGame()")
scene.resetGame()
})
console.log("AdTest: calling iAd.show()")
iAd.show()
}
where I tried to assign handlerFunc to a function that restarts the game when onClosed event is triggered, but got an effect that I did not expect. The console output of my app is:
qml: AdTest: calling resetGame()
qml: AdTest: calling iAd.show()
so obviously assigning handlerFunc to Qt.binding... actually calls the function (because resetGame is printed first), but I expected that it does only assignment. The similar technique is demonstrated here, with ':' but not with assignment.
What is wrong and what is the right way to implement this?
I also tried a code like this:
function resetGameHandler(params)
{
iAd.closed.connect(function() {
scene.resetGame(params)
iAd.closed.disconnect(/*...???...*/)
})
iAd.show();
}
but with no success because I can't disconnect it, without having a reference to the implicitly created function (as far as I see it means that I need a regular function with a name).
I haven't done any QML for some months, so I might be wrong. But if my memory is any good, this might help you.
To stay close to your approach:
variant is deprecated. Using var instead is recommended.
You won't need Qt.binding(). You can directly assign a function to that property.
Call the function in the property.
InterstitialAd {
id: iAd
property var handlerFunc <-- Use var instead of variant
onClosed: {
if (handlerFunc && typeof handlerFunc === "function") {
handlerFunc() <-- Call it!
handlerFunc = null
}
}
}
iAd.handlerFunc = function() { // doSomething cool here }
Alternatively you might be able to produce the same results with Binding and Connection-Objects in a more declarative way, but the right choice depends on what shall be done onClosed

Meteor: store object in rendered() to be used in child helpers

I would like to store an object that I create during Template.myTemplate.rendered = function ( ) { ... } and use that object in Template.myChildTemplate.helpers(helpers). So far I'm resorting to using a global object, but that feels very hacky. Is there a nice Template-centric way of doing this?
You could use UI._templateInstance(); and ReactiveDict (to make your data reactive too) (added with meteor add reactive-dict
Template.myTemplate.created = function() {
this.templatedata = new ReactiveDict();
}
Template.myTemplate.rendered = function() {
this.templatedata.set("myname", "value";
};
Template.myTemplate.helpers({
myvalue: function() {
var tmpl = UI._templateInstance();
return tmpl.templatedata.get('myname');
}
});
This will allow you to use this template multiple times on the page, and still have a variable scope to each template, which global variables or non instance variables wouldn't allow.
A note of warning, the current iron router (0.7.1) breaks UI._templateInstance();, which is an open bug at the moment.
There's no such method yet, unfortunately.
The common pattern is to use reactive dict either as a file-wide variable, or in a namespace related to the template if you need the access in several files. The downside of this solution is that such variable is shared among all instances of the same template, so you have to work around this if you render this template in more than one place.
var data = new ReactiveDict();
Template.myTemplate.rendered = function() {
data.set('key', 'value');
};

Meteor: sharing variables between helpers

I am currently building a quizz app in Meteor and have three function within helpers
Template.quizPage.helpers({
//this helper finds the currentquiz and returns the currentquestion to the template
question: function(){
currentquiz = this.quiztitle;
currentQuestion = Session.get('currentQuestion') || 0;
return Quizzes.findOne({'quiztitle': currentquiz}).quizquestions[currentQuestion]
},
length: function (){
questionlength = $(Quizzes.findOne({'quiztitle': currentquiz}).quizquestions).length;
return questionlength;
},
answers: function(){
currentquiz = this.quiztitle;
currentQuestion = Session.get('currentQuestion') || 0;
return Quizzes.findOne({'quiztitle': currentquiz}).answers[1][currentQuestion]
}
});
As you can see some of this code is already duplicate (currentquiz = this.quiztitle). How can I share currentquiz between functions within a helper?
This is becoming a real problem as I need to define the variable currentquiz one time
currentQuestion = [0,0,0,0,0];
But current code resets the currentquestion any time I activate the helper in the template. I can;t define it above the function $(document.ready) wrap to set the variable or define it . This should be really easy right?
i know this is an old thread but I just came across the same problem. What you can do is define a reactive variable on the template level:
var abc;
Template.XY.rendered = function(){
abc = new ReactiveVar("abc");
},
Template.XY.helpers({
someFunction:function(){
return abc.get();
}
)}
I define a var abc; to bind the variable to the template instance (i guess this can also be done with this.abc = new ... )
To provide a variable available in the template helpers and events you just need to add it in the template instance.
In the onCreated function you can access the template instance with the keyword this.
Template.myTemplate.onCreated(function(){
this.mySharedVariable = new ReactiveVar("myValue");
});
In the helpers you can access to the templace instance with Template.instance().
Template.myTemplate.helpers({
myHelper1(){
const instance = Template.instance();
instance.mySharedVariable.get(); // Get the value "myValue"
// Do something
},
myHelper2(){
const instance = Template.instance();
instance.mySharedVariable.get(); // Get the value "myValue"
// Do something
}
});
In the events you can access to the template instance with the second parameter of the function.
Template.myTemplate.events({
'click .js-do-something' : function(event, instance){
instance.mySharedVariable.set("newValue"); // Set the value "newValue"
}
});
In the example above i'm using a ReactiveVar so if its value get changed the two helpers myHelper1 and myHelper2 will re-execute. But be free to use normal variable depending on your need.
PS: Because Session are global, you should not use Session if you only use this "shared" variable inside your template.

Meteor reactivity in functions, return session.get('variable'), runs everytime session.set('variable') is run?

Ok, let's say I have a client side function that returns a Session variable, eg:
Template.hello.random = function() {
return Session.get('variable');
};
Somewhere else let's say I have a button that does
Session.set('variable', random_number);
Everytime I hit that button, will my Template.hello.random function run? I find it hard to wrap my head around that..
All the Meteor "Magic" comes from Deps.Dependency and Deps.Computation (http://docs.meteor.com/#deps_dependency)
eg
var weather = "sunny";
var weatherDep = new Deps.Dependency;
var getWeather = function () {
weatherDep.depend()
return weather;
};
var setWeather = function (w) {
weather = w;
// (could add logic here to only call changed()
// if the new value is different from the old)
weatherDep.changed();
};
Session mirror's this pattern, but as a key/value store instead of just one value. (Actually Session is just an instance of the ReactiveDict class)
When you have a computation that calls getWeather() the .depend() call links it to the computation - and the .changed() call invalidates that computation.
eg, getting a computation via Deps.autorun()
computaton = Deps.autorun(function(){
var localWeather = getWeather();
console.log("local weather", localWeather);
});
computation.onInvalidate(function(){
console.log("a dependency of this computation changed");
});
console.log("setting weather");
setWeather("abc");
With this infrastructure - we find out that Template helpers are run in a computation - and when the dependencies of the computation are .changed(), it queues up the template to re-render.

Google maps Autocomplete: output only address without country and city

I use Places library to autocomplete address input. Search is limited to only one city, and I get output like this:
"Rossiya, Moskva, Leninskiy prospekt 28"
How to hide "Rossiya, Moskva"? ...
My query:
function() {
// Search bounds
var p1 = new google.maps.LatLng(54.686534, 35.463867);
var p2 = new google.maps.LatLng(56.926993, 39.506836);
self.options = {
bounds : new google.maps.LatLngBounds(p1, p2),
componentRestrictions: {country: 'ru'},
};
var elements = document.querySelectorAll('.address');
for ( var i = 0; i < elements.length; i++) {
var autocomplete = new google.maps.places.Autocomplete(elements[i],
self.options);
}
You can but you have to replace the value of the input field in two places.
Example:
var autocomplete = new google.maps.places.Autocomplete(input, placesOptions);
var input = document.getElementById('searchTextField');
inside the 'place_changed' event you need to do the following:
placeResult = autocomplete.getPlace();
//This will get only the address
input.value = placeResult.name;
This will change the value in the searchtextfield to the street address.
The second place is a bit tricky:
input.addEventListener('blur', function(){
// timeoutfunction allows to force the autocomplete field to only display the street name.
if(placeResult){ setTimeout(function(){ input.value = placeResult.name; }, 1); } });
The reason why we have to do this is because if you only add the event listener for blur, google places will populate the input field with the full address, so you have to 'wait' for google to update and then force your change by waiting some miliseconds.
Try it without the setTimeout function and you will see what I mean.
EDIT
You can't. I had it the other way around, that you were just looking for a city. There is no way to only print out the street name (I'm assuming that's a street name) from the address component.
OPPOSITE OF WHAT WAS ASKED
From the docs:
the (cities) type collection instructs the Place service to return results that match either locality or administrative_area3.
var input = document.getElementById('searchTextField');
var options = {
bounds: defaultBounds,
types: ['(cities)']
};
autocomplete = new google.maps.places.Autocomplete(input, options);
in result u have hash and from it u can get part what u want:
google.maps.event.addListener(autocomplete, 'place_changed', function() {
var place = autocomplete.getPlace();
now from "place" u can get it
place.geometry.location.lat()
and for address
place.address_components[0] or place.address_components[1] ...
depends on what u want to get
I had a very similar problem which indeed was solvable. This in an Angular 2 project but it should be applicable elsewhere as well. I filter my results for establishments, and wanted to show only the name and hide the address part of the result. This did the trick for me, a function executing once you select a suggestion:
getAddress(place: Object) {
this.zone.run(() => {
this.establishment = place['name'];
});
where zone is an NgZone component injected in the constructor and this.establishment is the variable tied to [(NgModel)] in the input field.
Inside place_changed set a timeout function:
var streetString = place.address_components[0] or place.address_components[1];
window.setTimeout(function() {
$('input').val(streetString);
}, 200);
This solution worked for me.

Resources