three.js - webgl and canvas rendering performance issue - android

I've created a 3d scene with below code.
<!DOCTYPE html>
<html lang="en">
<head>
<title>3d Model using HTML5 and three.js</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="three.min.js" type="text/javascript"></script>
<script src="Curve.js" type="text/javascript"></script>
<script src="TubeGeometry.js" type="text/javascript"></script>
<script src="Stats.js" type="text/javascript"></script>
<script src="Detector.js" type="text/javascript"></script>
<script>
// variables
var container, stats;
var camera, scene, renderer, splineCamera, cameraHelper, cameraEye;
var text, plane, tube, tubeMesh, parent;
var targetRotation = 0;
var targetRotationOnMouseDown = 0;
var mouseX = 0;
var mouseXOnMouseDown = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
var binormal = new THREE.Vector3();
var normal = new THREE.Vector3();
init();
animate();
function init(){
// container
container = document.createElement( 'div' );
document.body.appendChild( container );
// info div
info = document.createElement( 'div' );
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
//info.innerHTML = 'Drag to spin the cylinder<br/> You can identify cylinder face by clicking on it.</br>';
container.appendChild( info );
// camera
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set(30,10,10);
//camera.up = new THREE.Vector3( 0, 1, 1 );
// scene
scene = new THREE.Scene();
camera.lookAt(scene.position);
// light
scene.add( new THREE.AmbientLight( 0x404040 ) );
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 1, 0 );
scene.add( light );
// CONTROLS
controls = new THREE.TrackballControls( camera );
// Grid
geometry = new THREE.Geometry();
geometry.vertices.push( new THREE.Vector3( - 500, 0, 0 ) );
geometry.vertices.push( new THREE.Vector3( 500, 0, 0 ) );
for ( var i = 0; i <= 20; i ++ ) {
line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
line.position.z = ( i * 50 ) - 500;
scene.add( line );
line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
line.position.x = ( i * 50 ) - 500;
line.rotation.y = 90 * Math.PI / 180;
scene.add( line );
}
// extrudePath, Helix Curve
extrudePath = new THREE.SplineCurve3([
new THREE.Vector3(0, 10, 10),
new THREE.Vector3(10, 0, 10),
new THREE.Vector3(10, 0, 0)
]);
console.log(extrudePath);
// Tube Geometry
var segments = 50;
var closed = false;
var debug = true;
var radiusSegments = 12;
//alert('hello');
var tube = new THREE.TubeGeometry(extrudePath, segments, 2, radiusSegments, closed, debug);
// Tube Mesh
tubeMesh = THREE.SceneUtils.createMultiMaterialObject( tube, [
new THREE.MeshLambertMaterial({
color: 0xff00ff,
opacity: tube.debug ? 0.2 : 0.8,
transparent: true
}),
new THREE.MeshBasicMaterial({
color: 0x000000,
opacity: 0.5,
wireframe: true
})]);
parent = new THREE.Object3D();
parent.position.y = 100;
if ( tube.debug ) tubeMesh.add( tube.debug );
//parent.add( tubeMesh );
scene.add( tubeMesh );
// projector
projector = new THREE.Projector();
// renderer
//renderer = new THREE.CanvasRenderer();
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
// stats
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'mouseover', onDocumentMouseOver, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.left = window.innerWidth / - 2;
camera.right = window.innerWidth / 2;
camera.top = window.innerHeight / 2;
camera.bottom = window.innerHeight / - 2;
camera.aspect = window.innerWidth / window.innerHeight;
//camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseDown( event ) {
event.preventDefault();
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'mouseout', onDocumentMouseOut, false );
mouseXOnMouseDown = event.clientX - windowHalfX;
targetRotationOnMouseDown = targetRotation;
}
function onDocumentMouseMove( event ) {
mouseX = event.clientX - windowHalfX;
targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02;
}
function onDocumentMouseUp( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentMouseOut( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentMouseOver( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentTouchStart( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
targetRotationOnMouseDown = targetRotation;
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;
}
}
function animate() {
requestAnimationFrame( animate );
render();
update();
}
function update()
{
controls.update();
stats.update();
}
function render() {
tubeMesh.rotation.y += ( targetRotation - tubeMesh.rotation.y ) * 0.15;
camera.updateMatrixWorld();
renderer.render( scene, camera );
}
</script>
</body>
</html>
Now when I change rendering from WebGL to Canvas, the FPS drops down to 1-2 FPS from 56-57 FPS on mobile browser. Native browser does not display anything on page and in Opera page becomes too slow for operations. How do I make page operations fast with Canvas rendering or how do I enable webgl rendering on mobile browsers ?

canvas renderer is software mode only, that means no GPU acceleration, the CPU has to do all the hard work that's why your fps drop.
AFAIK not every mobile browser is able to use webgl renderer yet, you could give opera mobile a try it's capable of webgl.

One way to speed up canvas rendering is to reduce the number of segments used in TubeGeometry

Related

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?

How to get native app feeling in Navigation drawer (Menu) in ionic application

Is there any way to get the native look and feeling in Navigation drawer(Menu) in ionic v1 application rather than pushing the center content?
I want to get the Android native look and feel in ionic application like above picture.
Though this is an old question and Ionic v2+ is currently available with this native Navigation drawer features (<ion-menu>). I just thought to share some code that shows how to implement this feature in Ionic v1 app. I think it will help to those who are still using Ionic v1 in their mobile app. Also Ionic v2+ implementation could be found at the end of this post.
Ionic v1
I just created a sample Ionic v1 app using their ready-made sidemenu app template.
ionic start myApp sidemenu --type ionic1
Then I created the following nativeSideMenu.js file inside js folder.
(function () {
'use strict';
angular.module('ionic.contrib.NativeDrawer', ['ionic'])
.controller('drawerCtrl', ['$rootScope', '$scope', '$element', '$attrs', '$ionicGesture', '$ionicBody', '$document', function ($rootScope, $scope, $element, $attr, $ionicGesture, $ionicBody, $document) {
var el = document.querySelectorAll("drawer")[0];
var mainContent = angular.element(document.querySelectorAll("ion-pane")[0]);
var dragging = false;
var startX, lastX, offsetX, newX, startY, lastY, offsetY, newY;
var side;
var isOpen = false;
var primaryScrollAxis = null;
mainContent.addClass('drawer-content');
// How far to drag before triggering
var thresholdX = 10;
// How far from edge before triggering
var edgeX = 40;
// Width of drawer set in css
var drawerWidth = 270;
var LEFT = 0;
var RIGHT = 1;
var isTargetDrag = false;
var isContentDrag = false;
var width = $element[0].clientWidth;
var height = $element[0].clientHeight;
var enableAnimation = function () {
angular.element(el).addClass('animate');
};
var disableAnimation = function () {
angular.element(el).removeClass('animate');
};
// Check if this is on target or not
var isTarget = function (el) {
while (el) {
if (el === $element[0]) {
return true;
}
el = el.parentNode;
}
};
var startDrag = function (e) {
disableAnimation();
dragging = true;
offsetX = lastX - startX;
offsetY = lastY - startY;
$ionicBody.addClass('drawer-open');
};
var startTargetDrag = function (e) {
disableAnimation();
dragging = true;
isTargetDrag = true;
offsetX = lastX - startX;
offsetY = lastY - startY;
};
var doEndDrag = function (e) {
startX = null;
lastX = null;
offsetX = null;
startY = null;
lastY = null;
offsetY = null;
isTargetDrag = false;
if (!dragging) {
return;
}
dragging = false;
enableAnimation();
if (isOpen && newX < (-width / 3)) {
el.style.transform = el.style.webkitTransform = 'translate3d(' + (-width - 5) + 'px, 0, 0)';
$ionicBody.removeClass('drawer-open');
isOpen = false;
} else if (newX < (-width / 1.5)) {
el.style.transform = el.style.webkitTransform = 'translate3d(' + (-width - 5) + 'px, 0, 0)';
$ionicBody.removeClass('drawer-open');
isOpen = false;
} else {
el.style.transform = el.style.webkitTransform = 'translate3d(0px, 0, 0)';
$ionicBody.addClass('drawer-open');
isOpen = true;
}
};
var doEndContentDrag = function (e) {
if (startX > lastX) {
startX = null;
lastX = null;
offsetX = null;
startY = null;
lastY = null;
offsetY = null;
isTargetDrag = false;
isContentDrag = false;
if (!dragging) {
return;
}
dragging = false;
enableAnimation();
el.style.transform = el.style.webkitTransform = 'translate3d(-101%, 0, 0)';
$ionicBody.removeClass('drawer-open');
isOpen = false;
}
else {
el.style.transform = el.style.webkitTransform = 'translate3d(0 0, 0)';
}
};
var doDrag = function (e) {
if (e.defaultPrevented) {
return;
}
if (!lastX) {
startX = e.gesture.touches[0].pageX;
}
if (!lastY) {
startY = e.gesture.touches[0].pageY;
}
lastX = e.gesture.touches[0].pageX;
lastY = e.gesture.touches[0].pageY;
if (!dragging) {
// Dragged 15 pixels and finger is by edge
if (Math.abs(lastX - startX) > thresholdX) {
if (isTarget(e.target)) {
startTargetDrag(e);
} else if (startX < edgeX) {
startDrag(e);
}
}
// Closing from outside of drawer
else if (isOpen && startX > width) {
disableAnimation();
dragging = true;
isContentDrag = true;
}
} else {
newX = Math.min(0, (-width + (lastX - offsetX)));
newY = Math.min(0, (-height + (lastY - offsetY)));
var absX = Math.abs(lastX - startX);
var absY = Math.abs(lastY - startY);
if (isContentDrag && lastX < startX) {
var drawerOffsetX = lastX - drawerWidth;
el.style.transform = el.style.webkitTransform = 'translate3d(' + -absX + 'px, 0, 0)';
}
else if (isTargetDrag && absX > absY + 5) {
el.style.transform = el.style.webkitTransform = 'translate3d(' + newX + 'px, 0, 0)';
} else {
el.style.transform = el.style.webkitTransform = 'translate3d(' + newX + 'px, 0, 0)';
}
}
if (dragging) {
e.gesture.srcEvent.preventDefault();
}
};
side = $attr.side == 'left' ? LEFT : RIGHT;
var dragFunction = function (e) {
if (el.attributes.candrag) {
doDrag(e);
}
};
var dragEndFunction = function (e) {
if (el.attributes.candrag) {
doEndDrag(e);
}
};
var onContentDrag = function (e) {
if (isOpen) {
doDrag(e);
}
};
var onContentTap = function (e) {
if (isOpen) {
closeDrawer();
e.gesture.srcEvent.preventDefault();
}
};
var contentDragEndFunction = function (e) {
if (isOpen) {
doEndContentDrag(e);
e.gesture.srcEvent.preventDefault();
}
};
var openDrawer = function () {
enableAnimation();
el.style.transform = el.style.webkitTransform = 'translate3d(0%, 0, 0)';
$ionicBody.addClass('drawer-open');
isOpen = true;
};
var closeDrawer = function () {
enableAnimation();
el.style.transform = el.style.webkitTransform = 'translate3d(-101%, 0, 0)';
$ionicBody.removeClass('drawer-open');
isOpen = false;
};
var toggleDrawer = function () {
if (isOpen) {
closeDrawer();
} else {
openDrawer();
}
};
this.close = function () {
closeDrawer();
};
$rootScope.toggleDrawerRoot = function () {
toggleDrawer();
};
this.open = function () {
openDrawer();
};
this.toggle = function () {
toggleDrawer();
};
$ionicGesture.on('drag', function (e) {
doDrag(e);
}, $document);
$ionicGesture.on('dragend', function (e) {
doEndDrag(e);
}, $document);
var dragGesture = $ionicGesture.on('drag', dragFunction, $document);
var dragEndGesture = $ionicGesture.on('dragend', dragEndFunction, $document);
var contentTapGesture = $ionicGesture.on('tap', onContentTap, mainContent);
var contentDragGesture = $ionicGesture.on('drag', onContentDrag, mainContent);
var contentDragEndGesture = $ionicGesture.on('dragend', contentDragEndFunction, mainContent);
$scope.$on('$destroy', function () {
$ionicGesture.off(dragGesture, 'drag', dragFunction);
$ionicGesture.off(dragEndGesture, 'dragend', dragEndFunction);
$ionicGesture.off(contentTapGesture, 'tap', onContentTap);
$ionicGesture.off(contentDragGesture, 'drag', onContentDrag);
$ionicGesture.off(contentDragEndGesture, 'dragend', contentDragEndFunction);
});
}])
.directive('drawer', ['$rootScope', '$ionicGesture', function ($rootScope, $ionicGesture) {
return {
restrict: 'E',
controller: 'drawerCtrl',
link: function ($scope, $element, $attr, ctrl) {
$element.addClass($attr.side);
$scope.openDrawer = function () {
ctrl.open();
};
$scope.closeDrawer = function () {
ctrl.close();
};
$scope.toggleDrawer = function () {
ctrl.toggle();
};
}
}
}])
.directive('menuAndDrawerToggle', ['$rootScope', '$ionicGesture', function ($rootScope, $ionicGesture) {
return {
controller: '',
link: function ($scope, $element, $attr) {
$element.bind('click', function () {
$rootScope.toggleDrawerRoot();
});
}
};
}])
.directive('menuAndDrawerClose', ['$ionicViewService', function ($ionicViewService) {
return {
restrict: 'AC',
require: '^drawer',
link: function ($scope, $element, $attr, ctrl) {
$element.bind('click', function () {
ctrl.close();
});
}
};
}]);
})();
And also created the following nativeSideMenu.css file inside css folder
drawer {
display: block;
position: fixed;
width: 270px;
height: 100%;
z-index: 100;
background-color:white;
}
drawer .header-menu{
margin-top:0px;
padding-top:0px;
}
drawer .header-menu ion-list .list{
padding-top:0px;
}
drawer.animate {
-webkit-transition: all ease-in-out 400ms;
transition: all ease-in-out 400ms;
}
drawer.left {
-webkit-transform: translate3d(-101%, 0, 0);
transform: translate3d(-101%, 0, 0);
box-shadow: 1px 5px 10px rgba(0,0,0,0.3);
}
drawer.right {
right: 0;
top: 0;
-webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
.drawer-open .drawer-content .pane, .drawer-open .drawer-content .scroll-content {
pointer-events: none;
opacity:0.2;
}
drawer .item-icon-left .icon{
font-size: 24px;
padding-bottom: 2px;
}
ion-side-menu .current a.item-content,ion-side-menu .clickable.current, drawer .current a.item-content, drawer .clickable.current {
color:#343434 !important;
}
drawer a.item-content, drawer .clickable{
color: #858585;
font-size:20px;
}
drawer .item-complex .item-content{
padding-top:16px;
padding-bottom:16px;
font-size:20px;
}
/*This section would normally have .platform-android at the front */
.platform-android4_0 drawer.left{
box-shadow: none;
border-left:0px;
border-right:0px;
}
.header-menu{
top:0px;
bottom:44px;
}
.menu .scroll-content {
top: 42px;
}
.menu-content{
box-shadow: none;
}
.drawer-open ion-pane.pane{
background-color: rgb(0,0,0);
}
.drawer-open view{
background-color: rgb(0,0,0);
}
.ion-view.pane{
transition: opacity .25s ease-in-out;
-moz-transition: opacity .25s ease-in-out;
-webkit-transition: opacity .25s ease-in-out;
}
.menu-open ion-view.pane, .drawer-open ion-view.pane{
/* opacity:0.4;
*/
}
.bar .title.no-nav{
text-align: left;
left: 0px !important;
}
.bar .button-icon.ion-navicon{
margin-left: -20px;
padding-right: 20px;
}
.bar .title{
text-align: left;
left: 16px !important;
}
.modal-wrapper .bar .title{
text-align: center;
left: 0px !important;
}
.bar .title.title-center{
text-align: center;
left: 0px !important;
right: 0px !important;
}
.ion-ios7-arrow-back:before{
content:"\f2ca";
}
.bar .button.button-icon.ion-ios7-arrow-back:before{
font-size: 17px;
line-height: 32px;
padding-right: 100px;
}
After that I added reference links to index.html file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title></title>
<link rel="manifest" href="manifest.json">
<!-- un-comment this code to enable service worker
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('service-worker.js')
.then(() => console.log('service worker installed'))
.catch(err => console.log('Error', err));
}
</script>-->
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<link href="css/nativeSideMenu.css" rel="stylesheet">
<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
<link href="css/ionic.app.css" rel="stylesheet">
-->
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<!-- your app's js -->
<script src="js/app.js"></script>
<script src="js/nativeSideMenu.js"></script>
<script src="js/controllers.js"></script>
</head>
<body ng-app="starter">
<ion-nav-view></ion-nav-view>
</body>
</html>
Then I included the ionic.contrib.NativeDrawer in angular.module in app.js file.
angular.module('starter', ['ionic', 'starter.controllers','ionic.contrib.NativeDrawer'])
After that I updated the code of menu.html file inside templates folder like below.
<ion-side-menus>
<ion-side-menu-content>
<ion-nav-bar class="bar-stable bar-positive-900">
<ion-nav-back-button>
</ion-nav-back-button>
<ion-nav-buttons side="left">
<button class="button button-icon button-clear ion-navicon" menu-and-drawer-toggle>
</button>
</ion-nav-buttons>
</ion-nav-bar>
<ion-pane drawer-menu-content>
<ion-nav-view name="menuContent"></ion-nav-view>
</ion-pane>
</ion-side-menu-content>
<drawer side="left">
<ion-content>
<ion-list>
<ion-item menu-and-drawer-close ng-click="login()">
Login
</ion-item>
<ion-item menu-and-drawer-close href="#/app/search">
Search
</ion-item>
<ion-item menu-and-drawer-close href="#/app/browse">
Browse
</ion-item>
<ion-item menu-and-drawer-close href="#/app/playlists">
Playlists
</ion-item>
</ion-list>
</ion-content>
</drawer>
</ion-side-menus>
Now just run the ionic serve and have the native feeling in Navigation drawer.
Use bellow reference links for more details
Ref. 1
Ref. 2
Ref. 3
Ionic v2+
We do not have that much of work to do in Ionic v2+ because by default it is giving the native feeling of the Navigation drawer. But we could change that behavior by passing the value to type on the <ion-menu>
<ion-menu type="overlay" [content]="mycontent">...</ion-menu>
According to DOC type details as bellow.
The display type of the menu. Default varies based on the mode, see
the menuType in the config. Available options: "overlay", "reveal",
"push".
Hope this will help to someone else!

What is Cordova trying to tell me?

Cordova error message in logcat:
D/chromium(24894): Unknown chromium error: 0
D/CordovaLog(24894): file:///android_asset/www/index.html: Line 2 : Uncaught TypeError: object is not a function
E/Web Console(24894): Uncaught TypeError: object is not a function at file:///android_asset/www/index.html:2
I did not find an android_asset folder. My best bet is myapp-debug.apk/assets/www/index.html, but where should there be an issue in line 2?
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="apple-touch-icon" href="resources/icons/myApp-ico.png">
<title>myApp</title>
<script type="text/javascript" src="cordova.js"></script>
<style type="text/css">
/**
* Example of an initial loading indicator.
* It is recommended to keep this as minimal as possible to provide instant feedback
* while other resources are still being loaded for the first time
*/
html, body {
height: 100%;
background-color: #1985D0
}
#appLoadingIndicator {
position: absolute;
top: 50%;
margin-top: -15px;
text-align: center;
width: 100%;
height: 30px;
-webkit-animation-name: appLoadingIndicator;
-webkit-animation-duration: 0.5s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-direction: linear;
}
#appLoadingIndicator > * {
background-color: #FFFFFF;
display: inline-block;
height: 30px;
-webkit-border-radius: 15px;
margin: 0 5px;
width: 30px;
opacity: 0.8;
}
#-webkit-keyframes appLoadingIndicator{
0% {
opacity: 0.8
}
50% {
opacity: 0
}
100% {
opacity: 0.8
}
}
</style>
<!-- The line below must be kept intact for Sencha Command to build your application -->
<script type="text/javascript">
/**
* Sencha Blink - Testing
* #author Jacky Nguyen <jacky#sencha.com>
*/
(function(global) {
var head = global.document.head,
Ext = global.Ext;
if (typeof Ext == 'undefined') {
global.Ext = Ext = {};
}
function write(content) {
document.write(content);
}
function addMeta(name, content) {
var meta = document.createElement('meta');
meta.setAttribute('name', name);
meta.setAttribute('content', content);
head.appendChild(meta);
}
Ext.blink = function(options) {
var scripts = options.js || [],
styleSheets = options.css || [],
i, ln, path, platform, theme;
if (navigator.userAgent.match(/IEMobile\/10\.0/)) {
var msViewportStyle = document.createElement("style");
msViewportStyle.appendChild(
document.createTextNode(
"#media screen and (orientation: portrait) {" +
"#-ms-viewport {width: 320px !important;}" +
"}" +
"#media screen and (orientation: landscape) {" +
"#-ms-viewport {width: 560px !important;}" +
"}"
)
);
document.getElementsByTagName("head")[0].appendChild(msViewportStyle);
}
addMeta('viewport', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no');
addMeta('apple-mobile-web-app-capable', 'yes');
addMeta('apple-touch-fullscreen', 'yes');
Ext.microloaded = true;
var filterPlatform = window.Ext.filterPlatform = function(platform) {
var profileMatch = false,
ua = navigator.userAgent,
j, jln, exclude;
platform = [].concat(platform);
function isPhone(ua) {
var isMobile = /Mobile(\/|\s)/.test(ua);
// Either:
// - iOS but not iPad
// - Android 2
// - Android with "Mobile" in the UA
return /(iPhone|iPod)/.test(ua) ||
(!/(Silk)/.test(ua) && (/(Android)/.test(ua) && (/(Android 2)/.test(ua) || isMobile))) ||
(/(BlackBerry|BB)/.test(ua) && isMobile) ||
/(Windows Phone)/.test(ua);
}
function isTablet(ua) {
return !isPhone(ua) && (/iPad/.test(ua) || /Android|Silk/.test(ua) || /(RIM Tablet OS)/.test(ua) ||
(/MSIE 10/.test(ua) && /; Touch/.test(ua)));
}
// Check if the ?platform parameter is set in the URL
var paramsString = window.location.search.substr(1),
paramsArray = paramsString.split("&"),
params = {},
testPlatform, i;
for (i = 0; i < paramsArray.length; i++) {
var tmpArray = paramsArray[i].split("=");
params[tmpArray[0]] = tmpArray[1];
}
testPlatform = params.platform;
if (testPlatform) {
return platform.indexOf(testPlatform) != -1;
}
for (j = 0, jln = platform.length; j < jln; j++) {
switch (platform[j]) {
case 'phone':
profileMatch = isPhone(ua);
break;
case 'tablet':
profileMatch = isTablet(ua);
break;
case 'desktop':
profileMatch = !isPhone(ua) && !isTablet(ua);
break;
case 'ios':
profileMatch = /(iPad|iPhone|iPod)/.test(ua);
break;
case 'android':
profileMatch = /(Android|Silk)/.test(ua);
break;
case 'blackberry':
profileMatch = /(BlackBerry|BB)/.test(ua);
break;
case 'safari':
profileMatch = /Safari/.test(ua) && !(/(BlackBerry|BB)/.test(ua));
break;
case 'chrome':
profileMatch = /Chrome/.test(ua);
break;
case 'ie10':
profileMatch = /MSIE 10/.test(ua);
break;
case 'windows':
profileMatch = /MSIE 10/.test(ua) || /Trident/.test(ua);
break;
case 'tizen':
profileMatch = /Tizen/.test(ua);
break;
case 'firefox':
profileMatch = /Firefox/.test(ua);
}
if (profileMatch) {
return true;
}
}
return false;
};
for (i = 0,ln = styleSheets.length; i < ln; i++) {
path = styleSheets[i];
if (typeof path != 'string') {
platform = path.platform;
exclude = path.exclude;
theme = path.theme;
path = path.path;
}
if (platform) {
if (!filterPlatform(platform) || filterPlatform(exclude)) {
continue;
}
Ext.theme = {
name: theme || 'Default'
};
}
write('<link rel="stylesheet" href="'+path+'">');
}
for (i = 0,ln = scripts.length; i < ln; i++) {
path = scripts[i];
if (typeof path != 'string') {
platform = path.platform;
exclude = path.exclude;
path = path.path;
}
if (platform) {
if (!filterPlatform(platform) || filterPlatform(exclude)) {
continue;
}
}
write('<script src="'+path+'"></'+'script>');
}
}
})(this);
if(document.URL.indexOf('file://')==0) {
oldBlink = Ext.blink;
Ext.blink = function(options) {
document.addEventListener("deviceready", function() {
oldBlink(options);
}, false);
}
}
</script>
</head>
<body>
<div id="appLoadingIndicator">
<div></div>
<div></div>
<div></div>
</div>
</body>
</html>
Could it be that "Line 2" does refer to something different entirely? If yes, what does it refer to?
Prettify this ugly line of code and try again to get a useful error message.
<script type="text/javascript">
(function(e) {
var c = e.document.head,
b = e.Ext;
if (typeof b == "undefined") {
e.Ext = b = {}
}
function d(f) {
document.write(f)
}
function a(f, g) {
var h = document.createElement("meta");
h.setAttribute("name", f);
h.setAttribute("content", g);
c.appendChild(h)
}
b.blink = function(p) {
var j = p.js || [],
n = p.css || [],
l, m, o, g, k;
if (navigator.userAgent.match(/IEMobile\/10\.0/)) {
var h = document.createElement("style");
h.appendChild(document.createTextNode("#media screen and (orientation: portrait) {#-ms-viewport {width: 320px !important;}}#media screen and (orientation: landscape) {#-ms-viewport {width: 560px !important;}}"));
document.getElementsByTagName("head")[0].appendChild(h)
}
a("viewport", "width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no");
a("apple-mobile-web-app-capable", "yes");
a("apple-touch-fullscreen", "yes");
b.microloaded = true;
var f = window.Ext.filterPlatform = function(u) {
var D = false,
r = navigator.userAgent,
w, A, s;
u = [].concat(u);
function z(E) {
var i = /Mobile(\/|\s)/.test(E);
return /(iPhone|iPod)/.test(E) || (!/(Silk)/.test(E) && (/(Android)/.test(E) && (/(Android 2)/.test(E) || i))) || (/(BlackBerry|BB)/.test(E) && i) || /(Windows Phone)/.test(E)
}
function y(i) {
return !z(i) && (/iPad/.test(i) || /Android|Silk/.test(i) || /(RIM Tablet OS)/.test(i) || (/MSIE 10/.test(i) && /; Touch/.test(i)))
}
var q = window.location.search.substr(1),
t = q.split("&"),
v = {},
B, x;
for (x = 0; x < t.length; x++) {
var C = t[x].split("=");
v[C[0]] = C[1]
}
B = v.platform;
if (B) {
return u.indexOf(B) != -1
}
for (w = 0, A = u.length; w < A; w++) {
switch (u[w]) {
case "phone":
D = z(r);
break;
case "tablet":
D = y(r);
break;
case "desktop":
D = !z(r) && !y(r);
break;
case "ios":
D = /(iPad|iPhone|iPod)/.test(r);
break;
case "android":
D = /(Android|Silk)/.test(r);
break;
case "blackberry":
D = /(BlackBerry|BB)/.test(r);
break;
case "safari":
D = /Safari/.test(r) && !(/(BlackBerry|BB)/.test(r));
break;
case "chrome":
D = /Chrome/.test(r);
break;
case "ie10":
D = /MSIE 10/.test(r);
break;
case "windows":
D = /MSIE 10/.test(r) || /Trident/.test(r);
break;
case "tizen":
D = /Tizen/.test(r);
break;
case "firefox":
D = /Firefox/.test(r)
}
if (D) {
return true
}
}
return false
};
for (l = 0, m = n.length; l < m; l++) {
o = n[l];
if (typeof o != "string") {
g = o.platform;
exclude = o.exclude;
k = o.theme;
o = o.path
}
if (g) {
if (!f(g) || f(exclude)) {
continue
}
b.theme = {
name: k || "Default"
}
}
d('<link rel="stylesheet" href="' + o + '">')
}
for (l = 0, m = j.length; l < m; l++) {
o = j[l];
if (typeof o != "string") {
g = o.platform;
exclude = o.exclude;
o = o.path
}
if (g) {
if (!f(g) || f(exclude)) {
continue
}
}
d('<script src="' + o + '"><\/script>')
}
}
})(this);
if (document.URL.indexOf("file://") == 0) {
oldBlink = Ext.blink;
Ext.blink = function(a) {
document.addEventListener("deviceready", function() {
oldBlink(a)
}, false)
}
}
Ext.blink({
id: "8b19cfab-9dd1-44d0-892e-28f50a42aecd",
js: [{
path: "lzstring.js",
update: "full",
version: "1.0.0"
}, {
path: "microloader-enhancement.js",
update: "full",
version: "1.0.0"
}, {
path: "app.js",
update: "full",
version: "1.1.11"
}],
css: [{
path: "resources/css/app.css",
update: "full",
theme: "Default"
}, {
path: "resources/css/sch.css",
update: "full"
}, {
path: "resources/css/myApp.css",
update: "full"
}]
});
</script>
The webviewis just trying to make you understand that you're trying to call functions from the object Ext (like Ext.blink) but did not include any js library that would include that object.
You need to copy extjs somewhere in jour www folder and then add the missing <script type="text/javascript" src="somewhere/extjs.js"></script> line.
Next time, put your js in a separate file, you should get more accurate error messages.
I found the error to be caused by a script that is added to index.html by code from another javascript, using Ext.Loader.injectScriptElement, which roughly translates to the following JS:
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
For some reason yet to be determined, the "object is not a function" error inside the referenced script is thrown inside Cordova WebView, but not inside Chrome. Once I found the line where it is thrown and corrected it, no more error is thrown.
For some other reason yet to be determined, it is thrown as an "error in index.html:2", whereas the error could also have read "error in locale-de.js:72".
Don't ask how I found it, this tiny little problem just required a whole week of debugging...

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