How to get all objects in the scene from a component? - aframe

What's the right way to get all objects in a scene, while in a component?
If I need to raycast everything, for example.
AFRAME.registerComponent('foo', {
init: function () {
var el = this.el;
// Get all objects in scene?
}
});

You can grab the scene, and then from there all the children. https://aframe.io/docs/0.3.0/core/entity.html#sceneel
AFRAME.registerComponent('foo', {
init: function () {
var allObjects = this.el.sceneEl.object3D.children;
}
});
this: component instance
el: <a-entity> element that component is attached to
sceneEl: <a-scene> element
object3D: three.js scene object
children: three.js all objects of scene

Related

Here Map stacks in Bootstraps Modal

I have several modal buttons which on click should show pre-saved Map Route in PolyLine.
Below code I used on php Ajax Modal Call. $jsline, $center_lat, $center_lng are php variable which are determined on modal click by ajax query.
<div id="map" style="width:100%;height:450px"></div>
<script>
$(document).on("shown.bs.modal", function () {
function addPolylineToMap(map) {
var lineString = new H.geo.LineString();
'.$jsline.'
map.addObject(new H.map.Polyline(
lineString, { style: { lineWidth: 4 }}
));
}
var platform = new H.service.Platform({
apikey: myhereapi
});
var defaultLayers = platform.createDefaultLayers();
var map = new H.Map(document.getElementById("map"),
defaultLayers.vector.normal.map,{
center: {lat:'.$center_lat.', lng:'.$center_lng.'},
zoom: 5.65,
pixelRatio: window.devicePixelRatio || 1
});
window.addEventListener("resize", () => map.getViewPort().resize());
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
var ui = H.ui.UI.createDefault(map, defaultLayers);
addPolylineToMap(map);
});
</script>
If I remove on("shown.bs.modal") modal window pops up with blank map (white background, no map). When I use on("shown.bs.modal") modal window pops up and work properly on first click. However, second, third, and further clicks will stack maps. I mean in second click there 2 maps appear. In third click 3 maps appear.
Why maps get stacked ? How to resolve this issue ? As far as I can see no one else faced with similar problem before.
I managed to find solution, so I am sharing it if anyone else faces with such issue.
I have added $("#map").empty(); just before new instance of map is loaded as below.
<div id="map" style="width:100%;height:450px"></div>
<script>
$(document).on("shown.bs.modal", function () {
function addPolylineToMap(map) {
var lineString = new H.geo.LineString();
'.$jsline.'
map.addObject(new H.map.Polyline(
lineString, { style: { lineWidth: 4 }}
));
}
$("#map").empty();
var platform = new H.service.Platform({
apikey: myhereapi
});
var defaultLayers = platform.createDefaultLayers();
var map = new H.Map(document.getElementById("map"),
defaultLayers.vector.normal.map,{
center: {lat:'.$center_lat.', lng:'.$center_lng.'},
zoom: 5.65,
pixelRatio: window.devicePixelRatio || 1
});
window.addEventListener("resize", () => map.getViewPort().resize());
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
var ui = H.ui.UI.createDefault(map, defaultLayers);
addPolylineToMap(map);
});
</script>

How do I update entities or objects in A-Frame?

I am using a component that I can code in HTML. For example with the text geometry component, I created text:
<a-entity text="text: 0"></a-entity>
How do I update the text component's text property?
Entity.setAttribute
Just like updating normal DOM elements, we can use setAttribute.
el.setAttribute('visible', false);
If a component has multiple properties, we have three arguments. Component name, property name, value:
el.setAttribute('material', 'color', 'black');
el.setAttribute('text', 'text', '1');
Where to put this code? Within a component would be good:
AFRAME.registerComponent('update-text-every-second', {
init: function () {
var el = this.el;
var i = 0;
setInterval(function () {
el.setAttribute('text', 'text', i.toString());
}, 1000);
}
});
And use:
<a-entity text="text: 0" update-text-every-second></a-entity>

Rendering a Google Map without react-google-map

