Create a simplified reflective custom shader in A-FRAME - webgl

So I have inevitably gone down the path of custom shaders in A-FRAME. When really researching this, and given I could be considered a newbie with this tech, I have bumped into all sorts of complicated and not-so clear solutions.
Examples like: https://rawgit.com/mrdoob/three.js/master/examples/webgl_materials_cubemap_balls_reflection.html , create even more questions than answers.
However, when I visited this example: https://stemkoski.github.io/Three.js/Reflection.html , I did notice a different approach which seemed a bit more simplified.
This lead me to research more about CubeCameras and how threejs can use it as a shader in order to simulate reflectivity.
//Create cube camera
var cubeCamera = new THREE.CubeCamera( 1, 100000, 128 );
scene.add( cubeCamera );
//Create car
var chromeMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff, envMap: cubeCamera.renderTarget } );
var car = new Mesh( carGeometry, chromeMaterial );
scene.add( car );
//Update the render target cube
car.setVisible( false );
cubeCamera.position.copy( car.position );
cubeCamera.updateCubeMap( renderer, scene );
//Render the scene
car.setVisible( true );
renderer.render( scene, camera );
Now the question is, how can I translate that into A-FRAME? I tried the following:
AFRAME.registerComponent('chromeThing', {
schema: {
???
},
init: function () {
var el = this.el; // Entity.
var cubeCam = document.querySelector('#cubeCam'); //There is an <a-entity camera id="cubeCam">
var mirrorCubeMaterial = new THREE.MeshBasicMaterial( { envMap: cubeCam.renderTarget } );
mirrorCube = new THREE.Mesh( el, mirrorCubeMaterial );
el.setObject3D('mesh', mirrorCube);
}
});
As you might notice, I'm not sure what the scheme of this would be.
Also, should this be a shader or a component? (how could I use this best)
EDIT:
After #ngokevin reply, I've come up with this code which is still not giving me the desired results.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Chrome box</title>
<meta name="description" content="Physically-Based Materials - A-Frame">
<meta name="apple-mobile-web-app-capable" content="yes">
<script src="https://aframe.io/releases/0.3.0/aframe.min.js"></script>
<script src="https://rawgit.com/ngokevin/kframe/master/dist/kframe.min.js"></script>
<script src="https://rawgit.com/ngokevin/kframe/master/components/reverse-look-controls/index.js"></script>
</head>
<body>
<a-scene>
<a-assets>
<img id="equi1" crossorigin src="https://rawgit.com/aframevr/aframe/master/examples/boilerplate/panorama/puydesancy.jpg" preload="auto">
</a-assets>
<!-- MAIN CAMERA -->
<a-entity id="mainCam" camera="userHeight: 1.6" reverse-look-controls wasd-controls></a-entity>
<!-- CMAERA FOR TEXTURE (?) -->
<a-entity id="cubecamera" camera near="0.1" far="5000" fov="512"></a-entity>
<!-- SKY DOME TO REFLECT ON BOX -->
<a-sky src="#equi1"></sky>
<!-- MAKE THIS BOX CHROME -->
<a-box id="theCube" camera-envmap-material="#cubecamera" color="tomato" depth="2" height="4" width="5" position="0 0 -3" materials=""></a-box>
<!-- THIS BOX IS MOVING AND SHOULD REFLECT ON THE CHROME BOX -->
<a-box id="reflector" color="red" position="0 0 20">
<a-animation attribute="rotation" dur="10000" fill="forwards" to="0 360 0" repeat="indefinite"></a-animation>
</a-box>
</a-scene>
</body>
<script>
AFRAME.registerComponent('camera-envmap-material', {
dependencies: ['material'],
// Selector type so we do `<a-entity camera-envmap-material="#cubecamera">`.
schema: {
type: 'selector'
},
init: function () {
var cameraEl = this.data;
var material = this.el.getObject3D('mesh').material;
// Set envmap on existing material.
// This assumes you have a CubeCamera component that does `setObject3D('cube-camera', new THREE.CubeCamera)`.
material.envMap = cameraEl.getObject3D('camera').renderTarget;
material.needsUpdate = true;
}
});
</script>
</html>
UPDATE #2
After recommendations from #ngokevin here is where I'm at, however, I can't get component to update. The problem seems to be the passing of variables to the tick:function(), I keep getting Uncaught TypeError: Cannot read property 'renderTarget' of undefined
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Chrome box</title>
<meta name="description" content="Physically-Based Materials - A-Frame">
<meta name="apple-mobile-web-app-capable" content="yes">
<script src="https://aframe.io/releases/0.3.0/aframe.min.js"></script>
<script src="https://rawgit.com/ngokevin/kframe/master/dist/kframe.min.js"></script>
<script src="https://rawgit.com/ngokevin/kframe/master/components/reverse-look-controls/index.js"></script>
</head>
<body>
<a-scene>
<a-assets>
<img id="equi1" crossorigin src="https://rawgit.com/aframevr/aframe/master/examples/boilerplate/panorama/puydesancy.jpg" preload="auto">
</a-assets>
<!-- MAIN CAMERA -->
<a-entity id="mainCam" camera="userHeight: 1.6" reverse-look-controls wasd-controls></a-entity>
<!-- SKY DOME TO REFLECT ON BOX -->
<a-sky src="#equi1"></sky>
<!-- MAKE THIS BOX CHROME -->
<a-box id="theCube" camera-envmap-material depth="2" height="4" width="5" position="0 0 -3" metalness="1">
</a-box>
<!-- MAKE THIS ROTATE AND REFLECT ON CHROME -->
<a-box id="reflector" color="red" position="0 0 10">
<a-animation attribute="rotation" dur="10000" fill="forwards" to="0 360 0" repeat="indefinite"></a-animation>
</a-box>
</a-scene>
</body>
<script>
AFRAME.registerComponent('camera-envmap-material', {
dependencies: ['material'],
init: function(data) {
this.cameraEl = this.data;
this.material = this.el.getObject3D('mesh').material;
this.theElement = this.el;
this.theScene = this.theElement.sceneEl;
if (!this.theScene.renderStarted) {
this.theScene.addEventListener('renderstart', this.init.bind(this));
return;
}
this.cubeCamera = new THREE.CubeCamera( 0.1, 5000, 512);
this.cubeCamera.position.set(5, 2, 4);
this.cubeCamera.updateCubeMap( this.theScene.renderer, this.theScene.object3D );
this.theElement.setObject3D('cube-camera', this.cubeCamera);
this.material.envMap = this.cubeCamera.renderTarget;
this.material.needsUpdate = true;
},
tick:function(){
this.material.envMap = this.cubeCamera.renderTarget;
this.material.needsUpdate = true;
}
});
</script>
</html>

