Adobe Animate CC 2018 multiple canvas in one page

2018 10 24 No Comments

DEMO

I faced a interesting problem today. Solution was deadly simple but it took to understand a little time. There is bug when exporting custom named “symbols” in Animate CC.
First of all, if you wanna make play multiple animations in one page you should be careful about your .fla names and symbols key.

If you wonder where is the symbol key here you are(in publish sttings):

Let’s start.
For example you have an animation file named TestAnimaton.fla
Go your publish settings > Click HTML/JS tab. Change symbols area to TestAnimatonSVG

File name: OzerAnimaton.fla
Symbols: OzerAnimatonSVG
And click publish. Open your HTML. You will see the animation doesnt work. As you understand this is interesting bug…

1. Open OzerAnimaton.js
2. Find “lib” and replace with “OzerAnimationSVG” – Be sure replacing case sensitive words. Because there is function in this file includes “lib” keyword. This is getLibrary function. This returns animation object or class. Whatever.
3.I have to change a few field in HTML file. Open TestAnimation.html

We see this JS codes in script area.

var canvas, stage, exportRoot, anim_container, dom_overlay_container, fnStartAnimation;
function init() {
	canvas = document.getElementById("canvas");
	anim_container = document.getElementById("animation_container");
	dom_overlay_container = document.getElementById("dom_overlay_container");
	var comp=AdobeAn.getComposition("18000F61DE99F54DADFAEF867374C03C");
	var OzerAnimasyonSVG=comp.getLibrary();
	var loader = new createjs.LoadQueue(false);
	loader.addEventListener("fileload", function(evt){handleFileLoad(evt,comp)});
	loader.addEventListener("complete", function(evt){handleComplete(evt,comp)});
	var OzerAnimasyonSVG=comp.getLibrary();
	loader.loadManifest(OzerAnimasyonSVG.properties.manifest);
}
function handleFileLoad(evt, comp) {
	var images=comp.getImages();	
	if (evt && (evt.item.type == "image")) { images[evt.item.id] = evt.result; }	
}
function handleComplete(evt,comp) {
	//This function is always called, irrespective of the content. You can use the variable "stage" after it is created in token create_stage.
	var OzerAnimasyonSVG=comp.getLibrary();
	var ss=comp.getSpriteSheet();
	var queue = evt.target;
	var ssMetadata = OzerAnimasyonSVG.ssMetadata;
	for(i=0; i<ssMetadata.length; i++) {
		ss[ssMetadata[i].name] = new createjs.SpriteSheet( {"images": [queue.getResult(ssMetadata[i].name)], "frames": ssMetadata[i].frames} )
	}
	exportRoot = new OzerAnimasyonSVG.OzerAnimasyon();
	stage = new OzerAnimasyonSVG.Stage(canvas);	
	//Registers the "tick" event listener.
	fnStartAnimation = function() {
		stage.addChild(exportRoot);
		createjs.Ticker.setFPS(OzerAnimasyonSVG.properties.fps);
		createjs.Ticker.addEventListener("tick", stage)
		stage.addEventListener("tick", handleTick)
		function getProjectionMatrix(container, totalDepth) {
			var focalLength = 528.25;
			var projectionCenter = { x : lib.properties.width/2, y : lib.properties.height/2 };
			var scale = (totalDepth + focalLength)/focalLength;
			var scaleMat = new createjs.Matrix2D;
			scaleMat.a = 1/scale;
			scaleMat.d = 1/scale;
			var projMat = new createjs.Matrix2D;
			projMat.tx = -projectionCenter.x;
			projMat.ty = -projectionCenter.y;
			projMat = projMat.prependMatrix(scaleMat);
			projMat.tx += projectionCenter.x;
			projMat.ty += projectionCenter.y;
			return projMat;
		}
		function handleTick(event) {
			var cameraInstance = exportRoot.___camera___instance;
			if(cameraInstance !== undefined && cameraInstance.pinToObject !== undefined)
			{
				cameraInstance.x = cameraInstance.pinToObject.x + cameraInstance.pinToObject.pinOffsetX;
				cameraInstance.y = cameraInstance.pinToObject.y + cameraInstance.pinToObject.pinOffsetY;
				if(cameraInstance.pinToObject.parent !== undefined && cameraInstance.pinToObject.parent.depth !== undefined)
				cameraInstance.depth = cameraInstance.pinToObject.parent.depth + cameraInstance.pinToObject.pinOffsetZ;
			}
			applyLayerZDepth(exportRoot);
		}
		function applyLayerZDepth(parent)
		{
			var cameraInstance = parent.___camera___instance;
			var focalLength = 528.25;
			var projectionCenter = { 'x' : 0, 'y' : 0};
			if(parent === exportRoot)
			{
				var stageCenter = { 'x' : lib.properties.width/2, 'y' : lib.properties.height/2 };
				projectionCenter.x = stageCenter.x;
				projectionCenter.y = stageCenter.y;
			}
			for(child in parent.children)
			{
				var layerObj = parent.children[child];
				if(layerObj == cameraInstance)
					continue;
				applyLayerZDepth(layerObj, cameraInstance);
				if(layerObj.layerDepth === undefined)
					continue;
				if(layerObj.currentFrame != layerObj.parent.currentFrame)
				{
					layerObj.gotoAndPlay(layerObj.parent.currentFrame);
				}
				var matToApply = new createjs.Matrix2D;
				var cameraMat = new createjs.Matrix2D;
				var totalDepth = layerObj.layerDepth ? layerObj.layerDepth : 0;
				var cameraDepth = 0;
				if(cameraInstance && !layerObj.isAttachedToCamera)
				{
					var mat = cameraInstance.getMatrix();
					mat.tx -= projectionCenter.x;
					mat.ty -= projectionCenter.y;
					cameraMat = mat.invert();
					cameraMat.prependTransform(projectionCenter.x, projectionCenter.y, 1, 1, 0, 0, 0, 0, 0);
					cameraMat.appendTransform(-projectionCenter.x, -projectionCenter.y, 1, 1, 0, 0, 0, 0, 0);
					if(cameraInstance.depth)
						cameraDepth = cameraInstance.depth;
				}
				if(layerObj.depth)
				{
					totalDepth = layerObj.depth;
				}
				//Offset by camera depth
				totalDepth -= cameraDepth;
				if(totalDepth < -focalLength)
				{
					matToApply.a = 0;
					matToApply.d = 0;
				}
				else
				{
					if(layerObj.layerDepth)
					{
						var sizeLockedMat = getProjectionMatrix(parent, layerObj.layerDepth);
						if(sizeLockedMat)
						{
							sizeLockedMat.invert();
							matToApply.prependMatrix(sizeLockedMat);
						}
					}
					matToApply.prependMatrix(cameraMat);
					var projMat = getProjectionMatrix(parent, totalDepth);
					if(projMat)
					{
						matToApply.prependMatrix(projMat);
					}
				}
				layerObj.transformMatrix = matToApply;
			}
		}
	}	    
	//Code to support hidpi screens and responsive scaling.
	function makeResponsive(isResp, respDim, isScale, scaleType) {		
		var lastW, lastH, lastS=1;		
		window.addEventListener('resize', resizeCanvas);		
		resizeCanvas();		
		function resizeCanvas() {			
			var w = OzerAnimasyonSVG.properties.width, h = OzerAnimasyonSVG.properties.height;			
			var iw = window.innerWidth, ih=window.innerHeight;			
			var pRatio = window.devicePixelRatio || 1, xRatio=iw/w, yRatio=ih/h, sRatio=1;			
			if(isResp) {                
				if((respDim=='width'&&lastW==iw) || (respDim=='height'&&lastH==ih)) {                    
					sRatio = lastS;                
				}				
				else if(!isScale) {					
					if(iw<w || ih<h)						
						sRatio = Math.min(xRatio, yRatio);				
				}				
				else if(scaleType==1) {					
					sRatio = Math.min(xRatio, yRatio);				
				}				
				else if(scaleType==2) {					
					sRatio = Math.max(xRatio, yRatio);				
				}			
			}			
			canvas.width = w*pRatio*sRatio;			
			canvas.height = h*pRatio*sRatio;
			canvas.style.width = dom_overlay_container.style.width = anim_container.style.width =  w*sRatio+'px';				
			canvas.style.height = anim_container.style.height = dom_overlay_container.style.height = h*sRatio+'px';
			stage.scaleX = pRatio*sRatio;			
			stage.scaleY = pRatio*sRatio;			
			lastW = iw; lastH = ih; lastS = sRatio;            
			stage.tickOnUpdate = false;            
			stage.update();            
			stage.tickOnUpdate = true;		
		}
	}
	makeResponsive(true,'both',false,1);	
	AdobeAn.compositionLoaded(OzerAnimasyonSVG.properties.id);
	fnStartAnimation();
}
<body onload="init();" style="margin:0px;">
	<div id="animation_container" style="background-color:rgba(255, 255, 255, 1.00); width:300px; height:300px">
		<canvas id="canvas" width="300" height="300" style="position: absolute; display: block; background-color:rgba(255, 255, 255, 1.00);"></canvas>
		<div id="dom_overlay_container" style="pointer-events:none; overflow:hidden; width:300px; height:300px; position: absolute; left: 0px; top: 0px; display: block;">
		</div>
	</div>
