I'm trying to write an aframe component to get a value from the position attribute. But, curiously, when I use the console.log, it first shows {x:0, y:0, z:0}, but when I click, it shows other values (the values that I need {x:5, y:0, z:0}, but I can't get through my code).
Code:
AFRAME.registerComponent('mycomponent', {
schema: {
destination: {type: 'string', default:''}
},
update: function () {
if(this.data.destination){
let destinationEl = document.querySelector(this.data.destination);
let positionEl = destinationEl.getAttribute('position');
console.log(positionEl);
}
}
});
Console
Access the code running here.
This is expected. You're trying to access data from an entity that has not yet initialized. Entities initialize children first and top to bottom
You can put the entity first in the DOM:
<a-box id="obj2"></a-box>
<a-box mycomponent="destination:#obj2;"></a-box>
Make it a child:
<a-box mycomponent="destination:#obj2;">
<a-box id="obj2"></a-box>
</a-box>
Or wait for the entity to load, making code independent of the DOM structure.
var self = this;
if (destinationEl.hasLoaded) {
this.printPosition();
} else {
destinationEl.addEventListener('loaded', function () {
self.printPosition();
});
}
Corrected glitch
Also make sure you're using latest A-Frame. 1.3.0 at the moment of writing this.
Related
I am trying to write an inventory system for a game using the AFrame library. I have a custom component that is set up to set the item i'm picking up to invisible and turn the in hand item visible. However when ever it runs it won't work.
Currently, i have a click eventlistener set up check when clicked. When clicked it is set to set the target item invisible (el) and the object in hand visible (handObj). It appears as tho the click function isn't evening running as I have a console.log set up to just check if the function ran or not.
Edit: I created a glitch with an example project
https://glitch.com/~tundra-ironclad
var hands = [null, null];
AFRAME.registerComponent('pickUp', {
schema: {
handObj: {type: 'selector', default: ''},
id: {type: 'string', default: ''}
},
init: function() {
var el = this.el;
var data = this.data;
el.addEventListener('click', function() {
//pickup="target= #right
console.log("hello");
if(hands[0] == null) hands[0] = data.id;
else if (hands[1] == null) hands[1] = data.id;
else break;
el.setAttribute('visible', 'false');
data.handObj.setAttribute('visible', 'true');
});
}
});
<a-box id="left1"
color="#AA0000" class="clickable"
position="8.000 0.200 7" depth = ".25" height = ".25" width = ".25"
event-set__enter="_event: mouseenter; material.color: #FF0000"
event-set__leave="_event: mouseleave; material.color: #AA0000"
pickUp="handObj: #left2; id: left"
>
I don't understand why the click function isn't working at all since i have copied the formatting from tutorials and those components work fine.
Your example freezes for me, but try pick-up instead of pickUp. HTML attributes are case-insensitive. We should add a warning for that.
I want to add a 3rd Inspector which will open only for an element(not a link) of specific type, for example only for basic.Rect in Rappid.
So far, there are 2 Inspectors.For elements and for links.
Is there any way it can be done?
The following code is a part of the KitchenSkink version of Rappid.
Here is function createInspector:
createInspector: function(cellView) {
var cell = cellView.model || cellView;
// No need to re-render inspector if the cellView didn't change.
if (!this.inspector || this.inspector.options.cell !== cell) {
// Is there an inspector that has not been removed yet.
// Note that an inspector can be also removed when the underlying cell is removed.
if (this.inspector && this.inspector.el.parentNode) {
this.inspectorClosedGroups[this.inspector.options.cell.id] = _.map(app.inspector.$('.group.closed'), function(g) {
return $(g).attr('data-name');
});
// Clean up the old inspector if there was one.
this.inspector.updateCell();
this.inspector.remove();
}
var inspectorDefs = InspectorDefs[cell.get('type')];
this.inspector = new joint.ui.Inspector({
inputs: inspectorDefs ? inspectorDefs.inputs : CommonInspectorInputs,
groups: inspectorDefs ? inspectorDefs.groups : CommonInspectorGroups,
cell: cell
});
this.initializeInspectorTooltips();
this.inspector.render();
$('.inspector-container').html(this.inspector.el);
if (this.inspectorClosedGroups[cell.id]) {
_.each(this.inspectorClosedGroups[cell.id], this.inspector.closeGroup, this.inspector);
} else {
this.inspector.$('.group:not(:first-child)').addClass('closed');
}
}
}
If you use joint.ui.Inspector.create('#path', inspectorProperties) any previous instance of the Inspector in a specific DOM element is removed and new one is created and rendered into the DOM automatically (it avoids creating a new instance of joint.ui.Inspector(), rendering it, adding the rendered result manually and removing the previous instance).
It also keeps track on open/closed groups and restore them based on the last used state.
Besides this, you may always have several different inspectorProperties objects previously defined when you are about to create() the inspector. So following the code you pasted, you could perform the tests you need first and then create the appropriate inspector:
if(cell instanceof joint.basic.Rect){
var customInputs = _.clone(CommonInspectorInputs);
// extend more inputs into `customInputs` from a variable previously defined
// OR modify the default rectangle's inspector directly, example:
customInputs.attrs.text = {
type: 'textarea',
label: 'Multiline text',
text: 'Type\nhere!',
group: joint.util.getByPath(CommonInspectorInputs.attrs, 'text/group', '/');
};
joint.ui.Inspector.create('.extra-inspector-container', {
cell: cell
inputs: customInputs,
groups: CommonInspectorGroups,
});
} // if only ONE inspector needs to be loaded add an ELSE block here
// and use '.inspector-container' in the `create()` above
// If `InspectorDefs` is a global variable with all the cells inspectors properties
// create and load the default inspector
joint.ui.Inspector.create('.inspector-container', _.extend({cell: cell},
InspectorDefs[cell.get('type')])
);
I have some trouble with adding event listener to element after DOM updating.
I have some page, that sort two lists and save the stage.
I can move elements between this lists by d&d and by clicking special button. And it work fine for me.
https://jsfiddle.net/bmj32ma0/2/
But, I have to save stage of this lists, and after reloading I have to extract stage, so I write code below.
function saveFriendsLists(e) {
if(e.target.classList.contains("b--drugofilter--save-button")){
var vkFriends = document.querySelector('.b--friends-from-vk .js--friends-container').innerHTML;
var choosenFriends = document.querySelector('.b--friends-choosen .js--friends-container').innerHTML;
localStorage.setItem('vkFriends', vkFriends);
localStorage.setItem('choosenFriends', choosenFriends);
}
}
function loadFriensListFromStorage() {
if(localStorage&&localStorage.choosenFriends&&localStorage.vkFriends){
document.querySelector('.b--friends-from-vk .js--friends-container').innerHTML = localStorage.vkFriends;
document.querySelector('.b--friends-choosen .js--friends-container').innerHTML = localStorage.choosenFriends;
}
}
document.addEventListener("DOMContentLoaded", loadFriensListFromStorage);
But after adding this, the preview functionality like D&D doesn't work. And I can't provide you valid jsfidle because, as I can understand, localStoradge reason or something.
When I tried to move my addEventListener to loadFriensListFromStorage function, like this:
function loadFriensListFromStorage() {
if(localStorage&&localStorage.choosenFriends&&localStorage.vkFriends){
document.querySelector('.b--friends-from-vk .js--friends-container').innerHTML = localStorage.vkFriends;
document.querySelector('.b--friends-choosen .js--friends-container').innerHTML = localStorage.choosenFriends;
}
[].forEach.call(friends, function(friend) {
friend.addEventListener('dragstart', handleDragStart, false);
});
}
But that doesn't have any effect.
How can I fix this issue? Thx.
I have the following code, and what I would like to do is update the chart with values coming from an AJAX call on a button push (also on page start). The issue I am having is that the chart will not update or re-render. I have hard coded the values coming in from the server just as a test because I know I can get the values.
require(["dojox/charting/Chart",
"dojox/charting/axis2d/Default",
"dojox/charting/plot2d/Lines",
"dojo/ready",
"dojox/charting/themes/Claro",
"dojo/request",
"dojo/dom",
"dojo/on"],
function(Chart, Default, Lines, ready, theme, request, dom, on){
ready(function(){
var policeResChart = new Chart("simplechart");
policeResChart.addPlot("default", {type: Lines, enableCache:true});
policeResChart.setTheme(theme);
policeResChart.theme.plotarea.fill = "";
policeResChart.fill = "";//the broder around the chart
policeResChart.addSeries("data", policeResponses, {stroke:{color:"orange", width:3}});
policeResChart.render();
var myButton = dom.byId("btn");
on (myButton, "click", function(evt){
request.post("test.jsp", {
data:{
color: "blue"
}
}).then(
function(response){
var newData = [
{ y: 1 },
{ y: 1 },
{ y: 1 },
{ y: 31 },
{ y: 1 }];
policeResChart.updateSeries("data", newData);
policeResChart.render();
}//end response
);
});//end onclick
});//ends ready function
});//ends require
whats also really strange is that only 1 render() can be called. so for example if I take the first (the on ready) render out and use the onclick render it will work. Im also noticing that ANYTHING i put after the second render in the onclick does not work. so alert("test") after the second render in the button push does nothing. Im not so sure why.
Ok so, for some strange reason when I use policeResChart.fullRender(); in the button push this works. Can someone explain why? I dont fully understand why the render() did not work.
Anyway, glad its "fixed".
Im using OpenLayers and i need to be able to tell difference between when map has been moved by my own scrip or by user. Yeah im aware that i can use moveend. But it also triggers when the same script is moving or repositioning map based on incoming data from ajax calls. So moveend or other map events wont work.
I did some googling and found OpenLayers.Hander.Drag. But all that i managed with it was to stop users from dragging map.
My script:
this.dragger = new OpenLayers.Handler.Drag('',{
'dragStart': function(evt){
this.userdragged = true;
console.log('drag');
}},{
'map':this.mymap
});
this.dragger.activate();
As you can see, i tried to set userdragged variable to true to use this same variable in moveend event later. Unfortunately all this did was to stop my map from beeing draggable.
Can someone assist me please?
Alan
Got it!
What got it working was :
dragcontrol = new OpenLayers.Control.DragPan({'map':this.mymap, 'panMapDone':function(evt){
this.userdragged = true;
console.log('drag');
}});
dragcontrol.draw();
this.mymap.addControl(dragcontrol);
dragcontrol.activate();
Booyaka!
Edit:
Actually this.userdragged wont work in there... the scope of this is different there. you would need to do something like var that = this; before that object initialization and use that.userdragged = true....
Edit2:
I later found, that this panMapDone function overwrites DragPans own method which has same name. With just my previous example, you can end up with map that results in vector features going out of sync with map, when user drags map. To stop that from happening, you should copy the original functionality into that function too... to make it look something like that:
dragcontrol = new OpenLayers.Control.DragPan({'map':this.mymap, 'panMapDone':function(xy){
if(this.panned) {
var res = null;
if (this.kinetic) {
res = this.kinetic.end(xy);
}
this.map.pan(
this.handler.last.x - xy.x,
this.handler.last.y - xy.y,
{dragging: !!res, animate: false}
);
if (res) {
var self = this;
this.kinetic.move(res, function(x, y, end) {
self.map.pan(x, y, {dragging: !end, animate: false});
});
}
this.panned = false;
}
that.userdragged = true;
// do whatever you want here
}});
dragcontrol.draw();
this.mymap.addControl(dragcontrol);
dragcontrol.activate();
Alan
Looking at the documentation on Drag handlers, it states that it's supposed to be used with a Control object. Are you using it that way? Maybe the code snippet doesn't show it?
"If a handler is being used without a control, the handlers setMap method must be overridden to deal properly with the map."
I haven't tried it, but it seems as you should go for something like this:
var myControl = new OpenLayers.Control();
var dragger = new OpenLayers.Handler.Drag{
control: myControl,
callbacks: { 'done': function() { // do something }},
options: {}
}
myMap.addControl(myControl);
myControl.activate();
Just posting an example here of executing an arbitrary function when the user drag the map, without interfering with the normal click-drag used to pan the map, because this page was the most frequent result during my search to find how to do that.
var CustomDragControl = OpenLayers.Class(OpenLayers.Control, {
defaultHandlerOptions: {
'stopDown': false
/* important, otherwise it prevent the click-drag event from
triggering the normal click-drag behavior on the map to pan it */
},
initialize: function(options) {
this.handlerOptions = OpenLayers.Util.extend(
{}, this.defaultHandlerOptions
);
OpenLayers.Control.prototype.initialize.apply(
this, arguments
);
this.handler = new OpenLayers.Handler.Drag(
this, {
'down': this.onDown //could be also 'move', 'up' or 'out'
}, this.handlerOptions
);
},
onDown: function(evt) {
// do something when the user clic on the map (so on drag start)
console.log('user clicked down on the map');
}
});
then add the control to you map's controls list when creating the map instance, or with a map.addControl(), with
new CustomDragControl ({'autoActivate': true})
i have use that in OpenLayers 6:
map.on('pointerdrag', function (event) {
is_map_center = false;
})
hf gl!