A component would be okay to set properties on an existing material. A shader is more for registering shaders/materials, but A-Frame already has basic/standard materials. And you want the selector property in the schema.:
AFRAME.registerComponent('camera-envmap-material', {
dependencies: ['material'],
// Selector type so we do `<a-entity camera-envmap-material="#cubecamera">`.
schema: {
type: 'selector'
},
init: function () {
var cameraEl = this.data;
var material = this.el.getObject3D('mesh').material;
// Set envmap on existing material.
// This assumes you have a CubeCamera component that does `setObject3D('cube-camera', new THREE.CubeCamera)`.
material.envMap = cameraEl.getObject3D('camera').renderTarget;
material.needsUpdate = true;
}
});
Update
AFRAME.registerComponent('camera-envmap-material', {
dependencies: ['material'],
init: function () {
var cameraEl = this.data;
var material = this.el.getObject3D('mesh').material;
if (!this.el.sceneEl.renderStarted) {
this.el.sceneEl.addEventListener('renderstart', this.init.bind(this));
return;
}
var cubeCamera = new THREE.CubeCamera( 1, 100000, 128 );
cubeCamera.position.set(5, 2, 4);
cubeCamera.updateCubeMap( this.el.sceneEl.renderer, this.el.sceneEl.object3D );
this.el.setObject3D('cube-camera', cubeCamera);
material.envMap = cubeCamera.renderTarget;
material.needsUpdate = true;
}
});

Related

Can´t reproduce bootstrap documentation using js example. Why?