</body>

First thing we do is change getElementById to querySelector. Because we will use multiple canvas in this page. Also we capsulate this js code with a function named OzerAnimationPlay() because we dont want the use canvas, stage, exportRoot variables outside of scope. So the most logical thing is to do right now is cover with it a function. It makes variables local.

After this, my code looks like this.

        /* ozer animasyon **************************************************************/
        function OzerAnimasyonPlay() {
            var canvas, stage, exportRoot, anim_container, dom_overlay_container, fnStartAnimation, lib;
            function init() {
                canvas = document.querySelector(".OzerAnimasyon");
                anim_container = document.querySelector(".OzerAnimasyonContainer");
                dom_overlay_container = document.querySelector(".OzerAnimasyonContainer");
                var comp = AdobeAn.getComposition("18000F61DE99F54DADFAEF867374C03C");
                lib = comp.getLibrary();
                var loader = new createjs.LoadQueue(false);
                loader.addEventListener("fileload", function (evt) { handleFileLoad(evt, comp) });
                loader.addEventListener("complete", function (evt) { handleComplete(evt, comp) });
                loader.loadManifest(lib.properties.manifest);
            }
            function handleFileLoad(evt, comp) {
                var images = comp.getImages();
                if (evt && (evt.item.type == "image")) { images[evt.item.id] = evt.result; }
            }
            function handleComplete(evt, comp) {
                //This function is always called, irrespective of the content. You can use the variable "stage" after it is created in token create_stage.
                var lib = comp.getLibrary();
                var ss = comp.getSpriteSheet();
                var queue = evt.target;
                var ssMetadata = lib.ssMetadata;
                for (i = 0; i < ssMetadata.length; i++) {
                    ss[ssMetadata[i].name] = new createjs.SpriteSheet({ "images": [queue.getResult(ssMetadata[i].name)], "frames": ssMetadata[i].frames })
                }
                exportRoot = new lib.OzerAnimasyon();
                stage = new lib.Stage(canvas);
                //Registers the "tick" event listener.
                fnStartAnimation = function () {
                    stage.addChild(exportRoot);
                    createjs.Ticker.setFPS(lib.properties.fps);
                    createjs.Ticker.addEventListener("tick", stage)
                    stage.addEventListener("tick", handleTick)
                    function getProjectionMatrix(container, totalDepth) {
                        var focalLength = 528.25;
                        var projectionCenter = { x: lib.properties.width / 2, y: lib.properties.height / 2 };
                        var scale = (totalDepth + focalLength) / focalLength;
                        var scaleMat = new createjs.Matrix2D;
                        scaleMat.a = 1 / scale;
                        scaleMat.d = 1 / scale;
                        var projMat = new createjs.Matrix2D;
                        projMat.tx = -projectionCenter.x;
                        projMat.ty = -projectionCenter.y;
                        projMat = projMat.prependMatrix(scaleMat);
                        projMat.tx += projectionCenter.x;
                        projMat.ty += projectionCenter.y;
                        return projMat;
                    }
                    function handleTick(event) {
                        var cameraInstance = exportRoot.___camera___instance;
                        if (cameraInstance !== undefined && cameraInstance.pinToObject !== undefined) {
                            cameraInstance.x = cameraInstance.pinToObject.x + cameraInstance.pinToObject.pinOffsetX;
                            cameraInstance.y = cameraInstance.pinToObject.y + cameraInstance.pinToObject.pinOffsetY;
                            if (cameraInstance.pinToObject.parent !== undefined && cameraInstance.pinToObject.parent.depth !== undefined)
                                cameraInstance.depth = cameraInstance.pinToObject.parent.depth + cameraInstance.pinToObject.pinOffsetZ;
                        }
                        applyLayerZDepth(exportRoot);
                    }
                    function applyLayerZDepth(parent) {
                        var cameraInstance = parent.___camera___instance;
                        var focalLength = 528.25;
                        var projectionCenter = { 'x': 0, 'y': 0 };
                        if (parent === exportRoot) {
                            var stageCenter = { 'x': lib.properties.width / 2, 'y': lib.properties.height / 2 };
                            projectionCenter.x = stageCenter.x;
                            projectionCenter.y = stageCenter.y;
                        }
                        for (child in parent.children) {
                            var layerObj = parent.children[child];
                            if (layerObj == cameraInstance)
                                continue;
                            applyLayerZDepth(layerObj, cameraInstance);
                            if (layerObj.layerDepth === undefined)
                                continue;
                            if (layerObj.currentFrame != layerObj.parent.currentFrame) {
                                layerObj.gotoAndPlay(layerObj.parent.currentFrame);
                            }
                            var matToApply = new createjs.Matrix2D;
                            var cameraMat = new createjs.Matrix2D;
                            var totalDepth = layerObj.layerDepth ? layerObj.layerDepth : 0;
                            var cameraDepth = 0;
                            if (cameraInstance && !layerObj.isAttachedToCamera) {
                                var mat = cameraInstance.getMatrix();
                                mat.tx -= projectionCenter.x;
                                mat.ty -= projectionCenter.y;
                                cameraMat = mat.invert();
                                cameraMat.prependTransform(projectionCenter.x, projectionCenter.y, 1, 1, 0, 0, 0, 0, 0);
                                cameraMat.appendTransform(-projectionCenter.x, -projectionCenter.y, 1, 1, 0, 0, 0, 0, 0);
                                if (cameraInstance.depth)
                                    cameraDepth = cameraInstance.depth;
                            }
                            if (layerObj.depth) {
                                totalDepth = layerObj.depth;
                            }
                            //Offset by camera depth
                            totalDepth -= cameraDepth;
                            if (totalDepth < -focalLength) {
                                matToApply.a = 0;
                                matToApply.d = 0;
                            }
                            else {
                                if (layerObj.layerDepth) {
                                    var sizeLockedMat = getProjectionMatrix(parent, layerObj.layerDepth);
                                    if (sizeLockedMat) {
                                        sizeLockedMat.invert();
                                        matToApply.prependMatrix(sizeLockedMat);
                                    }
                                }
                                matToApply.prependMatrix(cameraMat);
                                var projMat = getProjectionMatrix(parent, totalDepth);
                                if (projMat) {
                                    matToApply.prependMatrix(projMat);
                                }
                            }
                            layerObj.transformMatrix = matToApply;
                        }
                    }
                }
                //Code to support hidpi screens and responsive scaling.
                function makeResponsive(isResp, respDim, isScale, scaleType) {
                    var lastW, lastH, lastS = 1;
                    window.addEventListener('resize', resizeCanvas);
                    resizeCanvas();
                    function resizeCanvas() {
                        var w = lib.properties.width, h = lib.properties.height;
                        var iw = window.innerWidth, ih = window.innerHeight;
                        var pRatio = window.devicePixelRatio || 1, xRatio = iw / w, yRatio = ih / h, sRatio = 1;
                        if (isResp) {
                            if ((respDim == 'width' && lastW == iw) || (respDim == 'height' && lastH == ih)) {
                                sRatio = lastS;
                            }
                            else if (!isScale) {
                                if (iw < w || ih < h)
                                    sRatio = Math.min(xRatio, yRatio);
                            }
                            else if (scaleType == 1) {
                                sRatio = Math.min(xRatio, yRatio);
                            }
                            else if (scaleType == 2) {
                                sRatio = Math.max(xRatio, yRatio);
                            }
                        }
                        canvas.width = w * pRatio * sRatio;
                        canvas.height = h * pRatio * sRatio;
                        canvas.style.width = dom_overlay_container.style.width = anim_container.style.width = w * sRatio + 'px';
                        canvas.style.height = anim_container.style.height = dom_overlay_container.style.height = h * sRatio + 'px';
                        stage.scaleX = pRatio * sRatio;
                        stage.scaleY = pRatio * sRatio;
                        lastW = iw; lastH = ih; lastS = sRatio;
                        stage.tickOnUpdate = false;
                        stage.update();
                        stage.tickOnUpdate = true;
                    }
                }
                makeResponsive(false, 'both', false, 1);
                AdobeAn.compositionLoaded(lib.properties.id);
                fnStartAnimation();
            }
            init();
        }

Be careful because below the code block, I placed init() to run this code when load assets.

My HTML codes:

<body style="margin:0px;"> 
    <div class="OzerAnimasyonContainer" style="background-color:rgba(255, 255, 255, 1.00); width:300px; height:300px">
        <canvas class="OzerAnimasyon" width="300" height="300" style="position: absolute; display: block; background-color:rgba(255, 255, 255, 1.00);"></canvas>
        <div class="OzerAnimasyonOverlay" style="pointer-events:none; overflow:hidden; width:300px; height:300px; position: absolute; left: 0px; top: 0px; display: block;">
        </div>
    </div>
</body>

As you see I deleted onload=”init()” from body. Because we will have multiple animations. Easiest way is, run these animations in window load event.

/* window load */
window.addEventListener("load", function () {
    OzerAnimasyonPlay()
})

Done. You are ready to reproduce it.
Here are you a demo for you, look page source code carefully.

DEMO