d3js map displays incorrectly in mobile chrome - android

I am relatively new to d3js, and trying to create a visualization of my quartet's concert schedule using a map. My first attempt works great in a desktop chrome browser and desktop safari browser.
On my android device in mobile chrome, the map renders the entire globe incorrectly except for the United States.
http://test.chiaraquartet.net/topo/index.html
Any insight into what I am doing wrong/if there is a bug in d3 would be appreciated.
Here is the code in question:
var center = [90, -38.7],
ratio = window.devicePixelRatio || 1,
graticule = d3.geo.graticule(),
width = 500,
height = 500,
degrees = 180 / Math.PI,
projection = d3.geo.orthographic()
.scale(height / 2 - 1)
.rotate(center)
.translate([width / 2, height / 2])
.clipAngle(90)
.precision(.1)
var graticule = d3.geo.graticule()()
// Round to integer pixels for speed, and set pixel ratio.
function roundRatioContext(context) {
return {
moveTo: function(x, y) { context.moveTo(Math.round(x * ratio), Math.round(y * ratio)); },
lineTo: function(x, y) { context.lineTo(Math.round(x * ratio), Math.round(y * ratio)); },
closePath: function() { context.closePath(); }
};
}
var canvas = d3.select("body").append("canvas")
.attr("width", width * ratio)
.attr("height", height * ratio)
.style("width", width + "px")
.style("height", height + "px")
var c = canvas.node().getContext("2d");
var path = d3.geo.path()
.projection(projection)
.context(roundRatioContext(c));
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append('g')
var textbox = d3.select("body").append("div")
.style('position', 'absolute')
.attr('class', 'popup')
.classed('hidden', true)
var sphere = svg.append("path")
.datum({type: "Sphere"})
.attr("id", "sphere")
.attr("d", path)
var runner = queue()
.defer(d3.json, 'world.json')
.defer(d3.xhr('/concertrpc.php')
.header('content-type', 'application/json')
.post, JSON.stringify({
params: [],
id: 1
}))
.await(function(error, world, info) {
if (error) return console.error(error);
var features = topojson.feature(world, world.objects.states)
var countries = topojson.feature(world, world.objects.countries)
console.log(world)
var concerts = JSON.parse(info.responseText)
if (concerts.error) {
console.log(concerts.error)
return
}
concerts = concerts.result.concerts
console.log(concerts)
var globe = {type: "Sphere"},
graticule = d3.geo.graticule()(),
countries = topojson.feature(world, world.objects.countries),
states = topojson.feature(world, world.objects.states),
country_borders = topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b }),
state_borders = topojson.mesh(world, world.objects.states, function(a, b) { return a.id !== b.id }),
temp_context
temp_context = path.context()
path.context(null)
svg.selectAll('.concert')
.data(concerts, function(d) { return d.properties.id })
.enter().append("path")
.attr('class', 'concert')
.attr('d', path)
.on('mouseover', concertMouseover)
.on('mouseout', function(d) {
textbox.classed('hidden', true)
})
path.context(temp_context)
d3.select('body').append('div').append('button')
.attr('type', 'button')
.text('This season')
.on('click', function() {
getConcertData('This season')
})
var zoom = d3.geo.zoom()
.projection(projection)
.duration(function(S) { return 2000 * Math.sqrt(S); }) // assume ease="quad-in-out"
.scaleExtent([height / 2 - 1, Infinity])
.on("zoom", function() {
projection.clipAngle(Math.asin(Math.min(1, .5 * Math.sqrt(width * width + height * height) / projection.scale())) * degrees);
c.clearRect(0, 0, width * ratio, height * ratio);
c.strokeStyle = "#999", c.lineWidth = .25 * ratio, c.beginPath(), path(graticule), c.stroke();
c.fillStyle = "#69d2e7", c.beginPath(), path(countries), c.fill();
c.fillStyle = "#00f", c.beginPath(), path(states), c.fill();
c.strokeStyle = "#fff", c.lineWidth = .5 * ratio, c.beginPath(), path(country_borders), c.stroke();
c.strokeStyle = "#fff", c.lineWidth = .5 * ratio, c.beginPath(), path(state_borders), c.stroke();
c.strokeStyle = "#000", c.lineWidth = .5 * ratio, c.beginPath(), path(globe), c.stroke();
temp_context = path.context()
path.context(null)
svg.selectAll("path").attr("d",path);
path.context(temp_context)
})
//.on("zoomend", transition);
canvas
.call(zoom)
.call(zoom.event);
sphere
.call(zoom)
function transition() {
zoomBounds(projection, states.features[30]);
canvas.transition()
.ease("quad-in-out")
.duration(2000) // see https://github.com/mbostock/d3/pull/2045
.call(zoom.projection(projection).event);
}
function zoomBounds(projection, o) {
var centroid = d3.geo.centroid(o),
clip = projection.clipExtent();
projection
.rotate([-centroid[0], -centroid[1]])
.clipExtent(null)
.scale(1)
.translate([0, 0]);
var b = path.bounds(o),
k = Math.min(1000, .45 / Math.max(Math.max(Math.abs(b[1][0]), Math.abs(b[0][0])) / width, Math.max(Math.abs(b[1][1]), Math.abs(b[0][1])) / height));
projection
.clipExtent(clip)
.scale(k)
.translate([width / 2, height / 2]);
}
})
function concertMouseover(d) {
var loc = projection(d3.select(this).datum().geometry.coordinates)
textbox.style('top', loc[1] + "px")
textbox.style('left', loc[0] + 15 + "px")
textbox.text(d.properties.title)
textbox.classed('hidden', false)
}
function getConcertData(request) {
d3.xhr('/concertrpc.php')
.header('content-type', 'application/json')
.post(JSON.stringify({
params: [request],
id: 1
}), function(error, info) {
var concerts = JSON.parse(info.responseText)
if (concerts.error) {
console.log(concerts.error)
return
}
var c = svg.selectAll('.concert')
.data(concerts.result.concerts, function(d) { return d.properties.id })
c.transition()
.style('opacity', '1')
c.enter()
.append('path')
.attr('class', 'concert')
.attr('d', path)
.on('mouseover', concertMouseover)
.on('mouseout', function(d) {
textbox.classed('hidden', true)
})
c.exit().transition()
.duration(1000)
.style('opacity', '0')
.remove()
})
}