I´m trying to reproduce bootstrap documentation example:
https://getbootstrap.com/docs/5.2/components/list-group/#javascript-behavior
With 2 diferences: using js to create the html tags and using a nested list instead of single list.
The 'activate' highlight doesn´t work and the right side content doesn´t change. Need help on why and how to make it work.
I´m also trying to create a collapse effect for the nested list when the parent item is clicked.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- CSS only -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
<!-- <link rel="stylesheet" href="style.css"> -->
</head>
<body>
<div id="tree"></div>
<!-- JavaScript Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
<script>
function clearChildren(node){
while(node.children.length > 0)
node.removeChild(node.lastElementChild)
}
let idCounter = 0
function createNode(name,meta={}){
return {
name,
id: idCounter++,
children:new Array(),
meta
}
}
function makeTreeTable(parentElement, rootNode){
clearChildren(parentElement)
parentElement.setAttribute('class', 'row')
//Make Tree Div
const divTree = document.createElement('div')
divTree.setAttribute('class','col-8')
divTree.setAttribute('id', 'div-tree')
parentElement.appendChild(divTree)
//Make Meta Div
const divMeta = document.createElement('div')
divMeta.setAttribute('class','col-4')
divMeta.setAttribute('id', 'div-node')
parentElement.appendChild(divMeta)
const metaDisplay = document.createElement('div')
metaDisplay.setAttribute('class','tab-content')
metaDisplay.setAttribute('id','nav-tabContent')
divMeta.appendChild(metaDisplay)
maketree(divTree, rootNode, metaDisplay)
}
let activeMeta = 'tab-pane fade show active'
function createMetaList(treeNode){
const metaList = document.createElement('div')
console.log(treeNode.id)
metaList.setAttribute('id', `${treeNode.id}-meta`)
metaList.setAttribute('class',activeMeta)
activeMeta = 'tab-pane fade'
metaList.setAttribute('role','tabpanel')
metaList.setAttribute('aria-labelledby',treeNode.id)
for (const [key, value] of Object.entries(treeNode.meta)) {
const metaItem = document.createElement('div')
metaItem.innerHTML = `${key} : ${value}`
metaList.appendChild(metaItem)
}
return metaList
}
let activeNode = 'list-group-item list-group-item-action active'
function maketree(parentElement, nodeTgt, metaDisplay) {
//Make ul node
const ul = document.createElement("div");
ul.setAttribute('class', 'list-group')
ul.setAttribute('id','nodeTgt.name')
ul.setAttribute('role','tablist')
//Make all li´s nodes
for(const node of nodeTgt.children){
const li = document.createElement("a");
li.innerHTML = node.name;
li.setAttribute("id", node.id);
li.setAttribute("class", activeNode)
activeNode = 'list-group-item list-group-item-action'
li.setAttribute('data-bs-toogle','list')
li.setAttribute('role','tab')
li.setAttribute('href',`#${node.id}-meta`)
li.setAttribute('aria-controls',`${node.id}-meta`)
li.addEventListener('click',(e)=>{
e.stopPropagation()
console.log('clicked ', node.name)
})
ul.appendChild(li);
metaDisplay.appendChild(createMetaList(node))
//Make recursive items
if(nodeTgt.children.length > 0)
maketree(li,node, metaDisplay)
}
parentElement.appendChild(ul)
}
function makeMeta(i){
return{
meta1:`this is ${i}`,
meta2:`this is ${++i}`,
meta3:`this is ${++i}`,
}
}
const root = createNode('root', makeMeta(0))
root.children.push(createNode('node1', makeMeta(1)))
root.children.push(createNode('node2', makeMeta(2)))
root.children.push(createNode('node3', makeMeta(3)))
const node1 = root.children[0]
const node2 = root.children[1]
const node3 = root.children[2]
node1.children.push(createNode('node11', makeMeta(11)))
node1.children.push(createNode('node12', makeMeta(12)))
node2.children.push(createNode('node21', makeMeta(21)))
node2.children.push(createNode('node22', makeMeta(22)))
node3.children.push(createNode('node31', makeMeta(31)))
node3.children.push(createNode('node32', makeMeta(32)))
const node11 = node1.children[0]
const node12 = node1.children[1]
const node31 = node3.children[0]
const node32 = node3.children[1]
node11.children.push(createNode('node111', makeMeta(111)))
node11.children.push(createNode('node112', makeMeta(112)))
node12.children.push(createNode('node121', makeMeta(121)))
node12.children.push(createNode('node122', makeMeta(122)))
node31.children.push(createNode('node311', makeMeta(111)))
node31.children.push(createNode('node312', makeMeta(112)))
node32.children.push(createNode('node321', makeMeta(121)))
node32.children.push(createNode('node322', makeMeta(122)))
makeTreeTable(document.querySelector('#tree'), root)
</script>
</body>
</html>
Thanks
You need to initialize the created elements individually.
https://getbootstrap.com/docs/5.2/components/list-group/#via-javascript
Put the following at the end of your script:
const triggerTabList = document.querySelectorAll('#tree a')
triggerTabList.forEach(triggerEl => {
const tabTrigger = new bootstrap.Tab(triggerEl)
triggerEl.addEventListener('click', event => {
event.preventDefault()
tabTrigger.show()
})
})
Then you will see an error that says "#1-meta" is not a valid selector. I think you need to refactor your code to have all of the ids start with a letter [a-z]. So you want to use "meta-1" format instead.