Has anyone been able to render a google map using React and not using the react-google-map plugin? I'm trying something like this:
var MapTab = React.createClass({
render: function() {
return <div className="map-container">
<div id='map' ></div>
</div>
},
componentDidMount: function(){
console.log("Hello")
window.onload = function(){
(function initMap() {
var markers = [];
var geocoder = new google.maps.Geocoder();
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 12,
center: {lat: 37.7749300, lng: -122.4194200}
});
})();
}
}// end of cdm;
});
module.exports = MapTab;
Nothing I have tried has worked. I have tried capturing the map using refs as well but that did not render the map either. I have placed the google maps script in the header as well (with key) and have verified that the key is valid in a vanilla js project.
With componentDidMount you know you map container div has loaded, but you are not guaranteed that the external maps api has loaded yet. Google provides you the option to give a callback function (initMap() in their examples).
https://maps.googleapis.com/maps/api/js?key=&callback=initMap
Now you can proceed as follows, After your map component did mount you can:
window.initMap = this.initMap to make initMap from react available for Google maps to callback to.
load the google maps JS with initMap parameter.
In this.initMap in your component you can do your map stuff, because now you know your container ánd Google API have loaded.
const React = require('react')
const PropTypes = require('prop-types')
import Reflux from 'reflux'
const Radium = require('radium')
class Map extends Reflux.Component {
constructor(props) {
super(props)
this.loadJS = this.loadJS.bind(this)
this.initMap = this.initMap.bind(this)
}
componentDidMount() {
window.initMap = this.initMap;
if (typeof google === 'object' && typeof google.maps === 'object') {
this.initMap()
} else {
this.loadJS('https://maps.googleapis.com/maps/api/js?key=<API_KEY>&callback=initMap')
}
}
// https://github.com/filamentgroup/loadJS/blob/master/loadJS.js
loadJS(src) {
var ref = window.document.getElementsByTagName("script")[0];
var script = window.document.createElement("script");
script.src = src;
script.async = true;
ref.parentNode.insertBefore(script, ref);
}
initMap() {
var map = new google.maps.Map(this.refs.map, {
center: {lat: -34.397, lng: 150.644},
zoom: 8
})
}
render() {
return (<div ref='map'></div>)
}
}
module.exports = Radium(Map)
get rid of window.onload. By the time componentDidMount method is called window is already loaded so your initMap() function never fires.
It seems that you are not familiar with React Component Life Cycle yet.
https://facebook.github.io/react/docs/react-component.html#the-component-lifecycle
or this: http://busypeoples.github.io/post/react-component-lifecycle/ (this has the table of order in which react's methods are executed)
Actually, in the componentDidMount() ("DID-mount" means the element has already been there on the page, so you can start binding events to it)
React Component's idea is interesting, so we don't need to use javascript's "window.onload()" or jQuery's "$(document).ready()"
Therefore, your code can be revised as follows:
render: function() {
return <div className="map-container">
<div id='map' ></div>
</div>
},
componentDidMount: function(){
console.log("Hello")
var markers = [];
var geocoder = new google.maps.Geocoder();
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 12,
center: {lat: 37.7749300, lng: -122.4194200}
});
}// end of cdm;
PS: Besides, in order to make the map appear, you need to style the map-container and map correctly (which need a height in pixel, in your case of "0 px width, maybe you need to put the width, too - either in px or 100%) Feel free to style them, though!
You can render a google map easily using React Refs Which are an ideal solution when integrating with third party libraries. Like this:
class App extends React.Component {
constructor(props){
super(props)
this.state = {
// no state for now..
}
// Use createRef() to create a reference to the DOM node we want
this.myMapContainer = React.createRef()
}
componentDidMount() {
// Instead of using: document.getElementById, use the ref we created earlier to access the element
let map = new google.maps.Map(this.myMapContainer.current, {
center: { lat: -34.9973268, lng: -58.582614 },
scrollwheel: false,
zoom: 4
})
}
render() {
return (
<div className="container">
<div ref={this.myMapContainer} id="map"></div>
<div id="text"><p>Google Maps now requires the use of a valid API Key.
That's why you see the popup window "This page can't load Google Maps correctly."</p>
Go get one!
</div>
</div>
)
}
}
Working Example here
Note: Don't forget to place the <script> that makes the call to the Google Maps API. If you created your project using create-react-app, you can place the script inside of public/index.html

Google maps circle overlay . how to call a function on after drag complete?

Guys after a long R&D I was able to draw a circle and put markers which are inside that area of circle based on position and radius.
I'm calling a function which triggers whenever the radius or the position of the circle changes..
It is working fine( function triggers and it fetches the markers from the database.) but the function is called when the circle is being dragged(some 100 times). i want that function to called OnDragComplete.. i didn't find any such events Google API..
below is my code.. Any help would be greatly appreciated.
google.maps.event.addListener(distanceWidget, 'distance_changed', function() {
displayInfo(distanceWidget);
searchLocations();
});
google.maps.event.addListener(distanceWidget, 'position_changed', function() {
displayInfo(distanceWidget);
searchLocations();
});
You could add a "dragging" property to the widget on the mouse events and check it in your other functions:
google.maps.event.addListener(distanceWidget, 'mousedown', function() {
distanceWidget.dragging = true;
});
google.maps.event.addListener(distanceWidget, 'mouseup', function() {
distanceWidget.dragging = false;
});
google.maps.event.addListener(distanceWidget, 'position_changed', function() {
if (distanceWidget.dragging === false) {
displayInfo(distanceWidget);
searchLocations();
}
});
I too faced this issue. we can use drag and dragend event listener inside
DistanceWidget function and use marker instance to listen
function DistanceWidget(map) {
this.set('map', map);
this.set('position', map.getCenter());
var marker = new google.maps.Marker({
lat: $('input[name=lat]').val(),
lng: $('input[name=lng]').val(),
draggable: true,
crossOnDrag: false,
cursor: 'crosshair',
title: 'Drag to change circle radius!',
icon: 'assets/front/images/pin.png',
});
google.maps.event.addListener(marker, 'drag', function(e) {
console.log('starting');
});
google.maps.event.addListener(marker, 'dragend', function(e) {
// Trigger once u drop the widget marker
console.log('end');
});
}

Google Maps APIV3 listener set_at not firing until second time

I have the following code, which should trigger an alert when a Polygon shape is changed. This alert only appears after the shape has been changed twice. Meaning, I have to resize the shape two times before the event is triggered.
Any idea as to what may be causing this behavior?
function drawListener(drawingManager) {
var coord_listener = google.maps.event.addListener(drawingManager, 'polygoncomplete', function (polygon) {
var coordinates = (polygon.getPath().getArray()); //get
var bounds = new google.maps.LatLngBounds();
var people = [];
google.maps.event.addListener(polygon.getPath(), 'set_at', function () { //check to see if the item has been changed //THIS ONLY GETS CALLED AFTER POLYGON HAS BEEN CHANGED TWICE
alert('changed');
});
});
I found my answer: I must use 'insert_at' in addition to 'set_at'
google.maps.event.addListener(polygon.getPath(), 'set_at', function () {
alert('changed');
});
google.maps.event.addListener(polygon.getPath(), 'insert_at', function () {
alert('also changed');
});
Thanks.

Resources