I'm not sure what was causing the problem, but the culprit was in the topojson file generated by my attempts to combine a map of the countries of the world with a map of the states of the USA. I found a different map of the world to use, and now the map displays the same way on both the phone and the desktop.

Related

"THREE.WebGLRenderer: A WebGL context could not be created. Reason: Failed to create a WebGL2 context" error in Angular Studio

I'm new to Angular-Ionic and I created my first App with THREE js, now. When I run it in Firefox or Chrome, I don't get any erros at all. But when I run it with Android Studio I get a lot of errors.
Examples:
Could not create a WebGL context, VENDOR = 0xffff, DEVICE = 0xffff, GL_VENDOR = Google (NVIDIA Corporation), GL_RENDERER = Android Emulator OpenGL ES Translator (NVIDIA GeForce MX350/PCIe/SSE2), GL_VERSION = 526.98, Sandboxed = no, Optimus = no, AMD switchable = no, Reset notification strategy = 0x8252, ErrorMessage = bindToCurrentThread failed:
glDrawElements: framebuffer incomplete (check)
Shader Error 1280 - VALIDATE_STATUS false
Failed to create a WebGL2 context.
in Angular Studio
in Firefox
my home.page.ts (and I know, it's not a clean code):
import { Component, ElementRef, HostListener, ViewChild } from '#angular/core';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { Water } from 'three/examples/jsm/objects/Water';
import { Sky } from 'three/examples/jsm/objects/Sky';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
#Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
steps = 1000
target = 10000
progress = this.steps / this.target
#ViewChild('canvas') container!: ElementRef;
protected scene
protected camera
protected renderer
protected controls
protected pmremGenerator
constructor() {
this.scene = new THREE.Scene()
this.camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 1, 20000);
this.renderer = new THREE.WebGLRenderer({antialias: true})
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
this.pmremGenerator = new THREE.PMREMGenerator(this.renderer)
}
ngAfterViewInit() {
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
this.container.nativeElement.appendChild(this.renderer.domElement);
this.camera.position.set(0, 0, -1000);
this.renderer.shadowMap.enabled = true;
this.controls.maxPolarAngle = Math.PI * 0.46;
this.controls.minDistance = 10.0;
this.controls.maxDistance = 200.0;
this.controls.update();
this.controls.update();
let sun = new THREE.Vector3();
const waterGeometry = new THREE.PlaneGeometry(10000, 10000);
let water = new Water(
waterGeometry,
{
textureWidth: 1024,
textureHeight: 1024,
waterNormals: new THREE.TextureLoader().load('../../assets/textures/waternormals.jpg', function (texture) {
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
}),
sunDirection: new THREE.Vector3(),
sunColor: 0xffffff,
waterColor: 0x001e0f,
distortionScale: 3.7,
fog: true
}
);
water.rotation.x = - Math.PI / 2;
this.scene.add(water);
const sky = new Sky();
sky.scale.setScalar(10000);
this.scene.add(sky);
const skyUniforms = sky.material.uniforms;
skyUniforms['turbidity'].value = 5;
skyUniforms['rayleigh'].value = 0.1;
skyUniforms['mieCoefficient'].value = 0.006;
skyUniforms['mieDirectionalG'].value = 0.55;
let renderTarget;
let cylinderGeo = new THREE.CylinderGeometry(50, 50, 10, 100)
let cylinderMat = new THREE.MeshStandardMaterial({
metalness: 0,
roughness: 1
})
let cylinder = new THREE.Mesh(cylinderGeo, cylinderMat)
this.scene.add(cylinder)
cylinder.position.set(0, -3, 0)
cylinder.receiveShadow = true
const loader = new GLTFLoader;
loader.load(
'assets/Wohnhaus.glb',
(object) => {
this.scene.add(object.scene);
object.scene.position.set(0, 2, 0)
object.scene.scale.set(10,10,10)
}
)
this.updateSun(sky, water, sun, renderTarget);
this.animate(water)
}
animate(water: Water) {
requestAnimationFrame(() => { this.animate(water) })
this.controls.update()
water.material.uniforms['time'].value += 1.0 / 60.0;
this.renderer.render(this.scene, this.camera)
}
#HostListener('window:resize', ['$event'])
onResize() {
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.render(this.scene, this.camera);
}
updateSun(sky: Sky, water: Water, sun: THREE.Vector3, renderTarget: any) {
const parameters = {
elevation: 10,
azimuth: 90
};
const phi = THREE.MathUtils.degToRad(90 - parameters.elevation);
const theta = THREE.MathUtils.degToRad(parameters.azimuth);
sun.setFromSphericalCoords(1, phi, theta);
sky.material.uniforms['sunPosition'].value.copy(sun);
water.material.uniforms['sunDirection'].value.copy(sun).normalize();
sky.castShadow = true
water.castShadow = true
if (renderTarget !== undefined) renderTarget.dispose();
renderTarget = this.pmremGenerator.fromScene(this.scene);
this.scene.environment = renderTarget.texture;
}
}
I already tried different Android Versions and Phones and I always have the same problems.
Update
I have changed WEBGLRenderer to WEBGL1Renderer. In my Code I removed the commented code. Now I don't get any Errors at all. I can see the cylinder now, but not the GLTFModel.
let cylinderGeo = new THREE.CylinderGeometry(50, 50, 10, 100)
/*let cylinderMat = new THREE.MeshStandardMaterial({
metalness: 0,
roughness: 1
})*/
let cylinder = new THREE.Mesh(cylinderGeo)
this.scene.add(cylinder)
cylinder.position.set(0, -3, 0)
const loader = new GLTFLoader;
loader.load(
'assets/Wohnhaus.glb',
(object) => {
this.scene.add(object.scene);
object.scene.position.set(0, 2, 0)
object.scene.scale.set(10, 10, 10)
}
)