ArcGIS 3.x to 4.x Migration

I was using ArcGIS JS API 3.10 and have a Github
repository to display GeoJSON data on a map but now I have to upgrade to
4.9 version I read 3.x to 4.x migration document published by ESRI and apply he changes like link location etc. but it’s not working anymore.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=7,IE=9">
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
<title>ArcGIS GeoJSON Layer</title>
<!-- ArcGIS API for JavaScript CSS-->
<link rel="stylesheet" href="https://js.arcgis.com/4.9/esri/css/main.css">
#*<link rel="stylesheet" href="//js.arcgis.com/3.9/js/esri/css/esri.css">*#
<!-- Web Framework CSS - Bootstrap (getbootstrap.com) and Bootstrap-map-js (github.com/esri/bootstrap-map-js) -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<link rel="stylesheet" href="//esri.github.io/bootstrap-map-js/src/css/bootstrapmap.css">
<style>
html, body, #mapDiv {
height: 500px;
width: 100%;
}
</style>
<script src="https://js.arcgis.com/4.9/"></script>
<!-- ArcGIS API for JavaScript library references -->
#*<script src="//js.arcgis.com/3.10"></script>*#
<!-- Terraformer reference -->
<script src="/vendor/terraformer/terraformer.min.js"></script>
<script src="/vendor/terraformer-arcgis-parser/terraformer-arcgis-parser.min.js"></script>
<script>
require(["esri/Map",
"/Scripts/Refine.js",
"dojo/on",
"dojo/dom",
"dojo/domReady!"],
function (Map, GeoJsonLayer, on, dom) {
// Create map
var map = new Map("mapDiv", {
basemap: "gray",
center: [-122.5, 45.5],
zoom: 5
});
map.on("load", function () {
addGeoJsonLayer("http://113.197.55.251/api/punjab");
});
// Add the layer
function addGeoJsonLayer(url) {
// Create the layer
var geoJsonLayer = new GeoJsonLayer({
url: url
});
// Zoom to layer
geoJsonLayer.on("update-end", function (e) {
map.setExtent(e.target.extent.expand(1.2));
});
// Add to map
map.add(geoJsonLayer);
}
});
</script>
</head>
<body>
<div id="mapDiv"></div>
</body>
</html>
In ArcGIS 4.9 you have to use a MapView like below:
For the conversion between GeoJson and EsriJson, I suggest you the arcgis-to-geojson-utils library
Import the library in your html:
<script src="https://unpkg.com/#esri/arcgis-to-geojson-utils"></script>
javascript:
require([
"esri/Map",
"esri/views/MapView",
"esri/Graphic",
"esri/layers/FeatureLayer",
"esri/layers/support/Field",
"dojo/on",
"dojo/dom",
"dojo/domReady!"],
function (Map, MapView, Graphic, FeatureLayer, Field, on, dom) {
// Create mapView and map
var mapView = new MapView({
container: mapDiv,
map: new Map({
basemap: "gray"
}),
center: [-122.5, 45.5],
zoom: 5
}).when(function(mapView) {
makeRequest("http://113.197.55.251/api/punjab", function(response) {
createLayerFromGeoJSON(response, mapView);
});
});
// Request the geojson data using XmlHttpRequest
function makeRequest(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.setRequestHeader("Content-type", "application/json; charset=utf-8");
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
callback(JSON.parse(xhr.response));
}
};
xhr.onerror = function(error) {
throw error;
}
xhr.send();
};
// Create the layer from the geojson data
function createLayerFromGeoJSON(geojson, mapView) {
// Convert geojson to esriJson using arcgis-to-geojson-utils library
var esriJson = ArcgisToGeojsonUtils.geojsonToArcGIS(geojson);
// Create an array of graphics from the esriJson
var graphics = esriJson.map(function(feature, i) {
return new Graphic({
geometry: {
type: "polygon",
rings: feature.geometry.rings
},
attributes: {
ObjectID: i,
Name: feature.attributes.Name
}
});
});
// Create a FeatureLayer from the graphics
var layer = new FeatureLayer({
title: "My feature layer",
source: graphics, // autocast as an array of esri/Graphic
geometryType: "polygon",
fields: [
new Field({
name: "ObjectID",
alias: "ObjectID",
type: "oid"
}),
new Field({
name: "Name",
alias: "Name",
type: "string"
}),
],
objectIdField: "ObjectID", // This must be defined when creating a layer from Graphics
renderer: {
type: "simple", // autocasts as new SimpleRenderer()
symbol: {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: {r: 200, g: 200, b: 200, a: 0.5},
outline: { // autocasts as new SimpleLineSymbol()
width: 0.5,
color: "black"
}
}
}
});
mapView.map.add(layer);
return layer;
};
});
In ArcGis Js 4.x version you have to also declare a view constructor (MapView for 2D or SceneView for 3D). Here is a guide on how to set up 2D view: https://developers.arcgis.com/javascript/latest/sample-code/intro-mapview/index.html
Another way to add Json file is to convert your existing your json file to an esri json format, like in this guide: https://developers.arcgis.com/javascript/latest/sample-code/sandbox/index.html?sample=layers-featurelayer-collection.
Since I don't know your json file attributes I can't really provide a working sample, but its really simple.

Cordova Media Plugin setVolume() not working

Here is my play function: As you can see I setVolume() in multiple locations to 0. This has absolutely no effect. I've tried to also set to 0.8, 0.2, doesn't matter it wont work. I've also tried non string value, which doesn't really matter as the value is converted to a float val inside of the Obj-C module. I also NSLogged to ensure the value was being passed correctly and it is.
Testing with iPad iOS 9.2 | Cordova 6.2 | Cordova Media Plugin 2.3.1.
play: function(src, seekTime)
{
App.Log.info('Playing audio source', src);
seekTime = seekTime ? seekTime : 0;
var obj = {
source: src,
startTime: new Date().getTime(),
seekTime: seekTime,
duration: 0,
preloadedNext: false,
audioSource: false
};
obj.audioSource = new Media(src, function(event){
$this.player().onAudioEnd(event, obj);
}, function(){
//on error
}, function(status)
{
obj.audioSource.setVolume("0.0");
if(status == 2){
obj.audioSource.setVolume("0.0");
obj.audioSource.seekTo(obj.seekTime * 1000);
obj.timer = setInterval(function(){
obj.seekTime++;
obj.duration = obj.audioSource._duration;
if(obj.duration < 0){
return;
}
if(obj.seekTime >= (obj.duration - $this.default.fadeTime))
{
if(obj.preloadedNext){
return;
}
obj.preloadedNext = true;
$this.player().preloadNext(obj);
}
}, 1000);
}
});
obj.audioSource.setVolume("0.0");
obj.audioSource.play();
obj.audioSource.setVolume("0.0");
obj.audioSource.seekTo(obj.seekTime * 1000);
console.log('Audio Source', JSON.stringify(obj));
$this.playing.push(obj);
}
Any help or direction would be awesome.
The following sample code works fine and it is tested in Android & iOS devices:
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="format-detection" content="telephone=no" />
<!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
<link rel="stylesheet" type="text/css" href="css/index.css" />
<meta name="msapplication-tap-highlight" content="no" />
<title>Hello World</title>
</head>
<body>
<button id="playMp3">Play MP3</button><br><br>
<button id="playMp3Mild">Play MP3 Mild</button><br><br>
<button id="playRemoteFile">Play Remote File</button>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="js/index.js"></script>
</body>
</html>
index.js:
document.addEventListener('deviceready', onDeviceReady, false);
function onDeviceReady() {
document.querySelector("#playMp3").addEventListener("touchend", playMP3, false);
document.querySelector("#playMp3Mild").addEventListener("touchend", playMp3Mild, false);
document.querySelector("#playRemoteFile").addEventListener("touchend", playRemoteFile, false);
};
function playMP3() {
var mp3URL = getMediaURL("sounds/button-1.mp3");
var media = new Media(mp3URL, null, mediaError);
media.setVolume(1.0);
media.play();
}
function playMp3Mild() {
var mp3URL = getMediaURL("sounds/button-1.mp3");
var media = new Media(mp3URL, null, mediaError);
media.setVolume(0.1);
media.play();
}
function playRemoteFile() {
var media = new Media("http://SERVER_IP:PORT/media/test.mp3");
media.setVolume(0.1);
media.play();
}
function getMediaURL(s) {
if(device.platform.toLowerCase() === "android") return "/android_asset/www/" + s;
return s;
}
function mediaError(e) {
alert('Media Error');
alert(JSON.stringify(e));
}
The sample app can be downloaded from the github page. Ensure to add media and device plugin to test the same. More info can be found on the README file of the sample app. Hope it helps.
I'm not sure this will solve your issue, but maybe the volume is not set to zero because the setVolume is called too "early". Could you please try this code and report eventually some logs in order to refine my solution?
play: function(src, seekTime)
{
App.Log.info('Playing audio source', src);
seekTime = seekTime ? seekTime : 0;
var obj = {
source: src,
startTime: new Date().getTime(),
seekTime: seekTime,
duration: 0,
preloadedNext: false,
audioSource: false
};
obj.audioSource = new Media(src, function(event){
$this.player().onAudioEnd(event, obj);
}, function(){
//on error
}, function(status)
{
obj.audioSource.setVolume("0.0");
if(status == 2){
obj.audioSource.setVolume("0.0");
obj.audioSource.seekTo(obj.seekTime * 1000);
obj.timer = setInterval(function(){
obj.seekTime++;
obj.duration = obj.audioSource._duration;
if(obj.duration < 0){
return;
}
if(obj.seekTime >= (obj.duration - $this.default.fadeTime))
{
if(obj.preloadedNext){
return;
}
obj.preloadedNext = true;
$this.player().preloadNext(obj);
}
}, 1000);
}
});
//obj.audioSource.setVolume("0.0");
obj.audioSource.play();
setTimeout(function() { //try to set volume to 0 after 10 milliseconds
obj.audioSource.setVolume("0.0");
}, 10);
setTimeout(function() { //try to seekTo after 1 second
obj.audioSource.seekTo(obj.seekTime * 1000);
}, 1000);
console.log('Audio Source', JSON.stringify(obj));
$this.playing.push(obj);
}
Can you set a mute delay of one second to see if it creates at least a correct delayed behaviour? (process of elimination)
setTimeout(function() {
obj.audioSource.setVolume("0.0");
}, 1000);