3D Model not loading on android device

I have a page on my(very very recent only 2days old) website that contains a 3D model. The model was made in Blender, and was exported in the .glb format using glTF-Blender-IO by the KhronosGroup. It is uploaded with the THREE.GLTFLoader. Everything works perfectly fine on desktop and on iOS devices, however not on Android devices. The model simply does not show up. The error I get reads as follows:
Three.WebGlShader: Shader couldn't compile
Three.WebGlProgram: shader error:1282 35715 false
gl.getProgramInfoLog invalid shaders WARNING:0:1:'GL_OES_standard_derivatives':extension is not supported
'use strict';
window.onload = function() {
main();
}
function main() {
var canvas = document.querySelector('#canvasExpo58');
var renderer = new THREE.WebGLRenderer({canvas, antialias:true, alpha:true});
var fov = 45;
var aspect = window.innerWidth/window.innerHeight;
var near = 1;
var far = 1000;
var camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(10, 2, 5); //Zou moeten de initiƫle positie van de camera zijn bij opstarten: dus wat je als eerste ziet vooraleer je de muis beweegt
var controls = new THREE.OrbitControls(camera, canvas);
controls.target.set(10, 25, 10);
controls.update();
var scene = new THREE.Scene();
scene.background = renderer.setClearColor(0x000000, 0); //Deze geeft, samen met de alpha:true in de WebGLRenderer, een transparante achtergrond
{
var light1 = new THREE.DirectionalLight(new THREE.Color(0xFFFFFF), 0.8);
light1.position.set(-5, -5, 25);
scene.add(light1);
scene.add(light1.target);
}
{
var light2 = new THREE.DirectionalLight(new THREE.Color(0xFFFFFF), 1);
light2.position.set(-40, -10, 4);
scene.add(light2);
scene.add(light2.target);
}
{
var light3 = new THREE.AmbientLight(new THREE.Color(0xCBC9D3), 0.9);
scene.add(light3);
scene.add(light3.target);
}
{
var loader = new THREE.GLTFLoader();
loader.load(
'images/Dressoir.glb',
(gltf) => {
var root = gltf.scene;
scene.add(root);
var box = new THREE.Box3().setFromObject(root);
var boxSize = box.getSize(new THREE.Vector3()).length();
var boxCenter = box.getCenter(new THREE.Vector3());
//frameArea(boxSize * 0.5, boxSize, boxCenter, camera);
controls.maxDistance = boxSize * 10;
controls.target.copy(boxCenter);
controls.update();
}
);
}
function resizeRendererToDisplaySize(renderer) {
var canvas = renderer.domElement;
var width = canvas.clientWidth;
var height = canvas.clientHeight;
var needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resizeRendererToDisplaySize(renderer)) {
var canvas = renderer.domElement;
camera.aspect = canvas.clientWidth/canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
Webpage of the Live Server
I have tried searching the web for an answer, but found nothing relevant.

Cordova radio stream spectrum analyzer iOS\Android

I have a problem with radio stream spectrum analyzer in iOS\Android.
My HTML:
<canvas id="canvas" width="512" height="100"></canvas>
<div id="playStream">Play</div>
<div id="stopStream">Stop</div>
And my javascript code:
window.onload = function () {
var ctx = document.getElementById("canvas").getContext("2d");
var audioContext = new(window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext)();
var analyser = audioContext.createAnalyser();
analyser.fftSize = 512;
analyser.connect(audioContext.destination);
var frequencyBins = new Uint8Array(analyser.frequencyBinCount);
var filter = audioContext.createBiquadFilter();
filter.type = "highpass";
filter.frequency.value = 0.0001;
filter.connect(analyser);
window.audio = new Audio('http://noasrv.caster.fm:10099/128mp3_autodj');
audio.crossOrigin = 'anonymous';
var audioSrc = audioContext.createMediaElementSource(audio);
audioSrc.connect(analyser);
audioSrc.connect(filter);
var osc = audioContext.createOscillator();
osc.connect(filter);
var WIDTH = 512;
var HEIGHT = 100;
var value, h, w;
function draw() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
for (var i = 0; i < frequencyBins.length; i++) {
value = frequencyBins[i];
h = HEIGHT * (value / 255);
w = WIDTH / frequencyBins.length;
ctx.fillRect(i * w, HEIGHT - 1, w, -h);
}
};
function animate() {
analyser.getByteFrequencyData(frequencyBins);
//console.log(frequencyBins);
draw();
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
playStream.addEventListener('click', function(){
audio.play();
}, false)
stopStream.addEventListener('click', function(){
audio.pause();
}, false)
};
And here is an example: http://jsfiddle.net/a2ZL9/46/.
This code works fine in browsers, but when I build android app it's doesn't work. Audio playing, but there is no animation of spectrum analyzer.
Can somebody help me with this problem?

Can't scroll a ScrollView when a View inside it triggers an event in Android

I'm working with Titanium SDK 3.1.1 and the logic in my app is like this:
I have a ScrollView that resembles a TableView which contains Views that work as sections, each section contains draggable Views, each of this horizontally draggable Views has a touchstart, touchmove and touchend event to drag them. The problem is that if I set the ScrollView's property canCancelEvents to false, I can't scroll the ScrollView. This problem doesn't happen in iOS, only in Android.
I tried to set the canCancelEvents property to true for Android, but while the scroll works, while I'm dragging one of the views inside the ScrollView, if by any chance I drag it vertically (the draggable views don't drag vertically, only horizontally) then the ScrollView's scroll event takes control of the event and the drag is interrupted.
This is my code:
// This function create a horizontal draggable View
function evaluationItem(item)
{
var self = Ti.UI.createView({
width:Ti.Platform.displayCaps.platformWidth,
height:88 + dpi
});
var backgroundWorkspace = Ti.UI.createView({
top:0 + dpi,
left:0 + dpi,
backgroundColor:"#404040",
width:Ti.Platform.displayCaps.platformWidth,
height:'100%',
zIndex:0
});
var checkEvaluation = Ti.UI.createImageView({
image:imagesPath + "CheckEvaluation.png",
opacity:0,
left:20 + dpi
});
var notYetEvaluation = Ti.UI.createImageView({
image:imagesPath + "NotYetEvaluation.png",
opacity:0,
right:20 + dpi
});
backgroundWorkspace.add(checkEvaluation);
backgroundWorkspace.add(notYetEvaluation);
var foregroundWorkspace = Ti.UI.createView({
top:0 + dpi,
left:0 + dpi,
backgroundColor:"#FFFFFF",
width:Ti.Platform.displayCaps.platformWidth,
height:'100%',
zIndex:1
});
var foregroundWorkspaceDraggable = Ti.UI.createView({
top:0 + dpi,
left:0 + dpi,
backgroundColor:"transparent",
width:Ti.Platform.displayCaps.platformWidth,
height:'100%',
zIndex:2
});
var curX, curY;
var deltaX, deltaY;
var currentPositionX, currentPositionY;
var initialViewX = parseInt(foregroundWorkspace.getLeft()) , initialViewY = parseInt(foregroundWorkspace.getTop());
var limitToTheRight = Ti.Platform.displayCaps.platformWidth/2.5;
var limitToTheLeft = (-1)* Ti.Platform.displayCaps.platformWidth/2.5;
var neutralColor = "#404040";
var positiveColor = "#79b715";
var negativeColor = "#9e9e9e";
// event for touchstart
foregroundWorkspaceDraggable.addEventListener('touchstart', function(e) {
curX = e.x;
curY = e.y;
});
var hoveringOver = 0;
// event for touchmove, this handles the dragging
foregroundWorkspaceDraggable.addEventListener('touchmove', function(e) {
var currentOpacity = currentPositionX / limitToTheRight;
if(currentOpacity < 0)
currentOpacity = 0;
else if(currentOpacity > 1)
currentOpacity = 1;
checkEvaluation.setOpacity(currentOpacity);
var currentOpacityNotYet = currentPositionX / limitToTheLeft;
if(currentOpacityNotYet < 0)
currentOpacityNotYet = 0;
else if(currentOpacityNotYet > 1)
currentOpacityNotYet = 1;
notYetEvaluation.setOpacity(currentOpacityNotYet);
deltaX = e.x - curX;
currentPositionX = initialViewX + deltaX;
if (currentPositionX > limitToTheRight) {
if (hoveringOver != 1) {
hoveringOver = 1;
backgroundWorkspace.animate({
backgroundColor : positiveColor,
duration : 250
});
}
} else if (currentPositionX <= limitToTheLeft) {
if (hoveringOver != -1) {
hoveringOver = -1;
backgroundWorkspace.animate({
backgroundColor : negativeColor,
duration : 250
});
}
} else {
if (hoveringOver != 0) {
hoveringOver = 0;
backgroundWorkspace.animate({
backgroundColor : neutralColor,
duration : 250
});
}
}
foregroundWorkspace.setLeft(currentPositionX);
});
function recallControl()
{
foregroundWorkspace.animate({
left : 0 + dpi,
duration : 500
});
}
// event for touchend, this handles where the view remains in the end
foregroundWorkspaceDraggable.addEventListener("touchend", function(e){
if (currentPositionX > limitToTheRight) {
foregroundWorkspace.animate({
left : Ti.Platform.displayCaps.platformWidth + dpi,
duration : 500
}, function() {
self.animate({
height : 0 + dpi,
duration : 500
});
});
} else if (currentPositionX <= limitToTheLeft) {
foregroundWorkspace.animate({
left : -Ti.Platform.displayCaps.platformWidth + dpi,
duration : 500
});
} else {
// alert('3');
recallControl();
}
});
var foregroundWorkspaceDecorator = Ti.UI.createView({
width:Ti.UI.FILL,
height:1 + dpi,
backgroundColor:"#d8d8d8",
bottom:0 + dpi,
left:0 + dpi
});
foregroundWorkspace.add(foregroundWorkspaceDecorator);
var evaluationIdView = Ti.UI.createView({
width:20 + dpi,
height:'100%',
top:0 + dpi,
left:10 + dpi,
backgroundColor:"transparent"
});
var evaluationIdLabel = Ti.UI.createLabel({
text : item.id + ".",
font : {
fontSize : 20 + dpi,
fontWeight : "bold"
},
color : item.color
});
evaluationIdView.add(evaluationIdLabel);
foregroundWorkspace.add(evaluationIdView);
var evaluationContentLabel = Ti.UI.createLabel({
text : "This is an evaluation,you can drag to the left or to the right and it will evaluate your kid",
left : 40 + dpi,
width : Ti.UI.FILL,
right : 30 + dpi,
font : {
fontSize : 14 + dpi
},
color : "#7a7a7a"
});
foregroundWorkspace.add(evaluationContentLabel);
self.add(backgroundWorkspace);
self.add(foregroundWorkspace);
self.add(foregroundWorkspaceDraggable);
return self;
}
// function that creates the sections for the ScrollView
function evaluationCategory(category)
{
var backgroundColor = "#229ce5";
switch(category.categoryType)
{
case 0: // blue
backgroundColor = "#229ce5";
break;
case 1: // pink
backgroundColor = "#c13a78";
break;
case 2: // orange
backgroundColor = "#f87739";
break;
case 3: // green
backgroundColor = "#79b715";
break;
case 4: // yellow
backgroundColor = "#ffd024";
break;
}
var self = Ti.UI.createView({
height:Ti.UI.SIZE,
layout:"vertical"
});
var titleView = Ti.UI.createView({
width:Ti.UI.FILL,
height:60 + dpi,
backgroundColor:backgroundColor
});
var titleViewLabel = Ti.UI.createLabel({
text : "physical",
font : {
fontSize : 20 + dpi,
fontWeight : "bold"
},
color : "#FFFFFF",
textAlign : "left",
width : Ti.UI.SIZE,
height : Ti.UI.SIZE,
left : 10 + dpi
});
titleView.add(titleViewLabel);
self.add(titleView);
var workspace = Ti.UI.createView({
width:Ti.UI.FILL,
height:Ti.UI.SIZE,
layout:"vertical"
});
for (var i = 0; i < 5; i++) {
workspace.add(evaluationItem({
id : i,
color : backgroundColor
}));
}
self.add(workspace);
return self;
}
// my ScrollView
if(osname === 'android'){
cancelEvents = true;
}
var scrollview = Ti.UI.createScrollView({
top : 0,
left : 0,
contentHeight : Ti.UI.SIZE,
scrollType : 'vertical',
layout : 'vertical',
showVerticalScrollIndicator : true,
canCancelEvents:cancelEvents,
});
scrollview.add(evaluationCategory({
categoryType : 0
}));
scrollview.add(evaluationCategory({
categoryType : 1
}));
scrollview.add(evaluationCategory({
categoryType : 2
}));
scrollview.add(evaluationCategory({
categoryType : 3
}));
It seems there's a problem in Android to handle this kind of behaviour. How can I make it so the ScrollView scrolls when it has to, but to not scroll when I'm dragging around one of the views inside of it?
The way I solved this problem was like this:
On the touchmove event I simply changed the value of the scrollview's scrollingEnabled property to false, so while I'm dragging one of the elements inside of it, the scrolling will be disabled. On the touchend event I enabled once again the scrolling. I passed a reference of the scrollview's setScrollingEnabled function.
foregroundWorkspaceDraggable.addEventListener('touchmove', function(e) {
setScrollingEnabled(false); //Added this
var currentOpacity = currentPositionX / limitToTheRight;
if(currentOpacity < 0)
currentOpacity = 0;
else if(currentOpacity > 1)
currentOpacity = 1;
checkEvaluation.setOpacity(currentOpacity);
var currentOpacityNotYet = currentPositionX / limitToTheLeft;
if(currentOpacityNotYet < 0)
currentOpacityNotYet = 0;
else if(currentOpacityNotYet > 1)
currentOpacityNotYet = 1;
notYetEvaluation.setOpacity(currentOpacityNotYet);
deltaX = e.x - curX;
currentPositionX = initialViewX + deltaX;
if (currentPositionX > limitToTheRight) {
if (hoveringOver != 1) {
hoveringOver = 1;
backgroundWorkspace.animate({
backgroundColor : positiveColor,
duration : 250
});
}
} else if (currentPositionX <= limitToTheLeft) {
if (hoveringOver != -1) {
hoveringOver = -1;
backgroundWorkspace.animate({
backgroundColor : negativeColor,
duration : 250
});
}
} else {
if (hoveringOver != 0) {
hoveringOver = 0;
backgroundWorkspace.animate({
backgroundColor : neutralColor,
duration : 250
});
}
}
foregroundWorkspace.setLeft(currentPositionX);
});
// event for touchend, this handles where the view remains in the end
foregroundWorkspaceDraggable.addEventListener("touchend", function(e){
setScrollingEnabled(true); //Added this
if (currentPositionX > limitToTheRight) {
foregroundWorkspace.animate({
left : Ti.Platform.displayCaps.platformWidth + dpi,
duration : 500
}, function() {
self.animate({
height : 0 + dpi,
duration : 500
});
});
} else if (currentPositionX <= limitToTheLeft) {
foregroundWorkspace.animate({
left : -Ti.Platform.displayCaps.platformWidth + dpi,
duration : 500
});
} else {
// alert('3');
recallControl();
}
});
This is a great alternative for both iOS and Android if you want to handle this kind of events on views contained in ScrollViews but don't wish to interrupted the scrollview's events.

Uncaught typeError cannot call method 'remove children' of undefined and Uncaught typeError cannot read property 'children' of undefined

I am doing project in android phonegap application using kineticjs and html5
I got 3 errors don't know what is the exact problem
Uncaught typeError cannot call method 'remove children' of undefined at file:///android_assest/www/index.html
Uncaught typeError cannot read property 'children' of undefined at file:///android_assest/www/index.html
Uncaught referenceError kinetic is not defined at file:///android_assest/www/index.html
I google it but cudn't find the answer so any help would be greatful
function clearCanvas() {
layer.removeChildren();
layer.draw();
haveBackground = false;
}
function downloadCanvas() {
var canvas = stage.children[0].canvas;
var oImgPNG = Canvas2Image.saveAsPNG(canvas, true);
document.body.appendChild(oImgPNG);
}
<img alt="" src="res/drawable-hdpi/design15.png" id="gabby" onClick="addClickedImage('gabby ')"/><br />
above those snippets in which i am getting error.Thanks in advance
Here is the script of my programm
<script type="text/javascript" src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.3.1.js"></script>
<script type="text/javascript" src="assets/www/base64.js"></script>
<script type="text/javascript" src="assets/www/canvas2image.js"></script>
<script type="text/javascript">
debugger;
var stage;
var layer;
var selected;
var wasSelected;
var haveBackground; // first dragged image sets stage size
/*
* Set up canvas stage and layer
*/
function initCanvas(id) {
stage = new Kinetic.Stage({
container: id,
width: 150,
height: 50
});
layer = new Kinetic.Layer();
stage.add(layer);
stage.draw();
}
/*
* Clear canvas, start again
*/
function clearCanvas() {
layer.removeChildren();
layer.draw();
haveBackground = false;
}
/*
* Download canvas
*/
function downloadCanvas() {
var canvas = stage.children[0].canvas;
var oImgPNG = Canvas2Image.saveAsPNG(canvas, true);
document.body.appendChild(oImgPNG);
}
/*
* Upload File
*/
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#blah')
.attr('src', e.target.result)
.width(20)
.height(20);
};
reader.readAsDataURL(input.files[0]);
}
}
/*
* Resize
*/
function resize(group, activeAnchor) {
var tl = group.get(".tl")[0];
var tr = group.get(".tr")[0]; group
var br = group.get(".br")[0];
var bl = group.get(".bl")[0];
var handle = group.get(".handle")[0];
var ghost = group.get(".ghost")[0];
var flip = group.get(".flip")[0];
var image = group.get(".image")[0];
switch (activeAnchor.attrs.name) {
case "tl":
bl.setPosition(tl.attrs.x, br.attrs.y);
tr.setPosition(br.attrs.x, tl.attrs.y);
break;
case "tr":
br.setPosition(tr.attrs.x, bl.attrs.y);
tl.setPosition(bl.attrs.x, tr.attrs.y);
break;
case "bl":
br.setPosition(tr.attrs.x, bl.attrs.y);
tl.setPosition(bl.attrs.x, tr.attrs.y);
break;
case "br":
bl.setPosition(tl.attrs.x, br.attrs.y);
tr.setPosition(br.attrs.x, tl.attrs.y);
break;
}
handle.setPosition((tr.attrs.x + tl.attrs.x) / 2, tl.attrs.y - 20);
ghost.setPosition(handle.getPosition());
flip.setPosition((tr.attrs.x + tl.attrs.x) / 2, bl.attrs.y + 20);
image.setPosition(tl.attrs.x, tl.attrs.y);
image.attrs.width = tr.attrs.x - tl.attrs.x;
image.attrs.height = bl.attrs.y - tl.attrs.y;
}
/*
* Rotate
*/
function rotate(group) {
var c = group.getAbsolutePosition();
var p0 = { x: c.x, y: c.y - 50 };
var p1 = stage.getUserPosition();
var p0c = Math.sqrt(Math.pow(c.x - p0.x, 2) + Math.pow(c.y - p0.y, 2)); // p0->c (b)
var p1c = Math.sqrt(Math.pow(c.x - p1.x, 2) + Math.pow(c.y - p1.y, 2)); // p1->c (a)
var p0p1 = Math.sqrt(Math.pow(p1.x - p0.x, 2) + Math.pow(p1.y - p0.y, 2)); // p0->p1 (c)
var deg = Math.acos((p1c * p1c + p0c * p0c - p0p1 * p0p1) / (2 * p1c * p0c));
// fix for negative rotation
if (p1.x < c.x) {
deg = (360 * (Math.PI / 180)) - deg;
}
group.setRotation(deg);
}
/*
* Flip
*/
function flip(group) {
group.attrs.scale.x = group.attrs.scale.x * -1;
}
/*
* Fix center offset (due to resizing from a corner)
*/
function fixCenterOffset(group) {
var image = group.get(".image")[0]
var currentOffset = group.getCenterOffset();
var currentPosition = group.getPosition();
var newOffset = { x: image.attrs.width / 2, y: image.attrs.height / 2 };
var newPosition = {
x: currentPosition.x - (currentOffset.x - newOffset.x),
y: currentPosition.y - (currentOffset.y - newOffset.y)
}
group.setCenterOffset(newOffset);
group.setPosition(newPosition);
layer.draw();
}
/*
* Prepare background image
*/
function prepareBackground(img) {
var maxWidth = 200;
var maxHeight = 100;
if (img.width > maxWidth) {
img.height = (maxWidth / img.width) * img.height;
img.width = maxWidth;
}
if (img.height > maxHeight) {
img.width = (maxHeight / img.height) * img.width;
img.height = maxHeight;
}
return img;
}
/*
* Add an image plus anchors to the canvas using group
*/
function initImage(img, type) {
if (type == "background") {
var kimggroup = initBackgroundImage(img);
} else {
var kimggroup = initNormalImage(img);
}
layer.add(kimggroup);
stage.add(layer);
// Draw the img
stage.draw();
}
/*
* Add background image
*/
function initBackgroundImage(img) {
var img = prepareBackground(img);
stage.setSize(img.width, img.height);
var kimggroup = new Kinetic.Group({
x: 0,
y: 0,
draggable: false
});
// Make the img and add it to the group
var kimg = new Kinetic.Image({
x: 0,
y: 0,
image: img,
width: img.width,
height: img.height,
name: "image"
});
kimggroup.add(kimg);
return kimggroup;
}
/*
* Add normal image
*/
function initNormalImage(img) {
var kimggroup = new Kinetic.Group({
x: stage.attrs.width / 2,
y: stage.attrs.height / 2,
draggable: true,
centerOffset: [img.width / 2, img.height / 2]
});
// Make the img and add it to the group
var kimg = new Kinetic.Image({
x: 0,
y: 0,
image: img,
width: img.width,
height: img.height,
name: "image"
});
kimggroup.add(kimg);
// Add anchors for resizing and rotation
addAnchor(kimggroup, 0, 0, "tl");
addAnchor(kimggroup, img.width, 0, "tr");
addAnchor(kimggroup, img.width, img.height, "br");
addAnchor(kimggroup, 0, img.height, "bl");
addAnchor(kimggroup, img.width / 2, -20, "handle");
addAnchor(kimggroup, img.width / 2, -20, "ghost");
addAnchor(kimggroup, img.width / 2, img.height + 20, "flip");
// On click make the image selected
kimggroup.on("mousedown", function () {
wasSelected = selected;
selected = this;
updateSelected();
this.moveToTop();
stage.draw();
});
kimg.on("mouseover", function () {
document.body.style.cursor = "move";
});
kimg.on("mouseout", function () {
document.body.style.cursor = "default";
});
// Double click to remove
kimg.on("dblclick dbltap", function () {
layer.remove(kimggroup);
layer.draw();
});
return kimggroup;
}
/*
* Create anchor and add to group
*/
function addAnchor(group, x, y, name) {
var config = {
x: x,
y: y,
stroke: "#666",
fill: "#ddd",
strokeWidth: 2,
radius: 4,
name: name,
draggable: true
}
switch (name) {
case "handle":
config.draggable = false;
var anchor = addRotateAnchor(group, config);
break;
case "ghost":
config.stroke = "#666";
var anchor = addRotateGhostAnchor(group, config);
break;
case "flip":
config.stroke = "#666";
config.draggable = false;
var anchor = addFlipAnchor(group, config);
break;
default:
var anchor = addResizeAnchor(group, config);
break;
}
anchor.hide();
group.add(anchor);
}
/*
* Set up resize anchor
*/
function addResizeAnchor(group, config) {
var anchor = new Kinetic.Circle(config);
anchor.on("dragmove", function () {
resize(group, this);
layer.draw();
});
anchor.on("mousedown touchstart", function () {
group.draggable(false);
this.moveToTop();
});
anchor.on("dragend", function () {
fixCenterOffset(group);
group.draggable(true);
layer.draw();
});
anchor.on("mouseover", function () {
var layer = this.getLayer();
document.body.style.cursor = "pointer";
this.setStrokeWidth(3);
layer.draw();
});
anchor.on("mouseout", function () {
var layer = this.getLayer();
document.body.style.cursor = "default";
this.setStrokeWidth(2);
layer.draw();
});
return anchor;
}
/*
* Set up rotation anchor
*/
function addRotateAnchor(group, config) {
var anchor = new Kinetic.Circle(config);
anchor.on("mouseover", function () {
var layer = this.getLayer();
document.body.style.cursor = "pointer";
this.setStrokeWidth(3);
layer.draw();
});
anchor.on("mouseout", function () {
var layer = this.getLayer();
document.body.style.cursor = "default";
this.setStrokeWidth(2);
layer.draw();
});
return anchor;
}
/*
* Set up rotation ghost anchor
*/
function addRotateGhostAnchor(group, config) {
var anchor = new Kinetic.Circle(config);
anchor.on("dragmove", function () {
rotate(group);
layer.draw();
});
anchor.on("mousedown touchstart", function () {
group.draggable(false);
this.moveToTop();
});
anchor.on("dragend", function () {
var handle = group.get(".handle")[0];
this.setPosition(handle.getPosition());
group.draggable(true);
layer.draw();
});
anchor.on("mouseover", function () {
var layer = this.getLayer();
document.body.style.cursor = "pointer";
this.setStrokeWidth(3);
layer.draw();
});
anchor.on("mouseout", function () {
var layer = this.getLayer();
document.body.style.cursor = "default";
this.setStrokeWidth(2);
layer.draw();
});
return anchor;
}
/*
* Set up flip anchor
*/
function addFlipAnchor(group, config) {
var anchor = new Kinetic.Circle(config);
anchor.on("mousedown touchstart", function () {
flip(group);
layer.draw();
});
anchor.on("mouseover", function () {
var layer = this.getLayer();
document.body.style.cursor = "pointer";
this.setStrokeWidth(3);
layer.draw();
});
anchor.on("mouseout", function () {
var layer = this.getLayer();
document.body.style.cursor = "default";
this.setStrokeWidth(2);
layer.draw();
});
return anchor;
}
/*
* Show anchors only when group selected
*/
function updateSelected() {
// Deselect the old img if there was any
if (wasSelected) {
wasSelected.get(".tl")[0].hide();
wasSelected.get(".tr")[0].hide();
wasSelected.get(".br")[0].hide();
wasSelected.get(".bl")[0].hide();
wasSelected.get(".handle")[0].hide();
wasSelected.get(".ghost")[0].hide();
wasSelected.get(".flip")[0].hide();
}
// Select the new image
selected.get(".tl")[0].show();
selected.get(".tr")[0].show();
selected.get(".br")[0].show();
selected.get(".bl")[0].show();
selected.get(".handle")[0].show();
selected.get(".ghost")[0].show();
selected.get(".flip")[0].show();
}
/*
* Add clicked images to the canvas
*/
function addClickedImage(name) {
var img = document.getElementById(name);
initImage(img, "normal");
}
/*
* Listen for images dragged into canvas and add them
*/
function setupDragAndDrop() {
stage.content.addEventListener("dragover", function (evt) {
evt.preventDefault();
}, false);
// Handle dropped image file - only Firefox and Google Chrome
stage.content.addEventListener("drop", function (evt) {
dragImg = new Image();
var files = evt.dataTransfer.files;
if (files.length > 0) {
var file = files[0];
if (typeof FileReader !== "undefined" && file.type.indexOf("image") != -1) {
var reader = new FileReader();
reader.onload = function (evt) {
dragImg.src = evt.target.result;
};
reader.readAsDataURL(file);
dragImg.onload = function () {
if (!haveBackground) {
haveBackground = true;
var type = "background";
} else {
var type = "normal";
}
initImage(this, type);
}
}
}
evt.preventDefault();
}, false);
}
window.onload = function () {
initCanvas("container");
setupDragAndDrop();
};
</script>
More details:
since you cannot 'remove children' of undefined, your layer is not being defined somewhere (or is removed or overwritten).
Make sure you have this somewhere:
var layer = new Kinetic.Layer();
not being able to access children means the same for your stage. but simply put since 'kinetic' is not defined somewhere you are either not including the Kinetic.4.3.0.1.JS in your sources, or you are declaring it incorrectly.
Make sure you have the kinetic.js file referenced somewhere, like in either the or tags:
<script src='http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.3.1.js'></script>
or link to a hard copy in your project
<script src='../kinetic-v4.3.1.js'></script> // in this example it is located one directory up, but you could put it anywhere really.
It's scoping issue.
Your variable layer is not accessible from function clearCanvas().
Not ideal, but it works by defining the variable first, then use it later like the following;
<script>
var layer;
$( function() {
layer = new Kinetic.Layer();
.....
});
</script>
so does the same apply to your variable 'stage'
--- edited after your comment ---
<script>
var layer, script, stage;
function initCanvas(id) {
stage = new Kinetic.Stage({ container: id, width: 150, height: 50 });
layer = new Kinetic.Layer();
stage.add(layer);
stage.draw();
}
</script>
if you defined 'stage = something' inside function it works like 'var stage=something'.
so if you want to access stage and layer outside of function, you defined it outside of your function.

Categories

Resources