HTML5 Bing Maps and Geolocation

I'm working on an windows 8 app in html5 and now I'm stuck with the map that is going to find the users location I don't know whats wrong, it says it some error I hope someone can help me because I have more to work on and i have a deadline on this project
map.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>BingMapsJSIntro</title>
<script src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0" type="text/javascript"></script>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
<!-- BingMapsJSIntro references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/default.js"></script>
<!-- Bing Maps references -->
<script type="text/javascript"
src="ms-appx:///Bing.Maps.JavaScript//js/veapicore.js"></script>
<!-- Our Bing Maps JavaScript Code -->
<script src="/js/bing.js"></script>
</head>
<body>
<div id="myMap"></div>
</body>
</html>
bing.js
var map;
function showMap(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
var map = new Microsoft.Maps.Map($("mymap")[0],
{
credentials: "MYBINGMAPCODE",
center: new Microsoft.Maps.Location(latitude, longitude),
mapTypeId: Microsoft.Maps.MapTypeId.road,
zoom: 10
});
var center = map.getCenter();
var pin = new Microsoft.Maps.Pushpin(center, { width: 50, height: 50, draggable: false });
map.entities.push(pin);
}
//Initialization logic for loading the map control
(function () {
function initialize() {
Microsoft.Maps.loadModule('Microsoft.Maps.Map', { callback: GetMap });
}
document.addEventListener("DOMContentLoaded", initialize, false);
})();
Your modules callback method "GetMap" is non-existant in the code you provided.
Microsoft.Maps.loadModule('Microsoft.Maps.Map', { callback: GetMap });
You need something like...
function GetMap ()
{
var mapOptions = { credentials:"<Insert Your Bing Maps Key Here>" }
var map = new Microsoft.Maps.Map(document.getElementById("myMap"), mapOptions );
}

Getting around the 500 row limit

I have written a Google Fusion Tables script I'm happy with (below), but it's loading only 500 rows of points in my table, which has over 20,000 rows. This is my first time in this neighborhood and I was really surprised to find the limit. Is there some way to load all the rows?
<!doctype html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8">
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<title>Points in box</title>
<link href="./stylesheets/example.css" media="screen" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="/images/favicon.ico" />
<noscript><meta http-equiv="refresh" content="0;url=/no_javascript.html"></noscript>
<!-- Find box coordinates javascript -->
<script type ="text/javascript" src="http://www.movable-type.co.uk/scripts/latlon.js"></script>
<!-- Type label text javascript -->
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="./js/label.js"></script>
<!-- Visulization javascript -->
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<!-- Initialize visualization -->
<script type="text/javascript">
google.load('visualization', '1', {});
</script>
</head>
<body class="developers examples examples_downloads examples_downloads_points-in-box examples_downloads_points-in-box_index">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
var store_table = 4121905;
//send a call to GViz to retrieve lat/long coordinates of the stores
function getStoreData() {
//set the query using the input from the user
var queryText = encodeURIComponent("SELECT Latitude,Longitude,Impressions FROM " + store_table);
var query = new google.visualization.Query('http://www.google.com/fusiontables/gvizdata?tq=' + queryText);
//set the callback function
query.send(doLoop);
}
function drawBox(topleftx, toplefty, bottomrightx, bottomrighty) {
var bounds = new google.maps.LatLngBounds(
new google.maps.LatLng( topleftx, toplefty ),
new google.maps.LatLng( bottomrightx, bottomrighty )
);
var overlay = new google.maps.Rectangle({
map: carto_map,
bounds: bounds,
strokeColor: "#0000ff",
strokeOpacity: 0.20,
strokeWeight: 2,
fillColor: "#0000ff",
fillOpacity: 0.050,
});
}
function doLoop(response) {
numRows = response.getDataTable().getNumberOfRows();
//Basic
var cartodbMapOptions = {
zoom: 7,
center: new google.maps.LatLng( 37.926868, -121.68457 ),
// center: new google.maps.LatLng( 40.7248057566452, -74.003 ),
// disableDefaultUI: true,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
// Init the map
carto_map = new google.maps.Map(document.getElementById("map"),cartodbMapOptions);
for(i = 0; i < numRows; i++) {
var centerX = response.getDataTable().getValue(i,0);
var centerY = response.getDataTable().getValue(i,1);
var imps = response.getDataTable().getValue(i,2);
var centerPoint = new LatLon(centerX,centerY);
var latLng = new google.maps.LatLng(centerX,centerY);
var toplefty = centerPoint.destinationPoint(-45, 6)._lon;
var topleftx = centerPoint.destinationPoint(-45, 7.7)._lat;
var bottomrighty = centerPoint.destinationPoint(135, 6)._lon;
var bottomrightx = centerPoint.destinationPoint(135, 7.7)._lat;
drawBox(topleftx, toplefty, bottomrightx, bottomrighty);
var marker = new google.maps.Marker({
position: latLng,
draggable: false,
markertext: imps,
flat: true,
map: carto_map
});
var label = new Label({
map: carto_map,
position: latLng,
draggable: true
});
label.bindTo('text', marker, 'markertext');
marker.setMap(null);
}
}
$(function() {
getStoreData();
});
</script>
<div id="map"></div>
</body>
</html>
I solved the problem by using the json call method. Code below.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>David's Build Up</title>
<link href="./stylesheets/example.css" media="screen" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="/images/favicon.ico" />
<noscript><meta http-equiv="refresh" content="0;url=/no_javascript.html"></noscript>
<!-- Find box coordinates javascript -->
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js">
</script>
<script type ="text/javascript" src="http://www.movable-type.co.uk/scripts/latlon.js"></script>
<!-- Type label text javascript -->
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="./js/label.js"></script>
<!-- Visulization javascript -->
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<!-- Initialize visualization -->
<script type="text/javascript">
google.load('visualization', '1', {});
</script>
<script type="text/javascript">
function drawBox(topleftx, toplefty, bottomrightx, bottomrighty) {
var bounds = new google.maps.LatLngBounds(
new google.maps.LatLng( topleftx, toplefty ),
new google.maps.LatLng( bottomrightx, bottomrighty )
);
var overlay = new google.maps.Rectangle({
map: carto_map,
bounds: bounds,
strokeColor: "#0000ff",
strokeOpacity: 0.20,
strokeWeight: 2,
fillColor: "#0000ff",
fillOpacity: 0.050,
});
}
function initialize() {
// Set the map parameters
var cartodbMapOptions = {
zoom: 5 ,
center: new google.maps.LatLng( 40.313043, -97.822266 ),
mapTypeId: google.maps.MapTypeId.ROADMAP
}
// Initialize the map
carto_map = new google.maps.Map(document.getElementById("map"),cartodbMapOptions);
// Query to grab the data
var query = "SELECT Latitude, Longitude, Impressions FROM " +
'[encrypted table ID here]';
var encodedQuery = encodeURIComponent(query);
// Construct the URL to grab the data
var url = ['https://www.googleapis.com/fusiontables/v1/query'];
url.push('?sql=' + encodedQuery);
url.push('&key=AIzaSyAm9yWCV7JPCTHCJut8whOjARd7pwROFDQ');
url.push('&callback=?');
// Set the number of rows
var numRows = 3500;
// Get the variables from the table, in a loop
$.ajax({
url: url.join(''),
dataType: 'jsonp',
success: function (data) {
var rows = data['rows'];
var ftData = document.getElementById('ft-data');
for (var i in rows) {
var centerX = rows[i][0];
var centerY = rows[i][1];
var imps = rows[i][2];
// Set the center points
var centerPoint = new LatLon(centerX,centerY);
var latLng = new google.maps.LatLng(centerX,centerY);
// Set top left points
var toplefty = centerPoint.destinationPoint(-45, 6)._lon;
var topleftx = centerPoint.destinationPoint(-45, 7.7)._lat;
// Set bottom right points
var bottomrighty = centerPoint.destinationPoint(135, 6)._lon;
var bottomrightx = centerPoint.destinationPoint(135, 7.7)._lat;
// Draw the box
drawBox(topleftx, toplefty, bottomrightx, bottomrighty);
// Drop markers
var marker = new google.maps.Marker({
position: latLng,
draggable: false,
markertext: imps,
flat: true,
map: carto_map
});
var label = new Label({
map: carto_map,
position: latLng,
draggable: true
});
label.bindTo('text', marker, 'markertext');
marker.setMap(null);
};
}
});
}
</script>
</head>
<body onload="initialize()">
<div id="map"></div>
<div id="ft-data"></div>
</body>
</html>
The Gviz API does have a 500 row limit for a given query.
Any table is limited to 100,000 mappable rows, but that's well outside your reported 20,000 rows.
The new Javascript API, currently accepting Trusted Testers, offers JSON format support for any number of rows returned for a query. You can apply for the TT program by requesting membership in this group:
https://groups.google.com/group/fusion-tables-api-trusted-testers
-Rebecca
The fusiontables/gvizdata URL is intended for Gviz charts and so is limited to 500 points. There are other ways to query that don't have that limitation. See https://developers.google.com/fusiontables/docs/sample_code for examples.
I routinely refresh a 2500 row table by deleting all rows and inserting new ones. The loop in my code that constructs the INSERT sql has a nested loop that just counts to 400, sends that sql, and then starts building another one with the next 400 records.

Resources