Skip to content

Instantly share code, notes, and snippets.

@kyle-wendling
Created June 26, 2021 01:47
Show Gist options
  • Save kyle-wendling/160f7a469ccd9032297970105178209e to your computer and use it in GitHub Desktop.
Save kyle-wendling/160f7a469ccd9032297970105178209e to your computer and use it in GitHub Desktop.
This file has been truncated, but you can view the full file.
// ZIM Cat - Interactive Media Framework at https://zimjs.com - code creativity!
// Also see https://zimjs.com/distill to minify only the functions in your app
// (c) 2021 ZIM - free to use - donations welcome of course! https://zimjs.com/donate
// With thanks...
// Thanks to ZzFX - Zuper Zmall Zound Zynth - Micro Edition for play() method of Synth
// MIT License - Copyright 2019 Frank Force - https://github.com/KilledByAPixel/ZzFX
// Thanks to Josh Forisha - https://github.com/joshforisha for open-simplex-noise-js
// ZIM converted Noise() from https://www.npmjs.com/package/open-simplex-noise
// Thanks to Frank Los for coding the ZIM Keyboard()
// There are several dozen thanks through out the code as well - cheers!
// ZIM is written in ES5. We are aware of ES6 and ES6 modules.
// Here are reasons why we purposefully do not use ES6 and ES6 modules:
// https://github.com/danzen/zimjs/issues/38
// There is no problem using ZIM with ES6 code.
// The many CodePen examples are ES6 and a great place to start:
// https://codepen.io/topic/zim
// We are innovators and inventors at ZIM.
// We work for the people - for the creators
// to make your coding experience as wonderful as possible.
// Please see the MORE section on the following page for treats!
// It outlines UI/UX for end users but also for us, the coders:
// https://zimjs.com/uiux.html
// ZIM is a Framework and rarely needs to be used with
// Node, React, Angular, VUE, Animate, XYZ, etc.
// When it does, a zim namespace can be turned on if desired with zns=true.
// We have provided Node packages for ZIM and CreateJS, SHIM for Adobe,
// and help others on the SLACK at https://zimjs.com/slack (come join us!)
// integrate with "tag" mode into React and VUE, etc.
// but really, we would recommend you try ZIM on its own.
// It is just so easy to paste the template into a Text Editor and go.
// Leave all your outside worries behind and simply enjoy coding with ZIM!
// Let us handle the complexities as a scroll through the code will show! ;-)
// Cheers,
// Dr Abstract, Pragma and ZIM Team
// 2021
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ZIM CODE
// GLOBALS - may not be used if zns (ZIM namespace) is set to true
// If zns is false (default), then zimplify() will run and turn classes, functions and more constants global
// Thanks Stefan Meyer from Uruguay for the ESLint work
// global variable to hold default frame - used by other ZIM modules like physics, etc.
if (typeof window == "undefined") window = {};
var zimDefaultFrame = window.zimDefaultFrame;
var zdf = window.zdf; // short version as long version was starting to add up in minified code ;-)
var createjs = window.createjs; // the expected CreateJS namespace - import CreateJS first
var OPTIMIZE = window.OPTIMIZE;
var ACTIONEVENT = window.ACTIONEVENT;
var KEYFOCUS = window.KEYFOCUS;
var TIMECHECK = window.TIMECHECK;
var TIME = window.TIME;
var STYLE = window.STYLE;
var MOBILE = window.MOBILE;
var LOCALSTORAGE = window.LOCALSTORAGE;
var GET = window.GET;
var POST = window.POST;
var SOCKET = window.SOCKET;
var FIT = window.FIT;
var FILL = window.FILL;
var FULL = window.FULL;
var zimContactListener = window.zimContactListener;
var zimDefaultPhysics = window.zimDefaultPhysics;
var b2ContactListener = window.b2ContactListener;
var b2Vec2 = window.b2Vec2;
// INTRODUCTION
// The code is broken into modules that once were individually available.
// We then introduced ZIM Distill (tree-shaking) as a more efficient way to reduce code
// but we have kept the modules as follows:
// WRAP, CODE, DISPLAY, METHODS, CONTROLS, FRAME, META, and docs only: GAME, THREE, SOCKET, PIZZAZZ
// You can text search a bunch of ////... to get to these.
// The docs also have these modules but ordered differently
// FRAME, DISPLAY, METHODS, CONTROLS, CODE, WRAP, META, GAME, THREE, SOCKET, PIZZAZZ.
// Each entry in the Docs has a VIEW button at the bottom
// that will nicely display the code for that entry - from this document.
// So... there is perhaps, little need to be here ;-).
// The docs are created from the description in this document.
// https://zimjs.com/docs.html
// WARNING: the WRAP and the CODE module at the start here
// are not the focus of the ZIM Framework but rather helper functions
// and even some helper functions for DOM manipulation.
// You may want to skip ahead using //// with a space after to find your way ;-)
//////////////// ZIM WRAP //////////////
// Zim Wrap creates global wrapper functions for less typing
// set var zon=false before calling zim scripts to hide script comments
if (typeof zon == "undefined") var zon = true; // comments from zim scripts
if (typeof zns == 'undefined') var zns = false; // require zim namespace
/*--
zog(item1, item2, etc.) ~ log
zog
global function
DESCRIPTION
Short version of console.log()
to log the item(s) to the console.
Use F12 to open your Browser console.
zog is dedicated to Pragma (Madeline Zen) who was coding with Dr Abstract (Dan Zen) from the start
Also comes in six ZIM colors:
zogg("green");
zogp("pink");
zogb("blue");
zogr("red");
zogy("yellow");
zogo("orange");
Note: If zon (comments on) is set to false before ZIM runs, then all zog() commands are turned off
EXAMPLE
zog("hello", circle.x); // logs these values to the console
END EXAMPLE
PARAMETERS
item1, item2 (optional), etc. - items (expressions) to log to the console
RETURNS items it is logging separated by a space if more than one
--*///+0
// reported a bug in Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1280818
// that after FF 46 binding the console did not show file and line number
// this is fixed in FF 50 - quite the conversation this stirred
var zog = zon?console.log.bind(console):function(){};
// Thanks Ami and Yalon for the technique
var zogStyle = " border:thin solid black; color: black";
var zogg = zon?console.log.bind(console, "%c Z ", "background: #acd241;"+zogStyle):function(){};
var zogp = zon?console.log.bind(console, "%c Z ", "background: #e472c4;"+zogStyle):function(){};
var zogb = zon?console.log.bind(console, "%c Z ", "background: #50c4b7;"+zogStyle):function(){};
var zogr = zon?console.log.bind(console, "%c Z ", "background: #fb4758;"+zogStyle):function(){};
var zogy = zon?console.log.bind(console, "%c Z ", "background: #ebcb35;"+zogStyle):function(){};
var zogo = zon?console.log.bind(console, "%c Z ", "background: #f58e25;"+zogStyle):function(){};
var zogl = zon?console.log.bind(console, "%c Z ", "background: #eeeeee;"+zogStyle):function(){};
var zogd = zon?console.log.bind(console, "%c Z ", "background: #444444; border:thin solid black; color: white"):function(){};
//-0
/*--
zid(string) ~ id
zid
global function
DESCRIPTION
Short version of document.getElementById(string)
to access an HTML tag by its id.
EXAMPLE
zid("logo").addEventListener("click", function(){});
END EXAMPLE
PARAMETERS
string - the id of the tag you are wanting to access
RETURNS HTML tag with id of string or null if not found
--*///+1
function zid(s) {
z_d("1");
return document.getElementById(s);
} //-1
/*--
zss(string) ~ css
zss
global function
DESCRIPTION
Short version of document.getElementById(string).style
to access the style property of an HTML tag by the tag id.
EXAMPLE
zss("logo").margin = "10px";
END EXAMPLE
PARAMETERS
string - the id of the tag whose style you are wanting to access
RETURNS style property of HTML tag with id of string or undefined if not found
--*///+2
function zss(s) {
z_d("2");
if (document.getElementById(s)) {return document.getElementById(s).style;}
else if (zon) zogy("zss(): id not found");
} //-2
/*--
zgo(url, target, width, height, fullscreen, modal) ~ go
zgo
global function
DESCRIPTION
Short version of either window.location.href or window.open
to open a link in the same window or a specified window.
EXAMPLE
zid("logo").addEventListener("click", function(){zgo("https://zimjs.com");});
// with a ZIM object:
var button = new Button();
button.center();
button.on("click", function() {zgo("http://zimjs.com");});
END EXAMPLE
PARAMETERS
url - the link to use (Absolute, Relative or Virtual)
target - (default null) the string name of a window (tab) _blank for new window each time
width - (default null) width of window (use with fullscreen true)
height - (default null) height of window (use with fullscreen true)
fullscreen - (default null) not really full screen but rather opens in a new window not tab
modal - (default false) set to true to force user to close window
RETURNS null if opening in same window or reference to the window otherwise
--*///+3
function zgo(u,t,w,h,f,m) {
z_d("3");
if ((zot(t) && t != "") || t == "_self") {
window.location.href = u;
} else {
var added = "";
if (w) added += "width=" + w + ",";
if (h) added += "height=" + h + ",";
if (f) added += "fullscreen=yes,";
if (m) added += "modal=yes,alwaysRaised=yes";
return window.open(u,t,added);
}
} //-3
/*--
zum(string) ~ num
zum
global function
DESCRIPTION
Takes the units off a string number.
Converts "10px" string from styles to number 10, for instance.
If there is no value then this will return 0.
EXAMPLE
// in HTML
<div id="logo" style="position:relative; left:10px">LOGO</div>
// in JavaScript
var left = zum(zss("logo").left); // converts 10px to the Number 10
left += 20; // adds 20 to 10
zss("logo").left = left + "px"; // assigns 30px to left style
END EXAMPLE
PARAMETERS
string - the string representation of a number eg. "10px"
RETURNS a Number
--*///+4
function zum(s) {
z_d("4");
if (zot(s)) return;
return Number(String(s).replace(/[^\d\.\-]/g, ''));
} //-4
/*--
zot(value) ~ not
zot
global function
DESCRIPTION
Test to see if value has no value (value must exist as var or parameter)
or if value has been set to null.
Good for setting function defaults.
Really just asking if the value == null.
Often we forget exactly how to do this - it is tricky:
value === null, value == undefined, value == 0, !value DO NOT WORK.
EXAMPLE
if (zot(width)) width = 100;
// equivalent to
if (width == null) width = 100;
END EXAMPLE
PARAMETERS
value - a variable or parameter you want to see if there is no value assigned
RETURNS Boolean true if value does not exist
--*///+4.5
function zot(v) {
return v==null; // both null and undefined match but not false or 0
}//-4.5
/*--
zop(e) ~ stop
zop
global function
DESCRIPTION
Stop event propagation to subsequently added existing listeners.
Must pass it e || window.event from your event function.
NOTE: this is not canceling the default action -
to cancel default action use e.preventDefault();
EXAMPLE
zid("button").addEventListener("click", function(e) {
// do something
zop(e||window.event);
});
END EXAMPLE
PARAMETERS
e - the event object from your event function
collect the event object as e and then pass in e || window.event
RETURNS null
--*///+5
function zop(e) {
z_d("5");
if (zot(e)) return;
if (e.stopImmediatePropagation) e.stopImmediatePropagation();
if (window.event) window.event.cancelBubble=true;
} //-5
/*--
zil() ~ still
zil
global function
DESCRIPTION
Stop keys from moving content - arrows, spacebar, pgup, pgdown, home, end.
Stop scroll wheel from moving content - scrolling the canvas for instance.
ZIM Frame does this in the full, fit and outside scale modes.
If not using Frame, then you can do this once at the start of your code.
Returns an array of references to three listeners: [keydown, wheel and DOMMouseScroll].
Use these to removeEventListeners.
The arrows, etc, still work but just not their default window behaviour.
EXAMPLE
// at the top of your code
var listenersArray = zil();
// key and mousewheel arrows, spacebar, etc.
// will have their default actions stopped until you remove the listeners:
// window.removeEventListener("keydown", listenersArray[0]); // etc.
END EXAMPLE
RETURNS an Array
--*///+6
function zil() {
z_d("6");
var a = function(e) {if (!e) e = event; if (e.keyCode && (e.keyCode >= 32 && e.keyCode <= 40)) e.preventDefault();};
var b = function(e) {if (!e) e = event; e.preventDefault();};
var c = b;
window.addEventListener("keydown", a, {passive:false});
window.addEventListener("wheel", b, {passive:false});
window.addEventListener("DOMMouseScroll", c, {passive:false});
return [a, b, c];
} //-6
/*--
zet(selector) ~ set
zet
global function
DESCRIPTION
Uses document.querySelectorAll() to get a list of tags.
Returns a ZIM Zet object which can be used to add events or styles to the set.
EXAMPLE
zet(".class").on("click", function(){}); // would add function event to all tags with the class
zet("p").css("color", "goldenrod"); // would make the text of all paragraphs goldenrod
zet("#test").css({color:"red", "background-color":"blue", paddingLeft:"20px"});
// set a custom open property on all section bars to false
zet("section .bar").prop("open", false);
// set the custom open property on all section bars to true and set the innerHTML to CLOSE
zet("section .bar").prop({open: true, innerHTML: "CLOSE"});
END EXAMPLE
PARAMETERS
selector - a CSS query selector such as a class, id, tag, or multiple selectors separated by commands
can also be complex selectors suchs as ".class img"
METHODS (on the returned Zet object)
zet(selector).on(type, function) - a shortcut for addEventListener() and will be added to all tags matching the selector
zet(selector).off(type, function) - a shortcut for removeEventListener() and will be remove from all tags matching the selector
zet(selector).css(property, value) - gets and sets styles
- gets the first programmatic property if a single string property is passed
- sets the property to the value on each of the Zet's tags from the selector passed to zet()
- if an object of properties and values is passed as the single parameter then sets all these properties
- NOTE: style names do not need quotes unless the dash is used - so camelCase does not require quotes
- NOTE: remember that commas are used for objects - not the semi-colon as in CSS
zet(selector).prop(property, value) - gets or sets a property on a set of tags
- if an object of properties and values is provided as a single parameter, then sets all these on the set
- else if no value is set then returns an array of the set tags values for the property
- else if value is a single value then sets the property of the tags in the set to the value
PROPERTIES (on the returned Zet object)
tags - an HTML NodeList tag list
RETURNS Zet object with on(), off(), css() methods and tags property (NodeList tag list)
--*///+6.1
function zet(selector) {
z_d("6.1");
function Zet() {
var that = this;
this.on = function(type, call) {
if (zot(selector) || zot(type) || zot(call)) return;
var tags = that.tags;
for (var i=0; i<tags.length; i++) {
tags[i].addEventListener(type, call);
}
};
this.off = function(type, call) {
if (zot(selector) || zot(type) || zot(call)) return;
var tags = that.tags;
for (var i=0; i<tags.length; i++) {
tags[i].removeEventListener(type, call);
}
};
Object.defineProperty(that, 'tags', {
get: function() {
if (zot(selector)) return [];
if (typeof selector == 'string' || selector instanceof String) {
return document.querySelectorAll(selector);
} else { // selector is already an object - assume a tag
if (typeof (selector).innerHTML == "string") return [selector];
return [];
}
},
set: function() {
}
});
this.css = function(property, value) {
// if property is object then assign all props in object
var tags = that.tags;
for (var i=0; i<tags.length; i++) {
if (arguments.length == 1 && arguments[0].constructor === {}.constructor) {
for (var p in property) {
tags[i].style[p] = property[p];
}
} else if (arguments.length == 1) {
return that.tags[0].style[property];
} else {
tags[i].style[property] = value;
}
}
};
this.prop = function(property, value) {
if (zot(property)) return;
var tags = that.tags;
var a = [];
for (var i=0; i<tags.length; i++) {
if (zot(value)) {
if (property.constructor === {}.constructor) {
for (var p in property) {
tags[i][p] = property[p];
}
} else {
a.push(tags[i][property]);
}
} else {
tags[i][property] = value;
}
}
if (zot(value)) return a;
};
}
return new Zet();
} //-6.1
/*--
zob(func, args, sig, scope) ~ object
zob
global function
DESCRIPTION
A system to build functions or classes that allow traditional parameters
or a configuration object passed in as a single parameter.
The configuration object has property names that match the function arguments.
To use zob on your own functions, pass in a function and the function's arguments
and insert zob into first line of your function as shown below.
Replace yourFunction with a reference to your function but keep arguments as is.
EXAMPLE
function test(a,b,c){
var duo; if (duo = zob(test, arguments)) return duo;
};
test(1,null,3); // traditional parameters in order
test({a:1,c:3}); // configuration object with zob
END EXAMPLE
NOTE: if you are running the function as a constructor with the new keyword
then you need to pass in this (keyword) as the last parameter (sig can be null)
this allows zob() to test to see if we need to rerun the function as a constructor
EXAMPLE
var duo; if (duo = zob(yourFunction, arguments, sig, this)) return duo;
END EXAMPLE
NOTE: if using an ES6 Class or minifying the file then you need to do an extra step
add a string version of the signature of your function above the duo call
then pass the signature in as a parameter to zob()
EXAMPLE
class Test extends Container {
constructor(a=1,b=2,c=3) {
super();
var sig = "a,b,c";
var duo; if (duo = zob(Test, arguments, sig, this)) return duo;
}
}
END EXAMPLE
many of the ZIM functions and classes use this "DUO" technique
the documentation for parameters will tell you if they support DUO
works also with JS6 default parameter values
PARAMETERS
func - reference to the function you want to use params or a config object with
args - reference to the arguments property of the function (literally, use "arguments" with no quotes)
sig - (default null) a string listing of the parameters just how they are in the () not including the ()
required if you are minifying the file as minifying changes the signature
scope - (default null) reference to this (litterally, use "this" without the quotes)
required if the function is being run with the new keyword
RETURNS um... a Boolean
--*///+7
function isDUO(a) {return a.length == 1 && a[0] != undefined && a[0].constructor === {}.constructor;}
function zob(func, args, sig, scope) {
var zimon = (zim && (zim.ZIMONON || ZIMONON));
if (isDUO(args)) {
z_d("7");
var zp = args[0];
var za = (zot(sig))?func.toString().split(/\n/,1)[0].match(/\((.*)\)/)[1].replace(/\s+/g,"").split(","):sig.replace(/\s+/g,"").split(",");
var zv = []; var zi; var zt;
for (zi=0; zi<za.length; zi++) {zt=za[zi].split("=")[0]; za[zi]=zt; zv.push(zp[zt]);}
for (zi in zp) {if (za.indexOf(zi)<0) {if (zon) zogy(func,"bad argument "+zi);}}
var zr; if (zr=(func.prototype.isPrototypeOf(scope))?new (func.bind.apply(func,[null].concat(zv)))():func.apply(null,zv)) {if (zimon && !zr.arguments) {zr.arguments = [zp];} return zr;} else {return true;}
} else {
if (zimon && scope && args && zot(scope.arguments)) {
scope.arguments = Array.prototype.slice.call(args);
}
}
}//-7
/*--
zik(Array|function|object|Pick) ~ pick
zik
global function
DESCRIPTION - DEPRECIATED as of ZIM 10
Has now been replaced with ZIM Pick() class which formalizes zik() and ZIM VEE into a more general class.
See ZIM Pick() under the Code module Classes.
--*///+7.5
function zik(v) {
z_d("7.5");
z_d("17.6");
if (zot(v)) return;
return zim.Pick.choose(v);
}//-7.5
/*--
zta(item1, item2, etc.) ~ table
zta
global function
DESCRIPTION
Short version of console.table()
to log the Arrays or Objects to the console as a table
Use F12 to open your Browser console.
Note: if zon (comments on) is set to false before ZIM runs then all zta() commands will be turned off
EXAMPLE
zta(["will", "this", "wind"]); // logs as a table
END EXAMPLE
PARAMETERS
item1, item2 (optional), etc. - Arrays or Objects to log to the console
RETURNS items it is logging
--*///+7.6
var zta = console.table&&zon?console.table.bind(console):function(){};
//-7.6
/*--
zor(item1, item2, etc.) ~ or
zor
global function
DESCRIPTION
picks the first non-null defined item so WILL pick a 0
EXAMPLE
var a = 0;
var x = zor(a,10); // x is 0
var y = zor(x,10); // y is 0
// note:
var z = a||10; // z is 10
var c;
var w = zor(c,a,20); // w is 0
END EXAMPLE
PARAMETERS
item1, item2 (optional), etc. - objects to test in order
RETURNS first non-null defined item or undefined if no valid items
--*///+7.7
var zor = function() {
for(var i=0; i<arguments.length; i++) {
if (!zot(arguments[i])) return arguments[i];
}
};
//-7.7
// the above functions are global for quick usage
// start the zim module pattern - from here on, everything is stored on the zim namespace
var zim = function(zim) {
//////////////// ZIM CODE //////////////
// Zim Code adds some general code functionality along with Browser and DOM code
// some of these are common Web solutions over the years (sorry for lack of credit)
// SUBSECTION FEATURED
/*--
zim.chop = function(obj, cols, rows, tile, margin)
chop
zim function
DESCRIPTION
Breaks up any DisplayObject into a grid of cols and rows and returns Tile or an array of Bitmap objects.
Handy to pass to a Scrambler().
See https://zimjs.com/explore/chop.html
See https://zimjs.com/cat/scrambler.html
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// A chopped Circle animating like pixels
chop(new Circle(200,red),20,20)
.center()
.noMouse()
.animate({
props:{alpha:0},
time:{min:.1, max:.4},
rewind:true,
loop:true,
sequence:.02
});
END EXAMPLE
EXAMPLE
new Scrambler(chop(asset("pic.jpg"),4,4)).center();
END EXAMPLE
PARAMETERS
obj - a ZIM DisplayObject like an asset() or Circle(), etc.
cols - the number of cols to break object into
rows - the number of rows to break object into
tile - (default true) return a Tile - set to false to return an array of Bitmaps
margin - (default 0) add a margin to image - will be outside bounds
RETURNS a Tile or an array of Bitmaps depending on tile parameter
--*///+7.8
zim.chop = function(obj, cols, rows, tile, margin) {
z_d("7.8");
if (zot(obj)) return;
if (zot(cols)) cols = 3;
if (zot(rows)) rows = 3;
if (zot(tile)) tile = true;
if (zot(margin)) margin = 0;
var w = obj.width/cols;
var h = obj.height/rows;
var m = margin;
var pieces = [];
zim.loop(rows, function (r) {
zim.loop(cols, function (c) {
var p = new zim.Bitmap(obj, w+m*2, h+m*2, c*w-m, r*h-m);
if (margin != 0) {
p.setBounds(m,m,w,h);
p.regX = m;
p.regY = m;
}
pieces.push(p);
});
});
if (tile) return new zim.Tile(pieces,cols,rows,0,0,true);
else return pieces;
};//-7.8
/*--
zim.shuffle = function(array)
shuffle
zim function
DESCRIPTION
Randomly shuffles elements of an array.
Actually changes the original array (and also returns it).
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var array = ["happy", "sad", "spooked"];
var randomFromArray = shuffle(array)[0];
// this will be randomized each time it is run
END EXAMPLE
EXAMPLE
var array = shuffle(["happy", "sad", "spooked"]);
for (var i=0; i<array.length) zog(array[i]);
// this will get random and unique elements of the array
END EXAMPLE
PARAMETERS
array - the Array to shuffle
RETURNS the modified Array
--*///+8
zim.shuffle = function(array) {
z_d("8");
if (zot(array)) return;
var i = array.length, j, temp;
if (i == 0) return array;
while(--i) {
j = Math.floor(Math.random()*(i+1));
temp=array[i];
array[i]=array[j];
array[j]=temp;
}
return array;
};//-8
/*--
zim.rand = function(a, b, integer, negative)
rand
zim function
DESCRIPTION
Returns a random integer between and including a and b if integer is true.
Returns a random number (with decimals) including a and up to b but not b if integer is false.
b is optional and if left out will default to 0 (includes 0).
integer is a boolean and defaults to true.
If a and b are 0 then just returns Math.random().
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var speed = rand(10,20); // 10, 11, 12... 18, 19 or 20
var colors = ["blue", "yellow", "green"];
var color = colors[rand(colors.length-1)]; // note the length-1
// the equivalent of:
var color = colors[Math.floor(Math.random()*colors.length)];
// OR a technique often used without using rand():
var color = shuffle(colors)[0];
// here we get a speed that is either from 5 to 10 or -5 to -10
var speed = rand(5,10,null,true);
END EXAMPLE
PARAMETERS
a - the first Number for the range
if a and b are not provided, rand() acts like Math.random()
if parameter b is not provided, rand will use range 0 to and including a
b - (default 0) second Number for the range
it does not matter if a>b or a<b
integer - (default true) set to false to include decimals in results
if false, range will include decimals up to but not including the highest number
if a or b have decimals this is set to false
negative - (default false) includes the negative range as well as the positive
RETURNS a Number
--*///+9
zim.rand = function(a, b, integer, negative) {
z_d("9");
if (zot(a) && zot(b)) return Math.random();
if (zot(a) || isNaN(a)) a = 0;
if (zot(b) || isNaN(b)) b = 0;
if (a%1!=0 || b%1!=0) integer = false;
if (zot(integer)) integer = true;
if (negative) if (Math.random()>.5) {a*=-1; b*=-1;}
if (integer) if (a>b) {a++;} else if (b>a) {b++;}
var r;
if (a == 0 && b == 0) return 0;
else if (b == 0) r = Math.random()*a;
else r = Math.min(a,b) + Math.random()*(Math.max(a,b)-Math.min(a,b));
if (integer) return Math.floor(r);
else return r;
};//-9
/*--
zim.series = function(array|item1|obj, item2, item3)
series
zim function
DESCRIPTION
Returns a function that will return each value passed as a parameter (or an Array) in order
or an object literal with min and max.
This goes in sequence each time the function is called.
Use this to pass a series in to any ZIM VEE value so a looping series is obtained.
NOTE: was called makeSeries() which is now depricated
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// note - do not call the variable name series
var colors = series(red, green, blue);
colors(); // red
colors(); // green
colors(); // blue
colors(); // red, etc.
// or
var colors = [red, green, blue];
var s = series(colors);
s(); // red
s(); // green
s(); // blue
s(); // red, etc.
new Tile(new Rectangle(10,10,[blue, red]), 10, 10); would randomize colors
new Tile(new Rectangle(10,10,series(blue, red)), 10, 10); would alternate colors
END EXAMPLE
EXAMPLE
STYLE = {color:series(pink, green, blue)}
loop(9, function (i) {
new Circle(100).loc(110+i*100, 400)
});
END EXAMPLE
EXAMPLE
// ten rectangles getting higher by 20 each time
var s = series({min:10, max:200}).step(20);
loop(10, function (i) {
new Rectangle(10, s, red).sca(1,-1).loc(100+i*20, 400);
});
END EXAMPLE
EXAMPLE
// added functionality as of ZIM 10.9.0
// start at index 3, reverse and don't go past 0
var nums = series(0, 1, 2, 3, 4).jump(3).reverse().constrain();
loop(5, function(){
zogb(nums()); // 3,2,1,0,0 (blue in console)
});
nums.reverse(false); // go forward - note, still starting at index 0
zogg(nums()); // 0 (green in console)
zogg(nums()); // 1
zogg(nums()); // 2
nums.bounce(); // go back and forth rather than default loop
loop(5, function(){
zogy(nums()); // 3,4,3,2,1 (yellow in console)
});
nums.step(3); // sitting at 0 then increase the step to 3
loop(5, function(){
zogr(nums()); // 0,3,2,1,4 (red in console)
// 3->6 bounces off 4 with two back to 2
// 2->-1 bounces off 0 with one forward to 1
// tricky but correct
});
zogp(nums.index); // 1 - coming back 3 steps from 4 to 1 as current index
END EXAMPLE
PARAMETERS
array|item1|{min,max,step} - the first item - or an array of results that will be called in order as the resulting function is called
or an object with min, max and step properties to make a series of numbers from and including min and max (step defaults to 0)
this will make an array of values and then it is just like an array was entered initially.
when used with ZIM VEE - the values may be further ZIM VEE values (including more series values)
item2 - the second item if the first is not an array
item3 - the third item, etc. to as many items as needed
METHODS
step(num) - num defaults to 1 - the number of items to move the index - or use index property
every(num) - num defaults to 0 - steps to wait before moving to the next index - remain on blue for five, then go to yellow for five, etc.
jump(index) - jump to an index but do not run it - the next call to the series will run here
reverse(boolean) - boolean defaults to true - reverses direction - or pass in false to cancel reverse
bounce(boolean) - boolean defaults to true - back and forth between 0 and length-1 - or pass in false to cancel bounce
constrain(boolean) - boolean defaults to true - keeps index between 0 and length-1 - or pass in false to cancel constrain
PROPERTIES
array - an array of items passed in to the function
length - the length of the series
index - get or set the current index of the series - what will run next
RETURNS a function that can be called many times - each time returning the next value in the series
--*///+13.61
zim.series = function() {
z_d("13.61");
var array;
var range;
if (arguments.length == 0) return function(){};
if (arguments.length == 1 && Array.isArray(arguments[0])) {
array = arguments[0];
} else if (arguments.length == 1 && arguments[0].constructor == {}.constructor) {
range = arguments[0];
if (zot(range.min)) range.min = 0;
if (zot(range.max)) range.max = 1;
if (zot(range.step)) range.step = 1;
array = [];
zim.loop(Math.floor(Math.abs(range.max-range.min)+range.step), function (i) {
array.push(i+range.min);
}, null, range.step);
range = null;
} else {
array = Array.prototype.slice.call(arguments);
}
var count = 0;
var dir = 1;
var step = 1;
var every = 0;
var everyCount = 0;
var bounce = false;
var constrain = false;
var lastVal;
var f = function() {
if (every && everyCount%(every) != 0) {
everyCount++;
return lastVal;
}
everyCount++;
var length = array.length;
var val;
val = array[(length*10+count)%length];
if (bounce) {
if (dir > 0 && count+dir*step >= length) {
dir = -1;
count = (length-1)-(count+step-(length-1));
} else if (dir < 0 && count+dir*step < 0) {
dir = 1;
count = step - count;
} else {
count += dir*step;
}
} else if (constrain) {
if (dir > 0 && count+dir*step >= length) count = length-1;
else if (dir < 0 && count+dir*step < 0) count = 0;
else count += dir*step;
} else {
count += dir*step;
}
lastVal = val;
return val;
};
f.array = array;
f.type = "series";
Object.defineProperty(f, 'index', {
get: function() {
var length = array.length;
return (length*10+count)%length;
},
set: function(value) {
count = value;
}
});
f.jump = function(value) {
count = value;
return f;
};
f.reverse = function(value) {
if (zot(value)) value = true;
if (value) dir = -1;
else dir = 1;
count = array.length-1;
return f;
};
f.bounce = function(value) {
// normalize count
if (zot(value)) value = true;
var length = array.length;
count = (length*10+count)%length;
bounce = value;
return f;
};
f.step = function(value) {
if (zot(value)) value = 1;
step = Math.floor(value);
return f;
};
f.every = function(value) {
if (zot(value)) value = 1;
every = Math.abs(value);
everyCount = 0;
return f;
};
f.constrain = function(value) {
if (zot(value)) value = true;
constrain = value;
return f;
};
return f;
};//-13.61
/*--
zim.makeSeries = function(array)
depreciated - use series()
--*///+13.6
zim.makeSeries = function(array) {
z_d("13.6");
if (zot(array)) return function(){};
var count = 0;
var f = function() {
return array[(count++)%array.length];
};
f.array = array;
return f;
};//-13.6
/*--
zim.loop = function(obj, call, reverse, step, start, end)
loop
zim function
DESCRIPTION
1. If you pass in a Number for obj then loop() does function call that many times
and passes function call the currentIndex, totalLoops, startIndex, endIndex, obj.
By default, the index starts at 0 and counts up to one less than the number.
So this is like: for (var i=0; i<obj; i++) {}
There are step, start and end index parameters - start cannot be negative
2. If you pass in an Array then loop() loops through the array
and passes the function call the element in the array, currentIndex, totalLoops, startIndex, endIndex and the array.
So this is like: for (var i=0; i<obj; i++) {element = array[i];}
3. If you pass in an Object literal then loop() loops through the object
and passes the function call the property name, value, currentIndex, totalLoops, startIndex, endIndex, obj
So this is like: for (var i in obj) {property = i; value = obj[i];}
4. If you pass in an String then loop() loops through the letters
and passes the function call the letter, currentIndex, totalLoops, startIndex, endIndex, obj.
So this is like: for (var i=0; i<obj.length; i++) {letter = obj[i];}
5. If you pass an HTML NodeList or HTMLCollection then loop() loops and gives each tag in the NodeList or HTMLCollection
see ZIM zet() for an example of getting a NodeList (like the $() in JQuery)
6. See also the loop method under ZIM Methods to see how to loop through a ZIM Container
NOTE: If you pass in true for reverse, the loop is run backwards counting to 0 (by default)
NOTE: use return to act like a continue in a loop and go to the next loop
NOTE: return a value to return out of the loop completely like a break (and return a result if desired)
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var container = new Container();
loop(1000, function(i) { // gets passed an index i, totalLoops 1000, startIndex 0, endIndex 999, obj 1000
// make 1000 rectangles
container.addChild(new Rectangle().loc(rand(stageW-100), rand(stageH-100)));
});
stage.addChild(container);
// to continue or break from loop have the function return the string "continue" or "break"
loop(10, function(i) {
if (i%2==0) return; // skip even
if (i>6) return "break"; // quit loop when > 6
zog(i);
});
loop(10, function(i) {
zog(i); // 9-0 in console
}, true);
loop(10, function (i) {
zog(i); // 5-9
}, null, 1, 5)
// the start parameter cannot be less than 0
// to get negative values for i subtract a desired value inside the loop
var colors = [green, yellow, pink];
loop(colors, function(color, index, start, end, array) { // do not have to collect all these
zog(color); // each color
});
var array = [0,0,0,1,0,0,0];
var pass = loop(array, function(val) {
if (val!=0) return false;
});
// below will log failed
if (pass) zog("passed"); // by default loop returns true (as of ZIM 10.6.1)
else zog("failed"); // false inside loop gets assigned to pass
var person = {name:"Dan Zen", occupation:"Inventor", location:"Dundas"}
var result = loop(person, function(prop, val, index, total, start, end, object) { // do not have to collect all these
zog(prop, val); // each key value pair
if (val == "criminal") return "criminal"; // this would return out of the loop to the containing function
});
if (result == "criminal") alert("oh no!");
var tags = zet(".heading").tags; // get an NodeList of tags styled with heading class
loop(tags, function(tag, i) {
tag.innerHTML = i + ". " + tag.innerHTML; // add an index number in front
});
END EXAMPLE
PARAMETERS supports DUO - parameters or single object with properties below
obj - a Number of times to loop or an Array or Object, String or NodeList to loop through
call - the function to call
the function will receive (as its final parameters) the index, total, start, end, obj
where the index is the current index, total is how many times the loop will run
start is the start index, end is the end index and obj is the object passed to the loop
the starting parameters vary depending on the type of obj:
if the obj is a number then the first parameter is the index (no extra starting parameters given)
if the obj is an array then the first parameter is the element at the current index
if the obj is an object literal then the first and second parameters are the property name and property value at the current index
if the obj is an string then the first parameter is the letter
if the obj is an HTMLCollection then the first parameter is the tag
reverse - (default false) set to true to run the loop backwards to 0
step - (default 1) each step will increase by this amount (positive whole number - use reverse to go backwards)
start - (default 0 or length-1 for reverse) index to start
end - (default length-1 or 0 for reverse) index to end
RETURNS any value returned from the loop - or true if no value is returned from a loop
--*///+9.5
zim.loop = function(obj, call, reverse, step, start, end) {
var sig = "obj, call, reverse, step, start, end";
var duo; if (duo = zob(zim.loop, arguments, sig)) return duo;
z_d("9.5");
if (zot(obj) || zot(call)) return undefined;
if (zot(reverse)) reverse = false;
if (zot(step) || step <= 0) step = 1;
var type = typeof obj=="number"?"number":(obj.constructor === Array?"array":(obj.constructor === {}.constructor?"object":(typeof obj == "string"?"string":(obj instanceof NodeList?"nodelist":(obj instanceof HTMLCollection?"htmlcollection":"invalid")))));
if (type == "invalid") {
return undefined;
}
if (type == "number" || type == "string" || type == "array" || type == "nodelist" || type == "htmlcollection") {
var length = type=="number"?obj:obj.length;
var total = getTotal(length-1);
if (total == 0) return true;
if (reverse) {
for(var i=start; i>=end; i-=step) {
var r;
if (type=="number") {
r = call(i, total, start, end, obj);
} else if (type=="array" || type=="string") {
r = call(obj[i], i, total, start, end, obj);
} else { // nodelist
r = call(obj.item(i), i, total, start, end, obj);
}
if (typeof r != 'undefined') return r;
}
} else {
for(var i=start; i<=end; i+=step) {
var r;
if (type=="number") {
r = call(i, total, start, end, obj);
} else if (type=="array" || type=="string") {
r = call(obj[i], i, total, start, end, obj);
} else { // nodelist or htmlcollection
r = call(obj.item(i), i, total, start, end, obj);
}
if (typeof r != 'undefined') return r;
}
}
return true;
} else if (type == "object") {
var length = 0;
var props = [];
for (var i in obj) {
length++;
props.push(i);
}
var total = getTotal(length-1);
if (total == 0) return;
if (reverse) {
for(var i=start; i>=end; i-=step) {
var r = call(props[i], obj[props[i]], i, total, start, end, obj);
if (typeof r != 'undefined') return r;
}
} else {
for(var i=start; i<=end; i+=step) {
var r = call(props[i], obj[props[i]], i, total, start, end, obj);
if (typeof r != 'undefined') return r;
}
}
return true;
}
function getTotal(max) {
if (zot(start)) start = reverse?max:0;
if (zot(end)) end = reverse?0:max;
if ((reverse && end > start) || (!reverse && start > end)) return 0;
if ((start < 0 && end) <0 || (start > max && end > max)) return 0;
start = Math.max(0, Math.min(start, max));
end = Math.max(0, Math.min(end, max));
return Math.floor((reverse?(start-end):(end-start)) / step) + 1;
}
};//-9.5
/*--
getTIME = function(time, timeType, minWarning, maxWarning, noWarning)
getTIME
global function
Checks for TIME and timeUnit
Used internally by interval, timeout, animate and others
returns the time unit as "s" or "m"
~~~~~~~~~~~~~~
checkTIME = function(time, timeChar, minWarning, maxWarning)
checkTIME
globalFunction
Tests to see if time is in expected units - timeChar is "s" or "m" for seconds or milliseconds
logs a warning if ((timeChar="s" && time>minWarning) || (timeChar=="m" && time<maxWarning))
Set TIMECHECK = false to turn off check if desired - for instance if getting false positives
--*///+9.99
function getTIME(time, timeUnit, minWarning, maxWarning, noWarning) {
if (!zim.timeCheck) {z_d("9.99"); zim.timeCheck=true;}
var timeType = zot(TIME) ? zot(zim.TIME) ? "seconds" : zim.TIME : TIME;
if (timeType && timeType.toLowerCase) timeType = timeType.toLowerCase();
if (timeType != "milliseconds" && timeType != "ms") timeType = "seconds";
if (timeUnit && timeUnit.toLowerCase) timeUnit = timeUnit.toLowerCase();
if (timeUnit=="ms" || timeUnit=="milliseconds" || timeUnit=="seconds" || timeUnit=="s") timeType = timeUnit;
if (zot(time)) return timeType.charAt(0);
if (timeType=="ms") timeType = "milliseconds";
if (timeType=="s") timeType = "seconds";
timeType = timeType.charAt(0);
if (!noWarning) checkTIME(time, timeType, minWarning, maxWarning);
return timeType;
}
function checkTIME(time, timeChar, minWarning, maxWarning) {
if (zot(minWarning)) minWarning = 10;
if (zot(maxWarning)) maxWarning = 9;
if (!zim.TIMECHECK && !TIMECHECK) return;
if ((timeChar!="m" && time>minWarning) || (timeChar=="m" && time<maxWarning)) {
if (zon) zogy("TIME - warning: time is in "+(timeChar=="m"?"milliseconds":"seconds")+ " ("+time+")");
}
}
//-9.99
/*--
zim.timeout = function(time, call, pauseOnBlur, timeUnit)
timeout
zim function
DESCRIPTION
Calls a function after the time delay - like window.setTimeout()
Uses window.requestAnimationFrame() that tends to rest when the window is not showing
NOTE: as of ZIM Cat time is in seconds not milliseconds.
Set TIME = "milliseconds"; to set all ZIM time to milliseconds
or pass in "milliseconds" to the timeUnit parameter for a specific override.
NOTE: setTimeout has the time parameter last, timeout has it first
so that it is consistent with loop() and the CreateJS on() method
NOTE: to clear a timeout you use returnID.clear() - different than window.clearTimeout(returnID)
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
timeout(1, function(){
circle.x += 100;
stage.update();
});
// moves the circle 100 pixels after one second
// GAME to press button within one second:
var timeout = timeout(1, function() {
zog("you lose!");
button.enabled = false;
});
var button = new Button().center();
button.on("click", function() {
zog("you win!");
timeout.clear();
});
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports VEE - parameters marked with ZIM VEE mean a zim Pick() object or Pick Literal can be passed
Pick Literal formats: [1,3,2] - random; {min:10, max:20} - range; series(1,2,3) - order, function(){return result;} - function
time - |ZIM VEE| seconds to wait until function is called
see TIME global constant (defaults to "seconds") can also override with timeUnit parameter set to "milliseconds"
call - function to call when the time passes - will receive the id object as a single parameter
pauseOnBlur - (default false) set to true to pause timeout when window is reduced or another tab gains focus
timeUnit - (default TIME) set to "milliseconds" for traditional JavaScript milliseconds
also see TIME constant which defaults to "seconds"
timeUnit will override the TIME constant
RETURNS a ZIM timeoutObject to pause and clear the timeout with the following methods and properties:
METHODS - of ZIM timeoutObject
pause(state, immediate, restart) - (default true) will pause the timeout - set to false to unpause the timeout at the time remaining
immediate (default false) set to true to make the timeout function run right away when unpausing (no effect when pausing)
reset (default false) set to true to set the timeout back to 0 time passed when unpausing (no effect when pausing)
clear() - will clear the timeout
PROPERTIES - of ZIM timeoutObject
time - the time that has lapsed (in the timeUnit)
paused - the paused state of the timeout
done - true if finished
timeUnit - get the timeUnit used at start
--*///+9.7
zim.timeout = function(time, call, pauseOnBlur, timeUnit) {
var sig = "time, call, pauseOnBlur, timeUnit";
var duo; if (duo = zob(zim.timeout, arguments, sig, this)) return duo;
z_d("9.7");
if (zot(call)) return;
if (typeof call != 'function') return;
var timeType = getTIME(time, timeUnit);
if (zot(time)) time = timeType=="s"?1:1000;
time = zim.Pick.choose(time);
var obj = {startTime:Date.now(), time:0, paused:false, done:false, timeUnit:timeUnit};
if (pauseOnBlur) {
if (zot(zim.blurCheck)) zim.setBlurDetect();
zim.pauseOnBlur.push(obj);
}
var lastTime = obj.startTime;
function next() {
var now = Date.now();
obj.time += (now - lastTime)/(timeType=="s"?1000:1);
lastTime = now;
if (obj.time >= time) {
obj.done = true;
(call)(obj);
obj.clear();
return;
}
obj.rid = requestAnimationFrame(next);
}
obj.pause = function(state, immediate, reset) {
if (zot(state)) state = true;
if (state) { // pausing
cancelAnimationFrame(obj.rid);
} else { // unpausing
if (immediate) lastTime = 0; // a long time ago ;-)
else if (reset) {lastTime = Date.now(); obj.time=0;}
else lastTime = Date.now();
next();
}
obj.paused = state;
};
obj.clear = function() {
if (obj) cancelAnimationFrame(obj.rid);
for (var i in obj) {
delete obj[i];
}
obj.pause = function() {};
obj.clear = function() {};
};
next(); // thanks StevenWarren for the glitch fix!
return obj;
};//-9.7
/*--
zim.interval = function(time, call, total, immediate, pauseOnBlur, timeUnit)
interval
zim function
DESCRIPTION
Calls a function after each time delay - like window.setInterval().
Can pass in an Array of two times to set random time delays each interval.
Can pass in how many times you want to run the function and whether it runs right away.
NOTE: as of ZIM Cat time is in seconds not milliseconds.
Set TIME = "milliseconds"; to set all ZIM time to milliseconds
or pass in "milliseconds" to the timeUnit parameter for a specific override.
NOTE: setInterval has the time parameter last, interval has it first
so that it is consistent with loop() and the CreateJS on() method
NOTE: to clear a interval you use intervalObj.clear() - different than window.clearInterval(returnID)
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
interval(1, function(){
circle.x += 100;
stage.update();
});
// every second the circle will move 100 pixels
// if you want smooth movement, use:
Ticker.add(function() {
circle.x += 100; // no need for stage.update()
});
interval(1, function(obj) {
zog("counting " + obj.count); // starts counting at 1
if (obj.count == 10) obj.clear(); // will now log 1 to 10
});
OR better:
interval(1, function(obj) {
zog("counting " + obj.count); // starts counting at 1
}, 10); // now will log 1 - 10 with total parameter set to 10
IMMEDIATE:
interval(1, function(obj) {
zog("counting " + obj.count); // starts counting at 0
}, 10, true); // now will log 0 - 9 with immediate parameter set to true
EXTERNAL control:
var interval = interval(1, function() {
zog("counting " + interval.count); // starts counting at 1
});
var button = new Button({label:"STOP", toggle:"START"}).center();
button.on("click", function(){interval.pause(button.toggled);});
RANDOM intervals with ZIM Pick() literals
interval({min:.2, max:.8}, dropBombs); // bombs will fall at different rates between 200ms and 800ms
interval([1, 2], dropBombs); // bombs will fall at either 1 or 2 s
var count = 1;
function increase() {return ++count}
interval(increase, dropBombs); // bombs will fall at 1 second, then again after 2 more seconds and 3 seconds more after that, etc.
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports VEE - parameters marked with ZIM VEE mean a zim Pick() object or Pick Literal can be passed
Pick Literal formats: [1,3,2] - random; {min:10, max:20} - range; series(1,2,3) - order, function(){return result;} - function
time - |ZIM VEE| (default 1) seconds for the interval (delay until the function runs - again and again)
see TIME global constant (defaults to "seconds") can also override with timeUnit parameter set to "milliseconds"
call - function to call when the interval passes
Will be passed a ZIM intervalObject as a single parameter
This is the same as the return object from animate()
See the Returns section below for methods and properties of the intervalObject
total - (default null - infinite) the number of times the function is called
note: the count property counts intervals but the total property is based on function calls.
The total will be equal to the end count with the immediate parameter set to false (default)
but the total will be one less than the count if the immediate parameter is true (like an Array index and length)
immediate - (default false) set to true to call the function right away (and then still call every interval)
This will not increase the count in the intervalObject because count counts intervals not function calls
Use the provided parameter of the call function to access the intervalObject inside the call function
pauseOnBlur - (default false) set to true to pause interval when window is reduced or another tab gains focus
timeUnit - (default seconds) set to "milliseconds" for traditional JavaScript milliseconds
also see TIME constant which defaults to "seconds"
timeUnit will override the TIME constant
RETURNS a ZIM intervalObject to pause and clear the interval with the following methods and properties:
METHODS - of ZIM intervalObject
pause(state, immediate, reset) - (default true) will pause the interval - set to false to unpause the interval with time left
immediate (default false) set to true to make the interval function run right away when unpausing (no effect when pausing)
reset (default false) set to true to set the interval back to 0 time passed when unpausing (no effect when pausing)
clear() - will clear the interval
PROPERTIES - of ZIM intervalObject
time - |ZIM VEE| get or set the time for the interval (see time parameter)
count - get the number of times the interval has run (if immediate is true, the first count is 0)
total - get or set the number of times the interval will run if the total parameter is set - otherwise -1 for infinite
paused - get the paused state of the interval (see pause() method)
pauseTimeLeft - if paused, get how much time is left once unpaused
--*///+9.8
zim.interval = function(time, call, total, immediate, pauseOnBlur, timeUnit) {
var sig = "time, call, total, immediate, pauseOnBlur, timeUnit";
var duo; if (duo = zob(zim.interval, arguments, sig, this)) return duo;
z_d("9.8");
if (zot(call)) return;
if (typeof call != 'function') return;
var timeType = getTIME(time, timeUnit);
if (zot(time)) time = timeType=="s"?1:1000;
if (zot(immediate)) immediate = false;
if (!zot(total) && (isNaN(total) || total<=0)) return;
if (zot(total)) total = -1;
var obj = {count:0, total:total, paused:false, time:time, active:true, timeUnit:timeUnit};
if (pauseOnBlur) {
if (zot(zim.blurCheck)) zim.setBlurDetect();
zim.pauseOnBlur.push(obj);
}
function interval() {
obj.startTime = Date.now();
obj.interval = zim.Pick.choose(obj.time);
obj.id = setTimeout(function() {
if (obj.paused) return;
if (!obj.active) return;
// obj.rid = requestAnimationFrame(interval);
obj.count++;
(call)(obj);
interval();
checkTotal();
}, obj.interval*(timeType=="s"?1000:1));
}
if (immediate) {
setTimeout(function() {
(call)(obj);
checkTotal();
}, 10);
}
function checkTotal() {
if (total == -1) return;
if (obj.count >= (immediate?obj.total-1:obj.total)) obj.clear();
}
var pausedTimeout;
obj.pause = function(state, immediate, reset) {
if (zot(state)) state = true;
if (state) { // pausing
clearTimeout(pausedTimeout);
clearTimeout(obj.id);
cancelAnimationFrame(obj.rid);
obj.pauseTimeLeft = obj.interval-(Date.now()-obj.startTime)/(timeType=="s"?1000:1);
} else { // unpausing
if (!obj.paused) obj.pause(true);
pausedTimeout = setTimeout(function() {
obj.count++;
(call)(obj);
interval();
checkTotal();
}, immediate?0:(reset?obj.interval:obj.pauseTimeLeft)*(timeType=="s"?1000:1));
obj.pauseTimeLeft = null;
}
obj.paused = state;
};
obj.clear = function() {
obj.active = false;
clearTimeout(pausedTimeout);
cancelAnimationFrame(obj.rid);
clearTimeout(obj.id);
var count = obj.count;
for (var i in obj) {
delete obj[i];
}
obj.active = false;
obj.count = count;
obj.pause = function() {};
obj.clear = function() {};
};
interval();
return obj;
};//-9.8
/*--
zim.async = function(url, callback, callbackString, maxTime, maxCancel)
async
zim function
DESCRIPTION
A way to send data back and forth to a server script without reloading the HTML page.
(like AJAX but without the bother)
Uses a dynamic script call with an optional callback (cross domain calls are okay)
also known as JSON-P pattern but JSON is unnecessary - note, no JSON in two of the examples below.
Pass a url to the server script (ie. php or node page)
and an optional callback function that you define in your code (cannot be an anonymous function).
async will automatically add a random number to the end of your script call to defeat cache.
NOTE: async uses GET so data is limited to GET length (as of ZIM 10 - this is 2K to 8K depending on Browser)
If more data is required, use an AJAX library
NOTE: async uses an r CGI key to send a random number to defeat cache.
Do not send an r property
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// existing JSONp service:
// assuming that we have a callback function called test as shown below
async("http://ip-api.com/json?callback=async.test",test);
function test(data) {zog(data.country);}
// note that the callback we pass the service is async.test not just test
// this allows zim to handle scope issues and garbage collect the dynamic script when done
END EXAMPLE
EXAMPLE
// existing JSON service:
// if the service just returns JSON - then pass through a JSONp wrapper:
var api = "https://zimjs.com/codepen/ranker.php"; // not JSONp - just JSON
async("https://zimjs.org/cdn/jsonp.php?api="+api+"&callback=async.getData", getData);
function getData(data) {
zog(data); // data will be the JSON parsed object
}
See a full example here: https://codepen.io/danzen/pen/gNKQYY
Here is the jsonp.php code if you would like to host:
<?php
$api = $_GET["api"];
if (!preg_match('/^http/i', $api)) exit;
$callback = $_GET["callback"];
header('Content-Type: application/javascript');
$data = file_get_contents($api);
echo $callback."(".$data.")";
?>
END EXAMPLE
EXAMPLE
// CLIENT - your own server script:
// assuming we have a callback function called myFunction as shown below
async("http://yourserver.com/script.php?id=72&name=dan", myFunction);
function myFunction(data){zog(data);}
// SERVER - your script must output the following format as a string:
// "async.myFunction(somedata)"
// in the php file we would use:
header('Content-type: text/javascript');
echo "async.myFunction('success')";
// to return an object literal with nodejs express for example, you would use:
res.send('async.myFunction({list:[1,2,3], name:"whatever"})');
// the data parameter in the myFunction function defined earlier would be an object literal
// we could then do zog(data.list[0]) to log the value 1, etc.
END EXAMPLE
PARAMETERS
url - url to the server script (ie. php or node page)
Note: async uses an r CGI key to send a random number to defeat cache - do not send an r property
callback - (default null) callback function that you define in your code (cannot be an anonymous function)
callbackString - (default null) a string name matching the function in case the file is minified
maxTime - (default 2 seconds) how long to wait for server response before triggering an error
may still trigger callback if callback comes later unless maxCancel is set to true
see also ZIM TIME constant
If maxTime is up without calling back the function
async will return two arguments to the callback function:
"asyncError" and either "timeout" or "cancelled"
maxCancel - (default false) set to true to have maxTime cancel a late callback response
calling the return function on async does two things:
1. it handles scope issues so we can find your callback function
2. it handles garbage collection to remove the dynamic script tag that was used
if you do not specify a callback function then just send "" back from your server script
NOTE: we have experienced duplicate script calls if nothing is sent back
NOTE: if more than one async() with the same named call function is run at the same time
then a queue of callbacks is created
if the data comes back in a different order, the wrong call could be called
if there is danger of this happening (rare) then use ZIM Ajax
RETURNS undefined
--*///+29
zim.async = function (url, callback, callbackString, maxTime, maxCancel) {
z_d("29");
if (zot(url)) return;
var tag = document.createElement("script");
var timeType = getTIME(maxTime);
if (zot(maxTime)) maxTime = timeType=="s"?2:2000;
if (callback) {
if (callbackString) var n = callbackString;
else var n = callback.toString().split(/\n/,1)[0].match(/^function\s?([^\s(]*)/)[1];
// create a queue if more than one async() to same callback function name
// if data is not returned in same order made, the wrong callbacks may be called
if (!zim.asyncList) zim.asyncList = {};
if (!zim.asyncList[n]) zim.asyncList[n] = [];
zim.asyncList[n].push(callback);
// create callback bridge on async function object
zim.async[n] = function() { // closure to access tag on callback bridge
var t = tag;
// var name = n;
var cancelMe = false;
var errorID = setTimeout(function(){
cancelMe = maxCancel;
if (typeof callback == "function") callback("asyncError", maxCancel?"cancelled":"timeout");
}, maxTime*(timeType=="s"?1000:1));
return function(d){
clearTimeout(errorID);
if (zim.asyncList[n]) callback = zim.asyncList[n].shift();
if (typeof callback == "function" && !cancelMe) callback(d);
// remove the script tag
if (t) t.parentNode.removeChild(t); t = null;
};
}();
} else {
if (zim.async.z_s && zim.async.z_s.parentNode) zim.async.z_s.parentNode.removeChild(zim.async.z_s); // keep overwriting same script tag if no callback
zim.async.z_s = tag;
}
if (!url.match(/\?/)) url += "?";
tag.setAttribute("src", url + "&r="+Math.random());
document.getElementsByTagName("head")[0].appendChild(tag);
};//-29
//
/*--
zim.couple = function(json)
couple
zim function
DESCRIPTION
Turns a nested JSON object into a single layer JSON object
The object will have _ between the id and the property name
eg. {"circle":{"x":"10", "y":"20"},"count":{"currentValue":"0"}}
is: {"circle_x":"10", "circle_y":"20", "count_currentValue":"0"}
This allows data to be JSON decoded on the server
and put more directly into table fields of the database
See also ZIM decouple()
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// note the two levels of nesting - this is the format of ZIM Bind data for instance
var test = JSON.stringify({circle:{x:10, y:20},count:{currentValue:0}});
zog(couple(test)); // {"circle_x":"10", "circle_y":"20", "count_currentValue":"0"}
END EXAMPLE
PARAMETERS
json - a JSON string in the nested form of:
{"obj1":{"prop1":"val", "prop2":"val"},"obj2":{"prop3":"val"}}
RETURNS a JSON string with one less level of objects in form of:
{"obj1_prop1":"val", "obj1_prop2":"val", "obj2_prop3":"val"}
--*///+29.2
zim.couple = function (json) {
z_d("29.2");
if (!zim.isJSON(json)) return json;
var obj = JSON.parse(json);
var obj2 = {};
for (var i in obj) {
var o = obj[i];
for (var j in o) {
obj2[i+"_"+j] = o[j];
}
}
return JSON.stringify(obj2);
};//-29.2
/*--
zim.decouple = function(json)
decouple
zim function
DESCRIPTION
Turns a flat coupled JSON object into a nested layer JSON object
The object will remove _ from between the id and the property name
eg. {"circle_x":"10", "circle_y":"20", "count_currentValue":"0"}
is: {"circle":{"x":"10", "y":"20"},"count":{"currentValue":"0"}}
This allows data from table fields of the database
to be more easily dealt with as objects with their own properties
See also ZIM couple()
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// note the two levels of nesting - this is the format of ZIM Bind data for instance
var test = {circle:{x:10, y:20},count:{currentValue:0}};
var test2 = JSON.stringify(test);
var test3 = couple(test);
// {"circle_x":"10", "circle_y":"20", "count_currentValue":"0"}
// send this to server to store in fields
// receive back similar coupled data from fields
// decouple the data:
var test4 = decouple(test3);
// {"circle":{"x":"10", "y":"20"},"count":{"currentValue":"0"}}
var test5 = JSON.parse(test4); // similar object to test!
// {circle:{x:10, y:20},count:{currentValue:0}};
END EXAMPLE
PARAMETERS
json - a JSON string in the coupled form of
{"obj1_prop1":"val", "obj1_prop2":"val", "obj2_prop3":"val"}
RETURNS a JSON string with one less level of objects in the form of:
{"obj1":{"prop1":"val", "prop2":"val"},"obj2":{"prop3":"val"}}
the original JSON string will be returned if the initial JSON string is not coupled
--*///+29.3
zim.decouple = function (json) {
z_d("29.3");
if (!zim.isJSON(json)) return json;
var obj = JSON.parse(json);
var obj2 = {};
for (var i in obj) {
var n = i.split("_", 2);
if (n.length != 2) return json;
if (!obj2[n[0]]) obj2[n[0]] = {};
obj2[n[0]][n[1]] = obj[i];
}
return JSON.stringify(obj2);
};//-29.3
/*--
zim.convertColor = function(color, toColorType, alpha)
convertColor
zim function
DESCRIPTION
Converts color to hex numbers - for example: "#333333"
Or converts color to HTML string - for example: "red"
Or converts color to RGB - for example: "rgb(0,0,0)"
Or converts color to RGBA - for example: "rgba(0,0,0,.5)"
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var color = convertColor("red"); // result is "#ff0000"
var color = convertColor("rgb(255,0,0)")); // result is "#ff0000"
var color = convertColor("rgb(0,0,255)", "string"); // result is "blue"
var color = convertColor("rgb(0,0,20)", "string"); // result is "#000014" - no matching string color
var color = convertColor("#ff0000", "string"); // result is "red"
var color = convertColor("f00", "string"); // result is "red" - note missing # okay and can use three digits
var color = convertColor(blue, "rgba", .5); // result is "rgba(80,196,183,0.5)"
var color = convertColor("rgb(256,256,0)", "rgba", .3); // result is "rgba(256,256,0,.3)"
var color = convertColor("rgba(0,0,0,.2)", anyType, .5); // result is "rgba(0,0,0,.5)"
var color = convertColor("red", "hexNumber"); // result is 0xff0000
END EXAMPLE
PARAMETERS
color - (default black) the HTML string or hex color (case insensitive)
"rgba()" to hex will ignore alpha
toColorType - (default "hex") or use "string", "rgb", "rgba", "zim", "hexNumber"
if "string" and color does not match existing HTML string color
then will return hex number as string
zim will convert zim rgb to zim string like "blue"
hexNumber is 0xff0000 in format
alpha - (default 1) the alpha used for the "rgba" toColorType
RETURNS a String with the converted color
--*///+27.5
zim.convertColor = function(color, toColorType, alpha) {
if (!zim.convertColorCheck) {z_d("27.5"); zim.convertColorCheck=true;}
if (zot(toColorType)) toColorType = "hex";
if (zot(color)) return;
color = zik(color);
var colors = ['black','aliceblue','antiquewhite','aqua','aquamarine','azure','beige','bisque','blanchedalmond','blue','blueviolet','brown','burlywood','cadetblue','chartreuse','chocolate','coral','cornflowerblue','cornsilk','crimson','cyan','darkblue','darkcyan','darkgoldenrod','darkgray','darkgrey','darkgreen','darkkhaki','darkmagenta','darkolivegreen','darkorange','darkorchid','darkred','darksalmon','darkseagreen','darkslateblue','darkslategray','darkslategrey','darkturquoise','darkviolet','deeppink','deepskyblue','dimgray','dimgrey','dodgerblue','firebrick','floralwhite','forestgreen','fuchsia','gainsboro','ghostwhite','gold','goldenrod','gray','grey','green','greenyellow','honeydew','hotpink','indianred','indigo','ivory','khaki','lavender','lavenderblush','lawngreen','lemonchiffon','lightblue','lightcoral','lightcyan','lightgoldenrodyellow','lightgray','lightgrey','lightgreen','lightpink','lightsalmon','lightseagreen','lightskyblue','lightslategray','lightslategrey','lightsteelblue','lightyellow','lime','limegreen','linen','magenta','maroon','mediumaquamarine','mediumblue','mediumorchid','mediumpurple','mediumseagreen','mediumslateblue','mediumspringgreen','mediumturquoise','mediumvioletred','midnightblue','mintcream','mistyrose','moccasin','navajowhite','navy','oldlace','olive','olivedrab','orange','orangered','orchid','palegoldenrod','palegreen','paleturquoise','palevioletred','papayawhip','peachpuff','peru','pink','plum','powderblue','purple','rebeccapurple','red','rosybrown','royalblue','saddlebrown','salmon','sandybrown','seagreen','seashell','sienna','silver','skyblue','slateblue','slategray','slategrey','snow','springgreen','steelblue','tan','teal','thistle','tomato','turquoise','violet','wheat','white','whitesmoke','yellow','yellowgreen'];
var hex = ['000000','f0f8ff','faebd7','00ffff','7fffd4','f0ffff','f5f5dc','ffe4c4','ffebcd','0000ff','8a2be2','a52a2a','deb887','5f9ea0','7fff00','d2691e','ff7f50','6495ed','fff8dc','dc143c','00ffff','00008b','008b8b','b8860b','a9a9a9','a9a9a9','006400','bdb76b','8b008b','556b2f','ff8c00','9932cc','8b0000','e9967a','8fbc8f','483d8b','2f4f4f','2f4f4f','00ced1','9400d3','ff1493','00bfff','696969','696969','1e90ff','b22222','fffaf0','228b22','ff00ff','dcdcdc','f8f8ff','ffd700','daa520','808080','808080','008000','adff2f','f0fff0','ff69b4','cd5c5c','4b0082','fffff0','f0e68c','e6e6fa','fff0f5','7cfc00','fffacd','add8e6','f08080','e0ffff','fafad2','d3d3d3','d3d3d3','90ee90','ffb6c1','ffa07a','20b2aa','87cefa','778899','778899','b0c4de','ffffe0','00ff00','32cd32','faf0e6','ff00ff','800000','66cdaa','0000cd','ba55d3','9370db','3cb371','7b68ee','00fa9a','48d1cc','c71585','191970','f5fffa','ffe4e1','ffe4b5','ffdead','000080','fdf5e6','808000','6b8e23','ffa500','ff4500','da70d6','eee8aa','98fb98','afeeee','db7093','ffefd5','ffdab9','cd853f','ffc0cb','dda0dd','b0e0e6','800080','663399','ff0000','bc8f8f','4169e1','8b4513','fa8072','f4a460','2e8b57','fff5ee','a0522d','c0c0c0','87ceeb','6a5acd','708090','708090','fffafa','00ff7f','4682b4','d2b48c','008080','d8bfd8','ff6347','40e0d0','ee82ee','f5deb3','ffffff','f5f5f5','ffff00','9acd32'];
if (toColorType.toLowerCase() == "zim") {
var i = zim.colorsHex.indexOf(color);
if (i<0) return color;
return zim.colors[zim.colorsHex.indexOf(color)];
}
var answer;
if (answer = color.match(/rgba\((.*)\)/)) {
if (zot(alpha)) {
color = "rgb("+answer[1]+")"; // includes alpha but does not matter
} else {
var c = color.split(",");
c[3] = alpha+")";
return c.join(",");
}
}
function rgbToHex(rgb) {
var hex = Number(rgb).toString(16);
if (hex.length < 2) {
hex = "0" + hex;
}
return hex;
}
function getRGB(string) {
var c = string.split(",");
var red = rgbToHex(c[0]);
var green = rgbToHex(c[1]);
var blue = rgbToHex(c[2]);
return [red, green, blue];
}
if (zot(alpha)) alpha == 1;
if (answer = color.match(/rgb\((.*)\)/)) {
if (toColorType == "rgba") {
var c = color.split(")");
return c[0]+","+alpha+c[1];
} else if (toColorType == "hex") {
var colors = getRGB(answer[1]);
return "#" + colors[0] + colors[1] + colors[2];
} else if (toColorType == "hexNumber") {
var colors = getRGB(answer[1]);
return parseInt(colors[0]+colors[1]+colors[2], 16);
} else if (toColorType == "string") {
var color = getRGB(answer[1]).join("").toLowerCase();
var index = hex.indexOf(color);
if (index == -1) return "#" + color;
else return colors[index];
} else return color;
}
if (toColorType == "rgb" || toColorType == "rgba") {
function hexToRgbA(hex){ // kennebec on StackOverflow
var c;
if(/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)){
c= hex.substring(1).split('');
if(c.length== 3){
c= [c[0], c[0], c[1], c[1], c[2], c[2]];
}
c= '0x'+c.join('');
if (toColorType == "rgb") {
return 'rgb('+[(c>>16)&255, (c>>8)&255, c&255]+')';
} else {
return 'rgba('+[(c>>16)&255, (c>>8)&255, c&255].join(',')+','+alpha+')';
}
} else {
if (toColorType == "rgb") {
return "rgb(0,0,0)";
} else {
return "rgba(0,0,0,1)";
}
}
}
if (color.charAt(0)=="#") {
return hexToRgbA(color);
} else {
return hexToRgbA(zim.convertColor(color));
}
} else if (toColorType == "hex") {
if (color.charAt(0)=="#") return color; // already hex
} else if (toColorType == "hexNumber") {
if (color.charAt(0)=="#") {
return parseInt(color.replace(/^#/, ''), 16);
}
} else {
if (color.charAt(0)=="#") {
color = color.replace("#","");
if (color.length == 3) {
color = color.charAt(0)+color.charAt(0)+color.charAt(1)+color.charAt(1)+color.charAt(2)+color.charAt(2);
}
}
}
if (toColorType == "string") {
var index = hex.indexOf(color);
if (index == -1) return "#" + color;
else return colors[index];
} else if (toColorType == "hexNumber") {
return parseInt(hex[colors.indexOf(color.toLowerCase())!=-1?colors.indexOf(color):0], 16);
} else {
return "#"+hex[colors.indexOf(color.toLowerCase())!=-1?colors.indexOf(color):0];
}
};//-27.5
/*--
zim.colorRange = function(color1, color2, ratio)
colorRange
zim function
DESCRIPTION
Gets the color in a range between two colors based on a ratio from 0-1
Used internally by setColorRange() method and colorRange property of ZIM shapes
including animating color from current color to a new color
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
zog(colorRange(green, blue, .5)); // #7ecb7c
var rect = new Rectangle(100,100,red).center().setColorRange(purple);
rect.colorRange = .1; // will change color to #f1455e (closer to red than purple)
rect.animate({color:purple}, 1000); // will animate color to purple in one second
rect.wiggle("colorRange", .5, .2, .5, 1, 5); // wiggles the color in the range
END EXAMPLE
PARAMETERS
color1 - (default null) the first color as an HTML string or hex color (case insensitive)
color2 - (default black) the second color as an HTML string or hex color (case insensitive)
ratio - (default .5) the ratio where 0 is the first color and 1 the second color
RETURNS a hex color string
--*///+27.6
zim.colorRange = function(color1, color2, ratio) {
if (!zim.colorRangeCheck) {z_d("27.6"); zim.colorRangeCheck=true;}
// thanks Chris Dolphin - StackOverflow
// modified by Dan Zen to use hex input and output
// possibly converting and converting back - but not quite...
if (zot(ratio)) ratio = .5;
ratio = Math.max(0, Math.min(1, ratio));
if (zot(color1)) color1 = "white";
if (zot(color2)) color2 = "black";
var c1 = zim.convertColor(color1, "rgb");
var c2 = zim.convertColor(color2, "rgb");
var color1 = c1.substring(4, c1.length - 1).split(',');
var color2 = c2.substring(4, c2.length - 1).split(',');
var difference;
var newColor = "#";
var c;
for (var i=0; i<color1.length; i++) {
difference = color2[i] - color1[i];
c = Math.floor(parseInt(color1[i], 10) + difference * ratio).toString(16);
if (c.length < 2) c = "0"+c;
newColor += c;
}
return newColor;
};//-27.6
/*--
zim.lighten = function(color, ratio)
lighten
zim function
DESCRIPTION
Lightens the color by a ratio from 0 to 1
A shortcut for ZIM colorRange(color, white, ratio);
A shortcut method is also added to the JavaScript String
for instance:
red.lighten(.2); // lightens ZIM red color
"red".lighten(.2); // lightens HTML red color
"#cc0000".lighten(.2); // lightens HTML Hex color
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// make a slightly lighter than ZIM blue circle
new Circle(100, lighten(blue, .2)).center();
// or use the String method directly
new Circle(100, blue.lighten(.2)).center();
END EXAMPLE
PARAMETERS
color - the color as an HTML string or hex color (case insensitive)
can be ZIM colors as they are just references to hex colors
not used with color String method
ratio - (default .5) the ratio where 0 is the color and 1 white
RETURNS a hex color string
--*///+27.65
zim.lighten = function(color, ratio) {
if (!zim.lightenCheck) {z_d("27.65"); zim.lightenCheck=true;}
if (zot(ratio)) ratio = .5;
if (ratio >= 0) return zim.colorRange(String(color), "#FFFFFF", ratio);
else return zim.colorRange(String(color), "#000000", -ratio);
};//-27.65
/*--
zim.darken = function(color, ratio)
darken
zim function
DESCRIPTION
Darkens the color by a ratio from 0 to 1
A shortcut for ZIM colorRange(color, black, ratio);
A shortcut method is also added to the JavaScript String
for instance:
red.darken(.2); // darkens ZIM red color
"red".darken(.2); // darkens HTML red color
"#cc0000".darken(.2); // darkens HTML Hex color
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// make a slightly darker than ZIM blue circle
new Circle(100, darken(blue, .2)).center();
// or use the String method directly
new Circle(100, blue.darken(.2)).center();
END EXAMPLE
PARAMETERS
color - the color as an HTML string or hex color (case insensitive)
can be ZIM colors as they are just references to hex colors
not used with color String method
ratio - (default .5) the ratio where 0 is the color and 1 black
RETURNS a hex color string
--*///+27.66
zim.darken = function(color, ratio) {
if (zot(ratio)) ratio = .5;
if (!zim.darkenCheck) {z_d("27.66"); zim.darkenCheck=true;}
if (ratio >= 0) return zim.colorRange(String(color), "#000000", ratio);
else return zim.colorRange(String(color), "#ffffff", -ratio);
};//-27.66
/*--
zim.toColor = function(color, targetColor, ratio)
toColor
zim function
DESCRIPTION
toColor the color by a ratio from 0 to 1
A shortcut for ZIM colorRange(color, white, ratio);
A shortcut method is also added to the JavaScript String
for instance:
red.toColor(blue, .2); // moves ZIM red color towards ZIM blue color
"red".toColor("blue", .2); // moves HTML red color towards HTML blue color
"#cc0000".toColor("#0000cc", .2); // moves HTML Hex red color towards HTML Hex blue color
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// make a ZIM blue circle be partway to ZIM pink
new Circle(100, toColor(blue, pink, .2)).center();
// or use the String method directly
new Circle(100, blue.toColor(pink, .2)).center();
END EXAMPLE
PARAMETERS
color - the color as an HTML string or hex color (case insensitive)
can be ZIM colors as they are just references to hex colors
not used with toColor String method
targetColor - the target color as an HTML string or hex color (case insensitive)
can be ZIM colors as they are just references to hex colors
ratio - (default .5) the ratio where 0 is the color and 1 targetColor
RETURNS a hex color string
--*///+27.67
zim.toColor = function(color, targetColor, ratio) {
if (!zim.toColorCheck) {z_d("27.67"); zim.toColorCheck=true;}
if (zot(ratio)) ratio = .5;
return zim.colorRange(String(color), targetColor, ratio);
};//-27.67
/*--
zim.toAlpha = function(color, alpha)
toAlpha
zim function
DESCRIPTION
Set the alpha of a the color by a ratio from 0 to 1
A shortcut for ZIM convertColor(color, "rgba", ratio);
A shortcut method is also added to the JavaScript String
for instance:
red.toAlpha(.2); // sets ZIM red color to .2 alpha
"red".toAlpha(.2); // sets HTML red color to .2 alpha
"#cc0000".toAlpha(.2); // sets HTML Hex red color to .2 alpha
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// make a ZIM blue circle be partway to ZIM pink
new Label({text:HELLO, background:blue.toAlpha(.5)}).pos(0,50,CENTER,BOTTOM)
END EXAMPLE
PARAMETERS
color - the color as an HTML string or hex color (case insensitive)
can be ZIM colors as they are just references to hex colors
not used with toAlpha String method
ratio - (default .5) the ratio where 0 is the color and 1 targetColor
RETURNS a hex color string
--*///+27.68
zim.toAlpha = function(color, ratio) {
if (!zim.toAlphaCheck) {z_d("27.68"); zim.toAlphaCheck=true;}
if (zot(ratio)) ratio = .5;
return zim.convertColor(String(color), "rgba", ratio);
};//-27.68
/*--
zim.zimEase = function(points, polynomials, convert)
zimEase
zim function
DESCRIPTION
Returns an easing function to pass in to ZIM animate() - or CreateJS TweenJS
The points to pass in to zimEase() can be created at https://zimjs.com/ease
At the top of the app there are default easing functions
but just use the build in easing function for most of these such as "quadOut", etc.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// go to https://zimjs.com/ease use the sliders and TEST the motion
// then press SAVE and copy the zimEase() code into ZIM animate()
// this example makes very big forward, back, forward motion
new Circle().loc(200,200).animate({
props:{x:400},
ease:zimEase([2.5,-0.5,-1,1]),
time:1.5
});
END EXAMPLE
EXAMPLE
// passing an array of two arrays will play the first for the first half
// and the second for the second half
// so here we pass an array of two arrays for a snapInOut effect
// this is cool so it is now a set of eases: "snapIn", "snapOut", "snapInOut" - cheers GreenSock!
new Circle().loc(200,200).animate({
props:{x:400},
ease:zimEase([[1.45,-0.57,0.67,0.55], [0.34,0.44,1.43,-0.31]]),
// ease:"snapInOut", // or use the new ZIM ease
time:2
});
END EXAMPLE
PARAMETERS
points - (default [.2,.4,.6,.8]) an array of 4 points to feed the equation - or an array of two arrays
use the tool at https://zimjs.com/ease and press SAVE to get these
the two ends are anchored at 0 and 1 and are the input to the quintic Bezier formula
If an array of two arrays is provided the first array is used for the first half of the tween (In)
and the second array is used for the second half of the tween (Out)
polynomials - (default null) an array of 5 points that are the results of the quintic Bezier formula
linear would be [0,0,0,0,1] - use this if you are given the polynomials - who knows!
otherwise see points.
mirror - (default null) will duplicate the ease equation and reverse the second copy all within the provided time
reverse - (default false) reverses the ease equation (does not work with mirror)
lockEnds - (default true) this snaps the start and end to the real values - set to false to draw curve based on data, for instance.
PROPERTIES
** The function result is an object that holds the easing equation in a noPick property
** this allows it to bypass the dynamic setting of ZIM VEE ease parameter.
** Also in this object are the additional properties
points - the array of points or the array of arrays of points
polynomials - the array of final values or an array of arrays of final values
RETURNS an easing function for ZIM animate() or CreateJS TweenJS
--*///+27.69
zim.zimEase = function(points, polynomials, mirror, reverse, lockEnds) {
z_d("27.69");
// with thanks to Timothée Groleau and all before
// http://www.timotheegroleau.com/Flash/experiments/easing_function_generator.htm
var two = false;
if (zot(lockEnds)) lockEnds=true;
if (points) {
if (Array.isArray(points[1])) {
two = true;
points2 = points[1];
points = points[0];
var c0z = 0;
var c1z = points2[0];
var c2z = points2[1];
var c3z = points2[2];
var c4z = points2[3];
var c5z = 1;
var ez = 5*(c1z - c0z);
var dz = 10*(c2z - c0z) - 4*ez;
var cz = 10*(c3z - c0z) + 30*(c1z - c2z);
var bz = 5*(c4z + c0z) - 20*(c3z + c1z) + 30*c2z;
var az = c5z - c0z - bz - cz - dz - ez;
}
var c0 = 0;
var c1 = points[0];
var c2 = points[1];
var c3 = points[2];
var c4 = points[3];
var c5 = 1;
var e = 5*(c1 - c0);
var d = 10*(c2 - c0) - 4*e;
var c = 10*(c3 - c0) + 30*(c1 - c2);
var b = 5*(c4 + c0) - 20*(c3 + c1) + 30*c2;
var a = c5 - c0 - b - c - d - e;
} else if (polynomials) {
var a = polynomials[0];
var b = polynomials[1];
var c = polynomials[2];
var d = polynomials[3];
var e = polynomials[4];
// calculate points - for consistent points property
var c1 = e / 5;
var c2 = (d+4*e)/10;
var c3 = (c + 6*e + 3*d)/10;
var c4 = (b + 4*e + 3*d + 2*c)/5;
} else {
var a = 0;
var b = 0;
var c = 0;
var d = 0;
var e = 1;
}
// return CreateJS ratio format with variables in enclosure
// looks like a lot of code but the tween code is just the function in noPick
// so we are putting the conditionals outside this during the single assignment
// this keeps the tween function fast as that runs at the framerate
if (mirror) {
var rF = function(){
return zim.zimEase(null,[a,b,c,d,e],true) // mirror would be the same
};
var obj = {
reverse:rF,
points:[c1,c2,c3,c4],
polynomials:[a,b,c,d,e]
}
obj.noPick = function(k) {
if (lockEnds) {
if (k<.025) return 0;
if (k>.975) return 1;
}
if (k<.5) {
k*=2; // k needs to be 0-1 to get full tween
var t = k*100;
var di = 100;
var ts=(t/=di)*t;
var tc=ts*t;
// the completeness is divided by 2
return (a*tc*ts + b*ts*ts + c*tc + d*ts + e*t)/2;
} else {
k=1-(k-.5)*2; // we use the second half of k but spread it out from 0 to 1 for complete formula (reversed for mirror)
var t = k*100;
var di = 100;
var ts=(t/=di)*t;
var tc=ts*t;
// the completeness is added to the second half and still divided by 2 (1 - for mirror)
return 1-(a*tc*ts + b*ts*ts + c*tc + d*ts + e*t)/2;
}
}
} else if (two) {
var rF = function(){
if (zon) zogy("zimEase - multi array points cannot be reversed");
return zim.zimEase(null,[a,b,c,d,e])
};
var obj = {
reverse:rF,
points:[[c1,c2,c3,c4],[c1z,c2z,c3z,c4z]],
polynomials:[[a,b,c,d,e],[az,bz,cz,dz,ez]]
}
obj.noPick = function(k) {
if (lockEnds) {
if (k<.025) return 0;
if (k>.975) return 1;
}
if (k<.5) {
k*=2; // k needs to be 0-1 to get full tween
var t = k*100;
var di = 100;
var ts=(t/=di)*t;
var tc=ts*t;
// the completeness is divided by 2
return (a*tc*ts + b*ts*ts + c*tc + d*ts + e*t)/2;
} else {
k=(k-.5)*2; // we use the second half of k but spread it out from 0 to 1 for complete formula
var t = k*100;
var di = 100;
var ts=(t/=di)*t;
var tc=ts*t;
// the completeness is added to the second half and still divided by 2
return .5+(az*tc*ts + bz*ts*ts + cz*tc + dz*ts + ez*t)/2;
}
}
} else {
var rF = function(){
return zim.zimEase(null,[a,b,c,d,e],null,true)
};
var obj = {
reverse:rF,
points:[c1,c2,c3,c4],
polynomials:[a,b,c,d,e]
}
if (reverse) {
obj.noPick = function(k) {
if (lockEnds) {
if (k<.025) return 0;
if (k>.975) return 1;
}
var t = 100-k*100; // reverse the time
var di = 100;
var ts=(t/=di)*t;
var tc=ts*t;
return 1-(a*tc*ts + b*ts*ts + c*tc + d*ts + e*t); // reverse the percent done
}
} else {
obj.noPick = function(k) {
if (lockEnds) {
if (k<.025) return 0;
if (k>.975) return 1;
}
var t = k*100;
var di = 100;
var ts=(t/=di)*t;
var tc=ts*t;
return (a*tc*ts + b*ts*ts + c*tc + d*ts + e*t);
}
}
}
obj.noPick.reverse = rF; // for once it is picked...
return obj;
}//-27.69
/*--
zim.pointAlongCurve = function(points, ratio, getAngle)
pointAlongCurve
zim function
DESCRIPTION
Finds a point along a cubic Bezier curve - such as that used in Blob and Squiggle
as well as the Shape.graphics.bezierCurveTo() or tiny api bt()
Used internally for animating along Blob and Bezier curves
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// point1, control1, control2, point2
var points = [{x:100,y:100}, {x:200,y:100}, {x:200,y:100}, {x:200,y:200}]
var shape = new Shape().addTo();
shape.graphics
.s("black").ss(2)
.mt(points[0].x,points[0].y)
.bt(points[1].x,points[1].y, points[2].x,points[2].y, points[3].x,points[3].y);
new Circle(10,red).loc(pointAlongCurve(points, .2));
END EXAMPLE
PARAMETERS
points - an array of point objects (or objects with an x and y property)
for a cubic Bezier - point1, control1, control2, point2
ratio - (default .5) the ratio where 0 is at the first point and 1 is at the second point
getAngle - (default false) request a calculated angle of tangent at point
even - (default false) use modified cubic equation for even spacing for percentages
even is used by Beads but not by placing a point along a path
RETURNS a point object with x and y properties on the curve at the ratio
as well as an angle property for the tangent if getAngle is true
--*///+27.7
zim.pointAlongCurve = function(points, ratio, getAngle, even) {
z_d("27.7");
if (!points || !points[0] || !points[1] || !points[2] || !points[3]) return;
if (zot(even)) even = false;
var cubic = new zim.Bezier(points[0],points[1],points[2],points[3]);
if (even) {
var x=cubic.mx(ratio);
var y=cubic.my(ratio);
} else {
var x=cubic.x(ratio);
var y=cubic.y(ratio);
}
if (getAngle) {
var lastRatio = ratio-.05;
var nextRatio = ratio+.05;
if (lastRatio < 0) lastRatio = 0;
if (nextRatio > 1) nextRatio = 1;
if (even) {
var x0=cubic.mx(lastRatio);
var y0=cubic.my(lastRatio);
var x2=cubic.mx(nextRatio);
var y2=cubic.my(nextRatio);
} else {
var x0=cubic.x(lastRatio);
var y0=cubic.y(lastRatio);
var x2=cubic.x(nextRatio);
var y2=cubic.y(nextRatio);
}
var angle = zim.angle(x0, y0, x2, y2);
return({x:x,y:y,angle:angle});
}
return({x:x,y:y});
};//-27.7
/*--
zim.distanceAlongCurve = function(points)
distanceAlongCurve
zim function
DESCRIPTION
Finds approximate distance along a cubic Bezier curve - such as that used in Blob and Squiggle
as well as the Shape.graphics.bezierCurveTo() or tiny api bt()
Used internally for animating along Blob and Bezier curves
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// point1, control1, control2, point2
var points = [{x:100,y:100}, {x:200,y:100}, {x:200,y:100}, {x:200,y:200}]
var shape = new Shape();
shape.graphics
.s("black").ss(2)
.mt(points[0].x,points[0].y)
.bt(points[1].x,points[1].y, points[2].x,points[2].y, points[3].x,points[3].y);
zog(distanceAlongCurve(points)); // 170.7
END EXAMPLE
PARAMETERS
points - an array of point objects (or objects with an x and y property)
for a cubic Bezier - point1, control1, control2, point2
RETURNS an approximate distance along the curve
--*///+27.8
zim.distanceAlongCurve = function(points) {
z_d("27.8");
// Thanks David F. Knight in OpenGl.org forumn
// points are [startPt, controlPt1, controlPt2, endPt]
var chord = zim.dist(points[0], points[3]);
var controlDist = zim.dist(points[0], points[1]) + zim.dist(points[1], points[2]) + zim.dist(points[2], points[3]);
return (chord + controlDist)/2;
};//-27.8
/*--
zim.closestPointAlongCurve = function(point, segmentPoints, num, interpolate, percentage)
closestPointAlongCurve
zim function
DESCRIPTION
Finds the closest point along a cubic Bezier curve before the given point.
Blob and Squiggle use cubic Bezier as does the Shape.graphics.bezierCurveTo() or tiny api bt()
Used internally for adding points to a Blob and Bezier curves
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var blob = new Blob().center();
var points = blob.segmentPoints;
stage.on("stagemousedown", function (e) {
var point = blob.globalToLocal(e.stageX, e.stageY)
zog(closestPointAlongCurve({x:point.x, y:point.y}, points))
// gives index of point on curve before mouse location
});
END EXAMPLE
PARAMETERS
point - an object with an x and y property
this could be {x:100, y:140} or circle, etc.
the results tell which segment to add the point to
the segment starting with the returned index
segmentPoints - an array of cubic Bezier point data
each being an array of points for a cubic Bezier
in the format of [point1, control1, control2, point2]
Note, this is not the same as Blob or Squiggle points
but rather use the segmentPoints property of Blob and Squiggle
num - (default 10) the number of points per segment used to calculate answer
interpolate - (default false) will return closest test point - not index of closest existing point
percentage - (default false) will return percent (0-100) the nearest point is on the path (overrides interpolate)
RETURNS the index of the closest point in segmentPoints before the given point
or if interpolate is true, will return the closest testPoint (use higher num for better result)
or if percentage is true, will return percent (0-100) the nearest point is on the path (overrides interpolate)
--*///+27.9
zim.closestPointAlongCurve = function(point, segmentPoints, num, interpolate, percentage) {
z_d("27.9");
var closest = 10000000;
var closestTestPoint;
var index = 0;
var secondaryIndex = 0;
if (zot(num)) num = 10;
zim.loop(segmentPoints, function(points, i, t) {
// add num more points to estimate closest
var cubic = new zim.Bezier(points[0],points[1],points[2],points[3]);
zim.loop(num, function (j, total) {
// var d = zim.dist(point, zim.pointAlongCurve(segmentPoints(that.points[i], that.points[i<t-1?i+1:0]), j/10));
// var testPoint = zim.pointAlongCurve(points, j/total);
// var d = zim.dist(point, testPoint);
var testPoint = {x:cubic.x(j/total), y:cubic.y(j/total)};
var d = zim.dist(point, testPoint);
if (d < closest) {
closest = d;
closestTestPoint = testPoint;
index = i;
secondaryIndex = j;
}
});
});
if (percentage) {
return (index*num+secondaryIndex)/(segmentPoints.length*num)*100;
} else if (interpolate) {
return closestTestPoint;
}
return index;
};//-27.9
/*--
zim.transformPoints = function(points, transformType, amount, x, y)
transformPoints
zim function
DESCRIPTION
Scales, rotates, or moves points about provided x and y - or 0, 0 if x and y are not provided
Used internally by Squiggle and Blob transformPoints method
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// from https://zimjs.com/nio/paths.html
var points = [[0,75,0,0,-150,150,150,-150],[300,75,0,0,0,0,0,0,"none"]];
var newPoints = transformPoints(points, "scale", 2);
// [[0,150,0,0,-300,300,300,-300],[600,150,0,0,0,0,0,0,"none"]]
END EXAMPLE
EXAMPLE
// or used with Squiggle:
var points = [[0,75,0,0,-150,150,150,-150],[300,75,0,0,0,0,0,0,"none"]];
var squiggle = new Squiggle({points:points}).transformPoints("scale", 2);
// a squiggle with points twice as big as before
END EXAMPLE
PARAMETERS
points - an array of points in the Squiggle and Blob format (controlType is left as is)
[[controlX, controlY, circleX, circleY, rect1X, rect1Y, rect2X, rect2Y, controlType], [etc]]
transformType - String any of: "scale", "scaleX", "scaleY", "rotation", "x", "y"
amount - the amount to transform
x, y - (default 0, 0) the x and y position to transform about
RETURNS an array of points with numbers transformed
--*///+27.95
zim.transformPoints = function(points, transformType, amount, x, y) {
z_d("27.95");
if (zot(points) || !Array.isArray(points)) return;
if (zot(x)) x = 0;
if (zot(y)) y = 0;
var points = zim.copy(points);
var xStart = x;
var yStart = y;
if (transformType == "rotation") {
if (x != 0) points = zim.transformPoints(points, "x", -xStart);
if (y != 0) points = zim.transformPoints(points, "y", -yStart);
}
var point;
for (var i=0; i<points.length; i++) {
point = points[i];
if (!Array.isArray(point)) continue;
// [[controlX, controlY, circleX, circleY, rect1X, rect1Y, rect2X, rect2Y, controlType], [etc]]
if (transformType == "x") {
point[0] += amount;
} else if (transformType == "y") {
point[1] += amount;
} else if (transformType == "scaleX") {
point[0] = (point[0]-x)*amount+x;
point[4] = (point[4])*amount;
point[6] = (point[6])*amount;
} else if (transformType == "scaleY") {
point[1] = (point[1]-y)*amount+y;
point[5] = (point[5])*amount;
point[7] = (point[7])*amount;
} else if (transformType == "scale") {
point[0] = (point[0]-x)*amount+x;
point[4] = (point[4])*amount;
point[6] = (point[6])*amount;
point[1] = (point[1]-y)*amount+y;
point[5] = (point[5])*amount;
point[7] = (point[7])*amount;
} else if (transformType == "rotation") {
var a = amount*Math.PI/180;
var x1 = point[0];
var y1 = point[1];
point[0] = x1*Math.cos(a) - y1*Math.sin(a);
point[1] = y1*Math.cos(a) + x1*Math.sin(a);
x1 = point[4];
y1 = point[5];
point[4] = x1*Math.cos(a) - y1*Math.sin(a);
point[5] = y1*Math.cos(a) + x1*Math.sin(a);
x1 = point[6];
y1 = point[7];
point[6] = x1*Math.cos(a) - y1*Math.sin(a);
point[7] = y1*Math.cos(a) + x1*Math.sin(a);
}
}
if (transformType == "rotation") {
if (x != 0) points = zim.transformPoints(points, "x", xStart);
if (y != 0) points = zim.transformPoints(points, "y", yStart);
}
return points;
};//-27.95
/*--
zim.makeID = function(type, length, letterCase)
makeID
zim function
DESCRIPTION
makes a random letter, number or mixed id of specified length
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var id1 = makeID(); // five random letters and numbers (starts with letter)
var id2 = makeID("strings"); // five random uppercase letters
var id3 = makeID("numbers", 10); // ten random numbers
var id4 = makeID(["Z", "I", "M", 1, 2, 3, 4, 5, "-"], 5); // random five characters from array (possibly repeating)
END EXAMPLE
PARAMETERS
type - (default "mixed") set to "letters" or "numbers" as well
note: no O, 0, 1, I or L due to identification problems
pass in an array of characters to make an id from only those characters
length - (default 5) the length of the id
letterCase - (default uppercase) - set to "lowercase" or "mixed" as well
RETURNS a String id (even if type is number)
--*///+13.5
zim.makeID = function(type, length, letterCase) {
z_d("13.5");
if (zot(type)) type = "mixed";
if (zot(length)) length = 5;
if (zot(letterCase)) letterCase = "uppercase";
var choices;
var nums = [2,3,4,5,6,7,8,9];
var lets = "abcdefghjkmnpqrstuvwxyz".split("");
if (type.constructor === Array) {
choices = type;
} else if (type == "numbers") {
choices = nums;
} else if (type == "letters") {
choices = lets;
} else {
choices = nums.concat(lets);
}
var id = "";
var c; // character - note, char is a reserved word for compressor!
var rand;
for (var i=0; i<length; i++) {
c = choices[Math.floor(Math.random()*choices.length)];
rand = Math.random();
if (letterCase == "uppercase" || (letterCase == "mixed" && rand > .5)) {
if (c.toUpperCase) c = c.toUpperCase();
} else {
if (c.toLowerCase) c = c.toLowerCase();
}
id += String(c);
}
return id;
};//-13.5
/*--
zim.swapProperties = function(property, objA, objB)
swapProperties
zim function
DESCRIPTION
Pass in a property as a string and two object references
and this function will swap the property values.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// exchanges the x position of two ZIM circles
swapProperties("x", circle1, circle2); stage.update();
END EXAMPLE
PARAMETERS
property - a String of the property to swap values eg. "alpha"
objA, objB - the objects on which to swap properties
RETURNS Boolean indicating success
--*///+17.1
zim.swapProperties = function(property, objA, objB) {
z_d("17.1");
if (zot(objA) || zot(objB) || zot(objA[property]) || zot(objB[property])) return false;
var temp = objB[property];
objB[property] = objA[property];
objA[property] = temp;
return true;
};//-17.1
/*--
zim.mobile = function(orientation)
mobile
zim function
DESCRIPTION
Detects if app is on a mobile device - if so, returns the mobile device type:
android, ios, blackberry, windows, other (all which evaluate to true) else returns false.
orientation defaults to true and if there is window.orientation then it assumes mobile
BUT this may return true for some desktop and laptop touch screens
so you can turn the orientation check off by setting orientation to false.
If orientation is set to false the check may miss non-mainstream devices
The check looks at the navigator.userAgent for the following regular expression:
/ip(hone|od|ad)|android|blackberry|nokia|opera mini|mobile|phone|nexus|webos/i
Microsoft mobile gets detected by nokia, mobile or phone.
NOTE: See also the ZIM MOBILE constant - this can be set to true or false to override mobile()
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
if (mobile()) {
var pane = new Pane(300, 200, "Desktop Only");
pane.show();
}
END EXAMPLE
PARAMETERS
orientation - (default true) uses window.orientation property to determine mobile
this may call certain touch screens mobile
but setting to false uses a test on mobile names which could be incomplete
RETURNS a String or false
--*///+28
zim.mobile = function(orientation) {
z_d("28");
if (typeof MOBILE != "undefined" && MOBILE!="default") return MOBILE;
if (!zot(zim.MOBILE) && zim.MOBILE!="default") return zim.MOBILE;
if (zot(orientation)) orientation = true;
if (/ip(hone|od|ad)/i.test(navigator.userAgent)) return "ios";
if (/android|nexus/i.test(navigator.userAgent)) return "android";
if (/blackberry/i.test(navigator.userAgent)) return "blackberry";
if (/nokia|phone|mobile/i.test(navigator.userAgent)) return "windows";
if (/opera mini|webos/i.test(navigator.userAgent)) return "other";
if (orientation && window.orientation !== undefined) {
if (/safari/i.test(navigator.userAgent)) return "ios";
return true;
}
return false;
};//-28
//
/*--
zim.vee = function(obj)
vee
zim function
DESCRIPTION
Determines if obj is a ZIM Pick() object or a Pick Literal - used by ZIM VEE parameters
Pick Literal format is [], {min:a, max:b}, function(){}, {noPick:x} or a function(){}
See https://zimjs.com/docs.html?type=Pick
ZIM Pick is a way to pass in dynamic parameters or style properties
This is very handy to pass in a series() function or an array for random pickings, etc.
Used to create dynamic particles with the Emitter or tile specific items in order, etc.
Pick.choose() accepts any value and if not in ZIM Pick format, will just return the object
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var color = [red, green, blue];
// ternary operator - if in Pick format, add "random" else ""
new Label((vee(color)?"random ":"") + "colors").center();
END EXAMPLE
PARAMETERS
obj - an object to pass in to test whether it is in ZIM VEE (Pick) format
RETURNS a Boolean true if Pick format or false if not (such as just a number, string, new Circle, etc.)
--*///+28.5
zim.vee = function(obj) {
z_d("28.5");
return !zot(obj) && (obj.type == "Pick" || Array.isArray(obj) || (obj.constructor == {}.constructor && (!zot(obj.max) || !zot(obj.noPick))) || typeof obj == "function");
};//-28.5
/*--
zim.extend = function(subclass, superclass, override, prefix, prototype)
extend
zim function - modified CreateJS extend and promote utility methods
DESCRIPTION
For ES5 - place after a sub class to extend a super class.
Extending a super class means that the sub class receives all the properties and methods of the super class.
For example, a ZIM Container() extends a CreateJS Container and then adds more methods and properties
but all the CreateJS Container methods and properties are still there too like x, y, addChild(), etc.
For ES6 - do not use zim.extend() but rather use the built in ES6 structures as follows:
EXAMPLE
// ES6 - do NOT use zim.extend()
class Person() {
constructor () {
zog("I am a person");
}
}
class Woman extends Person { // use JS6 extends keyword
constructor () {
super(); // use JS6 super() to call the Person constructor - will do the zog()
// Woman code
}
}
// ES6 to extend a zim Container for example (do NOT use zim.extend() in ES6)
class ChineseCoin extends Container { // use JS6 extends keyword
constructor () {
super(); // must call the zim Container before using keyword this
new Circle(100, "gold").addTo(this); // this will be the zim Container
new Rectangle(100, 100, "brown").center(this);
}
}
var coin = new ChineseCoin().center(); // coin is a zim Container with Circle and Rectangle inside
END EXAMPLE
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// ES5 examples using functions to make classes
// ES5 has no extends keyword and no super keyword so we use zim.extends()
function Person() {
this.talk = function() {
zog("I am a person");
}
}
function Woman() {
this.super_constructor(); // part of the zim.extend() system
}
extend(Woman, Person); // here is the zim.extend() for ES5
var woman = new Woman();
woman.talk();
END EXAMPLE
NOTE: CreateJS display objects require their constructor to be called otherwise it is like quantum entanglement (seriously)
extend() adds access to the super class constructor so it can be called in the subclass as follows:
this.super_constructor();
It also provides access to super class methods that are overridden
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// ES5 example - see the ES6 set of examples for ES6 ;-)
// make a Collection class that will extend a Container
// the Collection class will call the Container constructor
// and override the the ZIM Container center method in the class body
// and override the CreateJS Container addChild method in the prototype
// either method would work in either place - it is often a matter of preference
// but you might need to use a method in the class body to access local variables
// The ZIM extend() method parameter values need to change depending on where you override
// see the comments inline for the instructions
var Collection = function() {
// for CreateJS the super constructor must be run
this.super_constructor();
// override the zim center() method
// methods in the function call that override must be passed in as an array of strings
// to the override parameter of extend() to be able to access the super_method
this.center = function(where) {
this.super_center(where);
this.y -= 50;
}
}
// override the super class addChild() that comes from the CreateJS Container
// methods on the prototype that override are automatically provided a super_method
// unless the prototype parameter of extend() is set to false (default is true)
Collection.prototype.addChild = function(c) {
this.super_addChild(c); // call the super class addChild
zog("added a child to Collection");
}
// make the Collection extend a Container()
// it will receive all the properties and methods of the Container plus its own
extend(Collection, Container, "center"); // or pass an array of overridden methods
// use the Collection
var c = new Collection();
c.addChild(new Rectangle(100, 100, green)); // zogs "added a child to Collection"
c.center(); // centers the collection but then offsets it 50 pixels up
END EXAMPLE
NOTE: the superclass constructor is always available as this.prefix_constructor() no matter the override or prototype settings
NOTE: this.prefix_constructor(); should be called at the top of the subclass to avoid problems when multiple copies of object
NOTE: to extend a class that already extends a ZIM class then change the prefix to a unique name:
EXAMPLE
// if we already had the Collection example above and we want to extend that
// then we must use a new prefix when using extend()
var Records = function() {
this.Collection_constructor();
}
extend(Records, Collection, null, "Collection");
// you will still have this.super_center(), this.super_addChild() if needed
// plus any newly overridden methods available as this.Collection_methodName() etc.
var r = new Records();
r.addChild(new Circle(20, pink));
r.super_center(); // call the original center (without vertical shift)
// to extend again, use yet another prefix - for example: "Records"
var Jazz = function() {
this.Records_constructor();
}
extend(Jazz, Records, null, "Records");
END EXAMPLE
PARAMETERS supports DUO - parameters or single object with properties below
NOTE: do NOT use zim.extend() with ES6 - see ES6 examples at top instead
subclass - the class to extend
superclass - the class to extend from (an existing class)
override - (default null) an Array of methods (as Strings) to override.
You can override any function by just defining that function in the subclass
the override parameter gives you access to the overridden function in the superclass prototype
only methods on the superclass prototype can be accessed once overridden - not methods in the superclass body
if there is only one method being overridden then a single string is fine ("test" or ["test"] is fine)
any methods passed to this parameter will be given prefix_methodName() access on the sub class (this.prefix_methodName())
where the prefix is below (note, the prototype setting has no bearing on these manual overrides)
this list is only needed for methods in the subclass body
methods assigned to the prototype of the subclass that override are automatically given prefixes
prefix - (default "super") a prefix that will be followed by "_" and then the overridden method name
by default this.super_constructor() would call the super class constructor
if prefix is set to "Person" then this.Person_constructor() would call the super class constructor
the same system is used to call overridden files in override or prototype
prototype - (default true) will search the subclass prototype for overriding methods
the overridden methods are then available as this.prefix_methodName()
set to false to avoid searching the super class for methods overridden by the sub class prototype
just quickens the code minutely if there is no need
NOTE: extend() is included in Distill if DISPLAY, METHODS or FRAME Module classes are used (otherwise NOT included)
RETURNS the subclass
--*///+50.35
zim.extend = function(subclass, superclass, override, prefix, prototype) {
var sig = "subclass, superclass, override, prefix, prototype";
var duo; if (duo = zob(zim.extend, arguments, sig)) return duo;
if (zot(subclass) || zot(superclass)) {
if (zon && subclass!=zim.StageGL) zog("zim.extend() - please supply a class and its superclass");
return;
}
// zogr("start")
if (zot(prefix)) prefix = "super";
if (zot(override)) override = [];
if (!Array.isArray(override)) override = [override];
if (zot(prototype)) prototype = true;
// modified CreateJS extend() to include any prototype members already added
// see http://www.createjs.com/docs/easeljs/classes/Utility%20Methods.html
var existingP = {};
for (var f in subclass.prototype) Object.defineProperty(existingP,f,Object.getOwnPropertyDescriptor(subclass.prototype, f));
function o() {this.constructor = subclass;}
o.prototype = superclass.prototype;
subclass.prototype = new o();
for (f in existingP) {
Object.defineProperty(subclass.prototype,f,Object.getOwnPropertyDescriptor(existingP,f));
}
// modified CreateJS promote() to promote methods other than constructor only if methods is true
// zim does not override with prototypes so it is uneccessary to loop through the super class methods
// added checking an array of string values of methods defined in class (not prototype) that are being overridden
var subP = subclass.prototype;
var supP = (Object.getPrototypeOf&&Object.getPrototypeOf(subP))||subP.__proto__;
if (supP) {
subP[(prefix+="_") + "constructor"] = supP.constructor; // constructor is not always innumerable
var n;
for (var i=0; i<override.length; i++) {
n = override[i];
if (typeof supP[n] == "function") {
subP[prefix + n] = supP[n];
}
}
if (prototype) {
for (n in supP) {
if (subP.hasOwnProperty(n) && (typeof supP[n] == "function")) {subP[prefix + n] = supP[n];}
}
}
}
return subclass;
};
//-50.35
// SUBSECTION BASICS
/*--
zim.copy = function(obj, clone, cloneContainers)
copy
zim function
DESCRIPTION
Copies arrays and basic objects:
modified http://stackoverflow.com/users/35881/a-levy
If you have var obj = {prop:"val"};
and then try and copy obj to obj2 like so: obj2 = obj;
then obj2 and obj refer to the same object.
This means that after obj.prop = "new"; both obj.prop and obj2.prop would be "new".
copy(obj) returns a new object so both will work independently
and after obj.prop = "new"; obj2.prop would still be "val".
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var obj = {hair:blue, cars:["audi", "honda"]};
var cop = copy(obj);
cop.hair = "green";
zog(obj.hair, obj.cop); // blue, green
obj.cars.push("vw");
zog(obj.cars.length, cop.cars.length); // 3, 2
// copy with clone for cloneable objects
// without the second parameter as true these obj[0] and obj2[0] would be the same
// and when we do the second addTo it would just move the circle to the second position
var obj = [
new Circle(20,green),
new Rectangle(30,30,green),
new Triangle(40,40,40,green)
];
var obj2 = copy(obj, true); // copy and clone
obj[0].addTo(stage).pos(100, 200);
obj2[0].addTo(stage).pos(300, 400);
END EXAMPLE
PARAMETERS
obj - the object to copy
clone - (default false) set to true to clone any cloneable object while copying
cloneContainers - (default true if clone true) set to false to not copy objects with type="Container"
RETURNS a new Object
--*///+10
zim.copy = function(obj, clone, cloneContainer) {
if (!zim.copyCheck) {z_d("10"); zim.copyCheck = true;}
if (zot(clone)) clone = false;
if (zot(cloneContainer)) cloneContainer = true;
if (obj==null || !(obj instanceof Array || obj.constructor == {}.constructor)) return clone&&obj!=null?(obj.clone?(obj.type&&((obj.type!="Container"&&obj.type!="Stage"&&obj.type!="StageGL")||cloneContainer)?obj.clone():obj):obj):obj;
if (obj instanceof Array) {
var array = [];
for (var i=0; i<obj.length; i++) {
array[i] = zim.copy(obj[i], clone, cloneContainer);
}
return array;
}
if (obj.constructor == {}.constructor) {
var copy = {};
for (var attr in obj) {
var answer = zim.copy(obj[attr], clone, cloneContainer);
if (obj.hasOwnProperty(attr)) copy[attr] = answer;
}
return copy;
}
};//-10
/*--
zim.merge = function(objects)
merge
zim function
DESCRIPTION
Merges any number of objects {} you pass in as parameters.
Overwrites properties if they have the same name.
Returns a merged object with original objects kept intact.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var one = {food:"chocolate"};
var two = {drink:"milk"};
var tri = merge(one, two);
zog(tri.food, tri.drink); // chocolate, milk
END EXAMPLE
PARAMETERS
objects - a list of objects (any number) to merge together
RETURNS a new Object
--*///+12
zim.merge = function() {
if (!zim.mergeCheck) {z_d("12"); zim.mergeCheck = true;}
var obj = {}; var i; var j;
for (i=0; i<arguments.length; i++) {
for (j in arguments[i]) {
if (arguments[i].hasOwnProperty(j)) {
obj[j] = arguments[i][j];
}
}
}
return obj;
};//-12
/*--
zim.arraysEqual = function(a, b, strict)
arraysEqual
zim function
DESCRIPTION
Finds out if arrays are same (including nested arrays).
Works for arrays with strings and numbers (not necessarily other objects).
(Slightly modified Evan Steinkerchnerv & Tomas Zato)
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var one = [1,2,"wow",[3,4]];
var two = [1,2,"wow",[3,4]];
zog(arraysEqual(one, two)); // true
one[3][1] = 5;
zog(arraysEqual(one, two)); // false
END EXAMPLE
PARAMETERS
a, b - the arrays to check to see if they are equal
strict - (default true) set to false so order in arrays does not matter
RETURNS a Boolean
--*///+11
zim.arraysEqual = function(a, b, strict) {
z_d("11");
if (zot(a) || zot(b)) return false;
if (zot(strict)) strict = true; // must be the same order
if (a.length != b.length) return false;
for (var i = 0; i < a.length; i++) {
if (a[i] instanceof Array && b[i] instanceof Array) {
if (!zim.arraysEqual(a[i], b[i], strict)) return false;
}
else if (strict && a[i] != b[i]) {
return false;
}
else if (!strict) {
return zim.arraysEqual(a.sort(), b.sort(), true);
}
}
return true;
};//-11
/*--
zim.isEmpty = function(obj)
isEmpty
zim function
DESCRIPTION
returns whether an object literal is empty
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var o = {};
zog( isEmpty(o) ); // true
o.test = 9;
zog( isEmpty(o) ); // false
END EXAMPLE
PARAMETERS
obj - the object literal to test
RETURNS a Boolean
--*///+11.5
zim.isEmpty = function(obj) {
if (!zim.zimEmptyCheck) {z_d("11.5"); zim.zimEmptyCheck = true;}
if (zot(obj)) return;
var count = 0;
for (var o in obj) {
count++; break;
}
return (count == 0);
};//-11.5
/*--
zim.isJSON = function(str)
isJSON
zim function
DESCRIPTION
returns whether a string is a JSON string
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var s = '{"age":7,"name":"Dan Zen"}';
zog( isJSON(s) ); // true
var b = "hello";
zog( isJSON(b) ); // false
END EXAMPLE
PARAMETERS
str - the string to test
RETURNS a Boolean
--*///+11.6
zim.isJSON = function(str) {
z_d("11.6");
if (typeof str != "string") {
return false;
}
try {
JSON.parse(str);
return true;
}
catch (error) {
return false;
}
};//-11.6
/*--
zim.isPick = function(obj)
isPick
zim function
DESCRIPTION
Returns whether an object is a SPECIAL Pick literal
of type [], {min:val, max:val}, or function that returns a value
If any other object is passed to Pick, it just gets passed through
So in theory, all objects are in Pick literal format
but isPick() returns true if object operated on, not just passed through
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
zog(isPick(1)); // false
zog(isPick([1,2,3])); // true
zog(isPick({age:10})); // false
zog(isPick({min:10,max:20})); // true
zog(isPick(function(){})); // false
zog(isPick(function(){return 20;})); // true
var s = series(1,2,3);
zog(isPick(s)); // true
// important that the isPick() does not run the series to test if ZIM VEE
// so it checks the array property of series rather than checking for a function return value
zog(s()); // 1
END EXAMPLE
PARAMETERS
obj - the string to test
RETURNS a Boolean as to whether obj is SPECIAL ZIM Pick literal
--*///+11.7
zim.isPick = function(obj) {
if (!zim.zimPickCheck) {z_d("11.7"); zim.zimPickCheck = true;}
if(zot(obj)) return;
return (Array.isArray(obj)||(obj.constructor=={}.constructor && obj.min!=null && obj.max!=null)||(obj.constructor === Function && (obj.array!=null || obj()!=null))); // obj.array is a series
};//-11.7
/*--
zim.decimals = function(num, places, addZeros, addZerosBefore, includeZero, time)
decimals
zim function
DESCRIPTION
Rounds number to the number of decimal places specified by places.
Negative number places round to tens, hundreds, etc.
If addZeros is set to a number it adds 0 in empty spaces up to that many places after the decimal
If addZerosBefore is set to a number it adds 0 in empty spaces up to that many places before the decimal
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var score = 1.234;
score = decimals(score);
zog(score); // 1.2
zog(decimals(1.8345, 2)); // 1.83
zog(decimals(123,-1)); // 120
zog(decimals(2.3,null,2)); // 2.30
zog(decimals(3,null,null,2)); // 03
zog(decimals(.12,2,2,1,null,true)); // 0:12
END EXAMPLE
PARAMETERS
num - the Number to operate on
places - (default 1) how many decimals to include (negative for left of decimal place)
addZeros - (default 0) set to number of places to fill in zeros after decimal (and return String)
addZerosBefore - (default 0) set to number of places to fill in zeros before decimal (and return String)
includeZero - (default true) set to false to always have zero just be 0 without any extra zeros
time - (default false) a swap of : for . to handle minutes and seconds (not hours)
RETURNS a rounded Number or a String if addZeros, addZerosBefore or time is true
--*///+13
zim.zut = function(e) {
if (zot(e) || typeof e == "object") return true;
};
zim.decimals = function(num, places, addZeros, addZerosBefore, includeZero, time, evt) {
if (!zim.zimDecimalCheck) {z_d("13"); zim.zimDecimalCheck = true;}
if (zot(num)) return 0;
if (zot(places)) places = 1;
if (zot(addZeros)) addZeros = 0;
if (zot(addZerosBefore)) addZerosBefore = 0;
if (zot(addZerosBefore)) addZerosBefore = 0;
if (zot(includeZero)) includeZero = true;
if (zot(time)) time = false;
// if (addZeros && places < 0) {
// var place = String(num).indexOf(".");
// var length = String(num).length;
// var left = (place < 0) ? length : place;
// for (var i=0; i<-places-left; i++) {num = "0" + num;}
// return num;
// }
var answer = Math.round(num*Math.pow(10, places))/Math.pow(10, places);
if (time) {
var secs = answer - Math.floor(answer);
answer = zim.decimals(Math.floor(answer) + secs*60/100, 2);
}
// if (addZeros && places > 0 && answer != 0) {
// var place = String(answer).indexOf(".");
// var length = String(answer).length;
// if (place < 0) {place = length++; answer+=".";}
// for (var i=0; i<places-(length-place-1); i++) {answer += "0";}
// }
var sign = zim.sign(answer);
if (addZeros > 0) {
var place = String(answer).indexOf(".");
var length = String(answer).length;
if (place < 0) {place = length++; answer+=".";}
for (var i=0; i<addZeros-(length-place-1); i++) {answer += "0";}
}
if (addZerosBefore > 0) {
// fix this - Dan Zen - negative decimal number problem
if (sign == -1) answer = answer.substr(1,answer.length-1);
var place = String(answer).indexOf(".");
var length = String(answer).length;
var left = (place < 0) ? length : place;
for (var i=0; i<addZerosBefore-left; i++) {answer = "0" + answer;}
if (sign == -1) answer = "-" + answer;
}
if ((addZeros + addZerosBefore > 0) && !includeZero && Number(answer) == 0) answer = 0;
if (time) answer = String(answer).replace(".", ":");
return zim.zut(evt) ? answer : null;
};//-13
/*--
zim.sign = function(num)
sign
zim function
DESCRIPTION
returns -1, 0 or 1 depending on whether the number is less than, equal to or greater than 0
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var speed = 20;
zog(sign(speed)); // 1
var speed = 0;
zog(sign(speed)); // 0
var speed = -20;
zog(sSign(speed)); // -1
END EXAMPLE
PARAMETERS
num - the Number to operate on
RETURNS -1, 0 or 1
--*///+13.1
zim.sign = function(num) {
if (!zim.zimSignCheck) {z_d("13.1"); zim.zimSignCheck=true;}
return num?num<0?-1:1:0;
};//-13.1
/*--
zim.constrain = function(num, min, max, negative)
constrain
zim function
DESCRIPTION
returns a number constrained to min and max
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var cirle.x = constrain(circle.x, circle.radius, stageW-circle.radius);
// circle.x will not be smaller than the radius or bigger than stageW-radius
var speed = constrain(speed, minSpeed, maxSpeed, true);
// will confine the speed between minSpeed and maxSpeed if speed is positive
// and confine the speed between -maxSpeed and -minSpeed if the speed is negative
END EXAMPLE
PARAMETERS
num - the number to be constrained
min - (default 0) the minimum value of the return number
max - (default Number.MAX_VALUE) the maximum value of the return number
negative - (default false) allow the negative range of min and max when num is negative
RETURNS num if between min and max otherwise returns min if less or max if greater (inclusive)
RETURNS num between -max and -min if num is negative and negative parameter is set to true
--*///+13.2
zim.constrain = function(num, min, max, negative) {
z_d("13.2");
if (zot(num)) return;
if (zot(min)) min = 0;
if (zot(max)) max = Number.MAX_VALUE;
if (max < min) {var max2 = min; max = min; min = max2;} // ES6 Fix to come
if (zot(negative)) negative = false;
if (negative && num < 0) {
return Math.max(-max, Math.min(num, -min));
} else {
return Math.max(min, Math.min(num, max));
}
};//-13.2
/*--
zim.dist = function(a, b, c, d)
dist
zim function
DESCRIPTION
Calculates the distance between two points.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// using point values for each
var p1 = new Point(100, 100); // or {x:100, y:100}
var p2 = new Point(200, 200);
zog(dist(p1, p2)); // 141.42...
END EXAMPLE
EXAMPLE
// using x and y values for each
var distance = dist(stageW/2, stageH/2, frame.mouseX, frame.mouseY);
// distance of mouse from center of stage
END EXAMPLE
PARAMETERS
a - first Point - any object with x and y values - eg. a zim Container or zim Point or {x:10, y:30}
or if four parameter values, an x value of the first point
b - second Point - any object with x and y values
or if four parameter values, a y value of the first point
c - (default null) an x value of a second point - if using x and y values
d - (default null) a y value of a second point - if using x and y values
RETURNS a positive Number that is the distance (could be on an angle)
--*///+13.3
zim.dist = function(a, b, c, d) {
if (!zim.zimDistCheck) {z_d("13.3"); zim.zimDistCheck=true;}
if (zot(a) || zot(b)) return;
if (!zot(a.x) && !zot(b.x)) {
d = b.y;
c = b.x;
b = a.y;
a = a.x;
} else {
if (zot(c)) c = 0;
if (zot(d)) d = 0;
}
return Math.sqrt((Math.pow(c-a, 2) + Math.pow(d-b, 2)));
};//-13.3
//
/*--
zim.rectIntersect = function(a, b, margin)
rectIntersect
zim function
DESCRIPTION
Returns true if two rectangles are intersecting - this is a very fast but exact calculation
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// using point values for each
var r1 = {x:100, y:100, width:300, height:200}
var r2 = new Boundary(50,200,100,100);
zog(rectIntersect(r1, r2)); // true
END EXAMPLE
PARAMETERS
a - first rectangle with x, y, width and height properties - such as a bounds or Boundary
make sure that these are in the same coordinate systems - use ZIM boundsToGlobal for instance
b - second rectangle with x, y, width and height properties
margin - (default 0) positive value adds margin (more likely to intersect) and negative subtracts (less likely to intersect)
RETURNS a Boolean as to whether rectangles are intersecting
--*///+13.32
zim.rectIntersect = function(a, b, margin) {
if (!zim.zimRectIntersectCheck) {z_d("13.32"); zim.zimRectIntersectCheck=true;}
if (zot(margin)) margin = 0;
if (a.x >= b.x + b.width + margin || a.x + a.width + margin <= b.x ||
a.y >= b.y + b.height + margin || a.y + a.height + margin <= b.y ) {
return false;
} else {
return true;
}
};//-13.32
//
/*--
zim.boundsAroundPoints = function(points)
boundsAroundPoints
zim function
DESCRIPTION
Returns a rectangle {x,y,width,height} around an array of points {x,y}
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var blob = new Blob();
var points = blob.interpolate();
zog(boundsAroundPoints(points)); // {x:-100, y:-100, width:200, height:200}
// could call this after resizing the blob to get the rough bounds of the blob (or squiggle)
// interpolate defaults to 1 so setting 5 would be even more precise, etc.
END EXAMPLE
PARAMETERS
points - an array of points with x and y properties.
RETURNS an object with x, y, width and height properties
representing the rectangle around the points provided
--*///+13.34
zim.boundsAroundPoints = function(points) {
if (!zim.zimBoundsAroundPointsCheck) {z_d("13.34"); zim.zimBoundsAroundPointsCheck=true;}
var tX = 10000;
var tY = 10000;
var bX = -10000;
var bY = -10000;
for (var i=0; i<points.length; i++) {
var p = points[i];
if (p.x < tX) tX = p.x;
if (p.x > bX) bX = p.x;
if (p.y < tY) tY = p.y;
if (p.y > bY) bY = p.y;
}
return {x:tX, y:tY, width:bX-tX, height:bY-tY};
};//-13.34
/*--
zim.angle = function(x1, y1, x2, y2)
angle
zim function
DESCRIPTION
Calculates the angle between two points relative to the positive x axis
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var angle = angle(stageW/2, stageH/2, stageW/2+100, stageH/2+100); // 45
// angle from center of stage to 100, 100 to the right and down from the center of the stage
var angle2 = angle(stageW/2, stageH/2, stageW/2-100, stageH/2+100); // 135
var angle3 = angle(stageW/2, stageH/2, stageW/2+100, stageH/2-100); // 315
END EXAMPLE
PARAMETERS
x1, y1 - first point x and y
unless no second point in which case x1, y1 will be second point and first point will be 0, 0
x2, y2 - second point x and y
RETURNS a positive Number that is the angle between first and second point relative to positive x axis
--*///+13.4
zim.angle = function(x1, y1, x2, y2) {
if (!zim.angleCheck) {z_d("13.4"); zim.angleCheck = true;}
if (zot(x1) || zot(y1)) return;
if (zot(x2)) {x2 = x1; x1 = 0;}
if (zot(y2)) {y2 = y1; y1 = 0;}
return (Math.atan2(y2-y1, x2-x1)*180/Math.PI+360)%360;
};//-13.4
/*--
TAU, DEG, RAD
TAU, DEG, RAD
zim constants
DESCRIPTION
ZIM degrees and radian constants
If working in radians, TAU is equal to 2 radians (360).
This allows easy visualization of angles - TAU/2 is 180, TAU/4 is 90, etc.
DEG is 180/Math.PI so you multiply a radian value by DEG to get degrees.
RAD is Math.PI/180 so you multiply a degree value by RAD to get radians.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
Math.sin(TAU/4); // sin of 90 degrees (1)
// is same as
Math.sin(90*RAD);
// is same as
Math.sin(90*Math.PI/180);
// and
Math.asin(1)*DEG; // is 90
END EXAMPLE
--*///+83.6
zim.TAU = Math.PI * 2;
zim.DEG = 180/Math.PI;
zim.RAD = Math.PI/180;
//-83.6
/*--
zim.smoothStep = function(num, min, max)
smoothStep
zim function
DESCRIPTION
smoothStep takes an input value and outputs a value between 0 and 1
that represents a transition between the min and max with easing at both ends.
If you want the easing to be more pronounced, then reduce difference between min and max.
If the value falls outside the min or max then it is set to the min or max.
Remember the return value is between 0 and 1 so you can multiply by max-min and add it to min
to get a value at the original scale.
Used to make blobs with Noise(): https://zimjs.com/noise/blobs.html
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// here we use smoothStep to make a gradient between black and white
// not an even one right across but a gradient across a transition zone of 40-100
// create an empty Bitmap size 200, 200 and center it on the stage
var bmp = new Bitmap(null, 200, 200).center();
// we need to loop and get a value for each pixel
// normally we loop across the rows and then do each column
// but here we are making a horizontal gradient
// so we will loop across the x and get the desired value
// then when we loop across the y in the inner loop, we just use that same value
for (var x = 0; x < bmp.width; x++) {
// making gradient in x only so calculate smoothStep here
// x will be from 0 to the width of 200
// we pass in a min of 40 and a max of 100
// the result of smoothStep is between 0 and 1
// so from 0 to 40 the return of smoothStep will be 0
// and from 100 to 200 the return of smoothStep will be 1
// In between, the return value starts off close to 0, then speeds up
// and then slows down to 1 in a curve that is somewhat like the letter f
// When we multiply by 255 and apply that result to each color,
// we get black and then a range of greys and then white
var value = smoothStep(x, 40, 100)*255;
// now we loop down the column for the x position
for (var y = 0; y < bmp.height; y++) {
// imageData is four values per pixel
// the red, green, blue and alpha
// in one big long array - each value will be constrained to between 0 and 255
// this i value will increase by 4 each time
// then we write the same value for red, green, blue to get a shade of grey
var i = (x + y * bmp.width) * 4;
bmp.imageData.data[i] = value; // red (0-255)
bmp.imageData.data[i + 1] = value; // green (0-255)
bmp.imageData.data[i + 2] = value; // blue (0-255)
bmp.imageData.data[i + 3] = 255; // alpha (0-255)
}
}
bmp.drawImageData(); // draw the imageData to the Bitmap
END EXAMPLE
PARAMETERS
num - the input value with respect to min and max
min - the lower edge for smoothStep (often termed edge0) - anything smaller will be set to min
max - the upper edge for smoothStep (often termed edge1) - anything bigger will be set to max
RETURNS a number between 0 and 1 that represents a transition factor
--*///+13.7
zim.smoothStep = function(num, min, max) {
z_d("13.7");
var x = zim.constrain((num - min)/(max - min), 0, 1);
return x*x*x*(x*(x*6 - 15) + 10); // Perlin
};//-13.7
// SUBSECTION CLASSES
/*--
zim.Ajax = function(master, couple, lock, unique)
Ajax
zim class
DESCRIPTION
An AJAX class to send data back and forth to a server without reloading the page
NOTE: also see ZIM async() to send data back and forth as JSONp
using async can avoid various security issues with cross domain access
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// GET - note: GET is limited to approximately 2048 characters
var ajax = new Ajax();
new Button().center().tap(function () {
ajax.get("https://yourserver/ajax.php?record=pressed");
});
<?php
$record = isset($_GET["record"]) ? $_GET["record"] : "";
// $record would now hold the string "pressed"
?>
END EXAMPLE
EXAMPLE
// GET with user input and server response
var query = new TextArea(300,90).center();
new Button({label:"SUBMIT", corner:5}).sca(.7).pos(0,100,CENTER,CENTER)
.tap(function () {
new Ajax().get("https://yourserver/ajax.php?query="+encodeURI(query.text), callback);
});
function callback(data) {
query.text = "Date: " + data.date + "\nAnswer: " + data.answer;
}
<?php
$query = isset($_GET["query"]) ? $_GET["query"] : "";
// probably get info from database
$array = [];
$array["date"] = "March 10, 2020";
$array["answer"] = "yes, of course!";
echo json_decode($array);
?>
END EXAMPLE
EXAMPLE
// POST - virtually unlimited size
var ajax = new Ajax();
new Button().center().tap(function () {
var data = {name:"Dr Abstract", occupatio:"creator"};
// data will automatically have JSON.stringify() applied
var id = "AB234";
ajax.post("https://yourserver/ajax.php", data, "add", id, callback);
});
function callback(data) {
zog(data.name); // "Dr Abstract"
}
<?php
// ZIM Ajax POST the data is received as a data property:
$data = isset($_POST["data"]) ? $_POST["data"] : "";
// a command can be sent for add, select, update, delete, etc.
$command = isset($_POST["command"]) ? $_POST["command"] : "";
// extra information can be collected such as an id, etc.
$extra = isset($_POST["extra"]) ? $_POST["extra"] : "";
// add $data to database as JSON string for the id in the $extra
if ($command == "add") {}
// The data can be decoded too
$array = json_decode($data, true);
// here we "round-trip" to show it can be done
// send back encoded info from Database
echo json_encode($array);
?>
END EXAMPLE
EXAMPLE
// put - sends data in body of content
// same as POST but no command and receive in PHP as follows:
<?php
// ZIM Ajax put receive as follows:
$array = json_decode(file_get_contents('php://input'), true);
?>
END EXAMPLE
PARAMETERS
master - data to be sent with every get() or post() (not put())
this can be collected in php, for example, as $GET_["master"] or $POST_["master"]
couple - (default false) - set to true to turn nested JSON into a single layer
** for POST only - use ZIM couple() and decouple() manually with GET and PUT
see ZIM couple() and decouple() for more information
data for POST will be coupled when sent and uncoupled when received
lock - (defualt null) send an optional lock id - would need to be processed on the server
unique - (defualt null) send an optional unique=true - would need to be processed on the server
METHODS
get(url, call) - send and receive based on GET (approximate limit 2048 characters)
the url will have parameters in cgi format to send information
for example: "server.php?name="+encodeURI("Dr Abstract")+"&occupation=creator";
in PHP access these with $_GET["name"], $_GET["occupation"], etc.
call is the function to call and will receive (data, error) as parameters
the data will automatically have JSON.parse() applied if in JSON format
post(url, data, command, extra, call) - send and receive based on POST
** accepts the ZIM DUO technique of regular parameters or a configuration object with properties matching parameters
url is the url to a server script such as php or node
the url will not need parameters but rather use the data, command and extra
data will automatically have JSON.stringify() applied
in PHP access this with $data = $_POST["data"];
often, we might store this directly as JSON in the database
but it can be split up and put in fields as follows
$assoc = json_decode($data, true); // true for assoc array if desired
command is what to do with the data and will be encodeURI sent as variable command
so for instance receive $command = $_POST["command"];
this could have a value of "select", "add", "update", "delete", etc.
extra is any extra filter information and will be encodeURI sent as variable extra
so for instance receive $extra = $_POST["extra"];
this could be an id or a search term
call is the function to call and will receive (data, error) as parameters
the data will automatically have JSON.parse() applied if in JSON format
put(url, data, call) - send and receive based on PUT
put sends data in the body of the file
the url will not have parameters but rather use the data
the data will automatically have JSON.stringify() applied
in PHP access this with: $array = json_decode(file_get_contents('php://input'), true);
call is the function to call and will receive (data, error) as parameters
the data will automatically have JSON.parse() applied if in JSON format
PROPERTIES
master - get or set the master data being sent with each get() or post() (not put())
couple - get or set whether the POST data is coupled when sent and uncoupled when received (not get() and put())
lock - get or set the lock data being sent with each get() or post() (not put())
--*///+13.8
zim.Ajax = function(master, couple, lock, unique) {
z_d("13.8");
var http = new XMLHttpRequest();
this.master = master;
this.couple = couple;
this.lock = lock;
this.unique = unique;
var that = this;
this.get = function(url, callback) {
// add here in case property is changed
var addMaster = !zot(that.master)?"&master="+encodeURI(master):"";
var addLock = !zot(that.lock)?"&lock="+encodeURI(lock):"";
var addUnique = that.unique?"&unique=true":"";
http.open('GET', url+addMaster+addLock+addUnique, true);
http.onload = function() {
if (http.status==200) {
callback(zim.isJSON(http.responseText)?JSON.parse(http.responseText):http.responseText);
} else {
callback(null, 'Error: '+http.status);
}
};
http.send();
};
this.post = function(url, data, command, extra, callback) {
var sig = "url, data, command, extra, callback";
var duo; if (duo = zob(that.post, arguments, sig)) return duo;
if (zot(url)) return;
http.open('POST', url, true);
http.setRequestHeader('Content-type', "application/x-www-form-urlencoded");
http.onload = function() {
var r = http.responseText;
if (zim.isJSON(r)) {
if (that.couple) r = zim.decouple(r);
r = JSON.parse(r);
}
callback(r);
// callback(isJSON(http.responseText)?JSON.parse(http.responseText):http.responseText);
};
if (!zim.isJSON(data)) data = JSON.stringify(data);
if (that.couple) data = zim.couple(data);
var addMaster = !zot(that.master)?"&master="+encodeURIComponent(that.master):"";
var addLock = !zot(that.lock)?"&lock="+encodeURIComponent(that.lock):"";
// var addUnique = that.unique?"&unique=true":"";
var addCommand = !zot(command)?"&command="+encodeURIComponent(command):"";
var addExtra = !zot(extra)?"&extra="+encodeURIComponent(extra):"";
http.send("data="+encodeURIComponent(data)+addMaster+addLock+addCommand+addExtra);
};
this.put = function(url, data, callback) {
http.open('PUT', url, true);
http.setRequestHeader('Content-type', 'application/json');
http.onload = function() {
callback(zim.isJSON(http.responseText)?JSON.parse(http.responseText):that.http.responseText);
};
http.send(JSON.stringify(data));
};
};//-13.8
/*--
zim.Noise = function(seed)
Noise
zim class
DESCRIPTION
Noise creates OpenSimplex Noise: https://en.wikipedia.org/wiki/OpenSimplex_noise
Converted from https://www.npmjs.com/package/open-simplex-noise
See examples at https://zimjs.com/noise/
In general, this is special noise where the pixels relate to one another in a complex way.
This connection, lets us do things like create terrains or blobs, etc. that look organic.
There is 1D, 2D, 3D, and 4D noise where we pass in one value, two values, three values and four values.
We always get back a number between -1 and 1 and this result relates to the results around it.
1D - we can plot 1D by drawing line segments across the stage (x) and setting the y value to the result of simplex1D(x)
This makes a 2D mountain-like terrain across the stage
2D - if we keep the plot from the 1D but use 2D and change the second parameter, we can animate the line.
We just need to adjust the second parameter by a very small amount each time such as .005.
Or we can plot put the return value of simplex2D onto its x,y matching location in a Bitmap
mapping it to a greyscale to make a traditional noise pattern.
We can adjust the "size" of the noise by dividing the x and y values (frequency).
If we use the ZIM smoothStep() function we can smoothen these to make blobs.
We can also use the return value as height for 3D terrain.
3D - if we keep the traditional noise/blob pattern from the 2D but use simplex3D and animate the third parameter,
we can animate the 2D noise in time which looks great when we animate blobs!
This plotting is thousands of computations and will bog the computer if too big.
4D - will allow us to animate 3D values, etc.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// 1D Noise to make a jagged line across the stage
var noise = new Noise();
var shape = new Shape(stageW, stageH).addTo(stage);
shape.graphics.s("black").ss(2).mt(0, stageH/2);
loop(stageW/50, function(i) {
shape.graphics.lt((i+1)*50, stageH/2 + noise.simplex1D(i)*200);
});
// the above can be animated by using simplex2D and animating the second number by small amounts
END EXAMPLE
EXAMPLE
// 2D noise
// create a Noise object:
var noise = new Noise();
// create an empty Bitmap size 200, 200 into which to draw the noise
var bmp = new Bitmap(null, 200, 200).center();
// we fill the bitmap starting from top left going across in the inner loop,
// then down, then across, etc. until we get to bottom right.
for (var y = 0; y < bmp.height; y++) {
for (var x = 0; x < bmp.width; x++) {
// the noise methods return a number from -1 to 1
// by adding 1 we get a number between 0 and 2 and we divide by 2 to get 0-1
// and we multiply this by 255 to get a number between 0 and 255
var value = (noise.simplex2D(x,y)+1)/2 * 255;
// imageData is one big array with four values per pixel
// the red, green, blue and alpha
// each value will constrained to between 0 and 255
// the i value is how many on the current row plus the columns from the previous rows
// and we set it to increase by 4 each time giving us a place for each color and alpha
// We write the same value for red, green, blue to get a shade of grey
var i = (x + y * bmp.width) * 4;
bmp.imageData.data[i] = value; // red (0-255)
bmp.imageData.data[i + 1] = value; // green (0-255)
bmp.imageData.data[i + 2] = value; // blue (0-255)
bmp.imageData.data[i + 3] = 255; // alpha (0-255)
}
}
bmp.drawImageData(); // this draws the imageData to the Bitmap
// Here is the same example to get blobs using smoothStep:
var f = 25; // try changing this number around
for (var y = 0; y < bmp.height; y++) {
for (var x = 0; x < bmp.width; x++) {
var value = (noise.simplex2D(x/f, y/f)+1)/2; // 0-1
// smoothStep sets less than .3 to 0 and greater than .35 to 1
// and transitions between using an easing formula in the shape of an f
var value = smoothStep(value, .3, .35) * 255;
var i = (x + y * bmp.width) * 4;
bmp.imageData.data[i] = value; // red (0-255)
bmp.imageData.data[i + 1] = value; // green (0-255)
bmp.imageData.data[i + 2] = value; // blue (0-255)
bmp.imageData.data[i + 3] = 255; // alpha (0-255)
}
}
bmp.drawImageData();
END EXAMPLE
PARAMETERS
seed - (default Math.random()*1000000) keeping the same seed can remake a pattern the same
METHODS
simplex1D(x) - returns a noise value between -1 and 1
In each method, the noise value relates to its neighbor rather than a completely random value
simplex2D(x,y) - returns a noise value between -1 and 1
simplex3D(x,y,z) - returns a noise value between -1 and 1
simplex4D(x,y,z,w) - returns a noise value between -1 and 1
PROPERTIES
seed - read only - the seed that was used for the Noise object
--*///+13.9
zim.Noise = function(seed) {
"use strict";
z_d("13.9");
if (zot(seed)) seed = Math.random()*1000000;
var clientSeed = seed;
this.seed = seed;
var that = this;
var con = {}; // holds the constants
con.NORM_2D = 1.0 / 47.0;
con.NORM_3D = 1.0 / 103.0;
con.NORM_4D = 1.0 / 30.0;
con.SQUISH_2D = (Math.sqrt(2 + 1) - 1) / 2;
con.SQUISH_3D = (Math.sqrt(3 + 1) - 1) / 3;
con.SQUISH_4D = (Math.sqrt(4 + 1) - 1) / 4;
con.STRETCH_2D = (1 / Math.sqrt(2 + 1) - 1) / 2;
con.STRETCH_3D = (1 / Math.sqrt(3 + 1) - 1) / 3;
con.STRETCH_4D = (1 / Math.sqrt(4 + 1) - 1) / 4;
con.base2D = [
[1, 1, 0, 1, 0, 1, 0, 0, 0],
[1, 1, 0, 1, 0, 1, 2, 1, 1]
];
con.base3D = [
[0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1],
[2, 1, 1, 0, 2, 1, 0, 1, 2, 0, 1, 1, 3, 1, 1, 1],
[1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 2, 1, 1, 0, 2, 1, 0, 1, 2, 0, 1, 1]
];
con.base4D = [
[0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1],
[3, 1, 1, 1, 0, 3, 1, 1, 0, 1, 3, 1, 0, 1, 1, 3, 0, 1, 1, 1, 4, 1, 1, 1, 1],
[
1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 2, 1, 1, 0, 0, 2, 1, 0, 1, 0, 2, 1, 0, 0, 1, 2, 0, 1, 1,
0, 2, 0, 1, 0, 1, 2, 0, 0, 1, 1
],
[
3, 1, 1, 1, 0, 3, 1, 1, 0, 1, 3, 1, 0, 1, 1, 3, 0, 1, 1, 1, 2, 1, 1, 0, 0, 2, 1, 0, 1, 0, 2, 1, 0, 0, 1, 2, 0, 1, 1,
0, 2, 0, 1, 0, 1, 2, 0, 0, 1, 1
]
];
con.gradients2D = [5, 2, 2, 5, -5, 2, -2, 5, 5, -2, 2, -5, -5, -2, -2, -5];
con.gradients3D = [
-11, 4, 4, -4, 11, 4, -4, 4, 11,
11, 4, 4, 4, 11, 4, 4, 4, 11,
-11, -4, 4, -4, -11, 4, -4, -4, 11,
11, -4, 4, 4, -11, 4, 4, -4, 11,
-11, 4, -4, -4, 11, -4, -4, 4, -11,
11, 4, -4, 4, 11, -4, 4, 4, -11,
-11, -4, -4, -4, -11, -4, -4, -4, -11,
11, -4, -4, 4, -11, -4, 4, -4, -11
];
con.gradients4D = [
3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3,
-3, 1, 1, 1, -1, 3, 1, 1, -1, 1, 3, 1, -1, 1, 1, 3,
3, -1, 1, 1, 1, -3, 1, 1, 1, -1, 3, 1, 1, -1, 1, 3,
-3, -1, 1, 1, -1, -3, 1, 1, -1, -1, 3, 1, -1, -1, 1, 3,
3, 1, -1, 1, 1, 3, -1, 1, 1, 1, -3, 1, 1, 1, -1, 3,
-3, 1, -1, 1, -1, 3, -1, 1, -1, 1, -3, 1, -1, 1, -1, 3,
3, -1, -1, 1, 1, -3, -1, 1, 1, -1, -3, 1, 1, -1, -1, 3,
-3, -1, -1, 1, -1, -3, -1, 1, -1, -1, -3, 1, -1, -1, -1, 3,
3, 1, 1, -1, 1, 3, 1, -1, 1, 1, 3, -1, 1, 1, 1, -3,
-3, 1, 1, -1, -1, 3, 1, -1, -1, 1, 3, -1, -1, 1, 1, -3,
3, -1, 1, -1, 1, -3, 1, -1, 1, -1, 3, -1, 1, -1, 1, -3,
-3, -1, 1, -1, -1, -3, 1, -1, -1, -1, 3, -1, -1, -1, 1, -3,
3, 1, -1, -1, 1, 3, -1, -1, 1, 1, -3, -1, 1, 1, -1, -3,
-3, 1, -1, -1, -1, 3, -1, -1, -1, 1, -3, -1, -1, 1, -1, -3,
3, -1, -1, -1, 1, -3, -1, -1, 1, -1, -3, -1, 1, -1, -1, -3,
-3, -1, -1, -1, -1, -3, -1, -1, -1, -1, -3, -1, -1, -1, -1, -3
];
con.lookupPairs2D = [0, 1, 1, 0, 4, 1, 17, 0, 20, 2, 21, 2, 22, 5, 23, 5, 26, 4, 39, 3, 42, 4, 43, 3];
con.lookupPairs3D = [
0, 2, 1, 1, 2, 2, 5, 1, 6, 0, 7, 0, 32, 2, 34, 2, 129, 1, 133, 1, 160, 5, 161, 5, 518, 0, 519, 0, 546, 4, 550, 4, 645,
3, 647, 3, 672, 5, 673, 5, 674, 4, 677, 3, 678, 4, 679, 3, 680, 13, 681, 13, 682, 12, 685, 14, 686, 12, 687, 14, 712,
20, 714, 18, 809, 21, 813, 23, 840, 20, 841, 21, 1198, 19, 1199, 22, 1226, 18, 1230, 19, 1325, 23, 1327, 22, 1352, 15,
1353, 17, 1354, 15, 1357, 17, 1358, 16, 1359, 16, 1360, 11, 1361, 10, 1362, 11, 1365, 10, 1366, 9, 1367, 9, 1392, 11,
1394, 11, 1489, 10, 1493, 10, 1520, 8, 1521, 8, 1878, 9, 1879, 9, 1906, 7, 1910, 7, 2005, 6, 2007, 6, 2032, 8, 2033,
8, 2034, 7, 2037, 6, 2038, 7, 2039, 6
];
con.lookupPairs4D = [
0, 3, 1, 2, 2, 3, 5, 2, 6, 1, 7, 1, 8, 3, 9, 2, 10, 3, 13, 2, 16, 3, 18, 3, 22, 1, 23, 1, 24, 3, 26, 3, 33, 2, 37, 2,
38, 1, 39, 1, 41, 2, 45, 2, 54, 1, 55, 1, 56, 0, 57, 0, 58, 0, 59, 0, 60, 0, 61, 0, 62, 0, 63, 0, 256, 3, 258, 3, 264,
3, 266, 3, 272, 3, 274, 3, 280, 3, 282, 3, 2049, 2, 2053, 2, 2057, 2, 2061, 2, 2081, 2, 2085, 2, 2089, 2, 2093, 2,
2304, 9, 2305, 9, 2312, 9, 2313, 9, 16390, 1, 16391, 1, 16406, 1, 16407, 1, 16422, 1, 16423, 1, 16438, 1, 16439, 1,
16642, 8, 16646, 8, 16658, 8, 16662, 8, 18437, 6, 18439, 6, 18469, 6, 18471, 6, 18688, 9, 18689, 9, 18690, 8, 18693,
6, 18694, 8, 18695, 6, 18696, 9, 18697, 9, 18706, 8, 18710, 8, 18725, 6, 18727, 6, 131128, 0, 131129, 0, 131130, 0,
131131, 0, 131132, 0, 131133, 0, 131134, 0, 131135, 0, 131352, 7, 131354, 7, 131384, 7, 131386, 7, 133161, 5, 133165,
5, 133177, 5, 133181, 5, 133376, 9, 133377, 9, 133384, 9, 133385, 9, 133400, 7, 133402, 7, 133417, 5, 133421, 5,
133432, 7, 133433, 5, 133434, 7, 133437, 5, 147510, 4, 147511, 4, 147518, 4, 147519, 4, 147714, 8, 147718, 8, 147730,
8, 147734, 8, 147736, 7, 147738, 7, 147766, 4, 147767, 4, 147768, 7, 147770, 7, 147774, 4, 147775, 4, 149509, 6,
149511, 6, 149541, 6, 149543, 6, 149545, 5, 149549, 5, 149558, 4, 149559, 4, 149561, 5, 149565, 5, 149566, 4, 149567,
4, 149760, 9, 149761, 9, 149762, 8, 149765, 6, 149766, 8, 149767, 6, 149768, 9, 149769, 9, 149778, 8, 149782, 8,
149784, 7, 149786, 7, 149797, 6, 149799, 6, 149801, 5, 149805, 5, 149814, 4, 149815, 4, 149816, 7, 149817, 5, 149818,
7, 149821, 5, 149822, 4, 149823, 4, 149824, 37, 149825, 37, 149826, 36, 149829, 34, 149830, 36, 149831, 34, 149832,
37, 149833, 37, 149842, 36, 149846, 36, 149848, 35, 149850, 35, 149861, 34, 149863, 34, 149865, 33, 149869, 33,
149878, 32, 149879, 32, 149880, 35, 149881, 33, 149882, 35, 149885, 33, 149886, 32, 149887, 32, 150080, 49, 150082,
48, 150088, 49, 150098, 48, 150104, 47, 150106, 47, 151873, 46, 151877, 45, 151881, 46, 151909, 45, 151913, 44,
151917, 44, 152128, 49, 152129, 46, 152136, 49, 152137, 46, 166214, 43, 166215, 42, 166230, 43, 166247, 42, 166262,
41, 166263, 41, 166466, 48, 166470, 43, 166482, 48, 166486, 43, 168261, 45, 168263, 42, 168293, 45, 168295, 42,
168512, 31, 168513, 28, 168514, 31, 168517, 28, 168518, 25, 168519, 25, 280952, 40, 280953, 39, 280954, 40, 280957,
39, 280958, 38, 280959, 38, 281176, 47, 281178, 47, 281208, 40, 281210, 40, 282985, 44, 282989, 44, 283001, 39,
283005, 39, 283208, 30, 283209, 27, 283224, 30, 283241, 27, 283256, 22, 283257, 22, 297334, 41, 297335, 41, 297342,
38, 297343, 38, 297554, 29, 297558, 24, 297562, 29, 297590, 24, 297594, 21, 297598, 21, 299365, 26, 299367, 23,
299373, 26, 299383, 23, 299389, 20, 299391, 20, 299584, 31, 299585, 28, 299586, 31, 299589, 28, 299590, 25, 299591,
25, 299592, 30, 299593, 27, 299602, 29, 299606, 24, 299608, 30, 299610, 29, 299621, 26, 299623, 23, 299625, 27,
299629, 26, 299638, 24, 299639, 23, 299640, 22, 299641, 22, 299642, 21, 299645, 20, 299646, 21, 299647, 20, 299648,
61, 299649, 60, 299650, 61, 299653, 60, 299654, 59, 299655, 59, 299656, 58, 299657, 57, 299666, 55, 299670, 54,
299672, 58, 299674, 55, 299685, 52, 299687, 51, 299689, 57, 299693, 52, 299702, 54, 299703, 51, 299704, 56, 299705,
56, 299706, 53, 299709, 50, 299710, 53, 299711, 50, 299904, 61, 299906, 61, 299912, 58, 299922, 55, 299928, 58,
299930, 55, 301697, 60, 301701, 60, 301705, 57, 301733, 52, 301737, 57, 301741, 52, 301952, 79, 301953, 79, 301960,
76, 301961, 76, 316038, 59, 316039, 59, 316054, 54, 316071, 51, 316086, 54, 316087, 51, 316290, 78, 316294, 78,
316306, 73, 316310, 73, 318085, 77, 318087, 77, 318117, 70, 318119, 70, 318336, 79, 318337, 79, 318338, 78, 318341,
77, 318342, 78, 318343, 77, 430776, 56, 430777, 56, 430778, 53, 430781, 50, 430782, 53, 430783, 50, 431000, 75,
431002, 72, 431032, 75, 431034, 72, 432809, 74, 432813, 69, 432825, 74, 432829, 69, 433032, 76, 433033, 76, 433048,
75, 433065, 74, 433080, 75, 433081, 74, 447158, 71, 447159, 68, 447166, 71, 447167, 68, 447378, 73, 447382, 73,
447386, 72, 447414, 71, 447418, 72, 447422, 71, 449189, 70, 449191, 70, 449197, 69, 449207, 68, 449213, 69, 449215,
68, 449408, 67, 449409, 67, 449410, 66, 449413, 64, 449414, 66, 449415, 64, 449416, 67, 449417, 67, 449426, 66,
449430, 66, 449432, 65, 449434, 65, 449445, 64, 449447, 64, 449449, 63, 449453, 63, 449462, 62, 449463, 62, 449464,
65, 449465, 63, 449466, 65, 449469, 63, 449470, 62, 449471, 62, 449472, 19, 449473, 19, 449474, 18, 449477, 16,
449478, 18, 449479, 16, 449480, 19, 449481, 19, 449490, 18, 449494, 18, 449496, 17, 449498, 17, 449509, 16, 449511,
16, 449513, 15, 449517, 15, 449526, 14, 449527, 14, 449528, 17, 449529, 15, 449530, 17, 449533, 15, 449534, 14,
449535, 14, 449728, 19, 449729, 19, 449730, 18, 449734, 18, 449736, 19, 449737, 19, 449746, 18, 449750, 18, 449752,
17, 449754, 17, 449784, 17, 449786, 17, 451520, 19, 451521, 19, 451525, 16, 451527, 16, 451528, 19, 451529, 19,
451557, 16, 451559, 16, 451561, 15, 451565, 15, 451577, 15, 451581, 15, 451776, 19, 451777, 19, 451784, 19, 451785,
19, 465858, 18, 465861, 16, 465862, 18, 465863, 16, 465874, 18, 465878, 18, 465893, 16, 465895, 16, 465910, 14,
465911, 14, 465918, 14, 465919, 14, 466114, 18, 466118, 18, 466130, 18, 466134, 18, 467909, 16, 467911, 16, 467941,
16, 467943, 16, 468160, 13, 468161, 13, 468162, 13, 468163, 13, 468164, 13, 468165, 13, 468166, 13, 468167, 13,
580568, 17, 580570, 17, 580585, 15, 580589, 15, 580598, 14, 580599, 14, 580600, 17, 580601, 15, 580602, 17, 580605,
15, 580606, 14, 580607, 14, 580824, 17, 580826, 17, 580856, 17, 580858, 17, 582633, 15, 582637, 15, 582649, 15,
582653, 15, 582856, 12, 582857, 12, 582872, 12, 582873, 12, 582888, 12, 582889, 12, 582904, 12, 582905, 12, 596982,
14, 596983, 14, 596990, 14, 596991, 14, 597202, 11, 597206, 11, 597210, 11, 597214, 11, 597234, 11, 597238, 11,
597242, 11, 597246, 11, 599013, 10, 599015, 10, 599021, 10, 599023, 10, 599029, 10, 599031, 10, 599037, 10, 599039,
10, 599232, 13, 599233, 13, 599234, 13, 599235, 13, 599236, 13, 599237, 13, 599238, 13, 599239, 13, 599240, 12,
599241, 12, 599250, 11, 599254, 11, 599256, 12, 599257, 12, 599258, 11, 599262, 11, 599269, 10, 599271, 10, 599272,
12, 599273, 12, 599277, 10, 599279, 10, 599282, 11, 599285, 10, 599286, 11, 599287, 10, 599288, 12, 599289, 12,
599290, 11, 599293, 10, 599294, 11, 599295, 10
];
con.p2D = [0, 0, 1, -1, 0, 0, -1, 1, 0, 2, 1, 1, 1, 2, 2, 0, 1, 2, 0, 2, 1, 0, 0, 0];
con.p3D = [
0, 0, 1, -1, 0, 0, 1, 0, -1, 0, 0, -1, 1, 0, 0, 0, 1, -1, 0, 0, -1, 0, 1, 0, 0, -1, 1, 0, 2, 1, 1, 0, 1, 1, 1, -1, 0,
2, 1, 0, 1, 1, 1, -1, 1, 0, 2, 0, 1, 1, 1, -1, 1, 1, 1, 3, 2, 1, 0, 3, 1, 2, 0, 1, 3, 2, 0, 1, 3, 1, 0, 2, 1, 3, 0, 2,
1, 3, 0, 1, 2, 1, 1, 1, 0, 0, 2, 2, 0, 0, 1, 1, 0, 1, 0, 2, 0, 2, 0, 1, 1, 0, 0, 1, 2, 0, 0, 2, 2, 0, 0, 0, 0, 1, 1,
-1, 1, 2, 0, 0, 0, 0, 1, -1, 1, 1, 2, 0, 0, 0, 0, 1, 1, 1, -1, 2, 3, 1, 1, 1, 2, 0, 0, 2, 2, 3, 1, 1, 1, 2, 2, 0, 0,
2, 3, 1, 1, 1, 2, 0, 2, 0, 2, 1, 1, -1, 1, 2, 0, 0, 2, 2, 1, 1, -1, 1, 2, 2, 0, 0, 2, 1, -1, 1, 1, 2, 0, 0, 2, 2, 1,
-1, 1, 1, 2, 0, 2, 0, 2, 1, 1, 1, -1, 2, 2, 0, 0, 2, 1, 1, 1, -1, 2, 0, 2, 0
];
con.p4D = [
0, 0, 1, -1, 0, 0, 0, 1, 0, -1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 1, 0, 0, 0, 0, 1, -1, 0, 0, 0, 1, 0, -1, 0, 0, -1, 0, 1,
0, 0, 0, -1, 1, 0, 0, 0, 0, 1, -1, 0, 0, -1, 0, 0, 1, 0, 0, -1, 0, 1, 0, 0, 0, -1, 1, 0, 2, 1, 1, 0, 0, 1, 1, 1, -1,
0, 1, 1, 1, 0, -1, 0, 2, 1, 0, 1, 0, 1, 1, -1, 1, 0, 1, 1, 0, 1, -1, 0, 2, 0, 1, 1, 0, 1, -1, 1, 1, 0, 1, 0, 1, 1, -1,
0, 2, 1, 0, 0, 1, 1, 1, -1, 0, 1, 1, 1, 0, -1, 1, 0, 2, 0, 1, 0, 1, 1, -1, 1, 0, 1, 1, 0, 1, -1, 1, 0, 2, 0, 0, 1, 1,
1, -1, 0, 1, 1, 1, 0, -1, 1, 1, 1, 4, 2, 1, 1, 0, 4, 1, 2, 1, 0, 4, 1, 1, 2, 0, 1, 4, 2, 1, 0, 1, 4, 1, 2, 0, 1, 4, 1,
1, 0, 2, 1, 4, 2, 0, 1, 1, 4, 1, 0, 2, 1, 4, 1, 0, 1, 2, 1, 4, 0, 2, 1, 1, 4, 0, 1, 2, 1, 4, 0, 1, 1, 2, 1, 2, 1, 1,
0, 0, 3, 2, 1, 0, 0, 3, 1, 2, 0, 0, 1, 2, 1, 0, 1, 0, 3, 2, 0, 1, 0, 3, 1, 0, 2, 0, 1, 2, 0, 1, 1, 0, 3, 0, 2, 1, 0,
3, 0, 1, 2, 0, 1, 2, 1, 0, 0, 1, 3, 2, 0, 0, 1, 3, 1, 0, 0, 2, 1, 2, 0, 1, 0, 1, 3, 0, 2, 0, 1, 3, 0, 1, 0, 2, 1, 2,
0, 0, 1, 1, 3, 0, 0, 2, 1, 3, 0, 0, 1, 2, 2, 3, 1, 1, 1, 0, 2, 1, 1, 1, -1, 2, 2, 0, 0, 0, 2, 3, 1, 1, 0, 1, 2, 1, 1,
-1, 1, 2, 2, 0, 0, 0, 2, 3, 1, 0, 1, 1, 2, 1, -1, 1, 1, 2, 2, 0, 0, 0, 2, 3, 1, 1, 1, 0, 2, 1, 1, 1, -1, 2, 0, 2, 0,
0, 2, 3, 1, 1, 0, 1, 2, 1, 1, -1, 1, 2, 0, 2, 0, 0, 2, 3, 0, 1, 1, 1, 2, -1, 1, 1, 1, 2, 0, 2, 0, 0, 2, 3, 1, 1, 1, 0,
2, 1, 1, 1, -1, 2, 0, 0, 2, 0, 2, 3, 1, 0, 1, 1, 2, 1, -1, 1, 1, 2, 0, 0, 2, 0, 2, 3, 0, 1, 1, 1, 2, -1, 1, 1, 1, 2,
0, 0, 2, 0, 2, 3, 1, 1, 0, 1, 2, 1, 1, -1, 1, 2, 0, 0, 0, 2, 2, 3, 1, 0, 1, 1, 2, 1, -1, 1, 1, 2, 0, 0, 0, 2, 2, 3, 0,
1, 1, 1, 2, -1, 1, 1, 1, 2, 0, 0, 0, 2, 2, 1, 1, 1, -1, 0, 1, 1, 1, 0, -1, 0, 0, 0, 0, 0, 2, 1, 1, -1, 1, 0, 1, 1, 0,
1, -1, 0, 0, 0, 0, 0, 2, 1, -1, 1, 1, 0, 1, 0, 1, 1, -1, 0, 0, 0, 0, 0, 2, 1, 1, -1, 0, 1, 1, 1, 0, -1, 1, 0, 0, 0, 0,
0, 2, 1, -1, 1, 0, 1, 1, 0, 1, -1, 1, 0, 0, 0, 0, 0, 2, 1, -1, 0, 1, 1, 1, 0, -1, 1, 1, 0, 0, 0, 0, 0, 2, 1, 1, 1, -1,
0, 1, 1, 1, 0, -1, 2, 2, 0, 0, 0, 2, 1, 1, -1, 1, 0, 1, 1, 0, 1, -1, 2, 2, 0, 0, 0, 2, 1, 1, -1, 0, 1, 1, 1, 0, -1, 1,
2, 2, 0, 0, 0, 2, 1, 1, 1, -1, 0, 1, 1, 1, 0, -1, 2, 0, 2, 0, 0, 2, 1, -1, 1, 1, 0, 1, 0, 1, 1, -1, 2, 0, 2, 0, 0, 2,
1, -1, 1, 0, 1, 1, 0, 1, -1, 1, 2, 0, 2, 0, 0, 2, 1, 1, -1, 1, 0, 1, 1, 0, 1, -1, 2, 0, 0, 2, 0, 2, 1, -1, 1, 1, 0, 1,
0, 1, 1, -1, 2, 0, 0, 2, 0, 2, 1, -1, 0, 1, 1, 1, 0, -1, 1, 1, 2, 0, 0, 2, 0, 2, 1, 1, -1, 0, 1, 1, 1, 0, -1, 1, 2, 0,
0, 0, 2, 2, 1, -1, 1, 0, 1, 1, 0, 1, -1, 1, 2, 0, 0, 0, 2, 2, 1, -1, 0, 1, 1, 1, 0, -1, 1, 1, 2, 0, 0, 0, 2, 3, 1, 1,
0, 0, 0, 2, 2, 0, 0, 0, 2, 1, 1, 1, -1, 3, 1, 0, 1, 0, 0, 2, 0, 2, 0, 0, 2, 1, 1, 1, -1, 3, 1, 0, 0, 1, 0, 2, 0, 0, 2,
0, 2, 1, 1, 1, -1, 3, 1, 1, 0, 0, 0, 2, 2, 0, 0, 0, 2, 1, 1, -1, 1, 3, 1, 0, 1, 0, 0, 2, 0, 2, 0, 0, 2, 1, 1, -1, 1,
3, 1, 0, 0, 0, 1, 2, 0, 0, 0, 2, 2, 1, 1, -1, 1, 3, 1, 1, 0, 0, 0, 2, 2, 0, 0, 0, 2, 1, -1, 1, 1, 3, 1, 0, 0, 1, 0, 2,
0, 0, 2, 0, 2, 1, -1, 1, 1, 3, 1, 0, 0, 0, 1, 2, 0, 0, 0, 2, 2, 1, -1, 1, 1, 3, 1, 0, 1, 0, 0, 2, 0, 2, 0, 0, 2, -1,
1, 1, 1, 3, 1, 0, 0, 1, 0, 2, 0, 0, 2, 0, 2, -1, 1, 1, 1, 3, 1, 0, 0, 0, 1, 2, 0, 0, 0, 2, 2, -1, 1, 1, 1, 3, 3, 2, 1,
0, 0, 3, 1, 2, 0, 0, 4, 1, 1, 1, 1, 3, 3, 2, 0, 1, 0, 3, 1, 0, 2, 0, 4, 1, 1, 1, 1, 3, 3, 0, 2, 1, 0, 3, 0, 1, 2, 0,
4, 1, 1, 1, 1, 3, 3, 2, 0, 0, 1, 3, 1, 0, 0, 2, 4, 1, 1, 1, 1, 3, 3, 0, 2, 0, 1, 3, 0, 1, 0, 2, 4, 1, 1, 1, 1, 3, 3,
0, 0, 2, 1, 3, 0, 0, 1, 2, 4, 1, 1, 1, 1, 3, 3, 2, 1, 0, 0, 3, 1, 2, 0, 0, 2, 1, 1, 1, -1, 3, 3, 2, 0, 1, 0, 3, 1, 0,
2, 0, 2, 1, 1, 1, -1, 3, 3, 0, 2, 1, 0, 3, 0, 1, 2, 0, 2, 1, 1, 1, -1, 3, 3, 2, 1, 0, 0, 3, 1, 2, 0, 0, 2, 1, 1, -1,
1, 3, 3, 2, 0, 0, 1, 3, 1, 0, 0, 2, 2, 1, 1, -1, 1, 3, 3, 0, 2, 0, 1, 3, 0, 1, 0, 2, 2, 1, 1, -1, 1, 3, 3, 2, 0, 1, 0,
3, 1, 0, 2, 0, 2, 1, -1, 1, 1, 3, 3, 2, 0, 0, 1, 3, 1, 0, 0, 2, 2, 1, -1, 1, 1, 3, 3, 0, 0, 2, 1, 3, 0, 0, 1, 2, 2,
1, -1, 1, 1, 3, 3, 0, 2, 1, 0, 3, 0, 1, 2, 0, 2, -1, 1, 1, 1, 3, 3, 0, 2, 0, 1, 3, 0, 1, 0, 2, 2, -1, 1, 1, 1, 3, 3,
0, 0, 2, 1, 3, 0, 0, 1, 2, 2, -1, 1, 1, 1
];
// helper classes
function shuffleSeed(seed) {
var newSeed = new Uint32Array(1);
newSeed[0] = seed[0] * 1664525 + 1013904223;
return newSeed;
}
function Contribution2(multiplier, xsb, ysb) {
this.dx = -xsb - multiplier * con.SQUISH_2D;
this.dy = -ysb - multiplier * con.SQUISH_2D;
this.xsb = xsb;
this.ysb = ysb;
}
function Contribution3(multiplier, xsb, ysb, zsb) {
this.dx = -xsb - multiplier * con.SQUISH_3D;
this.dy = -ysb - multiplier * con.SQUISH_3D;
this.dz = -zsb - multiplier * con.SQUISH_3D;
this.xsb = xsb;
this.ysb = ysb;
this.zsb = zsb;
}
function Contribution4(multiplier, xsb, ysb, zsb, wsb) {
this.dx = -xsb - multiplier * con.SQUISH_4D;
this.dy = -ysb - multiplier * con.SQUISH_4D;
this.dz = -zsb - multiplier * con.SQUISH_4D;
this.dw = -wsb - multiplier * con.SQUISH_4D;
this.xsb = xsb;
this.ysb = ysb;
this.zsb = zsb;
this.wsb = wsb;
}
// initialize
var contributions2D = [];
for (var i = 0; i < con.p2D.length; i += 4) {
var baseSet = con.base2D[con.p2D[i]];
var previous = null;
var current = null;
for (var k = 0; k < baseSet.length; k += 3) {
current = new Contribution2(baseSet[k], baseSet[k + 1], baseSet[k + 2]);
if (previous === null)
contributions2D[i / 4] = current;
else
previous.next = current;
previous = current;
}
current.next = new Contribution2(con.p2D[i + 1], con.p2D[i + 2], con.p2D[i + 3]);
}
this.lookup2D = [];
for (var i = 0; i < con.lookupPairs2D.length; i += 2) {
this.lookup2D[con.lookupPairs2D[i]] = contributions2D[con.lookupPairs2D[i + 1]];
}
var contributions3D = [];
for (var i = 0; i < con.p3D.length; i += 9) {
var baseSet = con.base3D[con.p3D[i]];
var previous = null;
var current = null;
for (var k = 0; k < baseSet.length; k += 4) {
current = new Contribution3(baseSet[k], baseSet[k + 1], baseSet[k + 2], baseSet[k + 3]);
if (previous === null)
contributions3D[i / 9] = current;
else
previous.next = current;
previous = current;
}
current.next = new Contribution3(con.p3D[i + 1], con.p3D[i + 2], con.p3D[i + 3], con.p3D[i + 4]);
current.next.next = new Contribution3(con.p3D[i + 5], con.p3D[i + 6], con.p3D[i + 7], con.p3D[i + 8]);
}
this.lookup3D = [];
for (var i = 0; i < con.lookupPairs3D.length; i += 2) {
this.lookup3D[con.lookupPairs3D[i]] = contributions3D[con.lookupPairs3D[i + 1]];
}
var contributions4D = [];
for (var i = 0; i < con.p4D.length; i += 16) {
var baseSet = con.base4D[con.p4D[i]];
var previous = null;
var current = null;
for (var k = 0; k < baseSet.length; k += 5) {
current = new Contribution4(baseSet[k], baseSet[k + 1], baseSet[k + 2], baseSet[k + 3], baseSet[k + 4]);
if (previous === null)
contributions4D[i / 16] = current;
else
previous.next = current;
previous = current;
}
current.next = new Contribution4(con.p4D[i + 1], con.p4D[i + 2], con.p4D[i + 3], con.p4D[i + 4], con.p4D[i + 5]);
current.next.next = new Contribution4(con.p4D[i + 6], con.p4D[i + 7], con.p4D[i + 8], con.p4D[i + 9], con.p4D[i + 10]);
current.next.next.next = new Contribution4(con.p4D[i + 11], con.p4D[i + 12], con.p4D[i + 13], con.p4D[i + 14], con.p4D[i + 15]);
}
this.lookup4D = [];
for (var i = 0; i < con.lookupPairs4D.length; i += 2) {
this.lookup4D[con.lookupPairs4D[i]] = contributions4D[con.lookupPairs4D[i + 1]];
}
// end initialize
this.perm = new Uint8Array(256);
this.perm2D = new Uint8Array(256);
this.perm3D = new Uint8Array(256);
this.perm4D = new Uint8Array(256);
var source = new Uint8Array(256);
for (var i = 0; i < 256; i++)
source[i] = i;
var seed = new Uint32Array(1);
seed[0] = clientSeed;
seed = shuffleSeed(shuffleSeed(shuffleSeed(seed)));
for (var i = 255; i >= 0; i--) {
seed = shuffleSeed(seed);
var r = new Uint32Array(1);
r[0] = (seed[0] + 31) % (i + 1);
if (r[0] < 0)
r[0] += (i + 1);
this.perm[i] = source[r[0]];
this.perm2D[i] = this.perm[i] & 0x0E;
this.perm3D[i] = (this.perm[i] % 24) * 3;
this.perm4D[i] = this.perm[i] & 0xFC;
source[r[0]] = source[i];
}
this.simplex1D = function(x) {
return that.simplex2D(x, 1);
};
this.simplex2D = function (x, y) {
var stretchOffset = (x + y) * con.STRETCH_2D;
var _a = [x + stretchOffset, y + stretchOffset], xs = _a[0], ys = _a[1];
var _b = [Math.floor(xs), Math.floor(ys)], xsb = _b[0], ysb = _b[1];
var squishOffset = (xsb + ysb) * con.SQUISH_2D;
var _c = [x - (xsb + squishOffset), y - (ysb + squishOffset)], dx0 = _c[0], dy0 = _c[1];
var _d = [xs - xsb, ys - ysb], xins = _d[0], yins = _d[1];
var inSum = xins + yins;
var hashVals = new Uint32Array(4);
hashVals[0] = xins - yins + 1;
hashVals[1] = inSum;
hashVals[2] = inSum + yins;
hashVals[3] = inSum + xins;
var hash = hashVals[0] | (hashVals[1] << 1) | (hashVals[2] << 2) | (hashVals[3] << 4);
var c = that.lookup2D[hash];
var value = 0.0;
while (typeof c !== 'undefined') {
var _e = [dx0 + c.dx, dy0 + c.dy], dx = _e[0], dy = _e[1];
var attn = 2 - dx * dx - dy * dy;
if (attn > 0) {
var _f = [xsb + c.xsb, ysb + c.ysb], px = _f[0], py = _f[1];
var i = that.perm2D[(that.perm[px & 0xFF] + py) & 0xFF];
var valuePart = con.gradients2D[i] * dx + con.gradients2D[i + 1] * dy;
attn *= attn;
value += attn * attn * valuePart;
}
c = c.next;
}
return value * con.NORM_2D;
};
this.simplex3D = function (x, y, z) {
var stretchOffset = (x + y + z) * con.STRETCH_3D;
var _a = [x + stretchOffset, y + stretchOffset, z + stretchOffset], xs = _a[0], ys = _a[1], zs = _a[2];
var _b = [Math.floor(xs), Math.floor(ys), Math.floor(zs)], xsb = _b[0], ysb = _b[1], zsb = _b[2];
var squishOffset = (xsb + ysb + zsb) * con.SQUISH_3D;
var _c = [x - (xsb + squishOffset), y - (ysb + squishOffset), z - (zsb + squishOffset)], dx0 = _c[0], dy0 = _c[1], dz0 = _c[2];
var _d = [xs - xsb, ys - ysb, zs - zsb], xins = _d[0], yins = _d[1], zins = _d[2];
var inSum = xins + yins + zins;
var hashVals = new Uint32Array(7);
hashVals[0] = yins - zins + 1;
hashVals[1] = xins - yins + 1;
hashVals[2] = xins - zins + 1;
hashVals[3] = inSum;
hashVals[4] = inSum + zins;
hashVals[5] = inSum + yins;
hashVals[6] = inSum + xins;
var hash = hashVals[0] | hashVals[1] << 1 | hashVals[2] << 2 | hashVals[3] << 3 | hashVals[4] << 5 |
hashVals[5] << 7 | hashVals[6] << 9;
var c = that.lookup3D[hash];
var value = 0.0;
while (typeof c !== 'undefined') {
var _e = [dx0 + c.dx, dy0 + c.dy, dz0 + c.dz], dx = _e[0], dy = _e[1], dz = _e[2];
var attn = 2 - dx * dx - dy * dy - dz * dz;
if (attn > 0) {
var _f = [xsb + c.xsb, ysb + c.ysb, zsb + c.zsb], px = _f[0], py = _f[1], pz = _f[2];
var i = that.perm3D[(that.perm[(that.perm[px & 0xFF] + py) & 0xFF] + pz) & 0xFF];
var valuePart = con.gradients3D[i] * dx + con.gradients3D[i + 1] * dy + con.gradients3D[i + 2] * dz;
attn *= attn;
value += attn * attn * valuePart;
}
c = c.next;
}
return value * con.NORM_3D;
};
this.simplex4D = function (x, y, z, w) {
var stretchOffset = (x + y + z + w) * con.STRETCH_4D;
var _a = [x + stretchOffset, y + stretchOffset, z + stretchOffset, w + stretchOffset], xs = _a[0], ys = _a[1], zs = _a[2], ws = _a[3];
var _b = [Math.floor(xs), Math.floor(ys), Math.floor(zs), Math.floor(ws)], xsb = _b[0], ysb = _b[1], zsb = _b[2], wsb = _b[3];
var squishOffset = (xsb + ysb + zsb + wsb) * con.SQUISH_4D;
var dx0 = x - (xsb + squishOffset);
var dy0 = y - (ysb + squishOffset);
var dz0 = z - (zsb + squishOffset);
var dw0 = w - (wsb + squishOffset);
var _c = [xs - xsb, ys - ysb, zs - zsb, ws - wsb], xins = _c[0], yins = _c[1], zins = _c[2], wins = _c[3];
var inSum = xins + yins + zins + wins;
var hashVals = new Uint32Array(11);
hashVals[0] = zins - wins + 1;
hashVals[1] = yins - zins + 1;
hashVals[2] = yins - wins + 1;
hashVals[3] = xins - yins + 1;
hashVals[4] = xins - zins + 1;
hashVals[5] = xins - wins + 1;
hashVals[6] = inSum << 6;
hashVals[7] = inSum + wins;
hashVals[8] = inSum + zins;
hashVals[9] = inSum + yins;
hashVals[10] = inSum + xins;
var hash = hashVals[0] | hashVals[1] << 1 | hashVals[2] << 2 | hashVals[3] << 3 | hashVals[4] << 4 | hashVals[5] << 5 |
hashVals[6] << 6 | hashVals[7] << 8 | hashVals[8] << 11 | hashVals[9] << 14 | hashVals[10] << 17;
var c = that.lookup4D[hash];
var value = 0.0;
while (typeof c !== 'undefined') {
var _d = [dx0 + c.dx, dy0 + c.dy, dz0 + c.dz, dw0 + c.dw], dx = _d[0], dy = _d[1], dz = _d[2], dw = _d[3];
var attn = 2 - dx * dx - dy * dy - dz * dz - dw * dw;
if (attn > 0) {
var _e = [xsb + c.xsb, ysb + c.ysb, zsb + c.zsb, wsb + c.wsb], px = _e[0], py = _e[1], pz = _e[2], pw = _e[3];
var i = that.perm4D[(that.perm[(that.perm[(that.perm[px & 0xFF] + py) & 0xFF] + pz) & 0xFF] + pw) & 0xFF];
var valuePart = con.gradients4D[i] * dx + con.gradients4D[i + 1] * dy + con.gradients4D[i + 2] * dz + con.gradients4D[i + 3] * dw;
attn *= attn;
value += attn * attn * valuePart;
}
c = c.next;
}
return value * con.NORM_4D;
};
};//-13.9
/*--
zim.Point = function(x, y, z, q, r, s, t, u, v, w)
Point
zim class
DESCRIPTION
Stores x, y, z, q, r, s, t, u, v, w properties.
See also createjs.Point for a Point class with more features.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var point = new Point(100, 100);
zog(point.x, point.y); // 100, 100
END EXAMPLE
PARAMETERS
x - (default 0) the x value of the point
y - (default 0) the y value of the point
z - (default 0) the z value of the point - probably not used
q - (default 0) the q value of the point - very probably not used
r - (default 0) the r value of the point - very probably not used
s - (default 0) the s value of the point - very probably not used
t - (default 0) the t value of the point - very probably not used
u - (default 0) the u value of the point - very probably not used
v - (default 0) the v value of the point - very probably not used
w - (default 0) the w value of the point - very probably not used
PROPERTIES
x - the x value of the point
y - the y value of the point
z - the z value of the point - probably not used
q - the q value of the point - very probably not used
r - the r value of the point - very probably not used
s - the s value of the point - very probably not used
t - the t value of the point - very probably not used
u - the u value of the point - very probably not used
v - the v value of the point - very probably not used
w - the w value of the point - very probably not used
--*///+13.45
zim.Point = function(x, y, z, q, r, s, t, u, v, w) {
z_d("13.45");
if (zot(x)) x = 0;
if (zot(y)) y = 0;
if (zot(z)) z = 0;
if (zot(q)) q = 0;
if (zot(r)) r = 0;
if (zot(s)) s = 0;
if (zot(t)) t = 0;
if (zot(u)) u = 0;
if (zot(v)) v = 0;
if (zot(w)) w = 0;
this.x = x;
this.y = y;
this.z = z;
this.q = q;
this.r = r;
this.s = s;
this.t = t;
this.u = u;
this.v = v;
this.w = w;
};//-13.45
/*--
zim.Bezier = function(a, b, c, d)
Bezier
zim class
DESCRIPTION
Creates data for a Cubic Bezier to give x and y at a ratio of the curve
Also gives mx and my for a modified x and y that is more evenly spaced
Thanks Ivo Wetzel - StackExchange
Used internally by zim.getCurvePoint() used by Squiggle, Blob, Beads, and animate() in path
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var a = {x:100, y:100}; // start point
var b = {x:400, y:100}; // control point for start point
var c = {x:100, y:300}; // control point for end point
var d = {x:300, y:300}; // end point
var bezier = new Bezier(a,b,c,d);
new Shape().s(black).mt(a.x,a.y).bt(b.x,b.y, c.x,c.y, d.x,d.y).addTo();
loop(10, function (i) {
// original spacing
// new Circle(5).loc(bezier.x(i/10), bezier.y(i/10));
// modified spacing to be more even
new Circle(5).loc(bezier.mx(i/10), bezier.my(i/10));
});
END EXAMPLE
PARAMETERS
// all parameters are points with x and y properties {x:val, y:val}
a - start point of Bezier curve
b - control point for the start point
c - control point for the end point
d - end point
METHODS
x(r) - the x position of a point at ratio r (0-1) on the curve
y(r) - the y position of a point at ratio r (0-1) on the curve
mx(r) - the evenly-spaced x position of a point at ratio r (0-1) on the curve
my(r) - the evenly-spaced y position of a point at ratio r (0-1) on the curve
PROPERTIES
a, b, c, d - the points passed in - each having x and y properties
--*///+13.47
zim.Bezier = function Bezier(a, b, c, d) {
z_d("13.47");
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.len = 100;
this.arcLengths = new Array(this.len + 1);
this.arcLengths[0] = 0;
var ox = this.x(0), oy = this.y(0), clen = 0;
for(var i = 1; i <= this.len; i += 1) {
var x = this.x(i * 0.01), y = this.y(i * 0.01);
var dx = ox - x, dy = oy - y;
clen += Math.sqrt(dx * dx + dy * dy);
this.arcLengths[i] = clen;
ox = x, oy = y;
}
this.length = clen;
};
zim.Bezier.prototype = {
map: function(u) {
var targetLength = u * this.arcLengths[this.len];
var low = 0, high = this.len, index = 0;
while (low < high) {
index = low + (((high - low) / 2) | 0);
if (this.arcLengths[index] < targetLength) {
low = index + 1;
} else {
high = index;
}
}
if (this.arcLengths[index] > targetLength) {
index--;
}
var lengthBefore = this.arcLengths[index];
if (lengthBefore === targetLength) {
return index / this.len;
} else {
return (index + (targetLength - lengthBefore) / (this.arcLengths[index + 1] - lengthBefore)) / this.len;
}
},
mx: function (u) {
return this.x(this.map(u));
},
my: function (u) {
return this.y(this.map(u));
},
x: function (t) {
return ((1 - t) * (1 - t) * (1 - t)) * this.a.x
+ 3 * ((1 - t) * (1 - t)) * t * this.b.x
+ 3 * (1 - t) * (t * t) * this.c.x
+ (t * t * t) * this.d.x;
},
y: function (t) {
return ((1 - t) * (1 - t) * (1 - t)) * this.a.y
+ 3 * ((1 - t) * (1 - t)) * t * this.b.y
+ 3 * (1 - t) * (t * t) * this.c.y
+ (t * t * t) * this.d.y;
}
};//-13.47
/*--
zim.Boundary = function(x, y, width, height)
Boundary
zim class
DESCRIPTION
Stores the data for a rectangle with x, y, width and height.
Can be used with ZIM drag(), gesture() for boundaries
and the Physics module for world boundary.
NOTE: A createjs.Rectangle or an object {} with x, y, width and height properties can also be used
Boundary was introduced to reduce confusion over having a ZIM Rectangle (Shape) and a CreateJS Rectangle (data)
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
new Circle(100, blue)
.center()
.drag(new Boundary(0,0,stageW,stageH));
// note: drag and gesture used to have rect parameters
// these have now been depreciated and replaced with boundary parameters
// CONTRACT
// the drag() boundary contains the registration point
// note: the gesture() boundary contains the whole shape of the object
// here, we keep the circle inside the stage by contracting the Boundary by the radius
var radius = 100;
new Circle(radius, red)
.center()
.drag(new Boundary(0,0,stageW,stageH).contract(radius));
END EXAMPLE
PARAMETERS
x - the x position of the Boundary
y - the y position of the Boundary
width - the width of the Boundary
height - the height of the Boundary
PROPERTIES
x - the x position of the Boundary
y - the y position of the Boundary
width - the width of the Boundary
height - the height of the Boundary
METHODS
contract(number|x, y, width, height) - number of pixels to make the Boundary smaller
passing in a single number will contract this on all sides
passing in two numbers will contract from horizontal and vertical accordingly
passing in four numbers will contract from the sides accordingly
note: to expand pass in a negative number
returns object for chaining
--*///+13.46
zim.Boundary = function(x, y, width, height) {
z_d("13.46");
if (zot(x) || zot(y) || zot(width) || zot(height)) return;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.contract = function(a,b,c,d) {
if (zot(a)) return this;
if (zot(b)) b = a;
if (zot(c)) {
c = a*2;
} else {
c = c+a;
}
if (zot(d)) {
d = b*2;
} else {
d = d+b;
}
this.x += a;
this.y += b;
this.width -= c;
this.height -= d;
return this;
};
};//-13.46
/*--
zim.GradientColor = function(colors, ratios, x0, y0, x1, y1)
GradientColor
zim class
DESCRIPTION
Creates data for a Linear Gradient that can be used to color ZIM Shapes
like Circle, Rectangle, Triangle, Squiggle, Blob, Flare
and therefore all ZIM component background colors, etc.
Also see ZIM RadialColor and BitmapColor classes
NOTE: the base ZIM Shape class will need gradients applied as usual
NOTE: The chainable methods for linearGradient() and radialGradient() are depricated
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// linear gradient from pink to purple across whole gradient
// with the start at 0,0 and end at 0,500 - so from top to bottom
new Rectangle(1000, 500, new GradientColor([pink,purple], [0,1], 0,0, 0,500)).addTo();
// linear gradient with 30% pink transitioning to green at half way then to 30% pure pink
// along a horizontal path from 0 to 1000 in width
// could also go diagonal for instance 0,0,1000,500
new Rectangle(1000, 500, new GradientColor([pink,green,purple], [.3,.5,.7], 0,0, 1000,0)).addTo()
END EXAMPLE
PARAMETERS
colors - an Array of colors for the gradient, can be more than two
ratios - an Array of 0-1 numbers reprenting the start position of transitions for the colors above
x0 - the x position to start the gradient
y0 - the y position to start the gradient
x1 - the x position to end the gradient
y1 - the y position to end the gradient
PROPERTIES
type - the type of color as a String
** the above parameters are all available as properties
** but will not change objects with their color already set
--*///+13.465
zim.GradientColor = function(colors,ratios, x0,y0, x1,y1) {
z_d("13.465");
this.type = "GradientColor";
this.colors = zot(colors)?["black","white"]:colors;
this.ratios = zot(ratios)?[0,1]:ratios;
this.x0 = zot(x0)?0:x0;
this.y0 = zot(y0)?0:y0;
this.x1 = zot(x1)?0:x1;
this.y1 = zot(y1)?100:y1;
};//-13.465
/*--
zim.RadialColor = function(colors, ratios, x0, y0, r0, x1, y1, r1)
RadialColor
zim class
DESCRIPTION
Creates data for a Radial Gradient that can be used to color ZIM Shapes
like Circle, Rectangle, Triangle, Squiggle, Blob, Flare
and therefore all ZIM component background colors, etc.
Also see ZIM GradientColor and BitmapColor classes
NOTE: the base ZIM Shape class will need gradients applied as usual
NOTE: The chainable methods for linearGradient() and radialGradient() are depricated
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// radial gradient from purple to pink across whole gradient
// with the start at 0,0,200 and end at 0,0,0 - so from radius to center
new Circle(200, new RadialColor([purple,pink], [0,1], 0,0,200, 0,0,0)).center();
// radial gradient from dark to light with alpha reduced
// start fading the light right away to 30% the gradient then use the dark
// move the center of the dark right and up and bigger than radius
// move the center of the light right and up and at 0
// this makes a moon with the dark shade at the bottom left
new Circle(100, new RadialColor(
["rgba(0,0,0,.2)","rgba(255,255,255,.2)"],[0,.3], 50,-30,120, 40,-40,0)
).center()
END EXAMPLE
PARAMETERS
colors - an Array of colors for the gradient, can be more than two
ratios - an Array of 0-1 numbers reprenting the start position of transitions for the colors above
x0 - the x position to start the gradient
y0 - the y position to start the gradient
r0 - the radius at the start of the gradient
x1 - the x position to end the gradient
y1 - the y position to end the gradient
r1 - the radius at the end of the gradient
PROPERTIES
type - the type of color as a String
** the above parameters are all available as properties
** but will not change objects with their color already set
--*///+13.466
zim.RadialColor = function(colors,ratios, x0,y0,r0, x1,y1,r1) {
z_d("13.466");
this.type = "RadialColor";
this.colors = zot(colors)?["black","white"]:colors;
this.ratios = zot(ratios)?[0,1]:ratios;
this.x0 = zot(x0)?0:x0;
this.y0 = zot(y0)?0:y0;
this.r0 = zot(r0)?0:r0;
this.x1 = zot(x1)?0:x1;
this.y1 = zot(y1)?100:y1;
this.r1 = zot(r1)?100:r1;
};//-13.466
/*--
zim.BitmapColor = function(image, repetition, matrix)
BitmapColor
zim class
DESCRIPTION
Creates data for a Bitmap fill from a loaded asset
that can be used to color ZIM Shapes
like Circle, Rectangle, Triangle, Squiggle, Blob, Flare
and therefore all ZIM component background colors, etc.
Also see ZIM GradientColor and RadialColor classes
NOTE: the base ZIM Shape class will need a bitmap fill applied as usual
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var assets = "flecks.jpg";
var path = "assets/";
var frame = new Frame(scaling, width, height, color, outerColor, assets, path);
frame.on("ready", function() {
new Rectangle(frame.width, frame.height, new BitmapColor("flecks.jpg")).addTo();
// or use asset("flecks.png") instead of string "flecks.jpg" - but ZIM will figure it out
stage.update()
}
END EXAMPLE
PARAMETERS
image - a ZIM Bitmap() such as available with asset()
when asset is loaded with ZIM Frame or frame.loadAssets()
also accepts the string name of an asset that would go in asset()
may accept url to html image but image needs to be loaded first
so would recommend usual ZIM asset loading
repetition - (default "repeat") the repeat of the Bitmap fill
also "repeat-x", "repeat-y" or "no-repeat"
matrix - a transformation matrix to apply to the Bitmap
PROPERTIES
type - the type of color as a String
** the above parameters are all available as properties
** but will not change objects with their color already set
--*///+13.467
zim.BitmapColor = function(image, repetition, matrix) {
z_d("13.467");
this.type = "BitmapColor";
if (typeof image == "string" && window.asset) image = window.asset(image);
if (image.type == "Image") image = image.bitmap;
this.image = image.type=="Bitmap"?image.image:image;
this.repetition = repetition;
this.matrix = matrix;
};//-13.467
/*--
zim.Damp = function(startValue, damp)
Damp
zim class
DESCRIPTION
Damping emulates things slowing down due to friction.
The movement heads towards the right value and looks organic.
This is similar if not the same as easing out when tweening.
Create your Damp object outside an interval or Ticker
then inside an interval or ticker call the convert method.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var d = new Damp(parameters);
setInterval(function() {
dampedValue = d.convert(desiredValue);
}, 100);
END EXAMPLE
you would then apply that desired value to a property such as x or y or scale
if you want to do both x and y then you need two Damp objects
and two convert calls (you can do both in one interval or ticker)
EXAMPLE
var circle = new Circle();
circle.center();
var dampX = new Damp(circle.x);
var dampY = new Damp(circle.y);
// start moving once mouse enters stage
// this event will only run once (the last parameter is true)
stage.on("stagemousemove", start, null, true);
function start(e) {
Ticker.add(function() {
circle.x = dampX.convert(e.stageX);
circle.y = dampY.convert(e.stageY);
}, stage);
}
END EXAMPLE
PARAMETERS supports DUO - parameters or single object with properties below
startValue - (default 0) start object at this value and then start damping
damp - (default .1) the damp value with 1 being no damping and 0 being no movement
METHODS
convert(value) - converts a value into a damped value
immediate(value) - immediately goes to value and returns the Damp object
PROPERTIES
damp - can dynamically change the damping (usually just pass it in as a parameter to start)
lastValue - setting this would go immediately to this value (would not normally use)
--*///+14
zim.Damp = function(startValue, damp) {
z_d("14");
var sig = "startValue, damp";
var duo; if (duo = zob(zim.Damp, arguments, sig, this)) return duo;
this.lastValue = (zot(startValue)) ? 0 : startValue;
this.damp = (zot(damp)) ? .1 : damp;
};
zim.Damp.prototype.convert = function(desiredValue) {
return this.lastValue = this.lastValue + (desiredValue - this.lastValue) * this.damp;
};
zim.Damp.prototype.immediate = function(desiredValue) {
this.lastValue = desiredValue;
return this;
};//-14
/*--
zim.Proportion = function(baseMin, baseMax, targetMin, targetMax, factor, targetRound, clamp)
Proportion
zim class
DESCRIPTION
Proportion converts an input value to an output value on a different scale.
(sometimes called a map() function)
For instance, like a slider controlling the scale of an object or sound volume.
Make a Proportion object and then in an interval, ticker or event,
convert the base value to the target value using the convert method.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
frame.loadAssets("mySound.mp3");
frame.on("complete", function() {
var sound = frame.asset("mySound.mp3").play();
var p = new Proportion(0, 10, 0, 1);
var dial = new Dial(); // default range of 0 to 10
dial.currentValue = 10;
dial.on("change", function(){
sound.volume = p.convert(dial.currentValue);
}); // end of dial change
}); // end sound loaded
END EXAMPLE
PARAMETERS supports DUO - parameters or single object with properties below
baseMin - min for the input scale (say x value)
baseMax - max for the input scale (say x value)
targetMin - (default 0) min for the output scale (say volume)
targetMax - (default 1) max for the output scale (say volume)
factor - (default 1) is going the same direction and -1 is going in opposite direction
targetRound - (default false) set to true to round the converted number
clamp - (default true) set to false to let results go outside min and max range
METHODS
convert(input) - will return the output property (for instance, a volume)
NOTE: the object always starts by assuming baseMin as baseValue
just call the convert method right away if you want it to start at a different baseValue
for instance, if your slider went from 100 to 500 and you want to start at half way
make the object and call p.convert(300); on the next line
--*///+15
zim.Proportion = function(baseMin, baseMax, targetMin, targetMax, factor, targetRound, clamp) {
var sig = "baseMin, baseMax, targetMin, targetMax, factor, targetRound, clamp";
var duo; if (duo = zob(zim.Proportion, arguments, sig, this)) return duo;
z_d("15");
// factor - set to 1 for increasing and -1 for decreasing
// round - true to round results to whole number
if (zot(targetMin)) targetMin = 0;
if (zot(targetMax)) targetMax = 1;
if (zot(factor)) factor = 1;
if (zot(targetRound)) targetRound = false;
if (zot(clamp)) clamp = true;
// proportion
var baseAmount;
var proportion;
var targetAmount;
baseAmount = baseMin; // just start at the min otherwise call immediate(baseValue);
this.convert = function(baseAmount) {
if (isNaN(baseAmount) || (baseMax-baseMin==0)) {return;}
if (clamp) {
baseAmount = Math.max(baseAmount, baseMin);
baseAmount = Math.min(baseAmount, baseMax);
}
proportion = (baseAmount - baseMin) / (baseMax - baseMin);
if (factor > 0) {
targetAmount = targetMin + (targetMax-targetMin) * proportion;
} else {
targetAmount = targetMax - (targetMax-targetMin) * proportion;
}
if (targetRound) {targetAmount = Math.round(targetAmount);}
return targetAmount;
};
};//-15
/*--
zim.ProportionDamp = function(baseMin, baseMax, targetMin, targetMax, damp, factor, targetRound, clamp)
ProportionDamp
zim class
DESCRIPTION
ProportionDamp converts an input value to an output value on a different scale with damping.
Works like Proportion Class but with a damping parameter.
Damping needs constant calculating so do not put in mousemove event.
The below example scales the circle based on the mouse height.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var circle = new Circle(50, "red");
circle.center(); // center method added in ZIM 4TH
var pd = new ProportionDamp(0, stageH, 0, 5, .2);
Ticker.add(function() {
circle.sca(pd.convert(stage.mouseH)); // scale method added in ZIM 4TH
}, stage);
END EXAMPLE
PARAMETERS supports DUO - parameters or single object with properties below
baseMin - min for the input scale (say x value)
baseMax - max for the input scale (say x value)
targetMin - (default 0) min for the output scale (say volume)
targetMax - (default 1) max for the output scale (say volume)
damp - (default .1) the damp value with 1 being no damping and 0 being no movement
factor (default 1) is going the same direction and -1 is going in opposite direction
targetRound (default false) set to true to round the converted number
METHODS
convert(input) - converts a base value to a target value
immediate(input) - immediately sets the target value (no damping) and returns the ProportionDamp object
dispose() - clears interval
PROPERTIES
damp - can adjust this dynamically (usually just pass it in as a parameter to start)
NOTE: the object always starts by assuming baseMin as baseValue
if you want to start or go to an immediate value without easing then
call the pd.immediate(baseValue) method with your desired baseValue (not targetValue)
--*///+16
zim.ProportionDamp = function(baseMin, baseMax, targetMin, targetMax, damp, factor, targetRound, clamp) {
var sig = "baseMin, baseMax, targetMin, targetMax, damp, factor, targetRound, clamp";
var duo; if (duo = zob(zim.ProportionDamp, arguments, sig, this)) return duo;
z_d("16");
// damp - can be changed via damp get/set method property
// factor - set to 1 for increasing and -1 for decreasing
// round - true to round results to whole number
// zot() is found in danzen.js (the z version of not)
if (zot(targetMin)) targetMin = 0;
if (zot(targetMax)) targetMax = 1;
if (zot(damp)) damp = .1;
if (zot(factor)) factor = 1;
if (zot(targetRound)) targetRound = false;
if (zot(clamp)) clamp = true;
this.damp = damp; // want to expose as a property we can change
var that = this;
// proportion
var baseAmount;
var proportion;
var targetDifference;
var targetAmount;
// damping
var differenceAmount;
var desiredAmount=0;
var lastAmount = 0;
baseAmount = baseMin; // just start at the min otherwise call immediate(baseValue);
lastAmount = targetMin;
var interval = setInterval(calculate, 20);
function calculate() {
if (isNaN(baseAmount) || (baseMax-baseMin==0)) {return;}
if (clamp) {
baseAmount = Math.max(baseAmount, baseMin);
baseAmount = Math.min(baseAmount, baseMax);
}
proportion = (baseAmount - baseMin) / (baseMax - baseMin);
targetDifference = targetMax - targetMin;
if (factor > 0) {
targetAmount = targetMin + targetDifference * proportion;
} else {
targetAmount = targetMax - targetDifference * proportion;
}
desiredAmount = targetAmount;
differenceAmount = desiredAmount - lastAmount;
lastAmount += differenceAmount*that.damp;
}
this.immediate = function(n) {
that.convert(n);
calculate();
lastAmount = targetAmount;
if (targetRound) {lastAmount = Math.round(lastAmount);}
return that;
};
this.convert = function(n) {
baseAmount = n;
if (targetRound) {
return Math.round(lastAmount);
} else {
return lastAmount;
}
};
this.dispose = function(a,b,disposing) {
clearInterval(interval);
return true;
};
};//-16
/*--
zim.Dictionary = function(unique)
Dictionary
zim class
DESCRIPTION
An object that uses objects as keys to give values.
Similar to an object literal with properties except the property names are objects instead of strings.
JavaScript currently does not have a dictionary, but other languages do.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var o = {test:"test"};
var f = function(w) {zog(w)};
var c = new Circle();
var d = new Dictionary();
d.add(o, 1); d.add(f, 2); d.add(c, f);
zog(d.at(o)); // 1
zog(d.at(f)); // 2
d.at(c)("hello"); // hello
d.remove(o); // to clear o
zog(d.length); // 2
END EXAMPLE
EXAMPLE
var d = new Dictionary();
d.add(circle, "one");
d.add(circle, "two");
zog(d.at(circle)); // two - just the latest but "one" is still there
for (var i=0; i<d.length; i++) {
if (d.objects[i] == circle) zog(d.values[i]); // one then two
}
// note, loop backwards to clear values at a key
END EXAMPLE
EXAMPLE
// with unique property add(key, val) removes the last val at that key
var d = new Dictionary(true);
d.add(circle, "one");
d.add(circle, "two");
zog(d.at(circle)); // two - and now only two is there
for (var i=0; i<d.length; i++) {
if (d.objects[i] == circle) zog(d.values[i]); // two
}
// note, now d.remove(key) removes that unique entry for the key
END EXAMPLE
PARAMETERS
unique (default false) - set to true to only accept a single entry (the last added) for a key
METHODS
add(object, value) - adds a value that can be retrieved by an object reference
if unique is false, this will not overwrite previous entries at the object key
if unique is true, this will overwrite previous entries at the object key
value is optional and will default to true
at(object) - retrieves the last value stored at the object (or returns null if not there)
remove(object) - removes the last value at the object from the Dictionary returns boolean success
clear() - removes all objects from Dictionary - returns object for chaining
dispose() - deletes Dictionary object
PROPERTIES
length - the number of items in the Dictionary
unique - whether the dictionary will overwrite values (going from false to true will not delete previous values)
objects - array of keys
values - array of values synched to keys
--*///+17
zim.Dictionary = function(unique) {
z_d("17");
this.length = 0;
this.unique = unique;
var objects = this.objects = []; // store objects and values in synched arrays
var values = this.values = [];
this.add = function(o,v) {
if (zot(o)) return;
if (zot(v)) v = true;
if (this.unique) this.remove(o);
objects.push(o);
values.push(v);
this.length++;
};
this.at = function(o) {
if (zot(o)) return;
var i = objects.indexOf(o);
if (i > -1) return values[i];
return null;
};
this.remove = function(o) {
if (zot(o)) return false;
var i = objects.indexOf(o);
if (i > -1) {
objects.splice(i,1);
values.splice(i,1);
this.length--;
return true;
} else {
return false;
}
};
this.clear = function() {
objects = this.objects = []; // store objects and values in synched arrays
values = this.values = [];
this.length = null;
return this;
};
this.dispose = function(a,b,disposing) {
objects = null;
values = null;
this.length = null;
return true;
};
};//-17
/*--
zim.Hierarchy = function(input)
Hierarchy
zim class
DESCRIPTION
A hierarchy is a nested structure for organized data (like XML).
For instance, Hierarchy manages the accordion feature of ZIM List()
where the list can be expanded and collapsed to show nested sections.
HOW IT WORKS
There are two formats that can be used as input.
Each will create a data property in final hierarchy format.
A. The SIMPLE input is an easier format to write but
has a limitation in that identifiers must be strings.
The Hierarchy replaces the identifiers with sequential ids
and stores the original identifiers as an obj property.
B. The COMPLEX input starts off like the final hierarchy data
which has the advantage of storing any type of object in the hierarchy.
The disadvantage is the ids must be hand coded and it is longer.
The Hierarchy will add level, open and opened properties
and create the data property in final hierarchy format.
STRATEGY
The complex format is tricky.
One way to deal with it is to pass in a SIMPLE string version.
Then replace the strings with final objects in the data property.
The Hierarchy class is used internally by ZIM so may not be needed.
However, it will help for custom tree menus, mindmaps, etc.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE - SIMPLE INPUT
// 1. Here is linear input as an array - a boring tree - more like grass!
var simple = [1,2,3,4]; // so we would probably not use Hierarchy for this.
// 2. To hold nested data we use an object literal.
// The properties can hold linear arrays as values
// but if any of the values need to hold more values then use an object literal:
var simple = {
"linear":[1,2,3,4], // an array is okay as all items are leaf nodes (end nodes)
"nested":{ // an object literal is required as one or more items hold other items
"A":[], // this holds nothing (a leaf node) but still needs an empty array
"B":["one", "two", "three"], // this holds a linear list - all leaf nodes
"C":{ // this holds another nested list where at least one item holds more
"LEAF":[],
"LINEAR":[1,2,3,4],
"LEAF":[]
}
}
}
// If EXTRA info is desired this can be handled like so:
// Set the values as a list property of an object and add any extra properties desired
// The extra property does not have to be called extra and there can be multiple extra properties
// Avoid calling the properties list, obj, level, open or opened.
// The extra properties will be added to the complex data objects (see below)
var simple = {
"linear":{list:[1,2,3,4], extra:"val"},
"nested":{list:{ // an object literal is required as one or more items hold other items
"A":[], // this holds nothing (a leaf node) but still needs an empty array
"B":["one", "two", "three"], // this holds a linear list - all leaf nodes
"C":{ // this holds another nested list where at least one item holds more
"LEAF":[],
"LINEAR":[1,2,3,4],
"LEAF":[]
}
}, extra:"val"}
}
// pass the object into the input parameter:
var hierarchy = new Hierarchy(simple);
var data = hierarchy.data;
// data will be the following - note it is a more complex format
// but also a form that could hold any type of data as a value
// note the level matches the indent and all values have an id
data = {
id0:{obj:"linear", level:0, open:false, opened:false, list:{
id1:{obj:1, level:1},
id2:{obj:2, level:1},
id3:{obj:3, level:1},
id4:{obj:4, level:1}
}, extra:"val"},
id5:{obj:"nested", level:0, open:false, opened:false, list:{
id6:{obj:"A", level:1},
id7:{obj:"B", level:1, open:false, opened:false, list:{
id8:{obj:"one", level:2},
id9:{obj:"two", level:2},
id10:{obj:"three", level:2}
}},
id11:{obj:"C", level:1, open:false, opened:false, list:{
id12:{obj:"LEAF", level:2},
id13:{obj:"LINEAR", level:2, open:false, opened:false, list:{
id14:{obj:1, level:3},
id15:{obj:2, level:3},
id16:{obj:3, level:3},
id17:{obj:4, level:3}
}},
id18:{obj:"LEAF", level:2}
}}
}, extra:"val"}
}
END EXAMPLE
EXAMPLE - COMPLEX INPUT
// Here is a sample of passing in the more complex format.
// level, open, opened properties are not required
// they will be added by the Hierarchy.
// Note that there are no arrays in this data format so that each item has an id.
// This could be passed in to the data property of List
// to show an expandable hierarchy of objects rather than strings converted to buttons
var complex = {
id0:{obj:new Rectangle(), list:{
id1:{obj:new Triangle()},
id2:{obj:new Triangle()},
id3:{obj:new Triangle()}
}},
id4:{obj:new Circle(), list:{
id5:{obj:new Button()},
id6:{obj:new Button(), list:{
id7:{obj:new CheckBox()},
id8:{obj:new CheckBox()},
}},
id9:{obj:new Button(), list:{
id10:{obj:new Label("Leaf")},
id11:{obj:new Label("Nest"), list:{
id12:{obj:1},
id13:{obj:2},
id14:{obj:3},
id15:{obj:4},
}},
id16:{obj:new Label("Leaf")}
}}
}}
};
var hierarchy = new Hierarchy(complex);
var list = new List({list:hierarchy.data, align:"center"}).center();
END EXAMPLE
PARAMETERS
input (default null) - a simple formated input - see the examples
this will be turned in to a more complex object literal available as the data property
OR input a complex formated input - similar to the data property output
but only ids, obj and list properties are required.
The main purpose of Hierarchy is to create the complex data object
but passing in a complex format allows objects other than strings to be used.
METHODS
processSimple(input) - enter simple input - returns a Hierarchy data object literal
this is what the Hierarchy does when a simple input is provided to make its data property
the input must be in the simple format as described in the SIMPLE example.
processComplex(input) - enter complex input - returns a Hierarchy data object literal
this is what the Hierarchy does when complex data is provided to make its data property
processComplex will add level, open, and opened properties to the data
otherwise data must be in the same format as the final data property - see COMPLEX example
getLinearList(list) - enter final list from the data format, to get a linear list of top level objects
and all open list objects within according to the open property
getLinearIds(list) - enter final list from the data format, to get a linear list of top level ids
and all open lists ids within according to the open property
getData(id) - find the final data format for a given Hierarchy ID - eg. id0, id12, etc.
pass the data.list to the getLinearList() and getLinearIDs() methods
getNextSibling(id) - gets the id of the next sibling - skipping ids of any children
will find parents next sibling if last child in parent
or undefined if last child in hierarchy
getPrevSibling(id) - gets the id of the previous sibling - skipping ids of any children
will find the parent if first child in parent
or undefined if first child in hierarchy
PROPERTIES
data - a hierarchy formated object literal with ids that hold object literals
ids are in the format of id0, id1, id2, etc. numbered in order of creation (top to bottom)
the object literals have obj, level, open, opened and list properties
leaf nodes (end nodes) will have {} as its list property value
length - read only total length of all nodes
--*///+17.5
zim.Hierarchy = function(input, open) {
z_d("17.5");
var that = this;
if (zot(input)) return;
if (zot(open)) open = false;
var _length;
that.processSimple = function(list) {
var count = 0;
var m = {};
function makeLevel(list, obj, level, last) {
if (list.constructor == {}.constructor) {
var originalList;
if (list.list) { // in extra format
originalList = list;
list = list.list;
}
if (last && originalList) {
zim.loop(originalList, function (k,v) {
if (k=="list") return; // like a for loop continue
last[k] = v;
});
}
zim.loop(list, function (key, val) {
var newList = {};
var current = obj["id"+count] = {obj:key, level:level, open:open, opened:false, list:newList};
count++;
makeLevel(val, newList, level+1, current);
});
} else if (Array.isArray(list)) {
zim.loop(list, function (val) {
var newList = {};
obj["id"+count] = {obj:val};
count++;
});
}
}
makeLevel(input, m, 0);
_length = count;
return m;
};
that.processComplex = function(input) {
var count = 0;
function innerFunction(inp, level) {
zim.loop(inp, function (key, val) {
val.level = level;
if (zot(val.open)) val.open = open;
if (zot(val.opened)) val.opened = false;
if (val.list) innerFunction(val.list, level+1);
count++;
});
}
innerFunction(input, 0);
_length = count;
return input;
};
if (zot(input.id0)) {
that.data = that.processSimple(input);
} else {
that.data = that.processComplex(input);
}
that.getLinearList = function(data) {
if (zot(data)) data = that.data;
return getLinear(data)[0];
};
that.getLinearIDs = function(data) {
if (zot(data)) data = that.data;
return getLinear(data)[1];
};
function getLinear(data) {
var linear = [];
var ids = [];
function getLevel(data, level) {
zim.loop(data, function (item, list) {
linear.push(list.obj);
ids.push(item);
if (list.open) getLevel(list.list, level+1);
});
}
getLevel(data, 0);
return [linear, ids];
}
that.getData = function(id) {
// recursively find the data for id
var answer;
function find(obj) {
zim.loop(obj, function (key, val) {
if (key == id) {
answer = val;
return answer;
}
find(val.list);
});
}
find(that.data);
return answer;
};
that.getNextSibling = function(id) {
var current;
var answer;
function find(obj) {
zim.loop(obj, function (key, val) {
if (!answer && current) {
answer = key;
return answer;
}
if (key == id) {
current = val;
} else {
find(val.list);
}
});
}
find(that.data);
return answer;
};
that.getPrevSibling = function(id) {
var lasts = [];
var answer;
function find(obj, lev) {
zim.loop(obj, function (key, val) {
if (key == id) {
answer = lasts[lev] || lasts[lev-1];
return answer;
} else {
lasts[lev] = key;
find(val.list, lev+1);
}
});
}
find(that.data, 0);
return answer;
};
Object.defineProperty(that, 'length', {
get: function() {
return _length;
},
set: function(value) {
if (zon) zogy("Hierarchy() - length is read only");
}
});
};//-17.5
/*--
zim.Pick = function(choices)
Pick
zim class
HISTORY
Pick was originally zik() and ZIM VEE (introduced in ZIM 5) throughout the ZIM documentation
It was so handy that a general (non ZIM centric) name has been given to a class
that can be used by other libraries and languages.
See https://github.com/danzen/Pick for the complete general code and description
DESCRIPTION
Pick() provides a system to handle dynamic parameters.
It does so by providing formats for options and a choose() method to pick from the options.
For example, a particle emitter has an obj parameter to receive what type of particle to emit.
If a particle were randomly chosen from a rectangle, circle or triangle and passed into obj
then the emitter would only emit the randomly chosen particle - say, a bunch of triangles.
What is desired is that the emitter emit rectangles, circles and triangles randomly.
Pick() provides a way to pass in all three shapes and have the emitter choose each time it emits.
FORMATS
The Pick() formats handle:
1. a random selection: ["blue", "green", "yellow"] - array format
2. a random range: {min:10, max:30} - range object format
3. a series: series(10,20,30) - series format also Pick.series()
4. a function result: function(){return new Date().minutes} - function format
5. a normal value: 7 or "hello" - single-value format
6. a noPick object: {noPick:["real", "array"]} - escape format
7. a combination: [{min:10, max:20}, 30, 40] - combination format (recursive)
NOTE: the range format gets passed to ZIM rand() directly so see docs there
there are also integer and negative parameters both defaulting to false
PICK LITERAL
Formats are passed in to a Pick() object and the Pick object can be passed to a class or function parameter
In ZIM, the formats may be passed directly into the class or function parameter (as a Pick literal)
new Circle(new Pick([10,20]), red); // Pick()
new Circle([10,20], red); // Pick Literal
** The literal can run into conflicts such as for a ZIM corner parameter which accepts an array []
This would be avoided with a system always using Pick() and never the literal.
But... ZIM started off without the formalized Pick - and the literal is shorter ;-)
The conflict can be resolved by using {noPick:[]} and then the array is not picked from.
NOTE: Pick is used internally by by zim.interval, zim.animate, zim.Emitter, zim.Pen, etc.
as well as ZIM Shape basic parameters handy for cloning with Tile, Emitter, etc.
EXAMPLE
var loopCount = new Pick([1,2,3]);
var choice = Pick.choose(loopCount); // 1, 2, or 3
var loopCount = [1,2,3]; // Pick literal
var choice = Pick.choose(loopCount); // 1, 2, or 3
var choice = Pick.choose([1,2,3]); // 1, 2, or 3
var rotation = {min:10, max:20, integer:false, negative:true};
// an example of a Range object - this will give values between -20 and -10 or 10 and 20
// rotation now holds an object as to how to pick its value
// this can be passed into a zim.Emitter() for instance
// which will make multiple copies and rotate them based on Pick.choose()
// or this can be passed into an animation object
// and then into zim.Emitter() for the animate parameter
var emitter = new zim.Emitter({
obj:new Rectangle(),
random:{rotation:rotation} // the emitter will use Pick.choose() to pick a rotation for each particle
});
function age() {
// assuming user.age is some input value that exists
if (user.age >= 18) return ["a", "b", ["c","d"]];
else return ["e", "f"];
}
// below will be a, b, c or d if user is 18+ with a and b having more of a chance
// or e or f if not over 18
var show = Pick.choose(age);
// below we randomize the tile colors in the first example
// and make them in color order for the second example
new Tile(new Rectangle(10,10,["blue", "red"]), 10, 10).center(); would randomize colors
new Tile(new Rectangle(10,10,series("blue", "red")), 10, 10).center(); would alternate colors
// here we pass an array through without processing the array:
Pick.choose({noPick:[1,2,3,4,5]}); // result is [1,2,3,4,5]
// a range between one and three seconds - repeating after 3 choices
var pick = new Pick({min:1, max:3}).num(3);
interval(pick, function () {console.log("calling");}); // eg. 2.5s, 2.7s, 1.2s, 2.5s, 2.7s, 1.2s, etc.
END EXAMPLE
PARAMETERS
choices - any of the ZIM Pick formats:
1. an array of choices to choose from randomly
2. a range object with min and max (integer and negative) properties
3. a zim.series() or Pick.series() to pick objects in order
4. a function that returns a result
5. a single not one of the above that passes through
6. an escape object with a noPick property
7. any combination of the above to pick recursively
METHODS
num(number) - a chainable method to limit the number of options until Pick.choose() will repeat like a series
loop(number, call(value, index, total)) - a way to loop through options
number is the number of times to loop
call is a callback function that gets called each loop
the callback will recieve a value (the choice), the index of the loop and the total (the number parameter)
inside the function a return is like a continue and a return of any value is like a break in traditional for loops.
STATIC METHODS
Pick.choose(Pick Object or Pick Literal) - gets a value from the Pick object or Pick Literal
so chooses from a random array, or range, or gets the next in the series, etc.
Pick.rand(a, b, integer, negative) - gets a random number - same as zim.rand()
a - the first Number for the range
if a and b are not provided, rand() acts like Math.random()
if parameter b is not provided, rand will use range 0 to and including a
b - (default 0) second Number for the range
it does not matter if a>b or a<b
integer - (default true) set to false to include decimals in results
if false, range will include decimals up to but not including the highest number
if a or b have decimals this is set to false
negative - (default false) includes the negative range as well as the positive
Pick.series(array|item1, item2, item3, etc.) - same as zim.series()
returns a function that can be called many times each time returning the next value in the series (eventually looping)
array|item1 - the first item - or an array of results that will be called in order as the resulting function is called
item2 - the second item if the first is not an array
item3 - the third item, etc. to as many items as needed
PROPERTIES
type - the type of object as a String
choices - a reference to the choices object provided as the Pick(choices) parameter
--*///+17.6
zim.Pick = function(choices) {
if (!zim.pickCheck) {z_d("17.6"); zim.pickCheck=true;}
this.choices = choices;
this.num = function(num) {
var s = [];
for (var i=0; i<num; i++) {s.push(zim.Pick.choose(this));}
this.choices = zim.Pick.series(s);
return this;
};
var that = this;
this.loop = function(num, call) {
var r;
for (var i=0; i<num; i++) {
r = call(zim.Pick.choose(that), i, num);
if (typeof r != 'undefined') return r;
}
};
};
zim.Pick.prototype.type = "Pick";
zim.Pick.series = function() {
// see https://github.com/danzen/Pick for all inclusive class to use in other libraries / languages, etc.
if (!zim.pickCheck) {z_d("17.6"); zim.pickCheck=true;}
return zim.series.apply(null, arguments);
};
zim.Pick.rand = function(a, b, integer, negative) {
// see https://github.com/danzen/Pick for all inclusive class to use in other libraries / languages, etc.
if (!zim.pickCheck) {z_d("17.6"); zim.pickCheck=true;}
return zim.rand(a, b, integer, negative);
};
zim.Pick.choose = function(obj, literal, target) {
if (!zim.pickCheck) {z_d("17.6"); zim.pickCheck=true;}
if (literal == null) literal = true;
if (obj==null) return obj;
if (obj.type=="Pick" || literal) {
var c = obj.choices || obj;
if (Array.isArray(c)) {
var val = c[Math.floor(Math.random()*(c.length))];
return zim.Pick.choose(val); // recursive
} else if (c.constructor === {}.constructor) {
if (!zot(c.noPick)) return c.noPick; // a passthrough for arrays and functions
if (zot(c.max)) return c;
if (zot(c.integer)) c.integer = false;
var val = zim.Pick.rand(c.min, c.max, c.integer, c.negative);
return val; // this is just a number in a range - no need for recursive
} else if (c instanceof Function) {
if (c.count==null) c.count=0;
else c.count++;
return zim.Pick.choose((c)(target)); // recursive
}
return obj;
} else {
return obj;
}
};//-17.6
// DOM CODE
// SUBSECTION HTML FUNCTIONS
/*--
zim.scrollX = function(num, time)
scrollX
zim function
DESCRIPTION
This function gets or sets how many pixels from the left the browser window has been scrolled.
If num is provided then the function scrolls the window to this x position.
If num and time are provided it animates the window to the x position in time milliseconds.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// hide the logo if the page is scrolled left more than 200 pixels
if (scrollX < -200) zss("logo").display = "none";
END EXAMPLE
PARAMETERS
num - (default null) optional scroll position to go to (probably negative)
time - (default 0) time in seconds to take to go to the num position (also see ZIM TIME constant)
RETURNS a Number
--*///+18
zim.scrollX = function(num, time) {
z_d("18");
return zim.abstractScroll("X", "Left", num, time);
};//-18
/*--
zim.scrollY = function(num, time)
scrollY
zim function
DESCRIPTION
This function gets or sets how many pixels from the top the browser window has been scrolled.
If num is provided then the function scrolls the window to this y position.
If num and time are provided it animates the window to the y position in time milliseconds.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// animate the scroll position down 100 pixels in half a second
scrollY(scrollY()-100, .5);
END EXAMPLE
PARAMETERS
num - (default null) optional scroll position to go to (probably negative)
time - (default 0) time in seconds to take to go to the num position (also see ZIM TIME constant)
RETURNS a Number
--*///+19
zim.scrollY = function(num, time) {
z_d("19");
return zim.abstractScroll("Y", "Top", num, time);
};//-19
//+20
zim.abstractScroll = function(dir, side, num, time) {
z_d("20");
var timeType = getTIME(time);
var perpend = (dir == "X") ? "Y" : "X"; // perpendicular direction
if (zot(num)) {
var safari = 0;
var browser=navigator.applicationName;
var navindex=navigator.userAgent.indexOf('Safari');
if (navindex != -1 || browser=='Safari') {
var safari = 1;
}
return (document.documentElement && document.documentElement["scroll"+side]) || document.body["scroll"+side];
} else if (zot(time)) {
window.scrollTo(zim["scroll"+perpend](), num);
} else {
var interval = 50;
var t = time*(timeType=="s"?1000:1);
if (t < interval) t = interval;
var steps = t/interval;
var current = zim["scroll"+dir]();
var amount = num - current;
var diff = amount/steps;
var count = 0;
var scrollInterval = setInterval(function() {
count++;
current+=diff;
window.scrollTo(zim["scroll"+perpend](), current);
if (count >= steps) {
window.scrollTo(zim["scroll"+perpend](), num);
clearInterval(scrollInterval);
}
}, interval);
}
return num;
};//-20
/*--
zim.windowWidth = function()
windowWidth
zim function
DESCRIPTION
Returns the width of a window.
(window.clientWidth or window.innerWidth)
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
if (windowWidth() < 500) zss("related").display = "none";
END EXAMPLE
RETURNS a Number
--*///+21
zim.windowWidth = function() {
z_d("21");
var w = isNaN(window.innerWidth) ? window.clientWidth : window.innerWidth;
var h = isNaN(window.innerHeight) ? window.clientHeight : window.innerHeight;
if (zim.mobile() && !zot(window.orientation) && !window.parent) {
if ((w > h && Math.abs(window.orientation) != 90) || h > w && Math.abs(window.orientation) == 90) {
var oldW = w;
w = h;
h = oldW;
}
}
// 6. part of TEN PATCH
// pay attention to swapRotation from Frame
return (typeof zdf != "undefined" && zdf.swapRotation)?h:w;
};//-21
/*--
zim.windowHeight = function()
windowHeight
zim function
DESCRIPTION
Returns the height of a window.
(window.clientHeight or window.innerHeight)
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
if (windowHeight() > 1000) zgo("big.html");
END EXAMPLE
RETURNS a Number
--*///+22
zim.windowHeight = function() {
z_d("22");
var w = isNaN(window.innerWidth) ? window.clientWidth : window.innerWidth;
var h = isNaN(window.innerHeight) ? window.clientHeight : window.innerHeight;
if (zim.mobile() && !zot(window.orientation) && !window.parent) {
if ((w > h && Math.abs(window.orientation) != 90) || h > w && Math.abs(window.orientation) == 90) {
var oldW = w;
w = h;
h = oldW;
}
}
// 7. part of TEN PATCH
// pay attention to swapRotation from Frame
return (typeof zdf != "undefined" && zdf.swapRotation)?w:h;
};//-22
/*--
zim.getQueryString = function(string)
getQueryString
zim function
DESCRIPTION
Turns the HTML query string into a object.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// currentHTML page myPage.html?party=true&toys=many
var details = getQueryString();
zog(details.party); // "true"
zog(details.toys); // "many"
loop(details, function(key, val, i) {
zog(key, val, i);
});
// outputs:
// party true 0
// toys many 1
END EXAMPLE
EXAMPLE
// an array of values is created if a query string has multiple properties with the same name:
var collection = getQueryString("type=dog&age=10&age=20&age=30");
zog(collection.age); // [10,20,30]
END EXAMPLE
PARAMETERS
string - (default null) null will get string from end of HTML page after ?
set the key value pairs (without question mark) to parse a custom string
eg. party=true&toys=many
RETURNS an object literal with properties matching the keys and values matching the values (or undefined if no query string)
--*///+22.5
zim.getQueryString = function(s) {
z_d("22.5");
if (zot(s)) s = location.search.replace("?","");
if (s == "") return {};
var vars = s.split("&");
var obj = {};
for (var i=0; i<vars.length; i++) {
var pair = vars[i].split("=");
if (typeof obj[pair[0]] == "undefined") {
obj[pair[0]] = decodeURIComponent((pair[1] + '').replace(/\+/g, '%20'));
} else if (typeof obj[pair[0]] == "string") {
obj[pair[0]] = [obj[pair[0]], decodeURIComponent((pair[1] + '').replace(/\+/g, '%20'))];
} else {
obj[pair[0]].push(decodeURIComponent((pair[1] + '').replace(/\+/g, '%20')));
}
}
return obj;
};//-22.5
/*--
zim.swapHTML = function(idA, idB)
swapHTML
zim function
DESCRIPTION
Pass in two tag ids as strings and this function will swap their innerHTML content.
The content (including nested tags) will be swapped.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// exchanges the content of two divs called question and answer
swapHTML("question","answer");
END EXAMPLE
PARAMETERS
idA, idB - String names of the tag id with which to swap innerHTML values
RETURNS Boolean indicating success
--*///+17.2
zim.swapHTML = function(idA, idB) {
z_d("17.2");
return zim.swapProperties("innerHTML", zid(idA), zid(idB));
};//-17.2
/*--
zim.urlEncode = function(string)
urlEncode
zim function
DESCRIPTION
Matches PHP urlencode and urldecode functions
for passing data on end of URL.
NOTE: only encode values of key=value pairs (not keys and not both keys and values)
NOTE: JSON automatically encodes and decodes - except maybe &
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var motto = "good = life & life = now";
zgo("submit.php?motto="+urlEncode(motto));
END EXAMPLE
PARAMETERS
string - a value to URL encode (space to plus, etc.)
RETURNS a String
--*///+23
zim.urlEncode = function(s) {
z_d("23");
var s = (s + '').toString();
return encodeURIComponent(s).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').
replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+');
};//-23
/*--
zim.urlDecode = function(string)
urlDecode
zim function
DESCRIPTION
Matches PHP urlencode and urldecode functions
for receiving raw data from a source that URLencodes.
NOTE: JSON automatically encodes and decodes
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var pairs = command.split("&");
var motto = urlDecode(pairs[0].split("=")[1]);
END EXAMPLE
PARAMETERS
string - a URLencoded String to decode
RETURNS a String
--*///+24
zim.urlDecode = function(s) {
z_d("24");
return decodeURIComponent((s + '').replace(/\+/g, '%20'));
};//-24
/*--
zim.setCookie = function(name, value, days)
setCookie
zim function
DESCRIPTION
Sets an HTML cookie to remember some user data your site has set over time.
If no days, it will be a session cookie (while browser is open).
NOTE: cookies may not work unless files are on a server
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var visits = getCookie("visits");
if (zot(visits)) visits = 0;
setCookie("visits", ++visits);
END EXAMPLE
PARAMETERS
name - a String name for your cookie
value - a String value that you want to store
days - (default 0) for how many days do you want to store the cookie
ALSO: see getCookie and deleteCookie
RETURNS a Boolean indicating success
--*///+25
zim.setCookie = function(name, value, days) {
z_d("25");
if (zot(name) || zot(value)) return;
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
} else {
var expires = "";
}
document.cookie = name+"="+escape(value)+expires+"; path=/";
return true;
};//-25
/*--
zim.getCookie = function(name)
getCookie
zim function
DESCRIPTION
Gets an HTML cookie that you have previously set.
NOTE: cookies may not work unless files are on a server
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var visits = getCookie("visits");
if (zot(visits)) visits = 0;
setCookie("visits", ++visits);
END EXAMPLE
PARAMETERS
name - the String name of your stored cookie
ALSO: see setCookie and deleteCookie
RETURNS a String or undefined if not found
--*///+26
zim.getCookie = function(name) {
z_d("26");
var outer = document.cookie.split(/;\s*/);
var cookies = new Array();
var inner;
for (i=0; i<outer.length; i++) {
inner = outer[i].split("=");
cookies[inner[0]] = inner[1];
}
if (typeof cookies[name] == 'undefined') return undefined;
return unescape(cookies[name]);
};//-26
/*--
zim.deleteCookie = function(name)
deleteCookie
zim function
DESCRIPTION
Deletes an HTML cookie.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
deleteCookie("visits"); // clears the cookie
END EXAMPLE
PARAMETERS
name - the String name of your stored cookie to delete
ALSO: see setCookie and getCookie
RETURNS a Boolean indicating success
--*///+27
zim.deleteCookie = function(name) {
z_d("27");
if (zot(zim.getCookie(name))) return false;
zim.setCookie(name,"",-1);
return true;
};//-27
if (createjs == null) {if (zon) {zogr("ZIM >= 4.3.0 requires createjs namespace to be loaded (import createjs before zim)");} return zim;}
//////////////// ZIM DISPLAY //////////////
// Zim Display (formerly Zim Build) adds common display classes for Zapps (apps, art, games and gadgets with ZIM)
// classes in this module require createjs namespace to exist and in particular easel.js
// available at http://createjs.com
/*--
zim.Coordinates = function(canvasID)
Helper functions for localToGlobal, globalToLocal and localToLocal
--*///+50.43
zim.localToGlobal = function localToGlobal(x,y,scope,func) {
if (!zim.coordinatesCheck) {z_d("50.43"); zim.coordinatesCheck=true;}
if (x==null || y==null) return;
var point = func.call(scope,x,y);
var stage = scope.stage;
if (typeof zdf == "undefined") {
if (!stage) return point;
zdf = {stage:stage, canvas:stage.canvas};
}
point.x /= zim.scaX;
point.y /= zim.scaY;
return point;
};
zim.globalToLocal = function globalToLocal(x,y,scope,func) {
if (!zim.coordinatesCheck) {z_d("50.43"); zim.coordinatesCheck=true;}
if (x==null || y==null) return;
var stage = scope.stage;
if (typeof zdf == "undefined") {
if (!stage) return func.call(scope,x,y);
zdf = {stage:stage, canvas:stage.canvas};
}
x *= zim.scaX;
y *= zim.scaY;
var point = func.call(scope,x,y);
return point;
};
zim.localToLocal = function localToLocal(x,y,target,scope) {
if (!zim.coordinatesCheck) {z_d("50.43"); zim.coordinatesCheck=true;}
if (x==null || y==null || target==null) return;
var point = scope.localToGlobal(x,y);
var stage = scope.stage;
if (typeof zdf == "undefined") {
if (!stage) return target.globalToLocal(point.x, point.y);
zdf = {stage:stage, canvas:stage.canvas};
}
if (!stage) stage = zdf.stage;
if (target == stage) return point;
if (point) return target.globalToLocal(point.x, point.y);
};
//-50.43
/*--
zim.displayBase = function()
displayBase
zim function
DESCRIPTION
Used internally by ZIM to set common properties on basic DisplayObjects
Container, Shape, Bitmap, Sprite, MovieClip
Also called by zimify() if object does not already have these (hueBatch used for test)
Turns off and on allowDefault if allowDefault is true as object is interacted with
this prevents the page from scrolling on mobile when drag, gesture, transform, etc. are happening
Might have set these on CreateJS DisplayObject
--*///+50.432
zim.displayBase = function(obj) {
if (!zim.zimDBCheck) {z_d("50.432"); zim.zimDBCheck=true;}
var that = obj;
Object.defineProperty(obj, 'width', {
enumerable: true,
get: function() {
// that.setBounds(null);
var b = this.getBounds();
return (zot(b))?null:Math.abs(b.width*this.scaleX);
},
set: function(value) {
var b = this.getBounds();
if (zot(b) || b.width==0) {
if (zon) zogy("DisplayObject() - width needs bounds set with setBounds()");
return;
}
var s = value/b.width;
this.scaleX = this.scaleY = s;
}
});
Object.defineProperty(obj, 'height', {
enumerable: true,
get: function() {
// that.setBounds(null);
var b = this.getBounds();
return (zot(b))?null:Math.abs(b.height*this.scaleY);
},
set: function(value) {
var b = this.getBounds();
if (zot(b) || b.height==0) {
if (zon) zogy("DisplayObject() - height needs bounds set with setBounds()");
return;
}
var s = value/b.height;
this.scaleX = this.scaleY = s;
}
});
Object.defineProperty(obj, 'widthOnly', {
enumerable: true,
get: function() {
// that.setBounds(null);
var b = this.getBounds();
return (zot(b))?null:Math.abs(b.width*this.scaleX);
},
set: function(value) {
var b = this.getBounds();
if ((zot(b) || b.width==0) && zon) {zogy("DisplayObject() - widthOnly needs bounds set with setBounds()"); return;}
var s = value/b.width;
this.scaleX = s;
}
});
Object.defineProperty(obj, 'heightOnly', {
enumerable: true,
get: function() {
// that.setBounds(null);
var b = this.getBounds();
return (zot(b))?null:Math.abs(b.height*this.scaleY);
},
set: function(value) {
var b = this.getBounds();
if ((zot(b) || b.height==0) && zon) {zogy("DisplayObject() - heightOnly needs bounds set with setBounds()"); return;}
var s = value/b.height;
this.scaleY = s;
}
});
Object.defineProperty(obj, 'level', {
enumerable: true,
get: function() {
if (this.parent) return this.parent.getChildIndex(this); return null;
},
set: function(value) {
if (this.parent) this.parent.setChildIndex(this, Math.max(0, Math.min(value, this.parent.numChildren-1)));
}
});
Object.defineProperty(obj, 'depth', {
enumerable: true,
get: function() {
return this._depth;
},
set: function(depth) {
this._depth = depth;
if (!zot(this.vrChannel)) {
var parallaxShift = this.vrParallaxDistance ? depth*this.vrParallax*this.vrParallaxDistance : 0;
if (this.vrChannel == "left") {
this.x = this.vrStartX + depth + parallaxShift;
} else if (this.vrChannel == "right") {
this.x = this.vrStartX - depth + parallaxShift;
}
}
}
});
Object.defineProperty(obj, 'blendMode', {
enumerable: true,
get: function() {
return this.compositeOperation;
},
set: function(value) {
this.compositeOperation = value;
}
});
if (!that.name) {
var _name;
Object.defineProperty(that, 'name', {
get: function() {
return _name;
},
set: function(value) {
_name = value;
zim.zimObjectIDs[value] = that;
}
});
}
that._draggable;
Object.defineProperty(that, 'draggable', {
get: function() {
return this._draggable;
},
set: function(value) {
if (value == this._draggable) return;
this._draggable = value;
if (this._draggable) this.drag();
else this.noDrag();
}
});
var frame;
var adCheck;
that.on("mousedown", function (e) {
if (e.target.stage) {
frame = e.target.stage.frame;
if (frame.allowDefault) {
adCheck = true;
frame.allowDefault = false;
}
}
});
that.on("pressup", function (e) {
if (frame && adCheck) frame.allowDefault = true;
});
// EFFECTS
// making 8 properties, 4 that update effect and 4 that do not
// so that regular properties can update effect - obj.hue=20 // updates
// but animate and wiggle can bulk update effect - obj.hueBatch=20 // does not update
var effects = ["hue", "saturation", "brightness", "contrast"];
for (var i=0; i<effects.length; i++) {
-function() { // closure to remember eff
var eff = effects[i];
for (var j=0; j<2; j++) {
-function() { // closure to remember add
var add = j==0?"":"Batch";
Object.defineProperty(that, eff+add, {
get: function() {
if (that.effects && that.effects.multi) return that.effects.multi[eff];
else return 0;
},
set: function(value) {
if (!that.effects || !that.effects.multi) that.effect(new MultiEffect(eff=="hue"?value:0,eff=="saturation"?value:0,eff=="brightness"?value:0,eff=="contrast"?value:0));
else that.effects.multi[eff] = value;
if (add=="") that.updateEffects();
}
});
}();
}
}();
}
}
//-50.432
/*--
zim.gD = function()
gD
zim function
DESCRIPTION
Used internally by ZIM to globally dispose common connections
--*///+50.435
zim.gD = function(obj) {
if (!zim.zimGDCheck) {z_d("50.435"); zim.zimGDCheck=true;}
if (!obj) return;
if (zim.KEYFOCUS == obj) zim.KEYFOCUS = null;
if (obj.draggable) obj.noDrag();
if (obj.zimTweens) obj.stopAnimate();
if (obj.zimWire) obj.noWire();
if (obj.zimWired) obj.noWired();
if (obj.zimClickHoldDownEvent) obj.noHold();
if (obj.transformControls) obj.transformControls.dispose();
if (obj.zimClickDownEvent) obj.zimClickDownEvent = null;
if (obj.zimClickUpEvent) obj.zimClickUpEvent = null;
if (obj.physics) obj.removePhysics();
if (obj.name && zim.zimObjectIDs[obj.name] == obj) delete zim.zimObjectIDs[obj.name];
}
//-50.435
/*--
zim.Stage = function(canvasID)
Stage
zim class - extends a createjs.Stage which extends a createjs.Container
DESCRIPTION
An extension of a createjs.Stage that includes read only type, width and height properties, loop and hitTestGrid methods.
When using zim.Frame, there should be no reason to make a zim.Stage.
This was put in place to match the ZIM TypeScript typings for stage width and height.
Also see https://www.createjs.com/docs/easeljs/classes/Stage.html
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var stage = new Stage("canvasID");
END EXAMPLE
PARAMETERS
canvasID - (default null) string ID for canvas tag
METHODS
loop(call, reverse, step, start, end) - see the ZIM Display Methods loop() for details
see the ZIM Display Methods loop() for details
hitTestGrid(width, height, cols, rows, x, y, offsetX, offsetY, spacingX, spacingY, local, type)
see the ZIM Display Methods hitTestGrid() for details
disposeAllChildren() - remove and dispose all children
See the CreateJS Easel Docs for Stage methods, such as:
clear, update, toDataURL
And all the Container methods such as:
on, off, setBounds, getBounds, globalToLocal, etc.
PROPERTIES
frame - if made with ZIM Frame then frame points to the frame that made the stage
type - holds the class name as a String
width - read only width set by ZIM Frame
height - read only height set by ZIM Frame
ALSO: see the CreateJS Easel Docs for Stage properties, such as:
autoClear, canvas, nextStage, etc.
and all the Container properties, such as:
children, mouseChildren, filters, cacheCanvas, etc.
Note: also makes a partial zdf allowing circle.center() to work
but will be overwritten if an actual Frame is made
EVENTS
See the CreateJS Easel Docs for Stage events, such as:
mouseenter, mouseleave, stagemousedown, stagemousemove, stagemouseup, drawstart, drawend, etc.
and all the Container events such as:
click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+50.44
zim.Stage = function(canvasID) {
z_d("50.44");
if (zot(canvasID)) return;
var tag = canvasID.tagName=="CANVAS"?canvasID:zid(canvasID);
if (zot(tag)) return;
this.cjsStage_constructor(canvasID);
this.setBounds(0,0,tag.width,tag.height);
this.type = "Stage";
if (typeof zdf == 'undefined') zimDefaultFrame = zdf = {stage:this};
this.cache = function(a,b,c,d,scale,options) {
if (zot(c)) {
if (zot(a)) {
var bounds = this.getBounds();
if (!zot(bounds)) {
var added = this.borderWidth > 0 ? this.borderWidth/2 : 0;
a = bounds.x-added;
b = bounds.y-added;
c = bounds.width+added*2;
d = bounds.height+added*2;
}
} else {
c = a;
d = b;
a = 0;
b = 0;
}
}
this.cjsStage_cache(a,b,c,d,scale,options);
return this;
};
this.on("mousedown", function(e) {
var e2 = e.clone();
e2.type = "pressdown";
e.target.dispatchEvent(e2);
}, undefined, false, undefined, true);
this.loop = function(call, reverse, step, start, end) {
return zim.loop(this, call, reverse, step, start, end);
};
this.hitTestGrid = function(width, height, cols, rows, x, y, offsetX, offsetY, spacingX, spacingY, local, type) {
return zim.hitTestGrid(this, width, height, cols, rows, x, y, offsetX, offsetY, spacingX, spacingY, local, type);
};
this.disposeAllChildren = function() {
for (var i=this.numChildren-1; i>=0; i--) {
var child = this.getChildAt(i)
if (child.dispose) child.dispose();
}
return this;
};
var frame = zdf || 1;
if (createjs && !createjs.stageTransformable && (zdf.retina || typeof exportRoot != "undefined")) {
Object.defineProperty(this, 'scale', {
get: function () {
return this.cjsStage_scale;
},
set: function (value) {
this.cjsStage_scaleX = value;
this.cjsStage_scaleY = value;
zim.scaX = createjs.stageTransformable ? 1 : value;
zim.scaY = createjs.stageTransformable ? 1 : value;
}
});
Object.defineProperty(this, 'scaleX', {
get: function () {
return this.cjsStage_scaleX;
},
set: function (value) {
this.cjsStage_scaleX = value;
zim.scaX = createjs.stageTransformable ? 1 : value;
}
});
Object.defineProperty(this, 'scaleY', {
get: function () {
return this.cjsStage_scaleY;
},
set: function (value) {
this.cjsStage_scaleY = value;
zim.scaY = createjs.stageTransformable ? 1 : value;
}
});
this.localToGlobal = function (x, y) {
return zim.localToGlobal(x, y, this, this.cjsStage_localToGlobal);
};
this.globalToLocal = function (x, y) {
return zim.globalToLocal(x, y, this, this.cjsStage_globalToLocal);
};
this.localToLocal = function (x, y, target) {
return zim.localToLocal(x, y, target, this);
};
}
};
zim.extend(zim.Stage, createjs.Stage, ["cache","localToLocal","localToGlobal","globalToLocal"], "cjsStage", false);
//-50.44
/*--
zim.StageGL = function(canvasID, options)
StageGL
zim class - extends a zim.Stage which extends a createjs.Stage
DESCRIPTION
An extension of a zim.Stage for WebGL support
See ZIM Stage and https://www.createjs.com/docs/easeljs/classes/StageGL.html
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var stage = new StageGL("canvasID", {preserveBuffer:true, antialias:true});
END EXAMPLE
PARAMETERS
canvasID - (default null) string ID for canvas tag
options - (default null) an object literal with the following properties
FROM https://www.createjs.com/docs/easeljs/classes/StageGL.html
preserveBuffer (default false)
If true, the canvas is NOT auto-cleared by WebGL (the spec discourages setting this to true). This is useful if you want persistent draw effects.
antialias (default false)
Specifies whether or not the browser's WebGL implementation should try to perform anti-aliasing. This will also enable linear pixel sampling on power-of-two textures (smoother images).
transparent (default false)
If true, the canvas is transparent. This is very expensive, and should be used with caution.
premultiply (default false)
Alters color handling. If true, this assumes the shader must account for pre-multiplied alpha. This can help avoid visual halo effects with some assets, but may also cause problems with other assets.
autoPurge (default 1200)
How often the system should automatically dump unused textures with purgeTextures(autoPurge) every autoPurge/2 draws. See purgeTextures for more information.
METHODS
loop(call, reverse, step, start, end) - see the ZIM Display Methods loop() for details
see the ZIM Display Methods loop() for details
hitTestGrid(width, height, cols, rows, x, y, offsetX, offsetY, spacingX, spacingY, local, type)
see the ZIM Display Methods hitTestGrid() for details
disposeAllChildren() - remove and dispose all children
See the CreateJS Easel Docs for StageGL methods:
https://www.createjs.com/docs/easeljs/classes/StageGL.html
PROPERTIES
frame - if made with ZIM Frame then frame points to the frame that made the stage
type - holds the class name as a String
width - read only width set by ZIM Frame
height - read only height set by ZIM Frame
See the CreateJS Easel Docs for Stage properties:
https://www.createjs.com/docs/easeljs/classes/StageGL.html
Note: also makes a partial zdf allowing circle.center() to work
but will be overwritten if an actual Frame is made
EVENTS
See the CreateJS Easel Docs for StageGL events, such as:
mouseenter, mouseleave, stagemousedown, stagemousemove, stagemouseup, drawstart, drawend, etc.
and all the Container events such as:
click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+50.45
zim.StageGL = function(canvasID, options) {
z_d("50.45");
if (zot(canvasID)) return;
var tag = canvasID.tagName=="CANVAS"?canvasID:zid(canvasID);
if (zot(tag)) return;
this.cjsStageGL_constructor(canvasID, options);
this.setBounds(0,0,tag.width,tag.height);
this.type = "StageGL";
if (typeof zdf == 'undefined') zdf = {stage:this};
this.cache = function(a,b,c,d,scale,options) {
if (zot(c)) {
if (zot(a)) {
var bounds = this.getBounds();
if (!zot(bounds)) {
var added = this.borderWidth > 0 ? this.borderWidth/2 : 0;
a = bounds.x-added;
b = bounds.y-added;
c = bounds.width+added*2;
d = bounds.height+added*2;
}
} else {
c = a;
d = b;
a = 0;
b = 0;
}
}
this.cjsStageGL_cache(a,b,c,d,scale,options);
return this;
};
this.on("mousedown", function(e) {
var e2 = e.clone();
e2.type = "pressdown";
e.target.dispatchEvent(e2);
}, undefined, false, undefined, true);
this.loop = function(call, reverse, step, start, end) {
return zim.loop(this, call, reverse, step, start, end);
};
this.hitTestGrid = function(width, height, cols, rows, x, y, offsetX, offsetY, spacingX, spacingY, local, type) {
return zim.hitTestGrid(this, width, height, cols, rows, x, y, offsetX, offsetY, spacingX, spacingY, local, type);
};
this.disposeAllChildren = function() {
for (var i=this.numChildren-1; i>=0; i--) {
var child = this.getChildAt(i)
if (child.dispose) child.dispose();
}
return this;
};
var frame = zdf || 1;
if (createjs && !createjs.stageTransformable && (zdf.retina || typeof exportRoot != "undefined")) {
Object.defineProperty(this, 'scale', {
get: function() {
return this.cjsStage_scale;
},
set: function(value) {
this.cjsStage_scaleX = value;
this.cjsStage_scaleY = value;
zim.scaX = createjs.stageTransformable ? 1 : value;
zim.scaY = createjs.stageTransformable ? 1 : value;
}
});
Object.defineProperty(this, 'scaleX', {
get: function() {
return this.cjsStage_scaleX;
},
set: function(value) {
this.cjsStage_scaleX = value;
zim.scaX = createjs.stageTransformable ? 1 : value;
}
});
Object.defineProperty(this, 'scaleY', {
get: function() {
return this.cjsStage_scaleY;
},
set: function(value) {
this.cjsStage_scaleY = value;
zim.scaY = createjs.stageTransformable ? 1 : value;
}
});
this.localToGlobal = function(x,y) {
return zim.localToGlobal(x,y,this,this.cjsStageGL_localToGlobal);
};
this.globalToLocal = function(x,y) {
return zim.globalToLocal(x,y,this,this.cjsStageGL_globalToLocal);
};
this.localToLocal = function(x,y,target) {
return zim.localToLocal(x,y,target,this);
};
}
};
zim.extend(zim.StageGL, createjs.StageGL, ["cache","localToLocal","localToGlobal","globalToLocal"], "cjsStageGL", false);
//-50.45
/*--
zim.Container = function(a, b, c, d, style, group, inherit)
Container
zim class - extends a createjs.Container
DESCRIPTION
A Container object is used to hold other display objects or other containers.
You can then move or scale the container and all objects inside will move or scale.
You can apply an event on a container and use the target property of the event object
to access the object in the container that caused the event
or use the currentTarget property of the event object to access the container itself.
Containers do not have bounds unless some items in the container have bounds -
at which point the bounds are the combination of the bounds of the objects with bounds.
You can manually set the bounds with setBounds(x,y,w,h) - read the CreateJS docs.
Or pass in width and height, or boundsX, boundsY, width, height to have Container set bounds
Manually set bounds will not update automatically unless you setBounds(null).
NOTE: All the ZIM shapes and components extend the Container.
This means all shapes and components inherit the methods and properties below
and indeed, the Container inherits all the createjs.Container methods and properties.
See the CreateJS documentation for x, y, alpha, rotation, on(), addChild(), etc.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var container = new Container();
stage.addChild(container);
container.x = 100; container.y = 100;
// demonstration of adding drag() to a Container
var rect = new Rectangle(100, 100, "blue");
container.addChild(rect); // add rectangle to container
var circle = new Circle(40, "red");
circle.center(container) // add the circle to the container and center
container.drag(); // will drag either the rectangle or the circle
container.drag({currentTarget:true}); // will drag both the rectangle and the circle
// below will reduce the alpha of the object in the container that was clicked (target)
container.on("click" function(e) {e.target.alpha = .5; stage.update();})
// below will reduce the alpha of all the objects in the container (currentTarget)
container.on("click" function(e) {e.currentTarget.alpha = .5; stage.update();})
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
** Container supports three different sets of parameters as follows:
a - (default null) - width and height equal to parameter a (x and y will be 0)
a, b - (default null) - the width and height (x and y will be 0)
a, b, c, d - (default null) - the x, y, width and height of the bounds
if parameter a is not set, then the Container will take bounds that grow with its content
the bounds of the Container can be set at any time with setBounds(a, b, c, d)
if the bounds are set, then the Container bounds will not change as content is added
the bounds can be removed with setBounds(null) and the Container will get auto bounds
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
* This class has all the DISPLAY METHODS introduced in ZIM 4TH
* the methods are available to all ZIM Display objects that extend a ZIM Container
* such as ZIM Rectangle, Circle, Triangle, BLob
* as well as all components like: Label, Button, Slider, Dial, Tab, Pane, etc.
* as well as the ZIM display wrappers: Container, Shape, Sprite, MovieClip and Bitmap
cache(width||x, height||y, null||width, null||height, scale, options, margin) - overrides CreateJS cache() and returns object for chaining
If you do not provide the first four parameters, then the cache dimensions will be set to the bounds of the object
width||x - (default getBounds().x) the width of the chache - or the x if first four parameters are provided
height||y - (default getBounds().y) the height of the chache - or the y if first four parameters are provided
width - (default getBounds().width) the width of the chache - or null if first two parameters are provided
height - (default getBounds().height) the height of the chache - or null if first two parameters are provided
scale - (default 1) set to 2 to cache with twice the fidelity if later scaling up
options - (default null) additional parameters for cache logic - see CreateJS somewhere for details
margin - (default 0) add or subtract a margin from the bounds
eg. margin:10 will make the cache size 10 pixels more on all sides
this can be handy when caching objects with borders - that go half outside the natural bounds
uncache() - uncaches and returns object for chaining
setBounds(width||x||Boundary, height||y, null||width, null||height) - overrides CreateJS setBounds() and returns object for chaining
If you do not provide the any parameters, then the bounds will be reset to the calculated bounds
width||x||Boundary - (default null) the width of the bounds - or the x if four parameters are provided
or a ZIM Boundary Object {x,y,width,height} - same as CreateJS Rectangle - thanks Joseph Diefenbach
height||y - (default width) the height of the bounds - or the y if four parameters are provided
width - (default null) the width of the bounds - or null if only the first two parameters are provided
height - (default null) the height of the bounds - or null if only the first two parameters are provided
childrenToBitmap() - turns content to a Bitmap and adds bitmap to container - removing all other children
specialColor(colorCommand, colorObject) - used internally by ZIM Shapes
to set GradientColor, RadialColor and BitmapColor on a fill or stroke color command
hasProp(property as String) - returns true if property exists on object else returns false
clone(exact) - clones the container, its properties and all its children
exact (default false) ZIM VEE (Pick) values are active in clones unless exact is set to true
For instance, if a Container holds a new Circle(20,[blue,green])
then its clone might be blue or green
If exact is set to true then the clone will be whatever color was picked for the original circle
disposeAllChildren() - removes and disposes all children but leaves the container (see also CreateJS removeAllChildren() which does not dispose them)
dispose(disposing) - removes from parent, removes event listeners - must still set outside references to null for garbage collection
if calling dispose() on the super class from a custom class then pass in true to indicate already started dispose (otherwise infinite loops)
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
** common to all DisplayObjects that extend a Container such as ZIM Shapes and Components
type - holds the class name as a String
group - used when the object is made to add STYLE with the group selector (like a CSS class)
** bounds must be set first (or width and height parameters set) for these to work
** setting these adjusts scale not bounds and getting these uses the bounds dimension times the scale
width - gets or sets the width. Setting the width will scale the height to keep proportion (see widthOnly below)
height - gets or sets the height. Setting the height will scale the width to keep proportion (see heightOnly below)
widthOnly - gets or sets the width. This sets only the width and may change the aspect ratio of the object
heightOnly - gets or sets the height. This sets only the height and may change the aspect ratio of the object
draggable - set to true for a default drag() and false for a noDrag()
level - gets or sets the level of the object in its parent container (or the stage) - a property for parent.getChildIndex() and parent.setChildIndex()
depth - for ZIM VR - the depth used to shift left and right channel and for parallax in VR - also see dep() ZIM Display method
blendMode - how the object blends with what is underneath - such as "difference", "multiply", etc. same as CreateJS compositeOperation
effects - an object that holds effects added such as blur, glow, shadow, color, multi and alpha - see effect() under ZIM Methods
** the following are convenience Effects that run a ZIM MultiEffect()
** these can use a lot of processing when animating - see Docs for effects()
** batch versions are available too as hueBatch, etc. these will not update the effect until updateEffects() is called on the object
hue - the tint of an object between -180 and 180 with 0 being no change
saturation - the amount of color of an object between -100 and 100 with 0 being no change
brightness - the lightness or darkness of an object between -255 and 255 with 0 being no change
contrast - the crispness of an object between -100 and 100 with 0 being no change
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scale, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+50.5
zim.Container = function(a, b, c, d, style, group, inherit) {
var sig = "a, b, c, d, style, group, inherit";
var duo; if (duo = zob(zim.Container, arguments, sig, this)) return duo;
if (!zim.containerCheck) {
z_d("50.5");
z_d("50.435"); // global dispose too - may not catch dispose in DISTILL check
zim.containerCheck=true;
}
this.cjsContainer_constructor();
this.type = "Container";
this.group = group;
var that = this;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
if (zot(a)) a = DS.a!=null?DS.a:null;
if (zot(b)) b = DS.b!=null?DS.b:null;
if (zot(c)) c = DS.c!=null?DS.c:null;
if (zot(d)) d = DS.d!=null?DS.d:null;
var n = normalizeBounds(a, b, c, d);
function normalizeBounds(a, b, c, d) {
var bounds = [];
if (zot(a)) {
bounds = [a,b,c,d];
} else if (zot(b)) {
bounds = [a.x, a.y, a.width, a.height];
} else if (!zot(c)) {
bounds[0] = a;
bounds[1] = b;
bounds[2] = c;
bounds[3] = d;
} else {
bounds[0] = 0;
bounds[1] = 0;
bounds[2] = a;
bounds[3] = b;
}
if (zot(bounds[3])) bounds[3] = bounds[2];
return bounds;
}
if (!zot(a)) this.setBounds(n[0],n[1],n[2],n[3]); // es6 to fix
this.cache = function(a,b,c,d,scale,options,margin) {
if (this.type=="AC"&&zdf) {zdf.ac("cache", arguments, this); return this;}
var sig = "a,b,c,d,scale,options,margin";
var duo; if (duo = zob(that.cache, arguments, sig)) return duo;
var bounds = that.getBounds();
if (zot(c)) {
if (zot(a)) {
if (!zot(bounds)) {
var added = that.borderWidth > 0 ? that.borderWidth/2 : 0;
a = bounds.x-added;
b = bounds.y-added;
c = bounds.width+added*2;
d = bounds.height+added*2;
}
} else {
c = a;
d = b;
a = 0;
b = 0;
}
}
if (that.type == "Triangle") {
a-=that.borderWidth?that.borderWidth:0;
c+=that.borderWidth?that.borderWidth*2:0;
b-=that.borderWidth?that.borderWidth:0;
d+=that.borderWidth?that.borderWidth*2:0;
}
if (zot(margin)) margin = 0;
that.cjsContainer_cache(a-margin,b-margin,c+margin*2,d+margin*2,scale,options);
if (bounds) that.setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
return that;
};
this.uncache = function() {
that.cjsContainer_uncache();
return that;
};
this.childrenToBitmap = function () {
var cached = this.cacheCanvas;
var pic = new zim.Bitmap(this.cache().cacheCanvas);
if (!cached) this.uncache();
this.removeAllChildren();
pic.addTo(this);
return this;
};
var frame = zdf || 1;
if (createjs && !createjs.stageTransformable && frame.retina) {
this.localToGlobal = function(x,y) {
return zim.localToGlobal(x,y,this,this.cjsContainer_localToGlobal);
};
this.globalToLocal = function(x,y) {
return zim.globalToLocal(x,y,this,this.cjsContainer_globalToLocal);
};
this.localToLocal = function(x,y,target) {
return zim.localToLocal(x,y,target,this);
};
}
this.setBounds = function(a,b,c,d) {
var n = normalizeBounds(a, b, c, d);
this.cjsContainer_setBounds(n[0],n[1],n[2],n[3]);
return this;
};
this.disposeAllChildren = function() {
for (var i=this.numChildren-1; i>=0; i--) {
var child = this.getChildAt(i)
if (child.dispose) child.dispose();
}
return this;
};
zim.displayBase(that);
if (style!==false) zim.styleTransforms(this, DS); // global function - would have put on DisplayObject if had access to it
this.clone = function(exact) {
if (this.type=="AC"&&zdf) {zdf.ac("clone", arguments, this); return this;}
var currentBounds = this.getBounds();
if (zot(currentBounds)) currentBounds = {x:null, y:null, width:null, height:null};
return this.cloneChildren(this.cloneProps(new zim.Container(currentBounds.x,currentBounds.y,currentBounds.width,currentBounds.height, style, this.group, inherit)), exact);
};
this.hasProp = function(prop) {
return (!zot(this[prop]) || this.hasOwnProperty(prop));
};
};
zim.Container.prototype.dispose = function(disposing) {
recursiveDispose(this, disposing);
return true;
};
zim.Container.prototype.specialColor = function(command, co) {
if (co.type=="GradientColor") command.linearGradient(co.colors, co.ratios, co.x0, co.y0, co.x1, co.y1);
else if (co.type=="RadialColor") command.radialGradient(co.colors, co.ratios, co.x0, co.y0, co.r0, co.x1, co.y1, co.r1);
else if (co.type == "BitmapColor") command.bitmap(co.image, co.repetition, co.matrix);
};
function recursiveDispose(obj, disposing) {
// zogr(obj.type)
if (obj) zim.gD(obj); // globalDispose function for common elements
// dispose was fixed in ZIM 10.7.0 in TWO ways:
// ONE
// Some classes have custom dispose - so may want to call these.
// If disposing is true then we are coming from a custom dispose already
// otherwise, call the custom dispose and pass true to say we are already disposing containers
// otherwise the custom dispose will try and call the container dispose and we have an endless loop
if (!disposing && obj && obj.dispose && obj.dispose !== zim.Container.prototype.dispose) {
obj.dispose(null,null,true);
}
// TWO
// dispose was only disposing type=="CONTAINER"
// so should have been type=="Container" - but even that is too narrow
// as would not include components parts or Tile parts, etc.
// so fixed it to include all decendents of Container by testing for addChild
// zog(obj.type)
// if (obj.type == "Container") {
if (obj && obj.addChild) {
obj.dispatchEvent("removed");
obj.removeAllEventListeners();
if (obj.numChildren) {
for (var i=obj.numChildren-1; i>=0; i--) {
recursiveDispose(obj.getChildAt(i));
}
}
}
if (obj && obj.parent) obj.parent.removeChild(obj);
}
zimify(zim.Container.prototype);
zim.extend(zim.Container, createjs.Container, ["cache","uncache","setBounds","clone","localToLocal","localToGlobal","globalToLocal"], "cjsContainer", false);
//-50.5
/*--
zim.Shape = function(a, b, c, d, graphics, optimize, style, group, inherit)
Shape
zim class - extends a createjs.Shape
DESCRIPTION
ZIM Shape lets you draw dynamic shapes beyond the ZIM provided shapes.
You make a new shape object and then draw in its graphics property
using similar commands to the HTML Canvas commands (and Flash Bitmap drawing).
See the CreateJS Easel Shapes and Graphics docs:
http://www.createjs.com/docs/easeljs/classes/Graphics.html
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
NOTE: as of ZIM 10.6.0 the tiny API is available right on the Shape (no need for graphics)
EXAMPLE
var shape = new Shape().addTo();
shape.graphics.beginFill(red).drawRect(0,0,200,100);
// similar to Rectangle(200, 100, "Red");
// or we can use the tiny API (see methods)
// NOTE: these can be chained directly on the Shape object
new Shape().f(red).dr(0,0,200,100).addTo();
// we can draw lines, etc.
var g = shape.graphics; // shorter reference to graphics object
g.beginStroke(blue).moveTo(200,200).lineTo(300,300);
// or we can use the tiny API (see methods)
new Shape().s(blue).ss(5).mt(200,200).lt(300,300).addTo();
// to change a color or stroke after it has been made use command:
var shape = new Shape().addTo();
var strokeColor = shape.s(red).command;
shape.dr(50,50,100,100);
stage.update();
timeout(1, function(){
strokeColor.style = blue;
stage.update();
});
// note - we can draw as much as we want in the same shape
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
** Shape supports three different sets of parameters as follows:
a - (default null) - width and height equal to parameter a (x and y will be 0)
a, b - (default null) - the width and height (x and y will be 0)
a, b, c, d - (default null) - the x, y, width and height of the bounds
graphics - (default null) a CreateJS Graphics instance (see CreateJS docs)
or just use the graphics property of the shape object (like usual)
optimize - (default false) set to true to not store graphics methods directly on Shape
this means the shapes graphics property will need to be used to access f(), s(), ss(), etc.
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
The following shortcuts to CreateJS graphics methods are provided (as long as optimize is false)
See https://www.createjs.com/docs/easeljs/classes/Graphics.html for definitions and parameters
mt() moveTo
lt() lineTo
a() arc
at() arcTo
bt() bezierCurveTo
ct() curveTo
qt() quadraticCurveTo (same as curveTo)
r() rect
cp() closePath
c() clear
f() beginFill
lf() beginLinearGradientFill
rf() beginRadialGradientFill
bf() beginBitmapFill
ef() endFill
ss() setStrokeStyle
sd() setStrokeDash
s() beginStroke
ls() beginLinearGradientStroke
rs() beginRadialGradientStroke
bs() beginBitmapStroke
es() endStroke
dr() drawRect
rr() drawRoundRect
rc() drawRoundRectComplex
dc() drawCircle
de() drawEllipse
dp() drawPolyStar
pg() polygon // added in ZIM CreateJS 1.3.3 (Diamond)
p() decodePath
cache(width||x, height||y, null||width, null||height, scale, options, margin) - overrides CreateJS cache() and returns object for chaining
If you do not provide the first four parameters, then the cache dimensions will be set to the bounds of the object
width||x - (default getBounds().x) the width of the chache - or the x if first four parameters are provided
height||y - (default getBounds().y) the height of the chache - or the y if first four parameters are provided
width - (default getBounds().width) the width of the chache - or null if first two parameters are provided
height - (default getBounds().height) the height of the chache - or null if first two parameters are provided
scale - (default 1) set to 2 to cache with twice the fidelity if later scaling up
options - (default null) additional parameters for cache logic - see CreateJS somewhere for details
margin - (default 0) add or subtract a margin from the bounds
eg. margin:10 will make the cache size 10 pixels more on all sides
this can be handy when caching objects with borders - that go half outside the natural bounds
setBounds(width||x, height||y, null||width, null||height) - overrides CreateJS setBounds() and returns object for chaining
width||x - (default null) the width of the bounds - or the x if four parameters are provided
height||y - (default width) the height of the bounds - or the y if four parameters are provided
width - (default null) the width of the bounds - or null if only the first two parameters are provided
height - (default null) the height of the bounds - or null if only the first two parameters are provided
hasProp(property) - returns true if String property exists on object else returns false
clone(recursive) - makes a copy of the shape
recursive defaults to true so copy will have own copy of graphics
set recursive to false to have clone share graphic property
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), placeReg(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
command - save a previously chained operation as a command
then can use the command to change the operation later (see example above)
group - used when the object is made to add STYLE with the group selector (like a CSS class)
** bounds must be set first (or width and height parameters set) for these to work
** setting these adjusts scale not bounds and getting these uses the bounds dimension times the scale
width - gets or sets the width. Setting the width will scale the height to keep proportion (see widthOnly below)
height - gets or sets the height. Setting the height will scale the width to keep proportion (see heightOnly below)
widthOnly - gets or sets the width. This sets only the width and may change the aspect ratio of the object
heightOnly - gets or sets the height. This sets only the height and may change the aspect ratio of the object
draggable - set to true for a default drag() and false for a noDrag()
level - gets or sets the level of the object in its parent container (or the stage) - a property for parent.getChildIndex() and parent.setChildIndex()
depth - for ZIM VR - the depth used to shift left and right channel and for parallax in VR - also see dep() ZIM Display method
blendMode - how the object blends with what is underneath - such as "difference", "multiply", etc. same as CreateJS compositeOperation
effects - an object that holds effects added such as blur, glow, shadow, color, multi and alpha - see effect() under ZIM Methods
** the following are convenience Effects that run a ZIM MultiEffect()
** these can use a lot of processing when animating - see Docs for effects()
** batch versions are available too as hueBatch, etc. these will not update the effect until updateEffects() is called on the object
hue - the tint of an object between -180 and 180 with 0 being no change
saturation - the amount of color of an object between -100 and 100 with 0 being no change
brightness - the lightness or darkness of an object between -255 and 255 with 0 being no change
contrast - the crispness of an object between -100 and 100 with 0 being no change
ALSO: see the CreateJS Easel Docs for Shape properties, such as:
graphics, x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, mouseEnabled, etc.
EVENTS
See the CreateJS Easel Docs for Shape events, such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+50.6
zim.Shape = function(a, b, c, d, graphics, optimize, style, group, inherit) {
var sig = "a, b, c, d, graphics, optimize, style, group, inherit";
var duo; if (duo = zob(zim.Shape, arguments, sig, this)) return duo;
z_d("50.6");
this.cjsShape_constructor(graphics);
this.type = "Shape";
this.group = group;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
var that = this;
if (zot(a)) a = DS.a!=null?DS.a:null;
if (zot(b)) b = DS.b!=null?DS.b:null;
if (zot(c)) c = DS.c!=null?DS.c:null;
if (zot(d)) d = DS.d!=null?DS.d:null;
if (zot(graphics)) graphics = DS.graphics!=null?DS.graphics:null;
if (zot(optimize)) optimize = DS.optimize!=null?DS.optimize:false;
var n = normalizeBounds(a, b, c, d);
function normalizeBounds(a, b, c, d) {
var bounds = [];
if (!zot(c)) {
bounds[0] = a;
bounds[2] = c;
bounds[1] = b;
bounds[3] = d;
} else {
bounds[0] = 0;
bounds[2] = a;
bounds[1] = 0;
bounds[3] = b;
}
if (zot(bounds[3])) bounds[3] = bounds[2];
return bounds;
}
if (!zot(a)) this.setBounds(n[0],n[1],n[2],n[3]); // es6 to fix
if (!optimize) {
var shorts = ["mt","lt","a","at","bt","ct","qt","cp","c",
"f","lf","rf","bf","ef","ss","sd","s",
"ls","rs","bs","es","dr","rr","rc","dc","de","dp","pg","p"];
for (var i=0; i<shorts.length; i++) {
~function() { // store each in closure to maintain name
var n = i;
that[shorts[n]] = function(){
if (shorts[n]=="ct") that.graphics.curveTo.apply(that.graphics, arguments);
else that.graphics[shorts[n]].apply(that.graphics, arguments);
return that;
};
}();
}
}
Object.defineProperty(that, 'command', {
get: function() {
return that.graphics.command;
},
set: function(value) {
}
});
this.cache = function(a,b,c,d,scale,options,margin) {
var sig = "a,b,c,d,scale,options,margin";
var duo; if (duo = zob(that.cache, arguments, sig)) return duo;
var bounds = that.getBounds();
if (zot(c)) {
if (zot(a)) {
if (!zot(bounds)) {
var added = that.borderWidth > 0 ? that.borderWidth/2 : 0;
a = bounds.x-added;
b = bounds.y-added;
c = bounds.width+added*2;
d = bounds.height+added*2;
}
} else {
c = a;
d = b;
a = 0;
b = 0;
}
}
if (zot(margin)) margin = 0;
that.cjsShape_cache(a-margin,b-margin,c+margin*2,d+margin*2,scale,options);
return that;
};
this.setBounds = function(a,b,c,d) {
var n = normalizeBounds(a, b, c, d);
this.cjsShape_setBounds(n[0],n[1],n[2],n[3]);
return this;
};
if (style!==false) zim.styleTransforms(this, DS); // global function - would have put on DisplayObject if had access to it
this.clone = function(recursive) {
if (zot(recursive)) recursive = true;
var currentBounds = this.getBounds();
if (zot(currentBounds)) currentBounds = {x:null, y:null, width:null, height:null};
var c = that.cloneProps(new zim.Shape(currentBounds.x,currentBounds.y,currentBounds.width,currentBounds.height, graphics, style, group, inherit));
if (recursive) c.graphics = that.graphics.clone();
else c.graphics = that.graphics;
return c;
};
var frame = zdf || 1;
if (createjs && !createjs.stageTransformable && frame.retina) {
this.localToGlobal = function(x,y) {
return zim.localToGlobal(x,y,this,this.cjsShape_localToGlobal);
};
this.globalToLocal = function(x,y) {
return zim.globalToLocal(x,y,this,this.cjsShape_globalToLocal);
};
this.localToLocal = function(x,y,target) {
return zim.localToLocal(x,y,target,this);
};
}
this.hasProp = function(prop) {
return (!zot(this[prop]) || this.hasOwnProperty(prop));
};
// this.pg = function(points, close) {
// if (!Array.isArray(points)) points = Array.from(arguments);
// var type = points[0].x != null?"obj":points[0][0] != null?"arr":"par";
//
// var p, fp, sp;
// if (type=="obj") p = points[0];
// else if (type=="arr") p = {x:points[0][0], y:points[0][1]||0};
// else p = {x:points[0], y:points[1]||0};
// fp = {x:p.x, y:p.y};
// this.mt(fp.x, fp.y);
// for (var i=1; i<points.length; i++) {
// if (type=="obj") p = points[i];
// else if (type=="arr") p = {x:points[i][0], y:points[i][1]||0};
// else p = {x:points[i*2], y:points[i*2+1]||0};
// if (i==1) sp = {x:p.x, y:p.y};
// this.lt(p.x, p.y);
// }
// this.lt(fp.x, fp.y).lt(sp.x, sp.y); // go around to second point to get correct end bevel/miter
// return this;
// }
zim.displayBase(that);
this.dispose = function(a,b,disposing) {
zim.gD(this); // globalDispose function for common elements
this.graphics.c();
this.dispatchEvent("removed");
this.removeAllEventListeners();
if (this.parent) this.parent.removeChild(this);
};
};
zim.extend(zim.Shape, createjs.Shape, ["cache","clone","setBounds","localToLocal","localToGlobal","globalToLocal"], "cjsShape", false);
zimify(zim.Shape.prototype);
//-50.6
/*--
zim.Bitmap = function(image, width, height, left, top, id, style, group, inherit)
Bitmap
zim class - extends a createjs.Bitmap
DESCRIPTION
Makes a Bitmap object from an image source (image, video or canvas).
It is best to use the assets and path parameters of ZIM Frame or the loadAssets() method of Frame
to preload the image and then use the asset() method to access the Bitmap.
See the ZIM Frame class and asset example on the ZIM Frame page of templates.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var frame = new Frame();
frame.on("ready", function() {
var stage = frame.stage;
frame.loadAssets("logo.jpg");
frame.on("complete", function() {
var logo = frame.asset("logo.jpg"); // logo is a Bitmap
logo.center();
stage.update();
});
});
END EXAMPLE
EXAMPLE
// turn a container of circles into a Bitmap
var circles = new Container(stageW, stageH).addTo();
loop(400, function() {
new Circle(rand(10), [pink,green,blue,yellow,purple], dark).center(circles);
});
var pic = new Bitmap(circles).drag();
circles.dispose();
previous to ZIM 10.8.0 we needed to use the cacheCanvas:
var pic = new Bitmap(circles.cache().cacheCanvas).drag();
circles.uncache(); etc.
END EXAMPLE
EXAMPLE
// fill a Bitmap with noise:
var noise = new Noise();
// empty Bitmap size 200, 200
var bmp = new Bitmap(null,200,200).center();
// we fill the bitmap starting from top left going across in the inner loop,
// then down, then across, etc. until we get to bottom right.
var f = 50; // used to make noise bigger or smaller - see the blob comment below
for (var y = 0; y < bmp.height; y++) {
for (var x = 0; x < bmp.width; x++) {
// the noise methods return a number from -1 to 1
// by adding 1 we get a number between 0 and 2 then divide by 2
// and we multiply this by 255 to get a number between 0 and 255
value = (noise.simplex2D(x, y)+1)/2 * 255;
// or get blobs by smoothing and adjusting frequency:
// var value = smoothStep((noise.simplex2D(x/f, y/f)+1)/2, .3,.35) * 255;
// imageData is four values per pixel
// the red, green, blue and alpha
// in one big long array - each value will be constrained to between 0 and 255
// this i value will increase by 4 each time
// then we write the same value for red, green, blue to get a shade of grey
var i = (x + y * bmp.width) * 4;
bmp.imageData.data[i] = value; // red (0-255)
bmp.imageData.data[i + 1] = value; // green (0-255)
bmp.imageData.data[i + 2] = value; // blue (0-255)
bmp.imageData.data[i + 3] = 255; // alpha (0-255)
}
}
bmp.drawImageData();
END EXAMPLE
EXAMPLE
// applying filters
var bitmap = frame.asset("statue.jpg");
bitmap.filters = [new createjs.BlurFilter(25, 25, 1)];
bitmap.cache().center();
END EXAMPLE
EXAMPLE
// getting the color at point(100, 100) on the Bitmap
var bitmap = frame.asset("statue.jpg").cache();
var ctx = bitmap.cacheCanvas.getContext('2d');
var data = ctx.getImageData(100, 100, 1, 1).data;
var color = "rgba("+data.join(", ")+")";
END EXAMPLE
EXAMPLE
// a Base64 image:
var image = "data:image/png;base64,longlistofcharacters";
var logo;
Bitmap.fromData(image, function (bitmap) {
logo = bitmap.center();
stage.update();
});
END EXAMPLE
EXAMPLE
var thumbs = [];
var cols = 5;
var rows = 5;
var image = asset("yourimage.jpg");
var w = image.width/cols;
var h = image.height/cols;
loop(rows, function (r) {
loop(cols, function (c) {
// make Bitmap show a different part of the main image each time
// note: width, height, left, top
// NOT x, y, width, height like Container
// left and top specifiy where in an image
// to start the picture at 0,0 in the Bitmap
thumbs.push(new Bitmap(image, w, h, c*w, r*h));
});
});
var tile = new Tile(thumbs, cols, rows, 0, 0, true).center();
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
image - an HTML image URL (may not load right away - see Frame loadAssets)
or as of 10.8.0 a DisplayObject - this will be turned into a cacheCanvas
and then the DisplayObject turned back to its previous cached setting
width - (default image width or 100) the width of the resulting Bitmap - will potentially crop an image
see also height, left and top parameters
which allow part of an image to be drawn into the Bitmap
and is handy rather than masking to cut up an image into squares for instance
height - (default image height or 100) the height of the resulting Bitmap
left - (default 0) where on the source image to start the left of the image
top - (default 0) where on the source image to start the top of the image
id - an optional id
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
fromData(data, callback) - STATIC method so use the Bitmap class directly: Bitmap.fromData()
The callback will receive a reference to the Bitmap after 50ms or 100ms.
There is no event for making a Bitmap from base64 for instance - so this will have to do.
drawImageData(x, y, sourceX, sourceY, sourceWidth, sourceHeight) - draws the Bitmap's imageData data to the Bitmap
NOTE: This is only used when dynamically drawing a Bitmap with data - not for your normal picture
See the imageData property which should be set before using the drawImageData() method
ZIM calls a putImageData method for the HTML Canvas and then transfers this to the Bitmap
See also https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/putImageData - but let ZIM do the work...
Usually just leave the parameters blank
x - (default 0) where to start putting the drawing in the x
y - (default 0) where to start putting the drawing in the y
sourceX - (default 0) where in the imageData to start using the data in the x
sourceY - (default 0) where in the imageData to start using the data in the y
sourceWidth - (default the width of the imageData) how much width of the data to use
sourceHeight - (default the height of the imageData) how much height of the data to use
cache(width||x, height||y, null||width, null||height, scale, options) - overrides CreateJS cache() and returns object for chaining
** Usually you do not want to cache a Bitmap as it is already a Bitmap ;-)
** But for applying a filter or using a cacheCanvas to get a context, etc. then you might.
If you do not provide the first four parameters, then the cache dimensions will be set to the bounds of the object
width||x - (default getBounds().x) the width of the chache - or the x if first four parameters are provided
height||y - (default getBounds().y) the height of the chache - or the y if first four parameters are provided
width - (default getBounds().width) the width of the chache - or null if first two parameters are provided
height - (default getBounds().height) the height of the chache - or null if first two parameters are provided
scale - (default 1) set to 2 to cache with twice the fidelity if later scaling up
options - (default null) additional parameters for cache logic - see CreateJS somewhere for details
getColorAt(x,y) - returns the rgba() value at the x and y location
hasProp(property as String) - returns true if property exists on object else returns false
clone() - makes a copy with properties such as x, y, etc. also copied
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
if this is a cloned bitmap then the original asset("image.png") will still exist unless it is disposed.
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Bitmap methods, such as:
on(), off(), getBounds(), setBounds(), dispatchEvent(), etc.
PROPERTIES
type - holds the class name as a String
imageData - data for the pixels stored in a data property of an ImageData object
NOTE: This is only used when dynamically drawing a Bitmap with data - not for your normal picture
The data property is an one dimensional Array with consecutive red, green, blue, alpha values (0-255) for each pixels
eg. 0,0,0,255,255,255,255,255 is a black pixel with 1 alpha and a white pixel with 1 alpha
You set this before calling the Bitmap drawImageData() method
See also https://developer.mozilla.org/en-US/docs/Web/API/ImageData - but let ZIM do the work
group - used when the object is made to add STYLE with the group selector (like a CSS class)
** bounds must be set first (or width and height parameters set) for these to work
** setting these adjusts scale not bounds and getting these uses the bounds dimension times the scale
width - gets or sets the width. Setting the width will scale the height to keep proportion (see widthOnly below)
height - gets or sets the height. Setting the height will scale the width to keep proportion (see heightOnly below)
widthOnly - gets or sets the width. This sets only the width and may change the aspect ratio of the object
heightOnly - gets or sets the height. This sets only the height and may change the aspect ratio of the object
draggable - set to true for a default drag() and false for a noDrag()
level - gets or sets the level of the object in its parent container (or the stage) - a property for parent.getChildIndex() and parent.setChildIndex()
depth - for ZIM VR - the depth used to shift left and right channel and for parallax in VR - also see dep() ZIM Display method
blendMode - how the object blends with what is underneath - such as "difference", "multiply", etc. same as CreateJS compositeOperation
effects - an object that holds effects added such as blur, glow, shadow, color, multi and alpha - see effect() under ZIM Methods
** the following are convenience Effects that run a ZIM MultiEffect()
** these can use a lot of processing when animating - see Docs for effects()
** batch versions are available too as hueBatch, etc. these will not update the effect until updateEffects() is called on the object
hue - the tint of an object between -180 and 180 with 0 being no change
saturation - the amount of color of an object between -100 and 100 with 0 being no change
brightness - the lightness or darkness of an object between -255 and 255 with 0 being no change
contrast - the crispness of an object between -100 and 100 with 0 being no change
ALSO: see the CreateJS Easel Docs for Bitmap properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, mouseEnabled, etc.
EVENTS
See the CreateJS Easel Docs for Bitmap events, such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+50.7
zim.Bitmap = function(image, width, height, left, top, id, style, group, inherit) {
var sig = "image, width, height, left, top, id, style, group, inherit";
var duo; if (duo = zob(zim.Bitmap, arguments, sig, this)) return duo;
z_d("50.7");
if (!zot(image)) {
if (image.uncache) { // testing if it has a CreateJS uncache method
var cached = image.cacheCanvas;
var original = image;
image = image.cache().cacheCanvas; // what we will pass to bitmap
}
}
this.cjsBitmap_constructor(image);
if (original && !cached) original.uncache();
var that = this;
this.type = "Bitmap";
this.group = group;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
this.id = that.fileID = DS.id!=null?DS.id:id;
if (zot(width)) width = DS.width!=null?DS.width:image?image.width:100;
if (zot(height)) height = DS.height!=null?DS.height:image?image.height:100;
if (!zot(width) && !zot(height)) that.setBounds(0,0,width,height);
if (zot(left)) left = DS.left!=null?DS.left:0;
if (zot(top)) top = DS.top!=null?DS.top:0;
if (zdf) {
// not supported by IE - thanks Chris Spolton for the find and suggested fix
if (zdf.canvas.getContext("2d")) {
this.imageData = zdf.canvas.getContext("2d").createImageData(width, height);
} else {
this.imageData = document.createElement('canvas').getContext("2d").createImageData(width, height);
// if (ImageData) this.imageData = new ImageData(width, height);
}
this.drawImageData = function(x, y, sourceX, sourceY, sourceWidth, sourceHeight) {
if (zot(x)) x = 0;
if (zot(y)) y = 0;
if (zot(sourceX)) sourceX = 0;
if (zot(sourceY)) sourceY = 0;
if (zot(sourceWidth)) sourceWidth = width;
if (zot(sourceHeight)) sourceHeight = height;
if (!that.proxyCanvas) {
var c = that.proxyCanvas = document.createElement("canvas");
c.setAttribute("width", width);
c.setAttribute("height", height);
that.proxyContext = c.getContext('2d');
image = that.image = c;
}
if (that.proxyContext) {
that.proxyContext.putImageData(that.imageData, x, y, sourceX, sourceY, sourceWidth, sourceHeight);
}
};
if (zot(image)) that.drawImageData();
// handle delay when creating Bitmap from data
if (image.match && image.match(/data:image/i)) setTimeout(function() {
if (that.stage) that.stage.update();
setTimeout(function() {
if (that.stage) that.stage.update();
}, 50);
}, 50);
}
if (image && image.nodeName && image.nodeName.toLowerCase() != "video") that.sourceRect = {x:left, y:top, width:width, height:height};
this.cache = function(a,b,c,d,scale,options) {
if (zot(c)) {
if (zot(a)) {
var bounds = this.getBounds();
if (!zot(bounds)) {
var added = this.borderWidth > 0 ? this.borderWidth/2 : 0;
a = bounds.x-added;
b = bounds.y-added;
c = bounds.width+added*2;
d = bounds.height+added*2;
}
} else {
c = a;
d = b;
a = 0;
b = 0;
}
}
var bounds = this.getBounds();
this.cjsBitmap_cache(a,b,c,d,scale,options);
this.setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
return this;
};
this.clone = function() {
var c = this.cloneProps(new zim.Bitmap(image, width, height, left, top, that.fileID, style, this.group, inherit));
c.cloned = true;
return c;
};
var frame = zdf || 1;
if (createjs && !createjs.stageTransformable && frame.retina) {
this.localToGlobal = function(x,y) {
return zim.localToGlobal(x,y,this,this.cjsBitmap_localToGlobal);
};
this.globalToLocal = function(x,y) {
return zim.globalToLocal(x,y,this,this.cjsBitmap_globalToLocal);
};
this.localToLocal = function(x,y,target) {
return zim.localToLocal(x,y,target,this);
};
}
this.hasProp = function(prop) {
return (!zot(this[prop]) || this.hasOwnProperty(prop));
};
var myContext;
this.getColorAt = function(x,y) {
if (!myContext) {
that.cache();
myContext = that.cacheCanvas.getContext('2d');
that.uncache();
}
var d = myContext.getImageData(x, y, 1, 1).data;
return "rgba("+d[0]+","+d[1]+","+d[2]+","+d[3]+")";
};
zim.displayBase(that);
if (style!==false) zim.styleTransforms(this, DS); // global function - would have put on DisplayObject if had access to it
this.dispose = function(a,b,disposing) {
zim.gD(this); // globalDispose function for common elements
this.dispatchEvent("removed");
this.removeAllEventListeners();
if (!this.cloned) {
if (this.id) {
if (this.stage && this.stage.frame) frame = this.stage.frame;
else frame = zdf;
if (frame && frame.assets) {
if (frame.assets[this.id]) delete frame.assets[this.id];
}
if (zim.assets[this.id]) delete zim.assets[this.id];
}
}
if (this.parent) this.parent.removeChild(this);
};
};
zim.Bitmap.fromData = function(data, callback) {
var width = 100;
var height = 100;
var img = new Image();
img.onload = function() {
width = img.naturalWidth;
height = img.naturalHeight;
if (zot(width)) width = img.width;
if (zot(height)) height = img.height;
var bitmap = new zim.Bitmap(data, width, height);
setTimeout(function() {
callback(bitmap);
}, 50);
}
img.src = data;
};
zim.extend(zim.Bitmap, createjs.Bitmap, ["cache","clone","dispose","localToLocal","localToGlobal","globalToLocal"], "cjsBitmap", false);
zimify(zim.Bitmap.prototype);
//-50.7
/*--
zim.Sprite = function(image, cols, rows, count, offsetX, offsetY, spacingX, spacingY, width, height, animations, json, id, globalControl, spriteSheet, label, frame, style, group, inherit)
Sprite
zim class - extends a createjs.Sprite
DESCRIPTION
A Sprite plays an animation of a spritesheet
which is a set of images layed out in one file.
You play the Sprite with the run() method.
This animates the Sprite over a given time
with various features like playing a labelled animation,
playing animation series,
SEE: https://zimjs.com/spritesheet/index.html
AND: https://zimjs.com/spritesheet/skateboard.html
wait, loop, rewind and call functions.
This actually runs a ZIM animation and animates the frames.
NOTE: A ZIM Sprite handles both an evenly tiled spritesheet - use cols and rows
and an un-evenly tiled spritesheet - use the json parameter.
The json can come from TexturePacker for instance exported for EaselJS/CreateJS
CreateJS Easel Sprite and SpriteSheet docs:
http://www.createjs.com/docs/easeljs/classes/Sprite.html
http://www.createjs.com/docs/easeljs/classes/SpriteSheet.html
You can optionally pass in an existing createjs.SpriteSheet as a parameter.
When you do so, all other parameters are ignored.
NOTE: You can use CreateJS gotoAndPlay(), play(), etc.
but we found the framerate could not be kept
with other animations or Ticker events running.
So we recommend using the ZIM Sprite run() method.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// inside Frame template
// boom.png is a sprite sheet found online
// It has 8 columns and 6 rows that we can visually count
// We can enter a total parameter if it does not end evenly in the grid
// A graphics editor (like Photoshop) could be used to see
// if there is an offset or spacing, etc. and enter those as parameters
// In this case, we do not need to do any of this - just enter the cols and rows
frame.on("complete", function() {
var spriteImage = frame.asset("boom.png");
var animation = new Sprite({
image:spriteImage,
cols:8,
rows:6,
animations:{mid:[10,20], end:[30,40]} // optional animations with labels
// see CreateJS SpriteSheet docs for the various animation format as there are a few different ones!
});
animation.center();
animation.run(2); // plays the frames of the Sprite over 2 seconds (master time)
// OR use the label to play the frames listed in animations parameter
animation.run(1, "mid");
// OR run a series of animations
// by passing an array of label objects to the label parameter
// these each have a time so the master time is ignored
// they can also have any of the run() parameters
// if you provide an array of labels, you cannot rewind the overall animation
animation.run(null, [
{label:"mid", time:1},
{label:"end", time:.5, loop:true, loopCount:5, call:function(){zog("loops done");}},
{startFrame:10, endFrame:20, time:1}
]);
// OR can call a function when done
animation.run(1, "mid", function(){
stage.removeChild(animation);
stage.update();
});
// OR can loop the animation
animation.run({time:2, loop:true}); // see run() parameters for more
});
END EXAMPLE
EXAMPLE
// using Sprite as a texture atlas - or spritesheet of different images
// see: https://zimjs.com/explore/fruit.html
// load in assets and path
var frame = new Frame({assets:["fruit.png", "fruit.json"], path:"assets/"});
frame.on("ready", function() {
new Sprite({json:frame.asset("fruit.json"), label:"apple"}).center();
frame.stage.update();
});
END EXAMPLE
EXAMPLE
// Here is an example with CreateJS SpriteSheet data
// robot.png is a sprite sheet made by ZOE based on a Flash swf
// you can also make your own with Photoshop or Texture Packer
frame.loadAssets("robot.png");
frame.on("complete", function() {
// using ZOE to export swf animation to spritesheet data
// spritesheet data uses the image name, not the Bitmap itself
var image = frame.asset("robot.png").image;
var spriteData = {
"framerate":24,
"images":[image],
"frames":[[0, 0, 256, 256, 0, -54, -10], many more - etc.],
"animations":{}
};
var animation = new Sprite({json:spriteData});
animation.center();
animation.run(2); // note, duration alternative to framerate
});
OR
// load in data from external JSON
frame.loadAssets(["robot.json", "robot.png"]);
// ... same as before
var animation = new Sprite({json:frame.asset("robot.json")});
// ... same as before
// see CreateJS SpriteSheet docs for the format of the JSON file
// including various animation formats
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
image - the ZIM Bitmap for the spritesheet
cols - (default 1) - the columns in the spritesheet
rows - (default 1) the rows in the spritesheet
count - (default cols*rows) how many total frames in the spritesheet
offsetX - (default 0) the pixels from the left edge to the frames
offsetY - (default 0) the pixels from the top edge to the frames
spacingX - (default 0) the horizontal spacing between the frames
spacingY - (default 0) the vertical spacing between the frames
width - (default image width) the width including offset and spacing for frames
height - (default image height) the height including offset and spacing for frames
animations - (default null) an object literal of labels holding frames to play
{label:3, another:[4,10]}
run(1, "label") would play frame 3 for a second
run(1, "another") would play frames 4 to 10 for a second
{unordered:{frames:[1,2,3,22,23,24,"anotherLabel",5,6], next:prevLabel}}
There are also ways to set speeds - but would recommend dividing into simple labels
and using the label series technique available with the run() method
json - (default null) a JSON string for a CreateJS SpriteSheet
If you pass in a json parameter, all other parameters are ignored
NOTE: remember that JSON needs quotes around the animation properties above:
{"label":3, "another":[4,10]}
id - (default randomly assigned) an id you can use in other animations - available as sprite.id
use this id in other animations for pauseRun and stopRun to act on these as well
globalControl - (default true) pauseRun and stopRun will control other animations with same id
spriteSheet - (default null) pass in a CreateJS SpriteSheet to build a Sprite from that
label - (default null) pass in a label to stop on initially - to play from a label use the run({label:val}) method
frame - (default zimDefaultFrame) specify a Frame other than the default frame
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
run(time, label, call, params, wait, waitedCall, waitedParams, loop, loopCount, loopWait, loopCall, loopParams, loopWaitCall, loopWaitParams, loopPick, rewind, rewindWait, rewindCall, rewindParams, rewindWaitCall, rewindWaitParams, rewindTime, rewindEase, startFrame, endFrame, tweek, id, globalControl)
The run() method animates the Sprite over an amount of time
Would recommend this method over the CreateJS play() and gotoAndPlay()
methods because the framerate for these get overwritten by other stage.update() calls
With run() you get other nice ZIM animate features as well as follows:
Returns the object for chaining
Can be paused with pauseAnimate(true) or unpaused with pauseAnimate(false)
Can be stopped with stopAnimate() on the Sprite
supports DUO - parameters or single object with properties below
time (default 1) - the time in seconds to run the animations (the master time)
label (default null) - a label specified in the Sprite animations parameter
if this is an array holding label objects for example:
[{label:"run", time:1}, {label:"stand", time:2}]
then the sprite will play the series with the times given and ignore the master time
Note: if any of the series has a loop and loops forever (a loopCount of 0 or no loopCount)
then this will be the last of the series to run
rewind is not available on the outside series but is available on an inside series
call - (default null) the function to call when the animation is done
params - (default target) a single parameter for the call function (eg. use object literal or array)
wait - (default 0) seconds to wait before doing animation
waitedCall - (default null) call the function after a wait time if there is one
waitedParams - (default null) parameters to pass to the waitedCall function
loop - (default false) set to true to loop animation
loopCount - (default 0) if loop is true how many times it will loop (0 is forever)
loopWait - (default 0) seconds to wait before looping (post animation wait)
loopCall - (default null) calls function after loop and loopWait (not including last loop)
loopParams - (default target) parameters to send loopCall function
loopWaitCall - (default null) calls function after at the start of loopWait
loopWaitParams - (default target) parameters to send loopWaitCall function
rewind - (default false) set to true to rewind (reverse) animation (doubles animation time) (not available on label series)
rewindWait (default 0) seconds to wait in the middle of the rewind
rewindCall (default null) calls function at middle of rewind after rewindWait
rewindParams - (default target) parameters to send rewindCall function
rewindWaitCall (default null) calls function at middle of rewind before rewindWait
rewindWaitParams - (default target) parameters to send rewindCall function
rewindTime - (default time) set to a time in seconds to adjust the time to rewind
rewindEase - (default null) see ease parameter for options for rewind ease
note - this goes backwards - so "bounceOut" would happen at the end of the rewind
startFrame - (default null - or 0) the frame to start on - will be overridden by a label with frames
endFrame - (default null - or totalFrames) the frame to end on - will be overridden by a label with frames
tweek - (default 1) a factor for extra time on rewind and loops if needed
id - (default randomly assigned) an id you can use in other animations - available as sprite.id
use this id in other animations for pauseRun and stopRun to act on these as well
globalControl - (default true) pauseRun and stopRun will control other animations with same id
pauseOnBlur - (default true) pause the sprite when the window is not seen or set to false to keep playing the sprite
pauseRun(state) - pause or unpause the animation (including an animation series)
state - (default true) when true the animation is paused - set to false to unpause
returns object for chaining
stopRun() - stop the sprite from animating
hasProp(property as String) - returns true if property exists on object else returns false
clone() - makes a copy with properties such as x, y, etc. also copied
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Sprite methods, such as:
play(), gotoAndPlay(), gotoAndStop(), stop(), advance(),
on(), off(), getBounds(), setBounds(), dispatchEvent(), etc.
PROPERTIES
type - holds the class name as a String
id - an id that you can use in other animations to also be controlled by pauseRun() and stopRun()
frame - get and set the current frame of the Sprite
normalizedFrame - if animations have CreateJS speeds applied, zim handles these by making extra frames
for example, if a speed is given of .5 then two frames are made (min resulution is .1)
normalizedFrames - an array of total frames after being normalized - really for internal usage
totalFrames - get the total frames of the Sprite - read only
animations - the animations data with labels of frames to animate
running - is the sprite animation being run (includes both paused and unpaused) - read only
runPaused - is the sprite animation paused (also returns paused if not running) - read only
note: this only syncs to pauseRun() and stopRun() not pauseAnimate() and stopAnimate()
note: CreateJS has paused, etc. but use that only if running the CreateJS methods
such as gotoAndPlay(), gotoAndStop(), play(), stop()
draggable - set to true for a default drag() and false for a noDrag()
group - used when the object is made to add STYLE with the group selector (like a CSS class)
** bounds must be set first (or width and height parameters set) for these to work
** setting these adjusts scale not bounds and getting these uses the bounds dimension times the scale
width - gets or sets the width. Setting the width will scale the height to keep proportion (see widthOnly below)
height - gets or sets the height. Setting the height will scale the width to keep proportion (see heightOnly below)
widthOnly - gets or sets the width. This sets only the width and may change the aspect ratio of the object
heightOnly - gets or sets the height. This sets only the height and may change the aspect ratio of the object
draggable - set to true for a default drag() and false for a noDrag()
level - gets or sets the level of the object in its parent container (or the stage) - a property for parent.getChildIndex() and parent.setChildIndex()
depth - for ZIM VR - the depth used to shift left and right channel and for parallax in VR - also see dep() ZIM Display method
blendMode - how the object blends with what is underneath - such as "difference", "multiply", etc. same as CreateJS compositeOperation
effects - an object that holds effects added such as blur, glow, shadow, color, multi and alpha - see effect() under ZIM Methods
** the following are convenience Effects that run a ZIM MultiEffect()
** these can use a lot of processing when animating - see Docs for effects()
** batch versions are available too as hueBatch, etc. these will not update the effect until updateEffects() is called on the object
hue - the tint of an object between -180 and 180 with 0 being no change
saturation - the amount of color of an object between -100 and 100 with 0 being no change
brightness - the lightness or darkness of an object between -255 and 255 with 0 being no change
contrast - the crispness of an object between -100 and 100 with 0 being no change
ALSO: see the CreateJS Easel Docs for Sprite properties, such as:
currentFrame, framerate, paused, currentAnimation, currentAnimationFrame, spriteSheet,
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, mouseEnabled, etc.
EVENTS
See the CreateJS Easel Docs for Sprite events, such as:
animationend, change, added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+50.8
zim.Sprite = function(image, cols, rows, count, offsetX, offsetY, spacingX, spacingY, width, height, animations, json, id, globalControl, spriteSheet, label, frame, style, group, inherit) {
var sig = "image, cols, rows, count, offsetX, offsetY, spacingX, spacingY, width, height, animations, json, id, globalControl, spriteSheet, label, frame, style, group, inherit";
var duo; if (duo = zob(zim.Sprite, arguments, sig, this)) return duo;
z_d("50.8");
this.type = "Sprite";
this.group = group;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
var that = this;
var sheet;
if (zot(frame)) frame = DS.frame!=null?DS.frame:zdf;
if (zot(json) && !zot(image)) {
if (zot(cols)) cols = DS.cols!=null?DS.cols:1;
if (zot(rows)) rows = DS.rows!=null?DS.rows:1;
if (zot(count)) count = DS.count!=null?DS.count:(cols*rows);
if (zot(offsetX)) offsetX = DS.offsetX!=null?DS.offsetX:0;
if (zot(offsetY)) offsetY = DS.offsetY!=null?DS.offsetY:0;
if (zot(spacingX)) spacingX = DS.spacingX!=null?DS.spacingX:0;
if (zot(spacingY)) spacingY = DS.spacingY!=null?DS.spacingY:0;
if (zot(width)) width = DS.width!=null?DS.width:image.width;
if (zot(height)) height = DS.height!=null?DS.height:image.height;
var frameW = (width-offsetX+spacingX) / cols - spacingX;
var frameH = (height-offsetY+spacingY) / rows - spacingY;
var frames = [];
var num = 0;
outer:
for (var j=0; j<rows; j++) {
for (var i=0; i<cols; i++) {
if (++num > count) break outer;
frames.push([
offsetX + i*(frameW+spacingX),
offsetY + j*(frameH+spacingY),
frameW,
frameH
]);
}
}
makeSheet(image, frames, animations);
} else if (spriteSheet) {
sheet = spriteSheet;
animations = sheet.animations;
} else if (json) {
// even though data is in JSON, may want to create SpriteSheet from image
// so that cors will work - so see if provided an image
// or that the images in the JSON are available in frame.assets
frames = json.frames;
animations = json.animations;
if (!zot(image)) {
makeSheet(image, frames, animations);
} else {
var im = json.images?json.images[0]:null;
if (!im || !im.split) {
sheet = new createjs.SpriteSheet(json);
} else {
var assets = [];
zim.loop(json.images, function(im) {
var imEnd = im.split("/").pop();
if (frame.asset(im) && frame.asset(im).type != "EmptyAsset") {
assets.push(frame.asset(im));
} else if (frame.asset(imEnd) && frame.asset(imEnd).type != "EmptyAsset") {
assets.push(frame.asset(imEnd));
} else if (frame.asset(im).type != "EmptyAsset") {
assets.push(frame.asset(im));
} else {
if (zon) zogy("Sprite() - please preload Sprite in Frame or with loadAssets");
}
});
makeSheet(assets, frames, animations);
}
}
} else {
return;
}
function makeSheet(image, frames, animations) {
if (!Array.isArray(image)) image = [image];
zim.loop(image, function(im, i) {
image[i] = im.image;
});
var spriteData = {
images:image,
frames:frames,
animations:animations?animations:[]
};
sheet = new createjs.SpriteSheet(spriteData);
}
this.animations = animations;
this.cjsSprite_constructor(sheet, label);
if (!zot(label)) this.stop();
if (zot(id)) id = zim.makeID();
this.id = id;
if (zot(globalControl)) globalControl = true;
that.globalControl = globalControl;
var _normalizedFrame = 0;
var _normalizedFrames;
this.parseFrames = function(label, startFrame, endFrame, fromDynamo) {
var frames = [];
var minSpeed = Number.MAX_VALUE;
var maxSpeed = 0;
if (zot(label)) {
if (zot(startFrame)) startFrame = 0;
if (zot(endFrame)) endFrame = that.totalFrames-1;
addSequential(startFrame, endFrame);
} else {
if (zot(that.animations) || zot(that.animations[label])) return [];
var a = that.animations[label];
processAnimation(a);
}
function processAnimation(a) {
if (Array.isArray(a)) {
processArray(a);
} else if (a.constructor == {}.constructor) {
processObject(a);
} else if (!isNaN(a)) {
frames.push({f:Math.floor(a), s:1});
}
}
function processArray(a) {
addSequential(a[0], a[1], a[3]);
if (a[2] && !zot(that.animations[a[2]])) processAnimation(that.animations[a[2]]);
}
function processObject(a) {
if (zot(a.frames)) return;
if (zot(a.speed)) a.speed = 1;
for (var i=0; i<a.frames.length; i++) {
if (a.speed < minSpeed) minSpeed = a.speed;
if (a.speed > maxSpeed) maxSpeed = a.speed;
frames.push({f:a.frames[i], s:a.speed});
}
if (a.next && !zot(that.animations[a.next])) processAnimation(that.animations[a.next]);
}
function addSequential(start, end, speed) {
if (zot(speed)) speed = 1;
if (end > start) {
for (var i=start; i<=end; i++) {inner(i);}
} else {
for (var i=end; i<=start; i++) {inner(start-(i-end));}
}
function inner(i) {
if (speed < minSpeed) minSpeed = speed;
if (speed > maxSpeed) maxSpeed = speed;
frames.push({f:i, s:speed});
}
}
if (fromDynamo) return frames;
// run() uses an array of frame numbers (normalized to speed) where dynamo uses the speed
// normalize up to 1/10 - as in if put at .1 then have to multiply all others speeds by 10
minSpeed = zim.constrain(zim.decimals(minSpeed), .1);
maxSpeed = zim.constrain(zim.decimals(maxSpeed), .1);
// normalize speed:
var framesNormalized = [];
var normalize = (minSpeed != maxSpeed);
var fr;
for (var i=0; i<frames.length; i++) {
fr = frames[i];
if (normalize) {
// if minSpeed less than 1 then divide all others by minSpeed otherwise use speed - and need to round to a number that is at least .1
for (var j=0; j<zim.constrain(Math.round(minSpeed<1?fr.s/minSpeed:fr.s), .1); j++) {
framesNormalized.push(fr.f);
}
} else {
framesNormalized.push(fr.f);
}
}
return framesNormalized;
};
this.run = function(time, label, call, params, wait, waitedCall, waitedParams, loop, loopCount, loopWait, loopCall, loopParams, loopWaitCall, loopWaitParams, loopPick, rewind, rewindWait, rewindCall, rewindParams, rewindWaitCall, rewindWaitParams, rewindTime, rewindEase, startFrame, endFrame, tweek, id, globalControl, pauseOnBlur) {
var sig = "time, label, call, params, wait, waitedCall, waitedParams, loop, loopCount, loopWait, loopCall, loopParams, loopWaitCall, loopWaitParams, loopPick, rewind, rewindWait, rewindCall, rewindParams, rewindWaitCall, rewindWaitParams, rewindTime, rewindEase, startFrame, endFrame, tweek, id, globalControl, pauseOnBlur";
var duo; if (duo = zob(this.run, arguments, sig)) return duo;
var timeType = getTIME();
var obj;
var set;
var lookup;
if (zot(tweek)) tweek = 1;
if (!zot(id)) that.id = id;
if (!zot(globalControl)) that.globalControl = globalControl;
if (Array.isArray(label)) {
// check labels
var innerLabel;
var lastLabel;
obj = [];
var extraTime = 0;
var firstStartFrame;
for (var i=0; i<label.length; i++) {
innerLabel = label[i]; // {label:"first", time:1, etc}
innerLabel.lookup = that.parseFrames(innerLabel.label, innerLabel.startFrame, innerLabel.endFrame);
if (i==0) firstStartFrame = innerLabel.lookup[0];
delete innerLabel.startFrame;
delete innerLabel.endFrame;
innerLabel.obj = zim.merge(innerLabel.obj, {normalizedFrame:innerLabel.lookup.length-1});
innerLabel.set = zim.merge(innerLabel.set, {normalizedFrames:{noPick:innerLabel.lookup}, normalizedFrame:0});
// based on previous frames
if (zot(innerLabel.wait)) innerLabel.wait = extraTime*tweek;
lastLabel = innerLabel.label;
delete innerLabel.label;
obj.push(innerLabel);
// will get applied next set of frames
extraTime = 0;
var tt = zot(innerLabel.time)?time:innerLabel.time;
if (endFrame-startFrame > 0) extraTime = tt / (endFrame-startFrame) / 2; // slight cludge - seems to look better?
// if (i==0) firstStartFrame = startFrame;
}
//startFrame = firstStartFrame;
if (obj.length == 0) return this;
if (obj.length == 1) { // just one label in list ;-)
time = obj[0].time;
label = lastLabel;
setSingle();
} else {
that.gotoAndStop(firstStartFrame);
}
} else { // single label
setSingle();
}
function setSingle() {
_normalizedFrames = that.parseFrames(label, startFrame, endFrame);
_normalizedFrame = 0;
that.gotoAndStop(_normalizedFrames[_normalizedFrame]);
startFrame = endFrame = null;
obj = {normalizedFrame:_normalizedFrames.length-1};
}
if (zot(time)) time = timeType=="s"?1:1000;
// if already running the sprite then stop the last run
if (that.running) that.stopAnimate(that.id);
that.running = true;
if (!Array.isArray(obj)) {
var extraTime = 0;
if (endFrame-startFrame > 0) extraTime = time / Math.abs(endFrame-startFrame) / 2; // slight cludge - seems to look better?
if (_normalizedFrames && _normalizedFrames.length>0) extraTime = time / _normalizedFrames.length / 2; // slight cludge - seems to look better?
if (zot(loopWait)) {loopWait = extraTime*tweek;}
if (zot(rewindWait)) {rewindWait = extraTime*tweek;}
}
// locally override call to add running status after animation done
var localCall = function() {
that.running = false;
that.stop();
if (call && typeof call == 'function') call(params||that);
};
zim.animate({
target:that,
obj:obj,
time:time,
ease:"linear",
call:localCall,
params:params,
wait:wait, waitedCall:waitedCall, waitedParams:waitedParams,
loop:loop,
loopCount:loopCount,
loopWait:loopWait,
loopCall:loopCall, loopParams:loopParams,
loopWaitCall:loopWaitCall, loopWaitParams:loopWaitParams,
rewind:rewind, rewindWait:rewindWait, // rewind is ignored by animation series
rewindCall:rewindCall, rewindParams:rewindParams,
rewindWaitCall:rewindWaitCall, rewindWaitParams:rewindWaitParams,
rewindTime:rewindTime, rewindEase:rewindEase,
override:false,
pauseOnBlur:pauseOnBlur,
id:that.id
});
that.runPaused = false;
return that;
};
this.runPaused = true;
this.pauseRun = function(paused) {
if (zot(paused)) paused = true;
that.runPaused = paused;
if (that.globalControl) {
zim.pauseAnimate(paused, that.id);
} else {
that.pauseAnimate(paused, that.id);
}
return that;
};
this.stopRun = function() {
that.runPaused = true;
that.running = false;
if (that.globalControl) {
zim.stopAnimate(that.id);
} else {
that.stopAnimate(that.id);
}
return that;
};
Object.defineProperty(this, 'frame', {
get: function() {
return this.currentFrame;
},
set: function(value) {
value = Math.round(value);
if (this.paused) {
this.gotoAndStop(value);
} else {
this.gotoAndPlay(value);
}
}
});
Object.defineProperty(this, 'normalizedFrame', {
get: function() {
return _normalizedFrame;
},
set: function(value) {
_normalizedFrame = Math.round(value);
this.gotoAndStop(_normalizedFrames[_normalizedFrame]);
}
});
Object.defineProperty(this, 'normalizedFrames', {
get: function() {
return _normalizedFrames;
},
set: function(value) {
_normalizedFrames = value;
}
});
Object.defineProperty(this, 'totalFrames', {
get: function() {
return sheet.getNumFrames();
},
set: function(value) {
zog("zim.Sprite - totalFrames is read only");
}
});
if (style!==false) zim.styleTransforms(this, DS); // global function - would have put on DisplayObject if had access to it
this.clone = function() {
return this.cloneProps(new zim.Sprite(image, cols, rows, count, offsetX, offsetY, spacingX, spacingY, width, height, animations, json, null, globalControl, spriteSheet, label, frame, style, this.group, inherit));
};
var frame = zdf || 1;
if (createjs && !createjs.stageTransformable && frame.retina) {
this.localToGlobal = function(x,y) {
return zim.localToGlobal(x,y,this,this.cjsSprite_localToGlobal);
};
this.globalToLocal = function(x,y) {
return zim.globalToLocal(x,y,this,this.cjsSprite_globalToLocal);
};
this.localToLocal = function(x,y,target) {
return zim.localToLocal(x,y,target,this);
};
}
this.hasProp = function(prop) {
return (!zot(this[prop]) || this.hasOwnProperty(prop));
};
zim.displayBase(that);
this.dispose = function(a,b,disposing) {
zim.gD(this); // globalDispose function for common elements
this.dispatchEvent("removed");
this.removeAllEventListeners();
if (this.parent) this.parent.removeChild(this);
};
};
zim.extend(zim.Sprite, createjs.Sprite, ["clone","localToLocal","localToGlobal","globalToLocal"], "cjsSprite", false);
zimify(zim.Sprite.prototype);
//-50.8
/*--
zim.MovieClip = function(mode, startPosition, loop, labels, style, group, inherit)
MovieClip
zim class - extends a createjs.MovieClip
DESCRIPTION
A MovieClip adds timelines to a Container.
The timelines are animate() zimTween properties.
The zimTween property returns a CreateJS Tween object.
Primarily made to support Adobe Animate MovieClip export.
*Consider this experimental for the moment...
NOTE: to use animate() on a MovieClip, add the MovieClip to a Container and animate() the Container
otherwise the animate() may advance the MovieClip.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var movieClip = new MovieClip();
var circle = new Circle(20, blue).animate({
props:{scale:3}, time:.1, rewind:true, loop:true
});
// Time is in frames NOT in ms - so 100 frames at the Ticker.framerate 60 fps by default is almost 2 seconds
// To change the Ticker's framerate use setFPS(mobile, desktop) method
// If you use one number then both mobile and desktop are set to that fps.
// The defaults are 60 fps mobile (as of ZIM Cat 04) and 60 fps desktop
movieClip.timeline.addTween(circle.zimTween);
movieClip.play();
movieClip.center();
stage.on("stagemousedown", function() {
movieClip.paused = !movieClip.paused;
});
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
// from the CreateJS MovieClip docs: http://www.createjs.com/docs/easeljs/classes/MovieClip.html
mode - (default "independent") or single_frame (based on startPosition) or synched (syncs to parent)
startPosition - (default 0) the start position of the MovieClip (*could not get to work)
loop - (default true) set to false not to loop (*did not seem to loop so use loop:true in zim.animate())
labels - (default null) declare label property with position value
eg. {explode:20} to use with gotoAndPlay("explode") rather than gotoAndPlay(20)
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
hasProp(property as String) - returns true if property exists on object else returns false
clone() - makes a copy with properties such as x, y, etc. also copied
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for MovieClip methods, such as:
play(), gotoAndPlay(), gotoAndStop(), stop(), advance(),
on(), off(), getBounds(), setBounds(), dispatchEvent(), etc.
PROPERTIES
type - holds the class name as a String
draggable - set to true for a default drag() and false for a noDrag()
group - used when the object is made to add STYLE with the group selector (like a CSS class)
** bounds must be set first (or width and height parameters set) for these to work
** setting these adjusts scale not bounds and getting these uses the bounds dimension times the scale
width - gets or sets the width. Setting the width will scale the height to keep proportion (see widthOnly below)
height - gets or sets the height. Setting the height will scale the width to keep proportion (see heightOnly below)
widthOnly - gets or sets the width. This sets only the width and may change the aspect ratio of the object
heightOnly - gets or sets the height. This sets only the height and may change the aspect ratio of the object
draggable - set to true for a default drag() and false for a noDrag()
level - gets or sets the level of the object in its parent container (or the stage) - a property for parent.getChildIndex() and parent.setChildIndex()
depth - for ZIM VR - the depth used to shift left and right channel and for parallax in VR - also see dep() ZIM Display method
blendMode - how the object blends with what is underneath - such as "difference", "multiply", etc. same as CreateJS compositeOperation
effects - an object that holds effects added such as blur, glow, shadow, color, multi and alpha - see effect() under ZIM Methods
** the following are convenience Effects that run a ZIM MultiEffect()
** these can use a lot of processing when animating - see Docs for effects()
** batch versions are available too as hueBatch, etc. these will not update the effect until updateEffects() is called on the object
hue - the tint of an object between -180 and 180 with 0 being no change
saturation - the amount of color of an object between -100 and 100 with 0 being no change
brightness - the lightness or darkness of an object between -255 and 255 with 0 being no change
contrast - the crispness of an object between -100 and 100 with 0 being no change
ALSO: see the CreateJS Easel Docs for MovieClip properties, such as:
currentFrame, totalFrames, currentLabel, duration, framerate, labels, loop, mode, paused, startPosition, timeline,
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, mouseEnabled, parent, etc.
EVENTS
See the CreateJS Easel Docs for MovieClip events, such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+50.9
zim.MovieClip = function(mode, startPosition, loop, labels, style, group, inherit) {
var sig = "mode, startPosition, loop, labels, style, group, inherit";
var duo; if (duo = zob(zim.MovieClip, arguments, sig, this)) return duo;
z_d("50.9");
this.type = "MovieClip";
this.group = group;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
if (zot(mode)) mode = DS.mode!=null?DS.mode:null;
if (zot(startPosition)) startPosition = DS.startPosition!=null?DS.startPosition:null;
if (zot(loop)) loop = DS.loop!=null?DS.loop:null;
if (zot(labels)) labels = DS.labels!=null?DS.labels:null;
this.cjsMovieClip_constructor(mode, startPosition, loop, labels);
if (style!==false) zim.styleTransforms(this, DS); // global function - would have put on DisplayObject if had access to it
this.clone = function() {
return this.cloneProps(new zim.MovieClip(mode, startPosition, loop, labels, style, this.group, inherit));
};
this.hasProp = function(prop) {
return (!zot(this[prop]) || this.hasOwnProperty(prop));
};
var frame = zdf || 1;
if (createjs && !createjs.stageTransformable && frame.retina) {
this.localToGlobal = function(x,y) {
return zim.localToGlobal(x,y,this,this.cjsMovieClip_localToGlobal);
};
this.globalToLocal = function(x,y) {
return zim.globalToLocal(x,y,this,this.cjsMovieClip_globalToLocal);
};
this.localToLocal = function(x,y,target) {
return zim.localToLocal(x,y,target,this);
};
}
zim.displayBase(this);
this.dispose = function(a,b,disposing) {
zim.gD(this); // globalDispose function for common elements
this.dispatchEvent("removed");
this.removeAllEventListeners();
if (this.parent) this.parent.removeChild(this);
};
};
zim.extend(zim.MovieClip, createjs.MovieClip, ["clone","localToLocal","localToGlobal","globalToLocal"], "cjsMovieClip", false);
zimify(zim.MovieClip.prototype);
//-50.9
/*--
zim.SVGContainer = function(svg, splitTypes, geometric, showControls, interactive, style, group, inherit)
SVGContainer
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
Parses SVG and adds items to a ZIM Container.
Items are created as ZIM Shapes: Circle, Rectangle, Blob, Squiggle.
If geometric is true then Circle and Rectangle are used otherwise Blob is used.
Items can be accessed using svgcontainer.getChildAt(0), etc.
See: https://zimjs.com/svg/
See: https://zimjs.com/explore/svgcontainer.html
An SVG path string can be passed directly to a Squiggle or Blob points parameter
and so avoiding the SVGContainer - see ZIM Squiggle and Blob
WARNING: this should be considered experimental
The idea is that paths from SVG can be made editable in ZIM
or animation, dragging, or Label along paths can be accommodated
As such, not all SVG features will work - no CSS, Text, Gradients, DropShadows, etc.
It is possible that these will be added at some point
See also the ZIM svgToBitmap() function under META to get an exact image of the SVG
Thank you https://github.com/colinmeinke/svg-arc-to-cubic-bezier for the Arc conversion
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var svgContainer = new SVGContainer(asset("sample.svg")).addTo();
// OR
var svg = `<svg width="150" height="200" xmlns="h t t p ://www.w3.org/2000/svg">
<path id="lineAB" d="M 0 0 l 150 200" stroke="red" stroke-width="3" fill="none" />
</svg>`;
var svgContainer = new SVGContainer(svg).center();
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
svg - an SVG file loaded into an asset() or SVG text
splitTypes - (default false) - set to true to split different types of paths into separate objects
geometric - (default true) - set to false to load Rectangle and Circle objects as Blob objects
showControls - (default true) set to false to start with controls not showing
interactive - (default true) set to false to turn off controls, move, toggle, select, edit - leaving just the shapes
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
processPath(path) - path is an SVG path string - returns a ZIM Blob or Squiggle points array
hasProp(property as String) - returns true if property exists on object else returns false
clone() - makes a copy with properties such as x, y, etc. also copied
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
svg - a reference to the SVG text
type - holds the class name as a String
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+50.95
zim.SVGContainer = function(svg, splitTypes, geometric, showControls, interactive, style, group, inherit) {
var sig = "svg, splitTypes, geometric, showControls, interactive, style, group, inherit";
var duo; if (duo = zob(zim.SVGContainer, arguments, sig, this)) return duo;
z_d("50.95");
this.group = group;
var DS = style===false?{}:zim.getStyle("SVGContainer", this.group, inherit);
if (svg && svg.type == "Bitmap") svg = svg.svg; // svg is now loaded into a Bitmap automatically in Frame
var that = this;
var startPosition = new zim.Point(0,0); // the x,y of the last shape
var aCommand=[]; //kv adjust logic
var arcToBezier;
function makeArcCode() {
// ~~~~~~~~~~~~~~~~~~~~~~~~
// ES5 Babel port from ES6 https://github.com/colinmeinke/svg-arc-to-cubic-bezier
function _sa(arr, i) { return _ah(arr) || _il(arr, i) || _ua(arr, i) || _ni(); }
function _ni() { throw new TypeError("Invalid"); }
function _ua(o, minLen) { if (!o) return; if (typeof o === "string") return _ala(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _ala(o, minLen); }
function _ala(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _il(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _ah(arr) { if (Array.isArray(arr)) return arr; }
var TAU = Math.PI * 2;
var me = function me(_ref, rx, ry, cosphi, sinphi, centerx, centery) {
var x = _ref.x,
y = _ref.y;
x *= rx;
y *= ry;
var xp = cosphi * x - sinphi * y;
var yp = sinphi * x + cosphi * y;
return {
x: xp + centerx,
y: yp + centery
};
};
var approxUnitArc = function approxUnitArc(ang1, ang2) {
// If 90 degree circular arc, use a constant
// as derived from http://spencermortensen.com/articles/bezier-circle
var a = ang2 === 1.5707963267948966 ? 0.551915024494 : ang2 === -1.5707963267948966 ? -0.551915024494 : 4 / 3 * Math.tan(ang2 / 4);
var x1 = Math.cos(ang1);
var y1 = Math.sin(ang1);
var x2 = Math.cos(ang1 + ang2);
var y2 = Math.sin(ang1 + ang2);
return [{
x: x1 - y1 * a,
y: y1 + x1 * a
}, {
x: x2 + y2 * a,
y: y2 - x2 * a
}, {
x: x2,
y: y2
}];
};
var vectorAngle = function vectorAngle(ux, uy, vx, vy) {
var sign = ux * vy - uy * vx < 0 ? -1 : 1;
var dot = ux * vx + uy * vy;
if (dot > 1) {
dot = 1;
}
if (dot < -1) {
dot = -1;
}
return sign * Math.acos(dot);
};
var getArcCenter = function getArcCenter(px, py, cx, cy, rx, ry, largeArcFlag, sweepFlag, sinphi, cosphi, pxp, pyp) {
var rxsq = Math.pow(rx, 2);
var rysq = Math.pow(ry, 2);
var pxpsq = Math.pow(pxp, 2);
var pypsq = Math.pow(pyp, 2);
var radicant = rxsq * rysq - rxsq * pypsq - rysq * pxpsq;
if (radicant < 0) {
radicant = 0;
}
radicant /= rxsq * pypsq + rysq * pxpsq;
radicant = Math.sqrt(radicant) * (largeArcFlag === sweepFlag ? -1 : 1);
var centerxp = radicant * rx / ry * pyp;
var centeryp = radicant * -ry / rx * pxp;
var centerx = cosphi * centerxp - sinphi * centeryp + (px + cx) / 2;
var centery = sinphi * centerxp + cosphi * centeryp + (py + cy) / 2;
var vx1 = (pxp - centerxp) / rx;
var vy1 = (pyp - centeryp) / ry;
var vx2 = (-pxp - centerxp) / rx;
var vy2 = (-pyp - centeryp) / ry;
var ang1 = vectorAngle(1, 0, vx1, vy1);
var ang2 = vectorAngle(vx1, vy1, vx2, vy2);
if (sweepFlag === 0 && ang2 > 0) {
ang2 -= TAU;
}
if (sweepFlag === 1 && ang2 < 0) {
ang2 += TAU;
}
return [centerx, centery, ang1, ang2];
};
return function arcToBezier(_ref2) {
var px = _ref2.px,
py = _ref2.py,
cx = _ref2.cx,
cy = _ref2.cy,
rx = _ref2.rx,
ry = _ref2.ry,
_ref2$xAxisRotation = _ref2.xAxisRotation,
xAxisRotation = _ref2$xAxisRotation === void 0 ? 0 : _ref2$xAxisRotation,
_ref2$largeArcFlag = _ref2.largeArcFlag,
largeArcFlag = _ref2$largeArcFlag === void 0 ? 0 : _ref2$largeArcFlag,
_ref2$sweepFlag = _ref2.sweepFlag,
sweepFlag = _ref2$sweepFlag === void 0 ? 0 : _ref2$sweepFlag;
var curves = [];
if (rx === 0 || ry === 0) {
return [];
}
var sinphi = Math.sin(xAxisRotation * TAU / 360);
var cosphi = Math.cos(xAxisRotation * TAU / 360);
var pxp = cosphi * (px - cx) / 2 + sinphi * (py - cy) / 2;
var pyp = -sinphi * (px - cx) / 2 + cosphi * (py - cy) / 2;
if (pxp === 0 && pyp === 0) {
return [];
}
rx = Math.abs(rx);
ry = Math.abs(ry);
var lambda = Math.pow(pxp, 2) / Math.pow(rx, 2) + Math.pow(pyp, 2) / Math.pow(ry, 2);
if (lambda > 1) {
rx *= Math.sqrt(lambda);
ry *= Math.sqrt(lambda);
}
var _getArcCenter = getArcCenter(px, py, cx, cy, rx, ry, largeArcFlag, sweepFlag, sinphi, cosphi, pxp, pyp),
_getArcCenter2 = _sa(_getArcCenter, 4),
centerx = _getArcCenter2[0],
centery = _getArcCenter2[1],
ang1 = _getArcCenter2[2],
ang2 = _getArcCenter2[3];
var ratio = Math.abs(ang2) / (TAU / 4);
if (Math.abs(1.0 - ratio) < 0.0000001) {
ratio = 1.0;
}
var segments = Math.max(Math.ceil(ratio), 1);
ang2 /= segments;
for (var i = 0; i < segments; i++) {
curves.push(approxUnitArc(ang1, ang2));
ang1 += ang2;
}
return curves.map(function (curve) {
var _me = me(curve[0], rx, ry, cosphi, sinphi, centerx, centery),
x1 = _me.x,
y1 = _me.y;
var _me2 = me(curve[1], rx, ry, cosphi, sinphi, centerx, centery),
x2 = _me2.x,
y2 = _me2.y;
var _me3 = me(curve[2], rx, ry, cosphi, sinphi, centerx, centery),
x = _me3.x,
y = _me3.y;
return {
x1: x1,
y1: y1,
x2: x2,
y2: y2,
x: x,
y: y
};
});
};
// ~~~~~~~~~~~~~~~~~~~~~~~~
}
if (zot(splitTypes)) splitTypes = false;
if (zot(geometric)) geometric = true;
if (!zot(svg)) {
if (svg.replace) svg = svg.replace(/style\s?=[^"]*"[^"]*"/ig, ""); // 10.9.0 remove style parameters
if (!zot(svg.draggable)) {
var parser = new DOMParser();
var svg = !svg.innerHTML?svg:parser.parseFromString(svg.innerHTML,"text/xml");
var list = svg.getElementsByTagName("svg");
var tag = this.svg = list?svg.getElementsByTagName("svg")[0]:null;
} else {
if (!svg.getAttribute) {
var parser = new DOMParser();
svg = parser.parseFromString(svg, "image/svg+xml").documentElement;
}
var tag = this.svg = svg;
}
var w, h;
if (!zot(tag)){
var w = tag.getAttribute("width");
var h = tag.getAttribute("height");
}
if (w) w = Number(w.trim());
if (h) h = Number(h.trim());
this.zimContainer_constructor(w, h);
this.type = "SVGContainer";
if (zot(tag)) return;
var defaultFill = zim.black, generalFill = zim.black;
var defaultStroke =zim. black, generalStroke = zim.black;
var defaultStrokeSize = 2, generalStrokeSize = 2;
var defaultAlpha = 1, generalAlpha = 1;
var defaultStrokeAlpha = 1, generalStrokeAlpha = 1;
var currentTransform;
function processTag(tag) {
zim.loop(tag, function (t) {
var tn = t.tagName.toLowerCase();
if (tn == "path") processPath(t);
if (tn == "circle") processShape("circle", t);
if (tn == "rect") processShape("rect", t);
if (tn == "ellipse") processShape("ellipse", t);
if (tn == "line") processShape("line", t);
if (tn == "polygon") processShape("polygon", t);
if (tn == "polyline") processShape("polyline", t);
if (tn == "g") {
// styles can be overwritten by parameters in the general tag
// so find styles first
var style = t.getAttribute("style");
var f,s,ss,a,aa;
if (style) {
var styles = processStyle(style);
f = styles[0];
s = styles[1];
ss = styles[2];
a = styles[3];
aa = styles[4];
}
// then overwrite styles with any attribute values
currentTransform = t.getAttribute("transform");
generalFill = t.getAttribute("fill")?t.getAttribute("fill"):!zot(f)?f:defaultFill;
generalStroke = t.getAttribute("stroke")?t.getAttribute("stroke"):!zot(s)?s:defaultStroke;
generalStrokeSize = t.getAttribute("stroke-width")?t.getAttribute("stroke-width"):!zot(ss)?ss:defaultStrokeSize;
generalAlpha = t.getAttribute("fill-opacity")?t.getAttribute("fill-opacity"):!zot(a)?a:defaultAlpha;
generalStrokeAlpha = t.getAttribute("stroke-opacity")?t.getAttribute("stroke-opacity"):!zot(aa)?aa:defaultStrokeAlpha;
}
// general settings can wrap any number of tags - the tags are processed here:
processTag(t.children);
// after this nest of tags are processed, clear the general settings
if (t.tagName.toLowerCase() == "g") {
generalFill = defaultFill;
generalStroke = defaultStroke;
generalStrokeSize = defaultStrokeSize;
generalAlpha = defaultAlpha;
generalStrokeAlpha = defaultStrokeAlpha;
currentTransform = null;
}
});
}
var process = svg.getElementsByTagName("svg");
if (process.length == 0) process = [svg];
function processStyle(style) {
var st = style.split(";"); //kv note: there si bug when style contains ; at the end of the string
var f,s,ss,a,aa;
zim.loop(st, function (sty) {
var sty = sty.replace(/,/g,"");
var styl = sty.split(":");
var prop = styl[0].trim().toLowerCase();
var val = styl[1].trim().toLowerCase().replace("px", "");
if (prop=="fill") f = val;
if (prop=="stroke") s = val;
if (prop=="stroke-width") ss = val;
if (prop=="opacity") a = val, aa = val;
if (prop=="fill-opacity") a = val;
if (prop=="stroke-opacity") aa = val;
});
return [f,s,ss,a,aa];
}
function processShape(type, tag) {
var shape;
var g = processGeneral(tag); // want ES6
var f = g[0], s = g[1], ss = g[2], a = g[3], aa = g[4], x = g[5], y = g[6];
if (type == "circle") {
var r = Number(tag.getAttribute("r").trim());
var d = r*.5523;
if (geometric) shape = new zim.Circle(Number(tag.getAttribute("r")), f, s, ss);
else shape = new zim.Blob(f, s, ss, 4, r, d, "mirror", null, showControls, null, null, null, null, null, null, null, null, null, null, interactive);
} else if (type == "rect") {
if (geometric) shape = new zim.Rectangle(Number(tag.getAttribute("width")), Number(tag.getAttribute("height")), f, s, ss, Number(tag.getAttribute("rx")));
else {
var w = Number(tag.getAttribute("width"));
var h = Number(tag.getAttribute("height"));
var rx = Number(tag.getAttribute("rx"));
var ry = Number(tag.getAttribute("ry"));
if (rx && ry) {
var dx = rx*.5523;
var dy = ry*.5523;
shape = new zim.Blob(f, s, ss, [
[rx,0,0,0,-dx,0,0,0,"free"],[w-rx,0,0,0,0,0,dx,0,"free"],
[w,ry,0,0,0,-dy,0,0,"free"],[w,h-ry,0,0,0,0,0,dy,"free"],
[w-rx,h,0,0,dx,0,0,0,"free"],[rx,h,0,0,0,0,-dx,0,"free"],
[0,h-ry,0,0,0,dy,0,0,"free"],[0,ry,0,0,0,0,0,-dy,"free"]], null, null, null, null, showControls, null, null, null, null, null, null, null, null, null, null, interactive);
} else {
shape = new zim.Blob(f, s, ss, [[0,0],[w,0],[w,h],[0,h]], null, null, null, null, showControls, null, null, null, null, null, null, null, null, null, null, interactive);
}
}
} else if (type == "line") {
shape = new zim.Squiggle(s, ss, [[Number(tag.getAttribute("x1")), Number(tag.getAttribute("y1"))],[Number(tag.getAttribute("x2")), Number(tag.getAttribute("y2"))]], null, null, null, null, showControls, null, null, null, null, null, null, null, null, null, null, interactive);
} else if (type == "polygon" || type == "polyline") {
var p = tag.getAttribute("points");
p = p.replace(/-/g, " -");
p = p.replace(/\s+/g, " ");
var points = [];
if (p.indexOf(",") != -1) {
zim.loop(p.split(" "), function (point) {
var pp = point.split(",");
points.push([Number(pp[0].trim()), Number(pp[1].trim())]);
});
} else {
var lastP;
zim.loop(p.split(" "), function (point, i) {
if ((i+1)%2==0) points.push([lastP, point.trim()]);
lastP = point.trim();
});
}
if (type=="polygon") shape = new Blob(f, s, ss, points);
else shape = new zim.Squiggle(s, ss, points, null, null, null, null, showControls, null, null, null, null, null, null, null, null, null, null, interactive);
} else if (type == "ellipse") {
shape = new zim.Blob(f, s, ss, ellipse(0, 0, Number(tag.getAttribute("rx")), Number(tag.getAttribute("ry"))), null, null, null, null, showControls, null, null, null, null, null, null, null, null, null, null, interactive);
}
shape.loc(x,y,that);
var transform = tag.getAttribute("transform");
if (transform || currentTransform) processTransform(shape, transform || currentTransform);
if (interactive && (shape.type == "Rectangle" || shape.type=="Circle")) shape.transform({showReg:false, visible:showControls});
}
function processTransform(shape, transform) {
var tr = transform.split(")");
// apply all transforms in the order given
zim.loop(tr, function (tra) {
if (tra=="") return;
var tran = tra.trim().split("(");
var prop = tran[0].trim().toLowerCase();
var val = tran[1].trim().toLowerCase().replace("px", "").replace("deg", "");
if (prop=="translate") {
var m = val.split(",");
shape.mov(Number(m[0].trim()), m[1]?Number(m[1].trim()):0);
}
if (prop=="scale"){
var s = val.split(",");
if (shape.type=="Blob" || shape.type=="Squiggle") {
if (s.length == 1) shape.transformPoints("scale", Number(s[0].trim()));
else if (s.length == 2) {
shape.transformPoints("scaleX", Number(s[0].trim()));
shape.transformPoints("scaleY", Number(s[1].trim()));
}
} else {
if (s.length == 1) shape.sca(Number(s[0].trim()));
else if (s.length == 2) {
shape.sca(Number(s[0].trim()), Number(s[1].trim()));
}
}
}
if (prop=="rotate") {
var r = val.split(",");
// if (shape.type=="Blob" || shape.type=="Squiggle") {
// rotation is a different way for SVG and transform() - too bad
// it rotates around 0,0 unless a different point is chosen
// so shape.transformPoints which is a registration point system
// is unlikely to work - and too complex to add rotate around a given point
// so we will use zim rot() to which we have added rotating around a different point
// but this will rotate the little box handles
// maybe look into keeping those parallel in the blob and squiggle - no matter what the rotation
// if (r.length == 1) shape.transformPoints("rotation", Number(r[0].trim()))
if (r.length == 1) r.push(0,0);
else if (r.length == 2) r.push(0);
shape.rot(Number(r[0].trim()), Number(r[1].trim()), Number(r[2].trim()));
}
if (prop=="skewX") shape.skewX = val;
if (prop=="skewY") shape.skewY = val;
});
}
// beatgammit on StackOverflow
function ellipse(x, y, xDis, yDis) {
var kappa = 0.5522848, // 4 * ((√(2) - 1) / 3)
ox = xDis * kappa, // control point offset horizontal
oy = yDis * kappa, // control point offset vertical
xe = x + xDis, // x-end
ye = y + yDis; // y-end
var points = [ // modified by Dan Zen to relative
[x - xDis, y, 0, 0, x, ye+oy-yDis, x, y-oy, "mirror"],
[x, y - yDis, 0, 0, x-ox, y, xe+ox-xDis, y, "mirror"],
[xe, y, 0, 0, x, y-oy, x + ox-ox, ye+oy-yDis, "mirror"],
[x, ye, 0, 0, xe-xDis+ox, y, x-ox, y, "mirror"]
];
return points;
}
processTag(process);
}
function processGeneral(tag) {
// any styles on the tag overwrites general styles or attributes
var f,s,ss,a,aa;
var style = tag.getAttribute("style");
if (style) {
var styles = processStyle(style);
f = styles[0];
s = styles[1];
ss = styles[2];
a = styles[3];
aa = styles[4];
}
// kv comments: need to apply string cleansing, application bugs when there is a semi colon character used in tags.
// get rid of semi colon,
// any attributes on the tag overwrites styles or general
f = tag.getAttribute("fill")?tag.getAttribute("fill"):!zot(f)?f:generalFill;
s = tag.getAttribute("stroke")?tag.getAttribute("stroke"):!zot(s)?s:generalStroke;
ss = tag.getAttribute("stroke-width")?tag.getAttribute("stroke-width"):!zot(ss)?ss:generalStrokeSize;
a = tag.getAttribute("fill-opacity")?tag.getAttribute("fill-opacity"):!zot(a)?a:generalAlpha;
aa = tag.getAttribute("stroke-opacity")?tag.getAttribute("stroke-opacity"):!zot(aa)?aa:generalStrokeAlpha;
var x = tag.getAttribute("x")?tag.getAttribute("x"):0;
x = tag.getAttribute("cx")?tag.getAttribute("cx"):x;
var y = tag.getAttribute("y")?tag.getAttribute("y"):0;
y = tag.getAttribute("cy")?tag.getAttribute("cy"):y;
if (!zot(a) && !zot(f)) f = zim.convertColor(f, "rgba", Number(a));
if (!zot(aa) && !zot(s)) s = zim.convertColor(s, "rgba", Number(aa));
return [f,s,Number(ss),Number(a),Number(aa),Number(x),Number(y)];
}
function processPath (path, make) {
if (zot(make)) make = true;
var commands = ["M","m","L","l","H","h","V","v","C","c","S","s","Q","q","T","t","A","a","z","Z"];
var commandsRelative = ["m","l","h","v","c","s","q","t","a","z"];
var position = new zim.Point(0,0); // the current position - relative places based on this
if (zot(path.getAttribute)) {
var d = path;
} else {
var id = path.getAttribute("id");
var d = path.getAttribute("d");
}
// m251.85 119.04c7.85 10.45-9.81
d = d.replace(/,/g ," ");
d = d.replace(/([a-zA-Z])/g, " $1 ");
d = d.replace(/-/g, " -");
d = d.replace(/\s+/g, " ");
// can also bump decimal numbers together if one decimal place in first - sigh... Cat 01
// 10.93.12 is really 10.93 .12
d = d.replace(/\.(\d*)\./g, ".$1 .");
if (make) {
var g = processGeneral(path); // want ES6
var f = g[0]; var s = g[1]; var ss = g[2]; var a = g[3]; var aa = g[4];
}
var shape; //kv adjust logic
var aNumber; //kv adjust logic
//var points = [[0,0]]; //kv adjust logic
var points = []; //kv adjust logic
var lastTempPoint = [0,0]; //kv adjust logic
var line = new zim.Point(0,0);
var quad = new zim.Point(0,0,0,0);
var cube = new zim.Point(0,0,0,0,0,0);
var arc = new zim.Point(0,0,0,0,0,0,0);
//kv var data = d.split(" "); //kv adjust logic
var dataOrigin = d.split(" "); //kv adjust logic
var data = dataOrigin.slice(1,dataOrigin.length); //kv adjust logic
var aCommand = []; //kv adjust logic
var missingCommand = false; //not used yet //kv adjust logic
var lastCommand = ""; //kv adjust label
var previousCommand = ""; //not used yet //kv adjust logic
var adding = false;
var what;
var type = "squiggle";
var dataType = null;
//kv loop(data, function (command) { //kv adjust logic
zim.loop(data, function (command, i) { //kv adjust logic
if (i==0) {
startPosition.x = 0;
startPosition.y = 0;
lastTempPoint = [0,0];
lastCommand = "";
previousCommand = "";
}
if (commands.indexOf(command) == -1) {
if (what == "lxo") {what="lx"; aCommand.push("l");missingCommand=true;} //kv adjust logic
if (what == "lyo") {what="ly"; missingCommand=true;} //kv adjust logic
if (what == "Lxo") {what="Lx"; aCommand.push("L");missingCommand=true;} //kv adjust logic
if (what == "Lyo") {what="Ly"; missingCommand=true;} //kv adjust logic
aNumber = Number(command); //kv adjust logic
aNumber = Math.round(aNumber * 100) / 100; //kv adjust logic
// position
if (what == "X") {
startPosition.x = aNumber;
what = "Y";
} else if (what == "Y") {
startPosition.y = aNumber;
//kv what = "Lx"; // in case no letters come next //kv adjust logic
what = "Lxo"; // in case no letters come next //kv adjust logic
points.push([startPosition.x, startPosition.y]); //kv adjust logic
// what = null;
} else if (what == "x") {
//if (points.length > 1) {
// startPosition.x = points[points.length-1][0]; //kv adjust logic
// startPosition.y = points[points.length-1][1] //kv adjust logic
//} else {
// startPosition.x = lastTempPoint[0]; //kv adjust logic
// startPosition.y = lastTempPoint[1] //kv adjust logic
//};
startPosition.x = startPosition.x+aNumber;
what = "y";
} else if (what == "y") {
startPosition.y = startPosition.y+aNumber;
what = "lxo"; //kv adjust logic
//kv what = "lx"; // in case no letters come next //kv adjust logic
points.push([startPosition.x, startPosition.y]); //kv adjust logic
// what = null;
}
// left, right, top or bottom
if (what == "H" || what == "h") {
position.x = points[points.length-1][0]; //kv adjust logic
position.y = points[points.length-1][1]; //kv adjust logic
position.x = position.x + (what=="h"?aNumber:aNumber-startPosition.x);
points.push([position.x, position.y]);
what = "Lx";
} else if (what == "V" || what == "v") {
position.x = points[points.length-1][0]; //kv adjust logic
position.y = points[points.length-1][1]; //kv adjust logic
position.y = position.y + (what=="v"?aNumber:aNumber-startPosition.y);
points.push([position.x, position.y]);
what = "lx";
}
// line
if (what == "Lx") {
//kv line.x = aNumber-startPosition.x; //kv adjust logic
line.x = aNumber; //kv adjust logic
what = "Ly";
} else if (what == "Ly") {
//kv line.y = aNumber-startPosition.y; //kv adjust logic
line.y = aNumber; //kv adjust logic
position.x = line.x;
position.y = line.y;
points.push([position.x, position.y]);
what = "Lx";
} else if (what == "lx") {
if (aCommand.length > 0) { //kv adjust logic
if (position.x != 0 && position.y != 0 ) {
startPosition.x = position.x;
startPosition.y = position.y;
}
else {
startPosition.x = position.x + startPosition.x; //kv adjust logic
startPosition.y = position.y + startPosition.y; //kv adjust logic
//startPosition.x = position.x + lastTempPoint[0]; //kv adjust logic
//startPosition.y = position.y + lastTempPoint[1]; //kv adjust logic
}
} //kv adjust logic
line.x = startPosition.x + aNumber; //kv adjust logic
//kv line.x = line.x + aNumber; //kv adjust logic
if (missingCommand) {what="lyo";} else //kv adjust logic
what = "ly";
} else if (what == "ly") {
line.y = startPosition.y + aNumber; //kv adjust logic
//line.y = line.y + aNumber; //kv adjust logic
position.x = line.x;
position.y = line.y;
points.push([position.x, position.y]);
what = "lx";
}
// Quadratic
if (what == "qx" || what == "Qx") {
if (points.length > 0) { //kv adjust logic
startPosition.x = points[points.length-1][0]; //kv adjust logic
startPosition.y = points[points.length-1][1]; //kv adjust logic
} else { //kv adjust logic
startPosition.x = 0; //kv adjust logic
startPosition.y = 0; //kv adjust logic
} //kv adjust logic
//kv quad.x = what=="qx"?position.x+aNumber:aNumber-startPosition.x;
quad.x = what=="qx"?startPosition.x+aNumber:aNumber; //kv adjust logic
what = what=="qx"?"qy":"Qy";
} else if (what == "qy" || what == "Qy") {
//kv quad.y = what=="qy"?position.y+aNumber:aNumber-startPosition.y;
quad.y = what=="qy"?startPosition.y+aNumber:aNumber; //kv adjust logic
what = what=="qy"?"qz":"Qz";
if (adding) {
adding = false;
var lastPoint = points[points.length-1];
lastPoint[6] = -lastPoint[4];
lastPoint[7] = -lastPoint[5];
lastPoint[8] = "mirror";
position.x = quad.x;
position.y = quad.y;
points[points.length] = [
position.x, position.y,
0, 0,
-lastPoint[6], lastPoint[7],
0,0,
"free"
];
what = what=="qy"?"qx":"Qx";
}
} else if (what == "qz" || what == "Qz") {
//kv quad.z = what=="qz"?position.x+aNumber:aNumber-startPosition.x;
quad.z = what=="qz"?startPosition.x+aNumber:aNumber; //kv adjust logic
what = what=="qz"?"qq":"Qq";
} else if (what == "qq" || what == "Qq") {
//kv quad.w = what=="qq"?position.y+aNumber:aNumber-startPosition.y;
quad.w = what=="qq"?startPosition.y+aNumber:aNumber; //kv adjust logic
var lastPoint = points[points.length-1];
position.x = lastPoint[0]; //kv adjust logic
position.y = lastPoint[1]; //kv adjust logic
if (points.length == 1) { //kv adust logic
lastPoint[2] = 0; lastPoint[3] = 0; lastPoint[4] = 0; lastPoint[5] = 0; //kv adjust logic //kv debug
lastPoint[6] = 2/3 *(quad.x - position.x); // relative needs position and absolute does not it
lastPoint[7] = 2/3 *(quad.y - position.y);
lastPoint[8] = "free";
} //kv adjust logic
else { //kv adjust logic
points[points.length] = [ //kv adjust logic
position.x, position.y, //kv adjsut logic
0, 0, 0, 0, //kv adjust logic
2/3*(quad.x-position.x), //kv adjust logic
2/3*(quad.y-position.y), //kv adjust logic
"free" //kv adjust logic
]; //kv adjust logic
} //kv adjust logic
position.x = quad.z; // assign this point's position - fix this and apply throughout...
position.y = quad.w;
points[points.length] = [
position.x, position.y,
0, 0,
// relative needs - startPosition and absolute does not
2/3*(quad.x-position.x), 2/3*(quad.y-position.y),
0,0,
"free"
];
what = what=="qq"?"qx":"Qx";
}
// Cubic
if (what == "cx" || what == "Cx") {
if (points.length > 0) { //kv adjust logic
startPosition.x = points[points.length-1][0]; //kv adjust logic
startPosition.y = points[points.length-1][1]; //kv adjust logic
} else { //kv adjust logic
startPosition.x = 0; //kv adjust logic
startPosition.y = 0; //kv adjust logic
} //kv adjust logic
//kv cube.x = what=="cx"?position.x+aNumber:aNumber-startPosition.x;
cube.x = what=="cx"?startPosition.x+aNumber:aNumber; //kv adjust logic
what = what=="cx"?"cy":"Cy";
} else if (what == "cy" || what == "Cy") { // y Control Point 1
//kv cube.y = what=="cy"?position.y+aNumber:aNumber-startPosition.y;
cube.y = what=="cy"?startPosition.y+aNumber:aNumber; //kv adjust logic
what = what=="cy"?"cz":"Cz";
} else if (what == "cz" || what == "Cz") { // x Control Point 2
//kv cube.z = what=="cz"?position.x+aNumber:aNumber-startPosition.x;
cube.z = what=="cz"?startPosition.x+aNumber:aNumber; //kv adjust logic
what = what=="cz"?"cq":"Cq";
} else if (what == "cq" || what == "Cq") { // y Control Point 2
//kv cube.q = what=="cq"?position.y+aNumber:aNumber-startPosition.y;
cube.q = what=="cq"?startPosition.y+aNumber:aNumber; //kv adjust logic
what = what=="cq"?"cr":"Cr";
if (adding) {
if (lastCommand=="s") {previousCommand = "s";} else {previousCommand = "S";}
//kv adding = false;
//kv update previous point
var lastPoint = points[points.length-1];
lastPoint[2] = 0; //kv adjust logic
lastPoint[3] = 0; //kv adjust logic
if(zot(lastPoint[4])) {lastPoint[4] =0;} //kv adjust logic
if(zot(lastPoint[5])) {lastPoint[5] =0;} //kv adjust logic
lastPoint[6] = -lastPoint[4];
lastPoint[7] = -lastPoint[5];
// lastPoint[6] = - (cube.x-cube.z); //kv adjust logic
// lastPoint[7] = - (cube.y-cube.q); //kv adjust logic
lastPoint[8] = "mirror";
//kv create very lastPoint
position.x = cube.z;
position.y = cube.q;
points[points.length] = [
position.x, position.y,
0, 0,
cube.x-position.x, cube.y-position.y,
0,0,
"free"
];
//kv what = what=="cq"?"cx":"Cx";
what = what=="cr"?"cx":"Cx"; //kv adjust logic
}
} else if (what == "cr" || what == "Cr") {
//kv cube.r = what=="cr"?position.x+aNumber:aNumber-startPosition.x;
cube.r = what=="cr"?startPosition.x+aNumber:aNumber; //kv adjust logic
what = what=="cr"?"cs":"Cs";
} else if (what == "cs" || what == "Cs") { // y 2nd Point
//kv cube.s = what=="cs"?position.y+aNumber:aNumber-startPosition.y;
cube.s = what=="cs"?startPosition.y+aNumber:aNumber; //kv adjust logic
//points.push([cube.r, cube.s]); //kv adjust logic
//[controlX, controlY, circleX, circleY, rect1X, rect1Y, rect2X, rect2Y, controlType], //kv debug
var lastPoint = points[points.length-1];
if (points.length == 1) {lastPoint[2] = 0; lastPoint[3] = 0; lastPoint[4] = 0; lastPoint[5] = 0;} //kv adjust logic
lastPoint[6] = cube.x-lastPoint[0];
lastPoint[7] = cube.y-lastPoint[1];
lastPoint[8] = "free";
position.x = cube.r;
position.y = cube.s;
points[points.length] = [
position.x, position.y,
0, 0,
cube.z-position.x, cube.q-position.y,
0,0,
"free"
];
what = what=="cs"?"cx":"Cx";
// Arc
// https://github.com/colinmeinke/svg-arc-to-cubic-bezier/issues/7
// rx ry x-axis-rotation large-arc-flag sweep-flag x y
} else if (what == "ax" || what == "Ax") {
if (points.length > 0) {
startPosition.x = points[points.length-1][0];
startPosition.y = points[points.length-1][1];
} else {
startPosition.x = 0;
startPosition.y = 0;
}
arc.x = aNumber; // radius x
what = what=="ax"?"ay":"Ay";
} else if (what == "ay" || what == "Ay") {
arc.y = aNumber; // radius y
what = what=="ay"?"az":"Az";
} else if (what == "az" || what == "Az") {
arc.z = aNumber; // x-axis-rotation
what = what=="az"?"aq":"Aq";
} else if (what == "aq" || what == "Aq") {
arc.q = aNumber; // large-arc-flag
what = what=="aq"?"ar":"Ar";
} else if (what == "ar" || what == "Ar") {
arc.r = aNumber; // sweep-flag
what = what=="ar"?"as":"As";
} else if (what == "as" || what == "As") {
arc.s = what=="as"?startPosition.x+aNumber:aNumber;
what = what=="as"?"at":"At";
} else if (what == "at" || what == "At") {
arc.t = what=="at"?startPosition.y+aNumber:aNumber;
// rx ry x-axis-rotation large-arc-flag sweep-flag x y
if (!arcToBezier) arcToBezier = makeArcCode();
var curves = arcToBezier({
px: startPosition.x,
py: startPosition.y,
cx: arc.s,
cy: arc.t,
rx: arc.x,
ry: arc.y,
xAxisRotation: arc.z,
largeArcFlag: arc.q,
sweepFlag: arc.r,
});
loop(curves, function (curve, ii) {
lastPoint = points[points.length-1];
if (points.length == 1) {lastPoint[2] = 0; lastPoint[3] = 0; lastPoint[4] = 0; lastPoint[5] = 0;} //kv adjust logic
if (ii==0 && points.length == 1) {
lastPoint[6] = curve.x1-position.x-startPosition.x;
lastPoint[7] = curve.y1-position.y-startPosition.y;
} else {
lastPoint[6] = curve.x1-position.x;
lastPoint[7] = curve.y1-position.y;
}
lastPoint[8] = "free";
position.x = curve.x;
position.y = curve.y;
points[points.length] = [
position.x, position.y,
0, 0,
curve.x2-position.x, curve.y2-position.y,
0,0,
"free"
];
});
what = what=="at"?"ax":"Ax";
}
}
else {
aCommand.push(command); // kv adjust logic
// Commands
if (command != "s") {
adding = false;
} // kv adjust logic
if (aCommand.length > 1) { // kv adjust logic
// if (aCommand[aCommand.length-2] != command) {
if (command=="M" || command=="m") {
makeShape(aCommand);
if (command=="M") {startPosition.x = 0; startPosition.y=0;}
else {
startPosition.x = points[points.length-1][0]; startPosition.y=points[points.length-1][1];
}
points = [];
aCommand = [];
aCommand.push(command);
}
} // kv adjust logic
if (command=="M") {
what = "X";
} else if (command=="m") {
what = "x";
} else if (command=="L") {
what = "Lx";
if (splitTypes && dataType && (dataType != "l")) makeShape(aCommand);
dataType = "l";
} else if (command=="l") {
what = "lx";
if (splitTypes && dataType && (dataType != "l")) makeShape(aCommand);
dataType = "l";
} else if (command=="H") {
what = "H";
if (splitTypes && dataType && (dataType != "l")) makeShape(aCommand);
dataType = "l";
} else if (command=="h") {
what = "h";
if (splitTypes && dataType && (dataType != "l")) makeShape(aCommand);
dataType = "l";
} else if (command=="V") {
what = "V";
if (splitTypes && dataType && (dataType != "l")) makeShape(aCommand);
dataType = "l";
} else if (command=="v") {
what = "v";
if (splitTypes && dataType && (dataType != "l")) makeShape(aCommand);
dataType = "l";
} else if (command=="C") {
what = "Cx";
if (splitTypes && dataType && (dataType != "c")) makeShape(aCommand);
dataType = "c";
} else if (command=="c") {
what = "cx";
if (splitTypes && dataType && (dataType != "c")) makeShape(aCommand);
dataType = "c";
} else if (command=="S") {
adding = true;
what = "Cx";
if (splitTypes && dataType && (dataType != "c")) makeShape(aCommand);
dataType = "c";
} else if (command=="s") {
adding = true;
what = "cx";
if (splitTypes && dataType && (dataType != "c")) makeShape(aCommand);
dataType = "c";
} else if (command=="Q") {
what = "Qx";
if (splitTypes && dataType && (dataType != "q")) makeShape(aCommand);
dataType = "q";
} else if (command=="q") {
what = "qx";
if (splitTypes && dataType && (dataType != "q")) makeShape(aCommand);
dataType = "q";
} else if (command=="T") {
adding = true;
what = "Qx";
if (splitTypes && dataType && (dataType != "q")) makeShape(aCommand);
dataType = "q";
} else if (command=="t") {
adding = true;
what = "qx";
if (splitTypes && dataType && (dataType != "q")) makeShape(aCommand);
dataType = "q";
} else if (command=="A") {
// type = null;
what = "Ax";
if (splitTypes && dataType && (dataType != "a")) makeShape();
dataType = "a";
} else if (command=="a") {
what = "ax";
if (splitTypes && dataType && (dataType != "a")) makeShape();
dataType = "a";
} else if (command=="z" || command=="Z") {
type = "blob";
}
} // end of Command process
}); // end of data loop
function makeShape(myCommand, interest) {
var myCommand;
//var shape; //kv adjust logic
lastCommand = aCommand[aCommand.length-1]; //kv adjust logic
if (points.length >= 2)
// M 100 350 l 150 -300
if (lastCommand == "z" || lastCommand == "Z") {type = "blob";} //kv adjust logic
//if (zot(shape)) { //kv adjust logic
if (type == "squiggle") shape = new zim.Squiggle(s, ss, points, null, null, null, null, showControls, null, null, null, null, null, null, null, null, null, null, interactive);
else shape = new zim.Blob(f, s, ss, points, null, null, null, null, showControls, null, null, null, null, null, null, null, null, null, null, interactive);
shape.loc(0,0,that); //kv adjust logic
//} else { //kv adjust logic
// var dataPointsArray = []; //kv adjust logic
// dataPointsArray = shape.recordPoints().concat(points); //kv adjust logic
// //shape.removeFrom(); //kv adjust logic
// if (type == "squiggle") shape = new Squiggle(s, ss, dataPointsArray) //kv adjust logic
// else shape = new Blob(f, s, ss, dataPointsArray) //kv adjust logic
//};
//kv shape.loc(startPosition.x, startPosition.y, that); //kv adjust logic
//kv startPosition.x = startPosition.x + position.x; //kv adjust logic
//kv startPosition.y = startPosition.y + position.y; //kv adjust logic
lastCommand = aCommand[aCommand.length-1]; //kv adjust logic
previousCommand = aCommand[aCommand.length-2]; //kv adjust logic
if (commandsRelative.indexOf(lastCommand) >= 0) {
//if (aCommand[aCommand.length-1] == "m") { //kv adjust logic
lastTempPoint[0] = points[points.length-1][0]; lastTempPoint[1] = points[points.length-1][1]; //kv adjust logic
startPosition.x = points[points.length-1][0]; startPosition.y = points[points.length-1][1]; //kv adjust logic
points = []; // LATEST CHANGES
points.push([lastTempPoint[0], lastTempPoint[1]]); //kv adjust logic
} else {lastTempPoint = [0,0]; points = [[0,0]];}
aCommand = []; //kv adjust logic
if (lastCommand != "z" && lastCommand != "Z") aCommand.push(lastCommand); //kv adjust logic
position.x = 0;
position.y = 0;
//kv points = [[0,0]];
var transform = path.getAttribute("transform");
if (transform || currentTransform) processTransform(shape, transform || currentTransform);
}
if (make) makeShape();
return points;
} // end process path
that.processPath = function(path) {
return processPath(path,false);
};
if (style!==false) zim.styleTransforms(this, DS); // global function - would have put on DisplayObject if had access to it
this.clone = function() {
return that.cloneProps(new zim.SVGContainer(svg, splitTypes, geometric, showControls, interactive, style, this.group, inherit));
};
};
zim.extend (zim.SVGContainer, zim.Container, "clone", "zimContainer", false);
//-50.95
// SUBSECTION ZIM SHAPES
/*--
zim.CustomShape = function(x, y, w, h)
CustomShape
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
Used internally to make ZIM Shapes - Circle, Rectangle, Triangle, etc.
Holds the following properties in common:
color, colorRange, borderColor, borderWidth, thickness, dashed, dashedOffset, corner
Holds the following functions in common: (most methods applied through ZIM 4TH methods)
setColorRange, cloneAll(), linearGradient (depreciated), radialGradient (depreciated)
NOTE: this is NOT a generic Shape - see the zim.Shape() class for that.
EXAMPLE
// would recommend just extending a Container() for custom shapes / objects
// unless properties listed above are needed over multiple projects
// but it could be done with matching various private properties, etc.
// also note that a Blob can make just about any shape...
var Smile = function(color) {
this.super_constructor(-100,-20,200,70);
this._color = color;
this.shape = new Shape().addTo(this);
// this is an example of how ZIM changes shape color
// will need to go through and do similar things for borderColor, etc.
this.colorCommand = this.shape.f(this._color).command;
this.shape.mt(-100,-20).bt(0,70,0,70,100,-20);
}
extend(Smile, CustomShape);
var smile = new Smile(red).center();
timeout(1, function () {
smile.color = blue;
stage.update();
});
END EXAMPLE
SEE - ZIM shapes for details.
--*///+50.97
zim.CustomShape = function(x, y, w, h) {
if (!zim.zimCustomShapeCheck) {z_d("50.97"); zim.zimCustomShapeCheck=true;}
this.zimContainer_constructor(x, y, w, h, false);
var that = this;
this.mouseChildren = false;
that._dashedOffset = 5;
Object.defineProperty(that, 'color', {
get: function() {
return that._color;
},
set: function(value) {
if (zot(value)) value = "black";
that._color = value;
if (value && value.type) that.specialColor(that.colorCommand, value);
else that.colorCommand.style = value;
}
});
this.setColorRange = function(color1, color2) {
if (zot(color2)) {
that.startColor = that.color;
that.endColor = color1;
} else if (zot(color1)) {
that.startColor = that.color;
that.endColor = color2;
} else {
that.startColor = color1;
that.endColor = color2;
}
return that;
};
that._colorRange = 0;
Object.defineProperty(that, 'colorRange', {
get: function() {
return that._colorRange;
},
set: function(value) {
that._colorRange = value;
if (!zot(that.startColor) && !zot(that.endColor)) {
that.color = zim.colorRange(that.startColor, that.endColor, value);
}
}
});
Object.defineProperty(that, 'borderColor', {
get: function() {
return that._borderColor;
},
set: function(value) {
that._borderColor = value;
if (value && !that.borderWidth) {
that.borderWidth = 1;
}
if (!that.borderColorCommand) {
that.drawShape();
}
else if (value && value.type) that.specialColor(that.borderColorCommand, value);
else that.borderColorCommand.style = value;
}
});
Object.defineProperty(that, 'borderWidth', {
get: function() {
return that._borderWidth;
},
set: function(value) {
if (!(value>0)) value = 0;
that._borderWidth = value;
if (!that.borderWidthCommand || that._borderWidth == 0) {
that.borderWidthCommand = null;
that.drawShape();
}
else {
that.borderWidthCommand.width = that._borderWidth;
if (that._dashed) {
that.borderDashedCommand.segments = that._dashed;
that.borderDashedCommand.offset = that._dashedOffset;
}
}
}
});
Object.defineProperty(that, 'thickness', {
get: function() {
return that._thickness;
},
set: function(value) {
if (!(value>0)) value = 0;
that._thickness = value;
if (!that.thicknessCommand || that._thickness == 0) that.drawShape();
else {
that.thicknessCommand.width = that._thickness;
if (that._dashed) {
that.dashedCommand.segments = that._dashed;
that.dashedCommand.offset = that._dashedOffset;
}
}
}
});
Object.defineProperty(that, 'dashed', {
get: function() {
return that._dashed;
},
set: function(value) {
that._dashed = value;
if (value && !Array.isArray(that._dashed)) that.dashed = [10, 10];
if (that.type == "Squiggle" || that.type == "Line") {
if (!that.thicknessCommand || that._thickness == 0) return;
var dashedCommand = that.dashedCommand;
} else {
if (!that.borderWidthCommand || that._borderWidth == 0) return;
var dashedCommand = that.borderDashedCommand;
}
if (!dashedCommand) {
that.drawShape();
} else {
if (that._dashed) {
dashedCommand.segments = that._dashed;
dashedCommand.offset = that._dashedOffset;
} else {
dashedCommand.segments = null;
dashedCommand.offset = null;
}
}
}
});
Object.defineProperty(that, 'dashedOffset', {
get: function() {
return that._dashedOffset;
},
set: function(value) {
if (isNaN(value)) value = 5;
that._dashedOffset = value;
if (that.type == "Squiggle" || that.type == "Line") {
if (!that.thicknessCommand || that._thickness == 0) return;
var dashedCommand = that.dashedCommand;
} else {
if (!that.borderWidthCommand || that._borderWidth == 0) return;
var dashedCommand = that.borderDashedCommand;
}
if (!dashedCommand) {
that.drawShape();
} else {
if (that._dashed) {
dashedCommand.segments = that._dashed;
dashedCommand.offset = that._dashedOffset;
} else {
dashedCommand.segments = null;
dashedCommand.offset = null;
}
}
}
});
Object.defineProperty(that, 'corner', {
get: function() {
return that._corner;
},
set: function(value) {
that._corner = value;
that.drawShape();
}
});
// depreciated
this.linearGradient = function(colors,ratios,x0,y0,x1,y1) {
this.linearGradientParams = Array.prototype.slice.call(arguments);
this.colorCommand.linearGradient(colors,ratios,x0,y0,x1,y1);
return this;
};
this.radialGradient = function(colors,ratios,x0,y0,radius0,x1,y1,radius1) {
this.radialGradientParams = Array.prototype.slice.call(arguments);
this.colorCommand.radialGradient(colors,ratios,x0,y0,radius0,x1,y1,radius1);
return this;
};
// special clone that clones contents of shape
this.cloneAll = function(exact, style, group, inherit) {
var currentBounds = this.getBounds();
if (zot(currentBounds)) currentBounds = {x:null, y:null, width:null, height:null};
var body = this.cloneChildren(this.cloneProps(new zim.Container(currentBounds.x,currentBounds.y,currentBounds.width,currentBounds.height, style, group, inherit)), exact);
body.mouseChildren = false;
body.type = this.type;
return body;
};
};
zim.extend(zim.CustomShape, zim.Container, null, "zimContainer", false);
//-50.97
/*--
zim.Circle = function(radius, color, borderColor, borderWidth, dashed, percent, percentClose, strokeObj, style, group, inherit)
Circle
zim class - extends a zim.CustomShape which extends a zim.Container which extends a createjs.Container
DESCRIPTION
Makes a circle shape inside a container.
The registration and origin will be the center.
NOTE: mouseChildren is turned to false for all zim Shape containers.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var circle = new Circle(50, "red");
circle.center();
// or with 10 pixel grey stroke
var circle = new Circle(50, "red", "#666", 10);
// fill the circle with a radial gradient fill
circle.colorCommand.radialGradient([yellow,green], [0, .7], 0, 0, 20, 0, 0, 50);
// make a half circle - or any percent of a circle
var semi = new Circle({radius:200, color:pink, percent:50}).center();
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports VEE - parameters marked with ZIM VEE mean a zim Pick() object or Pick Literal can be passed
Pick Literal formats: [1,3,2] - random; {min:10, max:20} - range; series(1,2,3) - order, function(){return result;} - function
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
radius - |ZIM VEE| (default 50) the radius (from the center to the edge or half the diameter) ;-)
color - |ZIM VEE| (default "black") the fill color as any CSS color including "rgba()" for alpha fill (set a to 0 for tranparent fill)
borderColor - |ZIM VEE| (default null) the stroke color
borderWidth - |ZIM VEE| (default 1 if stroke is set) the size of the stroke in pixels
dashed - (default false) set to true for dashed border (if borderWidth or borderColor set)
or set to an array of line size then space size, etc.
eg. [20, 10] is 20 line and 10 space repeated and [20,100,50,10] is 20 line, 100 space, 50 line, 10 space, etc.
percent - (default 100) set to a percentage of a circle (arc) - registration stays at radius center, bounds shrink to arc
percentClose - (default true) set to false to not close the border of a circle with percent set
strokeObj - (default {caps:"butt", joints:"miter", miterLimit:10, ignoreScale:false}) set to adjust stroke properties
// note, not all applicable to a Circle - perhaps just ignoreScale...
caps options: "butt", "round", "square" or 0,1,2
joints options: "miter", "round", "bevel" or 0,1,2
miterLimit is the ration at which the mitered joint will be clipped
ignoreScale set to true will draw the specified line thickness regardless of object scale
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
setColorRange(color1, color2) - set a color range for shape - used by colorRange property - returns obj for chaining
if one color is used, the current color is used and color1 is the second color in the range
cache(see Container docs for parameter description) - overrides CreateJS cache() and returns object for chaining
Leave parameters blank to cache bounds of shape (plus outer edge of border if borderWidth > 0)
hasProp(property as String) - returns true if property exists on object else returns false
clone(exact) - makes a copy of the shape
exact (default false) ZIM VEE (Pick) values are active in clones unless exact is set to true
For instance, if the object's color is [blue, green]
then its clone might be blue or green - which could be different than the original
If exact is set to true then the clone will be the color of the original object
cloneAll(exact, style, group, inherit) - copies shape and any custom content in shape - experimental - usually shapes do not have content (use a Container)
exact (default false) in theory will copy ZIM VEE values as they are in the original
see main class for style, group, inherit parameters
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
shape - gives access to the circle shape
color - get and set the fill color
colorRange - if setColorRange() is used, the colorRange is a ratio (0-1) between the colors
setting the colorRange will change the color property of the shape
for instance, shape.setColorRange(blue, pink) then shape.colorRange = .5
will set the color of the shape to half way between blue and pink
shape.animate({color:red}, 1000); is a shortcut to animate the colorRange
shape.wiggle("colorRange", .5, .2, .5, 1000, 5000) will wiggle the colorRange
colorCommand - access to the CreateJS fill command for bitmap, linearGradient and radialGradient fills
depreciated - see ZIM GradientColor, RadialColor and BitmapColor
borderColor - get and set the stroke color
borderColorCommand - access to the CreateJS stroke command for bitmap, linearGradient and radialGradient strokes
See: https://www.createjs.com/docs/easeljs/classes/Graphics.Stroke.html
borderWidth - get and set the stroke size in pixels
borderWidthCommand - access to the CreateJS stroke style command (width, caps, joints, miter, ignoreScale)
See: https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeStyle.html
dashed - get and set the dashed - use true / false or an array (see dashed parameter)
dashedOffset - get and set the offset of the dash (50 default) - can animate this property for a marquee effect
borderDashedCommand - access to the CreateJS stroke dashed command (segments, offset)
see https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeDash.html
radius - gets or sets the radius.
The radius is independent of scaling and can be different than the width/2
Setting the radius redraws the circle but any current scaling is kept
percent - get or set the percent of the circle (see percent parameter)
percentClose - get or set the percent close of the circle (see percentClose parameter)
mouseChildren - set to false to avoid dragging the shape inside
to drag or interact with objects inside then set mouseChildren to true
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+51
zim.Circle = function(radius, color, borderColor, borderWidth, dashed, percent, percentClose, strokeObj, style, group, inherit) {
var sig = "radius, color, borderColor, borderWidth, dashed, percent, percentClose, strokeObj, style, group, inherit";
var duo; if (duo = zob(zim.Circle, arguments, sig, this)) return duo;
z_d("51");
this.zimCustomShape_constructor(null,null,null,null,false);
this.type = "Circle";
this.group = group;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
if (zot(radius)) radius = DS.radius!=null?DS.radius:50;
if (zot(dashed)) dashed = DS.dashed!=null?DS.dashed:false;
if (zot(borderColor)) borderColor = DS.borderColor!=null?DS.borderColor:null;
if (zot(borderWidth)) borderWidth = DS.borderWidth!=null?DS.borderWidth:null;
if (borderColor < 0 || borderWidth < 0) borderColor = borderWidth = null;
else if (borderColor!=null && borderWidth==null) borderWidth = 1;
if (zot(color)) color = DS.color!=null?DS.color:(borderWidth>0?"rgba(0,0,0,0)":"black");
if (zot(percent)) percent = DS.percent!=null?DS.percent:100;
if (zot(percentClose)) percentClose = DS.percentClose!=null?DS.percentClose:true;
if (zot(strokeObj)) strokeObj = DS.strokeObj!=null?DS.strokeObj:{};
// PICK
var oa = remember(radius, color, borderColor, borderWidth, percent);
function remember() {return arguments;} // for cloning PICK
radius = zim.Pick.choose(radius);
color = zim.Pick.choose(color);
borderColor = zim.Pick.choose(borderColor);
borderWidth = zim.Pick.choose(borderWidth);
percent = zim.Pick.choose(percent);
var that = this;
that._radius = radius;
that._color = color;
that._borderColor = borderColor;
that._borderWidth = borderWidth;
that._dashed = dashed;
if (that._dashed && !Array.isArray(that._dashed)) that._dashed = [10, 10];
var circle = this.shape = new createjs.Shape();
this.addChild(circle);
var g = circle.graphics;
that.drawShape = function() {
g.c();
that.colorCommand = g.f(that._color).command;
if (that._color && that._color.type) that.specialColor(that.colorCommand, that._color);
// border of 0 or a string value still draws a border in CreateJS
if (zot(that._borderWidth) || that._borderWidth > 0) { // no border specified or a border > 0
if (!zot(that._borderColor) || !zot(that._borderWidth)) { // either a border color or thickness
if (zot(that._borderColor)) that._borderColor = "black";
that.borderColorCommand = g.s(that._borderColor).command;
if (that._borderColor && that._borderColor.type) that.specialColor(that.borderColorCommand, that._borderColor);
that.borderWidthCommand = g.ss(that._borderWidth, strokeObj.caps, strokeObj.joints, strokeObj.miterLimit, strokeObj.ignoreScale).command;
if (that._dashed) that.borderDashedCommand = g.sd(Array.isArray(that._dashed)?that._dashed:[10, 10], that._dashedOffset).command;
}
}
var h = that._radius*2;
if (typeof percent == "number" && percent >= 0 && percent < 100) {
var p = 360*percent/100/2;
g.arc(0, 0, that._radius, (-p-90)*Math.PI/180, (p-90)*Math.PI/180, false);
if (percentClose) g.cp();
h = that._radius-Math.cos(p*Math.PI/180)*that._radius;
} else {
g.dc(0,0,that._radius);
}
that.setBounds(-that._radius,-that._radius,that._radius*2,h);
};
that.drawShape();
Object.defineProperty(that, 'radius', {
get: function() {
return that._radius;
},
set: function(value) {
that._radius = value;
that.drawShape();
}
});
Object.defineProperty(that, 'percent', {
get: function() {
return percent;
},
set: function(value) {
percent = value;
that.drawShape();
}
});
Object.defineProperty(that, 'percentClose', {
get: function() {
return percentClose;
},
set: function(value) {
percentClose = value;
that.drawShape();
}
});
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NOTE: extends ZIM CustomShape for more properties and a few functions.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (style!==false) zim.styleTransforms(this, DS); // global function - would have put on DisplayObject if had access to it
this.clone = function(exact, container) {
var newShape = that.cloneProps(new zim.Circle((exact||!zim.isPick(oa[0]))?that.radius:oa[0], (exact||!zim.isPick(oa[1]))?that.color:oa[1], (exact||!zim.isPick(oa[2]))?that.borderColor:oa[2], (exact||!zim.isPick(oa[3]))?that.borderWidth:oa[3], that.dashed, (exact||!zim.isPick(oa[4]))?percent:oa[4], percentClose, strokeObj, style, this.group, inherit));
if (that.linearGradientParams) newShape.linearGradient.apply(newShape, that.linearGradientParams);
if (that.radialGradientParams) newShape.radialGradient.apply(newShape, that.radialGradientParams);
return newShape;
};
};
zim.extend(zim.Circle, zim.CustomShape, "clone", "zimCustomShape", false);
//-51
/*--
zim.Rectangle = function(width, height, color, borderColor, borderWidth, corner, dashed, strokeObj, style, group, inherit)
Rectangle
zim class - extends a zim.CustomShape which extends a zim.Container which extends a createjs.Container
DESCRIPTION
Makes a rectangle shape inside a container.
The registration and origin will be top left corner.
NOTE: mouseChildren is turned to false for all zim Shape containers.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var rect = new Rectangle(200, 100, "blue");
rect.center();
// or with rounded corners:
var rect = new Rectangle({width:200, height:100, color:"blue", corner:20});
// or with 2 pixel white stroke
var rect = new Rectangle(200, 100, "blue", "white", 2);
// fill the rectangle with a Bitmap fill assuming icon has been loaded - not the image property
rect.colorCommand.bitmap(frame.asset("icon.png").image);
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports VEE - parameters marked with ZIM VEE mean a zim Pick() object or Pick Literal can be passed
Pick Literal formats: [1,3,2] - random; {min:10, max:20} - range; series(1,2,3) - order, function(){return result;} - function
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
width - |ZIM VEE| (default the height if provided else 100) the width
height - |ZIM VEE| (default the width if provided else 100) the height
color - |ZIM VEE| (default "black") the fill color as any CSS color including "rgba()" for alpha fill (set a to 0 for tranparent fill)
borderColor - |ZIM VEE| (default null) the stroke color
borderWidth - |ZIM VEE| (default 1 if stroke is set) the size of the stroke in pixels
corner - (default 0) the round of corner
can also be an array of [topLeft, topRight, bottomRight, bottomLeft]
dashed - (default false) set to true for dashed border (if borderWidth or borderColor set)
or set to an array of line size then space size, etc.
eg. [20, 10] is 20 line and 10 space repeated and [20,100,50,10] is 20 line, 100 space, 50 line, 10 space, etc.
strokeObj - (default {caps:"butt", joints:"miter", miterLimit:10, ignoreScale:false}) set to adjust stroke properties
caps options: "butt", "round", "square" or 0,1,2
joints options: "miter", "round", "bevel" or 0,1,2
miterLimit is the ration at which the mitered joint will be clipped
ignoreScale set to true will draw the specified line thickness regardless of object scale
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
setColorRange(color1, color2) - set a color range for shape - used by colorRange property - returns obj for chaining
if one color is used, the current color is used and color1 is the second color in the range
cache(see Container docs for parameter description) - overrides CreateJS cache() and returns object for chaining
Leave parameters blank to cache bounds of shape (plus outer edge of border if borderWidth > 0)
hasProp(property as String) - returns true if property exists on object else returns false
clone(exact) - makes a copy of the shape
exact (default false) ZIM VEE (Pick) values are active in clones unless exact is set to true
For instance, if the object's color is [blue, green]
then its clone might be blue or green - which could be different than the original
If exact is set to true then the clone will be the color of the original object
cloneAll(exact style, group, inherit) - copies shape and any custom content in shape - experimental - usually shapes do not have content (use a Container)
exact (default false) in theory will copy ZIM VEE values as they are in the original
see main class for style, group, inherit parameters
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
shape - gives access to the rectangle shape
color - get and set the fill color
colorRange - if setColorRange() is used, the colorRange is a ratio (0-1) between the colors
setting the colorRange will change the color property of the shape
for instance, shape.setColorRange(blue, pink) then shape.colorRange = .5
will set the color of the shape to half way between blue and pink
shape.animate({color:red}, 1000); is a shortcut to animate the colorRange
shape.wiggle("colorRange", .5, .2, .5, 1000, 5000) will wiggle the colorRange
colorCommand - access to the CreateJS fill command for bitmap, linearGradient and radialGradient fills
depreciated - see ZIM GradientColor, RadialColor and BitmapColor
borderColor - get and set the stroke color
borderColorCommand - access to the CreateJS stroke command for bitmap, linearGradient and radialGradient strokes
See: https://www.createjs.com/docs/easeljs/classes/Graphics.Stroke.html
borderWidth - get and set the stroke size in pixels
borderWidthCommand - access to the CreateJS stroke style command (width, caps, joints, miter, ignoreScale)
See: https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeStyle.html
corner - get or set the corner or array of corners (see corner parameter)
dashed - get and set the dashed - use true / false or an array (see dashed parameter)
dashedOffset - get and set the offset of the dash (50 default) - can animate this property for a marquee effect
borderDashedCommand - access to the CreateJS stroke dashed command (segments, offset)
see https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeDash.html
mouseChildren - set to false to avoid dragging the shape inside
to drag or interact with objects inside then set mouseChildren to true
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+52
zim.Rectangle = function(width, height, color, borderColor, borderWidth, corner, dashed, strokeObj, style, group, inherit) {
var sig = "width, height, color, borderColor, borderWidth, corner, dashed, strokeObj, style, group, inherit";
var duo; if (duo = zob(zim.Rectangle, arguments, sig, this)) return duo;
z_d("52");
this.zimCustomShape_constructor(null,null,null,null,false);
this.type = "Rectangle";
this.group = group;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
if (zot(width)) width = DS.width!=null?DS.width:null;
if (zot(height)) height = DS.height!=null?DS.height:!zot(width)?width:100;
if (zot(width)) width = height;
if (zot(corner)) corner = DS.corner!=null?DS.corner:0;
if (zot(dashed)) dashed = DS.dashed!=null?DS.dashed:false;
if (zot(borderColor)) borderColor = DS.borderColor!=null?DS.borderColor:null;
if (zot(borderWidth)) borderWidth = DS.borderWidth!=null?DS.borderWidth:null;
if (borderColor < 0 || borderWidth < 0) borderColor = borderWidth = null;
else if (borderColor!=null && borderWidth==null) borderWidth = 1;
if (zot(color)) color = DS.color!=null?DS.color:(borderWidth>0?"rgba(0,0,0,0)":"black");
if (zot(strokeObj)) strokeObj = DS.strokeObj!=null?DS.strokeObj:{};
// PICK
var oa = remember(width, height, color, borderColor, borderWidth);
function remember() {return arguments;} // for cloning PICK
width = zim.Pick.choose(width);
height = zim.Pick.choose(height);
color = zim.Pick.choose(color);
borderColor = zim.Pick.choose(borderColor);
borderWidth = zim.Pick.choose(borderWidth);
var that = this;
that._color = color;
that._borderColor = borderColor;
that._borderWidth = borderWidth;
that._dashed = dashed;
if (that._dashed && !Array.isArray(that._dashed)) that._dashed = [10, 10];
that._corner = corner;
var rectangle = this.shape = new createjs.Shape();
this.addChild(rectangle);
var g = rectangle.graphics;
that.drawShape = function() {
g.c();
that.colorCommand = g.f(that._color).command;
if (color && color.type) that.specialColor(that.colorCommand, color);
// border of 0 or a string value still draws a border in CreateJS
if (zot(that._borderWidth) || that._borderWidth > 0) { // no border specified or a border > 0
if (!zot(that._borderColor) || !zot(that._borderWidth)) { // either a border color or thickness
if (zot(that._borderColor)) that._borderColor = "black";
that.borderColorCommand = g.s(that._borderColor).command;
if (that._borderColor && that._borderColor.type) that.specialColor(that.borderColorCommand, that._borderColor);
that.borderWidthCommand = g.ss(that._borderWidth, strokeObj.caps, strokeObj.joints, strokeObj.miterLimit, strokeObj.ignoreScale).command;
if (that._dashed) that.borderDashedCommand = g.sd(Array.isArray(that._dashed)?that._dashed:[10, 10], that._dashedOffset).command;
}
}
if (Array.isArray(that._corner)) {
g.rc(0,0,width,height,that._corner[0],that._corner[1],that._corner[2],that._corner[3]);
} else if (that._corner > 0) {
g.rr(0,0,width,height,that._corner);
} else {
g.r(0,0,width,height);
}
that.setBounds(0,0,width,height);
};
that.drawShape();
// Object.defineProperty(that, 'corner', {
// get: function() {
// return corner;
// },
// set: function(value) {
// corner = value;
// that.drawShape();
// }
// });
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NOTE: extends ZIM CustomShape for more properties and a few functions.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (style!==false) zim.styleTransforms(this, DS);
this.clone = function(exact) {
var newShape = that.cloneProps(new zim.Rectangle((exact||!zim.isPick(oa[0]))?width:oa[0], (exact||!zim.isPick(oa[1]))?height:oa[1], (exact||!zim.isPick(oa[2]))?that.color:oa[2], (exact||!zim.isPick(oa[3]))?that.borderColor:oa[3], (exact||!zim.isPick(oa[4]))?that.borderWidth:oa[4], corner, that._dashed, strokeObj, style, this.group, inherit));
return newShape;
};
};
zim.extend(zim.Rectangle, zim.CustomShape, "clone", "zimCustomShape", false);
//-52
/*--
zim.Triangle = function(a, b, c, color, borderColor, borderWidth, corner, center, adjust, dashed, strokeObj, style, group, inherit)
Triangle
zim class - extends a zim.CustomShape which extends a zim.Container which extends a createjs.Container
DESCRIPTION
Makes a triangle shape inside a container using three line lengths.
Passing one length parameter makes an equilateral triangle.
Passing two length parameters makes an isosceles triangle.
Passing -1 as the last length parameter makes a 90 degree triangle.
NOTE: mouseChildren is turned to false for all zim Shape containers.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var tri = new Triangle(200, null, null, "green");
tri.center();
// all three sides specified - tall pointy triangle with yellow stroke of 10 pixels
var tri = new Triangle(100, 200, 200, "green", "yellow", 10);
// here we adjust so rotation looks better
var tri = new Triangle({a:200, color:"green", adjust:30});
tri.center();
tri.animate({obj:{rotation:360}, time:3, ease:"linear", loop:true});
// here we fill the triangle with a linear gradient fill
triangle.colorCommand.linearGradient([green, blue ,green], [.2, .5, .8], 0, 0, triangle.width, 0);
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports VEE - parameters marked with ZIM VEE mean a zim Pick() object or Pick Literal can be passed
Pick Literal formats: [1,3,2] - random; {min:10, max:20} - range; series(1,2,3) - order, function(){return result;} - function
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
a, b and c - |ZIM VEE| (default 100) the lengths of the sides
a will run horizontally along the bottom
b is upwards and c is back to the origin
if c is set to -1 will assume a 90 angle
color - |ZIM VEE| (default "black") the fill color as any CSS color including "rgba()" for alpha fill (set a to 0 for tranparent fill)
borderColor - |ZIM VEE| (default null) the stroke color
borderWidth - |ZIM VEE| (default 1 if stroke is set) the size of the stroke in pixels
corner - (default 0) the round of corner
can also be an array of [bottomLeft, bottomRight, top]
center - (default true) puts the registration point to the center
adjust - (default 0) pixels to bring center towards vertical base
the actual center is not really the weighted center
dashed - (default false) set to true for dashed border (if borderWidth or borderColor set)
or set to an array of line size then space size, etc.
eg. [20, 10] is 20 line and 10 space repeated and [20,100,50,10] is 20 line, 100 space, 50 line, 10 space, etc.
strokeObj - (default {caps:"butt", joints:"miter", miterLimit:10, ignoreScale:false}) set to adjust stroke properties
caps options: "butt", "round", "square" or 0,1,2
joints options: "miter", "round", "bevel" or 0,1,2
miterLimit is the ration at which the mitered joint will be clipped
ignoreScale set to true will draw the specified line thickness regardless of object scale
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
setColorRange(color1, color2) - set a color range for shape - used by colorRange property - returns obj for chaining
if one color is used, the current color is used and color1 is the second color in the range
cache(see Container docs for parameter description) - overrides CreateJS cache() and returns object for chaining
Leave parameters blank to cache bounds of shape (plus outer edge of border if borderWidth > 0)
hasProp(property as String) - returns true if property exists on object else returns false
clone() - makes a copy of the shape
exact (default false) ZIM VEE (Pick) values are active in clones unless exact is set to true
For instance, if the object's color is [blue, green]
then its clone might be blue or green - which could be different than the original
If exact is set to true then the clone will be the color of the original object
cloneAll(exact style, group, inherit) - copies shape and any custom content in shape - experimental - usually shapes do not have content (use a Container)
exact (default false) in theory will copy ZIM VEE values as they are in the original
see main class for style, group, inherit parameters
exact (default false) in theory will copy ZIM VEE values as they are in the original
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
shape - gives access to the triangle shape
color - get and set the fill color
colorRange - if setColorRange() is used, the colorRange is a ratio (0-1) between the colors
setting the colorRange will change the color property of the shape
for instance, shape.setColorRange(blue, pink) then shape.colorRange = .5
will set the color of the shape to half way between blue and pink
shape.animate({color:red}, 1000); is a shortcut to animate the colorRange
shape.wiggle("colorRange", .5, .2, .5, 1000, 5000) will wiggle the colorRange
colorCommand - access to the CreateJS fill command for bitmap, linearGradient and radialGradient fills
depreciated - see ZIM GradientColor, RadialColor and BitmapColor
borderColor - get and set the stroke color
borderColorCommand - access to the CreateJS stroke command for bitmap, linearGradient and radialGradient strokes
See: https://www.createjs.com/docs/easeljs/classes/Graphics.Stroke.html
borderWidth - get and set the stroke size in pixels
borderWidthCommand - access to the CreateJS stroke style command (width, caps, joints, miter, ignoreScale)
See: https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeStyle.html
corner - get or set the corner or array of corners (see corner parameter)
dashed - get and set the dashed - use true / false or an array (see dashed parameter)
dashedOffset - get and set the offset of the dash (50 default) - can animate this property for a marquee effect
borderDashedCommand - access to the CreateJS stroke dashed command (segments, offset)
see https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeDash.html
one, two, three - read only - points with x, y properties for bottom left, bottom right, top right
angles - read only - Array of angles [bottom left, bottom right, top right]
adjusted - read only - the value of the adjust parameter or 0 if no adjust was supplied
mouseChildren - set to false to avoid dragging the shape inside
to drag or interact with objects inside then set mouseChildren to true
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+53
zim.Triangle = function(a, b, c, color, borderColor, borderWidth, corner, center, adjust, dashed, strokeObj, style, group, inherit) {
var sig = "a, b, c, color, borderColor, borderWidth, corner, center, adjust, dashed, strokeObj, style, group, inherit";
var duo; if (duo = zob(zim.Triangle, arguments, sig, this)) return duo;
z_d("53");
this.zimCustomShape_constructor(null,null,null,null,false);
this.type = "Triangle";
this.group = group;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
if (zot(a)) a = DS.a!=null?DS.a:100;
if (zot(b)) b = DS.b!=null?DS.b:a;
if (zot(c)) c = DS.c!=null?DS.c:b;
if (c==-1) c = Math.sqrt(Math.pow(a,2)+Math.pow(b,2));
if (zot(corner)) corner = DS.corner!=null?DS.corner:0;
if (zot(center)) center = DS.center!=null?DS.center:true;
if (zot(adjust)) adjust = DS.adjust!=null?DS.adjust:0;
if (zot(borderColor)) borderColor = DS.borderColor!=null?DS.borderColor:null;
if (zot(borderWidth)) borderWidth = DS.borderWidth!=null?DS.borderWidth:null;
if (borderColor < 0 || borderWidth < 0) borderColor = borderWidth = null;
else if (borderColor!=null && borderWidth==null) borderWidth = 1;
if (zot(color)) color = DS.color!=null?DS.color:(borderWidth>0?"rgba(0,0,0,0)":"black");
if (zot(adjust)) adjust = DS.adjust!=null?DS.adjust:0;
if (zot(strokeObj)) strokeObj = DS.strokeObj!=null?DS.strokeObj:{};
// PICK
var oa = remember(a, b, c, color, borderColor, borderWidth);
function remember() {return arguments;} // for cloning PICK
a = zim.Pick.choose(a);
b = zim.Pick.choose(b);
c = zim.Pick.choose(c);
this.a = a;
this.b = b;
this.c = c;
color = zim.Pick.choose(color);
borderColor = zim.Pick.choose(borderColor);
borderWidth = zim.Pick.choose(borderWidth);
var that = this;
that._color = color;
that._borderColor = borderColor;
that._borderWidth = borderWidth;
that._dashed = dashed;
if (that._dashed && !Array.isArray(that._dashed)) that._dashed = [10, 10];
that._corner = corner;
var lines = [a,b,c];
lines.sort(function(a, b){return b-a;});
var aa = lines[0];
var bb = lines[1];
var cc = lines[2];
var order = [lines.indexOf(a), lines.indexOf(b), lines.indexOf(c)];
if (aa > bb+cc) {
zog("zim display - Triangle(): invalid triangle lengths");
return;
}
var tri = this.shape = new createjs.Shape();
this.adjusted = adjust;
this.addChild(tri);
var g = tri.graphics;
that.drawShape = function() {
var corners = [];
if (Array.isArray(that._corner)) corners = that._corner;
else corners.push(that._corner, that._corner, that._corner);
for(var i=0; i<3; i++) {
if (corner[i] < 0 || typeof corner[i] != "number") corner[i] = 0;
}
g.c();
that.colorCommand = g.f(that._color).command;
if (that._color && that._color.type) that.specialColor(that.colorCommand, that._color);
// border of 0 or a string value still draws a border in CreateJS
if (zot(that._borderWidth) || that._borderWidth > 0) { // no border specified or a border > 0
if (!zot(that._borderColor) || !zot(that._borderWidth)) { // either a border color or thickness
if (zot(that._borderColor)) that._borderColor = "black";
that.borderColorCommand = g.s(that._borderColor).command;
if (that._borderColor && that._borderColor.type) that.specialColor(that.borderColorCommand, that._borderColor);
that.borderWidthCommand = g.ss(that._borderWidth, strokeObj.caps, strokeObj.joints, strokeObj.miterLimit, strokeObj.ignoreScale).command;
if (that._dashed) that.borderDashedCommand = g.sd(Array.isArray(that._dashed)?that._dashed:[10, 10], that._dashedOffset).command;
}
}
// g.mt(5,100)
// g.at(100,100, 0,0, 15).at(0,0, 0,100, 5).at(0,100,100,100, 5)
that.one={x:0,y:0};
that.two={x:a,y:0};
// find biggest angle with cosine rule
var angle1 = Math.acos( (Math.pow(bb,2) + Math.pow(cc,2) - Math.pow(aa,2)) / (2 * bb * cc) ) * 180 / Math.PI;
// use the sine rule for next biggest angle
var angle2 = Math.asin( bb * Math.sin(angle1 * Math.PI / 180) / aa ) * 180 / Math.PI;
// find last angle
var angle3 = 180 - angle1 - angle2;
// get position of angles by mapping to opposite side sizes
// as in smallest angle is across from smallest side
// largest angle is across from largest size, etc.
var temp = [angle1, angle2, angle3]; // largets to smallest
that.angles = [temp[order[1]], temp[order[2]], temp[order[0]]];
var nextAngle = that.angles[1];
var backX = Math.cos(nextAngle * Math.PI / 180) * b;
var upY = Math.sin(nextAngle * Math.PI / 180) * b;
var width = Math.max(a, a-backX);
var height = upY;
that.setBounds(0,adjust,width,height);
tri.y = height;
that.three={x:a-backX,y:0-upY};
var sX = a*corners[0]/((corners[0]+corners[1])||1);
g
.mt(sX,0)
.at(a,0, a-backX,0-upY, corners[1])
.at(a-backX,0-upY, 0,0, corners[2])
.at(0,0, a,0, corners[0])
.lt(sX,0);
g.cp();
if (center) {
that.regX = width/2;
that.regY = height/2;
}
if (adjust) {
that.shape.y+=adjust;
}
};
that.drawShape();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NOTE: extends ZIM CustomShape for more properties and a few functions.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (style!==false) zim.styleTransforms(this, DS);
this.clone = function(exact) {
var newShape = that.cloneProps(new zim.Triangle((exact||!zim.isPick(oa[0]))?a:oa[0], (exact||!zim.isPick(oa[1]))?b:oa[1], (exact||!zim.isPick(oa[2]))?c:oa[2], (exact||!zim.isPick(oa[3]))?that.color:oa[3], (exact||!zim.isPick(oa[4]))?that.borderColor:oa[4], (exact||!zim.isPick(oa[5]))?that.borderWidth:oa[5], center, adjust, dashed, strokeObj, style, this.group, inherit));
if (that.linearGradientParams) newShape.linearGradient.apply(newShape, that.linearGradientParams);
if (that.radialGradientParams) newShape.radialGradient.apply(newShape, that.radialGradientParams);
return newShape;
};
};
zim.extend(zim.Triangle, zim.CustomShape, "clone", "zimCustomShape");
//-53
/*--
zim.Poly = function(radius, sides, pointSize, color, borderColor, borderWidth, dashed, strokeObj, style, group, inherit)
Poly
zim class - extends a zim.CustomShape which extends a zim.Container which extends a createjs.Container
DESCRIPTION
Makes a regular polygon with radius like a Circle.
The number of sides can be set as well as a pointSize that will make star-like shapes
The registration and origin will be the center.
NOTE: mouseChildren is turned to false for all zim Shape containers.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var poly = new Poly(200, 5, 0, pink).center(); // pentagon
var poly = new Poly(200, 5, .6, pink).center(); // five point star
new Poly(200, 8, 2.5, purple)
.sca(1.1).center().sha("rgba(0,0,0,.3)", 10,10,5); // backing...
new Poly(200, 8, 2.5, pink)
.center();
new Label({text:"P O L Y", color:green, font:"impact", outlineColor:blue, size:75, shiftVertical:10})
.sha().rot(-25).center();
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports VEE - parameters marked with ZIM VEE mean a zim Pick() object or Pick Literal can be passed
Pick Literal formats: [1,3,2] - random; {min:10, max:20} - range; series(1,2,3) - order, function(){return result;} - function
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
radius - |ZIM VEE| (default 50) the radius (from the center to the edge or half the diameter) ;-)
sides - |ZIM VEE| (default 5) the number of sides
pointSize - |ZIM VEE| (default 0) a factor that will indent or outdent the sides to form stars
0 is no indent - 1 is a complete indent - which will have no fill and if there is a border will look like a stick figure
beyond 1 is cool - it overlaps on itself and makes multiple patterns
color - |ZIM VEE| (default "black") the fill color as any CSS color including "rgba()" for alpha fill (set a to 0 for tranparent fill)
borderColor - |ZIM VEE| (default null) the stroke color
borderWidth - |ZIM VEE| (default 1 if stroke is set) the size of the stroke in pixels
dashed - (default false) set to true for dashed border (if borderWidth or borderColor set)
or set to an array of line size then space size, etc.
eg. [20, 10] is 20 line and 10 space repeated and [20,100,50,10] is 20 line, 100 space, 50 line, 10 space, etc.
strokeObj - (default {caps:"butt", joints:"miter", miterLimit:10, ignoreScale:false}) set to adjust stroke properties
caps options: "butt", "round", "square" or 0,1,2
joints options: "miter", "round", "bevel" or 0,1,2
miterLimit is the ration at which the mitered joint will be clipped
ignoreScale set to true will draw the specified line thickness regardless of object scale
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
setColorRange(color1, color2) - set a color range for shape - used by colorRange property - returns obj for chaining
if one color is used, the current color is used and color1 is the second color in the range
cache(see Container docs for parameter description) - overrides CreateJS cache() and returns object for chaining
Leave parameters blank to cache bounds of shape (plus outer edge of border if borderWidth > 0)
hasProp(property as String) - returns true if property exists on object else returns false
clone(exact) - makes a copy of the shape
exact (default false) ZIM VEE (Pick) values are active in clones unless exact is set to true
For instance, if the object's color is [blue, green]
then its clone might be blue or green - which could be different than the original
If exact is set to true then the clone will be the color of the original object
cloneAll(exact style, group, inherit) - copies shape and any custom content in shape - experimental - usually shapes do not have content (use a Container)
exact (default false) in theory will copy ZIM VEE values as they are in the original
see main class for style, group, inherit parameters
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
radius - gets or sets the radius.
The radius is independent of scaling and can be different than the width/2
Setting the radius redraws the circle but any current scaling is kept
sides - get or set the sides of the shape
pointSize - get or set the point size of the shape (can be animated too)
shape - gives access to the poly shape
color - get and set the fill color
colorRange - if setColorRange() is used, the colorRange is a ratio (0-1) between the colors
setting the colorRange will change the color property of the shape
for instance, shape.setColorRange(blue, pink) then shape.colorRange = .5
will set the color of the shape to half way between blue and pink
shape.animate({color:red}, 1000); is a shortcut to animate the colorRange
shape.wiggle("colorRange", .5, .2, .5, 1000, 5000) will wiggle the colorRange
colorCommand - access to the CreateJS fill command for bitmap, linearGradient and radialGradient fills
depreciated - see ZIM GradientColor, RadialColor and BitmapColor
borderColor - get and set the stroke color
borderColorCommand - access to the CreateJS stroke command for bitmap, linearGradient and radialGradient strokes
See: https://www.createjs.com/docs/easeljs/classes/Graphics.Stroke.html
borderWidth - get and set the stroke size in pixels
borderWidthCommand - access to the CreateJS stroke style command (width, caps, joints, miter, ignoreScale)
See: https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeStyle.html
dashed - get and set the dashed - use true / false or an array (see dashed parameter)
dashedOffset - get and set the offset of the dash (50 default) - can animate this property for a marquee effect
borderDashedCommand - access to the CreateJS stroke dashed command (segments, offset)
see https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeDash.html
mouseChildren - set to false to avoid dragging the shape inside
to drag or interact with objects inside then set mouseChildren to true
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+53.1
zim.Poly = function(radius, sides, pointSize, color, borderColor, borderWidth, dashed, strokeObj, style, group, inherit) {
var sig = "radius, sides, pointSize, color, borderColor, borderWidth, dashed, strokeObj, style, group, inherit";
var duo; if (duo = zob(zim.Poly, arguments, sig, this)) return duo;
z_d("53.1");
this.zimCustomShape_constructor(null,null,null,null,false);
this.type = "Poly";
this.group = group;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
if (zot(radius)) radius = DS.radius!=null?DS.radius:50;
if (zot(sides)) sides = DS.sides!=null?DS.sides:5;
if (zot(pointSize)) pointSize = DS.pointSize!=null?DS.pointSize:0;
if (zot(dashed)) dashed = DS.dashed!=null?DS.dashed:false;
if (zot(borderColor)) borderColor = DS.borderColor!=null?DS.borderColor:null;
if (zot(borderWidth)) borderWidth = DS.borderWidth!=null?DS.borderWidth:null;
if (borderColor < 0 || borderWidth < 0) borderColor = borderWidth = null;
else if (borderColor!=null && borderWidth==null) borderWidth = 1;
if (zot(color)) color = DS.color!=null?DS.color:(borderWidth>0?"rgba(0,0,0,0)":"black");
if (zot(strokeObj)) strokeObj = DS.strokeObj!=null?DS.strokeObj:{};
// PICK
var oa = remember(radius, sides, pointSize, color, borderColor, borderWidth);
function remember() {return arguments;} // for cloning PICK
radius = zim.Pick.choose(radius);
sides = zim.Pick.choose(sides);
pointSize = zim.Pick.choose(pointSize);
color = zim.Pick.choose(color);
borderColor = zim.Pick.choose(borderColor);
borderWidth = zim.Pick.choose(borderWidth);
var that = this;
that._radius = radius;
that._color = color;
that._sides = sides;
that._pointSize = pointSize;
that._borderColor = borderColor;
that._borderWidth = borderWidth;
that._dashed = dashed;
if (that._dashed && !Array.isArray(that._dashed)) that._dashed = [10, 10];
var poly = this.shape = new createjs.Shape();
this.addChild(poly);
poly.rotation = -90;
var g = poly.graphics;
that.drawShape = function() {
g.c();
that.colorCommand = g.f(that._color).command;
if (that._color && that._color.type) that.specialColor(that.colorCommand, that._color);
// border of 0 or a string value still draws a border in CreateJS
if (zot(that._borderWidth) || that._borderWidth > 0) { // no border specified or a border > 0
if (!zot(that._borderColor) || !zot(that._borderWidth)) { // either a border color or thickness
if (zot(that._borderColor)) that._borderColor = "black";
that.borderColorCommand = g.s(that._borderColor).command;
if (that._borderColor && that._borderColor.type) that.specialColor(that.borderColorCommand, that._borderColor);
that.borderWidthCommand = g.ss(that._borderWidth, strokeObj.caps, strokeObj.joints, strokeObj.miterLimit, strokeObj.ignoreScale).command;
if (that._dashed) that.borderDashedCommand = g.sd(Array.isArray(that._dashed)?that._dashed:[10, 10], that._dashedOffset).command;
}
}
g.dp(0,0,that._radius, that._sides, that._pointSize);
that.setBounds(-that._radius,-that._radius, that._radius*2, that._radius*2);
};
that.drawShape();
Object.defineProperty(that, 'radius', {
get: function() {
return that._radius;
},
set: function(value) {
that._radius = value;
that.drawShape();
}
});
Object.defineProperty(that, 'sides', {
get: function() {
return that._sides;
},
set: function(value) {
that._sides = value;
that.drawShape();
}
});
Object.defineProperty(that, 'pointSize', {
get: function() {
return that._pointSize;
},
set: function(value) {
that._pointSize = value;
that.drawShape();
}
});
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NOTE: extends ZIM CustomShape for more properties and a few functions.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (style!==false) zim.styleTransforms(this, DS); // global function - would have put on DisplayObject if had access to it
this.clone = function(exact, container) {
var newShape = that.cloneProps(new zim.Poly((exact||!zim.isPick(oa[0]))?that.radius:oa[0], (exact||!zim.isPick(oa[1]))?that.sides:oa[1], (exact||!zim.isPick(oa[2]))?that.pointSize:oa[2], (exact||!zim.isPick(oa[3]))?that.color:oa[3], (exact||!zim.isPick(oa[4]))?that.borderColor:oa[4], (exact||!zim.isPick(oa[5]))?that.borderWidth:oa[5], that.dashed, strokeObj, style, this.group, inherit));
if (that.linearGradientParams) newShape.linearGradient.apply(newShape, that.linearGradientParams);
if (that.radialGradientParams) newShape.radialGradient.apply(newShape, that.radialGradientParams);
return newShape;
};
};
zim.extend(zim.Poly, zim.CustomShape, "clone", "zimCustomShape", false);
//-53.1
/*--
zim.Line = function(length, thickness, color, startHead, endHead, dashed, strokeObj, lineType, lineOrientation, curveH, curveV, points, style, group, inherit)
Line
zim class - extends a zim.CustomShape which extends a zim.Container which extends a createjs.Container
DESCRIPTION
Makes a straight line with a length and thickness.
See also ZIM Squiggle() with points:[[0,0], [100,0] for instance for Bezier handles, etc.
See also ZIM Shape() for custom lines, curves, etc.
The registration and origin will be at the start point at the left.
Start point and end point can be adjusted in various ways to accommodate animation, etc.
NOTE: mouseChildren is turned to false for all zim Shape containers.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var line = new Line(500).center(); // centered line
END EXAMPLE
EXAMPLE
var line = new Line({points:[[0,0],[100,0],[100,100],[200,100]]}).center(); // over, up, over, etc.
// or with quadratic curves:
// 100,0 is control point to x,y of 100,50
var line = new Line({points:[[0,0],[100,0,100,50],[100,100,200,100]]}).center(); // over, up, over
// or with bezier curves:
// 100,0 is first control point, 100,0 is second control point and 100,50 is final point
var line = new Line({points:[[0,0],[100,0,100,0,100,50],[100,100,100,100,200,100]]}).center(); // over, up, over
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports VEE - parameters marked with ZIM VEE mean a zim Pick() object or Pick Literal can be passed
Pick Literal formats: [1,3,2] - random; {min:10, max:20} - range; series(1,2,3) - order, function(){return result;} - function
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
length - |ZIM VEE| (default 100) the length of the line - see also length property and start and end point properties
thickness - |ZIM VEE| (default 3) the size of the stroke in pixels
color - |ZIM VEE| (default "black") the fill color as any CSS color including "rgba()" for alpha fill (set a to 0 for tranparent fill)
startHead - |ZIM VEE| (default "none") the start head of the line - set to "arrow" (or "triangle") or "circle" or a custom DisplayObject - probably centerReg this
endHead - |ZIM VEE| (default "none") the end head of the line - set to "arrow" (or "triangle") or "circle" or a custom DisplayObject - probably centerReg this
dashed - (default false) set to true for dashed border (if borderWidth or borderColor set)
or set to an array of line size then space size, etc.
eg. [20, 10] is 20 line and 10 space repeated and [20,100,50,10] is 20 line, 100 space, 50 line, 10 space, etc.
strokeObj - (default {caps:"butt", joints:"miter", miterLimit:10, ignoreScale:false}) set to adjust stroke properties
caps options: "butt", "round", "square" or 0,1,2
joints options: "miter", "round", "bevel" or 0,1,2
miterLimit is the ration at which the mitered joint will be clipped
ignoreScale set to true will draw the specified line thickness regardless of object scale
lineType - (default "straight") - by default the line is a straight line between points
set to "corner" to draw only horizontal and vertical lines at 90 degree angles between lines (see lineOrientation)
set to "curve" to draw horizontal and vertical lines with curves between lines (see lineOrientation)
lineOrientation - (default "auto") - for lineType other than straight automatically decide between horizontal or vertical
set to "horizontal" to draw two horizontal lines and one vertical line between points
set to "vertical" to draw two vertical lines and one horizontal line between points
curveH - (default 100) - for "curve" lineType this is the horizontal distance of the curve
curveV - (default 100) - for "curve" lineType this is the vertical distance of the curve
points - (default null) an Array of points for the line which will ignore length and lineType parameters
points in the array can have the following formats (a mix is okay too):
[x,y] points for straight lines. This format should also be used for first point
[cpX, cpY, x, y] for quadratic curve to with a single control point followed by the destination point
[cp1X, cp1Y, cp2X, cp2Y, x, y] for Bezier curve to with start and end control points followed by the destination point
// see the ZIM Shape docs (or https://www.createjs.com/docs/easeljs/classes/Graphics) for details on the curves
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
setPoints(a, b, c, d) - pass in two ZIM Points or four numbers to set start points and end points or an array of points
this will not change the x and y of the shape
also see startPoint, endPoint, startX, startY, endX, endY properties
if an array is used the points are remade like when made with the points parameter
from(a, b) - pass in a ZIM Point or two numbers to set the start point
to(a, b) - pass in a ZIM Point or two numbers to set the end point
setColorRange(color1, color2) - set a color range for shape - used by colorRange property - returns obj for chaining
if one color is used, the current color is used and color1 is the second color in the range
cache(see Container docs for parameter description) - overrides CreateJS cache() and returns object for chaining
Leave parameters blank to cache bounds of shape (plus outer edge of border if borderWidth > 0)
hasProp(property as String) - returns true if property exists on object else returns false
clone(exact) - makes a copy of the shape
exact (default false) ZIM VEE (Pick) values are active in clones unless exact is set to true
For instance, if the object's color is [blue, green]
then its clone might be blue or green - which could be different than the original
If exact is set to true then the clone will be the color of the original object
cloneAll(exact style, group, inherit) - copies shape and any custom content in shape - experimental - usually shapes do not have content (use a Container)
exact (default false) in theory will copy ZIM VEE values as they are in the original
see main class for style, group, inherit parameters
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
** below will not change the x and y of the shape
** if points is being used: length, startPoint, start and end X and Y, endPoint and angle are ignored - use the point property
length - gets or sets the length of the line - will grow from its registration point
startPoint - (ZIM Point or x,y object) get or set the start point
startX - get or set the start x point - allows for animation
startY - get or set the start y point - allows for animation
endPoint - (ZIM Point or x,y object) get or set the end point
endX - get or set the end x point - allows for animation
endY - get or set the end y point - allows for animation
startHead - get or set the start head - see startHead parameter
endHead - get or set the end head - see endHead parameter
angle - gets (not sets) the current angle relative to the line (does not include line rotation)
points - get and set the points array (see points parameter) - ignoring all settings above
** above will not change the x and y of the shape
shape - gives access to the line shape
color - get and set the fill color
colorRange - if setColorRange() is used, the colorRange is a ratio (0-1) between the colors
setting the colorRange will change the color property of the shape
for instance, shape.setColorRange(blue, pink) then shape.colorRange = .5
will set the color of the shape to half way between blue and pink
shape.animate({color:red}, 1000); is a shortcut to animate the colorRange
shape.wiggle("colorRange", .5, .2, .5, 1000, 5000) will wiggle the colorRange
colorCommand - access to the CreateJS fill command for bitmap, linearGradient and radialGradient fills
depreciated - see ZIM GradientColor, RadialColor and BitmapColor
thickness - get and set the stroke size in pixels
thicknessCommand - access to the CreateJS stroke style command (width, caps, joints, miter, ignoreScale)
See: https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeStyle.html
dashed - get and set the dashed - use true / false or an array (see dashed parameter)
dashedOffset - get and set the offset of the dash (50 default) - can animate this property for a marquee effect
borderDashedCommand - access to the CreateJS stroke dashed command (segments, offset)
see https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeDash.html
lineType - read only access to type of line "straight", "corner", "curve"
mouseChildren - set to false to avoid dragging the shape inside
to drag or interact with objects inside then set mouseChildren to true
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+53.15
zim.Line = function(length, thickness, color, startHead, endHead, dashed, strokeObj, lineType, lineOrientation, curveH, curveV, points, style, group, inherit) {
var sig = "length, thickness, color, startHead, endHead, dashed, strokeObj, lineType, lineOrientation, curveH, curveV, points, style, group, inherit";
var duo; if (duo = zob(zim.Line, arguments, sig, this)) return duo;
z_d("53.15");
this.zimCustomShape_constructor(null,null,null,null,false);
this.type = "Line";
this.group = group;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
if (zot(length)) length = DS.length!=null?DS.length:100;
if (zot(dashed)) dashed = DS.dashed!=null?DS.dashed:false;
if (zot(thickness)) thickness = DS.thickness!=null?DS.thickness:3;
if (zot(color)) color = DS.color!=null?DS.color:"black";
if (zot(startHead)) startHead = DS.startHead!=null?DS.startHead:null;
if (zot(endHead)) endHead = DS.endHead!=null?DS.endHead:null;
if (zot(strokeObj)) strokeObj = DS.strokeObj!=null?DS.strokeObj:{};
if (zot(lineType)) lineType = DS.lineType!=null?DS.lineType:"straight";
if (lineType !== "corner" && lineType != "curve") lineType = "straight";
if (zot(lineOrientation)) lineOrientation = DS.lineOrientation!=null?DS.lineOrientation:"auto";
if (lineOrientation !== "vertical" && lineOrientation != "horizontal") lineOrientation = "auto";
if (zot(curveH)) curveH = DS.curveH!=null?DS.curveH:20;
if (zot(curveV)) curveV = DS.curveV!=null?DS.curveV:20;
if (zot(strokeObj)) strokeObj = DS.strokeObj!=null?DS.strokeObj:{};
// PICK
var oa = remember(length, color, thickness, startHead, endHead);
function remember() {return arguments;} // for cloning PICK
length = zim.Pick.choose(length);
color = zim.Pick.choose(color);
thickness = zim.Pick.choose(thickness);
startHead = zim.Pick.choose(startHead);
endHead = zim.Pick.choose(endHead);
// do below otherwise will be the same head and get moved if cloned
if (startHead && startHead.clone) startHead = startHead.clone();
if (endHead && endHead.clone) endHead = endHead.clone();
var that = this;
that._length = length;
that._color = color;
that._thickness = thickness;
that._dashed = dashed;
if (that._dashed && !Array.isArray(that._dashed)) that._dashed = [10, 10];
that._startX = 0;
that._startY = 0;
that._endX = length;
that._endY = 0;
that._startHead = startHead;
that._endHead = endHead;
that._points = points;
that._lineOrientation = lineOrientation;
that.angle = 0;
that.lineType = lineType;
var startRegY;
if (that._startHead) prepareHead("start", that._startHead);
if (that._endHead) prepareHead("end", that._endHead);
function prepareHead(type, head) {
if (head == "triangle" || head == "arrow") {
var h = that["_"+type+"Head"] = new zim.Triangle(thickness*4, thickness*4, thickness*4, color);
h.rotation = 90;
} else if (head == "circle") {
that["_"+type+"Head"] = new zim.Circle(thickness*2.2, color);
}
if (zot(that["_"+type+"Head"].startAngle)) that["_"+type+"Head"].startAngle = that["_"+type+"Head"].rotation;
}
startHead = that._startHead;
endHead = that._endHead;
if (startHead && startHead.type == "Triangle") startHead.startRegY = startHead.regY;
if (endHead && endHead.type == "Triangle") endHead.startRegY = endHead.regY;
var shape = this.shape = new createjs.Shape();
this.addChild(shape);
var g = shape.graphics;
that.drawShape = function(arrowAdjustStart, arrowAdjustEnd) {
g.c();
that.colorCommand = g.s(that._color).command;
if (color && color.type) that.specialColor(that.colorCommand, color);
that.thicknessCommand = g.ss(that._thickness, strokeObj.caps, strokeObj.joints, strokeObj.miterLimit, strokeObj.ignoreScale).command;
if (that._dashed) {
that.dashedCommand = g.sd(Array.isArray(that._dashed)?that._dashed:[10, 10], that._dashedOffset).command;
}
var startArrowGuide;
var endArrowGuide;
if (that._points) {
var start = that._points[0];
that._startX = start[0];
that._startY = start[1];
var endPoint = that._points[that._points.length-1];
var end = [endPoint[endPoint.length-2], endPoint[endPoint.length-1]];
that._endX = end[0];
that._endY = end[1];
g.mt(start[0], start[1]);
for (var i=1; i<that._points.length; i++) {
var point = that._points[i];
if (i==1) startArrowGuide = [that._startX, that._startY, point[0], point[1]];
if (point.length==2) g.lt(point[0], point[1]);
else if (point.length==4) g.qt(point[0], point[1], point[2], point[3]);
else if (point.length==6) g.bt(point[0], point[1], point[2], point[3], point[4], point[5]);
}
// end arrow will go along last control line or from last point to penultimate point if no control line
if (point.length >= 4) { // last point in loop
endArrowGuide = [point[point.length-4], point[point.length-3], that._endX, that._endY];
} else {
var penPoint = that._points[that._points.length-2];
endArrowGuide = [penPoint[penPoint.lenth-2], penPoint[penPoint.lenth-1], that._endX, that._endY];
}
} else {
var sX = that._startX;
var sY = that._startY;
var eX = that._endX;
var eY = that._endY;
if (that.lineType == "straight") {
if (startHead && startHead.type == "Triangle") {
startHead.regY = 0;
var d = zim.dist(sX,sY,eX,eY);
if (d != 0) sX = sX + that._startHead.height/2*(eX-sX)/d;
if (d != 0) sY = sY + that._startHead.height/2*(eY-sY)/d;
}
if (endHead && endHead.type == "Triangle") {
endHead.regY = 0;
var d = zim.dist(sX,sY,eX,eY);
if (d != 0) eX = eX - that._endHead.height/2*(eX-sX)/d;
if (d != 0) eY = eY - that._endHead.height/2*(eY-sY)/d;
}
} else {
if (arrowAdjustStart) {
if (that._lineOrientation == "horizontal" || that.autoOrientation == "horizontal") {
if (startHead && startHead.type == "Triangle") {
startHead.regY = 0;
// if (eX > sX) sX += that._startHead.height/2;
// else sX -= that._startHead.height/2;
if (eX > sX) {
sX = Math.min(eX, sX+that._startHead.height/2);
} else {
sX = Math.max(eX, sX-that._startHead.height/2);
}
}
} else {
if (startHead && startHead.type == "Triangle") {
startHead.regY = 0;
// if (eY > sY) sY += that._startHead.height/2;
// else sY -= that._startHead.height/2;
if (eY > sY) {
sY = Math.min(eY, sY+that._startHead.height/2);
} else {
sY = Math.max(eY, sY-that._startHead.height/2);
}
}
}
} else {
if (startHead && startHead.type == "Triangle") startHead.regY = startHead.startRegY;
}
if (arrowAdjustEnd) {
if (that._lineOrientation == "horizontal" || that.autoOrientation == "horizontal") {
if (endHead && endHead.type == "Triangle") {
endHead.regY = 0;
if (eX > sX) eX -= that._endHead.height/2;
else eX += that._endHead.height/2;
}
} else {
if (endHead && endHead.type == "Triangle") {
endHead.regY = 0;
if (eY > sY) eY -= that._endHead.height/2;
else eY += that._endHead.height/2;
}
}
} else {
if (endHead && endHead.type == "Triangle") endHead.regY = endHead.startRegY;
}
}
if (that.lineType == "straight") {
g.mt(sX, sY).lt(eX, eY);
startArrowGuide = endArrowGuide = [sX, sY, eX, eY];
} else if (that.lineType == "corner") {
var midX = sX + (eX-sX)*.4;
var midY = sY + (eY-sY)*.4;
if (that._lineOrientation == "auto") {
that.autoOrientation = (Math.abs(sX-eX) > Math.abs(sY-eY))?"horizontal":"vertical";
}
if (that._lineOrientation == "horizontal" || that.autoOrientation == "horizontal") {
startArrowGuide = endArrowGuide = [sX, sY, midX, sY];
// startArrowGuide = endArrowGuide = [that._startX, that._startY, midX, that._startY];
g.mt(sX, sY).lt(midX, sY).lt(midX, eY).lt(eX, eY);
} else {
startArrowGuide = endArrowGuide = [sX, sY, sX, midY];
// startArrowGuide = endArrowGuide = [that._startX, that._startY, that._startX, midY];
g.mt(sX, sY).lt(sX, midY).lt(eX, midY).lt(eX, eY);
}
} else { // "curve"
var hSign = (sX > eX)?-1:1;
var vSign = (sY > eY)?-1:1;
var nextX = sX; // relative drawing would be handy but not implemente in version yet
var nextY = sY;
var distX = Math.abs(sX - eX);
var distY = Math.abs(sY - eY);
var curveX = Math.min(curveH, distX*.5); // need proportion curve until hits curveH
var curveY = Math.min(curveV, distY*.5);
if (that._lineOrientation == "auto") {
that.autoOrientation = (Math.abs(sX-eX) > Math.abs(sY-eY))?"horizontal":"vertical";
}
if (that._lineOrientation == "horizontal" || that.autoOrientation == "horizontal") {
var insideDistance = (distY-curveY*2);
var outsideDistance = (distX-curveX*2)/2;
g.mt(nextX, nextY);
if (outsideDistance > 0) {
nextX = nextX+outsideDistance*hSign;
g.lt(nextX, nextY);
}
var lastY = nextY;
nextY = nextY+curveY*vSign;
nextX = nextX+curveX*hSign;
g.qt(nextX, lastY, nextX, nextY);
startArrowGuide = endArrowGuide = [sX, sY, nextX, sY];
if (insideDistance > 0) {
nextY = nextY+insideDistance*vSign;
g.lt(nextX, nextY);
}
nextY = nextY+curveY*vSign;
var lastX = nextX;
nextX = nextX+curveX*hSign;
g.qt(lastX, nextY, nextX, nextY);
if (outsideDistance > 0) {
nextX = nextX+outsideDistance*hSign;
g.lt(nextX, nextY);
}
} else {
var insideDistance = (distX-curveX*2);
var outsideDistance = (distY-curveY*2)/2;
g.mt(nextX, nextY);
if (outsideDistance > 0) {
nextY = nextY+outsideDistance*vSign;
g.lt(nextX, nextY);
}
var lastX = nextX;
nextX = nextX+curveX*hSign;
nextY = nextY+curveY*vSign;
g.qt(lastX, nextY, nextX, nextY);
startArrowGuide = endArrowGuide = [sX, sY, sX, nextY];
if (insideDistance > 0) {
nextX = nextX+insideDistance*hSign;
g.lt(nextX, nextY);
}
nextX = nextX+curveX*hSign;
var lastY = nextY;
nextY = nextY+curveY*vSign;
g.qt(nextX, lastY, nextX, nextY);
if (outsideDistance > 0) {
nextY = nextY+outsideDistance*vSign;
g.lt(nextX, nextY);
}
}
}
}
that.setBounds(Math.min(that._startX, that._endX),Math.min(that._startY, that._endY),Math.abs(that._startX-that._endX),Math.abs(that._startY-that._endY));
that._length = Math.sqrt(Math.pow(that._startX-that._endX,2) + Math.pow(that._startY-that._endY,2));
that.angle = Math.atan2(that._endY-that._startY, that._endX-that._startX) * 180 / Math.PI;
if (that._startHead && that._startHead.loc) {
that._startHead.loc(that._startX, that._startY, that);
var startAngle = Math.atan2(startArrowGuide[3]-startArrowGuide[1], startArrowGuide[2]-startArrowGuide[0]) * 180 / Math.PI;
that._startHead.rotation = startAngle-180+that._startHead.startAngle;
}
if (that._endHead && that._endHead.loc) {
that._endHead.loc(that._endX, that._endY, that);
var endAngle = Math.atan2(endArrowGuide[3]-endArrowGuide[1], endArrowGuide[2]-endArrowGuide[0]) * 180 / Math.PI;
that._endHead.rotation = endAngle+that._endHead.startAngle;
}
};
that.drawShape();
this.setPoints = function(a, b, c, d, arrowAdjustStart, arrowAdjustEnd) {
if (Array.isArray(a) && zot(b)) {
that.points = a;
return that;
} else if (a && !zot(a.x)) {
that._startX = zot(a.x)?that._startX:a.x;
that._startY = zot(a.y)?that._startY:a.y;
if (b) {
that._endX = zot(b.x)?that._endX:b.x;
that._endY = zot(b.y)?that._endY:b.y;
}
} else {
that._startX = zot(a)?that._startX:a;
that._startY = zot(b)?that._startY:b;
that._endX = zot(c)?that._endX:c;
that._endY = zot(d)?that._endY:d;
}
that.drawShape(arrowAdjustStart, arrowAdjustEnd);
return that;
};
this.from = function(a, b) {
if (a && !zot(a.x)) {
that._startX = zot(a.x)?that._startX:a.x;
that._startY = zot(a.y)?that._startY:a.y;
} else {
that._startX = zot(a)?that._startX:a;
that._startY = zot(b)?that._startY:b;
}
that.drawShape();
return that;
};
this.to = function(a, b) {
if (a && !zot(a.x)) {
that._endX = zot(a.x)?that._endX:a.x;
that._endY = zot(a.y)?that._endY:a.y;
} else {
that._endX = zot(a)?that._endX:a;
that._endY = zot(b)?that._endY:b;
}
that.drawShape();
return that;
};
Object.defineProperty(that, 'length', {
get: function() {
return that._length;
},
set: function(value) {
var s = that.length!=0 ? value/that.length : 0;
if (isNaN(s)) return;
var startScaleX = that.scaleX;
var startScaleY = that.scaleY;
that.scaleX *= s;
that.scaleY *= s;
var gStart = that.localToGlobal(that._startX, that._startY);
var gEnd = that.localToGlobal(that._endX, that._endY);
that.scaleX = startScaleX;
that.scaleY = startScaleY;
var lStart = that.globalToLocal(gStart.x, gStart.y);
var lEnd = that.globalToLocal(gEnd.x, gEnd.y);
that.setPoints(lStart, lEnd);
}
});
Object.defineProperty(that, 'startPoint', {
get: function() {
return new zim.Point(that._startX, that._startY);
},
set: function(value) {
that._startX = zot(value.x)?that._startX:value.x;
that._startY = zot(value.y)?that._startY:value.y;
that.drawShape();
}
});
Object.defineProperty(that, 'endPoint', {
get: function() {
return new zim.Point(that._endX, that._endY);
},
set: function(value) {
that._endX = zot(value.x)?that._endX:value.x;
that._endY = zot(value.y)?that._endY:value.y;
that.drawShape();
}
});
Object.defineProperty(that, 'startHead', {
get: function() {
return that._startHead;
},
set: function(value) {
that._startHead = value;
that.drawShape();
}
});
Object.defineProperty(that, 'endHead', {
get: function() {
return that._endHead;
},
set: function(value) {
that._endHead = value;
that.drawShape();
}
});
Object.defineProperty(that, 'startX', {
get: function() {
return that._startX;
},
set: function(value) {
that._startX = value||0;
that.drawShape();
}
});
Object.defineProperty(that, 'startY', {
get: function() {
return that._startY;
},
set: function(value) {
that._startY = value||0;
that.drawShape();
}
});
Object.defineProperty(that, 'endX', {
get: function() {
return that._endX;
},
set: function(value) {
that._endX = value||0;
that.drawShape();
}
});
Object.defineProperty(that, 'endY', {
get: function() {
return that._endY;
},
set: function(value) {
that._endY = value||0;
that.drawShape();
}
});
Object.defineProperty(that, 'points', {
get: function() {
return that._points;
},
set: function(value) {
if (!value) return;
that._points = value;
that.drawShape();
}
});
Object.defineProperty(that, 'lineOrientation', {
get: function() {
return that._lineOrientation;
},
set: function(value) {
if (!value) return;
that._lineOrientation = value;
that.drawShape();
}
});
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NOTE: extends ZIM CustomShape for more properties and a few functions.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (style!==false) zim.styleTransforms(this, DS); // global function - would have put on DisplayObject if had access to it
this.clone = function(exact, container) {
var startH = (exact||!zim.isPick(oa[3]))?that._startHead:oa[3];
if (startH) {
if (startH.clone) {
startH = startH.clone();
startH.rotation = that._startHead.startAngle;
}
}
var endH = (exact||!zim.isPick(oa[4]))?that._endHead:oa[4];
if (endH) {
if (endH.clone) {
endH = endH.clone();
endH.rotation = that._endHead.startAngle;
}
}
var newShape = that.cloneProps(new zim.Line((exact||!zim.isPick(oa[0]))?that.length:oa[0], (exact||!zim.isPick(oa[2]))?that.thickness:oa[2], (exact||!zim.isPick(oa[1]))?that.color:oa[1], startH, endH, that.dashed, strokeObj, lineType, that._lineOrientation, curveH, curveV, zim.copy(points), style, this.group, inherit));
if (that.points) newShape.setPoints(that.points);
else newShape.setPoints(that._startX, that._startY, that._endX, that._endY);
if (that.linearGradientParams) newShape.linearGradient.apply(newShape, that.linearGradientParams);
if (that.radialGradientParams) newShape.radialGradient.apply(newShape, that.radialGradientParams);
return newShape;
};
};
zim.extend(zim.Line, zim.CustomShape, "clone", "zimCustomShape", false);
//-53.15
/*--
zim.Squiggle = function(color, thickness, points, length, controlLength, controlType, lockControlType, showControls, lockControls, handleSize, allowToggle, move, dashed, onTop, stickColor, selectColor, selectPoints, editPoints, interactive, strokeObj, style, group, inherit)
Squiggle
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
Makes a squiggly line with a number of points.
The points have Bezier controls - little handles that change the shape of the line.
The type of control can be specified overall and individually - and can be hidden or shown
The type of control can be changed by double clicking the point - colors of the handles will change
Points can be added by clicking on the line or removed by SHIFT clicking a point.
CTRL Z will undo adding or removing a point
The shape of the line can be recorded with the recordData() method and recreated with the setData() method
The Squiggle is set by default to show and hide controls when clicked
It is also draggable by default when the controls are showing
It can be set to copy with a shift click
MULTIPLE SELECT
Multiple points can be selected and dragged or moved with the keyboard arrows (moves 10 pixels with shift key down)
NOTE: mouseChildren is turned to false for all zim Shape containers.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var squiggle = new Squiggle().center(); // makes a line with default 4 points with Bezier controls
var line = new Squiggle({points:2, controlType:"none"}).pos(100,100); // makes a diagonal straight line that is editable
END EXAMPLE
EXAMPLE
// Animate along a Squiggle
// see https://zimjs.com/explore/squiggleAnimate.html for more
var line = new Squiggle().center();
new Circle(10, red).addTo().animate({path:line}, 1000);
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports VEE - parameters marked with ZIM VEE mean a zim Pick() object or Pick Literal can be passed
Pick Literal formats: [1,3,2] - random; {min:10, max:20} - range; series(1,2,3) - order, function(){return result;} - function
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
color - |ZIM VEE| - (default green) the line color as any CSS color including "rgba()" for alpha
thickness - (default 2) the thickness of the line in pixels
points - (default 5) a number of points to start with to make the shape
OR an SVG path like: points:"M0,129.5c22,0,40-31,40-41c0-8-3.2-13-10-13" etc. (also see SVGContainer)
OR an array of points as follows:
[[controlX, controlY, circleX, circleY, rect1X, rect1Y, rect2X, rect2Y, controlType], [etc]]
controlX and controlY - the x and y location of the control Container which holds the point circle and the two control rectangles
rect1X, rect1Y, rect2X, rect2Y - (default based on controlLength) the x and y location of the control rectangles relative to the control location
circleX and circleY - (default 0) the x and y location of the circle relative to the control location (usually 0, 0)
controlType - (default main controlType parameter or "straight" if not controlType parameter) the point's controlType "none", "mirror", "straight" or "free"
length - (default 300) the default length of line used to create the squiggle (also specifies the squiggle's bounds(0, 0, length, thickness))
controlLength - |ZIM VEE| (default radius*numPoints/4) specify a Number to override the calculated default
controlType - (default "straight") one of four String values as follows:
none - there are no control rectangles (they are actually set at 0,0). This makes a corner at the circle point.
mirror - the control rectangles reflect one another about the point circle - lengths are kept even
straight - the control rectangles keep a straight line through the point circle but length is independent
free - the control rectangle moves independently from the other control rectangle
** The controlType can be specified for each point - see the points parameter
** The controlType can be changed by doubleClicking the point circle to cycle through the controls in the order above - unless the lockControlType is set to true
lockControlType - (default false) set to true to disable doubleClicking of point circles to change controlType
showControls - (default true) set to false to start with controls not showing - can change this after with controlsVisible property or showControls() and hideControls() methods
lockControls - (default false) set to true to lock the editing of controls - can't move the points or handles - but can see them if showControls is set to true
handleSize - (default 20 mobile 10 for non-mobile) the size of control boxes and affects the circles too proportionally
allowToggle - (default true) set false to let turn off clicks showing and hiding controls
move - (default true) set to false to disable dragging when controls are showing
can also set to "always" to allow movement when controls are not showing
dashed - (default false) set to true for dashed border (if borderWidth or borderColor set)
or set to an array of line size then space size, etc.
eg. [20, 10] is 20 line and 10 space repeated and [20,100,50,10] is 20 line, 100 space, 50 line, 10 space, etc.
onTop - (default true) set to false to not bring shape to top of container when dragging
stickColor - (default "#111") set the stick color of the controls
selectColor - (default white) the color of the selected circle or rectangle of the controls if selectPoints is true
selectPoints - (default true) set to false to not allow point controls to be selected for keyboard control
editPoints - (default true) lets user add points by pressing on shape path or remove points by shift click or hold
set to "anywhere" to let users add points anywhere - will add points with controlType:"none"
set to false to not allow adding or removing points with shift click or hold
interactive - (default true) set to false to turn off controls, move, toggle, select, edit - leaving just the shape
strokeObj - (default {caps:"butt", joints:"miter", miterLimit:10, ignoreScale:false}) set to adjust stroke properties
caps options: "butt", "round", "square" or 0,1,2
joints options: "miter", "round", "bevel" or 0,1,2
miterLimit is the ration at which the mitered joint will be clipped
ignoreScale set to true will draw the specified line thickness regardless of object scale
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
approximateBounds(num, showPoints, margin) - update the bounds based on a Rectangle
that surrounds the number of points (default 80) distributed around the object path
set showPoints to true to draw little dots on points
margin increases (or if negative decreases) the bounds on all sides by the margin
use outline() after object has been added to the stage to see the bounds
addPoint(percent, controlType) - add a point at a percent (100) of the total curve
this is handy to make path have the same number of points for animate() path tweens
controlType can be as specified in main points parameter
returns object for chaining
addPoints(num, controlType, startPoint, spread, dataOnly, points) - add num points between existing points
controlType can be as specified in main points parameter
specify a startPoint to add points between the startPoint and the next point (one segment of points)
spread (default false) set to true to spread points evenly around path rather than evenly between segments
dataOnly and points are used internally
returns object for chaining
interpolate(num, startPoint, spread, points, even) - get point data {x,y} for existing points and num (default 1) points inbetween
used with hitTestPath() and animate() drag on path - also add points (note add points does not use even:true)
specify a startPoint to get points between the startPoint and the next point (one segment of points)
spread (default false) set to true to spread number of points around path rather equal number between segments
points (default all points) the points to work with in the same format as the points property
even (default false) set to true to use zim.Bezier() with even turned on for even percentage distribution
returns an array of point objects with x, y properties and an r property for ratio of distance along path
recordData(toJSON) - returns an object with x, y, points, color, borderColor, borderWidth, move, toggle, controls PROPERTIES to be used with setData() method
if toJSON (default false) is set to true, the return value is a JSON string
the points data comes from the points property
setData(data, fromJSON) - sets the properties to match the data object passed in - this should come from recordData()
if fromJSON (default false) is set to true, it will assume a JSON string is passed in as data
the points data is parsed with the set setPoints() so the number of points should be the same
returns object for chaining
recordPoints(popup) - returns an array with the same format as the points parameter - or can just use points property
popup - (default false) set to true to open a zim Pane (squiggle.pane) with the points in a zim TextArea (squiggle.textArea) (click off to close)
NOTE: the TextArea output uses JSON.stringify() - to add the points to the points parameter of the Squiggle use JSON.parse(output);
NOTE: using zog(JSON.stringify(squiggle.recordData()))... the console will remove the quotes from the controlTypes so those would have to be manually put back in before parse() will work
setPoints(data) - sets the Squiggle points to the data from recordPoints
This does not remake the Squiggle but rather shifts the controls so the number of points should be the same
changeControl(index, type, rect1X, rect1Y, rect2X, rect2Y, circleX, circleY, update) - change a control type and properties at an index
accepts ZIM DUO normal parameters or configuration object literal with parameter names as propterties
passing in null as the index will change all points to the specified properties
the update parameter defaults to false so set to true to show update or call update() below
this is so multiple changes can be batched before calling update - for instance when animating blobs.
transformPoints(transformType, amount, x, y) - scale, rotate, move points without affecting controls or borderWidth - returns object for chaining
Note - does not adjust original Bounds
transformType - String any of: "scale", "scaleX", "scaleY", "rotation", "x", "y"
amount - the amount to transform
x, y - (default 0, 0) the x and y position to transform about
update(normalize) - update the Squiggle if animating control points, etc. would do this in a Ticker
set normalize (default false) to true to use pointsAdjusted for rotated and scaled points
and if animating along the path after setting rotation or scale on point
just leave out if only animating points
showControls() - shows the controls (and returns squiggle) also see controlsVisible property
hideControls() - hides the controls (and returns squiggle) also see controlsVisible property
toggle(state - default null) - shows controls if hidden and hides controls if showing (returns the object for chaining)
or pass in true to show controls or false to hide controls
traverse(obj, start, end, time) - animates obj from start point to end point along path - thanks KV for the thought!
set start point greater than end point to traverse backwards
will dispatch a "traversed" event when done
setColorRange(color1, color2) - set a color range for shape - used by colorRange property - returns obj for chaining
if one color is used, the current color is used and color1 is the second color in the range
getPointAngle(index) - gets the angle made by the tangent at the index provided
getSegmentPoint(point1, point2) - returns an array of [point1, controlPoint1, controlPoint2, point2]
used internally for animating to path and adding removing Bezier points
getAdjacentSegmentData(index) - returns an array of two arrays:
The first is an array of cubic Bezier points for segments adjacent and including the provided point index
each element is in the form of [point1, controlPoint1, controlPoint2, point2]
The second is an array of starting point indexes for the segments that were tested
used internally to drag an animation along the path
getCurvePoint(ratio, segmentRatios, segmentPoints, getAngle) gets a point along whole curve at the ratio (0-1) provided
along with x and y values, the point has a z value that is the index of the squiggle point before the calculated point
if the getAngle parameter is true (default false) the point also has an angle property which is the angle of the tangent at the point
ratio is 0-1 with 0 being at the first point and 1 being at the end of the last segment
segmentRatios and segmentPoints will be calculated if not provided
used internally for animating along the path - if lockControls is true, only animate will precalculate these values
linearGradient([colors],[ratios], x0,y0, x1,y1) - shortcut to thicknessCommand linearGradient method (see properties below)
radialGradient([colors],[ratios], x0,y0,radius0, x1,y1,radius1) - shortcut to thicknessCommand radialGradient method (see properties below)
cache(see Container docs for parameter description) - overrides CreateJS cache() and returns object for chaining
Leave parameters blank to cache bounds of shape (plus outer edge of border if borderWidth > 0)
hasProp(property as String) - returns true if property exists on object else returns false
clone(exact, commands) - makes a copy of the object
exact (default false)
ZIM VEE (Pick) values are active in clones unless exact is set to true
For instance, if the object's color is [blue, green]
then its clone might be blue or green - which could be different than the original
If exact is set to true then the clone will be the color of the original object
commands (default false) makes clones with current color and borderColor commands of object
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
shape - gives access to the shape of the squiggle
color - get and set the fill color
colorRange - if setColorRange() is used, the colorRange is a ratio (0-1) between the colors
setting the colorRange will change the color property of the shape
for instance, shape.setColorRange(blue, pink) then shape.colorRange = .5
will set the color of the shape to half way between blue and pink
shape.animate({color:red}, 1000); is a shortcut to animate the colorRange
shape.wiggle("colorRange", .5, .2, .5, 1000, 5000) will wiggle the colorRange
stickColor - get or set the stickColor - requires an update() to see changes
colorCommand - access to the CreateJS fill command for bitmap, linearGradient and radialGradient fills
eg. shape.colorCommand.linearGradient([green, blue ,green], [.2, .5, .8], 0, 0, shape.width, 0)
See: https://www.createjs.com/docs/easeljs/classes/Graphics.Fill.html
thickness - get and set the stroke size in pixels
thicknessCommand - access to the CreateJS stroke style command (width, caps, joints, miter, ignoreScale)
See: https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeStyle.html
dashed - get and set the dashed - use true / false or an array (see dashed parameter)
dashedOffset - get and set the offset of the dash (50 default) - can animate this property for a marquee effect
dashedCommand - access to the CreateJS stroke dashed command (segments, offset)
see https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeDash.html
num - get the number of points - to set, use the points property
points - get or set the points array of the Squiggle in the same format as the points parameter:
[[controlX, controlY, circleX, circleY, rect1X, rect1Y, rect2X, rect2Y, controlType], [etc]]
pointsAdjusted - get points with any point rotation converted to 0 - see update(true)
pointControls - get an array of controls (a container) - use this to animate controls
pointCircles - get an array of control circles - use this to place some other object at the point
pointObjects - get an array of point objects for each point in the following format:
[[control, circle, rect1, rect2, controlType], [etc.]]
control - the container for the control that holds the circle and rectangles (also see pointControls)
circle - the control point circle (also see pointCircles)
rect1 - the first control point rectangle
rect2 - the second control point rectangle
controlType - the control type: default is "straight" (or null) and there is also "mirror", "free" and "none"
NOTE: control, circle, rect1, rect2 can be positioned or animated and controlType can be changed
NOTE: the update() method must be called if manually changing the control positions or type
NOTE: if constantly animating the controls then use a Ticker.add(function(){squiggle.update();})
NOTE: also see recordData(), setData(), recordPoints(), setPoints() methods for further options
addPointFactor - (default 20) used when placing new points along edge (editPoints is true)
divides the distance between points by this amount - the smaller the more accurate but also slower
addMinDistance - (default 15) edge press needs to be within this distance to add a point to the edge
segmentPoints - a read-only array of cubic Bezier points for each segment
each element is in the form of [point1, controlPoint1, controlPoint2, point2]
used internally to animate to the path and add and remove Bezier points
segmentRatios - a read-only array of cumulative ratio lengths of segments
for instance the default five points (four segments) is [.25, .5, .75, 1]
used internally to animate to the path and attribute proportional time to each segment
controls - access to the container that holds the sets of controls
each control is given a read-only num property
sticks - access to the container that holds the control sticks
lastSelected - access to the last selected (or created) control container
lastSelectedIndex - the index number of the last selected controls
controlsVisible - get or set the visibility of the controls - or use showControls() and hideControls()
toggled - read-only Boolean property as to whether picker is showing
types - get or set the general array for the types ["mirror", "straight", "free", "none"]
changing this or removing a type will adjust the order when the user double clicks the points to change their type
this is not an array of types for each point - see the points property to access the types of each point
lockControls - Boolean to lock controls from being adjusted or not
lockControlType - Boolean to lock the type of the controls in their current state or not
allowToggle - Boolean to get or set clicking to show and hide controls
move - Boolean to drag or not drag Squiggle when controls are showing
can also set to "always" to allow movement when controls are not showing
onTop - get or set the onTop
selectPoints - get or set whether points can be selected
interactive - get or set whether the shape is interactive - toggle, move, change or add controls, etc.
keyFocus - get or set the keyboard focus on the DisplayObject - see also zim.KEYFOCUS
will be set to true if this DisplayObject is the first made or DisplayObject is the last to be used with keyboard
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
dispatches a "change" event for when the bezier controls are adjusted (pressup only)
if monitoring constant change is needed add a pressmove event to Squiggle.controls
the change event object has a transformType property with values of "move", "bezierPoint", "bezierHandle", "bezierSwitch"
dispatches "controlsshow" and "controlshide" events when clicked off and on and toggle is true
dispatches an "update" event if the points are changed or a point is added or removed
this removes all listeners on the old shape and controls
so any custom listeners on shape and controls will need to be re-applied - use the update event to do so
dispatches a "traversed" event when traverse() is done - the event object has an obj property for the traversing object
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
MORE
https://zimjs.com/squiggle
https://www.youtube.com/watch?v=BA1bGBU4itI&list=PLCIzupgRt1pYtMlYPtNTKCtztFBeOtyc0
Note the points property has been split into points and pointObjects (and there have been a few property changes) since the time of the video
--*///+53.2
zim.Squiggle = function(color, thickness, points, length, controlLength, controlType, lockControlType, showControls, lockControls, handleSize, allowToggle, move, dashed, onTop, stickColor, selectColor, selectPoints, editPoints, interactive, strokeObj, style, group, inherit) {
var sig = "color, thickness, points, length, controlLength, controlType, lockControlType, showControls, lockControls, handleSize, allowToggle, move, dashed, onTop, stickColor, selectColor, selectPoints, editPoints, interactive, strokeObj, style, group, inherit";
var duo; if (duo = zob(zim.Squiggle, arguments, sig, this)) return duo;
z_d("53.2");
this.group = group;
var DS = style===false?{}:zim.getStyle("Squiggle", this.group, inherit);
if (zot(thickness)) thickness = DS.thickness!=null?DS.thickness:6;
if (zot(length)) length = DS.length!=null?DS.length:300;
if (zot(points)) points = DS.points!=null?DS.points:5;
if (typeof points == "string") {
var svgProcessor = new zim.SVGContainer();
points = svgProcessor.processPath(points);
}
var num = typeof points == "number" ? points : points.length;
if (num == 0) return;
if (zot(controlLength)) controlLength = DS.controlLength!=null?DS.controlLength:(length / num);
this.zimCustomShape_constructor(length, controlLength, null, null, false);
this.type = "Squiggle";
this.mouseChildren = true; // set to false in CustomShape
if (zot(dashed)) dashed = DS.dashed!=null?DS.dashed:false;
if (zot(color)) color = DS.color!=null?DS.color:zim.blue;
if (color.style) {this.colorCommand = color; color = "black";}
if (zot(controlType)) controlType = DS.controlType!=null?DS.controlType:null;
var originalControlType = controlType;
if (zot(controlType)) controlType = "mirror";
if (zot(lockControlType)) lockControlType = DS.lockControlType!=null?DS.lockControlType:false;
if (zot(interactive)) interactive = DS.interactive!=null?DS.interactive:true;
if (zot(showControls)) showControls = DS.showControls!=null?DS.showControls:interactive;
var _controls = showControls;
if (zot(lockControls)) lockControls = DS.lockControls!=null?DS.lockControls:!interactive;
if (zot(handleSize)) handleSize = DS.handleSize!=null?DS.handleSize:zim.mobile()?20:10;
if (zot(allowToggle)) allowToggle = DS.allowToggle!=null?DS.allowToggle:interactive;
if (zot(move)) move = DS.move!=null?DS.move:interactive;
if (zot(stickColor)) stickColor = DS.stickColor!=null?DS.stickColor:"#111";
if (zot(selectColor)) selectColor = DS.selectColor!=null?DS.selectColor:"#fff";
if (zot(selectPoints)) selectPoints = DS.selectPoints!=null?DS.selectPoints:interactive;
this.stickColor = stickColor;
if (zot(onTop)) onTop = DS.onTop!=null?DS.onTop:true;
if (zot(editPoints)) editPoints = DS.editPoints!=null?DS.editPoints:interactive;
if (zot(strokeObj)) strokeObj = DS.strokeObj!=null?DS.strokeObj:{};
var oa = remember(color);
function remember() {return arguments;} // for cloning PICK
color = zim.Pick.choose(color);
var that = this;
var stage;
var types = this.types = ["mirror", "straight", "free", "none"];
this.interactive = interactive;
this.num = num;
this.onTop = onTop;
this.move = move;
this.editPoints = editPoints;
this.allowToggle = allowToggle;
this.lockControlType = lockControlType;
this.selectPoints = selectPoints;
this.lockControls = lockControls;
var _points;
var _pointCircles;
var _pointControls;
that._color = color;
that._thickness = thickness;
that._dashed = dashed;
if (that._dashed && !Array.isArray(that._dashed)) that._dashed = [10, 10];
var shape;
var moveDownEvent;
var movePressEvent;
var moveUpEvent;
var draggingCheck = that.move;
var min = 2; // min distance within which a click will add a point
var mapMove;
var sets;
if (originalControlType && typeof points != "number") {
// override controlType
zim.loop(points, function(point) {
point[8]=originalControlType;
if (originalControlType == "none") {
point[4]=point[5]=point[6]=point[7]=0;
}
});
}
init();
function init() {
if (sets) sets.removeAllEventListeners();
that.num = num = typeof points == "number" ? points : points.length;
num = Math.max(2,num);
controlLength = length / num;
shape = that.shape = new zim.Shape({style:false}).addTo(that);
var sticks = that.sticks = new zim.Shape({style:false}).addTo(that);
if (handleSize <= 0) sticks.removeFrom();
var g = shape.graphics;
g.c();
var s = sticks.graphics;
s.c();
var ballS = handleSize/10*8;
var rectS = handleSize;
if (that.selectPoints) {
that.selectedBalls = new zim.SelectionSet();
that.selectedRect1s = new zim.SelectionSet();
that.selectedRect2s = new zim.SelectionSet();
that.selectionManager = new zim.SelectionManager([
that.selectedBalls,
that.selectedRect1s,
that.selectedRect2s
], "ctrl", false);
} else {
that.selectionManager = new zim.SelectionManager(null, "ctrl");
}
var mobile = zim.mobile();
sets = that.controls = new zim.Container({style:false}).addTo(that); // sets - a set contains a ball and two rects
if (that.interactive) sets.drag({onTop:!mobile});
_points = [];
_pointControls = [];
_pointCircles = [];
var angle, point, temp, set, rect1, rect2, ball, type, setInfo;
for (var i=0; i<num; i++) {
set = new zim.Container({style:false}).addTo(sets);
set.num = i;
if (typeof points == "number") { // no sets yet
var stickLength = zim.Pick.choose(controlLength);
temp = new zim.Container(stickLength, thickness, null, null, false).addTo(that).loc({x:i*length/(num-1)-stickLength/2, y:i%2*stickLength});
ball = new zim.Circle(ballS, that.selectPoints&&that.selectedBalls.isSelected(i)?selectColor:zim.light, zim.dark, 2, null, null, null, null, false)
.centerReg(temp)
.loc({x:stickLength/2, y:0});
rect1 = new zim.Rectangle(rectS, rectS, that.selectPoints&&that.selectedRect1s.isSelected(i)?selectColor:getBackgroundColor(controlType), handleSize==0?null:zim.dark, handleSize==0?null:2, null, null, null, false)
.centerReg(temp)
.loc({x:0,y:0});
rect2 = new zim.Rectangle(rectS, rectS, that.selectPoints&&that.selectedRect2s.isSelected(i)?selectColor:getBackgroundColor(controlType), handleSize==0?null:zim.dark, handleSize==0?null:2, null, null, null, false)
.centerReg(temp)
.loc({x:stickLength,y:0});
var ballPoint = temp.localToLocal(ball.x, ball.y, sets);
ball.x = ballPoint.x;
ball.y = ballPoint.y;
ball.addTo(set, null, false);
var rect1Point = temp.localToLocal(rect1.x, rect1.y, sets);
rect1.x = controlType=="none"?0:rect1Point.x-ball.x;
rect1.y = controlType=="none"?0:rect1Point.y-ball.y;
rect1.addTo(set, null, false);
var rect2Point = temp.localToLocal(rect2.x, rect2.y, sets);
rect2.x = controlType=="none"?0:rect2Point.x-ball.x;
rect2.y = controlType=="none"?0:rect2Point.y-ball.y;
rect2.addTo(set, null, false);
set.x = ball.x;
set.y = ball.y;
ball.x = 0;
ball.y = 0;
if (controlType=="none") ball.addTo(set, null, false); // on top
} else { // passing in set data
// _pointCircles are relative to squiggle but handles are relative to ball
// points is an array of [[setX, setY, ballX, ballY, handleX, handleY, handle2X, handle2Y, type], etc.]
setInfo = points[i];
type = setInfo[8] ? setInfo[8] : controlType;
set.loc({x:setInfo[0], y:setInfo[1]});
ball = new zim.Circle(ballS, zim.light, zim.dark, 2, null, null, null, null, false)
.centerReg({add:false})
.addTo(set)
.loc({x:setInfo[2],y:setInfo[3]});
rect1 = new zim.Rectangle(rectS, rectS, getBackgroundColor(type), handleSize==0?null:zim.dark, handleSize==0?null:2, null, null, null, false)
.centerReg({add:false})
.addTo(set, 0)
.loc({x:setInfo[4],y:setInfo[5]});
rect2 = new zim.Rectangle(rectS, rectS, getBackgroundColor(type), handleSize==0?null:zim.dark, handleSize==0?null:2, null, null, null, false)
.centerReg({add:false})
.addTo(set, 0)
.loc({x:setInfo[6],y:setInfo[7]});
}
ball.mySet = set;
ball.rect1 = rect1;
ball.rect2 = rect2;
ball.index = i;
if (mobile) {
ball.on("mousedown", mobileDouble);
} else {
ball.on("dblclick", doubleIt);
}
rect1.ball = ball;
rect1.other = rect2;
rect2.ball = ball;
rect2.other = rect1;
if (handleSize==0) {
ball.expand(10);
rect1.expand(10);
rect2.expand(10);
}
if (mobile) {
ball.expand();
rect1.expand();
rect2.expand();
}
point = [set, ball, rect1, rect2, setInfo?setInfo[8]:controlType];
_points.push(point);
_pointCircles.push(ball);
_pointControls.push(set);
}
var tappedTwice = false;
function mobileDouble(e) {
if (!tappedTwice) {
tappedTwice = true;
setTimeout(function() {
tappedTwice = false;
}, 300);
} else {
e.preventDefault();
doubleIt(e);
}
}
function doubleIt(e) {
if (that.lockControlType) return;
var ball = e.target;
// cycle through the types
var type = _points[ball.index][4] ? _points[ball.index][4] : controlType;
if (Math.abs(ball.rect1.x) <= 2 && Math.abs(ball.rect1.y) <= 2 && Math.abs(ball.rect2.x) <= 2 && Math.abs(ball.rect2.y) <= 2) {
type = "none";
}
if (type == "none") {
ball.parent.addChildAt(ball, 0);
}
// modulus going backwards needs to add the length so it does not go negative
type = that.types[(that.types.indexOf(type)+(that.shiftKey?-1:1)+that.types.length)%that.types.length];
if (type == "none") {
ball.rect1.x = ball.rect1.y = ball.rect2.x = ball.rect2.y = 0;
ball.parent.addChild(ball);
e.stopImmediatePropagation();
}
_points[ball.index][4] = type;
ball.rect1.color = getBackgroundColor(type);
ball.rect2.color = getBackgroundColor(type);
that.drawShape();
var ev = new createjs.Event("change");
ev.controlType = "bezierSwitch";
that.dispatchEvent(ev);
ball.stage.update();
}
function getBackgroundColor(type) {
var colors = {straight:zim.pink, free:zim.yellow, none:zim.blue};
return colors[type] ? colors[type] : zim.purple;
}
that.drawShape = function () {
g.c();
var minThickness = zim.mobile() ? 10 : 6;
if (thickness < minThickness) {
// 1. draw backing grab line
g.s("rgba(0,0,0,.01)").ss(minThickness);
var set = _points[0][0];
var ballPoint = set.localToLocal(_points[0][1].x, _points[0][1].y, shape);
g.mt(ballPoint.x, ballPoint.y);
var currentIndex; var nextIndex;
for (var i=0; i<_points.length; i++) {
var currentIndex = i;
var nextIndex = (i+1)%_points.length;
var set = _points[currentIndex][0];
var ball = _points[currentIndex][1];
var control1 = _points[currentIndex][2];
var control2 = _points[currentIndex][3];
var nextSet = _points[nextIndex][0];
var nextBall = _points[nextIndex][1];
var nextControl1 = _points[nextIndex][2];
var nextControl2 = _points[nextIndex][3];
// var ctype = _points[currentIndex][4]; // STEFAN
var control2Point = set.localToLocal(control2.x, control2.y, shape);
var nextControl1Point = nextSet.localToLocal(nextControl1.x, nextControl1.y, shape);
var nextBallPoint = nextSet.localToLocal(nextBall.x, nextBall.y, shape);
if (i != _points.length-1) {
// if (ctype == 'none') { // STEFAN
// g.lt(nextBallPoint.x, nextBallPoint.y);
// } else {
g.bt(
control2Point.x, control2Point.y,
nextControl1Point.x, nextControl1Point.y,
nextBallPoint.x, nextBallPoint.y
);
// }
}
}
}
// 2. draw real line
if (!that.colorCommand) {
that.colorCommand = g.s(that._color).command;
if (color && color.type) that.specialColor(that.colorCommand, color);
}
if (!that.thicknessCommand) that.thicknessCommand = g.ss(that._thickness, strokeObj.caps, strokeObj.joints, strokeObj.miterLimit, strokeObj.ignoreScale).command;
if (that._dashed) {
if (!that.dashedCommand) that.dashedCommand = g.sd(Array.isArray(that._dashed)?that._dashed:[10, 10], that._dashedOffset).command;
}
set = _points[0][0];
ballPoint = set.localToLocal(_points[0][1].x, _points[0][1].y, shape);
g.mt(ballPoint.x, ballPoint.y);
s.c().s(that.stickColor).ss(1);
var currentIndex; var nextIndex;
for (var i=0; i<_points.length; i++) {
var currentIndex = i;
var nextIndex = (i+1)%_points.length;
var set = _points[currentIndex][0];
var ball = _points[currentIndex][1];
var control1 = _points[currentIndex][2];
var control2 = _points[currentIndex][3];
// var ctype = _points[currentIndex][4]; // STEFAN
var nextSet = _points[nextIndex][0];
var nextBall = _points[nextIndex][1];
var nextControl1 = _points[nextIndex][2];
var nextControl2 = _points[nextIndex][3];
var control2Point = set.localToLocal(control2.x, control2.y, shape);
var nextControl1Point = nextSet.localToLocal(nextControl1.x, nextControl1.y, shape);
var nextBallPoint = nextSet.localToLocal(nextBall.x, nextBall.y, shape);
if (i != _points.length-1) {
g.bt(
control2Point.x, control2Point.y,
nextControl1Point.x, nextControl1Point.y,
nextBallPoint.x, nextBallPoint.y
);
}
// create the sticks
var ballPoint = set.localToLocal(ball.x, ball.y, shape);
var control1Point = set.localToLocal(control1.x, control1.y, shape);
if (i == 0) control1.visible = 0;
if (i != 0) s.mt(ballPoint.x, ballPoint.y).lt(control1Point.x, control1Point.y);
if (i != _points.length-1) s.mt(ballPoint.x, ballPoint.y).lt(control2Point.x, control2Point.y);
if (i == _points.length-1) control2.visible = 0;
}
// var currentIndex; var nextIndex;
// for (var i=0; i<_points.length; i++) {
// var currentIndex = i;
// var nextIndex = (i+1)%_points.length;
//
// var set = _points[currentIndex][0];
// var ball = _points[currentIndex][1];
// var control1 = _points[currentIndex][2];
// var control2 = _points[currentIndex][3];
// var ctype = _points[currentIndex][4]; // STEFAN
//
// var nextSet = _points[nextIndex][0];
// var nextBall = _points[nextIndex][1];
// var nextControl1 = _points[nextIndex][2];
// var nextControl2 = _points[nextIndex][3];
//
// var control2Point = set.localToLocal(control2.x, control2.y, shape);
// var nextControl1Point = nextSet.localToLocal(nextControl1.x, nextControl1.y, shape);
// var nextBallPoint = nextSet.localToLocal(nextBall.x, nextBall.y, shape);
//
// if (i != _points.length - 1) {
// // STEFAN
// if (ctype == 'none') {
// g.lt(nextBallPoint.x, nextBallPoint.y);
// control2.visible = 0;
// control1.visible = 0;
// } else {
// g.bt(control2Point.x, control2Point.y,
// nextControl1Point.x, nextControl1Point.y,
// nextBallPoint.x, nextBallPoint.y);
//
// // create the sticks
// var ballPoint = set.localToLocal(ball.x, ball.y, shape);
// var control1Point = set.localToLocal(control1.x, control1.y, shape);
// control2.visible = true;
// control1.visible = true;
// if (i == 0) control1.visible = false;
// if (i != 0) s.mt(ballPoint.x, ballPoint.y).lt(control1Point.x, control1Point.y);
// if (i != _points.length - 1) s.mt(ballPoint.x, ballPoint.y).lt(control2Point.x, control2Point.y);
// if (i == _points.length - 1) control2.visible = false;
// }
// }
// }
if (that._dashed) g.append(that.dashedCommand);
g.append(that.thicknessCommand);
g.append(that.colorCommand);
};
that.drawShape();
var startPosition;
sets.on("mousedown", function(e) {
stage = e.target.stage;
if (that.lockControls) return;
if (that.selectPoints) that.keyFocus = true;
startPosition = {x:e.target.x, y:e.target.y};
if (e.target.rect1) { // then mousedown on ball - which has a rect1
var ball = e.target;
ball.startX = ball.x;
ball.startY = ball.y;
ball.rect1.startX = ball.rect1.x;
ball.rect1.startY = ball.rect1.y;
ball.rect2.startX = ball.rect2.x;
ball.rect2.startY = ball.rect2.y;
} else { // mousedown on control
var rect = e.target;
rect.startX = rect.x;
rect.startY = rect.y;
var ball = rect.ball;
var index = ball.index;
var type = controlType;
if (!zot(_points[index][4])) type = _points[index][4];
if (type == "straight") {
var other = rect.other;
var dX = other.x - ball.x;
var dY = other.y - ball.y;
other.stickLength = Math.sqrt(Math.pow(dX,2) + Math.pow(dY,2));
}
}
if (that.selectPoints) {
// need to reset all start points for each control circle and rectangle moved
var currentSet = that.selectionManager.currentSet;
if (currentSet && currentSet.selections && currentSet.selections.length > 0) {
for(var i=0; i<currentSet.selections.length; i++) {
var point = that.pointObjects[currentSet.selections[i]];
point[1].startX = point[1].x;
point[1].startY = point[1].y;
point[2].startX = point[2].x;
point[2].startY = point[2].y;
point[3].startX = point[3].x;
point[3].startY = point[3].y;
}
}
}
});
if (that.selectPoints) {
sets.tap(function (e) {
if (e.target.rect1) { // then mousedown on ball - which has a rect1
var ball = e.target;
that.selectedBalls.toggle(ball.parent.num);
} else { // mousedown on control
var rect = e.target;
rect.color = "white";
var ball = rect.ball;
if (ball.rect1 == rect) that.selectedRect1s.toggle(ball.parent.num);
else that.selectedRect2s.toggle(ball.parent.num);
}
// loop through all controls and set to right color based on selection
for (var i=0; i<that.pointObjects.length; i++) {
var po = that.pointObjects[i];
po[1].color = that.selectedBalls.isSelected(i)?zim.white:zim.light;
po[2].color = that.selectedRect1s.isSelected(i)?zim.white:getBackgroundColor(po[4]);
po[3].color = that.selectedRect2s.isSelected(i)?zim.white:getBackgroundColor(po[4]);
}
stage.update();
});
}
sets.on("pressmove", function(e) {
if (that.lockControls) return;
if (that.selectPoints) {
var currentSelected = getCurrentSelected();
if (currentSelected.indexOf(e.target) == -1) {
mapMove(e.target);
that.drawShape();
} else {
if (currentSelected.length > 0) {
var diffX = e.target.x-e.target.startX;
var diffY = e.target.y-e.target.startY;
for(var i=0; i<currentSelected.length; i++) {
var pointObj = currentSelected[i];
pointObj.x = pointObj.startX + diffX;
pointObj.y = pointObj.startY + diffY;
mapMove(pointObj);
}
that.drawShape();
}
}
} else {
mapMove(e.target);
that.drawShape();
}
});
sets.on("pressup", function(e) {
if (that.lockControls) return;
var moveControlCheck = (e.target.x != startPosition.x || e.target.y != startPosition.y);
var ev = new createjs.Event("change");
if (e.target.rect1) { // pressup on ball
ev.controlType = "bezierPoint";
endMove(e.target);
} else {
ev.controlType = "bezierHandle";
}
if (moveControlCheck) that.dispatchEvent(ev);
});
function endMove(target) {
if (that.selectPoints) {
var currentSelected = getCurrentSelected();
if (currentSelected && currentSelected.indexOf(target) == -1) {
replaceControls(target);
} else if (currentSelected && currentSelected.length>0) {
for(var i=0; i<currentSelected.length; i++) {
replaceControls(currentSelected[i]);
}
} else {
replaceControls(target);
}
} else {
replaceControls(target);
}
}
that.changeControl = function(index, type, rect1X, rect1Y, rect2X, rect2Y, circleX, circleY, update) {
var sig = "index, type, rect1X, rect1Y, rect2X, rect2Y, circleX, circleY, update";
var duo; if (duo = zob(that.changeControl, arguments, sig)) return duo;
if (zot(index)) {
for (var i=0; i<_points.length; i++) {
that.changeControl(i, type, rect1X, rect1Y, rect2X, rect2Y, circleX, circleY);
}
return;
}
var point = _points[index];
point[4] = type;
if (type == "none") {
if (!zot(circleX)) point[2].x = circleX;
if (!zot(circleY)) point[2].y = circleY;
point[2].x = point[1].x;
point[2].y = point[1].y;
point[3].x = point[1].x;
point[3].y = point[1].y;
point[1].parent.addChild(point[1]);
} else {
if (!zot(rect1X)) point[2].x = rect1X;
if (!zot(rect1Y)) point[2].y = rect1Y;
if (!zot(rect2X)) point[3].x = rect2X;
if (!zot(rect2Y)) point[3].y = rect2Y;
if (!zot(circleX)) point[1].x = circleX;
if (!zot(circleY)) point[1].y = circleY;
point[1].parent.addChildAt(point[1], 0);
}
if (update) {
that.update();
if (stage) stage.update();
}
};
that.transformPoints = function(transformType, amount, x, y) {
that.points = zim.transformPoints(that.points, transformType, amount, x, y);
return that;
};
that.traverse = function(obj, start, end, time) {
var ratios = zim.copy(that.segmentRatios);
ratios.unshift(0);
if (zot(end)) end = start+1;
var forward = start < end;
if (forward) {
var startPercent = ratios[start]*100;
var endPercent = ratios[end]*100;
} else {
var startPercent = 50 + (100 - ratios[start]*100)/2;
var endPercent = 50 + (100 - ratios[end]*100)/2;
}
obj.percentComplete = obj.zimStartPercent = startPercent;
obj.animate({
ease:"linear",
props:{path:that},
rewind:!forward,
time:time,
events:true
});
obj.on("animation", function (e) {
// when it hits the end it may start over
if (obj.percentComplete > endPercent || obj.percentComplete == 0) {
obj.stopAnimate();
e.remove();
var eventObj = new createjs.Event("traversed");
eventObj.obj = obj;
that.dispatchEvent(eventObj);
}
});
return that;
};
that.update = function(normalize) {
if (normalize) {
// located any rotated or scaled points
// and set them back to non-rotated and non-scaled
// but keep control handles at the earlier positions
// need to normalize before doing more manual updates with Beziers
// do not need to normalize if animating blob points
that.points = that.pointsAdjusted;
} else {
that.drawShape();
}
that.zimAnimateChanged = true;
return that;
};
// squiggle
if (that.interactive) {
if (move) shape.drag({onTop:false});
moveDownEvent = shape.on("mousedown", function(e) {
stage = e.target.stage;
startPosition = {x:shape.x, y:shape.y};
if (that.selectPoints) that.keyFocus = true;
upTop();
});
movePressEvent = shape.on("pressmove", function() {
sets.x = shape.x;
sets.y = shape.y;
sticks.x = shape.x;
sticks.y = shape.y;
});
moveUpEvent = shape.on("pressup", function() {
var moveControlCheck = (shape.x != startPosition.x || shape.y != startPosition.y);
var movePoint = shape.localToLocal(that.regX,that.regY,that.parent);
that.x = movePoint.x;
that.y = movePoint.y;
sets.x = sets.y = sticks.x = sticks.y = shape.x = shape.y = 0;
if (moveControlCheck) {
var ev = new createjs.Event("change");
ev.controlType = "move";
that.dispatchEvent(ev);
}
if (stage) stage.update();
});
if (!that.move) stopDragging(true); // true is first time
}
function upTop() {
if (that.onTop) {
var nc = that.parent.numChildren-1;
if (that.parent.getChildAt(nc).type == "Keyboard") nc--;
that.parent.setChildIndex(that, nc);
}
}
that.toggleEvent = that.on("mousedown", function() {
if (!that.allowToggle) return;
if (!_controls) {
that.showControls();
that.dispatchEvent("controlsshow");
}
});
that.added(function() {
stage = that.stage;
if (that.toggleStageEvent) stage.off("stagemousedown", that.toggleStageEvent);
that.toggleStageEvent = stage.on("stagemousedown", function(e) {
if (!that.allowToggle || !that.stage) return;
if (_controls && !that.hitTestPoint(e.stageX/zim.scaX, e.stageY/zim.scaY, false)) {
that.hideControls();
that.dispatchEvent("controlshide");
}
});
});
that.clickEvent = that.on("click", function() {
if (that.ctrlKey) {
setTimeout(function() { // give time for record to work if drag with ctrl down
that.clone(true).addTo(that.stage).mov(0, 100);
if (that.allowToggle) {
that.hideControls();
that.dispatchEvent("controlshide");
}
var ev = new createjs.Event("change");
ev.controlType = "move";
that.dispatchEvent(ev);
that.stage.update();
}, 50);
}
});
that.hideControls = function() {
that.toggled = false;
sets.visible = false;
sticks.visible = false;
_controls = false;
if (that.stage) that.stage.update();
if (!that.allowToggle && that.move) stopDragging();
return that;
};
if (!showControls) that.hideControls();
that.showControls = function() {
that.toggled = true;
// if call this with code then will not trigger a change event - not good for TransformManager.persist()
sets.visible = true;
sticks.visible = true;
_controls = true;
sets.x = shape.x;
sets.y = shape.y;
sticks.x = shape.x;
sticks.y = shape.y;
that.addChildAt(shape,0); // put to bottom incase dragged
if (that.move && !that.allowToggle) startDragging();
if (that.stage) that.stage.update();
return that;
};
that.toggle = function(state) {
if (state===true) that.showControls();
else if (state===false) that.hideControls();
else if (_controls) that.hideControls();
else that.showControls();
return that;
};
that.recordData = function(toJSON) {
if (zot(toJSON)) toJSON = false;
var obj = {
type:"Blob",
index:that.parent?that.parent.getChildIndex(that):-1,
x:that.x, y:that.y,
points:that.recordPoints(),
color:that.color,
thickness:that.thickness,
move:that.move,
toggle:that.allowToggle,
controlsVisible:_controls
};
if (toJSON) return JSON.stringify(obj);
return obj;
};
that.setData = function(data, fromJSON) {
if (zot(data)) return;
if (fromJSON) {
try {
data = JSON.parse(data);
} catch (e) {
return;
}
}
var index = data.index;
if (zot(index)) index = -1;
delete data.index;
var pointData = data.points;
if (!zot(pointData)) that.setPoints(pointData);
delete data.points;
that.num = pointData.length;
for (var d in data) {
that[d] = data[d];
}
if (that.parent) {
that.parent.setChildIndex(that, index);
}
that.update();
return that;
};
that.recordPoints = function(popup) {
// balls are relative to blob but handles are relative to ball
// points is an array of [[ballX, ballY, handleX, handleY, handle2X, handle2Y, type], etc.]
if (zot(popup)) popup = false;
var points = that.points;
if (popup) {
if (!that.pane) {
var pane = that.pane = new zim.Pane({
container:that.stage,
width:Math.min(500, that.stage.width-20),
height:Math.min(500, that.stage.height-20),
draggable:true,
});
var textArea = that.textArea = new zim.TextArea(Math.min(400, that.stage.width-70), Math.min(400, that.stage.height-70));
textArea.centerReg(pane);
}
that.textArea.text = JSON.stringify(points);
that.pane.show();
}
return points;
};
that.setPoints = function(points) {
// adjust blob to match points passed in from recordPoints
var p;
var p2;
for (var i=0; i<points.length; i++) {
p = _points[i];
p2 = points[i];
if (zot(p)) continue;
p[0].x = p2[0];
p[0].y = p2[1];
p[1].x = p2[2];
p[1].y = p2[3];
p[2].x = p2[4];
p[2].y = p2[5];
p[3].x = p2[6];
p[3].y = p2[7];
p[4] = p2[8];
}
that.update();
return that;
};
if (style!==false) zim.styleTransforms(that, DS);
that.clone = function(exact, commands) {
var newShape = that.cloneProps(new zim.Squiggle(commands?that.colorCommand:((exact||!zim.isPick(oa[0]))?that.color:oa[0]), that.thickness, that.recordPoints(), length, controlLength, controlType, lockControlType, sets.visible, lockControls, handleSize, that.allowToggle, that.move, dashed, onTop, stickColor, selectColor, selectPoints, that.editPoints, interactive, strokeObj, style, that.group, inherit));
if (that.linearGradientParams) newShape.linearGradient.apply(newShape, that.linearGradientParams);
if (that.radialGradientParams) newShape.radialGradient.apply(newShape, that.radialGradientParams);
return newShape;
};
// to add a control - make sure click in one spot - not drag
that.shape.on("mousedown", function (e) {
stage = e.target.stage;
if (!that.editPoints) return;
if (that.controlsVisible) {
that.pressX = e.stageX/zim.scaX;
that.pressY = e.stageY/zim.scaX;
} else {
that.pressX = null;
that.pressY = null;
}
});
that.addPointFactor = 10;
that.addMinDistance = 15;
that.shape.on("pressup", function (e) {
if (!that.editPoints) return;
if (that.pressX && Math.abs(that.pressX-e.stageX/zim.scaX) < min && Math.abs(that.pressY-e.stageY/zim.scaY) < min) {
if (that.selectPoints) that.lastPoints = zim.copy(that.points);
var points = that.points;
var point = that.globalToLocal(e.stageX/zim.scaX, e.stageY/zim.scaY);
var pointBefore = zim.closestPointAlongCurve(point, that.segmentPoints);
if (that.editPoints == "anywhere") {
points.splice(pointBefore+1, 0, [point.x, point.y, 0,0, 0,0, 0,0]);
that.points = points;
that.changeControl({index:pointBefore+1, type:"mirror", update:true});
} else { // only on edge
// test close enough to edge otherwise return
var p = that.pointsAdjusted;
var cubic = that.getSegmentPoint(p[pointBefore], p[(pointBefore+1)%p.length]);
var length = zim.distanceAlongCurve(cubic);
var testNum = Math.round(length/that.addPointFactor);
var testPoints = that.interpolate(testNum, pointBefore, false, points);
// interpolate is setting 2 more points than asked
var closest=10000;
var closestPoint;
var closestIndex;
zim.loop(testPoints, function (p, k) {
var d = zim.dist(p, point);
if (d < closest) {
closest = d;
closestIndex = k;
closestPoint = p;
}
});
if (closest < that.addMinDistance) {
var ratios = that.segmentRatios;
var currentRatio = ratios[pointBefore];
var lastRatio = pointBefore>0?ratios[pointBefore-1]:0;
that.addPoint(100*(lastRatio+(currentRatio-lastRatio)*((closestIndex)/(testNum+1))));
}
}
that.lastSelectedIndex = pointBefore+1;
that.lastSelected = that.controls.getChildAt(that.lastSelectedIndex);
that.stage.update();
}
});
// remove point
that.controls.on("click", function (e) {
that.lastSelected = e.target.parent;
var index = that.lastSelectedIndex = that.controls.getChildIndex(e.target.parent);
if (!that.editPoints) return;
if (that.selectionManager.shiftKey) { // remove
// if (that.selectionManager.currentSet == that.selectedBalls && that.selectedBalls.selections.length > 0) return;
removeControl(e);
}
});
function removeControl(e) {
if (e.target.type == "Circle") {
var index = that.lastSelectedIndex = that.controls.getChildIndex(e.target.parent);
if (that.controls.numChildren <= 2) return;
var points = that.points;
if (that.selectPoints) that.lastPoints = zim.copy(points);
points.splice(index, 1); // remove the point at the index
that.points = points;
that.stage.update();
that.lastSelected = that.lastSelectedIndex = null;
}
}
that.controls.hold(removeControl);
if (!_controls) that.hideControls();
that.dispatchEvent("update");
} // end of init()
// if (that.selectPoints) {
function getCurrentSelected() {
var answer = [];
var currentSet = that.selectionManager.currentSet;
if (currentSet && currentSet.selections && currentSet.selections.length > 0) {
for(var i=0; i<currentSet.selections.length; i++) {
var point = that.pointObjects[currentSet.selections[i]];
if (currentSet == that.selectedBalls) {
answer.push(point[1]);
} else if (currentSet == that.selectedRect1s) {
answer.push(point[2]);
} else if (currentSet == that.selectedRect2s) {
answer.push(point[3]);
} else {
continue;
}
}
}
return answer;
}
function replaceControls(target) {
// move ball back to origin and move set accordingly
// so if we animate the set it will behave as expected
if (target.type != "Circle") return;
var ball = target;
var set = ball.mySet;
var rect1 = ball.rect1;
var rect2 = ball.rect2;
rect1.x -= ball.x;
rect1.y -= ball.y;
rect2.x -= ball.x;
rect2.y -= ball.y;
set.x += ball.x;
set.y += ball.y;
ball.x = 0;
ball.y = 0;
}
that.selectionManager.on("keydown", function (e) {
if (!that.selectPoints) return;
if (!that.keyFocus) return;
if (e.keyCode >= 37 && e.keyCode <= 40) {
var currentSelected = getCurrentSelected();
if (currentSelected.length > 0) {
for(var i=0; i<currentSelected.length; i++) {
var pointObj = currentSelected[i];
if (e.keyCode == 37) pointObj.x -= that.selectionManager.shiftKey?10:1;
else if (e.keyCode == 39) pointObj.x += that.selectionManager.shiftKey?10:1;
else if (e.keyCode == 38) pointObj.y -= that.selectionManager.shiftKey?10:1;
else if (e.keyCode == 40) pointObj.y += that.selectionManager.shiftKey?10:1;
mapMove(pointObj);
}
that.drawShape();
that.dispatchEvent("update");
if (that.stage) that.stage.update();
}
}
});
that.selectionManager.on("keyup", function (e) {
if (!that.selectPoints) return;
if (!that.keyFocus) return;
if (e.keyCode >= 37 && e.keyCode <= 40) {
var currentSelected = getCurrentSelected();
if (currentSelected.length > 0) {
for(var i=0; i<currentSelected.length; i++) {
replaceControls(currentSelected[i]);
}
}
}
});
that.selectionManager.on("undo", function () {
if (!that.selectPoints) return;
if (!that.keyFocus) return;
if (that.lastPoints) {
var tempPoints = zim.copy(that.lastPoints);
that.lastPoints = zim.copy(that.points);
that.points = tempPoints;
if (that.stage) that.stage.update();
}
});
// }
mapMove = function (target) {
if (that.lockControls) return;
if (target.rect1) { // pressmove on ball
var ball = target;
var diffX = ball.x - ball.startX;
var diffY = ball.y - ball.startY;
ball.rect1.x = ball.rect1.startX + diffX;
ball.rect1.y = ball.rect1.startY + diffY;
ball.rect2.x = ball.rect2.startX + diffX;
ball.rect2.y = ball.rect2.startY + diffY;
} else { // pressmove on control
var rect = target;
var other = rect.other; // the other handle
var ball = rect.ball;
var index = ball.index;
var type = controlType;
if (!zot(_points[index][4])) type = _points[index][4];
if (type == "straight" || type == "mirror") {
var dX = rect.x - ball.x;
var dY = rect.y - ball.y;
if (type == "mirror") {
other.x = ball.x - dX;
other.y = ball.y - dY;
} else {
var a = Math.atan2(dY, dX);
var dNewX = -other.stickLength * Math.cos(a+Math.PI);
var dNewY = -other.stickLength * Math.sin(a+Math.PI);
other.x = ball.x - dNewX;
other.y = ball.y - dNewY;
}
}
}
// that.setBounds();
// decided not to dynamically set bounds
// they really just go around the control points and not the shape
// and if dynamically set they go to null if the control points are not showing
};
Object.defineProperty(that, 'move', {
get: function() {
return move;
},
set: function(value) {
if (move != value) {
move = value;
if (value) {
startDragging();
} else {
stopDragging();
}
}
}
});
Object.defineProperty(that, 'interactive', {
get: function() {
return interactive;
},
set: function(value) {
interactive = value;
_controls = interactive;
that.allowToggle = interactive;
that.editPoints = interactive;
that.lockControls = !interactive; // note negative!
that.selectPoints = interactive;
that.move = interactive;
that.points = that.points; // force remake
}
});
Object.defineProperty(that, 'allowToggle', {
get: function() {
return allowToggle;
},
set: function(value) {
if (allowToggle != value) {
allowToggle = value;
if (allowToggle) {
if (that.move) startDragging();
} else {
if (!_controls && that.move) stopDragging();
}
}
}
});
function startDragging() {
if (that.move=="always") return;
if (draggingCheck) return;
draggingCheck = true;
shape.drag({onTop:false});
moveDownEvent = shape.on("mousedown", moveDownEvent);
movePressEvent = shape.on("pressmove", movePressEvent);
moveUpEvent = shape.on("pressup", moveUpEvent);
}
function stopDragging(making) {
if (that.move=="always") return;
if (!making && !draggingCheck) return;
draggingCheck = false;
shape.noDrag();
shape.off("mousedown", moveDownEvent);
shape.off("pressmove", movePressEvent);
shape.off("pressup", moveUpEvent);
}
var _lockControls = lockControls;
Object.defineProperty(that, 'lockControls', {
get: function() {
return _lockControls;
},
set: function(value) {
_lockControls = value;
if (value) {
that.controls.mouseChildren = false;
that.controls.mouseEnabled = false;
} else {
that.controls.mouseChildren = true;
that.controls.mouseEnabled = true;
}
}
});
that.lockControls = _lockControls;
Object.defineProperty(that, 'controlsVisible', {
get: function() {
return _controls;
},
set: function(value) {
_controls = value;
if (value) {
that.showControls();
} else {
that.hideControls();
}
}
});
if (typeof KEYFOCUS !== typeof undefined) zim.KEYFOCUS = KEYFOCUS;
Object.defineProperty(this, 'keyFocus', {
get: function() {
return zim.KEYFOCUS == that;
},
set: function(value) {
zim.KEYFOCUS = that;
}
});
if (!zim.KEYFOCUS) setFocus();
function setFocus() {if (!that.selectPoints) return; that.keyFocus = true; var d=document.activeElement; if (d) d.blur();}
Object.defineProperty(that, 'points', {
get: function() {
var points = [];
var point; var p;
for (var i=0; i<_points.length; i++) {
p = _points[i];
point = [
zim.decimals(p[0].x),
zim.decimals(p[0].y),
zim.decimals(p[1].x),
zim.decimals(p[1].y),
zim.decimals(p[2].x),
zim.decimals(p[2].y),
zim.decimals(p[3].x),
zim.decimals(p[3].y)
];
if (p[4] && p[4]!=="mirror") point.push(p[4]);
points.push(point);
}
return points;
},
set: function(value) {
var x = that.x;
var y = that.y;
var v = that.visible;
that.dispose(true);
points = value;
// if (that.shape) {
// that.shape.graphics.clear();
// that.sticks.graphics.clear();
// that.controls.noDrag();
// that.removeAllChildren();
// delete that.shape;
// delete that.sticks;
// delete that.controls;
// }
init(); // remake Squiggle
that.lockControls = _lockControls;
that.x = x;
that.y = y;
that.visible = v;
}
});
Object.defineProperty(that, 'pointsAdjusted', { // points with rotation
get: function() {
var points = [];
var point; var p; var po;
var pObjects = that.pointObjects;
zim.loop(pObjects.length, function(i, t) {
po = pObjects[i];
p = _points[i];
if (po[0].rotation==0 && po[0].scaleX==0 && po[0].scaleY==0) { // get points
point = [
zim.decimals(p[0].x),
zim.decimals(p[0].y),
zim.decimals(p[1].x),
zim.decimals(p[1].y),
zim.decimals(p[2].x),
zim.decimals(p[2].y),
zim.decimals(p[3].x),
zim.decimals(p[3].y)
];
} else {
var lo1 = po[0].localToLocal(po[2].x, po[2].y, po[0].parent);
var lo2 = po[0].localToLocal(po[3].x, po[3].y, po[0].parent);
point = [
zim.decimals(p[0].x),
zim.decimals(p[0].y),
zim.decimals(p[1].x),
zim.decimals(p[1].y),
zim.decimals(lo1.x-p[0].x),
zim.decimals(lo1.y-p[0].y),
zim.decimals(lo2.x-p[0].x),
zim.decimals(lo2.y-p[0].y)
];
}
if (p[4] && p[4]!=="mirror") point.push(p[4]);
points.push(point);
});
return points;
},
set: function (value) {
if (zon) zogy("Squiggle() - pointsAdjusted is read only");
}
});
Object.defineProperty(that, 'pointObjects', {
get: function() {
return _points;
},
set: function (value) {
if (zon) { zog("Squiggle() - pointObjects is read only - but its contents can be manipulated - use squiggle.update() after changes"); }
}
});
Object.defineProperty(that, 'pointControls', {
get: function() {
return _pointControls;
},
set: function(value) {
if (zon) {zog("Squiggle() - pointControls is read only - but its contents can be manipulated - use blob.update() after changes");}
}
});
Object.defineProperty(that, 'pointCircles', {
get: function() {
return _pointCircles;
},
set: function(value) {
if (zon) {zog("Squiggle() - pointCircles is read only - but its contents can be manipulated - use blob.update() after changes");}
}
});
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// path manipulation and animating to path methods
Object.defineProperty(that, 'segmentPoints', {
get: function() {
var array = []; // array of prepared segment points
var p = that.pointsAdjusted;
zim.loop(p.length-1, function(i, t) {
var s = that.getSegmentPoint(p[i], p[i+1]);
array.push(s);
});
return array;
},
set: function(value) {
if (zon) {zog("Squiggle() - segmentPoints is read only");}
}
});
Object.defineProperty(that, 'segmentRatios', {
get: function() {
var distances = [];
var total = 0;
zim.loop(that.segmentPoints, function(points) {
var d = zim.distanceAlongCurve(points);
distances.push(d);
total += d;
});
var percents = [];
var totalPercents = 0;
zim.loop(distances, function (d) {
var p = d/total;
totalPercents += p;
percents.push(totalPercents);
});
return percents;
},
set: function(value) {
if (zon) {zog("Squiggle() - segmentRatios is read only");}
}
});
that.approximateBounds = function(num, showPoints, margin) {
if (zot(num)) num = 80;
if (zot(margin)) margin = 0;
num /= that.num;
var points = that.interpolate(num, null, true, null, true);
var bounds = zim.boundsAroundPoints(points);
that.setBounds(bounds.x-margin, bounds.y-margin, bounds.width+margin*2, bounds.height+margin*2);
if (showPoints) {
if (!that.parent) {
if (zon) zogy("approximateBounds() - add to stage to first to see points");
return that;
}
if (!that.hitPathPoints) that.hitPathPoints = new zim.Container().addTo();
else that.hitPathPoints.removeAllChildren();
that.hitPathPoints.top();
for (var i=0; i<points.length; i++) {
var point = points[i];
point = that.localToGlobal(point.x, point.y);
new zim.Circle(3).loc(point.x, point.y, that.hitPathPoints);
}
}
return that;
};
that.getPointAngle = function(index) {
var p = that.pointObjects[index][0]; // parent
var r1 = that.pointObjects[index][2];
var r2 = that.pointObjects[index][3];
if (p==that.stage) {
var globalR1 = new zim.Point(r1.x, r1.y);
var globalR2 = new zim.Point(r2.x, r2.y);
} else {
var globalR1 = p.localToGlobal(r1.x, r1.y);
var globalR2 = p.localToGlobal(r2.x, r2.y);
}
return zim.angle(globalR1.x, globalR1.y,globalR2.x, globalR2.y);
};
that.getSegmentPoint = function(point1, point2) {
if (zot(point1) || zot(point2)) return;
// dragging points temporarily puts data out of order
if (point1[2] != 0 || point1[3] != 0) {
point1[4] -= point1[2];
point1[5] -= point1[3];
point1[6] -= point1[2];
point1[7] -= point1[3];
point1[0] += point1[2];
point1[1] += point1[3];
point1[2] = 0;
point1[3] = 0;
}
if (point2[2] != 0 || point2[3] != 0) {
point2[4] -= point2[2];
point2[5] -= point2[3];
point2[6] -= point2[2];
point2[7] -= point2[3];
point2[0] += point2[2];
point2[1] += point2[3];
point2[2] = 0;
point2[3] = 0;
}
var p1 = {x:point1[0], y:point1[1]};
var p2 = {x:point1[0]+point1[6], y:point1[1]+point1[7]};
var p3 = {x:point2[0]+point2[4], y:point2[1]+point2[5]};
var p4 = {x:point2[0], y:point2[1]};
if (sets.x != 0 || sets.y !=0) {
p1.x+=sets.x;
p2.x+=sets.x;
p3.x+=sets.x;
p4.x+=sets.x;
p1.y+=sets.y;
p2.y+=sets.y;
p3.y+=sets.y;
p4.y+=sets.y;
}
return [p1,p2,p3,p4];
};
that.getAdjacentSegmentData = function(index) {
if (zot(index)) index = 0;
var p = that.pointsAdjusted;
if (that.num == 2) {
return [
[that.getSegmentPoint(p[0], p[1])],
[0]
];
}
if (index == 0) {
return [
[that.getSegmentPoint(p[0], p[1]),
that.getSegmentPoint(p[1], p[2])],
[0,1]
];
} else if (index >= that.num-2) {
return [
[that.getSegmentPoint(p[that.num-3], p[that.num-2]),
that.getSegmentPoint(p[that.num-2], p[that.num-1])],
[that.num-3, that.num-2]
];
} else {
return [
[that.getSegmentPoint(p[index-1], p[index]),
that.getSegmentPoint(p[index], p[index+1]),
that.getSegmentPoint(p[index+1], p[index+2])],
[index-1,index,index+1]
];
}
};
that.getCurvePoint = function(ratio, segmentRatios, segmentPoints, getAngle, even) {
if (zot(ratio) || isNaN(ratio)) ratio = 0;
if (zot(segmentRatios)) segmentRatios = that.segmentRatios;
if (zot(segmentPoints)) segmentPoints = that.segmentPoints;
if (zot(getAngle)) getAngle = false;
if (zot(even)) even = false;
var percents = segmentRatios;
var segments = segmentPoints;
var afterIndex = zim.loop(percents, function (p, i) {
if (p >= ratio) return i;
});
var earlierPercent = afterIndex > 0 ? percents[afterIndex-1] : 0;
var localTotal = afterIndex > 0 ? (percents[afterIndex]-percents[afterIndex-1]):percents[afterIndex];
if (!localTotal) return undefined;
var localPercent = (ratio-earlierPercent)/localTotal;
var finalPoint = zim.pointAlongCurve(segments[afterIndex], localPercent, getAngle, true);
var finalFinalPoint = that.localToGlobal(finalPoint.x, finalPoint.y);
finalFinalPoint.angle = finalPoint.angle;
finalFinalPoint.z = afterIndex;
return !zot(finalFinalPoint) ? finalFinalPoint : undefined;
};
function proportion(p1, p2, ratio) {
return {
x:p1.x + (p2.x-p1.x)*ratio,
y:p1.y + (p2.y-p1.y)*ratio
};
}
function insertPointData(points, controls, ratios, percent, controlType, skipPoint, dataOnly, even) {
var index = points.length-1; // adjust for squiggle
var lastRatio = 0;
var currentRatio = 0;
if (percent == 100 && that.type == "Squiggle") percent = 99.99;
percent = (percent+100000)%100;
zim.loop(ratios, function (ratio, i) {
if (percent/100 < ratio) {
index = i;
currentRatio = ratio;
return true;
}
lastRatio = ratio;
});
var segment = that.segmentPoints[index];
var r = currentRatio > 0?(percent/100-lastRatio)/(currentRatio-lastRatio):0;
var point = zim.pointAlongCurve(segment, r, null, even);
var newPoint = [point.x,point.y, 0, 0];
if (skipPoint) return;
if (dataOnly) {
that.interpolatedPoints.push({x:point.x, y:point.y, r:percent/100});
return;
}
if (controlType != "none") {
// calculate new handles and adjust old handles
// [controlX, controlY, circleX, circleY, rect1X, rect1Y, rect2X, rect2Y, controlType]
var startHandle = proportion(segment[0], segment[1], r);
var midPoint = proportion(segment[1], segment[2], r);
var endHandle = proportion(segment[2], segment[3], r);
var newStartHandle = proportion(startHandle, midPoint, r);
var newEndHandle = proportion(midPoint, endHandle, r);
newPoint[4] = newStartHandle.x-point.x;
newPoint[5] = newStartHandle.y-point.y;
newPoint[6] = newEndHandle.x-point.x;
newPoint[7] = newEndHandle.y-point.y;
var start = that.localToLocal(startHandle.x, startHandle.y, controls[index]);
points[index][6] = start.x;
points[index][7] = start.y;
var end = that.localToLocal(endHandle.x, endHandle.y, controls[(index+1)%points.length]);
points[(index+1)%points.length][4] = end.x;
points[(index+1)%points.length][5] = end.y;
}
if (controlType) newPoint[8] = controlType;
points.splice(index+1, 0, newPoint);
}
this.addPoint = function(percent, controlType) {
if (zot(percent)) percent = 100;
var points = that.points;
var ratios = that.segmentRatios;
var controls = that.pointControls;
controlType = controlType ? controlType : originalControlType;
insertPointData(points, controls, ratios, percent, controlType);
that.points = points;
that.num = points.length;
return that;
};
this.addPoints = function(num, controlType, startPoint, spread, dataOnly, points, even) {
if (zot(points)) points = zim.copy(that.points);
var ratios = zim.copy(that.segmentRatios);
var lastRatio = 0;
if (dataOnly) that.interpolatedPoints = [];
// dataOnly should add points to current point too
// but can't just use current point because sometimes that is static
// like when dragging the shape or a point - it does not register until mouseup
// and things like hitTestPath need that to be dynamic
// So the below does not work:
// if (dataOnly) {
// that.interpolatedPoints = [];
// zim.loop(points, function (point, i) {
// if (!zot(startPoint) && i!=startPoint) return;
// that.interpolatedPoints.push({x:point[0], y:point[1]})
// });
// }
if (spread) var totalPoints = ratios.length*num;
zim.loop(ratios, function (ratio, j) {
if (dataOnly) insertPointData(points, that.pointControls, that.segmentRatios, lastRatio*100, controlType, !zot(startPoint) && j!=startPoint, dataOnly, even);
var numCount = spread?Math.round(totalPoints*(ratio-lastRatio)):num;
var div = 1/(numCount+1);
zim.loop(numCount, function(i) {
var r = lastRatio + (ratio-lastRatio)*div*(i+1);
insertPointData(points, that.pointControls, that.segmentRatios, r*100, controlType, !zot(startPoint) && j!=startPoint, dataOnly, even);
if (!dataOnly && num > 0) that.points = points;
});
lastRatio = ratio;
});
if (dataOnly && that.type == "Squiggle") {
// changed to skipPoint false in zim 10.7.0 - not sure why it was true...
insertPointData(points, that.pointControls, that.segmentRatios, 100, controlType, false, dataOnly, even);
}
if (that.stage) that.stage.update();
that.num = points.length;
return that;
};
this.interpolate = function(num, startPoint, spread, points, even) {
if (zot(num)) num = 1;
// dataOnly will add Point to start point too
that.addPoints(num, "none", startPoint, spread, true, points, even);
return that.interpolatedPoints;
};
this.dispose = function(temp, b, disposing) {
if (!that.shape) return;
zim.gD(that); // globalDispose function for common elements
if (stage && that.toggleStageEvent) stage.off("stagemousedown", that.toggleStageEvent);
that.controls.noDrag(); // sets
that.controls.removeAllEventListeners();
if (that.selectPoints && that.selectionManager) that.selectionManager.dispose();
that.selectedBalls = null;
that.selectedRect1s = null;
that.selectedRect2s = null;
that.selectionManager = null;
that.off("mousedown", that.toggleEvent);
that.off("click", that.clickEvent);
if (temp) {
that.shape.dispose();
that.shape = null;
for (var i=0; i<that.points.length; i++) {
that.pointObjects[i][0].removeAllEventListeners();
that.pointObjects[i][1].removeAllEventListeners();
that.pointObjects[i][2].removeAllEventListeners();
that.pointObjects[i][3].removeAllEventListeners();
}
that.controls.removeFrom(that);
that.sticks.dispose();
_points = null;
_pointCircles = null;
} else {
that.removeAllEventListeners();
_points = null;
_pointCircles = null;
if (!disposing) this.zimCustomShape_dispose(true);
}
return true;
};
};
zim.extend(zim.Squiggle, zim.CustomShape, ["clone", "dispose"], "zimCustomShape", false);
//-53.2
/*--
zim.Blob = function(color, borderColor, borderWidth, points, radius, controlLength, controlType, lockControlType, showControls, lockControls, handleSize, allowToggle, move, dashed, onTop, stickColor, selectColor, selectPoints, editPoints, interactive, strokeObj, style, group, inherit)
Blob
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
Makes a blob shape inside a container using a number of points.
The points have Bezier controls - little handles that change the shape of the Blob.
The type of control can be specified overall and individually - and can be hidden or shown
The type of control can be changed by double clicking the point - colors of the handles will change
Points can be added by clicking on the shape or removed by SHIFT clicking a point.
CTRL Z will undo adding or removing a point
The shape of the Blob can be recorded with the recordData() method and recreated with the setData() method
The Blob is set by default to show and hide controls when clicked
It is also draggable by default when the controls are showing
MULTIPLE SELECT
Multiple points can be selected and dragged or moved with the keyboard arrows (moves 10 pixels with shift key down)
NOTE: mouseChildren is turned to false for all zim Shape containers.
NOTE: with the ZIM namespace zns = false, this overwrites a JS Blob - so the JS Blob is stored as document.Blob
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var blob = new Blob(); // makes a circle with default 4 points with Bezier controls
blob.center();
var moreBlob = new Blob({
points:12, // 12 points for more complex shape
}).center();
var specifiedBlob = new Blob({
color:purple,
controlType:"free", // free will be default control type (rather than "straight")
points:[
// the control position x, y
// then three point positions inside the control - so relative to the control position
// 1. circle position x, y (usually the same as the control position - so 0,0)
// 2. the location of the first control rectangle x and y
// 3. the location of the second control rectangle x and y
// then an optional specific type of control that overrides the controlType parameter (or the default type of "straight")
[-100,-100,-100,100,100,-100,0,0,"mirror"], // this will be type "mirror"
[100,-100,100,0,-50,0], // this will be type "free" because controlType parameter
[100,100], // these will be type "none" because no dimensions (or dimensions 0) specified for controls
[-100,100]
]
}).centerReg();
END EXAMPLE
EXAMPLE
// Transform the original points of a Blob
// If you rotate or scale, this affects the control points - the little rectangles rotate or they scale
// To avoid this, the points themselves can be transformed (scaleX, scaleY, scale, rotation, x, y)
// This makes a square and scales it bigger without affecting control size or stroke size (if there were a stroke)
// Note the default number of points is 4 but they are arranged at the top, bottom and sides - so would make a diamond with just controlType:"none"
new Blob({controlType:"none"}).transformPoints("rotation", 45).transformPoints("scale", 2).center();
END EXAMPLE
EXAMPLE
// make a Blob the shape of basic ZIM shapes
// this overrides the path parameter
new Blob({shape:"circle"}).pos(200,200);
new Blob({shape:new Rectangle(100,200)}).center();
new Blob({shape:new Triangle()}).transformPoints("rotation", 90).pos(50,50,true,true);
END EXAMPLE
EXAMPLE
// Animate along a Blob
// see https://zimjs.com/explore/blobAnimate.html for more
// see https://zimjs.com/explore/blobAnimate2.html for more
var path = new Blob().center();
new Circle(10, red).addTo().animate({path:path}, 1000);
END EXAMPLE
EXAMPLE
// Animate one Blob into another
var targetBlob = new Blob({points:"rectangle"});
var blob = new Blob({radius:50, points:"circle", interactive:false})
.pos(200,200)
.transformPoints("rotation", -45) // to better tween to rectangle
.animate({
props:{shape:targetBlob},
time:1,
rewind:true,
loop:true
});
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports VEE - parameters marked with ZIM VEE mean a zim Pick() object or Pick Literal can be passed
Pick Literal formats: [1,3,2] - random; {min:10, max:20} - range; series(1,2,3) - order, function(){return result;} - function
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
color - |ZIM VEE| - (default green) the fill color as any CSS color including "rgba()" for alpha fill (set a to 0 for tranparent fill)
borderColor - |ZIM VEE| - (default null) the stroke color
borderWidth - (default 1 if stroke is set) the size of the stroke in pixels
num - get the number of points - to set, use the points property
points - (default 4) a number of points to start with to make the shape
OR a shape string of "circle", "rectangle" or "triangle"
OR a ZIM Circle, Rectangle or Triangle with any dimensions that will be matched
OR an SVG path like: points:"M0,129.5c22,0,40-31,40-41c0-8-3.2-13-10-13" etc. (also see SVGContainer)
OR an array of points as follows:
[[controlX, controlY, circleX, circleY, rect1X, rect1Y, rect2X, rect2Y, controlType], [etc]]
controlX and controlY - the x and y location of the control Container which holds the point circle and the two control rectangles
circleX and circleY - (default 0) the x and y location of the circle relative to the control location (usually 0, 0)
rect1X, rect1Y, rect2X, rect2Y - (default based on controlLength) the x and y location of the control rectangles relative to the control location
controlType - (default main controlType parameter or "straight" if not controlType parameter) the point's controlType "none", "mirror", "straight" or "free"
radius - (default 100) the default radius of the circle used to create the blob (also specifies the blob's bounds(-radius, -radius, radius*2, radius*2))
controlLength - |ZIM VEE| (default radius*numPoints/4) specify a Number to override the calculated default
controlType - (default "straight") one of four String values as follows:
none - there are no control rectangles (they are actually set at 0,0). This makes a corner at the circle point.
mirror - the control rectangles reflect one another about the point circle - lengths are kept even
straight - the control rectangles keep a straight line through the point circle but length is independent
free - the control rectangle moves independently from the other control rectangle
** The controlType can be specified for each point - see the points parameter
** The controlType can be changed by doubleClicking the point circle to cycle through the controls in the order above - unless the lockControlType is set to true
lockControlType - (default false) set to true to disable doubleClicking of point circles to change controlType
showControls - (default true) set to false to start with controls not showing - can change this after with control property or showControls() method
lockControls - (default false) set to true to lock the editing of controls - can't move the points or handles - but can see them if showControls is set to true
handleSize - (default 20 mobile 10 for non-mobile) the size of control boxes and affects the circles too proportionally
If a handleSize of 0 is chosen, then the sticks will disappear too
allowToggle - (default true) set false to let turn off clicks showing and hiding controls
move - (default true) set to false to disable dragging when controls are showing
can also set to "always" to allow movement when controls are not showing
dashed - (default false) set to true for dashed border (if borderWidth or borderColor set)
or set to an array of line size then space size, etc.
eg. [20, 10] is 20 line and 10 space repeated and [20,100,50,10] is 20 line, 100 space, 50 line, 10 space, etc.
onTop - (default true) set to false to not bring shape to top of container when dragging
stickColor - (default "#111") set the stick color of the controls
selectColor - (default white) the color of the selected circle or rectangle of the controls if selectPoints is true
selectPoints - (default true) set to false to not allow point controls to be selected for keyboard control
editPoints - (default true) lets user add points by pressing on shape path.
set to "anywhere" to let users add points anywhere - will add points with controlType:"none"
set to false to not allow adding or removing points with click or shift click
interactive - (default true) set to false to turn off controls, move, toggle, select, edit - leaving just the shape
strokeObj - (default {caps:"butt", joints:"miter", miterLimit:10, ignoreScale:false}) set to adjust stroke properties
caps options: "butt", "round", "square" or 0,1,2
joints options: "miter", "round", "bevel" or 0,1,2
miterLimit is the ration at which the mitered joint will be clipped
ignoreScale set to true will draw the specified line thickness regardless of object scale
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
approximateBounds(num, showPoints) - update the bounds based on a Rectangle
that surrounds the number of points (default 80) distributed around the object path
set showPoints to true to draw little dots on points
use outline() after object has been added to the stage to see the bounds
addPoint(percent, controlType) - add a point at a percent (100) of the total curve
this is handy to make path have the same number of points for animate() path tweens
controlType can be as specified in main points parameter
returns object for chaining
addPoints(num, controlType, startPoint) - add num points between existing points
controlType can be as specified in main points parameter
specify a startPoint to add points between the startPoint and the next point (one segment of points)
spread (default false) set to true to spread points evenly around path rather than evenly between segments
dataOnly and points are used internally
returns object for chaining
interpolate(num, startPoint, spread, points, even) - get point data {x,y} for existing points and num (default 1) points inbetween
used with hitTestPath() and animate() drag on path - also add points (note add points does not use even:true)
specify a startPoint to get points between the startPoint and the next point (one segment of points)
spread (default false) set to true to spread number of points around path rather equal number between segments
points (default all points) the points to work with in the same format as the points property
even (default false) set to true to use zim.Bezier() with even turned on for even percentage distribution
returns an array of point objects with x, y properties and an r property for ratio of distance along path
recordData(toJSON) - returns an object with x, y, points, color, borderColor, borderWidth, move, toggle, controls PROPERTIES to be used with setData() method
if toJSON (default false) is set to true, the return value is a JSON string
the points data comes from the points property
setData(data, fromJSON) - sets the properties to match the data object passed in - this should come from recordData()
if fromJSON (default false) is set to true, it will assume a JSON string is passed in as data
the points data is parsed with the set setPoints() so the number of points should be the same
returns object for chaining
recordPoints(popup) - returns an array with the same format as the points parameter - or can just use points property
popup - (default false) set to true to open a zim Pane (blob.pane) with the points in a zim TextArea (blob.textArea) (click off to close)
NOTE: the TextArea output uses JSON.stringify() - to add the points to the points parameter of the Blob use JSON.parse(output);
NOTE: using zog(JSON.stringify(blob.recordData()))... the console will remove the quotes from the controlTypes so those would have to be manually put back in before parse() will work
setPoints(data) - sets the Blob points to the data from recordPoints
This does not remake the Blob but rather shifts the controls so the number of points should be the same
changeControl(index, type, rect1X, rect1Y, rect2X, rect2Y, circleX, circleY, update) - change a control type and properties at an index
accepts ZIM DUO normal parameters or configuration object literal with parameter names as propterties
passing in null as the index will change all points to the specified properties
the update parameter defaults to false so set to true to show update or call update() below
this is so multiple changes can be batched before calling update - for instance when animating blobs.
transformPoints(transformType, amount, x, y) - scale, rotate, move points without affecting controls or borderWidth - returns object for chaining
Note - does not adjust original Bounds
transformType - String any of: "scale", "scaleX", "scaleY", "rotation", "x", "y"
amount - the amount to transform
x, y - (default 0, 0) the x and y position to transform about
update(normalize) - update the Blob if animating control points, etc. would do this in a Ticker
set normalize (default false) to true to use pointsAdjusted for rotated and scaled points
use true for manually editing points after setting rotation or scale on point
just leave out if only animating points
showControls() - shows the controls (and returns blob) - or use blob.controlsVisible = true property
hideControls() - hides the controls (and returns blob) - or use blob.controlsVisible = false property
toggle(state - default null) - shows controls if hidden and hides controls if showing (returns the object for chaining)
or pass in true to show controls or false to hide controls
traverse(obj, start, end, time) - animates obj from start point to end point along path - thanks KV for the thought!
set start point greater than end point to traverse backwards
will dispatch a "traversed" event when done
setColorRange(color1, color2) - set a color range for shape - used by colorRange property - returns obj for chaining
if one color is used, the current color is used and color1 is the second color in the range
getPointAngle(index) - gets the angle made by the tangent at the index provided
getSegmentPoint(point1, point2) - returns an array of [point1, controlPoint1, controlPoint2, point2]
used internally for animating to path and adding removing Bezier points
getAdjacentSegmentData(index) - returns an array of two arrays:
The first is an array of cubic Bezier points for segments adjacent and including the provided point index
each element is in the form of [point1, controlPoint1, controlPoint2, point2]
The second is an array of starting point indexes for the segments that were tested
used internally to drag an animation along the path
will wrap around the blob if needed
getCurvePoint(ratio, segmentRatios, segmentPoints, getAngle) gets a point along whole curve at the ratio (0-1) provided
along with x and y values, the point has a z value that is the index of the blob point before the calculated point
if the getAngle parameter is true (default false) the point also has an angle property which is the angle of the tangent at the point
ratio is 0-1 with 0 being at the first point and 1 being at the end of the last segment (the first point)
segmentRatios and segmentPoints will be calculated if not provided
used internally for animating along the path - if lockControls is true, only animate will precalculate these values
linearGradient([colors],[ratios], x0,y0, x1,y1) - shortcut to colorCommand linearGradient method (see properties below)
radialGradient([colors],[ratios], x0,y0,radius0, x1,y1,radius1) - shortcut to colorCommand radialGradient method (see properties below)
cache(see Container docs for parameter description) - overrides CreateJS cache() and returns object for chaining
Leave parameters blank to cache bounds of shape (plus outer edge of border if borderWidth > 0)
hasProp(property as String) - returns true if property exists on object else returns false
clone(exact, commands) - makes a copy of the object
exact (default false)
ZIM VEE (Pick) values are active in clones unless exact is set to true
For instance, if the object's color is [blue, green]
then its clone might be blue or green - which could be different than the original
If exact is set to true then the clone will be the color of the original object
commands (default false) makes clones with current color commands of object
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
shape - gives access to the shape of the blob
color - get and set the fill color
colorRange - if setColorRange() is used, the colorRange is a ratio (0-1) between the colors
setting the colorRange will change the color property of the shape
for instance, shape.setColorRange(blue, pink) then shape.colorRange = .5
will set the color of the shape to half way between blue and pink
shape.animate({color:red}, 1000); is a shortcut to animate the colorRange
shape.wiggle("colorRange", .5, .2, .5, 1000, 5000) will wiggle the colorRange
colorCommand - access to the CreateJS fill command for bitmap, linearGradient and radialGradient fills
eg. shape.colorCommand.linearGradient([green, blue ,green], [.2, .5, .8], 0, 0, shape.width, 0)
See: https://www.createjs.com/docs/easeljs/classes/Graphics.Fill.html
borderColor - get and set the stroke color
borderColorCommand - access to the CreateJS stroke command for bitmap, linearGradient and radialGradient strokes
See: https://www.createjs.com/docs/easeljs/classes/Graphics.Stroke.html
borderWidth - get and set the stroke size in pixels
borderWidthCommand - access to the CreateJS stroke style command (width, caps, joints, miter, ignoreScale)
See: https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeStyle.html
dashed - get and set the dashed - use true / false or an array (see dashed parameter)
dashedOffset - get and set the offset of the dash (50 default) - can animate this property for a marquee effect
borderDashedCommand - access to the CreateJS stroke dashed command (segments, offset)
see https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeDash.html
stickColor - get or set the stick color of the controls - requires an update() to see changes
points - get or set the points array of the Blob in the same format as the points parameter:
a number, a shape string ("circle", "rectangle", "triangle"), a ZIM Circle, Rectangle, Triangle
or an array as follows:
[[controlX, controlY, circleX, circleY, rect1X, rect1Y, rect2X, rect2Y, controlType], [etc]]
pointsAdjusted - get points with any point rotation converted to 0 - see update(true)
pointControls - get an array of controls (a container) - use this to animate controls
pointCircles - get an array of control circles - use this to place some other object at the point
pointObjects - get an array of point objects for each point in the following format:
[[control, circle, rect1, rect2, controlType], [etc.]]
control - the container for the control that holds the circle and rectangles (also see pointControls)
circle - the control point circle (also see pointCircles)
rect1 - the first control point rectangle
rect2 - the second control point rectangle
controlType - the control type: default is "straight" (or null) and there is also "mirror", "free" and "none"
NOTE: control, circle, rect1, rect2 can be positioned or animated and controlType can be changed
NOTE: the update() method must be called if manually changing the control positions or type
NOTE: if constantly animating the controls then use a Ticker.add(function(){blob.update();})
NOTE: also see recordData(), setData(), recordPoints(), setPoints() methods for further options
addPointFactor - (default 20) used when placing new points along edge (editPoints is true)
divides the distance between points by this amount - the smaller the more accurate but also slower
addMinDistance - (default 15) edge press needs to be within this distance to add a point to the edge
segmentPoints - a read-only array of cubic Bezier points for each segment
each element is in the form of [point1, controlPoint1, controlPoint2, point2]
used internally to animate to the path and add and remove Bezier points
segmentRatios - a read-only array of cumulative ratio lengths of segments
for instance the default four points is [.25, .5, .75, 1]
used internally to animate to the path and attribute proportional time to each segment
controls - access to the container that holds the sets of controls
each control is given a read-only num property
sticks - access to the container that holds the control sticks
lastSelected - access to the last selected (or created) control container
lastSelectedIndex - the index number of the last selected controls
controlsVisible - get or set the visibility of the controls - or use showControls() and hideControls()
types - get or set the general array for the types ["mirror", "straight", "free", "none"]
changing this or removing a type will adjust the order when the user double clicks the points to change their type
this is not an array of types for each point - see the points property to access the types of each point
lockControls - Boolean to lock controls from being adjusted or not
allowToggle - Boolean to get or set clicking to show and hide controls
move - Boolean to drag or not drag Blob when controls are showing
can also set to "always" to allow movement when controls are not showing
lockControlType - Boolean to lock the type of the controls in their current state or not
onTop - get or set the onTop property
selectPoints - get or set whether points can be selected
interactive - get or set whether the shape is interactive - toggle, move, change or add controls, etc.
keyFocus - get or set the keyboard focus on the DisplayObject - see also zim.KEYFOCUS
will be set to true if this DisplayObject is the first made or DisplayObject is the last to be used with keyboard
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
dispatches a "change" event for when the bezier controls are adjusted (pressup only or moving with keys - thanks Yui Kim for find)
if monitoring constant change is needed add a pressmove event to Blob.sets
the change event object has a transformType property with values of "move", "bezierPoint", "bezierHandle", "bezierSwitch"
dispatches "controlsshow" and "controlshide" events when clicked off and on and toggle is true
dispatches an "update" event if the points are changed or a point is added or removed
this removes all listeners on the old shape and controls
so any custom listeners on shape and controls will need to be re-applied - use the update event to do so
dispatches a "traversed" event when traverse() is done - the event object has an obj property for the traversing object
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+53.5
zim.Blob = function(color, borderColor, borderWidth, points, radius, controlLength, controlType, lockControlType, showControls, lockControls, handleSize, allowToggle, move, dashed, onTop, stickColor, selectColor, selectPoints, editPoints, interactive, strokeObj, style, group, inherit) {
var sig = "color, borderColor, borderWidth, points, radius, controlLength, controlType, lockControlType, showControls, lockControls, handleSize, allowToggle, move, dashed, onTop, stickColor, selectColor, selectPoints, editPoints, interactive, strokeObj, style, group, inherit";
var duo; if (duo = zob(zim.Blob, arguments, sig, this)) return duo;
z_d("53.5");
this.group = group;
var DS = style===false?{}:zim.getStyle("Blob", this.group, inherit);
if (zot(radius)) radius = DS.radius!=null?DS.radius:100;
this.zimCustomShape_constructor(-radius,-radius,radius*2,radius*2,false);
this.type = "Blob";
this.mouseChildren = true; // set to false in CustomShape
if (zot(dashed)) dashed = DS.dashed!=null?DS.dashed:false;
if (zot(borderColor)) borderColor = DS.borderColor!=null?DS.borderColor:null;
if (zot(borderWidth)) borderWidth = DS.borderWidth!=null?DS.borderWidth:null;
if (borderColor < 0 || borderWidth < 0) borderColor = borderWidth = null;
else if (borderColor!=null && borderWidth==null) borderWidth = 1;
if (zot(color)) color = DS.color!=null?DS.color:(borderWidth>0?"rgba(0,0,0,0)":zim.green);
if (color.style) {this.colorCommand = color; color = "black";}
if (borderColor && borderColor.style) {this.borderColorCommand = borderColor; borderColor = "black";}
if (zot(points)) points = DS.points!=null?DS.points:4;
var num = typeof points == "number" ? points : points.length;
var controlLengthOriginal = controlLength;
if (zot(controlLength)) controlLength = DS.controlLength!=null?DS.controlLength:(radius * 4 / num);
if (zot(controlType)) controlType = DS.controlType!=null?DS.controlType:null;
var originalControlType = controlType;
if (zot(controlType)) controlType = "straight";
if (zot(lockControlType)) lockControlType = DS.lockControlType!=null?DS.lockControlType:false;
if (zot(interactive)) interactive = DS.interactive!=null?DS.interactive:true;
if (zot(showControls)) showControls = DS.showControls!=null?DS.showControls:interactive;
var _controls = showControls;
if (zot(lockControls)) lockControls = DS.lockControls!=null?DS.lockControls:!interactive;
if (zot(handleSize)) handleSize = DS.handleSize!=null?DS.handleSize:(zim.mobile()?20:10);
if (zot(allowToggle)) allowToggle = DS.allowToggle!=null?DS.allowToggle:interactive;
if (zot(move)) move = DS.move!=null?DS.move:interactive;
if (zot(stickColor)) stickColor = DS.stickColor!=null?DS.stickColor:"#111";
if (zot(selectColor)) selectColor = DS.selectColor!=null?DS.selectColor:"#fff";
if (zot(selectPoints)) selectPoints = DS.selectPoints!=null?DS.selectPoints:interactive;
this.stickColor = stickColor;
if (zot(onTop)) onTop = DS.onTop!=null?DS.onTop:true;
if (zot(editPoints)) editPoints = DS.editPoints!=null?DS.editPoints:interactive;
if (zot(strokeObj)) strokeObj = DS.strokeObj!=null?DS.strokeObj:{};
var oa = remember(color, borderColor);
function remember() {return arguments;} // for cloning PICK
color = zim.Pick.choose(color);
borderColor = zim.Pick.choose(borderColor);
var that = this;
this.interactive = interactive;
this.num = num;
this.editPoints = editPoints;
this.selectPoints = selectPoints;
this.lockControls = lockControls;
this.onTop = onTop;
this.move = move;
this.allowToggle = allowToggle;
this.lockControlType = lockControlType;
var types = this.types = ["mirror", "straight", "free", "none"];
var _points;
var _pointCircles;
var _pointControls;
that._color = color;
that._borderColor = borderColor;
that._borderWidth = borderWidth;
that._dashed = dashed;
if (that._dashed && !Array.isArray(that._dashed)) that._dashed = [10, 10];
var shape;
var moveDownEvent;
var movePressEvent;
var moveUpEvent;
var stage;
var draggingCheck = that.move;
var min = 2; // distance within which to count as click to add point
var mapMove;
var sets;
points = checkForShape(points);
function checkForShape(shape) {
if (shape=="circle" || shape == "rectangle" || shape =="triangle") {
if (shape == "circle") shape = new zim.Circle(radius);
if (shape == "rectangle") shape = new zim.Rectangle(radius*2,radius*2).centerReg({add:false});
if (shape == "triangle") shape = new zim.Triangle(radius*2,radius*2,radius*2);
}
var points;
if (shape.type == "Circle" || shape.type == "Rectangle" || shape.type == "Triangle") {
var b = shape.getBounds();
if (shape.type == "Circle") {
points = 4;
controlLengthOriginal = controlLength = radius*2*.5523;
} else if (shape.type == "Rectangle") {
shape.centerReg({add:false});
points = [[b.x-b.width/2, b.y-b.height/2],[b.x+b.width/2, b.y-b.height/2],[b.x+b.width/2, b.y+b.height/2],[b.x-b.width/2, b.y+b.height/2]];
that.setBounds(b.x-b.width/2, b.y-b.height/2, b.width, b.height);
that.regX = shape.regX-b.width/2;
that.regY = shape.regY-b.height/2;
// this.rotation = shape.rotation;
// this.scaleX = shape.scaleX;
// this.scaleY = shape.scaleY;
} else if (shape.type == "Triangle") {
points = [[shape.three.x-shape.width/2, shape.three.y+shape.height/2+shape.adjusted],[shape.two.x-shape.width/2, shape.two.y+shape.height/2+shape.adjusted],[shape.one.x-shape.width/2, shape.one.y+shape.height/2+shape.adjusted]];
that.setBounds(b.x-b.width/2, b.y-b.height/2, b.width, b.height);
}
return points;
} else {
return shape;
}
}
if (typeof points == "string") {
var svgProcessor = new zim.SVGContainer();
points = svgProcessor.processPath(points);
}
if (originalControlType && typeof points != "number") {
// override controlType
zim.loop(points, function(point) {
point[8]=originalControlType;
if (originalControlType == "none") {
point[4]=point[5]=point[6]=point[7]=0;
}
});
}
init();
function init() {
if (sets) sets.removeAllEventListeners();
if (that.selectPoints) {
that.selectedBalls = new zim.SelectionSet();
that.selectedRect1s = new zim.SelectionSet();
that.selectedRect2s = new zim.SelectionSet();
that.selectionManager = new zim.SelectionManager([
that.selectedBalls,
that.selectedRect1s,
that.selectedRect2s
], "ctrl", false);
} else {
that.selectionManager = new zim.SelectionManager(null, "ctrl");
}
num = typeof points == "number" ? points : points.length;
if (num <= 0) return;
if (zot(controlLengthOriginal)) controlLength = radius * 4 / num;
shape = that.shape = new zim.Shape({style:false}).addTo(that);
var sticks = that.sticks = new zim.Shape({style:false}).addTo(that);
if (handleSize <= 0) sticks.removeFrom();
var g = shape.graphics;
g.c();
var s = sticks.graphics;
s.c();
var ballS = handleSize/10*8;
var rectS = handleSize;
var mobile = zim.mobile();
sets = that.controls = new zim.Container({style:false}).addTo(that); // sets - a set contains a ball and two rects
if (that.interactive) sets.drag({onTop:!mobile});
_points = [];
_pointControls = [];
_pointCircles = [];
var angle, point, temp, set, rect1, rect2, ball, type, setInfo;
for (var i=0; i<num; i++) {
set = new zim.Container({style:false}).addTo(sets);
set.num = i;
if (typeof points == "number") { // no sets yet
// easier to create controls in a temp vertical Container
// set the registration point at the circle center
// then rotate the temp container
// then get the resulting rotated coordinates and use localToLocal
// to find coordinates of controls in set Container
// afterwards, adjust controls in set Container so origin and registration is at ball
// then move the set Container so it matches that adjustment
// (or could have calculated all positions to start with aTan2, sin, cos etc.)
var length = zim.Pick.choose(controlLength);
temp = new zim.Container(length, radius, null, null, false).reg(length/2, radius).addTo(that);
temp.rotation = i/num * 360;
ball = new zim.Circle(ballS, that.selectPoints&&that.selectedBalls.isSelected(i)?selectColor:zim.light, zim.dark, 2, null, null, null, null, false)
.centerReg(temp)
.loc({x:length/2,y:0});
rect1 = new zim.Rectangle(rectS, rectS, that.selectPoints&&that.selectedRect1s.isSelected(i)?selectColor:getBackgroundColor(controlType), handleSize==0?null:zim.dark, handleSize==0?null:2, null, null, null, false)
.centerReg(temp)
.loc({x:0,y:0});
rect2 = new zim.Rectangle(rectS, rectS, that.selectPoints&&that.selectedRect2s.isSelected(i)?selectColor:getBackgroundColor(controlType), handleSize==0?null:zim.dark, handleSize==0?null:2, null, null, null, false)
.centerReg(temp)
.loc({x:length,y:0});
var ballPoint = temp.localToLocal(ball.x, ball.y, sets);
ball.x = ballPoint.x;
ball.y = ballPoint.y;
ball.addTo(set, null, false);
var rect1Point = temp.localToLocal(rect1.x, rect1.y, sets);
rect1.x = controlType=="none"?0:rect1Point.x-ball.x;
rect1.y = controlType=="none"?0:rect1Point.y-ball.y;
rect1.addTo(set, null, false);
var rect2Point = temp.localToLocal(rect2.x, rect2.y, sets);
rect2.x = controlType=="none"?0:rect2Point.x-ball.x;
rect2.y = controlType=="none"?0:rect2Point.y-ball.y;
rect2.addTo(set, null, false);
set.x = ball.x;
set.y = ball.y;
ball.x = 0;
ball.y = 0;
if (controlType=="none") ball.addTo(set, null, false); // on top
} else { // passing in set data
// balls are relative to blob but handles are relative to ball
// points is an array of [[setX, setY, ballX, ballY, handleX, handleY, handle2X, handle2Y, type], etc.]
setInfo = points[i];
type = setInfo[8] ? setInfo[8] : controlType;
set.loc({x:setInfo[0], y:setInfo[1]});
ball = new zim.Circle(ballS, zim.light, zim.dark, 2, null, null, null, null, false)
.centerReg({add:false})
.addTo(set)
.loc({x:setInfo[2],y:setInfo[3]});
rect1 = new zim.Rectangle(rectS, rectS, getBackgroundColor(type), handleSize==0?null:zim.dark, handleSize==0?null:2, null, null, null, false)
.centerReg({add:false})
.addTo(set, 0)
.loc({x:setInfo[4],y:setInfo[5]});
rect2 = new zim.Rectangle(rectS, rectS, getBackgroundColor(type), handleSize==0?null:zim.dark, handleSize==0?null:2, null, null, null, false)
.centerReg({add:false})
.addTo(set, 0)
.loc({x:setInfo[6],y:setInfo[7]});
}
ball.mySet = set;
ball.rect1 = rect1;
ball.rect2 = rect2;
ball.index = i;
if (handleSize==0) {
ball.expand(10);
rect1.expand(10);
rect2.expand(10);
}
if (mobile) {
ball.on("mousedown", mobileDouble);
} else {
ball.on("dblclick", doubleIt);
}
rect1.ball = ball;
rect1.other = rect2;
rect2.ball = ball;
rect2.other = rect1;
if (mobile) {
ball.expand();
rect1.expand();
rect2.expand();
}
point = [set, ball, rect1, rect2, setInfo?setInfo[8]:controlType];
_points.push(point);
_pointCircles.push(ball);
_pointControls.push(set);
}
var tappedTwice = false;
function mobileDouble(e) {
if (!tappedTwice) {
tappedTwice = true;
setTimeout(function() {
tappedTwice = false;
}, 300);
} else {
e.preventDefault();
doubleIt(e);
}
}
function doubleIt(e) {
if (that.lockControlType) return;
var ball = e.target;
// cycle through the types
var type = _points[ball.index][4] ? _points[ball.index][4] : controlType;
if (Math.abs(ball.rect1.x) <= 2 && Math.abs(ball.rect1.y) <= 2 && Math.abs(ball.rect2.x) <= 2 && Math.abs(ball.rect2.y) <= 2) {
type = "none";
}
if (type == "none") {
ball.parent.addChildAt(ball, 0);
}
// modulus going backwards needs to add the length so it does not go negative
type = that.types[(that.types.indexOf(type)+(that.shiftKey?-1:1)+that.types.length)%that.types.length];
if (type == "none") {
ball.rect1.x = ball.rect1.y = ball.rect2.x = ball.rect2.y = 0;
ball.parent.addChild(ball);
e.stopImmediatePropagation();
}
_points[ball.index][4] = type;
ball.rect1.color = getBackgroundColor(type);
ball.rect2.color = getBackgroundColor(type);
that.drawShape();
var ev = new createjs.Event("change");
ev.controlType = "bezierSwitch";
that.dispatchEvent(ev);
ball.stage.update();
}
function getBackgroundColor(type) {
var colors = {mirror:zim.purple, free:zim.yellow, none:zim.blue};
return colors[type] ? colors[type] : zim.pink;
}
that.drawShape = function() {
g.c();
if (!that.colorCommand) {
that.colorCommand = g.f(that._color).command;
if (color && color.type) that.specialColor(that.colorCommand, color);
}
// border of 0 or a string value still draws a border in CreateJS
if (zot(that._borderWidth) || that._borderWidth > 0) { // no border specified or a border > 0
if (!zot(that._borderColor) || !zot(that._borderWidth)) { // either a border color or thickness
if (zot(that._borderColor)) that._borderColor = "black";
if (!that.borderColorCommand) {
that.borderColorCommand = g.s(that._borderColor).command;
if (that._borderColor && that._borderColor.type) that.specialColor(that.borderColorCommand, that._borderColor);
}
if (!that.borderWidthCommand) that.borderWidthCommand = g.ss(that._borderWidth, strokeObj.caps, strokeObj.joints, strokeObj.miterLimit, strokeObj.ignoreScale).command;
if (that._dashed) {
if (!that.borderDashedCommand) that.borderDashedCommand = g.sd(Array.isArray(that._dashed)?that._dashed:[10, 10], that._dashedOffset).command;
}
}
}
var set = _points[0][0];
var ballPoint = set.localToLocal(_points[0][1].x, _points[0][1].y, shape);
g.mt(ballPoint.x, ballPoint.y);
s.c().s(that.stickColor).ss(1);
var currentIndex; var nextIndex;
for (var i=0; i<_points.length; i++) {
var currentIndex = i;
var nextIndex = (i+1)%_points.length;
var set = _points[currentIndex][0];
var ball = _points[currentIndex][1];
var control1 = _points[currentIndex][2];
var control2 = _points[currentIndex][3];
var nextSet = _points[nextIndex][0];
var nextBall = _points[nextIndex][1];
var nextControl1 = _points[nextIndex][2];
var nextControl2 = _points[nextIndex][3];
var control2Point = set.localToLocal(control2.x, control2.y, shape);
var nextControl1Point = nextSet.localToLocal(nextControl1.x, nextControl1.y, shape);
var nextBallPoint = nextSet.localToLocal(nextBall.x, nextBall.y, shape);
g.bt(
control2Point.x, control2Point.y,
nextControl1Point.x, nextControl1Point.y,
nextBallPoint.x, nextBallPoint.y
);
// create the sticks
var ballPoint = set.localToLocal(ball.x, ball.y, shape);
var control1Point = set.localToLocal(control1.x, control1.y, shape);
s.mt(ballPoint.x, ballPoint.y).lt(control1Point.x, control1Point.y);
s.mt(ballPoint.x, ballPoint.y).lt(control2Point.x, control2Point.y);
}
g.cp();
g.append(that.colorCommand);
if (that._dashed) g.append(that.borderDashedCommand);
if (that.borderWidthCommand) g.append(that.borderWidthCommand);
if (that.borderColorCommand) g.append(that.borderColorCommand);
};
that.drawShape();
var startPosition;
sets.on("mousedown", function(e) {
if (that.lockControls) return;
if (that.selectPoints) that.keyFocus = true;
startPosition = {x:e.target.x, y:e.target.y};
if (e.target.rect1) { // then mousedown on ball
var ball = e.target;
ball.startX = ball.x;
ball.startY = ball.y;
ball.rect1.startX = ball.rect1.x;
ball.rect1.startY = ball.rect1.y;
ball.rect2.startX = ball.rect2.x;
ball.rect2.startY = ball.rect2.y;
} else { // mousedown on control
var rect = e.target;
rect.startX = rect.x;
rect.startY = rect.y;
var ball = rect.ball;
var index = ball.index;
var type = controlType;
if (!zot(_points[index][4])) type = _points[index][4];
if (type == "straight") {
var other = rect.other;
var dX = other.x - ball.x;
var dY = other.y - ball.y;
other.stickLength = Math.sqrt(Math.pow(dX,2) + Math.pow(dY,2));
}
}
if (that.selectPoints) {
// need to reset all start points for each control circle and rectangle moved
var currentSet = that.selectionManager.currentSet;
if (currentSet && currentSet.selections && currentSet.selections.length > 0) {
for(var i=0; i<currentSet.selections.length; i++) {
var point = that.pointObjects[currentSet.selections[i]];
point[1].startX = point[1].x;
point[1].startY = point[1].y;
point[2].startX = point[2].x;
point[2].startY = point[2].y;
point[3].startX = point[3].x;
point[3].startY = point[3].y;
}
}
}
});
if (that.selectPoints) {
sets.tap(function (e) {
if (e.target.rect1) { // then mousedown on ball - which has a rect1
var ball = e.target;
that.selectedBalls.toggle(ball.parent.num);
} else { // mousedown on control
var rect = e.target;
rect.color = "white";
var ball = rect.ball;
if (ball.rect1 == rect) that.selectedRect1s.toggle(ball.parent.num);
else that.selectedRect2s.toggle(ball.parent.num);
}
// loop through all controls and set to right color based on selection
for (var i=0; i<that.pointObjects.length; i++) {
var po = that.pointObjects[i];
po[1].color = that.selectedBalls.isSelected(i)?zim.white:zim.light;
po[2].color = that.selectedRect1s.isSelected(i)?zim.white:getBackgroundColor(po[4]);
po[3].color = that.selectedRect2s.isSelected(i)?zim.white:getBackgroundColor(po[4]);
}
e.target.stage.update();
});
}
sets.on("pressmove", function(e) {
if (that.lockControls) return;
if (that.selectPoints) {
var currentSelected = getCurrentSelected();
if (currentSelected.indexOf(e.target) == -1) {
mapMove(e.target);
that.drawShape();
} else {
if (currentSelected.length > 0) {
var diffX = e.target.x-e.target.startX;
var diffY = e.target.y-e.target.startY;
for(var i=0; i<currentSelected.length; i++) {
var pointObj = currentSelected[i];
pointObj.x = pointObj.startX + diffX;
pointObj.y = pointObj.startY + diffY;
mapMove(pointObj);
}
that.drawShape();
}
}
} else {
mapMove(e.target);
that.drawShape();
}
});
sets.on("pressup", function(e) {
if (that.lockControls) return;
var moveControlCheck = (e.target.x != startPosition.x || e.target.y != startPosition.y);
var ev = new createjs.Event("change");
if (e.target.rect1) { // pressup on ball
ev.controlType = "bezierPoint";
endMove(e.target);
} else {
ev.controlType = "bezierHandle";
}
if (moveControlCheck) that.dispatchEvent(ev);
});
function endMove(target) {
if (that.selectPoints) {
var currentSelected = getCurrentSelected();
if (currentSelected && currentSelected.indexOf(target) == -1) {
replaceControls(target);
} else if (currentSelected && currentSelected.length>0) {
for(var i=0; i<currentSelected.length; i++) {
replaceControls(currentSelected[i]);
}
} else {
replaceControls(target);
}
} else {
replaceControls(target);
}
}
that.changeControl = function(index, type, rect1X, rect1Y, rect2X, rect2Y, circleX, circleY, update) {
var sig = "index, type, rect1X, rect1Y, rect2X, rect2Y, circleX, circleY, update";
var duo; if (duo = zob(that.changeControl, arguments, sig)) return duo;
if (zot(index)) {
for (var i=0; i<_points.length; i++) {
that.changeControl(i, type, rect1X, rect1Y, rect2X, rect2Y, circleX, circleY);
}
return that;
}
var point = _points[index];
point[4] = type;
if (type == "none") {
if (!zot(circleX)) point[1].x = circleX;
if (!zot(circleY)) point[1].y = circleY;
point[2].x = point[1].x,
point[2].y = point[1].y;
point[3].x = point[1].x,
point[3].y = point[1].y;
point[1].parent.addChild(point[1]);
} else {
if (!zot(circleX)) point[1].x = circleX;
if (!zot(circleY)) point[1].y = circleY;
if (!zot(rect1X)) point[2].x = rect1X;
if (!zot(rect1Y)) point[2].y = rect1Y;
if (!zot(rect2X)) point[3].x = rect2X;
if (!zot(rect2Y)) point[3].y = rect2Y;
point[1].parent.addChildAt(point[1], 0);
}
point[2].color = getBackgroundColor(type);
point[3].color = getBackgroundColor(type);
if (update) {
that.update();
if (that.stage) that.stage.update();
}
return that;
};
that.transformPoints = function(transformType, amount, x, y) {
that.points = zim.transformPoints(that.points, transformType, amount, x, y);
return that;
};
that.traverse = function(obj, start, end, time) {
var ratios = zim.copy(that.segmentRatios);
ratios.unshift(0);
if (zot(end)) end = start+1;
var forward = start < end;
if (forward) {
var startPercent = ratios[start]*100;
var endPercent = ratios[end]*100;
} else {
var startPercent = 50 + (100 - ratios[start]*100)/2;
var endPercent = 50 + (100 - ratios[end]*100)/2;
}
obj.percentComplete = startPercent;
obj.animate({
ease:"linear",
props:{path:that},
rewind:!forward,
time:time,
events:true
});
obj.on("animation", function (e) {
// when it hits the end it may start over
if (obj.percentComplete > endPercent || obj.percentComplete == 0) {
obj.stopAnimate();
e.remove();
var eventObj = new createjs.Event("traversed");
eventObj.obj = obj;
that.dispatchEvent(eventObj);
}
});
return that;
};
that.update = function(normalize) {
if (normalize) {
// located any rotated or scaled points
// and set them back to non-rotated and non-scaled
// but keep control handles at the earlier positions
// need to normalize before doing more manual updates with Beziers
// do not need to normalize if animating blob points
that.points = that.pointsAdjusted;
} else {
that.drawShape();
}
that.zimAnimateChanged = true;
return that;
};
// blob
if (that.move && that.interactive) shape.drag({onTop:false});
moveDownEvent = shape.on("mousedown", function(e) {
stage = e.target.stage;
startPosition = {x:shape.x, y:shape.y};
if (that.selectPoints) that.keyFocus = true;
upTop();
});
movePressEvent = shape.on("pressmove", function() {
sets.x = shape.x;
sets.y = shape.y;
sticks.x = shape.x;
sticks.y = shape.y;
});
moveUpEvent = shape.on("pressup", function() {
var moveControlCheck = (shape.x != startPosition.x || shape.y != startPosition.y);
var movePoint = shape.localToLocal(that.regX,that.regY,that.parent);
that.x = movePoint.x;
that.y = movePoint.y;
sets.x = sets.y = sticks.x = sticks.y = shape.x = shape.y = 0;
if (moveControlCheck) {
var ev = new createjs.Event("change");
ev.controlType = "move";
that.dispatchEvent(ev);
}
stage.update();
});
if (!move) stopDragging(true);
function upTop() {
if (that.onTop) {
var nc = that.parent.numChildren-1;
if (that.parent.getChildAt(nc).type == "Keyboard") nc--;
that.parent.setChildIndex(that, nc);
}
}
that.toggleEvent = that.on("mousedown", function() {
if (!that.allowToggle) return;
if (!_controls) {
that.showControls();
that.dispatchEvent("controlsshow");
}
});
that.added(function() {
stage = that.stage;
if (that.toggleStageEvent) that.stage.off("stagemousedown", that.toggleStageEvent);
that.toggleStageEvent = that.stage.on("stagemousedown", function(e) {
if (!that.allowToggle || !that.stage) return;
if (_controls && !that.hitTestPoint(e.stageX/zim.scaX, e.stageY/zim.scaY, false)) {
that.hideControls();
that.dispatchEvent("controlshide");
}
});
});
that.clickEvent = that.on("click", function() {
if (that.ctrlKey) {
setTimeout(function() { // give time for record to work if drag with ctrl down
that.clone(true).addTo(that.stage).mov(100);
if (that.allowToggle) {
that.hideControls();
that.dispatchEvent("controlshide");
}
var ev = new createjs.Event("change");
ev.controlType = "move";
that.dispatchEvent(ev);
that.stage.update();
}, 50);
}
});
that.hideControls = function() {
that.toggled = false;
sets.visible = false;
sticks.visible = false;
_controls = false;
if (that.stage) that.stage.update();
if (!that.allowToggle && that.move) stopDragging();
return that;
};
if (!_controls) that.hideControls();
that.showControls = function() {
// if call this with code then will not trigger a change event - not good for TransformManager.persist()
that.toggled = true;
sets.visible = true;
sticks.visible = true;
_controls = true;
sets.x = shape.x;
sets.y = shape.y;
sticks.x = shape.x;
sticks.y = shape.y;
that.addChildAt(shape,0); // put to bottom in case dragged
if (that.move && !that.allowToggle) startDragging();
if (that.stage) that.stage.update();
return that;
};
that.toggle = function(state) {
if (state===true) that.showControls();
else if (state===false) that.hideControls();
else if (_controls) that.hideControls();
else that.showControls();
return that;
};
that.recordData = function(toJSON) {
if (zot(toJSON)) toJSON = false;
var obj = {
type:"Blob",
index:that.parent?that.parent.getChildIndex(that):-1,
x:that.x, y:that.y,
points:that.recordPoints(),
color:that.color,
borderColor:that.borderColor,
borderWidth:that.borderWidth,
move:that.move,
toggle:that.allowToggle,
controlsVisible:_controls
};
if (toJSON) return JSON.stringify(obj);
return obj;
};
that.setData = function(data, fromJSON) {
if (zot(data)) return;
if (fromJSON) {
try{
data = JSON.parse(data);
} catch (e) {
return;
}
}
var index = data.index;
if (zot(index)) index = -1;
delete data.index;
var pointData = data.points;
if (!zot(pointData)) that.setPoints(pointData);
delete data.points;
this.num = pointData.length;
for (var d in data) {
that[d] = data[d];
}
if (that.parent) {
that.parent.setChildIndex(that, index);
}
return that;
};
that.recordPoints = function(popup) {
// _pointCircles are relative to blob but handles are relative to ball
// points is an array of [[ballX, ballY, handleX, handleY, handle2X, handle2Y, type], etc.]
if (zot(popup)) popup = false;
var points = that.points;
if (popup) {
if (!pane) {
var pane = that.pane = new zim.Pane({
displayClose:false,
container:that.stage,
width:Math.min(500, that.stage.width-20),
height:Math.min(500, that.stage.height-20),
draggable:true,
});
var textArea = that.textArea = new zim.TextArea(Math.min(400, that.stage.width-70), Math.min(400, that.stage.height-70));
textArea.centerReg(pane);
}
pane.show();
textArea.text = JSON.stringify(points);
}
return points;
};
that.setPoints = function(points) {
// adjust blob to match points passed in from recordPoints
var p;
var p2;
for (var i=0; i<points.length; i++) {
p = _points[i];
p2 = points[i];
if (zot(p)) continue;
p[0].x = p2[0];
p[0].y = p2[1];
p[1].x = p2[2];
p[1].y = p2[3];
p[2].x = p2[4];
p[2].y = p2[5];
p[3].x = p2[6];
p[3].y = p2[7];
p[4] = p2[8];
p[2].color = getBackgroundColor(p[4]);
p[3].color = getBackgroundColor(p[4]);
}
that.update();
return that;
};
if (style!==false) zim.styleTransforms(that, DS);
that.clone = function(exact, commands) {
var newShape = that.cloneProps(new zim.Blob(commands?that.colorCommand:((exact||!zim.isPick(oa[0]))?that.color:oa[0]), commands?that.borderColorCommand:((exact||!zim.isPick(oa[1]))?that.borderColor:oa[1]), that.borderWidth, that.recordPoints(), radius, controlLength, controlType, lockControlType, sets.visible, lockControls, handleSize, that.allowToggle, that.move, dashed, onTop, stickColor, selectColor, selectPoints, that.editPoints, interactive, strokeObj, style, that.group, inherit));
if (that.linearGradientParams) newShape.linearGradient.apply(newShape, that.linearGradientParams);
if (that.radialGradientParams) newShape.radialGradient.apply(newShape, that.radialGradientParams);
return newShape;
};
// to add a control - make sure click in one spot - not drag
that.shapeMousedownEvent = that.shape.on("mousedown", function (e) {
stage = e.target.stage;
if (!that.editPoints) return;
if (that.controlsVisible) {
that.pressX = e.stageX/zim.scaX;
that.pressY = e.stageY/zim.scaY;
} else {
that.pressX = null;
that.pressY = null;
}
});
that.addPointFactor = 10;
that.addMinDistance = 15;
that.shapePressupEvent = that.shape.on("pressup", function (e) {
if (!that.editPoints) return;
if (that.pressX && Math.abs(that.pressX-e.stageX/zim.scaX) < min && Math.abs(that.pressY-e.stageY/zim.scaY) < min) {
if (that.selectPoints) that.lastPoints = zim.copy(that.points);
var points = that.points;
var point = that.globalToLocal(e.stageX/zim.scaX, e.stageY/zim.scaY);
var pointBefore = zim.closestPointAlongCurve(point, that.segmentPoints);
if (that.editPoints == "anywhere") {
points.splice(pointBefore+1, 0, [point.x, point.y, 0,0, 0,0, 0,0]);
that.points = points;
that.changeControl({index:pointBefore+1, type:"mirror", update:true});
} else { // only on edge
// test close enough to edge otherwise return
var p = that.pointsAdjusted;
var cubic = that.getSegmentPoint(p[pointBefore], p[(pointBefore+1)%p.length]);
var length = zim.distanceAlongCurve(cubic);
var testNum = Math.round(length/that.addPointFactor);
var testPoints = that.interpolate(testNum, pointBefore, false, points);
var closest=10000;
var closestPoint;
var closestIndex;
zim.loop(testPoints, function (p, k) {
if (k==0) return; // don't put on existing point
var d = zim.dist(p, point);
if (d < closest) {
closest = d;
closestIndex = k;
closestPoint = p;
}
});
if (closest < that.addMinDistance) {
var ratios = that.segmentRatios;
var currentRatio = ratios[pointBefore];
var lastRatio = pointBefore>0?ratios[pointBefore-1]:0;
that.addPoint(100*(lastRatio+(currentRatio-lastRatio)*(closestIndex/(testNum+1))));
}
}
that.lastSelectedIndex = pointBefore+1;
that.lastSelected = that.controls.getChildAt(that.lastSelectedIndex);
that.stage.update();
}
});
// remove point
that.controlsClickEvent = that.controls.on("click", function (e) {
that.lastSelected = e.target.parent;
var index = that.lastSelectedIndex = that.controls.getChildIndex(e.target.parent);
if (!that.editPoints) return;
if (that.selectionManager.shiftKey) { // remove
removeControl(e);
}
});
function removeControl(e) {
if (e.target.type == "Circle") {
var index = that.lastSelectedIndex = that.controls.getChildIndex(e.target.parent);
if (that.controls.numChildren <= 2) return;
var points = that.points;
if (that.selectPoints) that.lastPoints = zim.copy(points);
points.splice(index, 1); // remove the point at the index
that.points = points;
that.stage.update();
that.lastSelected = that.lastSelectedIndex = null;
}
}
that.controls.hold(removeControl);
if (!_controls) that.hideControls();
that.dispatchEvent("update");
} // end of init()
function getCurrentSelected() {
var answer = [];
var currentSet = that.selectionManager.currentSet;
if (currentSet && currentSet.selections && currentSet.selections.length > 0) {
for(var i=0; i<currentSet.selections.length; i++) {
var point = that.pointObjects[currentSet.selections[i]];
if (currentSet == that.selectedBalls) {
answer.push(point[1]);
} else if (currentSet == that.selectedRect1s) {
answer.push(point[2]);
} else if (currentSet == that.selectedRect2s) {
answer.push(point[3]);
} else {
continue;
}
}
}
return answer;
}
function replaceControls(target) {
if (!that.selectPoints) return;
// move ball back to origin and move set accordingly
// so if we animate the set it will behave as expected
if (target.type != "Circle") return;
var ball = target;
var set = ball.mySet;
var rect1 = ball.rect1;
var rect2 = ball.rect2;
rect1.x -= ball.x;
rect1.y -= ball.y;
rect2.x -= ball.x;
rect2.y -= ball.y;
set.x += ball.x;
set.y += ball.y;
ball.x = 0;
ball.y = 0;
}
that.selectionManager.on("keydown", function (e) {
if (!that.selectPoints) return;
if (!that.keyFocus) return;
if (e.keyCode >= 37 && e.keyCode <= 40) {
var currentSelected = getCurrentSelected();
if (currentSelected.length > 0) {
for(var i=0; i<currentSelected.length; i++) {
var pointObj = currentSelected[i];
if (e.keyCode == 37) pointObj.x -= that.selectionManager.shiftKey?10:1;
else if (e.keyCode == 39) pointObj.x += that.selectionManager.shiftKey?10:1;
else if (e.keyCode == 38) pointObj.y -= that.selectionManager.shiftKey?10:1;
else if (e.keyCode == 40) pointObj.y += that.selectionManager.shiftKey?10:1;
mapMove(pointObj);
}
that.drawShape();
that.dispatchEvent("update");
if (that.stage) that.stage.update();
}
}
});
that.selectionManager.on("keyup", function (e) {
if (!that.selectPoints) return;
if (!that.keyFocus) return;
if (e.keyCode >= 37 && e.keyCode <= 40) {
var currentSelected = getCurrentSelected();
if (currentSelected.length > 0) {
for(var i=0; i<currentSelected.length; i++) {
replaceControls(currentSelected[i]);
}
}
}
});
that.selectionManager.on("undo", function () {
if (!that.selectPoints) return;
if (!that.keyFocus) return;
if (that.lastPoints) {
var tempPoints = zim.copy(that.lastPoints);
that.lastPoints = zim.copy(that.points);
that.points = tempPoints;
if (that.stage) that.stage.update();
}
});
mapMove = function (target) {
if (that.lockControls) return;
if (target.rect1) { // pressmove on ball
var ball = target;
var diffX = ball.x - ball.startX;
var diffY = ball.y - ball.startY;
ball.rect1.x = ball.rect1.startX + diffX;
ball.rect1.y = ball.rect1.startY + diffY;
ball.rect2.x = ball.rect2.startX + diffX;
ball.rect2.y = ball.rect2.startY + diffY;
} else { // pressmove on control
var rect = target;
var other = rect.other; // the other handle
var ball = rect.ball;
var index = ball.index;
var type = controlType;
if (!zot(_points[index][4])) type = _points[index][4];
if (type == "straight" || type == "mirror") {
var dX = rect.x - ball.x;
var dY = rect.y - ball.y;
if (type == "mirror") {
other.x = ball.x - dX;
other.y = ball.y - dY;
} else {
var a = Math.atan2(dY, dX);
var dNewX = -other.stickLength * Math.cos(a+Math.PI);
var dNewY = -other.stickLength * Math.sin(a+Math.PI);
other.x = ball.x - dNewX;
other.y = ball.y - dNewY;
}
}
}
};
Object.defineProperty(that, 'move', {
get: function() {
return move;
},
set: function(value) {
if (move != value) {
move = value;
if (value) {
startDragging();
} else {
stopDragging();
}
}
}
});
Object.defineProperty(that, 'interactive', {
get: function() {
return interactive;
},
set: function(value) {
interactive = value;
_controls = interactive;
that.allowToggle = interactive;
that.editPoints = interactive;
that.lockControls = !interactive; // note negative
that.selectPoints = interactive;
that.move = interactive;
that.points = that.points; // force remake
}
});
Object.defineProperty(that, 'allowToggle', {
get: function() {
return allowToggle;
},
set: function(value) {
if (allowToggle != value) {
allowToggle = value;
if (allowToggle) {
if (that.move) startDragging();
} else {
if (!_controls && that.move) stopDragging();
}
}
}
});
function startDragging() {
if (that.move=="always") return;
if (draggingCheck) return;
draggingCheck = true;
shape.drag({onTop:false});
moveDownEvent = shape.on("mousedown", moveDownEvent);
movePressEvent = shape.on("pressmove", movePressEvent);
moveUpEvent = shape.on("pressup", moveUpEvent);
}
function stopDragging(making) {
if (that.move=="always") return;
if (!making && !draggingCheck) return;
draggingCheck = false;
shape.noDrag();
shape.off("mousedown", moveDownEvent);
shape.off("pressmove", movePressEvent);
shape.off("pressup", moveUpEvent);
}
Object.defineProperty(that, 'controlsVisible', {
get: function() {
return _controls;
},
set: function(value) {
_controls = value;
if (value) {
that.showControls();
} else {
that.hideControls();
}
}
});
var _lockControls = lockControls;
Object.defineProperty(that, 'lockControls', {
get: function() {
return _lockControls;
},
set: function(value) {
_lockControls = value;
if (value) {
that.controls.mouseChildren = false;
that.controls.mouseEnabled = false;
} else {
that.controls.mouseChildren = true;
that.controls.mouseEnabled = true;
}
}
});
that.lockControls = _lockControls;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NOTE: extends ZIM CustomShape for more properties and a few functions.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (typeof KEYFOCUS !== typeof undefined) zim.KEYFOCUS = KEYFOCUS;
Object.defineProperty(this, 'keyFocus', {
get: function() {
return zim.KEYFOCUS == that;
},
set: function(value) {
zim.KEYFOCUS = that;
}
});
if (that.selectPoints && !zim.KEYFOCUS) setFocus();
function setFocus() {that.keyFocus = true; var d=document.activeElement; if (d) d.blur();}
Object.defineProperty(that, 'points', {
get: function() {
var points = [];
var point; var p;
for (var i=0; i<_points.length; i++) {
p = _points[i];
point = [
zim.decimals(p[0].x),
zim.decimals(p[0].y),
zim.decimals(p[1].x),
zim.decimals(p[1].y),
zim.decimals(p[2].x),
zim.decimals(p[2].y),
zim.decimals(p[3].x),
zim.decimals(p[3].y)
];
if (p[4] && p[4]!=="straight") point.push(p[4]);
points.push(point);
}
return points;
},
set: function(value) {
var x = that.x;
var y = that.y;
var v = that.visible;
that.dispose(true);
points = checkForShape(value);
if (that.shape) {
that.shape.graphics.clear();
that.sticks.graphics.clear();
that.controls.noDrag();
that.removeAllChildren();
delete that.shape;
delete that.sticks;
delete that.controls;
}
that.visible = false;
init(); // remake Blob
that.lockControls = _lockControls;
that.x = x;
that.y = y;
that.visible = v;
}
});
Object.defineProperty(that, 'pointsAdjusted', { // points with rotation
get: function() {
var points = [];
var point; var p; var po;
var pObjects = that.pointObjects;
zim.loop(pObjects.length, function(i, t) {
po = pObjects[i];
p = _points[i];
if (po[0].rotation==0 && po[0].scaleX==0 && po[0].scaleY==0) { // get points
point = [
zim.decimals(p[0].x),
zim.decimals(p[0].y),
zim.decimals(p[1].x),
zim.decimals(p[1].y),
zim.decimals(p[2].x),
zim.decimals(p[2].y),
zim.decimals(p[3].x),
zim.decimals(p[3].y)
];
} else {
var lo1 = po[0].localToLocal(po[2].x, po[2].y, po[0].parent);
var lo2 = po[0].localToLocal(po[3].x, po[3].y, po[0].parent);
point = [
zim.decimals(p[0].x),
zim.decimals(p[0].y),
zim.decimals(p[1].x),
zim.decimals(p[1].y),
zim.decimals(lo1.x-p[0].x),
zim.decimals(lo1.y-p[0].y),
zim.decimals(lo2.x-p[0].x),
zim.decimals(lo2.y-p[0].y)
];
}
if (p[4] && p[4]!=="mirror") point.push(p[4]);
points.push(point);
});
return points;
},
set: function(value) {
if (zon) zogy("Blob() - pointsAdjusted is read only");
}
});
Object.defineProperty(that, 'pointObjects', {
get: function() {
return _points;
},
set: function(value) {
if (zon) {zog("Blob() - pointObjects is read only - but its contents can be manipulated - use blob.update() after changes");}
}
});
Object.defineProperty(that, 'pointControls', {
get: function() {
return _pointControls;
},
set: function(value) {
if (zon) {zog("Blob() - pointControls is read only - but its contents can be manipulated - use blob.update() after changes");}
}
});
Object.defineProperty(that, 'pointCircles', {
get: function() {
return _pointCircles;
},
set: function(value) {
if (zon) {zog("Blob() - pointCircles is read only - but its contents can be manipulated - use blob.update() after changes");}
}
});
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// path manipulation and animating to path methods
Object.defineProperty(that, 'segmentPoints', {
get: function() {
var p = that.pointsAdjusted;
var array = []; // array of prepared segment points
zim.loop(p.length, function(i, t) {
var s = that.getSegmentPoint(p[i], p[i<t-1?i+1:0]);
array.push(s);
});
return array;
},
set: function(value) {
if (zon) {zog("Blob() - segmentPoints is read only");}
}
});
Object.defineProperty(that, 'segmentRatios', {
get: function() {
var distances = [];
var total = 0;
zim.loop(that.segmentPoints, function(points) {
var d = zim.distanceAlongCurve(points);
distances.push(d);
total += d;
});
var percents = [];
var totalPercents = 0;
zim.loop(distances, function (d) {
var p = d/total;
totalPercents += p;
percents.push(totalPercents);
});
return percents;
},
set: function(value) {
if (zon) {zog("Blob() - segmentRatios is read only");}
}
});
that.approximateBounds = function(num, showPoints) {
if (zot(num)) num = 80;
num /= that.num;
var points = that.interpolate(num, null, true, null, true);
var bounds = zim.boundsAroundPoints(points);
that.setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
if (showPoints) {
if (!that.parent) {
if (zon) zogy("approximateBounds() - add to stage to first to see points");
return that;
}
if (!that.hitPathPoints) that.hitPathPoints = new zim.Container().addTo();
else that.hitPathPoints.removeAllChildren();
that.hitPathPoints.top();
for (var i=0; i<points.length; i++) {
var point = points[i];
point = that.localToGlobal(point.x, point.y);
new zim.Circle(3).loc(point.x, point.y, that.hitPathPoints);
}
}
return that;
};
that.getPointAngle = function(index) {
var p = that.pointObjects[index][0]; // parent
var r1 = that.pointObjects[index][2];
var r2 = that.pointObjects[index][3];
if (p==that.stage) {
var globalR1 = new zim.Point(r1.x, r1.y);
var globalR2 = new zim.Point(r2.x, r2.y);
} else {
var globalR1 = p.localToGlobal(r1.x, r1.y);
var globalR2 = p.localToGlobal(r2.x, r2.y);
}
return zim.angle(globalR1.x, globalR1.y,globalR2.x, globalR2.y);
};
that.getSegmentPoint = function(point1, point2) {
if (zot(point1) || zot(point2)) return;
// dragging points temporarily puts data out of order
if (point1[2] != 0 || point1[3] != 0) {
point1[4] -= point1[2];
point1[5] -= point1[3];
point1[6] -= point1[2];
point1[7] -= point1[3];
point1[0] += point1[2];
point1[1] += point1[3];
point1[2] = 0;
point1[3] = 0;
}
if (point2[2] != 0 || point2[3] != 0) {
point2[4] -= point2[2];
point2[5] -= point2[3];
point2[6] -= point2[2];
point2[7] -= point2[3];
point2[0] += point2[2];
point2[1] += point2[3];
point2[2] = 0;
point2[3] = 0;
}
var p1 = {x:point1[0], y:point1[1]};
var p2 = {x:point1[0]+point1[6], y:point1[1]+point1[7]};
var p3 = {x:point2[0]+point2[4], y:point2[1]+point2[5]};
var p4 = {x:point2[0], y:point2[1]};
if (sets.x != 0 || sets.y !=0) {
p1.x+=sets.x;
p2.x+=sets.x;
p3.x+=sets.x;
p4.x+=sets.x;
p1.y+=sets.y;
p2.y+=sets.y;
p3.y+=sets.y;
p4.y+=sets.y;
}
return [p1,p2,p3,p4];
};
that.getAdjacentSegmentData = function(index) {
if (zot(index)) index = 0;
var p = that.pointsAdjusted;
if (that.num == 2) {
return [
[that.getSegmentPoint(p[0], p[1]),
that.getSegmentPoint(p[1], p[0])],
[0,1]
];
}
if (index == 0) {
return [
[that.getSegmentPoint(p[that.num-1], p[0]),
that.getSegmentPoint(p[0], p[1]),
that.getSegmentPoint(p[1], p[2])],
[that.num-1,0,1]
];
} else if (index >= that.num-1) {
return [
[that.getSegmentPoint(p[that.num-2], p[that.num-1]),
that.getSegmentPoint(p[that.num-1], p[0]),
that.getSegmentPoint(p[0], p[1])],
[that.num-2,that.num-1,0]
];
} else {
var lastIndex = (index+2>=that.num)?0:index+2;
return [
[that.getSegmentPoint(p[index-1], p[index]),
that.getSegmentPoint(p[index], p[index+1]),
that.getSegmentPoint(p[index+1], p[lastIndex])],
[index-1,index,index+1]
];
}
};
that.getCurvePoint = function(ratio, segmentRatios, segmentPoints, getAngle) {
if (zot(segmentRatios)) segmentRatios = that.segmentRatios;
if (zot(segmentPoints)) segmentPoints = that.segmentPoints;
if (zot(getAngle)) getAngle = false;
var percents = segmentRatios;
var segments = segmentPoints;
var afterIndex = zim.loop(percents, function (p, i) {
if (p >= ratio) return i;
});
var earlierPercent = afterIndex > 0 ? percents[afterIndex-1] : 0;
var localTotal = afterIndex > 0 ? (percents[afterIndex]-percents[afterIndex-1]):percents[afterIndex];
var localPercent = (ratio-earlierPercent)/localTotal;
var finalPoint = zim.pointAlongCurve(segments[afterIndex], localPercent, getAngle, true);
if (zot(finalPoint)) return undefined;
var finalFinalPoint = that.localToGlobal(finalPoint.x, finalPoint.y);
finalFinalPoint.angle = finalPoint.angle;
finalFinalPoint.z = afterIndex;
return !zot(finalFinalPoint) ? finalFinalPoint : undefined;
};
function proportion(p1, p2, ratio) {
return {
x:p1.x + (p2.x-p1.x)*ratio,
y:p1.y + (p2.y-p1.y)*ratio
};
}
function insertPointData(points, controls, ratios, percent, controlType, skipPoint, dataOnly, even) {
var index = points.length-1; // adjust for squiggle
var lastRatio = 0;
var currentRatio = 0;
if (percent == 100 && that.type == "Squiggle") percent = 99.99;
percent = (percent+100000)%100;
zim.loop(ratios, function (ratio, i) {
if (percent/100 < ratio) {
index = i;
currentRatio = ratio;
return true;
}
lastRatio = ratio;
});
var segment = that.segmentPoints[index];
var r = currentRatio > 0?(percent/100-lastRatio)/(currentRatio-lastRatio):0;
// zog(percent)
// zog(percent/100-currentRatio/ratios.length)
// var r = currentRatio > 0?(percent/100-1/ratios.length*currentRatio)/(currentRatio-lastRatio):0
var point = zim.pointAlongCurve(segment, r, null, even);
var newPoint = [point.x,point.y, 0, 0];
if (skipPoint) return;
if (dataOnly) {
that.interpolatedPoints.push({x:point.x, y:point.y, r:percent/100});
return;
}
if (controlType != "none") {
// calculate new handles and adjust old handles
// [controlX, controlY, circleX, circleY, rect1X, rect1Y, rect2X, rect2Y, controlType]
var startHandle = proportion(segment[0], segment[1], r);
var midPoint = proportion(segment[1], segment[2], r);
var endHandle = proportion(segment[2], segment[3], r);
var newStartHandle = proportion(startHandle, midPoint, r);
var newEndHandle = proportion(midPoint, endHandle, r);
newPoint[4] = newStartHandle.x-point.x;
newPoint[5] = newStartHandle.y-point.y;
newPoint[6] = newEndHandle.x-point.x;
newPoint[7] = newEndHandle.y-point.y;
var start = that.localToLocal(startHandle.x, startHandle.y, controls[index]);
points[index][6] = start.x;
points[index][7] = start.y;
var end = that.localToLocal(endHandle.x, endHandle.y, controls[(index+1)%points.length]);
points[(index+1)%points.length][4] = end.x;
points[(index+1)%points.length][5] = end.y;
}
if (controlType) newPoint[8] = controlType;
points.splice(index+1, 0, newPoint);
}
this.addPoint = function(percent, controlType) {
if (zot(percent)) percent = 100;
var points = that.points;
var ratios = that.segmentRatios;
var controls = that.pointControls;
controlType = controlType ? controlType : originalControlType;
insertPointData(points, controls, ratios, percent, controlType);
that.points = points;
that.num = points.length;
return that;
};
this.addPoints = function(num, controlType, startPoint, spread, dataOnly, points, even) {
if (zot(points)) points = zim.copy(that.points);
var ratios = zim.copy(that.segmentRatios);
var lastRatio = 0;
if (dataOnly) that.interpolatedPoints = [];
// dataOnly should add points to current point too
// but can't just use current point because sometimes that is static
// like when dragging the shape or a point - it does not register until mouseup
// and things like hitTestPath need that to be dynamic
// So the below does not work:
// if (dataOnly) {
// that.interpolatedPoints = [];
// zim.loop(points, function (point, i) {
// if (!zot(startPoint) && i!=startPoint) return;
// that.interpolatedPoints.push({x:point[0], y:point[1]})
// });
// }
if (spread) var totalPoints = ratios.length*num;
zim.loop(ratios, function (ratio, j) {
if (dataOnly) insertPointData(points, that.pointControls, that.segmentRatios, lastRatio*100, controlType, !zot(startPoint) && j!=startPoint, dataOnly, even);
var numCount = spread?Math.round(totalPoints*(ratio-lastRatio)):num;
var div = 1/(numCount+1);
zim.loop(numCount, function(i) {
var r = lastRatio + (ratio-lastRatio)*div*(i+1);
insertPointData(points, that.pointControls, that.segmentRatios, r*100, controlType, !zot(startPoint) && j!=startPoint, dataOnly, even);
if (!dataOnly && num > 0) that.points = points;
});
lastRatio = ratio;
});
if (dataOnly && that.type == "Squiggle") insertPointData(points, that.pointControls, that.segmentRatios, 100, controlType, null, dataOnly, even);
if (that.stage) that.stage.update();
that.num = points.length;
return that;
};
this.interpolate = function(num, startPoint, spread, points, even) {
if (zot(num)) num = 1;
// dataOnly will add Point to start point too
that.addPoints(num, "none", startPoint, spread, true, points, even);
return that.interpolatedPoints;
};
this.dispose = function(temp, d, disposing) {
if (!that.shape) return;
zim.gD(that); // globalDispose function for common elements
if (stage && that.toggleStageEvent) stage.off("stagemousedown", that.toggleStageEvent);
that.controls.noDrag(); // sets
that.controls.removeAllEventListeners();
if (that.selectPoints && that.selectionManager) that.selectionManager.dispose();
that.selectedBalls = null;
that.selectedRect1s = null;
that.selectedRect2s = null;
that.selectionManager = null;
that.off("mousedown", that.toggleEvent);
that.off("click", that.clickEvent);
if (temp) {
that.shape.dispose();
that.shape = null;
for (var i=0; i<that.points.length; i++) {
that.pointObjects[i][0].removeAllEventListeners();
that.pointObjects[i][1].removeAllEventListeners();
that.pointObjects[i][2].removeAllEventListeners();
that.pointObjects[i][3].removeAllEventListeners();
}
that.controls.removeFrom(that);
that.sticks.dispose();
_points = null;
_pointCircles = null;
} else {
that.removeAllEventListeners();
_points = null;
_pointCircles = null;
if (!disposing) this.zimCustomShape_dispose(true);
}
return true;
// // if (that.toggleStageEvent) that.stage.off("stagemousedown", that.toggleStageEvent);
// // this.zimContainer_dispose();
// // return true
// if (!that.shape) return;
// zim.gD(that); // globalDispose function for common elements
// that.shape.cursor = "default";
// for (var i=0; i<that.pointObjects.length; i++) {
// that.pointObjects[i][1].removeAllEventListeners();
// }
// for (i=0; i<_pointCircles.length; i++) {
// _pointCircles[i].removeAllEventListeners();
// }
// that.sticks.removeFrom(that);
// that.controls.removeFrom(that);
// that.shape.removeAllEventListeners();
// that.controls.removeAllEventListeners();
// that.off("mousedown", that.toggleEvent);
// that.off("click", that.clickEvent);
// if (stage && that.toggleStageEvent) stage.off("stagemousedown", that.toggleStageEvent);
// if (!temp && that.selectPoints) that.selectionManager.removeAllEventListeners();
// // if (!disposing) that.zimCustomShape_dispose(true);
// return true;
};
};
zim.extend(zim.Blob, zim.CustomShape, ["clone", "dispose"], "zimCustomShape", false);
//-53.5
/*--
zim.Flare = function(color, borderColor, borderWidth, crossAngle, thickness, thicknessA, thicknessB, pin, startX, startY, lengths, angles, anglesA, anglesB, anglesEnd, cross, crossColors, close, dashed, strokeObj, spineColor, spineBorderWidth, spineBorderColor, spineDashed, spineStrokeObj, closeColor, closeBorderWidth, closeBorderColor, closeDashed, closeStrokeObj, style, group, inherit)
Flare
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
Makes a flare shape - a shape with a gradual widening like flared pants or skirts.
The shape defaults to a horizontal rectangle flared outwardly to the right.
The flare angleA and angleB can be specified at any angle negative or positive.
The flare axis or spine can be at any angle to the horizontal positive in the x.
The cross or end angles can be specified relative to a normal the spine so 0 is -90.
Different color and border options are available and editable as properties.
More than one flare can be created in the same shape - these are called segments.
Multiple Flare objects can be easily combined into a ZIM MultiFlare
and a special FlareBox can be used to place flares or multiFlares around a rectangle
to be used for backings on buttons, pictures, etc.
See https://zimjs.com/ten/flare.html for examples of a 3D wall, a rocket and a button frame
NOTE: mouseChildren is turned to false for all zim Shape containers.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
new Flare().center();
// a Rocket
var rocket = new Flare({
thickness:100,
angles:-90, // all segment angles will point up
lengths:[40,.5,100,150,105],
anglesA:[-20,89,-12,0,-22], // anglesB will be mirrored by default
color:new GradientColor([dark,silver,dark],[.1,.6,.9],-50,0,50,0),
cross:true // add a line at segment borders
}).center();
// see also MultiFlare and FlareBox examples
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
color - (default black) the color of the flare
if null and a border is speficied the color will be transparent
borderColor - (default null) the stroke color
borderWidth - (default 1 if stroke is set) the size of the stroke in pixels
crossAngle - (default 0) the angle from the normal of the spine
so if the spine goes to the right at 0 degrees then 0 crossAngle starts at -90 and goes positive clockwise
a crossAangle of -45 would look like a picture frame bevel
if the flare starts at the top left corner of a rectangle
thickness - (default 20) the thickness at the start of the flare assuming 0 crossAngle
this will be divided evenly to thicknessA on one side of the spine and thicknessB on the other side of the spine
thicknessA - (default null) - will be set to half the thickness if thicknessB is not set otherwise thickness-thicknessB
thicknessB - (default null) - will be set to half the thickness if thicknessA is not set otherwise thickness-thicknessA
pin - (default null) - set to a segment number to set registration point at the start of the segment
Pin is used with MultiFlare to align flares at pinned segments
Pin is used with FlareBox to place pinned segments at any of the four corners of the box
When doing so, the Flare will be automatically rotated (corner number - pin number) * 90
This can be overriden by rotating the flare to the desired rotation after creation
startX - (default 0) shift the start of the flare in the x from the registration point (note, pin will reset registration)
startY - (default 0) shift the start of the flare in the y from the registration point (note, pin will reset registration)
lengths - (default [200]) an array of spine lengths
angles - (default [0]) an array of angles (degrees) for the spines relative to 0 along the positive x axis
anglesA - (default [10]) an array of relative angles to the left of the current spine when heading along the spine
so if the spine heads to the right, angleA is positive from the spine upwards
think of these as how much the shape flares out from the spine on one side
anglesB - (default anglesA) an array of relative angles to the right of the current spine when heading along the spine
so if the spine heads to the right, angleB is positive from the spine downwards
think of these as how much the shape flares out from the spine on another side
anglesEnd - (default [0]) an array of angles at the end of each segment from the normal of each segment spine
so if the spine goes to the right at 0 degrees then a 0 anglesEnd is perpendicular to the spine
an anglesEnd of 45 would look like a picture frame bevel
as the segments are placed around the picture frame clockwise
note: end angles greatly change the look of flared segments
poorly chosen angles can lead to flares crossing or massively diverging
good choices depend on the length of the flares, the spine angles and the flare angles
generally, a trial and error technique is the easiest to find the desired solution
cross - (default true) draw a crossing line at each segment - this draws each segment as a closed path
crossColors - (default null) an array of colors for each segment if cross is true
close - (default false) join the end of the last segment to the start of the first segment
dashed - (default false) set the dashed of the border if the borderColor or borderWidth is specified
strokeObj - (default {caps:"butt", joints:"miter", miterLimit:2, ignoreScale:false}) set to adjust stroke properties
caps options: "butt", "round", "square" or 0,1,2
joints options: "miter", "round", "bevel" or 0,1,2
miterLimit is the ration at which the mitered joint will be clipped
ignoreScale set to true will draw the specified line thickness regardless of object scale
spineColor - (default null) as the spine is drawn, fill the shape it makes with this color
this can create a picture frame effect as the spine color may hide half the flare for each segment
spineBorderWidth - (default null) the width of the spine
spineBorderColor - (default null) the color of the actual spine
spineDashed - (default false) set to true for dashed spine (if spineBorderWidth or spineBorderColor set)
spineStrokeObj - (default strokeObject) see strokeObject parameter for details
closeColor - (default color) the color of the segment created if closing the flare
closeBorderWidth - (default borderWidth) the borderWidth of the closing segment if closing the flare
closeBorderColor - (default borderColor) the borderColor of the closing segment if closing the flare
closeDashed - (default false) set to true for dashed closed segment (if closeBorderWidth or closeBorderColor set)
closeStrokeObj - (default strokeObject) see strokeObject parameter for details
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
add(lengths, angles, anglesA, anglesB, anglesEnd, cross, crossColors, close) |ZIM DUO| - add segment(s) to the Flare - returns object for chaining
see segment parameters for details - returns object for chaining
remake() - remake the Flare segments after setting properties
hasProp(property as String) - returns true if property exists on object else returns false
clone(exact) - makes a copy of the shape
exact (default false) ZIM VEE (Pick) values are active in clones unless exact is set to true
For instance, if the object's color is [blue, green]
then its clone might be blue or green - which could be different than the original
If exact is set to true then the clone will be the color of the original object
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
shape - access to the ZIM Shape for the flare(s)
spineShape - access to the ZIM Shape for the spine if spine is true
closeShape - access to the ZIM Shape for the closing segment if close is true
pin - get or set the pin number - which spine has the registration point
see the pin parameter for more details
points - access to array of flare shape points {x,y}
if not close - around outside then around inside
if close - around each segment
pinPoints - access to array of spine points {x,y} and then to final end spine point
color - get and set the fill color
colorRange - if setColorRange() is used, the colorRange is a ratio (0-1) between the colors
setting the colorRange will change the color property of the shape
for instance, shape.setColorRange(blue, pink) then shape.colorRange = .5
will set the color of the shape to half way between blue and pink
shape.animate({color:red}, 1000); is a shortcut to animate the colorRange
shape.wiggle("colorRange", .5, .2, .5, 1000, 5000) will wiggle the colorRange
borderColor - get and set the stroke color
borderWidth - get and set the stroke size in pixels
borderDashedCommand - access to the CreateJS stroke dashed command (segments, offset)
see https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeDash.html
closeColor - get and set the fill color of the close segment
closeBorderColor - get and set the stroke color of the close segment
closeBorderWidth - get and set the stroke size in pixels of the close segment
closeBorderDashedCommand - access to the CreateJS stroke dashed command (segments, offset)
see https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeDash.html
spineColor - get and set the fill color of the spine shape
spineBorderColor - get and set the stroke color of the spine shape
spineBorderWidth - get and set the stroke size in pixels of the spine shape
spineBorderDashedCommand - access to the CreateJS stroke dashed command (segments, offset)
see https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeDash.html
** the following properties can be read or changed
** if changed, the remake() method must be run to see changes
** see the Flare parameters for definitions
thicknessA - number
thicknessB - number
cross - boolean
close - boolean
lengths - array
angles - array
anglesA - array
anglesB - array
anglesEnd - array
crossColors - array
mouseChildren - set to false to avoid dragging the shape inside
to drag or interact with objects inside then set mouseChildren to true
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+53.6
zim.Flare = function(color, borderColor, borderWidth, crossAngle, thickness, thicknessA, thicknessB, pin, startX, startY, lengths, angles, anglesA, anglesB, anglesEnd, cross, crossColors, close, dashed, strokeObj, spineColor, spineBorderWidth, spineBorderColor, spineDashed, spineStrokeObj, closeColor, closeBorderWidth, closeBorderColor, closeDashed, closeStrokeObj, style, group, inherit) {
var sig = "color, borderColor, borderWidth, crossAngle, thickness, thicknessA, thicknessB, pin, startX, startY, lengths, angles, anglesA, anglesB, anglesEnd, cross, crossColors, close, dashed, strokeObj, spineColor, spineBorderWidth, spineBorderColor, spineDashed, spineStrokeObj, closeColor, closeBorderWidth, closeBorderColor, closeDashed, closeStrokeObj, style, group, inherit";
var duo; if (duo = zob(zim.Flare, arguments, sig, this)) return duo;
z_d("53.6");
this.zimContainer_constructor();
this.type = "Flare";
this.group = group;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
var that = this;
if (zot(borderColor)) borderColor = DS.borderColor!=null?DS.borderColor:null;
if (zot(borderWidth)) borderWidth = DS.borderWidth!=null?DS.borderWidth:null;
if (borderColor < 0 || borderWidth < 0) borderColor = borderWidth = null;
else if (borderColor!=null && borderWidth==null) borderWidth = 1;
if (zot(color)) color = DS.color!=null?DS.color:(borderWidth>0?"rgba(0,0,0,0)":"black");
if (zot(borderWidth) || borderWidth > 0) { // no border specified or a border > 0
if (!zot(borderColor) || !zot(borderWidth)) { // either a border color or thickness
if (zot(borderColor)) borderColor = "black";
}
}
if (zot(crossAngle)) crossAngle = DS.crossAngle!=null?DS.crossAngle:0;
var crossAngleOriginal = crossAngle;
crossAngle -= 90;
if (zot(thickness)) thickness = DS.thickness!=null?DS.thickness:null;
if (zot(thicknessA)) thicknessA = DS.thicknessA!=null?DS.thicknessA:null;
if (zot(thicknessB)) thicknessB = DS.thicknessB!=null?DS.thicknessB:null;
if (zot(thickness)) {
if (zot(thicknessB) && !zot(thicknessA)) thicknessB = thicknessA;
else if (zot(thicknessA) && !zot(thicknessB)) thicknessA = thicknessB;
else thicknessB = thicknessA = 10;
} else {
if (zot(thicknessB) && !zot(thicknessA)) thicknessB = thickness-thicknessA;
else if (zot(thicknessA) && !zot(thicknessB)) thicknessA = thickness-thicknessB;
else thicknessB = thicknessA = thickness/2;
}
that.thickness = thicknessA + thicknessB; // read-only
// from now on - do not use thickness
if (zot(cross)) cross =DS.cross!=null?DS.cross:true;
if (zot(crossColors)) crossColors =DS.crossColors!=null?DS.crossColors:null;
if (!zot(crossColors) && !Array.isArray(crossColors)) crossColors = [crossColors];
if (zot(close)) close = DS.close!=null?DS.close:false;
if (zot(startX)) startX = DS.startX!=null?DS.startX:0;
if (zot(startY)) startY = DS.startY!=null?DS.startY:0;
// lengths, angles, anglesA, anglesB, anglesEnd
if (zot(lengths)) lengths = DS.lengths!=null?DS.lengths:[200];
if (!Array.isArray(lengths)) lengths = [lengths];
if (zot(angles)) angles = DS.angles!=null?DS.angles:[0];
if (!Array.isArray(angles)) angles = [angles];
if (zot(anglesA)) anglesA = DS.anglesA!=null?DS.anglesA:[10];
if (!Array.isArray(anglesA)) anglesA = [anglesA];
if (zot(anglesB)) anglesB = DS.anglesB!=null?DS.anglesB:zim.copy(anglesA);
if (!Array.isArray(anglesB)) anglesB = [anglesB];
if (zot(anglesEnd)) anglesEnd = DS.anglesEnd!=null?DS.anglesEnd:[0];
if (!Array.isArray(anglesEnd)) anglesEnd = [anglesEnd];
if (zot(strokeObj)) strokeObj = DS.strokeObj!=null?DS.strokeObj:{miterLimit:2};
if (zot(spineBorderColor)) spineBorderColor = DS.spineBorderColor!=null?DS.spineBorderColor:null;
if (zot(spineBorderWidth)) spineBorderWidth = DS.spineBorderWidth!=null?DS.spineBorderWidth:null;
if (spineBorderColor < 0 || spineBorderWidth < 0) spineBorderColor = spineBorderWidth = null;
else if (spineBorderColor!=null && spineBorderWidth==null) spineBorderWidth = 1;
if (zot(spineColor)) spineColor = DS.spineColor!=null?DS.spineColor:(spineBorderWidth>0?"rgba(0,0,0,0)":"black");
if (zot(spineDashed)) spineDashed = DS.spineDashed!=null?DS.spineDashed:null;
if (zot(spineStrokeObj)) spineStrokeObj = DS.spineStrokeObj!=null?DS.spineStrokeObj:{miterLimit:2};
if (zot(spineBorderWidth) || spineBorderWidth > 0) {
if (!zot(spineBorderColor) || !zot(spineBorderWidth)) {
if (zot(spineBorderColor)) spineBorderColor = borderColor?borderColor:"black";
}
}
if (zot(closeBorderColor)) closeBorderColor = DS.closeBorderColor!=null?DS.closeBorderColor:null;
if (zot(closeBorderWidth)) closeBorderWidth = DS.closeBorderWidth!=null?DS.closeBorderWidth:null;
if (closeBorderColor < 0 || closeBorderWidth < 0) closeBorderColor = closeBorderWidth = null;
else if (closeBorderColor!=null && closeBorderWidth==null) closeBorderWidth = 1;
if (zot(closeColor)) closeColor = DS.closeColor!=null?DS.closeColor:(closeBorderWidth>0?"rgba(0,0,0,0)":null);
if (zot(closeDashed)) closeDashed = DS.closeDashed!=null?DS.closeDashed:null;
if (zot(closeStrokeObj)) closeStrokeObj = DS.closeStrokeObj!=null?DS.closeStrokeObj:{miterLimit:2};
if (zot(closeBorderWidth) || closeBorderWidth > 0) {
if (!zot(closeBorderColor) || !zot(closeBorderWidth)) {
if (zot(closeBorderColor)) closeBorderColor = borderColor?borderColor:"black";
}
}
this.thicknessA = thicknessA;
this.thicknessB = thicknessB;
this.cross = cross;
this.close = close;
this.lengths = lengths;
this.angles = angles;
this.anglesA = anglesA;
this.anglesB = anglesB;
this.anglesEnd = anglesEnd;
this.crossColors = crossColors;
drawShape(lengths, angles, anglesA, anglesB, anglesEnd, cross, crossColors, close);
function drawShape(lengths, angles, anglesA, anglesB, anglesEnd, cross, crossColors, close) {
that.removeAllChildren();
var s = that.shape = new zim.Shape().addTo(that);
that.colorCommand = s.c().f(color).command;
if (color && color.type) that.specialColor(that.colorCommand, color);
if (zot(borderWidth) || borderWidth > 0) {
if (!zot(borderColor) || !zot(borderWidth)) {
if (zot(borderColor)) borderColor = "black";
that.borderColorCommand = s.s(borderColor).command;
if (borderColor && borderColor.type) that.specialColor(that.borderColorCommand, borderColor);
that.borderWidthCommand = s.ss(borderWidth, strokeObj.caps, strokeObj.joints, strokeObj.miterLimit, strokeObj.ignoreScale).command;
if (dashed) that.borderDashedCommand = s.sd([10, 10], 5).command;
}
}
s.mt(0,0);
if (spineBorderWidth > 0) {
var spineS = that.spineShape = new zim.Shape().addTo(that);
that.spineColorCommand = spineS.c().f(spineColor).command;
if (spineColor && spineColor.type) that.specialColor(that.spineColorCommand, spineColor);
if (zot(spineBorderWidth) || spineBorderWidth > 0) {
if (!zot(spineBorderColor) || !zot(spineBorderWidth)) {
if (zot(spineBorderColor)) spineBorderColor = "black";
that.spineBorderColorCommand = spineS.s(spineBorderColor).command;
if (spineBorderColor && spineBorderColor.type) that.specialColor(that.spineBorderColorCommand, spineBorderColor);
that.spineBorderWidthCommand = spineS.ss(spineBorderWidth, spineStrokeObj.caps, spineStrokeObj.joints, spineStrokeObj.miterLimit, spineStrokeObj.ignoreScale).command;
if (spineDashed) that.spineBorderDashedCommand = spineS.sd([10, 10], 5).command;
}
}
}
if (!zot(closeColor)) {
var closeS = that.closeShape = new zim.Shape().addTo(that);
that.closeColorCommand = closeS.c().f(closeColor).command;
if (closeColor && closeColor.type) that.specialColor(that.closeColorCommand, closeColor);
if (zot(closeBorderWidth) || closeBorderWidth > 0) {
if (!zot(closeBorderColor) || !zot(closeBorderWidth)) {
if (zot(closeBorderColor)) closeBorderColor = "black";
that.closeBorderColorCommand = closeS.s(closeBorderColor).command;
if (closeBorder && closeBorder.type) that.specialColor(that.closeBorderCommand, closeBorderColor);
that.closeBorderWidthCommand = closeS.ss(closeBorderWidth, closeStrokeObj.caps, closeStrokeObj.joints, closeStrokeObj.miterLimit, closeStrokeObj.ignoreScale).command;
if (closeDashed) that.closeBorderDashedCommand = closeS.sd([10, 10], 5).command;
}
}
s.mt(0,0);
}
// start values
var sX = startX;
var sY = startY;
var f2 = crossAngle;
var f = f2-180;
var tA = thicknessA;
var tB = thicknessB;
var lastAngle = angles[0];
var num = Math.max(lengths.length, angles.length, anglesA.length, anglesB.length, anglesEnd.length);
var lastB, lastC;
var lastAngle = f;
var pointsA = [];
var pointsB = [];
var pointsC = [];
var points = that.points = [];
var spines = that.pinPoints = [];
zim.loop(num, function(i, t) {
var data = getSegment(i);
var cosine = Math.cos(data.a*zim.RAD);
var sine = Math.sin(data.a*zim.RAD);
var AA = new zim.Point(sX+data.A.x*cosine-data.A.y*sine, sY+data.A.x*sine+data.A.y*cosine);
var BB = new zim.Point(sX+data.B.x*cosine-data.B.y*sine, sY+data.B.x*sine+data.B.y*cosine);
var CC = new zim.Point(sX+data.C.x*cosine-data.C.y*sine, sY+data.C.x*sine+data.C.y*cosine);
var DD = new zim.Point(sX+data.D.x*cosine-data.D.y*sine, sY+data.D.x*sine+data.D.y*cosine);
pointsA.push(AA,BB);
pointsB.unshift(CC,DD);
pointsC.push([AA,BB,CC,DD]); // for cross
var FF = new zim.Point(sX+data.F.x*cosine-data.F.y*sine, sY+data.F.x*sine+data.F.y*cosine);
var EE = new zim.Point(sX+data.E.x*cosine-data.E.y*sine, sY+data.E.x*sine+data.E.y*cosine);
if (i==0) that.pinPoints.push(FF);
that.pinPoints.push(EE);
sX = EE.x;
sY = EE.y;
tA = data.tA;
tB = data.tB;
});
that.points = pointsA.concat(pointsB);
if (!cross) {
zim.loop(pointsA, function (point, i) {
if (i==0) s.mt(point.x, point.y);
else s.lt(point.x, point.y);
});
if (close) {
s.lt(pointsA[0].x, pointsA[0].y);
s.cp();
}
zim.loop(pointsB, function (point, i) {
if (i==0 && close) s.mt(point.x, point.y);
else s.lt(point.x, point.y);
});
if (close) {
s.lt(pointsB[0].x, pointsB[0].y);
}
s.cp();
} else {
zim.loop(pointsC, function (points, i) {
s .mt(points[0].x, points[0].y);
if (!zot(crossColors) && !zot(crossColors[i])) s.f(crossColors[i]).mt(points[0].x, points[0].y);
s .lt(points[1].x, points[1].y)
.lt(points[2].x, points[2].y)
.lt(points[3].x, points[3].y)
.cp();
});
if (close) {
s .mt(pointsC[pointsC.length-1][1].x, pointsC[pointsC.length-1][1].y)
.lt(pointsC[pointsC.length-1][2].x, pointsC[pointsC.length-1][2].y)
.lt(pointsC[0][3].x, pointsC[0][3].y)
.lt(pointsC[0][0].x, pointsC[0][0].y)
.cp();
}
}
if (spineS) {
zim.loop(spines, function (spine,i) {
if (i==0) spineS.mt(spine.x, spine.y);
else spineS.lt(spine.x, spine.y);
});
if (close) {
spineS.lt(spines[0].x, spines[0].y).cp();
}
}
if (!zot(closeColor)) {
zim.loop(pointsB, function (point,i) {
if (i==0) closeS.mt(point.x, point.y);
else closeS.lt(point.x, point.y);
});
if (close) {
closeS.lt(pointsB[0].x, pointsB[0].y).cp();
}
}
// segment values
function getSegment(num) {
var a = angles[num];
var d = lengths[num];
var aA = anglesA[num];
var aB = anglesB[num];
var e = anglesEnd[num];
if (crossColors) var cc = crossColors[num];
if (zot(a)) {a = lastAngle; that.angles[num] = a;}
if (zot(d)) {d = 200; that.lengths[num] = d;}
if (zot(aA)) {aA = 0; that.anglesA[num] = aA;}
if (zot(aB)) {aB = 0; that.anglesB[num] = aB;}
if (zot(e)) {e = 0; that.anglesEnd[num] = e;}
if (crossColors && zot(cc)) {cc = color; that.crossColors[num] = cc;}
e = e+90;
var e2 = 180-e;
var cosine = Math.cos((lastAngle-a)*zim.RAD);
var sine = Math.sin((lastAngle-a)*zim.RAD);
// GOAL is to find points F, A, B, C, D, E
var F = new zim.Point(0,0);
var E = new zim.Point(d,0);
if (zot(lastB)) {
var A = new zim.Point(Math.cos(f2*zim.RAD)*tA, Math.sin(f2*zim.RAD)*tA);
} else {
A = new zim.Point(lastB.x*cosine-lastB.y*sine, lastB.x*sine+lastB.y*cosine);
}
var pA = getEnd(d, A.x, A.y, aA, e2);
var B = new zim.Point(d-pA.x, -pA.y);
if (zot(lastC)) {
var D = new zim.Point(Math.cos(f*zim.RAD)*tA, Math.sin(f*zim.RAD)*tB);
} else {
var D = new zim.Point(lastC.x*cosine-lastC.y*sine, lastC.x*sine+lastC.y*cosine);
}
var pB = getEnd(d, D.x, D.y, aB, e);
var C = new zim.Point(d-pB.x, pB.y);
lastB = new zim.Point(B.x-d, B.y);
lastC = new zim.Point(C.x-d, C.y);
lastAngle = a;
// all the points, next start thickness AB
return {a:a, A:A, B:B, C:C, D:D, E:E, F:F, tA:pA.t, tB:pB.t};
}
function getEnd(dist, frontX, frontY, flare, endAngle) {
var u = endAngle-90;
var w = 90-u;
var v = 180-flare-w;
var n = Math.tan(u*zim.RAD)*frontY;
var s = dist-frontX-n;
var t1 = s/Math.sin(v*zim.RAD)*Math.sin(flare*zim.RAD);
var t2 = Math.sqrt(Math.pow(frontY,2) + Math.pow(n,2));
var t = t1 + t2;
var x = t*Math.sin(u*zim.RAD);
var y = t*Math.cos(u*zim.RAD);
return {x:x,y:y,t:t};
}
} // end makeShape
// METHODS
this.add = function(lengths, angles, anglesA, anglesB, anglesEnd, cross, crossColors, close) {
var sig = "lengths, angles, anglesA, anglesB, anglesEnd, cross, crossColors, close";
var duo; if (duo = zob(that.add, arguments, sig)) return duo;
if (!zot(cross)) that.cross = cross;
if (!zot(close)) that.close = close;
if (!zot(lengths)) {
if (!Array.isArray(lengths)) lengths = [lengths];
if (zot(that.lengths)) that.lengths = lengths;
else that.lengths = that.lengths.concat(lengths);
}
if (!zot(angles)) {
if (!Array.isArray(angles)) angles = [angles];
if (zot(that.angles)) that.angles = angles;
else that.angles = that.angles.concat(angles);
}
if (!zot(anglesA)) {
if (!Array.isArray(anglesA)) anglesA = [anglesA];
if (zot(that.anglesA)) that.anglesA = anglesA;
else that.anglesA = that.anglesA.concat(anglesA);
}
if (!zot(anglesB)) {
if (!Array.isArray(anglesB)) anglesB = [anglesB];
if (zot(that.anglesB)) that.anglesB = anglesB;
else that.anglesB = that.anglesB.concat(anglesB);
}
if (!zot(anglesEnd)) {
if (!Array.isArray(anglesEnd)) anglesEnd = [anglesEnd];
if (zot(that.anglesEnd)) that.anglesEnd = anglesEnd;
else that.anglesEnd = that.anglesEnd.concat(anglesEnd);
}
if (!zot(crossColors)) {
if (zot(that.crossColors)) {
if (zon) zogy("Flare() - must set crossColor for original object parameters");
} else {
if (!Array.isArray(crossColors)) crossColors = [crossColors];
if (zot(that.crossColors)) that.crossColors = crossColors;
else that.crossColors = that.crossColors.concat(crossColors);
}
}
that.remake();
return that;
};
this.remake = function() {
thicknessA = this.thicknessA;
thicknessB = this.thicknessB;
drawShape(that.lengths, that.angles, that.anglesA, that.anglesB, that.anglesEnd, that.cross, that.crossColors, that.close);
return that;
};
// PROPERTIES
Object.defineProperty(that, 'color', {
get: function() {
return color;
},
set: function(value) {
if (zot(value)) value = "black";
color = value;
if (value && value.type) that.specialColor(that.colorCommand, value);
else that.colorCommand.style = value;
}
});
var startColor;
var endColor;
this.setColorRange = function(color1, color2) {
if (zot(color2)) {
startColor = that.color;
endColor = color1;
} else if (zot(color1)) {
startColor = that.color;
endColor = color2;
} else {
startColor = color1;
endColor = color2;
}
return that;
};
var colorRange = 0;
Object.defineProperty(that, 'colorRange', {
get: function() {
return colorRange;
},
set: function(value) {
colorRange = value;
if (!zot(startColor) && !zot(endColor)) {
that.color = zim.colorRange(startColor, endColor, value);
}
}
});
Object.defineProperty(that, 'borderColor', {
get: function() {
return borderColor;
},
set: function(value) {
borderColor = value;
if (!that.borderColorCommand) drawShape();
else if (value && value.type) that.specialColor(that.borderColorCommand, value);
else that.borderColorCommand.style = value;
}
});
Object.defineProperty(that, 'borderWidth', {
get: function() {
return borderWidth;
},
set: function(value) {
if (!(value>0)) value = 0;
borderWidth = value;
if (!that.borderWidthCommand || borderWidth == 0) drawShape();
else {
that.borderWidthCommand.width = borderWidth;
if (dashed) {
that.borderDashedCommand.segments = [20, 10];
that.borderDashedCommand.offset = 5;
}
}
}
});
Object.defineProperty(that, 'spineColor', {
get: function() {
return spineColor;
},
set: function(value) {
if (zot(value)) value = "black";
spineColor = value;
if (!that.spineColorCommand) drawShape();
else if (value && value.type) that.specialColor(that.spineColorCommand, value);
else that.spineColorCommand.style = value;
}
});
Object.defineProperty(that, 'spineBorderColor', {
get: function() {
return spineBorderColor;
},
set: function(value) {
spineBorderColor = value;
if (!that.spineBorderColorCommand) drawShape();
else if (value && value.type) that.specialColor(that.spineBorderColorCommand, value);
else that.spineBorderColorCommand.style = value;
}
});
Object.defineProperty(that, 'spineBorderWidth', {
get: function() {
return spineBorderWidth;
},
set: function(value) {
if (!(value>0)) value = 0;
spineBorderWidth = value;
if (!that.spineBorderWidthCommand || spineBorderWidth == 0) drawShape();
else {
that.spineBorderWidthCommand.width = spineBorderWidth;
if (spineDashed) {
that.spineBorderDashedCommand.segments = [20, 10];
that.spineBorderDashedCommand.offset = 5;
}
}
}
});
Object.defineProperty(that, 'closeColor', {
get: function() {
return closeColor;
},
set: function(value) {
if (zot(value)) value = "black";
closeColor = value;
if (!that.closeColorCommand) drawShape();
else if (value && value.type) that.specialColor(that.closeColorCommand, value);
else that.closeColorCommand.style = value;
}
});
Object.defineProperty(that, 'closeBorderColor', {
get: function() {
return closeBorderColor;
},
set: function(value) {
closeBorderColor = value;
if (!that.closeBorderColorCommand) drawShape();
else if (value && value.type) that.specialColor(that.closeBorderColorCommand, value);
else that.closeBorderColorCommand.style = value;
}
});
Object.defineProperty(that, 'closeBorderWidth', {
get: function() {
return closeBorderWidth;
},
set: function(value) {
if (!(value>0)) value = 0;
closeBorderWidth = value;
if (!that.closeBorderWidthCommand || closeBorderWidth == 0) drawShape();
else {
that.closeBorderWidthCommand.width = closeBorderWidth;
if (closeDashed) {
that.closeBorderDashedCommand.segments = [20, 10];
that.closeBorderDashedCommand.offset = 5;
}
}
}
});
Object.defineProperty(that, 'pin', {
get: function() {
return pin;
},
set: function(value) {
if (!(value>0)) value = 0;
if (value > that.pinPoints.length-1) pin = 0;
pin = value;
var point = that.pinPoints[pin];
if (point) {
that.regX = point.x;
that.regY = point.y;
}
}
});
var b = zim.boundsAroundPoints(that.points);
this.setBounds(b.x, b.y, b.width, b.height);
if (!zot(pin)) that.pin = pin;
this.mouseChildren = false;
if (style!==false) zim.styleTransforms(this, DS);
this.clone = function() {
return that.cloneProps(new zim.Flare(color, borderColor, borderWidth, crossAngleOriginal, zim.copy(thickness), zim.copy(thicknessA), zim.copy(thicknessB), pin, startX, startY, zim.copy(lengths), zim.copy(angles), zim.copy(anglesA), zim.copy(anglesB), zim.copy(anglesEnd), cross, zim.copy(crossColors), close, dashed, strokeObj, spineColor, spineBorderWidth, spineBorderColor, spineDashed, spineStrokeObj, closeColor, closeBorderWidth, closeBorderColor, closeDashed, closeStrokeObj, style, this.group, inherit));
};
};
zim.extend(zim.Flare, zim.Container, ["clone"], "zimContainer", false);
//-53.6
//
/*--
zim.MultiFlare = function(flares, pins, angles, endToEnd, style, group, inherit)
MultiFlare
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
Joins multiple Flare objects in one container
at the pin points of the flares or end to end.
See also ZIM Flare and ZIM FlareBox.
NOTE: mouseChildren is turned to false for all zim Shape containers.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
// a fan of legs with feet!
var flare = new Flare({lengths:[100,100,20,8],anglesA:[5,-5,60],anglesB:[5,-5,0]})
var multi = new MultiFlare().center();
loop(12, function (i) {
multi.add(flare.rot(i*360/12))
});
// or prepare flares and angles ahead of time
var flares = [];
var angles = [];
loop(12, function (i) {
flares.push(flare.clone());
angles.push(i*360/12);
});
new MultiFlare(flares, null, angles).center();
// a ring of beads using endToEnd
var flare = new Flare({crossAngle:-360/12, lengths:[50,20,5,20,50],anglesA:[5,60,0,-60,-5]})
var flares = [];
var angles = [];
loop(12, function (i) {
flares.push(flare.clone());
angles.push(i*360/12);
});
new MultiFlare(flares, null, angles, true).center();
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
flares - (default null) an array of ZIM Flares objects to add - also see add() method
pins - (default null) an array of pin indexes for the flares
pins will set the registration point for each flare at whatever segment matches the pin index
angles - (default null) an array angles for the flares
endToEnd - (default false) set to true to locate each first segment point of the flare at the last segment point of the last flare
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
add(flares) - add an array of flares or a single flare to MultiFlare
add() redraws the whole flare so for many, make an array to start and pass it in as an argument
remove(flares) - remove an array of flares or a single flare to MultiFlare
remove() redraws the whole flare so for many, make an array to start and pass it in as an argument
cache(see Container docs for parameter description) - overrides CreateJS cache() and returns object for chaining
Leave parameters blank to cache bounds of shape (plus outer edge of border if borderWidth > 0)
hasProp(property as String) - returns true if property exists on object else returns false
clone() - makes a copy of the multiFlare cloning the flares too
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
** can get and change the following properties
** see the paremeters for details
** if properties are changed call the remake() method to update the MultiFlare
flares - array
pins - array
angles - array
endToEnd - boolean
mouseChildren - set to false to avoid dragging the shape inside
to drag or interact with objects inside then set mouseChildren to true
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+53.7
zim.MultiFlare = function(flares, pins, angles, endToEnd, style, group, inherit) {
var sig = "flares, pins, angles, endToEnd, style, group, inherit";
var duo; if (duo = zob(zim.MultiFlare, arguments, sig, this)) return duo;
z_d("53.7");
this.zimContainer_constructor();
this.type = "MultiFlare";
this.group = group;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
var that = this;
if (zot(flares)) flares = DS.flares!=null?DS.flares:[];
if (!Array.isArray(flares)) flares = [flares];
// pins, angles, endToEnd
if (zot(pins)) pins = DS.pins!=null?DS.pins:null;
if (zot(angles)) angles = DS.angles!=null?DS.angles:null;
if (zot(endToEnd)) endToEnd = DS.endToEnd!=null?DS.endToEnd:false;
that.flares = flares;
that.pins = pins;
that.angles = angles;
that.endToEnd = endToEnd;
that.mouseChildren = false;
that.add = function(f, clone) {
if (zot(f)) return that;
if (zot(clone)) clone = true;
if (!Array.isArray(f)) f = [f];
zim.loop(f, function (flare) {
if (clone) that.flares.push(flare.clone());
else that.flares.push(flare);
});
that.remake();
if (that.stage) that.stage.update();
return that;
};
that.remove = function(f) {
if (zot(f)) return that;
if (!Array.isArray(f)) f = [f];
zim.loop(f, function (flare) {
var index = that.flares.indexOf(flare);
if (index>=0) that.flares.splice(index, 1);
});
that.remake();
if (that.stage) that.stage.update();
return that;
};
that.remake = function () {
that.removeAllChildren();
zim.loop(that.flares, function (flare, i) {
if (pins && !zot(pins[i])) flare.pin = pins[i];
if (angles && !zot(angles[i])) flare.rotation = angles[i];
flare.addTo(that);
that.flares.push(flare);
if (endToEnd) {
if (i>0) {
var last = flares[i-1];
var lastPoint = last.pinPoints[last.pinPoints.length-1];
var point1 = last.localToLocal(lastPoint.x, lastPoint.y, that);
var firstPoint = flare.pinPoints[0];
var point2 = flare.localToLocal(firstPoint.x, firstPoint.y, that);
flare.mov(point1.x-point2.x, point1.y-point2.y);
}
}
});
};
that.remake();
if (style!==false) zim.styleTransforms(this, DS);
this.clone = function() {
return that.cloneProps(new zim.MultiFlare(zim.copy(flares,true), zim.copy(pins), zim.copy(angles), endToEnd, style, this.group, inherit));
};
};
zim.extend(zim.MultiFlare, zim.Container, ["clone"], "zimContainer", false);
//-53.7
/*--
zim.FlareBox = function(width, height, color, borderColor, borderWidth, flares, corners, pins, style, group, inherit)
FlareBox
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
Makes a Rectangle with ZIM Flare objects positioned around edges and corners.
Pass in an array of Flare objects or a MultiFlare
FlareBox places flares at specified corner indexes depending on flare pin index.
See also ZIM Flare and ZIM MultiFlare.
A FlareBox can be used as a backing and rollBacking for buttons and other components
to create exciting borders inspired by the tail lights of 2020 automibiles.
See: https://zimjs.com/ten/flare.html
NOTE: mouseChildren is turned to false for all zim Shape containers.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var border1 = new Flare({
thickness:6,
angles:[0,90], // to the right then down
lengths:[60,90],
anglesA:[3,-1.5], // flare angles
anglesEnd:[45,0], // 0 is optional
color:white,
pin:1 // pin at flare corner
});
var border2 = new Flare({
thickness:25,
angles:[0,90], // to right then down
lengths:[50,50],
anglesA:[-2,2], // anglesB will mirror these if not provided
anglesEnd:[45],
color:dark,
pin:1 // pin at flare corner
});
// put both flares at left top corner 0
// they each have pin of 1 so
// the rotation is (0-1)*90 = -90 (counter clockwise)
// they were to the right and down
// now they are up and to the right
var flareBox = new FlareBox(220, 100, blue, dark, 3, [border1, border2], [0,0])
.centerReg();
// clone the flares for the rollover FlareBox
// put the first flare at corner 2
// the rotation becomes (2-1)*90 = 90 (clockwise)
// it was built to go to the right and down
// now it is going down and to the left
var flareBoxOver = new FlareBox(220, 100, green, dark, 3, [border1.clone(), border2.clone()], [2,0])
.centerReg({add:false});
// use the flareBoxes as backings
var button = new Button({
width:flareBox.width,
height:flareBox.height,
backing:flareBox,
rollBacking:flareBoxOver
}).center();
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
width - (default 220) the width of the rectangle about which the Flare objects are placed
this is a little larger than the ZIM Button default width
height - (default 80) the height of the rectangle about which the Flare objects are placed
this is a little larger than the ZIM Button default height
color - (default "black") the fill color as any CSS color including "rgba()" for alpha fill (set a to 0 for tranparent fill)
borderColor - (default null) the stroke color
borderWidth - (default 1 if stroke is set) the size of the stroke in pixels
flares - (default null) an array of ZIM Flare objects or a single flare or a ZIM MultiFlare
corners - (default [0]) an array of corner indexes to place the pin points of the ZIM Flare objects
corner indexes are:
0 - LEFT TOP
1 - RIGHT TOP
2 - RIGHT BOTTOM
3 - LEFT BOTTOM
pins - (default null) an array of pins of the ZIM Flare objects
The pin index can be set on the Flare or through the MultiFlare or here in the FlareBox
The pin is also the registration point of the flare so the flare will be placed at the corner at its pin
FlareBox will also automatically rotate the flares with this formula:
flare.rotation = (corner-pin)*90
This formula allows for easy setting of angles on corners
See the Button at https://zimjs.com/ten/flare.html
This can be overridden by setting the flare rotation after the FlareBox is created
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
setColorRange(color1, color2) - set a color range for shape - used by colorRange property - returns obj for chaining
if one color is used, the current color is used and color1 is the second color in the range
cache(see Container docs for parameter description) - overrides CreateJS cache() and returns object for chaining
Leave parameters blank to cache bounds of shape (plus outer edge of border if borderWidth > 0)
hasProp(property as String) - returns true if property exists on object else returns false
clone() - makes a copy of the flareBox and clone flares as well
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
multiFlare - gives access to the ZIM Multiflare object
this is made automatically by FlareBox if an array of flares was used
flares - an array of flares that belong to the multiFlare
backing - gives access to the rectangle backing shape
color - get and set the fill color of the backing shape
colorRange - if setColorRange() is used, the colorRange is a ratio (0-1) between the colors
setting the colorRange will change the color property of the backing shape
for instance, shape.setColorRange(blue, pink) then shape.colorRange = .5
will set the color of the shape to half way between blue and pink
shape.animate({color:red}, 1000); is a shortcut to animate the colorRange
shape.wiggle("colorRange", .5, .2, .5, 1000, 5000) will wiggle the colorRange
borderColor - get and set the stroke color
borderWidth - get and set the stroke size in pixels
borderDashedCommand - access to the CreateJS stroke dashed command (segments, offset)
see https://www.createjs.com/docs/easeljs/classes/Graphics.StrokeDash.html
mouseChildren - set to false to avoid dragging the shape inside
to drag or interact with objects inside then set mouseChildren to true
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+53.8
zim.FlareBox = function(width, height, color, borderColor, borderWidth, flares, corners, pins, style, group, inherit) {
var sig = "width, height, color, borderColor, borderWidth, flares, corners, pins, style, group, inherit";
var duo; if (duo = zob(zim.FlareBox, arguments, sig, this)) return duo;
z_d("53.8");
this.group = group;
var DS = style===false?{}:zim.getStyle("FlareBox", this.group, inherit);
if (zot(width)) width = DS.width!=null?DS.width:220;
if (zot(height)) height = DS.height!=null?DS.height:80;
this.zimContainer_constructor(width, height);
this.type = "FlareBox";
var that = this;
this.mouseChildren = false;
if (zot(borderColor)) borderColor = DS.borderColor!=null?DS.borderColor:null;
if (zot(borderWidth)) borderWidth = DS.borderWidth!=null?DS.borderWidth:null;
if (borderColor < 0 || borderWidth < 0) borderColor = borderWidth = null;
else if (borderColor!=null && borderWidth==null) borderWidth = 1;
if (zot(color)) color = DS.color!=null?DS.color:(borderWidth>0?"rgba(0,0,0,0)":"black");
if (zot(borderWidth) || borderWidth > 0) { // no border specified or a border > 0
if (!zot(borderColor) || !zot(borderWidth)) { // either a border color or thickness
if (zot(borderColor)) borderColor = "black";
}
}
if (zot(flares)) flares = DS.flares!=null?DS.flares:null;
if (zot(corners)) corners = DS.corners!=null?DS.corners:null;
if (zot(pins)) pins = DS.pins!=null?DS.pins:null;
that.backing = new zim.Rectangle(width, height, color, borderColor, borderWidth).addTo(this);
if (zot(flares)) return;
if (flares.type != "MultiFlare") {
if (!Array.isArray(flares)) {
if (flares.type != "Flare") return;
flares = [flares];
}
flares = new zim.MultiFlare(flares, pins);
}
flares.addTo(that);
that.multiFlare = flares;
that.flares = that.multiFlare.flares;
flares.loop(function(flare, i) {
if (pins && !zot(pins[i])) flare.pin = pins[i];
else if (zot(flare.pin)) flare.pin = 0;
if (corners && !zot(corners[i])) flare.corner = corners[i];
else if (zot(flare.corner)) flare.corner = 0;
if (flare.corner==1) {
flare.loc(width,0);
} else if (flare.corner==2) {
flare.loc(width,height);
} else if (flare.corner==3) {
flare.loc(0,height);
} else {
flare.loc(0,0);
}
flare.rot((flare.corner-flare.pin)*90);
});
if (style!==false) zim.styleTransforms(this, DS);
this.clone = function() {
return that.cloneProps(new zim.FlareBox(width, height, color, borderColor, borderWidth, zim.copy(flares,true), zim.copy(corners), zim.copy(pins), style, this.group, inherit));
};
};
zim.extend(zim.FlareBox, zim.Container, ["clone"], "zimContainer", false);
//-53.8
// SUBSECTION COMPONENTS
/*--
zim.Label = function(text, size, font, color, rollColor, shadowColor, shadowBlur, align, valign, bold, italic, variant, lineWidth, lineHeight, backing, outlineColor, outlineWidth, backgroundColor, backgroundBorderColor, backgroundBorderWidth, corner, backgroundDashed, padding, paddingHorizontal, paddingVertical, shiftHorizontal, shiftVertical, rollPersist, labelWidth, labelHeight, maxSize, splitWords, style, group, inherit)
Label
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
Makes a label - wraps the createjs Text object.
Can use with Button, CheckBox, RadioButtons and Pane.
Text seems to come in different sizes so we do our best.
Have tended to find that left and alphabetic are most consistent across browsers.
Custom fonts loaded through css can be used as well.
NOTE: can wrap text at given width using lineWidth (or labelWidth) parameter.
To dynamically change the width without changing the font size use the labelWidth property.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var label = new Label("Hello");
label.center(); // adds label to and centers on the stage
var label = new Label({
text:"CLICK",
size:100,
font:"courier",
color:"white",
rollColor:"red",
bold:true,
italic:true
});
stage.addChild(label);
label.x = label.y = 100;
label.on("click", function(){zog("clicking");});
END EXAMPLE
EXAMPLE
// with text that wraps at labelWidth
// can also set this as a property later to dynamically change width of text
// without changing the size
const label = new Label({
text:"this is a long bunch of text, this is a long bunch of text, this is a long bunch of text",
labelWidth:200
}).center();
END EXAMPLE
EXAMPLE
STYLE = {font:"courier"};
new Label("Hi Courier").center(); // will be courier not arial
STYLE = {text:"YAY!", color:"Red"};
new Label().center().mov(0,100); // will say YAY! in red arial font
new Label("Hello").center().mov(0,200); // will say Hello in red arial
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
** supports VEE - parameters marked with ZIM VEE mean a zim Pick() object or Pick Literal can be passed
Pick Literal formats: [1,3,2] - random; {min:10, max:20} - range; series(1,2,3) - order, function(){return result;} - function
text |ZIM VEE| - String for the the text of the label
size - (default 36) the size of the font in pixels
font - (default arial) the font or list of fonts for the text
color - (default "black") color of font (any CSS color)
rollColor - (default color) the rollover color of the font
shadowColor - (default -1) for no shadow - set to any css color to see
shadowBlur - (default 14) if shadow is present
align - ((default "left") text registration point alignment also "center" and "right"
valign - (default "top") vertical registration point alignment alse "middle / center", "bottom"
bold - (default false) set the font to bold - note: fontOptions has been removed as of ZIM Cat
italic - (default false) set the font to italic - note: fontOptions has been removed as of ZIM Cat
variant - (default false) set to true to set the font to "small-caps" - note: fontOptions has been removed as of ZIM Cat
lineWidth - (default false) for no wrapping (use \n) Can set to number for wrap
lineHeight - (default getMeasuredLineHeight) set to number to adjust line height
backing - (default null) a Display object for the backing of the label (eg. Shape, Bitmap, Container, Sprite)
the backing most likely should be centerReg() ie. backing:new Rectangle(200,50,yellow).centerReg()
see ZIM Pizzazz module for a fun set of Shapes like Boomerangs, Ovals, Lightning Bolts, etc.
outlineColor - (default null - or black if outlineWidth set) - the color of the outline of the text
outlineWidth - (default null - or (size*.2) if outlineColor set) - the thickness of the outline of the text
backgroundColor - (default null) set to CSS color to add a rectangular color around the label
The background color will change size to match the text of the label
Note: the backgroundColor is different than a backing which can be any Display Object
and background parameters are ignored if a backing parameter is set
backgroundBorderColor - (default null) the background stroke color
backgroundBorderWidth - (default null) thickness of the background border
corner - (default 0) the round of corner of the background if there is one
can also be an array of [topLeft, topRight, bottomRight, bottomLeft]
backgroundDashed - (default null) set to true for dashed background border (if backgroundBorderColor or backgroundBorderWidth set)
padding - (default 10 if backgroundColor set) places the border this amount from text (see paddingHorizontal and paddingVertical)
padding parameters are ignored if there is no backgroundColor set (also ignored if a backing parameter is set)
paddingHorizontal - (default padding) places border out at top bottom
paddingVertical - (default padding) places border out at left and right
shiftHorizontal - (default 0) move the label (CreateJS Text) inside the Label container horizontally
shiftVertical - (default 0) move the label (CreateJS Text) inside the Label container vertically
rollPersist - (default false) set to true to maintain rollover stage as long as mousedown or press is activated (used by Buttons)
labelWidth - (default null) the same as the lineWidth - the text will wrap at the labelWidth (added to match labelHeight)
labelHeight - (default null) the height of the text - setting this will probably alter the font size - so the size parameter is overwritten
for labelHeight to work, the labelWidth must also be set
using labelWidth and labelHeight together allow you to fit as much text into specified width and height dimensions
maxSize - (default null) set to limit the font size when using labelWidth and labelHeight
splitWords - (default false) set to true when lineWidth > 0 to split words at the line width
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
setColorRange(color1, color2) - set a color range for label - used by colorRange property - returns obj for chaining
if one color is used, the current color is used and color1 is the second color in the range
showRollColor(visible) - default true to show roll color (used internally)
cache(see Container docs for parameter description) - overrides CreateJS cache() and returns object for chaining
Leave parameters blank to cache bounds of shape (plus outer edge of border if borderWidth > 0)
hasProp(property as String) - returns true if property exists on object else returns false
clone(exact) - makes a copy with properties such as x, y, etc. also copied
exact (default false) ZIM VEE (Pick) values are active in clones unless exact is set to true
For instance, if the object's color is [blue, green]
then its clone might be blue or green - which could be different than the original
If exact is set to true then the clone will be the color of the original object
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
label - references the CreateJS Text object of the label
text - references the text property of the CreateJS Text object
size - the font size of the Label (without px)
font - get or set the font of the text
bold - get or set the bold (boolean) of the font
italic - get or set the italic (boolean) of the font
variant - get or set the variant (boolean) of the font (true is "small-caps")
align - get or set the horizontal alignment of the text
valign - get or set the vertical alignment of the text
paddingHorizontal - read-only value for paddingHorizontal of label
note - no padding property - that gets split into paddingHorizontal and paddingVertical
paddingVertical - read-only value for paddingVertical of label
color - gets or sets the label text color
backgroundColor - gets or sets the label background color
colorRange - if setColorRange() is used, the colorRange is a ratio (0-1) between the colors
setting the colorRange will change the color property of the label
for instance, label.setColorRange(blue, pink) then label.colorRange = .5
will set the color of the label to half way between blue and pink
label.animate({color:red}, 1000); is a shortcut to animate the colorRange
label.wiggle("colorRange", .5, .2, .5, 1000, 5000) will wiggle the colorRange
rollColor - gets or sets the label rollover color
labelWidth - the width at which the text wraps
labelHeight - setting this and labelWidth will change the font size to fit within the specified dimensions
outlineLabel - reference to the outline CreateJS Text object if there is an outline
backing - access to backing object
background - access to background Rectangle if backgroundColor is set
enabled - default is true - set to false to disable
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
OPTIMIZED
This component is affected by the general OPTIMIZE setting (default is false)
if set to true, you will have to stage.update() after setting certain properties
EVENTS
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+54
zim.Label = function(text, size, font, color, rollColor, shadowColor, shadowBlur, align, valign, bold, italic, variant, lineWidth, lineHeight, backing, outlineColor, outlineWidth, backgroundColor, backgroundBorderColor, backgroundBorderWidth, corner, backgroundDashed, padding, paddingHorizontal, paddingVertical, shiftHorizontal, shiftVertical, rollPersist, labelWidth, labelHeight, maxSize, splitWords, style, group, inherit) {
var sig = "text, size, font, color, rollColor, shadowColor, shadowBlur, align, valign, bold, italic, variant, lineWidth, lineHeight, backing, outlineColor, outlineWidth, backgroundColor, backgroundBorderColor, backgroundBorderWidth, corner, backgroundDashed, padding, paddingHorizontal, paddingVertical, shiftHorizontal, shiftVertical, rollPersist, labelWidth, labelHeight, maxSize, splitWords, style, group, inherit";
var duo; if (duo = zob(zim.Label, arguments, sig, this)) return duo;
z_d("54");
this.zimContainer_constructor(null,null,null,null,false);
this.type = "Label";
this.group = group;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
if (zot(text)) text=DS.text!=null?DS.text:"LABEL";
if (zot(size)) size=DS.size!=null?DS.size:36;
if (zot(font)) font=DS.font!=null?DS.font:"arial"; // arial unless manually set
if (zot(color)) color=DS.color!=null?DS.color:"black";
if (zot(bold)) bold=DS.bold!=null?DS.bold:false;
if (zot(italic)) italic=DS.italic!=null?DS.italic:false;
var oa = remember(text, size, font, color, bold, italic);
function remember() {return arguments;}
text = zim.Pick.choose(text);
var emptyText = false;
if (text === "") {
text = " ";
emptyText = true;
}
size = zim.Pick.choose(size);
font = zim.Pick.choose(font);
color = zim.Pick.choose(color);
bold = zim.Pick.choose(bold);
italic = zim.Pick.choose(italic);
if (zot(rollColor)) rollColor=DS.rollColor!=null?DS.rollColor:null;
if (zot(shadowColor) || shadowColor=="ignore") shadowColor=(DS.shadowColor!=null&&shadowColor!="ignore")?DS.shadowColor:-1;
if (zot(shadowBlur) || shadowBlur=="ignore") shadowBlur=(DS.shadowBlur!=null&&shadowBlur!="ignore")?DS.shadowBlur:14;
if (zot(align)) align=DS.align!=null?DS.align:"left";
if (zot(valign)) valign=DS.valign!=null?DS.valign:"top";
if ((!zot(outlineColor) || !zot(DS.outlineColor)) && zot(outlineWidth)) outlineWidth = DS.outlineWidth!=null?DS.outlineWidth:Math.round(size*.2);
if ((!zot(outlineWidth) || !zot(DS.outlineWidth)) && zot(outlineColor)) outlineColor = DS.outlineColor!=null?DS.outlineColor:"#000000";
if (zot(outlineWidth)) outlineWidth = DS.outlineWidth!=null?DS.outlineWidth:0;
if (zot(backgroundColor) || backgroundColor=="ignore") backgroundColor = (DS.backgroundColor!=null&&backgroundColor!="ignore")?DS.backgroundColor:null;
if (zot(padding) || padding=="ignore") padding = (DS.padding!=null&&padding!="ignore")?DS.padding:10;
if (zot(paddingHorizontal)) paddingHorizontal = DS.paddingHorizontal!=null?DS.paddingHorizontal:padding;
if (zot(paddingVertical)) paddingVertical = DS.paddingVertical!=null?DS.paddingVertical:padding;
if (zot(shiftHorizontal)) shiftHorizontal = DS.shiftHorizontal!=null?DS.shiftHorizontal:0;
if (zot(shiftVertical)) shiftVertical = DS.shiftVertical!=null?DS.shiftVertical:0;
if (zot(variant)) variant=DS.variant!=null?DS.variant:false;
if (zot(lineWidth)) lineWidth = DS.lineWidth!=null?DS.lineWidth:null;
if (zot(lineHeight)) lineHeight = DS.lineHeight!=null?DS.lineHeight:null;
if (zot(backing) || backing=="ignore") backing = (DS.backing!=null&&backing!="ignore")?DS.backing.clone():null;
if (zot(rollPersist)) rollPersist = DS.rollPersist!=null?DS.rollPersist:false;
if (DS.labelWidth!=null) lineWidth = DS.labelWidth;
if (!zot(labelWidth)) lineWidth = labelWidth;
if (align == "middle") align = "center";
if (zot(labelHeight)) labelHeight = DS.labelHeight!=null?DS.labelHeight:null;
if (zot(maxSize)) maxSize = DS.maxSize!=null?DS.maxSize:null;
size = maxSize?Math.min(size, maxSize):size;
if (zot(splitWords)) splitWords=DS.splitWords!=null?DS.splitWords:false;
var retina = (typeof zdf!="undefined"&&zdf.retina);
var that = this;
this.mouseChildren = false;
this.paddingVertical = paddingVertical;
this.paddingHorizontal = paddingHorizontal;
var options = [];
options[0] = italic?"italic":"normal";
options[1] = variant?"small-caps":"normal";
options[2] = bold?"bold":"normal";
options[3] = size+"px";
options[4] = font;
var opt = options.join(" ");
var text = String(text);
var obj;
function makeLabel(t) {
var o = new createjs.Text(t, opt, color);
o.lineWidth = lineWidth;
o.lineHeight = lineHeight;
return o;
}
obj = makeLabel(text);
if (splitWords && lineWidth > size * 1.2) { // approximate
// measure lines to make sure not going past lineWidth
function testLine(l, w, line) {
var endIndex = Math.ceil(lineWidth/w*line.length);
var start = line.substr(0,endIndex);
var l2 = makeLabel(start);
var w2 = l2.getMeasuredWidth();
if (w2 > lineWidth) {
while (w2 > lineWidth) {
endIndex--;
start = line.substr(0,endIndex)
l2 = makeLabel(start);
w2 = l2.getMeasuredWidth();
}
} else if (w2 < lineWidth) {
while (w2 < lineWidth) {
endIndex++;
start = line.substr(0,endIndex)
l2 = makeLabel(start);
w2 = l2.getMeasuredWidth();
}
endIndex--;
start = line.substr(0,endIndex)
}
var end = line.substr(endIndex, line.length);
return {endIndex:endIndex, start:start, end:end};
}
var metrics = obj.getMetrics();
var wCount = 0;
while (metrics.width > lineWidth && wCount < 1000) {
wCount++;
zim.loop(metrics.lines, function(line, i) {
line = line.replace(/^[\s\t]+/, "");
var l = makeLabel(line);
var w = l.getMeasuredWidth();
if (w > lineWidth) {
var dat = testLine(l, w, line);
metrics.lines[i] = dat.start;
// move extra letters into the next line if there is one
if (metrics.lines.length > i+1) {
dat.end.trim();
metrics.lines[i+1] = dat.end + " " + metrics.lines[i+1];
} else {
metrics.lines.push(dat.end);
}
obj = makeLabel(metrics.lines.join(" "));
metrics = obj.getMetrics();
return false;
}
}); // end line loop
} // end while
} // end split test
this.label = obj;
obj.textAlign = align;
obj.textBaseline = "alphabetic";
if (outlineWidth > 0) {
var obj2 = this.outlineLabel = obj.clone();
obj2.color = outlineColor;
obj2.outline = outlineWidth;
}
if (shadowColor != -1 && shadowBlur > 0) obj.shadow = new createjs.Shadow(shadowColor, 3, 3, shadowBlur);
this.addChild(obj);
var backingPlaced = false;
if (zot(backing) && zot(backgroundColor)) {
var hitArea = new createjs.Shape();
that.hitArea = hitArea;
}
function setBackground() {
that.removeChild(that.background);
that.background = new zim.Rectangle(
that.getBounds().width+paddingHorizontal*2, that.getBounds().height+paddingVertical*2,
backgroundColor, backgroundBorderColor, backgroundBorderWidth, corner, backgroundDashed, null, false
);
zim.center(that.background, that, 0);
that.setBounds(that.background.x, that.background.y, that.background.width, that.background.height);
}
function setSize() {
var b = obj.getBounds();
var yAdjust;
if (valign == "baseline") {
yAdjust = b.y;
} else if (valign == "top") {
obj.y = size-size/6;
// if (!retina && obj2) obj2.y = size-size/6;
yAdjust = 0;
} else if (valign == "center" || valign == "middle") {
yAdjust = - b.height / 2;
obj.y = size*.3;
// if (!retina && obj2) obj2.y = size*.3;
} else { // bottom align
yAdjust = -b.height;
}
// if (valign!="baseline" && obj2) obj2.y -= size*.06/(valign=="center"?2:1);
that.setBounds(b.x, yAdjust, DS.width?DS.width-padding*2:b.width, DS.height?DS.height-padding*2:b.height);
if (that.hitArea) that.hitArea.graphics.c().f("black").r(that.getBounds().x, that.getBounds().y, that.getBounds().width, that.getBounds().height);
if (valign == "center" || valign == "middle") {
zim.pos(obj, null, 0);
zim.mov(obj, 0, 1);
}
if (backing) {
if (backingPlaced) setBackBounds();
} else if (!zot(backgroundColor)) {
setBackground();
}
if (valign != "baseline" && !retina) obj.y += size/32; //32; // backing often on capital letters without descenders - was /16
finalShift();
}
setSize();
if (!zot(backing)) {
if (backing.type == "Pattern") {
that.backing = new zim.Container(that.width+paddingHorizontal*2, that.height+paddingVertical*2, null, null, false).centerReg(null, null, false);
if (shadowColor != -1 && shadowBlur > 0) {
var shadowRect = new zim.Rectangle(that.width+paddingHorizontal*2-2, that.height+paddingVertical-2, "#666", null, null, corner, null, null, false).center(that.backing);
shadowRect.shadow = new createjs.Shadow(shadowColor, 3, 3, shadowBlur);
}
var mask = new zim.Rectangle(that.width+paddingHorizontal*2, that.height+paddingVertical*2, backgroundColor, null, null, corner, null, null, false).addTo(that.backing);
backing.centerReg(mask);
backing.setMask(mask);
that.backing.pattern = backing;
} else {
that.backing = backing;
}
that.backing.center(that, 0);
backing = that.backing;
setBackBounds();
backingPlaced = true;
}
function setBackBounds() {
var bb = backing.boundsToGlobal();
var bbb = that.boundsToGlobal(bb, true);
that.setBounds(bbb.x, bbb.y, bbb.width, bbb.height);
}
function finalShift() {
zim.pos(obj, (align=="left"||align=="right")?(backing||that.background?paddingHorizontal:0):null, (valign=="top"||valign=="baseline"||valign=="bottom")?(backing||that.background?paddingVertical:0):null, align=="right", valign=="bottom");
obj.x += shiftHorizontal;
obj.y += shiftVertical;
}
finalShift();
function setOutline() {
if (obj2) {
obj2.x = obj.x;
obj2.y = obj.y;
that.addChildAt(obj2,(that.background||that.backing)?1:0);
}
}
setOutline();
Object.defineProperty(that, 'text', {
get: function() {
var t = (obj.text == " " && emptyText) ? "" : obj.text;
return t;
},
set: function(value) {
emptyText = false;
if (value === "") {
value = " ";
emptyText = true;
}
obj.text = String(value);
if (obj2) obj2.text = String(value);
setSize();
if (!zot(lineWidth) && !zot(labelHeight)) {
fitText();
if (obj2) setOutline();
}
}
});
Object.defineProperty(that, 'size', {
get: function() {
return size;
},
set: function(value) {
size = maxSize?Math.min(value, maxSize):value;
options[3] = size + "px";
this.label.font = options.join(" ");
if (obj2) obj2.font = options.join(" ");
setSize();
}
});
Object.defineProperty(that, 'bold', {
get: function() {
return Boolean(this.label.font.match("bold"));
},
set: function(value) {
options[2] = value?"bold":"normal";
this.label.font = options.join(" ");
if (obj2) obj2.font = options.join(" ");
}
});
Object.defineProperty(that, 'italic', {
get: function() {
return Boolean(this.label.font.match("italic"));
},
set: function(value) {
options[0] = value?"italic":"normal";
this.label.font = options.join(" ");
if (obj2) obj2.font = options.join(" ");
}
});
Object.defineProperty(that, 'variant', {
get: function() {
return Boolean(this.label.font.match("small-caps"));
},
set: function(value) {
options[1] = value?"small-caps":"normal";
this.label.font = options.join(" ");
if (obj2) obj2.font = options.join(" ");
}
});
Object.defineProperty(that, 'font', {
get: function() {
return options[4];
},
set: function(value) {
if (zot(value)) return;
options[4] = value;
this.label.font = options.join(" ");
if (obj2) obj2.font = options.join(" ");
}
});
Object.defineProperty(that, 'align', {
get: function() {
return align;
},
set: function(value) {
if (zot(value)) return;
align = value;
this.label.textAlign = align;
if (obj2) obj2.textAlign = align;
setSize();
}
});
Object.defineProperty(that, 'valign', {
get: function() {
return valign;
},
set: function(value) {
if (zot(value)) return;
valign = value;
setSize();
}
});
Object.defineProperty(that, 'color', {
get: function() {
return color;
},
set: function(value) {
if (rollColor == color) rollColor = value;
color = value;
obj.color = color;
if ((!zim.OPTIMIZE&&(zns||!OPTIMIZE)) && that.stage) that.stage.update();
}
});
var startColor;
var endColor;
this.setColorRange = function(color1, color2) {
if (zot(color2)) {
startColor = that.color;
endColor = color1;
} else if (zot(color1)) {
startColor = that.color;
endColor = color2;
} else {
startColor = color1;
endColor = color2;
}
return that;
};
var _colorRange = 0;
Object.defineProperty(that, 'colorRange', {
get: function() {
return _colorRange;
},
set: function(value) {
_colorRange = value;
if (!zot(startColor) && !zot(endColor)) {
that.color = zim.colorRange(startColor, endColor, value);
}
}
});
Object.defineProperty(that, 'backgroundColor', {
get: function() {
return backgroundColor;
},
set: function(value) {
backgroundColor = value;
if (that.background) {
that.background.color = value;
} else if (that.backing) {
that.backing.color = value;
} else {
setBackground();
}
if ((!zim.OPTIMIZE&&(zns||!OPTIMIZE)) && that.stage) that.stage.update();
}
});
Object.defineProperty(that, 'outlineColor', {
get: function() {
return outlineColor;
},
set: function(value) {
outlineColor = value;
if (obj2) obj2.color = outlineColor;
if ((!zim.OPTIMIZE&&(zns||!OPTIMIZE)) && that.stage) that.stage.update();
}
});
Object.defineProperty(that, 'rollColor', {
get: function() {
return rollColor;
},
set: function(value) {
if (!that.mouseoverEvent && value) setRollColors();
if (value==null && that.mouseoverEvent) removeRollColors();
rollColor = value;
}
});
this._enabled = true;
Object.defineProperty(that, 'enabled', {
get: function() {
return that._enabled;
},
set: function(value) {
zenable(that, value);
obj.color = color;
that.mouseChildren = false;
if ((!zim.OPTIMIZE&&(zns||!OPTIMIZE)) && that.stage) that.stage.update();
}
});
this.showRollColor = function(yes) {
if (zot(yes)) yes = true;
if (yes) {
obj.color = rollColor;
} else {
obj.color = color;
}
if (that.stage) that.stage.update();
return that;
};
function setRollColors() {
that.mouseoverEvent = that.on("mouseover", function(e) {if (that.showRollColor) that.showRollColor();});
that.mouseoutEvent = that.on("mouseout", function(e) {if (!that.rollPersist) that.showRollColor(false);});
that.pressupEvent = that.on("pressup", function(e) {if (that.rollPersist) that.showRollColor(false);});
}
function removeRollColors() {
that.off("mouseover", that.mouseoverEvent);
that.off("mouseout", that.mouseoutEvent);
that.off("pressup", that.pressupEvent);
}
if (rollColor) setRollColors();
Object.defineProperty(that, 'labelWidth', {
get: function() {
return lineWidth;
},
set: function(value) {
if (value > 0) {
lineWidth = value;
that.label.lineWidth = value;
if (obj2) obj2.lineWidth = value;
}
if (labelHeight) fitText();
if ((!zim.OPTIMIZE&&(zns||!OPTIMIZE)) && that.stage) that.stage.update();
}
});
Object.defineProperty(that, 'labelHeight', {
get: function() {
return labelHeight;
},
set: function(value) {
if (value > 0) labelHeight = value;
if (lineWidth) fitText();
if ((!zim.OPTIMIZE&&(zns||!OPTIMIZE)) && that.stage) that.stage.update();
}
});
if (!zot(lineWidth) && !zot(labelHeight)) {
fitText();
}
function fitText() {
that.size = 200;
var count = 0;
while(lineHeight < labelHeight / 2 && (that.height > labelHeight || that.width > lineWidth)) {
// while(that.height > labelHeight || that.width > lineWidth) { // ami Aug 2019
count++;
that.size = that.size/2;
if (count>50) break;
}
count = 0;
while(that.height <= labelHeight && that.width <= lineWidth) {
count++;
that.size = Math.ceil(that.size + 1);
if (count>50) break;
}
that.size = that.size - 1;
setOutline();
}
zim.styleTransforms(this, DS);
this.clone = function(exact) {
return that.cloneProps(new zim.Label((exact||!zim.isPick(oa[0]))?that.text:oa[0], (exact||!zim.isPick(oa[1]))?size:oa[1], (exact||!zim.isPick(oa[2]))?font:oa[2], (exact||!zim.isPick(oa[3]))?color:oa[3], rollColor, shadowColor, shadowBlur, align, valign, (exact||!zim.isPick(oa[4]))?bold:oa[4], (exact||!zim.isPick(oa[5]))?italic:oa[5], variant, lineWidth, lineHeight,
!zot(backing)?backing.clone(exact):null, outlineColor, outlineWidth, backgroundColor, backgroundBorderColor, backgroundBorderWidth, corner, backgroundDashed, padding, paddingHorizontal, paddingVertical, shiftHorizontal, shiftVertical, rollPersist, labelWidth, labelHeight, maxSize, splitWords, style, this.group, inherit));
};
};
zim.extend(zim.Label, zim.Container, "clone", "zimContainer");
//-54
/*--
zim.LabelOnPath = function(label, path, percentAngle, percents, showPath, allowToggle, interactive, onTop, style, group, inherit)
LabelOnPath
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
Makes a label along a path of a Squiggle or Blob - which can be interactive, fixed, toggled or hidden
A list of percentages for where the letters are can be provided to move around letters
See: https://zimjs.com/explore/labelonpath.html
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var lop = new LabelOnPath({
label:"Hello World",
// label:new Label({text:"JELLO JIGGLES!", size:50}),
// path:new Blob(),
// path:new Squiggle({
// color:lighter,
// thickness:4,
// points:[[0,75,0,0,-100,200,100,-200],[300,75,0,0,-100,200,100,-200]]
// }).transformPoints("scaleX",2).transformPoints("rotation",0),
percentAngle:100, // default
showPath:false, // default
allowToggle:true, // default
interactive:true, // default
onTop:false // default
}).center();
zog(lop.text)
frame.on("keydown", function () {
// shows percent spacing of letters along path
// could pass [results] in as an array to percents parameter of LabelOnPath
zog(lop.percents.toString());
// uncomment to record the path
// could pass this in as the points parameter to start with a given path
// lop.path.recordPoints(true);
});
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
label - (default "Label on Path") a String or a ZIM Label
can set any label properties such as color, size, font, etc. on the label passed in
path - (default new Squiggle()) a ZIM Squiggle or ZIM Blob
can set any properties such as color, points, etc. on the shape passed in
percentAngle - (default 100) from 0-100 (or beyond in either direction) as to how much to tilt the letters
percents - (default null) an array of percentage locations of the letters along the line - should match number of letters
showPath - (default true) Boolean to show path at start
allowToggle - (default true) Boolean to allow user to toggle path off and on
interactive - (default true) Boolean to allow user to change path with controls, drag or add and remove points
can also set these individually on the path
onTop - (default false) - Boolean to set path on top when dragged
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
toggle(state) - leave off state to toggle path to opposite state. Use true to hide and false to show - returns object for chaining
hidePath() - hides path - returns object for chaining
showPath() - shows path - returns object for chaining
resize() - if not interactive, call this to update the text on the path - returns object for chaining
cache(see Container docs for parameter description) - overrides CreateJS cache() and returns object for chaining
Leave parameters blank to cache bounds of shape (plus outer edge of border if borderWidth > 0)
hasProp(property as String) - returns true if property exists on object else returns false
clone() - makes a copy with properties such as x, y, etc. also copied
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - the name of the class as a String
text - get or set the text on the path
path - read-only access to path - but can manipulate the path
letters - access to ZIM Container of labels used for letters
for instance labels.loop(function (label) {label.color = red;});
or animate as a sequence labels.animate({props:{scale:1.5}, loop:true, rewind:true, sequence:200});
numLetters - how many letters - same as letters.numChildren
percents - access to the array of percents for letter positioning - resize() after changing unless interactive which auto resizes
color - get or set the color of the text
allowToggle - get or set the Boolean to allow toggling the path
interactive - get or set the Boolean to allow interaction with the path
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+54.5
zim.LabelOnPath = function(label, path, percentAngle, percents, showPath, allowToggle, interactive, onTop, style, group, inherit) {
var sig = "label, path, percentAngle, percents, showPath, allowToggle, interactive, onTop, style, group, inherit";
var duo; if (duo = zob(zim.LabelOnPath, arguments, sig, this)) return duo;
z_d("54.5");
this.zimContainer_constructor(null,null,null,null,false);
this.type = "LabelOnPath";
this.group = group;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
if (zot(label)) label = DS.label!=null?DS.label:new zim.Label("Label on Path");
if (zot(path)) path = DS.path!=null?DS.path:new zim.Squiggle({points:[[0,0,0,0,-86,57,86,-57],[300,150,0,0,-133,21,133,-21]]});
if (zot(percentAngle)) percentAngle = DS.percentAngle!=null?DS.percentAngle:100;
if (zot(percents)) percents = DS.percents!=null?DS.percents:null;
if (zot(showPath)) showPath = DS.showPath!=null?DS.showPath:true;
if (zot(allowToggle)) allowToggle = DS.allowToggle!=null?DS.allowToggle:true;
if (zot(interactive)) interactive = DS.interactive!=null?DS.interactive:true;
if (zot(onTop)) onTop = DS.onTop!=null?DS.onTop:false;
var color = label.color;
path.addTo(this);
var that = this;
this.path = path;
this.allowToggle = allowToggle;
path.interactive = interactive;
if (typeof label == "string") label = new zim.Label(label);
var lastAlpha = path.alpha;
if (!showPath) path.alp(0);
path.onTop = onTop;
var letters = this.letters = new zim.Container().addTo(this);
if (!percents) {
percents = [];
for (var i=0; i<label.text.length; i++) {
percents.push(zim.decimals(1/(label.text.length-(path.type=="Blob"?0:1))*100*i));
}
}
this.percents = percents;
function setText() {
for (var i=letters.numChildren-1; i>=0; i--) {
letters.getChildAt(i).dispose();
}
that.numLetters = label.text.length;
for (var i=0; i<that.numLetters; i++) {
var letter = label.clone();
letter.text = label.text[i];
letter.centerReg(letters).reg(null,letter.height);
if (letter.text != "" && letter.text != " ") letter.expand(0);
if (that.allowToggle) letter.cursor = "pointer";
letter.on("mousedown", function () {
if (!that.allowToggle) return;
that.toggle();
});
}
that.resize();
}
this.resize = function() {
var segmentRatios = path.segmentRatios;
var segmentPoints = path.segmentPoints;
for (var i=0; i<this.numLetters; i++) {
var point = path.getCurvePoint(percents[i]/100, segmentRatios, segmentPoints, true);
if (!point) continue;
var locPoint = this.globalToLocal(point.x, point.y);
if (!locPoint) continue;
letters.getChildAt(i)
.loc(locPoint)
.rot((point.angle>180?(point.angle-360):point.angle)*percentAngle/100);
}
return this;
};
setText();
this.showPath = function(controls) {
this.toggle(true);
path.toggle(controls);
return this;
};
this.hidePath = function() {
this.toggle(false);
return this;
};
Object.defineProperty(that, 'text', {
get: function() {
return label.text;
},
set: function(value) {
label.text = value;
percents = [];
for (var i=0; i<label.text.length; i++) {
percents.push(zim.decimals(1/(label.text.length-(path.type=="Blob"?0:1))*100*i));
}
setText();
// if (that.stage) that.stage.update();
}
});
Object.defineProperty(this, 'color', {
get: function() {
return color;
},
set: function(value) {
color = value;
for (var i=0; i<that.letters.numChildren; i++) {that.letters.getChildAt(i).color = color;}
if (that.stage) that.stage.update();
}
});
Object.defineProperty(that, 'interactive', {
get: function() {
return interactive;
},
set: function(value) {
interactive = value;
path.interactive = value;
if (this.ticker) zim.Ticker.remove(this.ticker);
if (interactive) {
this.ticker = zim.Ticker.add(function () {
that.resize();
});
}
}
});
if (this.interactive) {
this.ticker = zim.Ticker.add(function () {
that.resize();
});
}
var _toggled = that.toggled = showPath;
this.toggle = function(state) {
if (!this.allowToggle) return;
if (zot(state)) _toggled = !_toggled;
else if (state) _toggled = true;
else _toggled = false;
if (_toggled) {
path.alp(lastAlpha);
if (this.interactive) {
path.showControls();
letters.mouseEnabled = false;
letters.mouseChildren = false;
letters.cursor = "default";
if (this.controlHideEvent) path.off("controlshide", this.controlHideEvent);
this.controlHideEvent = path.on("controlshide", function () {
letters.mouseEnabled = true;
letters.mouseChildren = true;
letters.cursor = "pointer";
lastAlpha = path.alpha;
path.alp(0);
_toggled = false;
that.toggled = _toggled;
if (that.stage) that.stage.update();
}, null, true); // just once
}
} else {
lastAlpha = path.alpha;
path.alp(0);
letters.mouseEnabled = true;
letters.mouseChildren = true;
letters.cursor = "pointer";
}
that.toggled = _toggled;
if (that.stage) that.stage.update();
return that;
};
that.toggle(true);
zim.styleTransforms(this, DS);
this.clone = function() {
return that.cloneProps(new zim.LabelOnPath(that.label.clone(), that.path.clone(), percentAngle, zim.copy(percents), showPath, allowToggle, interactive, onTop, style, this.group, inherit));
};
this.dispose = function(a,b,disposing) {
if (this.ticker) zim.Ticker.remove(this.ticker);
if (!disposing) this.zimContainer_dispose(true);
return true;
};
};
zim.extend(zim.LabelOnPath, zim.Container, ["clone", "dispose"], "zimContainer", false);
//-54.5
/*--
zim.LabelOnArc = function(label, size, font, color, radius, flip, spacing, letterSpacing, angles, showCircle, arcColor, arcBorderColor, arcBorderWidth, radiusSpread, style, group, inherit)
LabelOnArc
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
Makes a label along an arc - see also LabelOnPath - for a more interactive version
Used internally for making labels on Radial and RadialMenu objects
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var loa = new LabelOnArc({
label:"Hello World"
}).center();
zog(loa.text);
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
label - (default "Label on Arc") a String or a ZIM Label
can set any label properties such as color, size, font, etc. on the label passed in
size - (default 30) the font size of the label
font - (default "verdana") the font of the label - can load custom fonts in Frame() or frame.loadAssets()
color - (default white) a color for the text can be any ZIM or CSS color
radius - (default 100) the radius of the circle to apply the arc of the text
flip - (default false) set to true to flip text if between 90 and 270
spacing - (default 0) the space between the Label and the arc - varies with different fonts
letterSpacing - (default 5) - the space between letters
angles - (default null) optionally specify an array of angles for the letters
this will override letterSpacing - see also angles property to receive an array of angles
showCircle - (default false) set to true to see a circle - then use circle property to adjust if desired
arcColor - (default null) set to a color to see a filled arc
arcBorderColor - (default null) the borderColor of the arc
acrBorderWidth - (default 2 if arcBorderColor) the borderWidth of the arc
radiusSpread - (default false) set to true to keep same letter angles as radius is changed
ignored if angles are provided
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
hasProp(property as String) - returns true if property exists on object else returns false
clone() - makes a copy with properties such as x, y, etc. also copied
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - the name of the class as a String
text - get the text on the arc (make a new object if change of text is needed)
radius - get or set the radius of the arc (see radiusSpread parameter too)
labels - an array of ZIM Label objects for the letters
letters - access to ZIM Container of labels used for letters
for instance labels.loop(function (label) {label.color = red;});
or animate as a sequence labels.animate({props:{scale:1.5}, loop:true, rewind:true, sequence:200});
numLetters - how many letters - same as letters.numChildren
letterHeight - get the height of letters
color - get or set the text color
circle - access to the circle object
arc - access to the arc object
angles - access to the array angles for letter positioning
use angles.toString() to log angle data (for kerning)
this can be modified and passed in as an angles property to start
innerRadius - the inside radius at the bottom of the text
outerRadius - the outside radius at the top of the text
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+54.55
zim.LabelOnArc = function(label, size, font, color, radius, flip, spacing, letterSpacing, angles, showCircle, arcColor, arcBorderColor, arcBorderWidth, radiusSpread, style, group, inherit) {
var sig = "label, size, font, color, radius, flip, spacing, letterSpacing, angles, showCircle, arcColor, arcBorderColor, arcBorderWidth, radiusSpread, style, group, inherit";
var duo; if (duo = zob(zim.LabelOnArc, arguments, sig, this)) return duo;
z_d("54.55");
this.group = group;
var DS = style===false?{}:zim.getStyle("LabelOnArc", this.group, inherit);
if (zot(size)) size = DS.size!=null?DS.size:30;
if (zot(label)) label = DS.label!=null?DS.label:new zim.Label("Label on Arc", size);
if (zot(font)) font = DS.font!=null?DS.font:"verdana";
if (zot(color)) color = DS.color!=null?DS.color:"white";
if (zot(radius)) radius = DS.radius!=null?DS.radius:100;
if (zot(flip)) flip = DS.flip!=null?DS.flip:false;
if (zot(spacing)) spacing = DS.spacing!=null?DS.spacing:0;
if (zot(letterSpacing)) letterSpacing = DS.letterSpacing!=null?DS.letterSpacing:5;
if (zot(angles)) angles = DS.angles!=null?DS.angles:null;
var anglesO = !zot(angles);
if (zot(showCircle)) showCircle = DS.showCircle!=null?DS.showCircle:false;
if (zot(arcColor)) arcColor = DS.arcColor!=null?DS.arcColor:null;
if (zot(arcBorderColor)) arcBorderColor = DS.arcBorderColor!=null?DS.arcBorderColor:null;
if (zot(arcBorderWidth)) arcBorderWidth = DS.arcBorderWidth!=null?DS.arcBorderWidth:null;
if (zot(radiusSpread)) radiusSpread = DS.radiusSpread!=null?DS.radiusSpread:false;
//if (zot(inside)) inside = DS.inside!=null?DS.inside:true;
var outerRadius = this.outerRadius = radius + spacing + label.height;
this.innerRadius = radius + spacing;
this.zimContainer_constructor(-outerRadius,-outerRadius,outerRadius*2,outerRadius*2, false);
this.type = "LabelOnArc";
var that = this;
if (label.type != "Label") label = new zim.Label(label, size, font, color);
that.text = label.text;
if (flip) {
var rev = label.text.split("").reverse().join("");
label.text = rev;
}
var letters = that.letters = new zim.Container(this.width, this.height).centerReg(this);
var totalAngle;
var rawAngles;
that.numLetters = label.text.length;
this.letterHeight = label.height;
var labels = that.labels = [];
for (var i=0; i<that.numLetters; i++) {
var letter = label.clone();
labels.push(letter);
letter.text = label.text[i];
letter.letterHolder = new zim.Container(letter.width, letter.height);
letter.centerReg(letter.letterHolder).rot(flip?180:0);
}
var circle = this.circle = new zim.Circle(radius);
if (showCircle) circle.addTo(this);
var arc = this.arc = new zim.Shape().addTo(this);
function makeArc() {
totalAngle = 0;
rawAngles = [0];
for (i=0; i<that.numLetters; i++) {
var letter = labels[i];
var ang = Math.atan((letter.width+letterSpacing)/2/(radius+spacing))*180/Math.PI*2;
rawAngles.push(ang);
totalAngle += ang;
letter.letterHolder.centerReg(letters).reg(null,radius+spacing+letter.height + (flip?letter.height*.13:0));
}
that.circle.radius = radius;
if (arcColor || arcBorderColor || arcBorderWidth) {
if (arcBorderWidth>0 && zot(arcBorderColor)) arcBorderColor = "#000000";
else if (zot(arcBorderWidth) && !zot(arcBorderColor)) arcBorderWidth = 2;
arc.graphics.c().f(null).s(arcBorderColor).ss(arcBorderWidth).arc(0,0,radius, (startAngle-90)*Math.PI/180, (startAngle-90+totalAngle)*Math.PI/180);
}
}
makeArc();
if (angles) {
// overwrite totalAngle with given angles
totalAngle = 0;
for (var i=0; i<angles.length; i++) {
totalAngle += angles[i];
}
totalAngle += angles[angles.length-1]/2; // whatever
}
function makeAngles() {
if (!anglesO) {
angles = [];
for (var i=0; i<rawAngles.length-1; i++) {
angles[i] = Math.round((rawAngles[i]+rawAngles[i+1])/2*100)/100;
}
}
that.angles = angles;
var startAngle = that.startAngle = - totalAngle/2;
var lastAngle = startAngle;
for (var i=0; i<letters.numChildren; i++) {
var letter = letters.getChildAt(i);
var amount = angles[i];
lastAngle = letter.rotation = lastAngle + angles[i];
}
}
makeAngles();
Object.defineProperty(this, 'radius', {
get: function() {
return radius;
},
set: function(value) {
radius = value;
makeArc();
if (!anglesO && !radiusSpread) makeAngles();
}
});
Object.defineProperty(this, 'color', {
get: function() {
return color;
},
set: function(value) {
color = value;
for (var i=0; i<that.labels.length; i++) {that.labels[i].color = color;}
if (that.stage) that.stage.update();
}
});
zim.styleTransforms(this, DS);
this.clone = function() {
return that.cloneProps(new zim.LabelOnArc(label, size, font, color, radius, flip, spacing, letterSpacing, angles, showCircle, arcColor, arcBorderColor, arcBorderWidth, radiusSpread, style, this.group, inherit));
};
};
zim.extend(zim.LabelOnArc, zim.Container, "clone", "zimContainer", false);
//-54.55
/*--
zim.LabelLetters = function(label, align, valign, letterSpacing, letterSpacings, lineSpacing, lineSpacings, lineHeight, lineAlign, lineValign, cache, rtl, style, group, inherit)
LabelLetters
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
Splits apart a ZIM Label into labels per characater
to allow manipulation of each character - animation, kerning, etc.
Also accepts basic HTML-like tags to allow Canvas text to have multi-formatting.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var letters = new LabelLetters("Label Letters", "center", "bottom", 5)
.center()
.animate({
props:{scale:1.5, rotation:-10},
wait:.5,
time:.2,
sequence:.05,
rewind:true
});
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
label - (default "Label Letters") a String or a ZIM Label
can set any label properties such as color, size, font, etc. on the label passed in
can pass in a string with basic "old fashioned" HTML tags as follows:
<b>bold</b> - or <strong>bold</strong>
<i>italic</i> - or <em>italic</em>
<u>underline</i> - can use this with <a> to make a classic underlined link
<a href=url target=_blank>link</a>
<font
color=zimColor
backgroundColor='htmlColor'
rollBackgroundColor=#hexColor
size=20
family=verdana
group=groupStyle>font</font>
note: use NO QUOTES except for single quote with colors if want HTML blue for instance rather than ZIM blue
note: setting groupStyle will make letter from scratch as opposed to building on the submitted label styles
align - (default "center") set to "left", "center" / "middle", "right" for letter registration x positioning
also see lineAlign for alignment of lines
valign - (default "center") set to "top", "center" / "middle", "bottom" for letter registration y positioning
also see lineValign for vertical alignment of lines
letterSpacing - (default 5) - the space between letters
letterSpacing is turned off if the Label has a backgroundColor
to use letterSpacing and a backgroundColor use the backing parameter of Label instead of backgroundColor
or use letterSpacings (see below) to set specific spacings (kerning) on letters
letterSpacings - (default null) - an array of the space between letters each letter
any value here will override the letterSpacing
0 is the index for the space between first and second letter
the length of this should be one less than the number of letters
lineSpacing - (default 5) - the space between lines (not including lineHeight)
lineSpacings - (default null) - an array of the space between lines
any values here will override the lineSpacing
lineHeight - (default null) null will auto set the height. Set to a number to force line heights - if \n or <br> are present in label
lineAlign - (default LEFT or RIGHT for rtl:true) the horizontal alignment of lines if multiple lines - set to LEFT, CENTER/MIDDLE, RIGHT
lineValign - (default BOTTOM) the vertical alignment within lineSpacing if multiple lines - set to TOP, CENTER/MIDDLE, BOTTOM
cache - (default false) set to true to cache each letter - improves performance on animation
rtl - (default false) set to true to reverse letters other than a-zA-Z0-9 and set default lineAlign to RIGHT
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
hasProp(property as String) - returns true if property exists on object else returns false
clone() - makes a copy with properties such as x, y, etc. also copied
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - the name of the class as a String
text - get the text of the original Label
labels - an array of ZIM Label objects for the letters
numLetters - how many letters (same as numChildren)
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+54.57
zim.LabelLetters = function(label, align, valign, letterSpacing, letterSpacings, lineSpacing, lineSpacings, lineHeight, lineAlign, lineValign, cache, rtl, style, group, inherit) {
var sig = "label, align, valign, letterSpacing, letterSpacings, lineSpacing, lineSpacings, lineHeight, lineAlign, lineValign, cache, rtl, style, group, inherit";
var duo; if (duo = zob(zim.LabelLetters, arguments, sig, this)) return duo;
z_d("54.57");
this.group = group;
var DS = style===false?{}:zim.getStyle("LabelLetters", this.group, inherit);
if (zot(label)) label = DS.label != null ? DS.label : new zim.Label("Label Letters");
if (zot(align)) align = DS.align != null ? DS.align : "center";
if (zot(valign)) valign = DS.valign != null ? DS.valign : "center";
if (zot(letterSpacing)) letterSpacing = DS.letterSpacing != null ? DS.letterSpacing : 5;
if (zot(letterSpacings)) letterSpacings = DS.letterSpacings != null ? DS.letterSpacings : null;
if (zot(lineHeight)) lineHeight = DS.lineHeight != null ? DS.lineHeight : null;
if (zot(lineSpacing)) lineSpacing = DS.lineSpacing != null ? DS.lineSpacing : 5;
if (zot(lineSpacings)) lineSpacings = DS.lineSpacings != null ? DS.lineSpacings : null;
if (zot(rtl)) rtl = DS.rtl != null ? DS.rtl : false;
if (zot(lineAlign)) lineAlign = DS.lineAlign != null ? DS.lineAlign : rtl?"right":"left";
if (zot(lineValign)) lineValign = DS.lineValign != null ? DS.lineValign : "bottom";
if (zot(cache)) cache = DS.cache != null ? DS.cache : false;
this.zimContainer_constructor(null, null, null, null, false);
this.type = "LabelLetters";
var that = this;
var letterData = that.letterData = [];
var original;
if (label.type != "Label") {
data = parseHTML(label); // returns {text:text, data:data}
letterData = data.data;
label = new zim.Label(data.text);
} else {
data = parseHTML(label.text);
letterData = data.data;
label.text = data.text;
}
that.text = data.original;
that._color = label.color;
function parseHTML(html) {
var data = [];
// var example = "LabelLetters()<br><br><font group=heading backgroundColor=yellow rollBackgroundColor=green><a href=https://zimjs.com target=_blank>Example</a></font>: <b>strong</b> <i>emphasis</i> <u>underline</u><br><font color=red size=50 family=verdana><strong>big</strong> red verdana</font><br>the next line"
// "LabelLetters()Example: strong emphasis underlinebig red verdanathe next line"
// "01234567890123456789012345678901234567890123456789012345678901234567890120123456789012"
// "0 1 2 3 4 5 6 7"
// html = "!Roger הגיע בשבילך משהו בדואר Dan אני לומד עברית";
// html = "הגיע בשבילך משהו בדואר.";
if (rtl) {
count = -1;
function insert(data) {
return data.split("").reverse().join("")
}
html = html.replace(/[\u0591-\u07FF]+/ig, insert);
// and there may be tags or LTR characters next to RTL without a space:
html = html.replace(/([^\u0591-\u07FF ])([\u0591-\u07FF])/ig, "$1-!!-$2"); // note the not space
html = html.replace(/([\u0591-\u07FF])([^\u0591-\u07FF ])/ig, "$1-!!-$2"); // note the not space
html = html.replace(/([^\u0591-\u07FF]) ([\u0591-\u07FF])/ig, "$1-!!- -!!-$2");
html = html.replace(/([\u0591-\u07FF]) ([^\u0591-\u07FF])/ig, "$1-!!- -!!-$2");
var sp = html.split(/-!!-/g);
loop(sp, function(ssp, i){
if (ssp.match(/[\u0591-\u07FF]/i)) {
sp[i] = ssp.split(" ").reverse().join(" ");
}
});
html = sp.join("");
}
// normalize tags
html = html.replace(/\n|\r/g,"<br>");
html = html.replace(/<strong>|<strong \/>|<strong\/>/gi,"<b>");
html = html.replace(/<\/strong>/gi,"</b>");
html = html.replace(/<em>|<em \/>|<em\/>/gi,"<i>");
html = html.replace(/<\/em>/gi,"</i>");
html = html.replace(/\\n|\\r/g,"<br>");
html = html.replace(/<br>|<br \/>|<br\/>(<\/br>)?/gi,"<br>");
html = html.replace(/<b/gi,"<b");
html = html.replace(/<i/gi,"<i");
html = html.replace(/<u/gi,"<u");
html = html.replace(/<br/gi,"<br");
html = html.replace(/<a/gi,"<a");
html = html.replace(/<font/gi,"<font");
// turn all other tags into "" do split on tag and count index for tag
// process this and store in data so get index of tags in string with no tags counted
var regs = [
/<(a|i|u|f|br|\/a|\/i|\/u|\/f|\/b)[^>]*>/g,
/<(a|i|u|f|br|\/a|\/i|\/u|\/f|b)[^>]*>/g,
/<(b|i|u|f|br|\/b|\/i|\/u|\/f|\/a)[^>]*>/g,
/<(b|i|u|f|br|\/b|\/i|\/u|\/f|a)[^>]*>/g,
/<(b|a|u|f|br|\/b|\/a|\/u|\/f|\/i)[^>]*>/g,
/<(b|a|u|f|br|\/b|\/a|\/u|\/f|i)[^>]*>/g,
/<(b|a|i|f|br|\/b|\/a|\/i|\/f|\/u)[^>]*>/g,
/<(b|a|i|f|br|\/b|\/a|\/i|\/f|u)[^>]*>/g,
/<(b|a|i|u|br|\/b|\/a|\/i|\/u|\/f)[^>]*>/g,
/<(b|a|i|u|br|\/b|\/a|\/i|\/u|f)[^>]*>/g
];
var types = ["b","a","i","u","font"];
var p;
zim.loop(types, function(type, i) {
p = html.replace(regs[i*2],"");
if (type=="font") {
var arr = p.split("<font ");
} else if (type=="a") {
var arr = p.split("<a ");
} else {
var arr = p.split("<"+type+">");
}
process(arr, type, 0); // 0 for add
p = html.replace(regs[i*2+1],"");
arr = p.split("</"+type+">");
process(arr, type, 1); // 1 for remove
});
p = html.replace(/<br>/gi,"@^#");
p = p.replace(/<(b|a|i|u|f|\/b|\/a|\/i|\/u|\/f)[^>]*>/g,"");
arr = p.split("@^#");
var original = arr.join("\n");
p = arr.join("");
process(arr, "br", 0); // 0 for add
function process(text, type, action) {
if (text.length > 1) {
if ((type=="font" || type=="a") && action==0) {
var length = text[0].length;
zim.loop(text, function(s, i) {
if (i==0) return;
var d = data[length];
if (!d) data[length] = [];
d = data[length] ;
var arr = s.split(">");
if (d[action]) d[action].push(type + " " + arr[0]);
else d[action] = [type + " " + arr[0]];
length += arr[1].length;
});
} else {
text.pop();
var running = 0;
zim.loop(text, function(s) {
running += s.length;
var d = data[running];
if (!d) data[running] = [];
d = data[running];
if (d[action]) d[action].push(type);
else d[action] = [type];
});
}
}
}
// [[adds at index], [removes at index]]
// b,i,u,br,a,font
// var da = [,, [["b","i"]] ,[,["b"]],,,[["br","font color=red size=10 family=courier"]],["i"]],...];
return {text:p, data:data, original:original};
}
that.numLetters = label.text.length;
// NORMALIZE SPACINGS
var letterSpacingsOriginal = !zot(letterSpacings);
if (letterSpacings && !Array.isArray(letterSpacings)) letterSpacings = null;
if (!letterSpacings) {
letterSpacings = [];
for (var i = 0; i < that.numLetters; i++) {
letterSpacings.push(letterSpacing);
}
} else {
for (var i = 0; i < that.numLetters; i++) {
if (zot(letterSpacings[i])) letterSpacings[i] = letterSpacing;
}
}
that.letterSpacings = letterSpacings;
if (lineSpacings && !Array.isArray(lineSpacings)) lineSpacings = null;
if (!lineSpacings) {
lineSpacings = [];
for (var i = 0; i < that.numLetters - 1; i++) {
lineSpacings.push(lineSpacing);
}
} else {
for (var i = 0; i < that.numLetters - 1; i++) {
if (zot(lineSpacings[i])) lineSpacings[i] = lineSpacing;
}
}
that.lineSpacings = lineSpacings;
// LINE CONTROL
that.labels = [];
that.lines = [[]];
var lineWidths = [];
var lineHeights = [];
var linePositionsY = [0];
var lineY = 0;
var lineW = 0;
var lineH = 0;
var lineNum = 0;
var maxW = 0;
// HTML CONTROL
var d = letterData;
var bCheck = false;
var iCheck = false;
var uCheck = false;
var brCheck = false;
var colorCheck = false;
var sizeCheck = false;
var groupCheck = false;
var familyCheck = false;
var originalGroup = label.group;
var urlCheck = false;
var targetCheck = false;
var backgroundColorCheck = false;
var rollBackgroundColorCheck = false;
// ROLLOVER CONTROL
that.rolls = [[]];
for (var i=0; i<that.numLetters; i++) {
// PARSE TAG CHECKS
brCheck = false;
if (d[i]) {
// end tags - do ends first just in case tag ends at same letter it starts
if (d[i][1]) {
if (d[i][1].indexOf("b") >= 0) bCheck = false;
if (d[i][1].indexOf("i") >= 0) iCheck = false;
if (d[i][1].indexOf("u") >= 0) uCheck = false;
zim.loop(d[i][1], function (item) {
if (item.match(/^font/i)) {
colorCheck = false;
backgroundColorCheck = false;
if (rollBackgroundColorCheck) that.rolls.push([]);
rollBackgroundColorCheck = false;
sizeCheck = false;
familyCheck = false;
groupCheck = false;
return;
}
if (item.match(/^a/i)) {
urlCheck = false;
targetCheck = false;
return;
}
});
}
// start tags
if (d[i][0]) {
if (d[i][0].indexOf("b") >= 0) bCheck = true;
if (d[i][0].indexOf("i") >= 0) iCheck = true;
if (d[i][0].indexOf("u") >= 0) uCheck = true;
brCheck = 0;
zim.loop(d[i][0], function (item) {
if (item=="br") brCheck++;
});
zim.loop(d[i][0], function (item) {
if (item.match(/^font/i)) {
var r = item.match(/ color\s?=\s?(\S*)/i);
if (r) {
colorCheck = r[1];
var ind = zim.colors.indexOf(colorCheck);
if (ind>=0) colorCheck = zim.colorsHex[ind];
colorCheck = colorCheck.replace(/'/g,"");
}
r = item.match(/size\s?=\s?(\S*)/i);
if (r) sizeCheck = r[1];
r = item.match(/backgroundColor\s?=\s?(\S*)/i);
if (r) {
backgroundColorCheck = r[1];
var ind = zim.colors.indexOf(backgroundColorCheck);
if (ind>=0) backgroundColorCheck = zim.colorsHex[ind];
backgroundColorCheck = backgroundColorCheck.replace(/'/g,"");
}
r = item.match(/rollBackgroundColor\s?=\s?(\S*)/i);
if (r) {
rollBackgroundColorCheck = r[1];
var ind = zim.colors.indexOf(rollBackgroundColorCheck);
if (ind>=0) rollBackgroundColorCheck = zim.colorsHex[ind];
rollBackgroundColorCheck = rollBackgroundColorCheck.replace(/'/g,"");
}
r = item.match(/group\s?=\s?(\S*)/i);
if (r) groupCheck = r[1];
r = item.match(/family\s?=\s?(.*)/i);
if (r) {
familyCheck = r[1];
familyCheck = familyCheck.split(/\ssize\s?=|\scolor\s?=|\sgroup\s?=/i)[0];
}
return;
}
if (item.match(/^a/i)) {
var r = item.match(/href\s?=\s?(\S*)/i);
if (r) urlCheck = r[1];
r = item.match(/target\s?=\s?(\S*)/i);
if (r) targetCheck = r[1];
return;
}
});
} // end start tag
} // end all tags
// HANDLE CHECKS AND STORE MAX SIZES
if (groupCheck) {
var letter = new Label({text:label.text[i], group:groupCheck})
} else {
var letter = label.clone();
letter.text = label.text[i];
}
that.labels.push(letter);
if (bCheck) letter.bold = true;
if (iCheck) letter.italic = true;
if (colorCheck) letter.color = colorCheck;
if (backgroundColorCheck) letter.backgroundColor = backgroundColorCheck;
var s = letterSpacingsOriginal?letterSpacings[i]:zot(letter.backgroundColor)?letterSpacings[i]:-.5;
if (rollBackgroundColorCheck) {
letter.rollIndex = that.rolls.length-1;
letter.zrbc = rollBackgroundColorCheck;
letter.zobc = letter.backgroundColor;
that.rolls[letter.rollIndex].push(letter);
letter.expand(0);
letter.on("mouseover", rollOn);
letter.on("mouseout", rollOff);
}
if (urlCheck) {
letter.expand(s,0);
letter.zurl = urlCheck;
letter.ztar = targetCheck;
letter.cur();
letter.on("click", function (e) {
var letter = e.currentTarget;
rollOff(e);
if (!letter.ztar) letter.ztar = "_self";
zgo(letter.zurl, letter.ztar);
});
}
if (sizeCheck) letter.size = sizeCheck;
if (familyCheck) letter.font = familyCheck;
if (brCheck) {
lineY += (zot(lineHeight)?lineH:lineHeight) + lineSpacings[lineNum];
linePositionsY.push(lineY);
lineHeights.push(zot(lineHeight)?lineH:lineHeight);
lineWidths.push(lineW);
maxW = Math.max(maxW, lineW);
}
if (brCheck) {
if (brCheck > 1) {
zim.loop(brCheck-1, function (bi) {
that.lines.push([]);
lineY += (zot(lineHeight)?lineH:lineHeight) + lineSpacings[lineNum];
linePositionsY.push(lineY);
lineHeights.push(zot(lineHeight)?lineH:lineHeight);
lineWidths.push(0);
lineNum++;
});
}
lineH = 0;
lineW = 0;
that.lines.push([]);
lineNum++;
}
lineW += letter.width + s;
lineH = Math.max(lineH, letter.height);
if (i==that.numLetters-1) {
lineWidths.push(lineW);
lineHeights.push(lineH);
maxW = Math.max(maxW, lineW);
}
that.lines[lineNum].push(letter);
if (uCheck) letter.underline = new zim.Line(letter.width+s+1,1,letter.color).center(letter,this).mov(0,letter.height/2);
} // end checks
// ROLL FUNCTIONS
function rollOn(e) {
var letter = e.currentTarget;
var rolls = that.rolls[letter.rollIndex]
zim.loop(rolls, function (l) {
l.backgroundColor = letter.zrbc;
})
if (letter.stage) letter.stage.update();
}
function rollOff(e) {
var letter = e.currentTarget;
var rolls = that.rolls[letter.rollIndex]
zim.loop(rolls, function (l) {
l.backgroundColor = letter.zobc;
})
if (letter.stage) letter.stage.update();
}
// LOOP THROUGH LINES AND APPLY POSITIONS
var count = 0;
for (var j=0; j<that.lines.length; j++) {
var ll = that.lines[j];
var lineW = lineWidths[j];
var lineH = lineHeights[j];
var lineY = linePositionsY[j];
var startX, startY;
if (lineAlign=="left") startX = 0;
else if (lineAlign=="right") startX = maxW-lineW;
else startX = (maxW-lineW)/2;
startY = lineY;
for (i=0; i<ll.length; i++) {
count++;
if (cache) letter.cache();
letter = ll[i];
letter.regX = align=="left"?0:(align=="right"?letter.width:letter.width/2);
letter.regY = valign=="top"?0:(valign=="bottom"?letter.height:letter.height/2);
var sY = startY+(valign=="top"?0:valign=="bottom"?letter.height:letter.height/2);
if (lineValign=="center" || lineValign=="middle") {
sY += (lineHeights[j]-letter.height)/2;
} else if (lineValign=="bottom") {
sY += lineHeights[j]-letter.height;
}
var s = letterSpacingsOriginal?letterSpacings[count-1]:zot(letter.backgroundColor)?letterSpacings[count-1]:-.5;
// var s = zot(letter.backgroundColor)?letterSpacings[count-1]:(letter.text=="w")-1.5;
if (align=="left") {
letter.loc(startX, sY, this);
startX = letter.x+letter.width+s;
} else if (align=="right") {
letter.loc(startX+letter.width, sY, this);
startX = letter.x+s;
} else {
letter.loc(startX+letter.width/2, sY, this);
startX = letter.x+letter.width/2+s;
}
} // end lines letters
} // end lines
if (!this.getBounds()) this.setBounds(0,0,0,0);
this.regX = this.getBounds().x;
this.regY = this.getBounds().y;
Object.defineProperty(this, 'color', {
get: function () {
return this._color;
},
set: function (value) {
this._color = value;
for (var i = 0; i < that.numChildren; i++) { that.getChildAt(i).color = this._color; }
if (that.stage) that.stage.update();
}
});
this.dispose = function() {
zim.gD(this); // globalDispose function for common elements
zim.loop(that.labels, function (letter) {
letter.removeFrom();
letter.dispose();
});
that.removeFrom();
}
zim.styleTransforms(this, DS);
this.clone = function () {
return that.cloneProps(new zim.LabelLetters(label, align, valign, letterSpacing, letterSpacings, lineSpacing, lineSpacings, lineHeight, lineAlign, lineValign, cache, rtl, style, this.group, inherit));
};
};
zim.extend(zim.LabelLetters, zim.Container, "clone", "zimContainer", false);
//-54.57
/*--
zim.Button = function(width, height, label, backgroundColor, rollBackgroundColor, color, rollColor, borderColor, borderRollColor, borderWidth, corner, shadowColor, shadowBlur, hitPadding, gradient, gloss, dashed, backing, rollBacking, rollPersist, icon, rollIcon, toggle, toggleBackgroundColor, rollToggleBackgroundColor, toggleColor, rollToggleColor, toggleBacking, rollToggleBacking, toggleIcon, rollToggleIcon, toggleEvent, wait, waitTime, waitBackgroundColor, rollWaitBackgroundColor, waitColor, rollWaitColor, waitModal, waitEnabled, waitBacking, rollWaitBacking, waitIcon, rollWaitIcon, align, valign, indent, indentHorizontal, indentVertical, style, group, inherit)
Button
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
Makes a button with rollover and many more features - see parameters.
You will need to pass in a Label to change the font properties of the button from the default.
You will then need to add the button to the stage and add a mousedown or click event.
Button rollover is done automatically.
You can set a backing display object (Shape, Bitmap, Pattern, etc.) in place of the standard rectangle.
You can set an icon display object in place of the standard text
You can set the Button to toggle between text, backings or icons
SEE the ZIM Pizzazz series for a growing selection of backings, patterns and icons
https://zimjs.com/bits/view/pizzazz.html
https://zimjs.com/bits/view/icons.html
https://zimjs.com/patterns.html
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var button = new Button(200,60,"CLICK");
button.center();
button.on("click", function(){zog("clicking");});
// OR add custom label (needed to change label color for instance)
var label = new Label({
text:"POWER OPTION",
size:40,
backgroundColor:"violet",
fontOptions:"bold"
});
var button = new Button({
label:label,
width:390,
height:110,
backgroundColor:"purple",
rollBackgroundColor:"MediumOrchid",
borderWidth:8,
borderColor:"violet",
gradient:.3,
corner:0
});
button.center();
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
** supports VEE - parameters marked with ZIM VEE mean a zim Pick() object or Pick Literal can be passed
Pick Literal formats: [1,3,2] - random; {min:10, max:20} - range; series(1,2,3) - order, function(){return result;} - function
width - (default 200) the width of the button
height - (default 60) the height of the button
label - (default "CLICK") ZIM Label or plain text with default settings (white)
backgroundColor |ZIM VEE| - (default "orange") background color of button (any CSS color)
rollBackgroundColor |ZIM VEE| - (default "lightorange") rollover background color of button
color |ZIM VEE| - (default "white") label color of button (any CSS color) unless a custom Label is set
rollColor |ZIM VEE| - (default "white") rollover label color of button
borderColor - (default null) the color of the border
borderRollColor - (default borderColor) the rollover color of the border
borderWidth - (default null) thickness of the border
corner - (default 20) the round of the corner (set to 0 for no corner)
can also be an array of [topLeft, topRight, bottomRight, bottomLeft]
shadowColor - (default rgba(0,0,0,.3)) set to -1 for no shadow
shadowBlur - (default 14) how blurred the shadow is if the shadow is set
hitPadding - (default 0) adds extra hit area to the button (good for mobile)
Note that if the button alpha is 0 the button will still be active if hitPadding is not equal to 0
Set the hitPadding property to 0 in this case - thanks Frank Los for the notice
gradient - (default 0) 0 to 1 (try .3) adds a gradient to the button
gloss - (default 0) 0 to 1 (try .1) adds a gloss to the button
dashed - (default false) set to true to turn the border to dashed - if the borderColor or borderWidth is provided
backing - (default null) a Display object for the backing of the button (eg. Shape, Bitmap, Container, Sprite)
assumed to be center registration for easy positioning *** as with all backings
see ZIM Pizzazz module for a fun set of Button Shapes like Boomerangs, Ovals, Lightning Bolts, etc.
https://zimjs.com/bits/view/pizzazz.html
rollBacking - (default null) a Display object for the backing of the rolled-on button
rollPersist - (default false) set to true to keep rollover state when button is pressed even if rolling off
icon - (default null) set to display object to add icon at the center of the button and remove label
assumed to be center registration for easy positioning *** as with all icons
https://zimjs.com/bits/view/icons.html
rollIcon - (default null) set to display object to show icon on rollover
toggle - (default null) set to string to toggle with label - or set to true to activate toggle but keep label the same
the button will not toggle if there is a wait parameter set
see also toggle colors, backings and icons
toggleBackgroundColor - (default backgroundColor) background color to make button when toggled
rollToggleBackgroundColor - (default toggleBackgroundColor) background color for button when toggled and rolled over
toggleColor - (default label's color) color to make text when toggled
rollToggleColor - (default label's roll color) color for text when toggled and rolled over
toggleBacking - (default null) set to display object to set a different backing for toggled state
rollToggleBacking - (default null) set to display object to set a backing for the rolled toggle state
toggleIcon - (default null) set to display object to add icon at the center of the button and remove label in toggle state
rollToggleIcon - (default null) set to display object to show icon on rollover in toggle state
toggleEvent - (default mousedown for mobile and click for not mobile) what event causes the toggle
wait - (default null) - String word for button to show when button is pressed and a wait state is desired
LOADING: this can be used as a loading message - so change the button to "LOADING"
When the asset has loaded, use the clearWait() method to return to the normal button or toggled button state
CONFIRMING: this can also be used to confirm user action rather than a full new confirm panel
Set wait:"CONFIRM", set the waitBackgroundColor and rollWaitBackground parameters to red and the waitTime parameter to 4
In a button mousedown (must use mousedown - not click or tap if ACTIONEVENT is mousedown - the default),
check if the waiting property is true to test for confirmation
The waiting property will not be true for the first button press but will be true during the wait period
Perhaps set the waitModal parameter to true to clearWait() if the user clicks off the button
Use the clearWait() method to clear or cancel the wait status - for instance, if the pane the button is in is closed
waitTime - (default 5 seconds) seconds to show wait state before reverting to normal button (also see ZIM TIME constant)
waitBackgroundColor - (default red) background color to make button during wait time if wait is set
rollWaitBackgroundColor - (default rollBackgroundColor) background color for button when waiting and rolled over
waitColor - (default label's color) color to make text during wait time if wait is set
rollWaitColor - (default label's roll color) color for text when waiting and rolled over
waitModal - (default false) set to true to clearWait() if the user clicks off the button
waitEnabled - (default true) set to false to disable button while wait is in progress
waitBacking - (default null) set to display object to set a different backing for wait state
rollWaitBacking - (default null) set to display object to a different roll backing for wait state
waitIcon - (default null) set to display object to add icon at the center of the button and remove label in wait state
rollWaitIcon - (default null) set to display object to show icon on rollover in wait state
align - (default "center") horizontal align of the label
valign - (default "center") vertical align of the label
indent - (default 10) indent of label when align or valign is set
indentHorizontal - (default indent) horizontal indent of label when align or valign is set
indentVertical - (default indent) vertical indent of label when align or valign is set
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
setBacking(type, newBacking) - dynamically set any type of backing for button (if null removes backing for that type)
Backing types are: "backing", "rollBacking", "toggleBacking", "rollToggleBacking", "waitBacking", "rollWaitBacking"
note - all backing will have a pattern property if a pattern is set as a backing
setIcon(type, newIcon) - dynamically set any type of icon for button (if null removes icon for that type)
Icon types are: "icon", "rollIcon", "toggleIcon", "rollToggleIcon", "waitIcon", "rollWaitIcon"
toggle(state) - forces a toggle of label, backing and icon if set
state defaults to null so just toggles if left blank
pass in true to go to the toggled state and false to go to the original state
returns object for chaining
wait() - forces a wait state - with wait text, backings and icons if set
clearWait() - clears a wait state of the button - sets it back to normal
removeWait() - removes (and clears) a wait state of the button so it will not trigger again
hasProp(property as String) - returns true if property exists on object else returns false
clone(exact) - makes a copy with properties such as x, y, etc. also copied
exact - will ignore ZIM VEE values and clone the original values
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), cache(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
text - references the text property of the Label object of the button
label - gives access to the label
color - get or set non-rolled on label color (if no icon specified)
rollColor - get or set rolled on label color
backgroundColor - get or set non-rolled on backing color (if no backing specified)
rollBackgroundColor - get or set rolled on backing color
rollPersist - default is false - set to true to keep rollover state when button is pressed even if rolling off
borderColor - get or set non-rolled on border color
borderRollColor - get or set the border rolled color
hitPadding - extra padding for interactivity - see hitPadding parameter for extra notes
backing - references the backing of the button
use setBacking() to change as with all backings
note - all backings will have a pattern property if a pattern is set as a backing
rollBacking - references the rollBacking (if set)
icon - references the icon of the button (if set)
use setIcon() to change as with all icons
rollIcon - references the rollIcon (if set)
rolled - read-only true if button is being rolled over else false
toggled - read-only true if button is in toggled state, false if button is in original state
note: on mousedown toggle may not be switched over - except on mobile
so would recommend for consistency checking on click or tap or mouseup
toggleBacking - references the toggle backing (if set)
rollToggleBacking - references the toggle roll backing (if set)
toggleIcon - references the toggle icon (if set)
rollToggleIcon - references the toggle roll icon (if set)
waiting - read-only true if button is in the waiting state within wait time
note: must test this in a mousedown function not click or tap
waitBacking - references the wait backing (if set)
rollWaitBacking - references the wait roll backing (if set)
waitIcon - references the wait icon (if set)
rollWaitIcon - references the wait roll icon (if set)
focus - get or set the focus property of the Button used for tabOrder
enabled - default is true - set to false to disable
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
OPTIMIZED
This component is affected by the general OPTIMIZE setting (default is false)
if set to true, you will have to stage.update() after setting certain properties
for example seeing toggle take effect
EVENTS
dispatches a "waited" event if button is in wait state and the wait time has completed
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+55
zim.Button = function(width, height, label, backgroundColor, rollBackgroundColor, color, rollColor, borderColor, borderRollColor, borderWidth, corner, shadowColor, shadowBlur, hitPadding, gradient, gloss, dashed, backing, rollBacking, rollPersist, icon, rollIcon, toggle, toggleBackgroundColor, rollToggleBackgroundColor, toggleColor, rollToggleColor, toggleBacking, rollToggleBacking, toggleIcon, rollToggleIcon, toggleEvent, wait, waitTime, waitBackgroundColor, rollWaitBackgroundColor, waitColor, rollWaitColor, waitModal, waitEnabled, waitBacking, rollWaitBacking, waitIcon, rollWaitIcon, align, valign, indent, indentHorizontal, indentVertical, style, group, inherit) {
var sig = "width, height, label, backgroundColor, rollBackgroundColor, color, rollColor, borderColor, borderRollColor, borderWidth, corner, shadowColor, shadowBlur, hitPadding, gradient, gloss, dashed, backing, rollBacking, rollPersist, icon, rollIcon, toggle, toggleBackgroundColor, rollToggleBackgroundColor, toggleColor, rollToggleColor, toggleBacking, rollToggleBacking, toggleIcon, rollToggleIcon, toggleEvent, wait, waitTime, waitBackgroundColor, rollWaitBackgroundColor, waitColor, rollWaitColor, waitModal, waitEnabled, waitBacking, rollWaitBacking, waitIcon, rollWaitIcon, align, valign, indent, indentHorizontal, indentVertical, style, group, inherit";
var duo; if (duo = zob(zim.Button, arguments, sig, this)) return duo;
z_d("55");
this.group = group;
var DS = style===false?{}:zim.getStyle("Button", group, inherit);
if (zot(width)) width=DS.width!=null?DS.width:200;
if (zot(height)) height=DS.height!=null?DS.height:60;
this.zimContainer_constructor(width, height, null, null, false);
this.type = "Button";
if (zot(backgroundColor)) backgroundColor=DS.backgroundColor!=null?DS.backgroundColor:"#C60";
if (zot(rollBackgroundColor)) rollBackgroundColor=DS.rollBackgroundColor!=null?DS.rollBackgroundColor:"#F93";
var oColor = color;
var oRollColor = rollColor;
if (zot(color)) color=DS.color!=null?DS.color:"white";
if (zot(rollColor)) rollColor=DS.rollColor!=null?DS.rollColor:"white";
var oa = remember(backgroundColor, rollBackgroundColor, color, rollColor);
function remember() {return arguments;} // for cloning PICK
backgroundColor = zik(backgroundColor);
rollBackgroundColor = zik(rollBackgroundColor);
color = zik(color);
rollColor = zik(rollColor);
var originalBorderColor = borderColor;
var originalBorderWidth = borderWidth;
if (zot(borderColor)) borderColor = DS.borderColor!=null?DS.borderColor:null;
if (zot(borderWidth)) borderWidth = DS.borderWidth!=null?DS.borderWidth:null;
if (borderColor < 0 || borderWidth < 0) borderColor = borderWidth = null;
else if (borderColor!=null && borderWidth==null) borderWidth = 1;
if (zot(borderRollColor)) borderRollColor=DS.borderRollColor!=null?DS.borderRollColor:borderColor;
if (zot(corner)) corner=DS.corner!=null?DS.corner:20;
if (zot(shadowColor)) shadowColor=DS.shadowColor!=null?DS.shadowColor:"rgba(0,0,0,.3)";
if (zot(shadowBlur)) shadowBlur=DS.shadowBlur!=null?DS.shadowBlur:14;
if (zot(hitPadding)) hitPadding=DS.hitPadding!=null?DS.hitPadding:0;
if (zot(align)) align=DS.align!=null?DS.align:"center";
if (zot(valign)) valign=DS.valign!=null?DS.valign:"center";
if (zot(indent)) indent=DS.indent!=null?DS.indent:10;
if (zot(indentHorizontal)) indentHorizontal=DS.indentHorizontal!=null?DS.indentHorizontal:indent;
if (zot(indentVertical)) indentVertical=DS.indentVertical!=null?DS.indentVertical:indent;
if (zot(gradient)) gradient = DS.gradient!=null?DS.gradient:0;
if (zot(gloss)) gloss = DS.gloss!=null?DS.gloss:0;
if (zot(label)) {if (zot(icon)) {label = DS.label!=null?DS.label:"PRESS";} else {label = "";}}
var toggleOkay = (!zot(toggle) || !zot(toggleBacking) || !zot(rollToggleBacking) || !zot(toggleIcon) || !zot(rollToggleIcon)) && zot(wait) && zot(waitBacking) && zot(rollWaitBacking);
if (toggleOkay && zot(toggleEvent)) toggleEvent = zim.mobile()?"mousedown":"click";
// text, size, font, color, rollColor, shadowColor, shadowBlur, align, valign
if (typeof label === "string" || typeof label === "number") label = new zim.Label({
text:label, size:DS.size!=null?DS.size:36, font:DS.font!=null?DS.font:"arial", color:DS.color!=null&&oColor==null?DS.color:color, rollColor:DS.rollColor&&oRollColor==null!=null?DS.rollColor:rollColor, align:align, valign:valign, rollPersist:DS.rollPersist!=null?DS.rollPersist:false,
backing:"ignore", shadowColor:"ignore", shadowBlur:"ignore", padding:"ignore", backgroundColor:"ignore", shiftVertical:DS.shiftVertical!=null?DS.shiftVertical:0, shiftHorizontal:DS.shiftHorizontal!=null?DS.shiftHorizontal:0,
style:false, group:this.group
});
if (zot(rollPersist)) rollPersist = DS.rollPersist!=null?DS.rollPersist:false;
this.rollPersist = rollPersist;
if (zot(dashed)) dashed = DS.dashed!=null?DS.dashed:false;
if (!zot(toggle) && toggle.type=="Label") {if (zon) zogy("Button() - do not pass Label to toggle parameter - just pass a String");}
if (zot(toggleBackgroundColor)) toggleBackgroundColor=DS.toggleBackgroundColor!=null?DS.toggleBackgroundColor:backgroundColor;
if (zot(rollToggleBackgroundColor)) rollToggleBackgroundColor=DS.rollToggleBackgroundColor!=null?DS.rollToggleBackgroundColor:rollBackgroundColor;
if (zot(toggleColor)) toggleColor=DS.toggleColor!=null?DS.toggleColor:label.color;
if (zot(rollToggleColor)) rollToggleColor=DS.rollToggleColor!=null?DS.rollToggleColor:label.rollColor;
if (zot(waitBackgroundColor)) waitBackgroundColor=DS.waitBackgroundColor!=null?DS.waitBackgroundColor:backgroundColor;
if (zot(rollWaitBackgroundColor)) rollWaitBackgroundColor=DS.rollWaitBackgroundColor!=null?DS.rollWaitBackgroundColor:rollBackgroundColor;
if (zot(waitColor)) waitColor=DS.waitColor!=null?DS.waitColor:label.color;
if (zot(rollWaitColor)) rollWaitColor=DS.rollWaitColor!=null?DS.rollWaitColor:label.rollColor;
var that = this;
this.mouseChildren = false;
this.cursor = "pointer";
that.focus = false;
that.rolled = false;
var stage;
var timeType = getTIME(waitTime);
//~~~~~~~~~~~~~ BACKINGS
// also see manual setting of backings beneath getter setter methods
if (zot(backing)) backing = DS.backing!=null?DS.backing.clone():null;
if (zot(backing)) that.backing = new zim.Rectangle(width,height,backgroundColor,null,null,corner,dashed,null,false).centerReg(null, null, false);
else that.backing = backing; // if backing is null - we have no custom backing - this test is used later
that.rollBacking = zot(rollBacking)?(DS.rollBacking!=null?DS.rollBacking.clone():null):rollBacking;
that.waitBacking = zot(waitBacking)?(DS.waitBacking!=null?DS.waitBacking.clone():null):waitBacking;
that.rollWaitBacking = zot(rollWaitBacking)?(DS.rollWaitBacking!=null?DS.rollWaitBacking.clone():null):rollWaitBacking;
that.toggleBacking = zot(toggleBacking)?(DS.toggleBacking!=null?DS.toggleBacking.clone():null):toggleBacking;
that.rollToggleBacking = zot(rollToggleBacking)?(DS.rollToggleBacking!=null?DS.rollToggleBacking.clone():null):rollToggleBacking;
var backingTypes = ["backing", "rollBacking", "toggleBacking", "rollToggleBacking", "waitBacking", "rollWaitBacking"];
var t;
var b;
for (var i=0; i<backingTypes.length; i++) {
t = backingTypes[i];
b = that[t]; // access to object passed to parameter or null
if (b) {
if (b.type == "Pattern") {
b = setPattern(t, b);
} else if (shadowColor != -1 && shadowBlur > 0) {
b.shadow = new createjs.Shadow(shadowColor, 3, 3, shadowBlur);
}
// assumes center reg
b.x = width / 2;
b.y = height / 2;
}
}
that.addChild(that.backing);
if (borderWidth) {
that.border = new zim.Rectangle(width, height, "rgba(0,0,0,0)", borderColor, borderWidth, corner, dashed, null, false);
that.addChild(that.border);
}
function setPattern(type, pattern) {
that[type] = new zim.Container(width, height, null, null, false).centerReg(null, null, false);
if (shadowColor != -1 && shadowBlur > 0) {
var shadowRect = new zim.Rectangle(width-2, height-2, "#666", null, null, corner, null, null, false).center(that[type]);
shadowRect.shadow = new createjs.Shadow(shadowColor, 3, 3, shadowBlur);
}
var mask = that[type].mask = new zim.Rectangle(width, height, type.indexOf("roll")>=0?rollBackgroundColor:backgroundColor, null, null, corner, null, null, false).addTo(that[type]);
pattern.centerReg(mask);
pattern.setMask(mask.shape);
that[type].pattern = pattern;
return that[type];
}
//~~~~~~~~~~~~~ ICONS
that.icon = zot(icon)?(DS.icon!=null?DS.icon.clone():null):icon;
that.rollIcon = zot(rollIcon)?(DS.rollIcon!=null?DS.rollIcon.clone():null):rollIcon;
that.waitIcon = zot(waitIcon)?(DS.waitIcon!=null?DS.waitIcon.clone():null):waitIcon;
that.rollWaitIcon = zot(rollWaitIcon)?(DS.rollWaitIcon!=null?DS.rollWaitIcon.clone():null):rollWaitIcon;
that.toggleIcon = zot(toggleIcon)?(DS.toggleIcon!=null?DS.toggleIcon.clone():null):toggleIcon;
that.rollToggleIcon = zot(rollToggleIcon)?(DS.rollToggleIcon!=null?DS.rollToggleIcon.clone():null):rollToggleIcon;
var iconTypes = ["icon", "rollIcon", "toggleIcon", "rollToggleIcon", "waitIcon", "rollWaitIcon"];
for (var i=0; i<iconTypes.length; i++) {
var ty = iconTypes[i];
var ic = that[ty]; // access to object passed to parameter or null
if (ic) {
// assumes center reg
ic.x = width / 2;
ic.y = height / 2;
}
}
if (that.icon) that.addChild(that.icon);
//~~~~~~~~~~~~~ GRADIENT AND GLOSS
if (!Array.isArray(corner)) corner = [corner, corner, corner, corner];
if (gradient > 0) { // add an overlay
var gr = new createjs.Shape();
gr.graphics.lf(["rgba(255,255,255,"+gradient+")","rgba(0,0,0,"+gradient+")"], [0, 1], 0, 0, 0, height-borderWidth);
gr.graphics.rc(borderWidth/2, borderWidth/2, width-borderWidth, height-borderWidth, corner[0], corner[1], corner[2], corner[3]);
this.addChild(gr);
}
if (gloss > 0) { // add an overlay
var gl = new createjs.Shape();
gl.graphics.f("rgba(255,255,255,"+gloss+")");
gl.graphics.rc(borderWidth/2, borderWidth/2, width-borderWidth, (height-borderWidth)/2, corner[0], corner[1], 0, 0);
gl.graphics.f("rgba(0,0,0,"+gloss+")");
gl.graphics.rc(borderWidth/2, height/2, width-borderWidth, (height-borderWidth)/2, 0, 0, corner[2], corner[3]);
this.addChild(gl);
}
//~~~~~~~~~~~~~ HITAREA AND LABEL
var hitArea;
var rect;
if (hitPadding > 0) makeHitArea();
function makeHitArea() {
rect = new createjs.Shape();
rect.graphics.f("#000").r(-hitPadding,-hitPadding,width+hitPadding*2,height+hitPadding*2);
that.hitArea = hitArea = rect;
}
this.addChild(label);
label.center(this);
// label.y+=(typeof zdf!="undefined" && zdf.retina!=true)?1:0;
label.y+=1;
this.label = label;
zim.pos(label, (align=="left"||align=="right")?indentHorizontal:null, (valign=="top"||valign=="bottom")?indentVertical:null, align=="right", valign=="bottom");
//~~~~~~~~~~~~~ TOGGLE STATE
this.toggled = false;
if (toggleOkay) {
var originalText = label.text;
var originalColor = label.color;
var originalRollColor = label.rollColor;
this.on(toggleEvent, function() {
that.toggled = !that.toggled;
setToggled();
});
}
function setToggled() {
if (that.toggled) {
if (!zot(toggle)) that.label.text = toggle===true?originalText:toggle;
if (!zot(toggleColor)) that.label.color = toggleColor;
if (!zot(rollToggleColor)) that.label.rollColor = rollToggleColor;
// for toggle - may start in rollover or could be manually called
if (that.rolled) {
if (that.rollToggleBacking) changeObject("rollToggleBacking", that.rollToggleBacking);
else if (that.toggleBacking) changeObject("toggleBacking", that.toggleBacking);
if (that.rollToggleIcon) changeObject("rollToggleIcon", that.rollToggleIcon);
else if (that.toggleIcon) changeObject("toggleIcon", that.toggleIcon);
if (zot(backing) && zot(that.rollToggleBacking)) that.backing.color = rollToggleBackgroundColor;
} else {
if (that.toggleBacking) changeObject("toggleBacking", that.toggleBacking);
if (that.toggleIcon) changeObject("toggleIcon", that.toggleIcon);
if (zot(backing)) that.backing.color = toggleBackgroundColor;
}
} else {
that.label.color = originalColor;
that.label.rollColor = originalRollColor;
that.label.text = originalText;
setOriginalObjects();
}
if (that.stage) that.stage.update();
}
function setOriginalObjects() {
if (that.rolled) {
if (zot(backing) && !that.rollBacking) that.backing.color = rollBackgroundColor;
if (that.rollBacking) changeObject("rollBacking", that.rollBacking);
else if (that.backing) changeObject("backing", that.backing);
if (that.rollIcon) changeObject("rollIcon", that.rollIcon);
else if (that.icon) changeObject("icon", that.icon);
else changeObject("icon", null);
} else {
if (zot(backing)) that.backing.color = backgroundColor;
if (that.backing) changeObject("backing", that.backing);
if (that.icon) changeObject("icon", that.icon);
else changeObject("icon", null);
}
}
this.toggle = function(state) {
if (!toggleOkay) {
if (zon) zogy("Button() - can't toggle with wait parameters provided");
return that;
}
if (zot(state)) {
that.toggled = !that.toggled;
} else {
that.toggled = state;
}
setToggled();
return that;
};
//~~~~~~~~~~~~~ WAIT STATE
var pressCheck = false;
that.waiting = false;
var willBeWaiting = false;
var waitTimeout;
var waitStartText;
// var waitStartBackgroundColor;
var waitStartTextBackgroundColor = that.label.color;
var waitStartRollTextBackgroundColor = that.label.rollColor;
var waitStartEnabled;
var waitModalEvent;
var waitEvent = this.on("mousedown", function() {
pressCheck=true;
doWait();
});
function doWait() {
if ((!zot(wait) || !zot(waitBacking) || !zot(rollWaitBacking)) && !that.waiting) {
willBeWaiting = true;
if (zot(waitEnabled)) waitEnabled = true;
if (waitModal) waitModalEvent = that.stage.on("stagemousedown", function(e) {
if (!that.hitTestPoint(e.stageX/zim.scaX, e.stageY/zim.scaY)) that.clearWait();
}, null, true); // run only once
// wait before setting the waiting property so first click is not a waiting
setTimeout(function(){that.waiting = true;}, 50);
// set button to waiting state
waitStartText = label.text;
if (!zot(waitColor)) that.label.color = waitColor;
if (!zot(rollWaitColor)) that.label.rollColor = rollWaitColor;
waitStartEnabled = that.enabled;
if (!waitEnabled && that.enabled) that.enabled = false;
if (!zot(wait)) that.label.text = wait;
if (that.rolled) {
if (zot(backing) && !that.rollWaitBacking) that.backing.color = rollWaitBackgroundColor;
if (that.rollWaitBacking) changeObject("rollWaitBacking", that.rollWaitBacking);
else if (that.waitBacking) changeObject("waitBacking", that.waitBacking);
if (that.rollWaitIcon) changeObject("rollWaitIcon", that.rollWaitIcon);
else if (that.waitIcon) changeObject("waitIcon", that.waitIcon);
} else {
if (zot(backing) && !that.waitBacking) that.backing.color = waitBackgroundColor;
if (that.waitBacking) changeObject("waitBacking", that.waitBacking);
if (that.waitIcon) changeObject("waitIcon", that.waitIcon);
}
if (zot(waitTime)) waitTime = timeType=="s"?5:5000; // 5 seconds
if (waitTimeout) waitTimeout.clear();
waitTimeout = zim.timeout(waitTime, function() {
// set button to proper text, icon, backing, colors, etc.
if (!that.enabled) that.enabled = waitStartEnabled;
that.clearWait();
that.dispatchEvent("waited");
});
if (that.stage) that.stage.update();
}
}
this.wait = function() {
doWait();
};
this.clearWait = function() {
if (!waitTimeout) return that;
if (waitModalEvent) that.stage.off("stagemousedown", waitModalEvent);
waitTimeout.clear();
that.label.text = waitStartText;
setOriginalObjects();
that.label.color = waitStartTextBackgroundColor;
that.label.rollColor = waitStartRollTextBackgroundColor;
setTimeout(function(){that.waiting = false;}, 55); // give time for first click to see not waiting yet
willBeWaiting = false;
if (that.stage) that.stage.update();
return that;
};
this.removeWait = function() {
that.clearWait();
wait = null;
that.waitBacking = null;
that.rollWaitBacking = null;
that.off("mousedown", waitEvent);
return that;
};
//~~~~~~~~~~~~~ INTERACTION
this.on("pressup", function(){
pressCheck=false;
if (that.rollPersist && !reallyOn) removeRoll();
});
// visually swap button backing or icon
// on clicks if wait or toggle and on mouseover and mouseout
// note - icon will be removed if newObject is null
// BUT - backing will be ignored if newObject is null
// so these act slightly differently!
function changeObject(type, newObject) {
if (type.indexOf("con")>=0) { // icon
for (var i=0; i<iconTypes.length; i++) {
var ty = iconTypes[i];
var ic = that[ty];
that.removeChild(ic);
}
if (that[type]) that.addChildAt(that[type], 1);
} else {
if (!that[type]) return;
for (var i=0; i<backingTypes.length; i++) {
var t = backingTypes[i];
var b = that[t];
that.removeChild(b);
}
if (that[type]) that.addChildAt(that[type], 0);
}
}
var reallyOn = false;
this.on("mouseover", function (e) {
if (that.stage && that.stage.frame.leftMouseDown && !onCheck) return;
buttonOn(e);
});
function buttonOn(e) {
that.rolled = true;
reallyOn = true;
// specific to each setting
// so can have a rollover backing even without a backing
// also... if no rollWaitBacking or rollToggleBacking
// then if there is the backing for these, still set the backing
// all backings get removed and current backing object is placed
// normal buttons (with no backings) get borders on rectangle
// backings get overlayed border with borderColor and borderRollColor
// will have to track each state normal, toggle and wait
// do not set colors on any custom backings (aside from border colors)
if (willBeWaiting) {
if (zot(backing) && zot(that.rollWaitBacking)) that.backing.color = zot(rollWaitBackgroundColor)?rollBackgroundColor:rollWaitBackgroundColor;
changeObject("rollWaitBacking", that.rollWaitBacking);
if (that.rollWaitIcon) changeObject("rollWaitIcon", that.rollWaitIcon);
} else if (toggleOkay && that.toggled) {
if (zot(backing) && zot(that.rollToggleBacking)) that.backing.color = rollToggleBackgroundColor;
changeObject("rollToggleBacking", that.rollToggleBacking);
if (that.rollToggleIcon) changeObject("rollToggleIcon", that.rollToggleIcon);
} else {
if (zot(backing)) that.backing.color = rollBackgroundColor;
else if (!zot(backing.mask)) that.backing.mask.color = rollBackgroundColor;
changeObject("rollBacking", that.rollBacking);
if (that.rollIcon) changeObject("rollIcon", that.rollIcon);
}
if (that.border) that.border.borderColor = borderRollColor;
if (that.label.showRollColor) that.label.showRollColor();
if (that.stage) that.stage.update();
}
// for mobile with no mouseover
// and to stop rollover if pressed off button and rollover ZIM Cat 04
var onCheck = false;
var touchCheck = false;
this.on("mousedown", function (e) {
onCheck = true;
if (that.rolled) return;
touchCheck = true;
buttonOn(e);
});
this.on("pressup", function (e) {
onCheck = false;
if (touchCheck) { // touch screen
touchCheck = false;
buttonOff(e);
}
});
this.on("pressmove", function (e) {
var frame = that.stage ? that.stage.frame : zdf;
var hitting = that.hitTestPoint(frame.mouseX, frame.mouseY);
if (onCheck && !hitting) {
buttonOff(e);
onCheck = false;
} else if (!onCheck && hitting) {
buttonOn(e);
onCheck = true;
}
});
this.on("mouseout", buttonOff); // thanks Maxime Riehl
function buttonOff(e) {
reallyOn = false;
that.off("mouseout", buttonOff); // not working and not needed? 2018
if (that.rollPersist) {
if (!pressCheck) removeRoll();
} else {
removeRoll();
}
}
function removeRoll() {
that.rolled = false;
if (willBeWaiting || that.waiting) {
if (zot(backing) && zot(that.waitBacking)) that.backing.color = zot(waitBackgroundColor)?backgroundColor:waitBackgroundColor;
if (that.waitBacking) changeObject("waitBacking", that.waitBacking);
else changeObject("backing", that.backing);
if (that.waitIcon) changeObject("waitIcon", that.waitIcon);
else if (that.icon) changeObject("icon", that.icon);
else changeObject("icon", null);
} else if (that.toggled && toggleOkay) {
if (zot(backing) && zot(that.toggleBacking)) that.backing.color = toggleBackgroundColor;
if (that.toggleBacking) changeObject("toggleBacking", that.toggleBacking);
else changeObject("backing", that.backing);
if (that.toggleIcon) changeObject("toggleIcon", that.toggleIcon);
else if (that.icon) changeObject("icon", that.icon);
else changeObject("icon", null);
} else {
if (zot(backing)) that.backing.color = backgroundColor;
else if (!zot(backing.mask)) that.backing.mask.color = backgroundColor;
changeObject("backing", that.backing);
if (that.icon) changeObject("icon", that.icon);
else changeObject("icon", null);
}
if (that.border) that.border.borderColor = borderColor;
if (that.label.showRollColor) that.label.showRollColor(false);
if (that.stage) that.stage.update();
}
Object.defineProperty(that, 'text', {
get: function() {
var t = (label.text == " ") ? "" : label.text;
return t;
},
set: function(value) {
label.text = value;
if (originalText) originalText = value;
label.center(this);
label.y+=1;
zim.pos(label, (align=="left"||align=="right")?indentHorizontal:null, (valign=="top"||valign=="bottom")?indentVertical:null, align=="right", valign=="bottom");
}
});
Object.defineProperty(that, 'color', {
get: function() {
return color;
},
set: function(value) {
color = value;
if (originalColor) originalColor = color;
if (that.label && !zot(that.label.color)) {
that.label.color = color;
}
if ((!zim.OPTIMIZE&&(zns||!OPTIMIZE)) && that.stage) that.stage.update();
}
});
Object.defineProperty(that, 'rollColor', {
get: function() {
return rollColor;
},
set: function(value) {
rollColor = value;
if (originalRollColor) originalRollColor = rollColor;
if (that.label) {
that.label.rollColor = rollColor;
}
}
});
Object.defineProperty(that, 'backgroundColor', {
get: function() {
return backgroundColor;
},
set: function(value) {
backgroundColor = value;
if (that.backing.color) {
that.backing.color = backgroundColor;
} else if (that.backing.mask) {
that.backing.mask.color = backgroundColor;
}
if ((!zim.OPTIMIZE&&(zns||!OPTIMIZE)) && that.stage) that.stage.update();
}
});
Object.defineProperty(that, 'rollBackgroundColor', {
get: function() {
return rollBackgroundColor;
},
set: function(value) {
rollBackgroundColor = value;
if (that.rollBacking && that.rollBacking.color) {
that.rollBacking.color = rollBackgroundColor;
} else if (that.rollBacking && that.rollBacking.mask) {
that.rollBacking.mask.color = rollBackgroundColor;
}
}
});
Object.defineProperty(that, 'borderColor', {
get: function() {
return borderColor;
},
set: function(value) {
borderColor = value;
if (!that.rolled) {
if (that.backing && that.backing.borderColor) that.backing.borderColor = value;
if (that.border) that.border.borderColor = value;
}
}
});
Object.defineProperty(that, 'borderRollColor', {
get: function() {
return borderRollColor;
},
set: function(value) {
borderRollColor = value;
if (that.rolled) {
if (that.backing && that.backing.borderColor) that.backing.borderColor = value;
if (that.border) that.border.borderColor = value;
}
}
});
Object.defineProperty(that, 'hitPadding', {
get: function() {
return hitPadding;
},
set: function(value) {
hitPadding = value;
if (hitPadding == 0) {
if (hitArea) {
this.hitArea = null;
}
} else {
makeHitArea();
}
}
});
this._enabled = true;
this.startMouseChildren = this.mouseChildren;
Object.defineProperty(that, 'enabled', {
get: function() {
return that._enabled;
},
set: function(value) {
if (that._enabled) that.startMouseChildren = that.mouseChildren;
if (value) {
zenable(that, value);
that.mouseChildren = that.startMouseChildren;
} else {
removeRoll();
zenable(that, value);
}
label.color = label.color;
if ((!zim.OPTIMIZE&&(zns||!OPTIMIZE)) && that.stage) that.stage.update();
}
});
// setBacking or leave backing parameter blank to remove this type of backing
this.setBacking = function(type, newBacking) {
setObject(type, newBacking);
};
// setIcon or leave icon parameter blank to remove this type of icon
this.setIcon = function(type, newIcon) {
setObject(type, newIcon);
};
function setObject(type, newObject) {
if (zot(type)) return that;
if (that.contains(that[type])) {
that.removeChild(that[type]);
if (newObject) that.addChildAt(newObject, type.indexOf("con")>=0?that.numChildren-1:0);
if (that.stage) that.stage.update();
}
if (newObject) {
if (zot(backing) && type == "backing") backing = newObject;
if (newObject.type == "Pattern") newObject = setPattern(type, newObject);
that[type] = newObject;
that[type].x = width/2;
that[type].y = height/2;
} else {
that[type] = null;
}
return that;
}
if (style!==false) zim.styleTransforms(this, DS);
this.clone = function(exact) {
var but = new zim.Button(
width, height, label.clone(),
(exact||!zim.isPick(oa[0]))?backgroundColor :oa[0],
(exact||!zim.isPick(oa[1]))?rollBackgroundColor :oa[1],
(exact||!zim.isPick(oa[2]))?color :oa[2],
(exact||!zim.isPick(oa[3]))?rollColor :oa[3],
originalBorderColor, borderRollColor, originalBorderWidth, corner, shadowColor, shadowBlur, hitPadding, gradient, gloss, dashed,
!zot(backing)?that.backing.clone():null,
!zot(rollBacking)?that.rollBacking.clone():null,
rollPersist,
!zot(icon)?icon.clone():null, !zot(rollIcon)?rollIcon.clone():null,
toggle, toggleBackgroundColor, rollToggleBackgroundColor, toggleColor, rollToggleColor,
!zot(toggleBacking)?toggleBacking.clone():null,
!zot(rollToggleBacking)?rollToggleBacking.clone():null,
!zot(toggleIcon)?toggleIcon.clone():null,
!zot(rollToggleIcon)?rollToggleIcon.clone():null,
toggleEvent,
wait, waitTime, waitBackgroundColor, rollWaitBackgroundColor, waitColor, rollWaitColor, waitModal, waitEnabled,
!zot(waitBacking)?waitBacking.clone():null,
!zot(rollWaitBacking)?rollWaitBacking.clone():null,
!zot(waitIcon)?waitIcon.clone():null,
!zot(rollWaitIcon)?rollWaitIcon.clone():null,
align, valign, indent, indentHorizontal, indentVertical,
style,
this.group,
inherit // added in ZIM Cat 03 - not sure if it was missing on purpose
);
return that.cloneProps(but);
};
this.doDispose = function(a,b,disposing) {
if (that.icon) that.icon.dispose();
if (that.rollIcon) that.rollIcon.dispose();
if (that.waitIcon) that.waitIcon.dispose();
if (that.rollWaitIcon) that.rollWaitIcon.dispose();
if (that.toggleIcon) that.toggleIcon.dispose();
if (that.rollToggleIcon) that.rollToggleIcon.dispose();
that.icon = that.rollIcon = that.waitIcon = that.rollWaitIcon = that.toggleIcon = that.rollToggleIcon = null;
if (!disposing) this.zimContainer_dispose(true);
return true;
}
};
zim.extend(zim.Button, zim.Container, ["clone", "dispose"], "zimContainer", false);
zim.Button.prototype.dispose = function(disposing) {return this.doDispose(null,null,disposing);};
//-55
/*--
zim.CheckBox = function(size, label, startChecked, color, backgroundColor, borderColor, borderWidth, corner, margin, indicatorType, indicatorColor, tap, style, group, inherit)
CheckBox
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
A checkbox that when pressed toggles the check and a checked property.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var checkBox = new CheckBox(50, "TEST");
checkBox.center();
checkBox.on("change", function() {
zog(checkBox.checked); // will be true then false, etc.
});
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
size - (default 60) size in pixels (always square)
label - (default null) ZIM Label object - or String to make a default label (black)
startChecked - (default false) an initial parameter to set checked if true
color - (default "#111") the text color of the label
backgroundColor - (default "rgba(255,255,255,.8)") the background color of the box
borderColor - (default "#111") the color of the border
borderWidth - (default size/10) thickness of the border
corner - (default 0) the round of the corner
can also be an array of [topLeft, topRight, bottomRight, bottomLeft]
margin - (default 10) is on outside of box so clicking or pressing is easier
indicatorType - (default check) could be square (box) or x
indicatorColor - (default borderColor or black if no border) the color of the indicator
tap - (default false) set to true to tap to activate CheckBox rather than mousedown or click
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
setChecked(Boolean) - defaults to true to set button checked (or use checked property)
hasProp(property as String) - returns true if property exists on object else returns false
clone() - makes a copy with properties such as x, y, etc. also copied
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), cache(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
checked - gets or sets the check of the box
label - gives access to the label
text - the text of the label
box - the Rectangle of the checkBox
box2 - the border Rectangle of the checkBox
indicator - gives access to the check mark ie. indicator.sca(.8);
indicatorColor - get or set the color of the indicator
enabled - default is true - set to false to disable
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
OPTIMIZED
This component is affected by the general OPTIMIZE setting (default is false)
if set to true, you will have to stage.update() after setting certain properties
ACTIONEVENT
This component is affected by the general ACTIONEVENT setting
The default is "mousedown" - if set to something else the component will act on click (press)
EVENTS
dispatches a "change" event when pressed on but not when the checked property is set
ALSO: see the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+56
zim.CheckBox = function(size, label, startChecked, color, backgroundColor, borderColor, borderWidth, corner, margin, indicatorType, indicatorColor, tap, style, group, inherit) {
var sig = "size, label, startChecked, color, backgroundColor, borderColor, borderWidth, corner, margin, indicatorType, indicatorColor, tap, style, group, inherit";
var duo; if (duo = zob(zim.CheckBox, arguments, sig, this)) return duo;
z_d("56");
this.zimContainer_constructor(null,null,null,null,false);
this.type = "CheckBox";
this.group = group;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
if (zot(size)) size = DS.size!=null?DS.size:60;
if (zot(label)) label = DS.label!=null?DS.label:null;
if (zot(startChecked)) startChecked = DS.startChecked!=null?DS.startChecked:false;
var myChecked = startChecked;
if (zot(color)) color = DS.color!=null?DS.color:"#111";
if (zot(backgroundColor)) backgroundColor = DS.backgroundColor!=null?DS.backgroundColor:"rgba(255,255,255,.8)";
if (zot(borderColor)) borderColor = DS.borderColor!=null?DS.borderColor:"#111";
if (zot(borderWidth)) borderWidth = DS.borderWidth!=null?DS.borderWidth:size/10;
if (borderColor < 0 || borderWidth < 0) borderColor = borderWidth = null;
else if (borderColor!=null && borderWidth==null) borderWidth = size/10;
if (zot(corner)) corner=DS.corner!=null?DS.corner:0;
if (typeof label === "string" || typeof label === "number") label = new zim.Label({
text:label, size:size*5/6, color:color, valign:"center",
backing:"ignore", shadowColor:"ignore", shadowBlur:"ignore", padding:"ignore", backgroundColor:"ignore",
style:style, group:this.group
});
if (zot(margin)) margin = DS.margin!=null?DS.margin:size/5;
if (indicatorType != "box" && indicatorType != "square" && indicatorType != "x") indicatorType = DS.indicatorType!=null?DS.indicatorType:"check";
if (zot(indicatorColor)) indicatorColor = DS.indicatorColor!=null?DS.indicatorColor:borderWidth>0?borderColor:"black";
this.setBounds(-margin, -margin, size+margin*2, size+margin*2);
if (zot(tap)) tap = DS.tap!=null?DS.tap:false;
var that = this;
this.cursor = "pointer";
var box = this.box = new zim.Rectangle(size, size, backgroundColor, null, null, corner);
var box2 = this.box2 = new zim.Rectangle(size*5/7, size*5/7, "rgba(0,0,0,0)", borderColor, borderWidth, corner);
box2.x = size/7; box2.y = size/7;
this.addChild(box, box2);
var fullWidth = size;
if (label) {
label.center(that);
label.x = that.getBounds().width;
this.label = label;
this.setBounds(-margin, -margin, size+margin*3+label.getBounds().width, Math.max(size+margin*2, label.getBounds().height));
fullWidth = label.x + label.width;
}
var backing = new zim.Shape({style:false});
var g = backing.graphics;
g.f("rgba(0,0,0,.01)").r(
this.getBounds().x,
this.getBounds().y,
fullWidth+(margin*2),
this.getBounds().height
);
this.hitArea = backing;
// hitArea will stop rollovers on labels but oh well
var check = new zim.Shape({style:false});
var g2 = check.graphics;
if (indicatorType == "check") {
g2.f(indicatorColor).p("AnQAdICBiaIEEDZIF8nfICfB4In/KPg"); // width about 90 reg in middle
} else if (indicatorType == "box" || indicatorType == "square") {
g2.f(indicatorColor).dr(-35,-35,70,70);
} else { // x
g2.f(indicatorColor).p("AmJEVIEUkTIkXkWIB4h5IEWEYIETkTIB4B3IkTESIEQERIh4B4IkRkRIkSEVg"); // width about 90 reg in middle
}
var cW = 95;
check.setBounds(-cW/2, -cW/2, cW, cW);
var scale = size/(cW+66);
check.scaleX = check.scaleY = scale;
check.alpha = .9;
check.x = size/2;
check.y = size/2;
if (myChecked) this.addChild(check);
if (tap) {
this.tap(toggleCheck);
} else {
this.on((!zns?ACTIONEVENT=="mousedown":zim.ACTIONEVENT=="mousedown")?"mousedown":"click", toggleCheck);
}
Object.defineProperty(that, 'checked', {
get: function() {
return myChecked;
},
set: function(value) {
that.setChecked(value);
}
});
this.toggle = function(type) {
if (zot(type)) type = !myChecked;
that.setChecked(type);
};
Object.defineProperty(that, 'toggled', {
get: function() {
return myChecked;
},
set: function(value) {
that.setChecked(value);
}
});
Object.defineProperty(that, 'text', {
get: function() {
if (label) return label.text;
return null;
},
set: function(value) {
if (label) {
label.text = value;
if ((!zim.OPTIMIZE&&(zns||!OPTIMIZE)) && that.stage) that.stage.update();
}
}
});
Object.defineProperty(check, 'indicatorColor', {
get: function() {
return indicatorColor;
},
set: function(value) {
if (myChecked) {that.removeChild(check);}
check = new createjs.Shape();
g2 = check.graphics;
indicatorColor = value;
g2.f(indicatorColor).p("AnQAdICBiaIEEDZIF8nfICfB4In/KPg");
check.scaleX = check.scaleY = scale;
check.alpha = .9;
check.x = size/2;
check.y = size/2;
if (myChecked) that.addChild(check);
if ((!zim.OPTIMIZE&&(zns||!OPTIMIZE)) && that.stage) that.stage.update();
}
});
Object.defineProperty(that, 'indicator', {
get: function() {
return check;
},
set: function(value) {
zog("ZIM CheckBox - check is read only");
}
});
this._enabled = true;
Object.defineProperty(that, 'enabled', {
get: function() {
return that._enabled;
},
set: function(value) {
zenable(that, value);
}
});
function toggleCheck(e) {
myChecked = !myChecked;
that.setChecked(myChecked);
that.dispatchEvent("change");
}
this.setChecked = function(value) {
if (zot(value)) value = true;
myChecked = value;
if (myChecked) {
that.addChild(check);
} else {
that.removeChild(check);
}
if ((!zim.OPTIMIZE&&(zns||!OPTIMIZE)) && that.stage) that.stage.update();
return that;
};
if (style!==false) zim.styleTransforms(this, DS);
this.clone = function() {
return that.cloneProps(new zim.CheckBox(size, label?label.clone():"", startChecked, color, backgroundColor, borderColor, borderWidth, corner, margin, indicatorType, indicatorColor, tap, style, this.group, inherit));
};
};
zim.extend(zim.CheckBox, zim.Container, "clone", "zimContainer", false);
//-56
/*--
zim.RadioButtons = function(size, buttons, vertical, color, backgroundColor, spacing, margin, always, indicatorColor, style, group, inherit)
RadioButtons
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
A radio button set that lets you pick from choices.
Radio buttons can display radio buttons vertically (default) or horizontally.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var radioButtons = new RadioButtons(50, ["ONE", "TWO", "THREE"]);
radioButtons.center();
radioButtons.on("change", function() {
zog(radioButtons.text); // will be ONE, TWO or THREE
zog(radioButtons.selectedIndex); // will be 0, 1, or 2
});
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
size - (default 60) in pixels
buttons - an array of button data objects as follows:
[{label:ZIM Label or text, id:optional id, selected:optional Boolean}, {etc...}]
or just a list of labels for default labels ["hi", "bye", "what!"]
vertical - (default true) displays radio buttons vertically - set to false to display horizontally
color - (default "#111") the text color of the label
backgroundColor - (default "rgba(255,255,255,.8)") the background color of the circle
borderColor - (default "#111") the color of the border
borderWidth - (default size/9) thickness of the border
spacing - (size*.2 for vertical and size for horizontal) the space between radio button objects
margin - (size/5) the space around the radio button itself
always - (default false) if set true, cannot click on selection to unselect it
indicatorColor - (default borderColor or black) the color of the indicator
selectedIndex - (default 0) - set the selectedIndex at start
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
setSelected(num) - sets the selected index (or use selectedIndex) -1 is default (none)
hasProp(property as String) - returns true if property exists on object else returns false
clone() - makes a copy with properties such as x, y, etc. also copied
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), cache(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
selected - gets the selected object - selected.label, selected.id, etc.
selectedIndex - gets or sets the selected index of the buttons
label - current selected label object
text - current selected label text
id - current selected id
buttons - an array of button Container objects holding the shape and label (note - different than buttons parameter)
labels - an array of the ZIM Label objects. labels[0].text = "YUM"; labels[2].y -= 10;
indicators - an array of the zim Shape dot objects. indicators[0].color = "yellow";
enabled - default is true - set to false to disable
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
OPTIMIZED
This component is affected by the general OPTIMIZE setting (default is false)
if set to true, you will have to stage.update() after setting certain properties
and stage.update() in change event to see component change its graphics
ACTIONEVENT
This component is affected by the general ACTIONEVENT setting
The default is "mousedown" - if set to something else the component will act on click (press)
EVENTS
dispatches a "change" event when pressed but not when selectedIndex is set
then ask for the properties above for info
ALSO: see the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+57
zim.RadioButtons = function(size, buttons, vertical, color, backgroundColor, borderColor, borderWidth, spacing, margin, always, indicatorColor, selectedIndex, style, group, inherit) {
var sig = "size, buttons, vertical, color, backgroundColor, borderColor, borderWidth, spacing, margin, always, indicatorColor, selectedIndex, style, group, inherit";
var duo; if (duo = zob(zim.RadioButtons, arguments, sig, this)) return duo;
z_d("57");
this.zimContainer_constructor(null,null,null,null,false);
this.type = "RadioButtons";
this.group = group;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
if (zot(size)) size = DS.size!=null?DS.size:60;
size = Math.max(5, size);
if (zot(buttons)) buttons = DS.buttons!=null?DS.buttons:["A", "B", "C"];
if (zot(vertical)) vertical = DS.vertical!=null?DS.vertical:true;
if (zot(color)) color = DS.color!=null?DS.color:"#111";
if (zot(backgroundColor)) backgroundColor = DS.backgroundColor!=null?DS.backgroundColor:"rgba(255,255,255,.8)";
if (zot(borderColor)) borderColor = DS.borderColor!=null?DS.borderColor:"#111";
if (zot(borderWidth)) borderWidth = DS.borderWidth!=null?DS.borderWidth:size/9;
if (borderColor < 0 || borderWidth < 0) borderColor = borderWidth = null;
else if (borderColor!=null && borderWidth==null) borderWidth = size/10;
if (zot(spacing)) spacing = (vertical) ? DS.spacing!=null?DS.spacing:size*.2 : DS.spacing!=null?DS.spacing:size;
if (zot(margin)) margin = DS.margin!=null?DS.margin:size/5;
if (zot(always)) always = DS.always!=null?DS.always:false;
if (zot(indicatorColor)) indicatorColor = DS.indicatorColor!=null?DS.indicatorColor:borderWidth>0?borderColor:"black";
var that = this;
this.cursor = "pointer";
this.labels = [];
this.indicators = [];
var currentObject; // reference to the current data object
if (typeof buttons == "string") {
// convert to buttons object literal (for cloning)
var bString = buttons;
buttons = [];
for (var i=0; i<bString.length; i++) {
buttons.push({label:bString[i]});
}
}
var buttonContainer = new zim.Container({style:false});
this.addChild(buttonContainer);
function pressBut(e) {
var index = buttonContainer.getChildIndex(e.target);
if (always) {if (that.selectedIndex == index) return;}
that.setSelected(index);
that.dispatchEvent("change");
}
// loop through data and call makeButton() each time
makeButtons();
var currentK;
for (var k=0; k<buttonContainer.numChildren; k++) {
currentK = buttonContainer.getChildAt(k);
currentK.on((!zns?ACTIONEVENT=="mousedown":zim.ACTIONEVENT=="mousedown")?"mousedown":"click", pressBut);
}
var lastBut;
function makeButtons() {
// test for duplicate selected true properties (leave last selected)
var data; var selectedCheck = false;
for (var i=buttons.length-1; i>=0; i--) {
data = buttons[i];
if (data.selected && data.selected === true) {
if (!selectedCheck) {
selectedCheck = true; // first item marked selected
that.id = data.id;
} else {
data.selected = "false"; // turn off selected
}
}
}
buttonContainer.removeAllChildren();
that.buttons = [];
var but; var currentLocation = 0;
for (var i=0; i<buttons.length; i++) {
data = buttons[i];
if (typeof data === "string" || typeof data === "number") {
var d = {selected:false, label:new zim.Label({
text:data, size:size*5/6, color:DS.color!=null?DS.color:color, valign:"center",
backing:"ignore", shadowColor:"ignore", shadowBlur:"ignore", padding:"ignore", backgroundColor:"ignore",
style:style, group:that.group
})};
data = d;
}
if (data.label && typeof data.label === "string" || typeof data.label === "number") {
data.label = new zim.Label({text:data.label, size:DS.size!=null?DS.size:size*5/6, color:DS.color!=null?DS.color:color, valign:"center", style:style});
}
that.labels.push(data.label);
data.index = i;
buttons[i] = data; // for cloning
but = makeButton(data.selected, data.label);
but.type = "RadioButton"; // singular
but.obj = data;
if (data.selected) currentObject = but.obj;
buttonContainer.addChild(but);
if (vertical) {
but.y = currentLocation;
currentLocation += but.getBounds().height + spacing;
} else {
but.x = currentLocation;
currentLocation += but.getBounds().width + spacing;
}
}
}
// making a single button - similar to CheckBox class
function makeButton(mySelected, label) {
var but = new zim.Container({style:false});
that.buttons.push(but);
but.mouseChildren = false;
but.setBounds(-margin, -margin, size+margin*2, size+margin*2);
var box = new zim.Shape({style:false});
var g = box.graphics;
g.f(backgroundColor).dc(size/2,size/2,size/1.85);
g.s(borderColor).ss(borderWidth).dc(size/2, size/2, size/2-size/2/5);
but.addChild(box);
var check = but.check = new zim.Circle(size/5.2, indicatorColor, null, null, null, null, null, null, false);
that.indicators.push(check);
check.mouseEnabled = false;
check.alpha = .95;
check.regX = check.regY = -size/2;
var fullWidth = size;
if (label) {
but.addChild(label);
label.x = but.getBounds().width;
label.y = size/2;
but.setBounds(-margin, -margin, size+margin*2+label.getBounds().width, Math.max(size+margin*2, label.getBounds().height));
fullWidth = label.x + label.width;
but.text = label.text;
}
if (mySelected) {
but.addChild(check);
that.label = label;
if (that.label) that.text = label.text;
}
var backing = new zim.Shape({style:false});
g = backing.graphics;
g.f("rgba(0,0,0,.01)").r(
but.getBounds().x,
but.getBounds().y,
fullWidth+(margin*2),
but.getBounds().height
);
but.hitArea = backing;
// hitArea will stop rollovers on labels but oh well
return(but);
}
if (!this.getBounds()) this.setBounds(0,0,size,size);
this.setBounds(-margin,-margin,this.getBounds().width+margin*2,this.getBounds().height);
// the main function that sets a button selected (after the initial makeButton)
// this gets called by the setter methods below and the click event up top
this.setSelected = function(value) {
if (zot(value)) value = -1;
if (value != -1 && !buttonContainer.getChildAt(value)) return;
var but;
for (var i=0; i<buttonContainer.numChildren; i++) {
but = buttonContainer.getChildAt(i);
but.removeChild(but.check);
}
if (value >= 0) {
but = buttonContainer.getChildAt(value);
var lastIndex = -2;
if (currentObject) lastIndex = currentObject.index;
currentObject = but.obj;
}
if (value == -1 || lastIndex == currentObject.index) {
currentObject = null;
that.id = null;
that.label = null;
that.text = "";
} else {
but.addChild(but.check);
that.id = currentObject.id;
that.label = currentObject.label;
if (that.label) that.text = that.label.text;
}
if ((!zim.OPTIMIZE&&(zns||!OPTIMIZE)) && that.stage) that.stage.update();
return that;
};
// getter setter methods
Object.defineProperty(that, 'selected', {
get: function() {
return currentObject;
},
set: function(value) {
zog("ZIM RadioButton - selected is read only");
}
});
Object.defineProperty(that, 'selectedIndex', {
get: function() {
return (currentObject) ? currentObject.index : -1;
},
set: function(value) {
var index = value;
if (always) {if (that.selectedIndex == index) return;}
that.setSelected(index);
}
});
this._enabled = true;
Object.defineProperty(that, 'enabled', {
get: function() {
return that._enabled;
},
set: function(value) {
zenable(that, value);
}
});
if (zot(selectedIndex)) selectedIndex=DS.selectedIndex!=null?DS.selectedIndex:0;
that.selectedIndex = selectedIndex;
zim.styleTransforms(this, DS);
this.clone = function() {
var buttonsCopy = zim.copy(buttons);
for (var i=0; i<buttonsCopy.length; i++) {
buttonsCopy[i].label = buttonsCopy[i].label.clone();
}
return that.cloneProps(new zim.RadioButtons(size, buttonsCopy, vertical, color, backgroundColor, borderColor, borderWidth, spacing, margin, always, indicatorColor, selectedIndex, style, this.group, inherit));
};
};
zim.extend(zim.RadioButtons, zim.Container, "clone", "zimContainer", false);
//-57
/*--
zim.Toggle = function(width, height, label, startToggled, backgroundColor, margin, indicatorType, indicatorColor, tap, toggleBackgroundColor, color, borderColor, borderWidth, corner, indicatorCorner, shadowColor, shadowBlur, time, labelLeft, style, group, inherit)
Toggle
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
A Toggle button that toggles off and on - with optional labels
Thanks Andi Erni for the initial design and coding of the Toggle.
See: https://zimjs.com/explore/toggle.html
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
new Toggle({label:"ON"}).center().change(function (e) {
zog(e.target.toggled)
});
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
width - (default 80) the width of the toggle (less labels)
height - (default 50) the height of the toggle
label - (default null) an optional ZIM Label (or text for default label properties)
also see labelLeft for left side text
startToggled - (default false) set to true to start in the toggled position
backgroundColor - (default "#C60") dark orange - set to any HTML color for background color
margin - (default 10) the distance around and between the toggle and its parts
indicatorType - (default "circle" or "round") set to "rectangle" or "square" for square indicator
indicatorColor - (default "#111")
toggleBackgroundColor - (default "#F93") orange - for toggled background color
try setting the borderColor to the same color as the background for inner color change effect
color - (default "#111") the font color of the toggle
borderColor - (default null) the color of the border
borderWidth - (default null - or 1 if borderColor) the size of the border
corner - (default half the height) a corner radius - or an array of corners [topLeft, topRight, bottomRight, bottomLeft]
indicatorCorner - (default 0) change the corner radius of a rectangle toggleType - or an array of corners [topLeft, topRight, bottomRight, bottomLeft]
shadowColor - (default "rgba(0,0,0,.3)" if shadowBlur) the shadow color - set to -1 for no shadow
shadowBlur - (default 14 if shadowColor) the shadow blur - set to -1 for no shadow
time - (default .1) time in seconds for toggle to animate (also see ZIM TIME constant)
labelLeft - (default null) an optional ZIM Label for the left side of the toggle (or text for default label properties)
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
toggle(state) - toggle the toggle - state defaults to true - set to false to un-toggle
hasProp(property as String) - returns true if property exists on object else returns false
clone() - makes a copy with properties such as x, y, etc. also copied
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), cache(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
toggled - gets and sets the toggled state of the toggle
text - gets the selected label text or "on" / "off" if no label
indicator - access to the indicator object
background - access to background Rectangle
label - access to the label if provided
labelLeft - access to the label on the left if provided
enabled - default is true - set to false to disable
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
dispatches a "change" event when pressed but not when toggle() is used
ALSO: see the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+57.5
zim.Toggle = function(width, height, label, startToggled, backgroundColor, margin, indicatorType, indicatorColor, tap, toggleBackgroundColor, color, borderColor, borderWidth, corner, indicatorCorner, shadowColor, shadowBlur, time, labelLeft, style, group, inherit) {
var sig = "width, height, label, startToggled, backgroundColor, margin, indicatorType, indicatorColor, tap, toggleBackgroundColor, color, borderColor, borderWidth, corner, indicatorCorner, shadowColor, shadowBlur, time, labelLeft, style, group, inherit";
var duo; if (duo = zob(zim.Toggle, arguments, sig, this)) return duo;
z_d("57.5");
this.group = group;
var DS = style===false?{}:zim.getStyle("Toggle", this.group, inherit);
if (zot(width)) width=DS.width!=null?DS.width:80;
if (zot(height)) height=DS.height!=null?DS.height:50;
this.zimContainer_constructor(width, height, null, null, false);
this.type = "Toggle";
if (zot(backgroundColor)) backgroundColor=DS.backgroundColor!=null?DS.backgroundColor:"#C60";
if (zot(margin)) margin = DS.margin!=null?DS.margin:10; //20;
if (zot(indicatorType)) indicatorType=DS.indicatorType!=null?DS.indicatorType:"circle";
if (zot(indicatorColor)) indicatorColor=DS.indicatorColor!=null?DS.indicatorColor:"#fff";
if (zot(toggleBackgroundColor)) toggleBackgroundColor=DS.toggleBackgroundColor!=null?DS.toggleBackgroundColor:"#F93";
if (zot(color)) color=DS.color!=null?DS.color:"#111";
if (zot(borderColor)) borderColor = DS.borderColor!=null?DS.borderColor:null;
if (zot(borderWidth)) borderWidth = DS.borderWidth!=null?DS.borderWidth:null;
if (borderColor < 0 || borderWidth < 0) borderColor = borderWidth = null;
else if (borderColor!=null && borderWidth==null) borderWidth = 1;
if (zot(corner)) corner=DS.corner!=null?DS.corner:indicatorType!="circle"?0:25;
if (zot(indicatorCorner)) indicatorCorner=DS.indicatorCorner!=null?DS.indicatorCorner:0;
if (zot(shadowColor)) shadowColor=DS.shadowColor!=null?DS.shadowColor:"rgba(0,0,0,.3)";
if (zot(shadowBlur)) shadowBlur=DS.shadowBlur!=null?DS.shadowBlur:14;
if (zot(startToggled)) startToggled=DS.startToggled!=null?DS.startToggled:false;
var timeType = getTIME(time);
if (zot(time)) time = DS.time!=null?DS.time:timeType=="s"?.1:100;
if (zot(label)) label=DS.label!=null?DS.label:null;
if (zot(labelLeft)) labelLeft=DS.labelLeft!=null?DS.labelLeft:null;
var that = this;
that.cursor = "pointer";
if (typeof label === "string" || typeof label === "number") label = this.label = new zim.Label({
text:label, size:DS.size||height*5/6, color:color, valign:"center",
backing:"ignore", shadowColor:"ignore", shadowBlur:"ignore", padding:"ignore", backgroundColor:"ignore",
group:this.group
});
if (typeof labelLeft === "string" || typeof labelLeft === "number") labelLeft = this.labelLeft = new zim.Label({
text:labelLeft, size:DS.size||height*5/6, color:color, valign:"center",
backing:"ignore", shadowColor:"ignore", shadowBlur:"ignore", padding:"ignore", backgroundColor:"ignore",
group:this.group
});
this.background = new zim.Rectangle(width, height, backgroundColor, borderColor, borderWidth, corner).addTo(this);
if (indicatorType=="rectangle" || indicatorType=="square") this.indicator = new zim.Rectangle(height*.65, height*.65, indicatorColor, null, null, indicatorCorner).center(this.background).pos(height*.2, null, startToggled);
else this.indicator = new zim.Circle(height*.35, indicatorColor).center(this.background).pos(height*.175, null, startToggled);
var _toggled = startToggled;
that.background.color = _toggled?toggleBackgroundColor:backgroundColor;
if (shadowColor != -1 && shadowBlur > 0) {
this.background.shadow = new createjs.Shadow(shadowColor, 3, 3, shadowBlur);
}
if (label) {
this.addChild(label);
label.x = width + 2 + margin + borderWidth;
label.y = height/2;
this.label = label;
this.setBounds(-margin, -margin, width+margin*3+borderWidth+label.getBounds().width, Math.max(height+margin*2, label.getBounds().height));
}
if (labelLeft) {
this.addChild(labelLeft);
labelLeft.x = 0;
that.background.x += labelLeft.width + 3 + margin + borderWidth;
that.label.x += labelLeft.width + 3 + margin + borderWidth;
labelLeft.y = height/2;
this.labelLeft = labelLeft;
this.setBounds(-margin, -margin, that.getBounds().width+labelLeft.width + 3 + margin + borderWidth, that.getBounds().height);
}
this.expand(zim.mobile()?20:10);
this.tap(function (e) {
if (labelLeft) {
var point = that.localToGlobal(labelLeft.width+3+margin+borderWidth+width/2, 0);
if ((e.stageX/zim.scaX < (point.x-width/2) && !_toggled) || (e.stageX/zim.scaX >= (point.x+width/2) && _toggled)) return;
}
_toggled = !_toggled;
setToggle();
that.dispatchEvent("change");
}, zim.mobile()?20:10);
var swipe = new zim.Swipe(this, 20, timeType=="s"?.2:200);
swipe.on("swipe", function (e) {
if (e.swipeX==0) {
return;
} else if (e.swipeX==1 && _toggled) {
return;
} else if (e.swipeX==-1 && !_toggled) {
return;
}
_toggled = !_toggled;
setToggle();
that.dispatchEvent("change");
});
function setToggle(immediate){
var oldX = that.indicator.x;
var t = time;
if (immediate===true) t = 0;
if (indicatorType=="rectangle" || indicatorType=="square") {
that.indicator.pos(height*.2, null, _toggled);
if (time>0) that.indicator.animate({props:{x:oldX}, from:true, time:t});
} else {
that.indicator.pos(height*.175, null, _toggled);
if (time>0) that.indicator.animate({props:{x:oldX}, from:true, time:t});
}
that.background.color = _toggled?toggleBackgroundColor:backgroundColor;
that.text = _toggled?(that.label?that.label.text:"on"):(that.labelLeft?that.labelLeft.text:"off");
if (that.zimAccessibility) {
var string = "Toggle set to " + (_toggled?(that.label?that.label.text+".":"on."):(that.labelLeft?that.labelLeft.text+".":"off."));
setTimeout(function() {that.zimAccessibility.talk(string);}, 50);
}
}
Object.defineProperty(that, 'textLeft', {
get: function() {
if (labelLeft) return labelLeft.text;
return null;
},
set: function(value) {
if (labelLeft) {
labelLeft.text = value;
if ((!zim.OPTIMIZE&&(zns||!OPTIMIZE)) && that.stage) that.stage.update();
}
}
});
that.toggle = function(state, immediate) {
var lastToggle = _toggled;
if (zot(state)) state = true;
_toggled = state;
if (lastToggle != _toggled) setToggle(immediate);
return that;
};
that.text = _toggled?(that.label?that.label.text:"on"):(that.labelLeft?that.labelLeft.text:"off");
Object.defineProperty(that, 'toggled', {
get: function() {
return _toggled;
},
set: function(value) {
that.toggle(value);
}
});
this._enabled = true;
Object.defineProperty(that, 'enabled', {
get: function() {
return that._enabled;
},
set: function(value) {
zenable(that, value);
}
});
if (style !== false) zim.styleTransforms(this, DS);
this.clone = function () {
return that.cloneProps(new zim.Toggle(width, height, label ? label.clone() : "", startToggled, backgroundColor, margin, indicatorType, indicatorColor, tap, toggleBackgroundColor, color, borderColor, borderWidth, corner, indicatorCorner, shadowColor, shadowBlur, time, labelLeft ? labelLeft.clone() : "", style, this.group, inherit));
};
};
zim.extend(zim.Toggle, zim.Container, "clone", "zimContainer", false);
//-57.5
/*--
zim.Tip = function(text, align, valign, margin, marginH, marginV, outside, target, size, font, color, rollColor, shadowColor, shadowBlur, textAlign, textValign, lineWidth, lineHeight, backing, outlineColor, outlineWidth, backgroundColor, backgroundBorderColor, backgroundBorderWidth, corner, backgroundDashed, padding, paddingHorizontal, paddingVertical, shiftHorizontal, shiftVertical, rollPersist, labelWidth, labelHeight, maxSize, bold, italic, variant, splitWords, style, group, inherit)
Tip
zim class - extends a a zim.Label which extends a zim.Container which extends a createjs.Container
DESCRIPTION
A Tip() can be used to show some extra information - the tip disappears after an amount of time
Tip has easy positioning along the inside edges or the outside edges of a target.
NOTE: Tip places the tip on the stage when the show() method is called
You can reposition with .mov() etc. if desired
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
new Tip("Press Circle").show(1); // wait one second and show tip at 40 pixels from bottom right
var circle = new Circle().center().tap(function () {
circleTip.show();
});
var circleTip = new Tip({
text:"This is a default ZIM Circle",
backgroundColor:white,
color:black,
outside:true, // outside the circle
target:circle,
align:"center",
valign:"bottom",
margin:14,
corner:0,
size:20
});
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
text - (default "Here's a tip!") String for the the text of the tip
align - (default "right") the horizontal position of the tip ("left", "center"/"middle", "right")
valign - (default "bottom") the vertical position of the tip ("top", "center"/"middle", "bottom")
margin - (default 40) distance from side (unless centered) in pixels
marginH - (default margin) distance from horizontal edges
marginV - (default margin) distance from vertical edges
outside - (default false) set to true to place Tip on outside of container
target - (default zdf's stage) tip is placed on stage relative to container
** the rest are parameters for a Label (align and valign are set as textAlign and textValign)
size - (default 36) the size of the font in pixels
font - (default arial) the font or list of fonts for the text
color - (default "black") color of font (any CSS color)
rollColor - (default color) the rollover color of the font
shadowColor - (default "rgba(0,0,0,.3)") set to -1 for no shadow - set to any css color to see
shadowBlur - (default 1) if shadow is present
textAlign - ((default "left") text registration point alignment also "center" and "right"
textValign - (default "center") vertical registration point alignment alse "middle / center", "bottom"
lineWidth - (default false) for no wrapping (use \n) Can set to number for wrap
lineHeight - (default getMeasuredLineHeight) set to number to adjust line height
fontOptions - (default null) css VALUES as a single string for font-style font-variant font-weight
eg. "italic bold small-caps" or just "italic", etc.
backing - (default null) a Display object for the backing of the label (eg. Shape, Bitmap, Container, Sprite)
see ZIM Pizzazz module for a fun set of Shapes like Boomerangs, Ovals, Lightning Bolts, etc.
outlineColor - (default null - or black if outlineWidth set) - the color of the outline of the text
outlineWidth - (default null - or (size*.2) if outlineColor set) - the thickness of the outline of the text
backgroundColor - (default null) set to CSS color to add a rectangular color around the label
The background color will change size to match the text of the label
Note: the backgroundColor is different than a backing which can be any Display Object
and background parameters are ignored if a backing parameter is set
backgroundBorderColor - (default null) the background stroke color
backgroundBorderWidth - (default null) thickness of the background border
corner - (default 0) the round of corner of the background if there is one
can also be an array of [topLeft, topRight, bottomRight, bottomLeft]
backgroundDashed - (default null) set to true for dashed background border (if backgroundBorderColor or backgroundBorderWidth set)
padding - (default 10 if backgroundColor set) places the border this amount from text (see paddingHorizontal and paddingVertical)
padding parameters are ignored if there is no backgroundColor set (also ignored if a backing parameter is set)
paddingHorizontal - (default padding) places border out at top bottom
paddingVertical - (default padding) places border out at left and right
shiftHorizontal - (default 0) move the label (CreateJS Text) inside the Label container horizontally
shiftVertical - (default 0) move the label (CreateJS Text) inside the Label container vertically
rollPersist - (default false) set to true to maintain rollover stage as long as mousedown or press is activated (used by Buttons)
labelWidth - (default null) the same as the lineWidth - the text will wrap at the labelWidth (added to match labelHeight)
labelHeight - (default null) the height of the text - setting this will probably alter the font size - so the size parameter is overwritten
for labelHeight to work, the labelWidth must also be set
using labelWidth and labelHeight together allow you to fit as much text into specified width and height dimensions
maxSize - (default null) set to limit the font size when using labelWidth and labelHeight
bold - (default false) set to true to bold the tip
italic - (default false) set to true to italic the tip
variant - (default false) set to true to set the tip to small caps
splitWords - (default false) set to true to split words when wrapping
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
show(delay, time) - show the tip - delay in s defaults to 0 and time in s defaults to 2 (also see ZIM TIME constant)
hide() - hides tip - show() will also hide the tip automatically after the time provided
clear() - hides tip and removes the call to a delayed tip using a delay time in show()
hasProp(property as String) - returns true if property exists on object else returns false
clone() - makes a copy with properties such as x, y, etc. also copied
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: see all methods of a Label() such as setColorRange(), etc.
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), cache(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
align - get or set the horizontal alignment
valign - get or set the vertical alignment
text - get or set the text of the Tip
ALSO: see all properties of a Label() such as size, color, etc.
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+57.6
zim.Tip = function(text, align, valign, margin, marginH, marginV, outside, target, size, font, color, rollColor, shadowColor, shadowBlur, textAlign, textValign, lineWidth, lineHeight, backing, outlineColor, outlineWidth, backgroundColor, backgroundBorderColor, backgroundBorderWidth, corner, backgroundDashed, padding, paddingHorizontal, paddingVertical, shiftHorizontal, shiftVertical, rollPersist, labelWidth, labelHeight, maxSize, bold, italic, variant, splitWords, style, group, inherit) {
var sig = "text, align, valign, margin, marginH, marginV, outside, target, size, font, color, rollColor, shadowColor, shadowBlur, textAlign, textValign, lineWidth, lineHeight, backing, outlineColor, outlineWidth, backgroundColor, backgroundBorderColor, backgroundBorderWidth, corner, backgroundDashed, padding, paddingHorizontal, paddingVertical, shiftHorizontal, shiftVertical, rollPersist, labelWidth, labelHeight, maxSize, bold, italic, variant, splitWords, style, group, inherit";
var duo; if (duo = zob(zim.Tip, arguments, sig, this)) return duo;
z_d("57.6");
this.group = group;
var DS = style===false?{}:zim.getStyle("Tip", this.group, inherit);
if (zot(text)) text = DS.text!=null?DS.text:"Here's a tip!";
if (zot(margin)) margin = DS.margin!=null?DS.margin:40;
if (zot(marginH)) marginH = DS.marginH!=null?DS.marginH:margin;
if (zot(marginV)) marginV = DS.marginV!=null?DS.marginV:margin;
if (zot(align)) align = DS.align!=null?DS.align:"right";
if (zot(valign)) valign = DS.valign!=null?DS.valign:"bottom";
if (zot(outside)) outside = DS.outside!=null?DS.outside:false;
if (zot(backgroundColor)) backgroundColor = DS.backgroundColor!=null?DS.backgroundColor:zim.blue;
if (zot(color)) color = DS.color!=null?DS.color:zim.white;
if (zot(corner)) corner = DS.corner!=null?DS.corner:25;
if (zot(corner)) corner = DS.corner!=null?DS.corner:25;
if (zot(corner)) corner = DS.corner!=null?DS.corner:25;
if (zot(paddingHorizontal)) paddingHorizontal = DS.paddingHorizontal!=null?DS.paddingHorizontal:14+(Array.isArray(corner)?corner[0]:corner);
if (zot(shadowColor) || shadowColor=="ignore") shadowColor=(DS.shadowColor!=null&&shadowColor!="ignore")?DS.shadowColor:"rgba(0,0,0,.3)";
if (zot(shadowBlur) || shadowBlur=="ignore") shadowBlur=(DS.shadowBlur!=null&&shadowBlur!="ignore")?DS.shadowBlur:1;
this.zimLabel_constructor(text, size, font, color, rollColor, null, null, textAlign, textValign, bold, italic, variant, lineWidth, lineHeight, backing, outlineColor, outlineWidth, backgroundColor, backgroundBorderColor, backgroundBorderWidth, corner, backgroundDashed, padding, paddingHorizontal, paddingVertical, shiftHorizontal, shiftVertical, rollPersist, labelWidth, labelHeight, maxSize, splitWords, style, group, zim.copy(DS));
this.type = "Tip";
if (outside) {
marginH = -marginH;
marginV = -marginV;
}
var that = this;
that.align = align;
that.valign = valign;
this.background.sha(shadowColor, 3, 5, shadowBlur);
this.show = function(delay, time) {
var timeType = getTIME(time);
if (zot(delay)) delay = DS.delay!=null?DS.delay:0;
if (zot(time)) time = DS.time!=null?DS.time:timeType=="s"?2:2000;
var mess = "zim Tip(): Please pass in a reference to a container with bounds set as parameter to Tip";
if (zot(target)) {
if (zdf) {
target = zdf.stage;
} else {
return that;
}
} else if (!target.getBounds) {
return that;
} else if (zot(target.stage)) {
zog("zim display - Waiter(): The container must have a stage property");
return that;
}
if (delay > 0) {
that.showID = zim.timeout(delay, doShow);
} else {
doShow();
}
function doShow() {
if (target.boundsToGlobal) var b = target.boundsToGlobal();
else var b = target.getBounds();
var container = new zim.Container(b.x, b.y, b.width, b.height);
container.zimTemp = true;
container.loc(0, 0, target.stage);
if (that.align=="center" || that.align=="middle" || that.valign=="center" || that.valign=="middle") {
that.center(container);
}
that.pos((that.align == "center" || that.align == "middle") ? null : marginH, (that.valign == "center" || that.valign == "middle") ? null : marginV, (that.align == "right"), (that.valign == "bottom"), container);
if (outside) {
if (that.align == "right") that.x += that.width;
else if (that.align == "left") that.x -= that.width;
if (that.valign == "bottom") that.y += that.height;
else if (that.valign == "top") that.y -= that.height;
}
that.addTo(container.stage); // will transfer over position...
if (container.zimTemp && container.removeFrom) { container.removeFrom(); container = null; }
container = that.stage;
if (that.timeoutID) that.timeoutID.clear();
that.timeoutID = zim.timeout(time, function () {
that.hide();
container.stage.update();
});
// setTimeout(function() {
if (that.upID) container.stage.off("stagemouseup", that.upID);
that.upID = container.stage.on("stagemouseup", function () {
that.hide();
if (container.stage) container.stage.update();
});
// }, 200);
if (container.stage) container.stage.update();
}
return that;
};
this.hide = function() {
this.removeFrom();
if (this.timeoutID) this.timeoutID.clear();
if (this.upID && target.stage) target.stage.off("stagemouseup", this.downID);
return that;
};
this.clear = function() {
if (that.showID) that.showID.clear();
that.hide();
};
if (style !== false) zim.styleTransforms(this, DS);
this.clone = function () {
return that.cloneProps(new zim.Tip(text, align, valign, margin, marginH, marginV, outside, target, size, font, color, rollColor, shadowColor, shadowBlur, textAlign, textValign, lineWidth, lineHeight, backing, outlineColor, outlineWidth, backgroundColor, backgroundBorderColor, backgroundBorderWidth, corner, backgroundDashed, padding, paddingHorizontal, paddingVertical, shiftHorizontal, shiftVertical, rollPersist, labelWidth, labelHeight, maxSize, splitWords, style, this.group, inherit));
};
};
zim.extend(zim.Tip, zim.Label, "clone", "zimLabel", false);
//-57.6
/*--
zim.Panel = function(width, height, titleBar, titleBarColor, titleBarBackgroundColor, titleBarHeight, backgroundColor, borderColor, borderWidth, corner, close, closeColor, arrow, align, shadowColor, shadowBlur, draggable, boundary, extraButton, collapse, collapsed, style, group, inherit)
Panel
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
A simple panel with titleBar and optional arrow for more panels.
Panel can be set draggable and can have a close button
See: https://zimjs.com/explore/panel.html
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var panel = new Panel({titleBar:series("TODAY", "TOMORROW")})
.center();
// make a couple pages for the panels
// content for panel 1
var today = new Container(panel.width, panel.height).addTo(panel);
var sun = new Circle(30, yellow).center(today);
// content for panel 2
var tomorrow = new Container(panel.width, panel.height); // do not add yet
var label = new Label("-30").center(tomorrow);
// event to change content as panels change
panel.on("change", function () {
if (today.parent) {
today.removeFrom();
tomorrow.center(panel);
} else {
tomorrow.removeFrom();
today.center(panel);
}
});
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports VEE - parameters marked with ZIM VEE mean a zim Pick() object or Pick Literal can be passed
Pick Literal formats: [1,3,2] - random; {min:10, max:20} - range; series(1,2,3) - order, function(){return result;} - function
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
width - (default 250) the width of the panel
height - (default 300) the height of the panel
titleBar - |ZIM VEE| (default "PANEL") a String or ZIM Label title for the panel that will be presented on a titleBar across the top
titleBarColor - |ZIM VEE| (default "black") the text color of the titleBar if a titleBar is requested
titleBarBackgroundColor - |ZIM VEE| (default "rgba(0,0,0,.2)") the background color of the titleBar if a titleBar is requested
titleBarHeight - (default fit label) the height of the titleBar if a titleBar is requested
backgroundColor - |ZIM VEE| (default #eee) background color (use clear - or "rbga(0,0,0,0)" for no background)
borderColor - |ZIM VEE| (default #888) border color
borderWidth - (default 1) the thickness of the border
corner - (default 0) the round of corner
can also be an array of [topLeft, topRight, bottomRight, bottomLeft]
close - (default false) - add a close button top right
closeColor - (default titleBarColor) the color of the close button
arrow - (default true if more than one panel) set to false to not show an arrow if multiple panels
align - (default "left") set to "center", "middle" or "right" to align the label on the titleBar
shadowColor - (default "rgba(0,0,0,.3)" if shadowBlur) the shadow color - set to -1 for no shadow
shadowBlur - (default 14 if shadowColor) the shadow blur - set to -1 for no shadow
draggable - (default true if titleBar) set to false to not allow dragging titleBar to drag window
boundary - (default null) set to ZIM Boundary() object - or CreateJS.rectangle()
extraButton - (default null) creates a little square button with the letter R for reset
this is made with the group style id of "extraButton"
use the extraButton property to access the button to change its label or capture an event, etc.
collapse - (default false) set to true to double click panel title bar to collapse and unCollapse panel
collapsed - (default false) set to true to start the panel collapsed
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
nextPanel(index, event) - show next panel - the panels are set up to be a series or random or function based
this means there is not necessarily an order to be able to go backwards to... so, only forward!
If a series is provided to the Panel title, etc. then the index can be used to go to the title in the series at the index
event (default false) will dispatch a change event if nextPanel is called
hasProp(property as String) - returns true if property exists on object else returns false
clone() - makes a copy with properties such as x, y, etc. also copied
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), cache(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
panelHeight - get and set the height of the panel without scaling it as height does (for width, remake the Panel object)
titleBar - access to the titleBar container
label - access to the label of the current panel
text - access to the text of the current panel
titleBar - gives access to the titleBar Container - which also has a background property
titleBarLabel - gives access to the titleBar label
close - access to the close button
collapsed - pass in true to collapse the panel and false to unCollapse the panel
arrow - access to the next arrow
background - access to the background Rectangle
extraButton - access to the Label for the extra button if extraButton parameter is set to true
use this to set the text in the button (a one letter button is expected - for instance, i for info, x for close, etc.)
overlay - access to the overlay Rectangle used if enabled = false
enabled - default is true - set to false to disable
blendMode - how the object blends with what is underneath - such as "difference", "multiply", etc. same as CreateJS compositeOperation
group - used when the object is made to add STYLE with the group selector (like a CSS class)
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
dispatches a "change" event when arrow is pressed to go to the next panel
dispatches a "close" event when closed with close button if there is a close button
ALSO: see the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+57.7
zim.Panel = function(width, height, titleBar, titleBarColor, titleBarBackgroundColor, titleBarHeight, backgroundColor, borderColor, borderWidth, corner, close, closeColor, arrow, align, shadowColor, shadowBlur, draggable, boundary, extraButton, collapse, collapsed, style, group, inherit) {
var sig = "width, height, titleBar, titleBarColor, titleBarBackgroundColor, titleBarHeight, backgroundColor, borderColor, borderWidth, corner, close, closeColor, arrow, align, shadowColor, shadowBlur, draggable, boundary, extraButton, collapse, collapsed, style, group, inherit";
var duo; if (duo = zob(zim.Panel, arguments, sig, this)) return duo;
z_d("57.7");
this.group = group;
var DS = style===false?{}:zim.getStyle("Panel", this.group, inherit);
if (zot(width)) width=DS.width!=null?DS.width:250;
if (zot(height)) height=DS.height!=null?DS.height:300;
this.zimContainer_constructor(width, height, null, null, false);
this.type = "Panel";
if (zot(titleBar)) titleBar = DS.titleBar!=null?DS.titleBar:"PANEL";
if (zot(titleBarColor)) titleBarColor = DS.titleBarColor!=null?DS.titleBarColor:"#fff";
if (zot(titleBarBackgroundColor)) titleBarBackgroundColor = DS.titleBarBackgroundColor!=null?DS.titleBarBackgroundColor:"#555";
if (zot(titleBarHeight)) titleBarHeight = DS.titleBarHeight!=null?DS.titleBarHeight:30;
if (zot(backgroundColor)) backgroundColor=DS.backgroundColor!=null?DS.backgroundColor:"#eee";
if (zot(borderColor)) borderColor = DS.borderColor!=null?DS.borderColor:"#888";
if (zot(borderWidth)) borderWidth = DS.borderWidth!=null?DS.borderWidth:null;
if (borderColor < 0 || borderWidth < 0) borderColor = borderWidth = null;
else if (borderColor!=null && borderWidth==null) borderWidth = 1;
if (zot(corner)) corner=DS.corner!=null?DS.corner:5;
if (zot(align)) align=DS.align!=null?DS.align:"left";
if (zot(shadowColor)) shadowColor=DS.shadowColor!=null?DS.shadowColor:"rgba(0,0,0,.3)";
if (zot(shadowBlur)) shadowBlur=DS.shadowBlur!=null?DS.shadowBlur:14;
if (zot(draggable)) draggable = DS.draggable!=null?DS.draggable:false;
if (zot(boundary)) boundary = DS.boundary!=null?DS.boundary:null;
if (zot(close)) close=DS.close!=null?DS.close:false;
if (zot(closeColor)) closeColor = DS.closeColor != null ? DS.closeColor : !zot(titleBarColor) ? titleBarColor : "#555";
if (zot(arrow)) arrow=DS.arrow!=null?DS.arrow:zim.vee(titleBar);
if (!Array.isArray(corner)) corner = [corner,corner,corner,corner];
if (zot(collapse)) collapse=DS.collapse!=null?DS.collapse:false;
if (zot(collapsed)) collapsed=DS.collapsed!=null?DS.collapsed:false;
var that = this;
var background = this.background = new zim.Rectangle(width, height, backgroundColor, borderColor, borderWidth, corner).addTo(this);
if (shadowColor != -1 && shadowBlur > 0) {
this.background.shadow = new createjs.Shadow(shadowColor, 3, 3, shadowBlur);
}
var titleBarValue = titleBar; // as we assign the container to titleBar later
var t = zim.Pick.choose(titleBarValue);
var tBarColor = zim.Pick.choose(titleBarColor);
var tBarBackgroundColor = zim.Pick.choose(titleBarBackgroundColor);
var pBackgroundColor = zim.Pick.choose(backgroundColor);
var pBorderColor = zim.Pick.choose(borderColor);
if (typeof t == "string") t = new zim.Label({
text:t, color:tBarColor, size:DS.size!=null?DS.size:20, bold:DS.bold!=null?DS.bold:false,
backing:"ignore", shadowColor:"ignore", shadowBlur:"ignore", padding:"ignore", backgroundColor:"ignore",
group:this.group
});
var titleBarLabel = that.titleBarLabel = t;
if (zot(tBarBackgroundColor)) tBarBackgroundColor = "rgba(0,0,0,.2)";
that.titleBar = titleBar = new zim.Container(width, titleBarHeight, null, null, false).loc(0,0,that);
var titleBarRect = that.titleBar.backing = new zim.Rectangle(width+borderWidth, titleBarHeight, tBarBackgroundColor, null, null, [corner[0]*.95, corner[1]*.95, 0, 0], true, null, false).center(titleBar);
if (titleBar) positionBar();
that.label = t;
that.text = t.text;
if (close) {
var close = that.close = new zim.Shape(-40,-40,80,80,null,false);
close.graphics.f(closeColor).p("AmJEVIEUkTIkXkWIB4h5IEWEYIETkTIB4B3IkTESIEQERIh4B4IkRkRIkSEVg"); // width about 90 reg in middle
if (titleBar) {
close.centerReg(titleBar)
.scaleTo(titleBar, null, 50);
if (align=="right") close.pos(Math.max(corner[1]/2, 15));
else close.pos(Math.max(corner[1]/2, 15), null, true);
} else {
close.addTo(that)
.sca(.3)
.mov(width/2-close.width-3, -height/2+close.height);
}
close.expand(40);
close.cursor = "pointer";
close.on((!zns?ACTIONEVENT=="mousedown":zim.ACTIONEVENT=="mousedown")?"mousedown":"click", function () {
var s = that.stage;
that.removeFrom();
that.dispatchEvent("close");
s.update();
});
}
if (collapse) {
if (collapsed) that.collapsed = true;
that.collapseEvent = that.titleBar.on("dblclick", function () {
collapsed = !collapsed;
that.collapsed = collapsed;
});
}
this.nextPanel = function(index, event) {
var t = zot(index)||zot(titleBarValue.array)?zim.Pick.choose(titleBarValue):titleBarValue.array[index];
var tBarColor = zot(index)||zot(titleBarColor.array)?zim.Pick.choose(titleBarColor):titleBarColor.array[index];
var tBarBackgroundColor = zot(index)||zot(titleBarBackgroundColor.array)?zim.Pick.choose(titleBarBackgroundColor):titleBarBackgroundColor.array[index];
var pBackgroundColor = zot(index)||zot(backgroundColor.array)?zim.Pick.choose(backgroundColor):backgroundColor.array[index];
var pBorderColor = zot(index)||zot(borderColor.array)?zim.Pick.choose(borderColor):borderColor.array[index];
if (typeof t == "string") t = new zim.Label({
text:t, color:tBarColor, size:DS.size!=null?DS.size:20,
backing:"ignore", shadowColor:"ignore", shadowBlur:"ignore", padding:"ignore", backgroundColor:"ignore",
group:this.group
});
that.label = t;
that.text = t.text;
titleBarLabel.removeFrom();
titleBarLabel = that.titleBarLabel = t;
positionBar();
titleBarRect.color = tBarBackgroundColor;
that.background.color = pBackgroundColor;
that.background.borderColor = pBorderColor;
if (event) that.dispatchEvent("change");
if (!OPTIMIZE && that.stage) that.stage.update();
};
function positionBar() {
if (align=="right") titleBarLabel.center(titleBar).pos(Math.max(corner[0]/2, 10), null, true);
else if (align=="center" || align=="middle") titleBarLabel.center(titleBar);
else titleBarLabel.center(titleBar).loc(Math.max(corner[0]/2, 10));
titleBarLabel.mov(0,2);
}
if (draggable) {
titleBar.cursor = "pointer";
titleBar.on("mousedown", function() {
that.drag({rect:boundary, currentTarget:true});
});
titleBar.on("pressup", function() {
that.noDrag(false); // false for not recursive - leave objects inside so they do not lose their own cursors
});
}
if (arrow > 0) {
var added = close?close.width+15:0;
var next = that.arrow = new zim.Shape(-20,-20,40,40,null,false);
next.graphics.f(titleBarColor).p("AiJieIETCeIkTCfg"); // width about 90 reg in middle
next.centerReg(titleBar).scaleTo(titleBar, null, 70).alp(.8).hov(1).expand();
if (align=="right") next.pos(Math.max(corner[1]/2, 10)+added);
else next.pos(Math.max(corner[1]/2, 10)+added, null, true);
next.cursor = "pointer";
next.on((!zns?ACTIONEVENT=="mousedown":zim.ACTIONEVENT=="mousedown")?"mousedown":"click", function(){
that.nextPanel();
that.dispatchEvent("change");
});
}
if (!zot(extraButton)) {
var extraButton = that.extraButton = new zim.Button({
label:"R",
width:50,
height:50,
corner:5,
group:"PanelExtra"
}).scaleTo(titleBar, null, 70).centerReg(titleBar).expand();
if (align=="left") {
extraButton.pos(arrow>0?next.x-next.width-25:Math.max(corner[1]/2, 10) );
} else {
extraButton.pos((arrow>0&&align!="center")?next.x+next.width: Math.max(corner[1]/2, 10));
}
}
var overlay = that.overlay = new zim.Rectangle(width, height, null, null, null, corner).alp(.3);
Object.defineProperty(that, 'panelHeight', {
get: function() {
return that.background.height;
},
set: function(value) {
background.removeFrom();
background = this.background = new zim.Rectangle(width, value, backgroundColor, borderColor, borderWidth, corner)
.addTo(this).bot();
if (shadowColor != -1 && shadowBlur > 0) {
this.background.shadow = new createjs.Shadow(shadowColor, 3, 3, shadowBlur);
}
that.setBounds(width, value);
if (!OPTIMIZE && that.stage) that.stage.update();
}
});
Object.defineProperty(that, 'collapsed', {
get: function() {
return collapsed;
},
set: function(value) {
collapsed = value;
if (collapsed) that.setMask(that.titleBar.backing, true);
else that.setMask(null);
if (that.stage) that.stage.update();
}
});
this._enabled = true;
Object.defineProperty(that, 'enabled', {
get: function() {
return that._enabled;
},
set: function(value) {
zenable(that, value);
if (!value) that.overlay.addTo(that);
else that.overlay.removeFrom();
if (!OPTIMIZE && that.stage) that.stage.update();
}
});
if (style !== false) zim.styleTransforms(this, DS);
this.clone = function () {
return that.cloneProps(new zim.Toggle(width, height, titleBar ? titleBar.clone() : "", titleBarColor, titleBarBackgroundColor, titleBarHeight, backgroundColor, borderColor, borderWidth, corner, close, closeColor, arrow, align, shadowColor, shadowBlur, draggable, boundary, extraButton, collapse, collapsed, style, this.group, inherit));
};
this.doDispose = function(a,b,disposing) {
// need to dispose properly for Panel
if (collapse) this.titleBar.off("dblclick", this.collapseEvent);
if (!disposing) this.zimContainer_dispose(true);
return true;
}
};
zim.extend(zim.Panel, zim.Container, ["clone", "dispose"], "zimContainer", false);
zim.Panel.prototype.dispose = function(disposing) {return this.doDispose(null,null,disposing);};
//-57.7
/*--
zim.Pane = function(width, height, label, backgroundColor, color, draggable, resets, modal, corner, backdropColor, shadowColor, shadowBlur, center, displayClose, backdropClose, backing, fadeTime, container, titleBar, titleBarColor, titleBarBackgroundColor, titleBarHeight, close, closeColor, style, group, inherit)
Pane
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
Adds a window for alerts, etc.
You need to call the pane.show() to show the pane and pane.hide() to hide it.
You do not need to add it to the stage - it adds itself centered.
You can change the x and y (the origin and registration point are in the middle).
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var pane = new Pane(300, 200, "Watch out!", "#CCC");
pane.show(); // pressing anywhere will close pane (see parameters for options)
END EXAMPLE
EXAMPLE
var pane = new Pane({width:600, height:250, modal:false, displayClose:false});
var cancel = new Button(220, 100, "CANCEL", "red").center(pane).mov(-130);
var confirm = new Button(220, 100, "CONFIRM", "green").center(pane).mov(130);
cancel.on("click", function() {pane.hide();});
confirm.on("click", function() {zgo("http://zimjs.com")});
pane.show(); // pressing anywhere will close pane (see parameters for options)
// custom backing with ZIM Pizzazz 3
// up top link to https://d309knd7es5f10.cloudfront.net/pizzazz_03.js
new Pane({
label:new Label({color:white, text:"STOP", size:50}),
backing:pizzazz.makePattern({
type:"stripes",
colors:series(red,black),
rows:20
}).alp(.8)
}).show();
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
width - (default 200) width of pane
height - (default 200) height of pane
label - (default null) an optional ZIM Label (or text for default label properties)
backgroundColor - (default "white") a css color for the background of the Pane
color - (default "black") a css color for the text color of the Pane
draggable - (default false) pass in true to drag the pane
resets - (default true) resets position to start on re-open - set to false to keep last position
modal - (default true) pane will close when user clicks off the pane - set to false to keep pane open
corner - (default 20) is the corner radius - set to 0 for no corner
can also be an array of [topLeft, topRight, bottomRight, bottomLeft]
backdropColor - (default "rgba(0,0,0,.2)") the color of the background that fills the stage
shadowColor - (default "rgba(0,0,0,.3)") set to -1 for no shadow
shadowBlur - (default 20) how blurred the shadow is if shadow is set
center - (default true) centers the pane
if center is false you will have to set x and y for the pane
the registration point and the origin inside the pane is in the center
you can adjust the label placement by changing its x and y or registration point
displayClose - (default true) closes the Pane if display backing is pressed
if draggable is set to true, displayClose will automatically be set to false
backdropClose - (default true) closes the Pane if backdrop is pressed
backing - (default null) a Display object for the backing of the pane (eg. Shape, Bitmap, Container, Sprite)
see ZIM Pizzazz module for a fun set of Shapes like Boomerangs, Ovals, Lightning Bolts, etc.
as well as patterned backings using Pizzazz 3
fadeTime - (default 0) seconds to fade in and out - also see ZIM TIME constant
container - (default - the default stage) container for the pane
titleBar - (default null - no titleBar) a String or ZIM Label title for the pane that will be presented on a titleBar across the top
titleBarColor - (default "black") the color of the titleBar text if a titleBar is requested
titleBarBackgroundColor - (default "rgba(0,0,0,.2)") the background color of the titleBar if a titleBar is requested
titleBarHeight - (default fit label) the height of the titleBar if a titleBar is requested
close - (default false) - a close X for the top right corner that closes the pane when pressed
closeColor - (default #555) - the color of the close X if close is requested
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
show() - shows the pane (returns the pane for chaining)
hide(callEvent) - hides the pane - callEvent defaults to false - set to true to also call close event
toggle(state - default null) - shows if hidden and hides if showing (returns the pane for chaining)
or pass in true to show pane or false to hide pane
hasProp(property as String) - returns true if property exists on object else returns false
clone() - makes a copy with properties such as x, y, etc. also copied (returns the new pane for chaining)
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), cache(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
backing - or display - reference to the pane box
text - gives access to the label text
label - gives access to the label
titleBar - gives access to the titleBar Container - which also has a background property
titleBarLabel - gives access to the titleBar label
toggled - read-only Boolean property as to whether pane is showing
close - access to the ZIM Shape if there is a close X
backdrop - reference to the backdrop that covers the stage
container - get or set the container the pane will be added to
resetX - if reset is true you can dynamically adjust the position if needed
resetY - and the y position for reset...
enabled - set to false to disable component
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
OPTIMIZED
This component is affected by the general OPTIMIZE setting (default is false)
if set to true, you will have to stage.update() after setting certain properties
and stage.update() in change event to see component change its graphics
ACTIONEVENT
This component is affected by the general ACTIONEVENT setting
The default is "mousedown" - if set to something else the component will act on click (press)
EVENTS
dispatches a "close" event when closed by clicking on backing, display, close, etc. when applicable
dispatches a "fadedin" event if fadeTime is set and pane has finished its fade in animation
dispatches a "fadedout" event if fadeTime is set and pane has finished its fade out animation
ALSO: see the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+58
zim.Pane = function(width, height, label, backgroundColor, color, draggable, resets, modal, corner, backdropColor, shadowColor, shadowBlur, center, displayClose, backdropClose, backing, fadeTime, container, titleBar, titleBarColor, titleBarBackgroundColor, titleBarHeight, close, closeColor, style, group, inherit) {
var sig = "width, height, label, backgroundColor, color, draggable, resets, modal, corner, backdropColor, shadowColor, shadowBlur, center, displayClose, backdropClose, backing, fadeTime, container, titleBar, titleBarColor, titleBarBackgroundColor, titleBarHeight, close, closeColor, style, group, inherit";
var duo; if (duo = zob(zim.Pane, arguments, sig, this)) return duo;
z_d("58");
this.zimContainer_constructor(null,null,null,null,false);
this.type = "Pane";
var mess = "zim display - Pane(): Please pass in a reference to a container with bounds set as first parameter";
if (zot(container)) {
if (zdf) {
container = zdf.stage;
} else {
zog(mess);
return;
}
} else if (!container.getBounds) {
zog(mess);
return;
} else if (zot(container.getStage)) {
zog("zim display - Pane(): The container must have a stage property");
return;
}
this.group = group;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
if (zot(width)) width=DS.width!=null?DS.width:200;
if (zot(height)) height=DS.height!=null?DS.height:200;
if (zot(label)) label = DS.label!=null?DS.label:null;
if (typeof label === "string" || typeof label === "number") label = new zim.Label({
text:label, size:DS.size!=null?DS.size:40, align:DS.align!=null?DS.align:"center", valign:DS.valign!=null?DS.valign:"center", color:DS.color!=null?DS.color:color,
backing:"ignore", shadowColor:"ignore", shadowBlur:"ignore", padding:"ignore", backgroundColor:"ignore",
group:this.group
});
if (zot(backgroundColor)) backgroundColor=DS.backgroundColor!=null?DS.backgroundColor:"white";
if (zot(draggable)) draggable=DS.draggable!=null?DS.draggable:false;
if (zot(resets)) resets=DS.resets!=null?DS.resets:true;
if (zot(modal)) modal=DS.modal!=null?DS.modal:true;
if (zot(corner)) corner=DS.corner!=null?DS.corner:20;
if (zot(titleBar)) titleBar = DS.titleBar!=null?DS.titleBar:null;
if (zot(titleBarColor)) titleBarColor = DS.titleBarColor!=null?DS.titleBarColor:null;
if (zot(titleBarBackgroundColor)) titleBarBackgroundColor = DS.titleBarBackgroundColor!=null?DS.titleBarBackgroundColor:null;
if (zot(titleBarHeight)) titleBarHeight = DS.titleBarHeight!=null?DS.titleBarHeight:null;
if (zot(backdropColor)) backdropColor=DS.backdropColor!=null?DS.backdropColor:"rgba(0,0,0,.2)";
if (zot(shadowColor)) shadowColor=DS.shadowColor!=null?DS.shadowColor:"rgba(0,0,0,.3)";
if (zot(shadowBlur)) shadowBlur=DS.shadowBlur!=null?DS.shadowBlur:20;
if (zot(center)) center=DS.center!=null?DS.center:true;
if (zot(displayClose)) displayClose=DS.displayClose!=null?DS.displayClose:true;
if (draggable) displayClose = false;
if (zot(backdropClose)) backdropClose=DS.backdropClose!=null?DS.backdropClose:true;
if (zot(fadeTime)) fadeTime=DS.fadeTime!=null?DS.fadeTime:0;
if (zot(close)) close=DS.close!=null?DS.close:false;
if (zot(closeColor)) closeColor=DS.closeColor!=null?DS.closeColor:"#555";
var backdrop = this.backdrop = new zim.Shape({style:false});
backdrop.type = "CreateJS_Shape";
// make a big backing that closes the pane when clicked
// could also provide a close button
var g = backdrop.graphics;
g.f(backdropColor);
g.drawRect(-5000,-5000,10000,10000);
// makes it seem like the pane has the dimensions of the display
this.setBounds(-width/2,-height/2, width, height);
var that = this;
that.container = container;
backdrop.on((!zns?ACTIONEVENT=="mousedown":zim.ACTIONEVENT=="mousedown")?"mousedown":"click", backdropClose?closePane:function(e){e.stopImmediatePropagation();});
var htmlList = new zim.Dictionary(true);
function closePane(e) {
removePane();
that.container.stage.update();
that.dispatchEvent("close");
e.stopImmediatePropagation();
}
backdrop.on("mousedown", function(e) {
e.stopImmediatePropagation();
});
if (modal) this.addChild(backdrop);
var display;
if (zot(backing)) {
display = this.backing = this.display = new zim.Rectangle({
width:width, height:height, color:backgroundColor, corner:corner, style:false
});
} else {
if (backing.type == "Pattern") {
var pattern = backing;
// width, height, color, borderColor, borderWidth, corner, dashed, strokeObj, style, group, inherit
display = new zim.Rectangle(width, height, backgroundColor, null, null, corner, null, null, false);
pattern.centerReg(display);
pattern.setMask(display.shape);
} else {
display = backing;
}
that.display = that.backing = display;
}
if (displayClose) {
display.cursor = "pointer";
display.on((!zns?ACTIONEVENT=="mousedown":zim.ACTIONEVENT=="mousedown")?"mousedown":"click", closePane);
}
if (shadowColor != -1 && shadowBlur > 0) display.shadow = new createjs.Shadow(shadowColor, 8, 8, shadowBlur);
display.on("click", function(e) {
// stops the click from going through the display to the background
e.stopImmediatePropagation();
});
this.resetX; this.resetY;
if (draggable) {
display.cursor = "pointer";
var diffX, diffY;
var stage;
display.on("mousedown", function(e) {
stage = e.target.stage;
if (isNaN(that.resetX)) that.resetX = that.x;
if (isNaN(that.resetY)) that.resetY = that.y;
diffX = e.stageX/zim.scaX - that.x;
diffY = e.stageY/zim.scaY - that.y;
display.cursor = "pointer";
});
display.on("pressmove", function(e) {
var p = checkBounds(e.stageX/zim.scaX-diffX, e.stageY/zim.scaY-diffY);
that.x = p.x;
that.y = p.y;
var ch;
for (var i=0; i<that.numChildren; i++) {
ch = that.getChildAt(i);
if (ch.type == "TextArea" || ch.type == "Loader" || ch.type == "Tag") {
ch.resize();
}
}
that.stage.update();
});
this.on("pressup", function(e) {
display.cursor = "pointer";
if (that.stage) that.stage.update();
});
}
display.centerReg(this);
if (label) {
this.addChild(label);
zim.center(label, this);
this.label = label;
this.text = label.text;
label.mouseEnabled = false;
}
if (!zot(titleBar)) {
if (typeof titleBar == "string") titleBar = new zim.Label(titleBar, null, null, titleBarColor);
var titleBarLabel = that.titleBarLabel = titleBar;
if (zot(titleBarHeight)) titleBarHeight=titleBarLabel.height * 1.5;
if (zot(titleBarColor)) titleBarColor = "black";
if (zot(titleBarBackgroundColor)) titleBarBackgroundColor = "rgba(0,0,0,.2)";
that.titleBar = titleBar = new zim.Container(width, titleBarHeight, null, null, false).centerReg(that).mov(0,-height/2+titleBarHeight/2);
titleBar.mouseEnabled = false;
titleBar.mouseChildren = false;
var titleBarRect = that.titleBar.backing = new zim.Rectangle(width, titleBarHeight, titleBarBackgroundColor, null, null, [corner*.95,corner*.95, 0,0], null, null, false).addTo(titleBar);
titleBarLabel.center(titleBar).pos({x:Math.max(corner/2, 10), reg:true});
}
if (close) {
var close = that.close = new zim.Shape(-40,-40,80,80,null,false);
close.graphics.f(closeColor).p("AmJEVIEUkTIkXkWIB4h5IEWEYIETkTIB4B3IkTESIEQERIh4B4IkRkRIkSEVg"); // width about 90 reg in middle
if (titleBar) close.addTo(that).scaleTo(titleBar, null, 50).mov(width/2-Math.max(corner/2, 10)-close.width/2, -height/2+titleBarHeight/2).expand(40);
else close.addTo(that).sca(.3).mov(width/2-close.width-3, -height/2+close.height).expand(40);
close.cursor = "pointer";
close.expand();
close.on((!zns?ACTIONEVENT=="mousedown":zim.ACTIONEVENT=="mousedown")?"mousedown":"click", closePane);
}
Object.defineProperty(that, 'text', {
get: function() {
var t = (label.text == " ") ? "" : label.text;
return t;
},
set: function(value) {
label.text = value;
}
});
this._enabled = true;
Object.defineProperty(that, 'enabled', {
get: function() {
return that._enabled;
},
set: function(value) {
zenable(that, value);
}
});
this.hide = function(callEvent) {
removePane();
that.toggled = false;
if (callEvent) that.dispatchEvent("close");
return that;
};
function removePane() {
if (fadeTime > 0) {
that.animate({obj:{alpha:0}, time:fadeTime, call:function(){
end();
that.dispatchEvent("fadedout");
}});
} else {
end();
}
function end() {
that.container.removeChild(that);
var ch;
for (var i=0; i<that.numChildren; i++) { // record depths first
ch = that.getChildAt(i);
if (ch.type == "TextArea" || ch.type == "Loader" || ch.type == "Tag") {
var obj = {obj:ch, depth:that.getChildIndex(ch)};
htmlList.add(ch, obj);
}
}
for (var i=that.numChildren-1; i>=0; i--) { // remove textareas and loaders second
ch = that.getChildAt(i);
if (ch.type == "TextArea" || ch.type == "Loader" || ch.type == "Tag") {
that.removeChild(ch);
}
}
if ((!zim.OPTIMIZE&&(zns||!OPTIMIZE))) that.container.stage.update();
if (resets) {
if (!isNaN(that.resetX)) that.x = that.resetX;
if (!isNaN(that.resetY)) that.y = that.resetY;
}
if (that.zimAccessibility) {
var a = that.zimAccessibility;
a.resize(that);
if (accessibilityClicker) accessibilityClicker.focus();
else that.zimTabTag.nextSibling.focus();
setTimeout(function() {a.talk("Pane has been closed.");}, 50);
}
}
}
var accessibilityClicker;
this.show = function() {
if (center) {
if (isNaN(that.resetX)) {
that.x = (that.container.getBounds().width) /2;
that.y = (that.container.getBounds().height) /2;
}
}
that.container.addChild(that);
for (var i=0; i<htmlList.length; i++) {
that.addChildAt(htmlList.values[i].obj, htmlList.values[i].depth);
}
if (fadeTime > 0) {
that.alpha = 0;
that.animate({
props:{alpha:1},
time:fadeTime,
call:function(){
that.dispatchEvent("fadedin");
}
});
} else {
if (that.container.stage) that.container.stage.update();
}
if (that.zimAccessibility) {
var a = that.zimAccessibility;
setTimeout(function(){if (a.activatedObject) accessibilityClicker = a.activatedObject.zimTabTag;}, 50);
a.resize(that);
a.tabIndex = that.zimTabIndex;
}
that.toggled = true;
return that;
};
function checkBounds(x,y) {
x = Math.max(width/2, Math.min(that.container.getBounds().width-width/2, x));
y = Math.max(height/2, Math.min(that.container.getBounds().height-height/2, y));
return {x:x,y:y};
}
this.toggle = function(state) {
if (state===true) that.show();
else if (state===false) that.hide();
else if (that.container.contains(that)) that.hide();
else that.show();
return that;
};
if (style!==false) zim.styleTransforms(this, DS);
this.clone = function() {
var lX = label.x; // new Panes automatically center the label
var lY = label.y;
var p2 = that.cloneProps(new zim.Pane(width, height, label.clone(), backgroundColor, color, draggable, resets, modal, corner, backdropColor, shadowColor, shadowBlur, center, displayClose, backdropClose, zot(backing)?backing.clone():null, fadeTime, that.container, titleBar, titleBarColor, titleBarBackgroundColor, titleBarHeight, close, closeColor, style, this.group, inherit));
p2.label.x = lX;
p2.label.y = lY;
return p2;
};
};
zim.extend(zim.Pane, zim.Container, "clone", "zimContainer", false);
//-58
/*--
zim.Window = function(width, height, backgroundColor, borderColor, borderWidth, padding, corner, swipe, scrollBarActive, scrollBarDrag, scrollBarColor, scrollBarAlpha, scrollBarFade, scrollBarH, scrollBarV, slide, slideDamp, slideSnap, interactive, shadowColor, shadowBlur, paddingHorizontal, paddingVertical, scrollWheel, damp, titleBar, titleBarColor, titleBarBackgroundColor, titleBarHeight, draggable, boundary, onTop, close, closeColor, cancelCurrentDrag, fullSize, fullSizeColor, resizeHandle, style, group, inherit)
Window
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
Adds a window for content that can be swiped and scrolled.
NOTE: if zim namespace zns = true then this overwrites a JS Window - so the JS Window is stored as document.window
NOTE: set the enable property to false if animating the position of the whole Window
then set the enable property to true on the animate call function. See update() method for more.
NOTE: to add ZIM Swipe() to objects in window set the overrideNoSwipe parameter of Swipe to true
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var win = new Window({
height:300,
interactive:false,
padding:0,
slideDamp:.2
});
var container = new Container(); // make some content
var c; spacing = 10;
for (var i=0; i<4; i++) {
c = frame.makeCircles();
c.x = win.width/2;
c.y = c.width/2 + (c.width+spacing)*i;
container.addChild(c);
}
win.add(container); // add the content to the window
win.center();
stage.update();
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
width - (default 300) the width of the window
height - (default 200) the height of window - including the titleBar if there is a titleBar
backgroundColor - (default #333) background color (use clear - or "rbga(0,0,0,0)" for no background)
borderColor - (default #999) border color
borderWidth - (default 1) the thickness of the border
padding - (default 0) places the content in from edges of border (see paddingHorizontal and paddingVertical)
padding is ignored if content x and y not 0 - and really only works on top left - so more like an indent
corner - (default 0) is the rounded corner of the window (does not accept corner array - scrollBars are too complicated)
swipe - (default auto/true) the direction for swiping set to none / false for no swiping
also can set swipe to just vertical or horizontal
scrollBarActive - (default true) shows scrollBar (set to false to not)
scrollBarDrag - (default false) set to true to be able to drag the scrollBar
scrollBarColor - (default borderColor) the color of the scrollBar
scrollBarAlpha - (default .3) the transparency of the scrollBar
scrollBarFade - (default true) fades scrollBar unless being used
scrollBarH - (default true) if scrolling in horizontal is needed then show scrollBar
scrollBarV - (default true) if scrolling in vertical is needed then show scrollBar
slide - (default true) Boolean to throw the content when drag/swipe released
slideDamp - (default .6) amount the slide damps when let go 1 for instant, .01 for long slide, etc.
slideSnap - (default "vertical") "auto" / true, "none" / false, "horizontal"
slides past bounds and then snaps back to bounds when released
vertical snaps when dragging up and down but not if dragging horizontal
interactive - (default true) allows interaction with content in window
set to false and whole window will be swipeable but not interactive inside
shadowColor - (default rgba(0,0,0,.3)) the color of the shadow
shadowBlur - (default 20) set shadowBlur to -1 for no drop shadow
paddingHorizontal - (default padding) places content in from left and right (ignored if content x not 0)
paddingVertical - (default padding) places content in from top and bottom (ignored if content y not 0)
scrollWheel - (default true) scroll vertically with scrollWheel
damp - (default null) set to .1 for instance to damp the scrolling
titleBar - (default null - no titleBar) a String or ZIM Label title for the window that will be presented on a titleBar across the top
titleBarColor - (default "black") the text color of the titleBar if a titleBar is requested
titleBarBackgroundColor - (default "rgba(0,0,0,.2)") the background color of the titleBar if a titleBar is requested
titleBarHeight - (default fit label) the height of the titleBar if a titleBar is requested
draggable - (default true if titleBar) set to false to not allow dragging titleBar to drag window
boundary - (default null) set to ZIM Boundary() object - or CreateJS.rectangle()
onTop - (default true) set to false to not bring Window to top of container when dragging
close - (default false) - a close X for the top right corner that closes the window when pressed
closeColor - (default #555) - the color of the close X if close is requested
cancelCurrentDrag - (default false) - set to true to cancel window dragging when document window loses focus
this functionality seems to work except if ZIM is being used with Animate - so we have left it turned off by default
fullSize - (default false) - set to true to add a fullsize icon to the titleBar
to let user increase the size of the window to the frame - will turn into a reduce size icon
fullSizeColor - (default #555) - the color of the fullSize icon
resizeHandle - (default false) - set to true to rollover bottom right corner to resize window with resizeHandle
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
add(obj, replace) - adds obj to content container of window (at padding) must have bounds set
it is best to position and size obj first before adding
otherwise if adjusting to outside current content size then call update()
replace defaults to false and if set to true, removes all content then adds the obj.
returns window for chaining
remove(obj) - removes object from content container of window and updates - returns window for chaining
removeAll() - removes all objects from content container of window and updates - returns window for chaining
resize(width, height) - resizes the Window without scaling the content (also calls update() for scroll update)
width and height are optional - returns window for chaining
update() - resets window scrolling if perhaps the content gets bigger or smaller
update() does not quite update the dragBoundary due to a timeout in waiting for scrolls to be set
so if animating the position of a window, set the enable property to false before animating
then set the enable property to true on the animate call function
cancelCurrentDrag() - stop current drag on window - but add dragging back again for next drag
clone(recursive) - makes a copy with properties such as x, y, etc. also copied
recursive (default true) clones the window content as well (set to false to not clone content)
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), cache(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
backing - CreateJS Shape used for backing of Window
content - ZIM Container used to hold added content
enabled - get or set whether the Window is enabled
scrollEnabled - get or set whether the Window can be scrolled
scrollBar - data object that holds the following properties (with defaults):
you can set after object is made - call window.update() to see change
scrollBar.horizontal = zim Shape // the horizontal scrollBar rectangle shape
scrollBar.vertical = zim Shape // the vertical scrollBar rectangle shape
scrollBar.color = borderColor; // the color of the scrollBar
scrollBar.size = 6; // the width if vertical or the height if horizontal
scrollBar.minSize = 12; // for the height if vertical or the width if horizontal
scrollBar.spacing = 3 + size + borderWidth / 2;
scrollBar.margin = 0; // adds extra space only at end by scrollBars
scrollBar.corner = scrollBar.size / 2;
scrollBar.showTime = .5; // s to fade in
scrollBar.fadeTime = 3; // s to fade out
scrollX - gets and sets the content x position in the window (this will be negative)
scrollY - gets and sets the content y position in the window (this will be negative)
scrollXMax - gets the max we can scroll in x based on content width - window width (plus padding and margin)
scrollYMax - gets the max we can scroll in y based on content height - window height (plus padding and margin)
titleBar - access to the ZIM Container for the titleBar if there is a titleBar also has a backing property
titleBarLabel - access to the ZIM Label of the titleBar if there is a titleBar
close - access to the ZIM Shape if there is a close X
resizeHandle - access the ZIM Rectangle that makes up the resizeHandle when resizeHandle parameter is set to true
resizeHandle.removeFrom() would stop resize from being available and resizeHandle.addTo(window) would activate it again
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
dispatches a "select" event when clicked on in a traditional manner (fast click with little movement)
dispatches a "hoverover" event when rolled on without moving for 300 ms
dispatches a "hoverout" event when not hovering due to movement or mouseout on the window
dispatches a "scrolling" event when the window scrolls
dispatches a "close" event when the window is closed with the x on the titleBar if there is a titleBar
dispatches a "slidestart" event if slide is true and window starts sliding (on pressup)
dispatches a "slidestop" event if slide is true and window stops sliding
ALSO: see the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+58.1
zim.Window = function(width, height, backgroundColor, borderColor, borderWidth, padding, corner, swipe, scrollBarActive, scrollBarDrag, scrollBarColor, scrollBarAlpha, scrollBarFade, scrollBarH, scrollBarV, slide, slideDamp, slideSnap, interactive, shadowColor, shadowBlur, paddingHorizontal, paddingVertical, scrollWheel, damp, titleBar, titleBarColor, titleBarBackgroundColor, titleBarHeight, draggable, boundary, onTop, close, closeColor, cancelCurrentDrag, fullSize, fullSizeColor, resizeHandle, style, group, inherit) {
var sig = "width, height, backgroundColor, borderColor, borderWidth, padding, corner, swipe, scrollBarActive, scrollBarDrag, scrollBarColor, scrollBarAlpha, scrollBarFade, scrollBarH, scrollBarV, slide, slideDamp, slideSnap, interactive, shadowColor, shadowBlur, paddingHorizontal, paddingVertical, scrollWheel, damp, titleBar, titleBarColor, titleBarBackgroundColor, titleBarHeight, draggable, boundary, onTop, close, closeColor, cancelCurrentDrag, fullSize, fullSizeColor, resizeHandle, style, group, inherit";
var duo; if (duo = zob(zim.Window, arguments, sig, this)) return duo;
z_d("58.1");
this.zimContainer_constructor(null,null,null,null,false);
this.type = "Window";
this.group = group;
var DS = style===false?{}:zim.getStyle(this.type, this.group, inherit);
if (zot(width)) width=DS.width!=null?DS.width:300;
if (zot(height)) height=DS.height!=null?DS.height:200;
if (zot(backgroundColor)) backgroundColor=DS.backgroundColor!=null?DS.backgroundColor:"#333";
var originalBorderColor = borderColor;
var originalBorderWidth = borderWidth;
if (zot(borderColor)) borderColor=DS.borderColor!=null?DS.borderColor:"#999";
if (zot(borderWidth)) borderWidth=DS.borderWidth!=null?DS.borderWidth:1; // 0
if (zot(padding)) padding=DS.padding!=null?DS.padding:0;
if (zot(corner)) corner=DS.corner!=null?DS.corner:0;
if (zot(swipe)) swipe=DS.swipe!=null?DS.swipe:true; // true / auto, vertical, horizontal, false / none
if (zot(scrollBarActive)) scrollBarActive=DS.scrollBarActive!=null?DS.scrollBarActive:true;
if (zot(scrollBarDrag)) scrollBarDrag=DS.scrollBarDrag!=null?DS.scrollBarDrag:false;
if (zot(scrollBarColor)) scrollBarColor=DS.scrollBarColor!=null?DS.scrollBarColor:borderColor;
if (zot(scrollBarAlpha)) scrollBarAlpha=DS.scrollBarAlpha!=null?DS.scrollBarAlpha:.3;
if (zot(scrollBarFade)) scrollBarFade=DS.scrollBarFade!=null?DS.scrollBarFade:true;
if (zot(scrollBarH)) scrollBarH = DS.scrollBarH!=null?DS.scrollBarH:true;
if (zot(scrollBarV)) scrollBarV = DS.scrollBarV!=null?DS.scrollBarV:true;
if (scrollBarDrag) scrollBarFade = DS.scrollBarFade!=null?DS.scrollBarFade:false;
if (zot(slide)) slide=DS.slide!=null?DS.slide:true;
if (zot(slideDamp)) slideDamp=DS.slideDamp!=null?DS.slideDamp:.6;
if (zot(slideSnap)) slideSnap=DS.slideSnap!=null?DS.slideSnap:"vertical"; // true / auto, vertical, horizontal, false / none
if (zot(interactive)) interactive=DS.interactive!=null?DS.interactive:true;
if (zot(shadowColor)) shadowColor=DS.shadowColor!=null?DS.shadowColor:"rgba(0,0,0,.3)";
if (zot(shadowBlur)) shadowBlur=DS.shadowBlur!=null?DS.shadowBlur:20;
if (zot(paddingVertical)) paddingVertical=DS.paddingVertical!=null?DS.paddingVertical:padding;
if (zot(paddingHorizontal)) paddingHorizontal=DS.paddingHorizontal!=null?DS.paddingHorizontal:padding;
if (zot(scrollWheel)) scrollWheel = DS.scrollWheel!=null?DS.scrollWheel:true;
if (zot(titleBar)) titleBar = DS.titleBar!=null?DS.titleBar:null;
if (zot(titleBarColor)) titleBarColor = DS.titleBarColor!=null?DS.titleBarColor:null;
if (zot(titleBarBackgroundColor)) titleBarBackgroundColor = DS.titleBarBackgroundColor!=null?DS.titleBarBackgroundColor:null;
if (zot(titleBarHeight)) titleBarHeight = DS.titleBarHeight!=null?DS.titleBarHeight:null;
if (zot(draggable)) draggable = DS.draggable!=null?DS.draggable:null;
if (zot(boundary)) boundary = DS.boundary!=null?DS.boundary:null;
if (zot(onTop)) onTop = DS.onTop!=null?DS.onTop:null;
if (zot(close)) close = DS.close!=null?DS.close:null;
if (zot(closeColor)) closeColor = DS.closeColor!=null?DS.closeColor:null;
if (zot(cancelCurrentDrag)) cancelCurrentDrag = DS.cancelCurrentDrag!=null?DS.cancelCurrentDrag:false;
if (zot(fullSize)) fullSize = DS.fullSize!=null?DS.fullSize:null;
if (zot(fullSizeColor)) fullSizeColor = DS.fullSizeColor!=null?DS.fullSizeColor:null;
if (zot(resizeHandle)) resizeHandle = DS.resizeHandle!=null?DS.resizeHandle:null;
if (titleBar === false) titleBar = null;
if (!zot(titleBar)) {
if (zot(titleBarHeight)) titleBarHeight = 30;
height = height - titleBarHeight;
}
var that = this;
this.scrollX = this.scrollY = this.scrollXMax = this.scrollYMax = 0;
var backing = this.backing = new zim.Shape({style:false});
this.addChild(backing);
var mask = new createjs.Shape();
mask.type = "WindowBacking";
var mg = mask.graphics;
// make the mask in the update function
// when we know if there are vertical and horizontal scrollBars
this.addChild(mask);
var content = this.content = new zim.Container({style:false});
this.addChild(content);
content.mask = mask;
var stage;
if (!interactive) {
// hitArea makes the whole window draggable
// but then you can't interact with the content inside the window
var hitArea = new createjs.Shape();
}
if (borderWidth > 0) {
var border = new createjs.Shape();
this.addChild(border);
}
var titleBarCorner = titleBar?0:corner;
// we call this function at start and when resize() is called to resize the window without scaling content
function sizeWindow() {
that.setBounds(0,0,width,height);
backing.graphics.c().f(backgroundColor).rc(0,0,width,height,titleBarCorner,titleBarCorner,corner,corner);
if (shadowColor != -1 && shadowBlur > 0) backing.shadow = new createjs.Shadow(shadowColor, 4, 4, shadowBlur);
if (borderWidth > 0) {
if (corner) {
border.graphics.c().s(borderColor).ss(borderWidth, "square", "miter").rc(0,0,width,height,titleBarCorner,titleBarCorner,corner,corner);
} else {
border.graphics.c().s(borderColor).ss(borderWidth, "square", "miter").dr(0,0,width,height);
}
}
if (!zot(titleBarRect)) {
titleBarRect = titleBar.backing.widthOnly = that.width;
that.setBounds(0,-titleBarHeight,that.width,height+titleBarHeight);
}
if (that.close) {
if (titleBar) close.pos({x:width-Math.max(corner/2, 10)-close.width/2, y:titleBarHeight/2, reg:true});
else close.pos((Math.max(corner/2, 10))/2, close.height/2, true, false, that);
}
if (that.fullSize) {
fullSize.pos({x:width-Math.max(corner/2, 10)-fullSize.width/2, y:titleBarHeight/2, reg:true});
if (that.close) fullSize.mov(-close.width-10);
}
}
sizeWindow();
// this exposes an scrollBar data object so creators can adjust scrollBar properties
// note that these properties are set dynamically in the update function
var scrollBar = this.scrollBar = {}; // data object to expose scrollBar properties
scrollBar.color = scrollBarColor;
scrollBar.size = 6;
scrollBar.minSize = scrollBar.size*2; // if vertical scroll, this is vertical minSize where size is horizontal size
scrollBar.spacing = 3.5 + borderWidth / 2;
scrollBar.margin = 0;
scrollBar.corner = scrollBar.size / 2;
scrollBar.showTime = .5;
scrollBar.fadeTime = 3;
if (scrollBarActive) {
var hscrollBar = scrollBar.horizontal = new zim.Shape({style:false});
var hg = hscrollBar.graphics;
hscrollBar.alpha = scrollBarAlpha;
this.addChild(hscrollBar);
if (scrollBarDrag) hscrollBar.drag({localBounds: true});
var vscrollBar = scrollBar.vertical = new zim.Shape({style:false});
var vg = vscrollBar.graphics;
vscrollBar.alpha = scrollBarAlpha;
this.addChild(vscrollBar);
if (scrollBarDrag) vscrollBar.drag({localBounds: true});
}
var hProportion;
var vProportion;
var hCheck;
var vCheck;
var gap;
var contentWidth;
var contentHeight;
var hEvent;
var vEvent;
var dTimeout;
this.update = function() {
if (scrollBarActive) {
// clear the scrollBars and remake anytime this function is called
// as these may change as people add and remove content to the Window
hg.clear(); // horizontal scrollBar
vg.clear(); // vertical scrollBar
}
// assume no gap at left and top
// gap is applied in x if there is a scroll in y
// gap is applied in y if there is a scroll in x
gap = (scrollBarActive) ? scrollBar.size+scrollBar.spacing*2 : 0;
contentWidth = content.getBounds()?content.getBounds().width:0;
contentHeight = content.getBounds()?content.getBounds().height:0;
// note, the contentWidth and contentHeight include ONE padding
hCheck = (scrollBarH && contentWidth > width-paddingHorizontal && (scrollBarActive || swipe === true || swipe == "auto" || swipe == "horizontal"));
vCheck = (scrollBarV && contentHeight > height-paddingVertical && (scrollBarActive || swipe === true || swipe == "auto" || swipe == "vertical"));
that.scrollXMax = contentWidth+paddingHorizontal*2-width+(vCheck?gap+scrollBar.margin:0);
that.scrollYMax = contentHeight+paddingVertical*2-height+(hCheck?gap+scrollBar.margin:0);
// set mask dynamically as scrollBars may come and go affecting the mask size slightly
mg.clear();
var xx = borderWidth/2;
var yy = borderWidth/2;
var ww = width-((vCheck && scrollBarActive)?scrollBar.size+scrollBar.spacing*2:0)-(vCheck?0:borderWidth);
var hh = height-((hCheck && scrollBarActive)?scrollBar.size+scrollBar.spacing*2:0)-(hCheck?0:borderWidth);
mg.f("rgba(0,0,0,0)").rc(xx,yy,ww,hh,titleBarCorner,titleBarCorner,vCheck&&scrollBarActive?0:corner,hCheck&&scrollBarActive?0:corner);
mask.setBounds(that.getBounds().x,that.getBounds().y,that.getBounds().width, that.getBounds().height);
zim.expand(mask, 0);
if (!interactive) {
hitArea.graphics.c().f("red").dr(xx,yy,ww,hh);
content.hitArea = hitArea;
}
var edgeAdjust = Math.max(corner, Math.min(scrollBar.corner, scrollBar.spacing));
var edgeLeft = edgeAdjust + borderWidth/2;
var edgeRight = edgeAdjust + (vCheck?gap:0) + borderWidth/2;
var edgeTop = edgeAdjust + borderWidth/2;
var edgeBottom = edgeAdjust + (hCheck?gap:0) + borderWidth/2;
var scrollBarLength;
if (hCheck && scrollBarActive) {
scrollBarLength = Math.max(scrollBar.minSize, (width-edgeLeft-edgeRight) * (width-edgeLeft-edgeRight) / (contentWidth + paddingHorizontal + scrollBar.margin));
hg.f(scrollBar.color).rr(0,0,scrollBarLength,scrollBar.size,scrollBar.corner);
hscrollBar.x = edgeLeft;
hscrollBar.y = height-scrollBar.size-scrollBar.spacing;
// for swiping window:
hProportion = new zim.Proportion(-that.scrollXMax, 0, edgeLeft, width-scrollBarLength-edgeRight, -1);
if (scrollBarDrag) {
hscrollBar.setBounds(0,0,scrollBarLength,scrollBar.size);
// drag rect for scrollBar
var rect = new createjs.Rectangle(
edgeLeft, hscrollBar.y, width-scrollBarLength-edgeLeft-edgeRight, 0
);
hscrollBar.dragBoundary(rect);
hscrollBar.proportion = new zim.Proportion(
rect.x, rect.x+rect.width, 0, -that.scrollXMax
);
hscrollBar.off("pressmove", hEvent);
hEvent = hscrollBar.on("pressmove", function() {
that.dispatchEvent("scrolling");
if (hitArea) {
// move hitarea to display box
hitArea.x = -content.x;
hitArea.y = -content.y;
}
content.x = hscrollBar.proportion.convert(hscrollBar.x);
});
}
}
if (vCheck && scrollBarActive) {
scrollBarLength = Math.max(scrollBar.minSize, (height-edgeTop-edgeBottom) * (height-edgeTop-edgeBottom) / (contentHeight + paddingVertical + scrollBar.margin));
vg.f(scrollBar.color).rr(0,0,scrollBar.size,scrollBarLength,scrollBar.corner);
vscrollBar.x = width-scrollBar.size-scrollBar.spacing;
vscrollBar.y = edgeTop;
// for swiping window:
vProportion = new zim.Proportion(-that.scrollYMax, 0, edgeTop, height-scrollBarLength-edgeBottom, -1);
if (scrollBarDrag) {
vscrollBar.setBounds(0,0,scrollBar.size,scrollBarLength);
// drag rect for scrollBar
var rect = new createjs.Rectangle(
vscrollBar.x, edgeTop, 0, height-scrollBarLength-edgeTop-edgeBottom
);
vscrollBar.dragBoundary(rect);
vscrollBar.proportion = new zim.Proportion(
rect.y, rect.y+rect.height, 0, -that.scrollYMax
);
vscrollBar.off("pressmove", vEvent);
vEvent = vscrollBar.on("pressmove", function() {
that.dispatchEvent("scrolling");
if (hitArea) {
// move hitarea to display box
hitArea.x = -content.x;
hitArea.y = -content.y;
}
desiredY = content.y = vscrollBar.proportion.convert(vscrollBar.y);
});
}
}
movescrollBars();
clearTimeout(that.d2Timeout);
that.d2Timeout = setTimeout(function(){
if (hscrollBar && hscrollBar.proportion) content.x = hscrollBar.proportion.convert(hscrollBar.x);
if (vscrollBar && vscrollBar.proportion) content.y = vscrollBar.proportion.convert(vscrollBar.y);
}, 50);
clearTimeout(that.dTimeout);
that.dTimeout = setTimeout(function(){setdragBoundary();}, 300);
setdragBoundary();
};
this.resize = function(w, h) {
if (zot(w)) w = width;
if (zot(h)) h = height;
var min = 20;
if (titleBar) min = titleBarLabel.x+titleBarLabel.width+10;
if (w < min) w = min;
if (h < 20) h = 20;
width = w;
height = h;
sizeWindow();
for (var i=0; i<content.numChildren; i++) {
var cont = content.getChildAt(i);
if (cont.type == "Wrapper") resizeWrapper(cont);
}
that.update();
desiredY = content.y;
if (damp) dampY.immediate(desiredY);
return that;
};
if (!zot(titleBar)) {
if (zot(draggable)) draggable = true;
if (typeof titleBar == "string") titleBar = new zim.Label({
text:titleBar, color:titleBarColor, size:DS.size!=null?DS.size:20,
backing:"ignore", shadowColor:"ignore", shadowBlur:"ignore", padding:"ignore", backgroundColor:"ignore",
group:this.group
});
var titleBarLabel = that.titleBarLabel = titleBar;
if (zot(titleBarBackgroundColor)) titleBarBackgroundColor = "rgba(0,0,0,.2)";
that.titleBar = titleBar = new zim.Container(width, titleBarHeight, null, null, false).centerReg(that).mov(0,-height/2-titleBarHeight/2);
var titleBarRect = that.titleBar.backing = new zim.Rectangle(width+borderWidth, titleBarHeight, titleBarBackgroundColor, null, null, [corner*.95, corner*.95, 0, 0], true, null, false).center(titleBar);
titleBarLabel.center(titleBar).pos({x:Math.max(corner/2, Math.max(10, padding)), reg:true});
that.regX = 0; that.regY = -titleBarHeight;
that.setBounds(0,-titleBarHeight,width,height+titleBarHeight);
if (draggable) {
titleBar.cursor = "pointer";
titleBar.on("mousedown", function() {
that.drag({rect:boundary, currentTarget:true, onTop:onTop});
});
titleBar.on("pressup", function() {
that.noDrag(false);
});
} else {
titleBar.on("mousedown", function () {});
}
}
if (close) {
if (zot(closeColor)) closeColor = "#555";
var close = that.close = new zim.Shape(-40,-40,80,80,null,false);
close.graphics.f(closeColor).p("AmJEVIEUkTIkXkWIB4h5IEWEYIETkTIB4B3IkTESIEQERIh4B4IkRkRIkSEVg"); // width about 90 reg in middle
if (titleBar) close.centerReg(that).scaleTo(titleBar, null, 50).pos({x:width-Math.max(corner/2, 10)-close.width/2, y:titleBarHeight/2, reg:true}).expand(40);
else {
close.sca(.3).pos((Math.max(corner/2, 10))/2, close.height/2, true, false, that).expand(40);
}
close.cursor = "pointer";
close.expand();
close.on((!zns?ACTIONEVENT=="mousedown":zim.ACTIONEVENT=="mousedown")?"mousedown":"click", function(){
var ss = that.stage;
that.removeFrom();
that.dispatchEvent("close");
if (ss) ss.update();
});
}
if (!zot(titleBar)) {
if (fullSize) {
if (zot(fullSizeColor)) fullSizeColor = "#555";
var fullSize = that.fullSize = new zim.Rectangle(80,80,zim.faint,fullSizeColor,16);
var reduceSize = new zim.Shape()
.s(fullSizeColor).ss(16)
.mt(-19.6,-20.6)
.lt(-19.6,-40).lt(40,-40).lt(40,20.7).lt(19.6,20.7).lt(19.6,40).lt(-40,40).lt(-40,-20.6).lt(-19.6,-20.6).lt(19.6,-20.6).lt(19.6,20.7)
.addTo(that.fullSize)
.mov(40,40)
.alp(0);
fullSize.centerReg(that)
.scaleTo(titleBar, null, 42)
.pos({x:width-Math.max(corner/2, 10)-fullSize.width/2, y:titleBarHeight/2, reg:true})
.expand(40);
if (that.close) fullSize.mov(-close.width-10);
fullSize.cursor = "pointer";
fullSize.expand();
that.fullCheck = false;
var lastWidth = width;
var lastHeight = height;
var lastX = that.x;
var lastY = that.y;
fullSize.on((!zns?ACTIONEVENT=="mousedown":zim.ACTIONEVENT=="mousedown")?"mousedown":"click", function(){
if (that.fullCheck) {
that.resize(lastWidth, lastHeight-titleBar.height);
that.x = lastX;
that.y = lastY;
that.fullCheck = false;
reduceSize.alpha = 0;
that.fullSize.getChildAt(0).alpha = 1;
} else {
lastWidth = that.width;
lastHeight = that.height;
lastX = that.x;
lastY = that.y;
that.resize(that.parent.width, that.parent.height);
that.x = 0;
that.y = 0;
that.fullCheck = true;
reduceSize.alpha = 1;
that.fullSize.getChildAt(0).alpha = .01;
}
if (that.stage) that.stage.update();
});
}
}
if (resizeHandle) {
var handle = that.resizeHandle = new zim.Rectangle(25, 25, zim.grey, zim.white)
.alp(.01)
.centerReg()
.rot(45)
.hov(.5)
.loc(0, 0, that)
.mov(that.width, that.height - (that.titleBar ? that.titleBar.height : 0))
.drag();
handle.on("pressmove", function () {
that.resize(handle.x, handle.y);
});
handle.on("pressup", placeHandle);
if (that.titleBar) that.titleBar.on("pressup", placeHandle);
function placeHandle() {
handle
.loc(0, 0, that)
.top()
.alp(.01)
.mov(that.width, that.height - (that.titleBar ? that.titleBar.height : 0));
}
}
function resizeWrapper(cont) {
if (cont.align == "right") {
cont.x=paddingHorizontal;
cont.resize(that.width-(vCheck?scrollBar.size+scrollBar.spacing*2:paddingHorizontal)-paddingHorizontal*2);
} else if (cont.align == "center" || cont.align == "middle") {
cont.resize(that.width-(vCheck?scrollBar.size+scrollBar.spacing*2:0)-paddingHorizontal*2);
} else {
cont.resize(that.width-(vCheck?scrollBar.size+scrollBar.spacing*2:0)-paddingHorizontal*2);
}
cont.alpha = cont.wrapperLastAlpha;
}
// METHODS to add and remove content from Window
this.add = function(c, replace) {
makeDamp(c);
if (!c.getBounds()) {zog("SwipeBox.add() - please add content with bounds set"); return;}
if (replace) that.removeAll();
content.addChild(c);
if (c.type == "Wrapper") {
vscrollBar.alpha = 0;
scrollBarH = false;
c.wrapperLastAlpha = c.alpha;
c.alpha = 0;
this.added(function(){
resizeWrapper(c);
that.resize();
hscrollBar.alpha = 1;
vscrollBar.alpha = 1;
});
}
if (c.x == 0) c.x = paddingHorizontal;
if (c.y == 0) c.y = paddingVertical;
that.update();
return that;
};
this.remove = function(c) {
content.removeChild(c);
that.update();
return that;
};
this.removeAll = function() {
content.removeAllChildren();
that.update();
return that;
};
function setdragBoundary(on) {
if (zot(stage)) stage = that.stage || zimDefaultFrame.stage;
if (zot(on)) on = true;
if (on) zim.dragBoundary(content, new createjs.Rectangle(0, 0, hCheck?-that.scrollXMax:0, vCheck?-that.scrollYMax:0));
else zim.dragBoundary(content, new createjs.Rectangle(-1000, -1000, stage.width+2000, stage.height+2000));
}
var swipeCheck = false;
if (swipe) {
content.on("mousedown", function() {
if (!swipeCheck) zim.Ticker.add(swipeMovescrollBars, content.stage);
swipeCheck = true;
if (hCheck && scrollBarActive) if (scrollBarFade) zim.animate(hscrollBar, {alpha:scrollBarAlpha}, scrollBar.showTime);
if (vCheck && scrollBarActive) if (scrollBarFade) zim.animate(vscrollBar, {alpha:scrollBarAlpha}, scrollBar.showTime);
});
}
function swipeMovescrollBars() {
// this is being called by the swipe which has its own damping
// so we need to set the desiredY and then move the scrollBars
// as the movescrollBars needs to run independently - so both types of damp can controll it
desiredY = content.y;
if (damp) dampY.immediate(desiredY);
if (scrollBarActive) movescrollBars();
}
function movescrollBars() {
that.dispatchEvent("scrolling");
if (hitArea) {
// move hitarea to display box
hitArea.x = -content.x;
hitArea.y = -content.y;
}
if (hCheck && scrollBarActive) hscrollBar.x = hProportion.convert(content.x);
if (vCheck && scrollBarActive) vscrollBar.y = vProportion.convert(content.y);
}
// may add content before adding Window to stage...
this.on("added", function() {
setDrag(50);
}, null, true); // once
function setDrag(delay) {
if (zot(delay)) delay = 100;
makeDamp(that);
if (!swipe) return;
setTimeout(function(){
if (content) {
zim.drag({
obj:content,
currentTarget:true,
localBounds:true,
slide:slide,
slideDamp:slideDamp,
slideSnap:(scrollBarH && (swipe===true||swipe=="auto"||swipe=="horizontal")) || (scrollBarV && (swipe===true||swipe=="auto"||swipe=="vertical"))?slideSnap:false
});
content.removeAllEventListeners("slidestart");
content.on("slidestart", function () {
that.dispatchEvent("slidestart");
});
content.removeAllEventListeners("slidestop");
content.on("slidestop", function (e) {
if (slide) stageUp(e);
that.dispatchEvent("slidestop");
});
if (content.getBounds() && content.getBounds().width > 0) {
setdragBoundary();
}
}
}, delay);
}
this.cancelCurrentDrag = function() {
if (that.content) that.content.noDrag(false);
setTimeout(function(){
if (content) {
zim.drag({
obj:content,
currentTarget:true,
localBounds:true,
slide:slide, slideDamp:slideDamp,
slideSnap:(scrollBarH && (swipe===true||swipe=="auto"||swipe=="horizontal")) || (scrollBarV && (swipe===true||swipe=="auto"||swipe=="vertical"))?slideSnap:false
});
if (content.getBounds() && content.getBounds().width > 0) {
setdragBoundary();
}
}
}, 300);
};
var stage, stageEvent;
this.added(function (_stage) {
stage = _stage;
stageEvent = stage.on("stagemousemove", function (e) {
that.windowMouseX = e.stageX/zim.scaX;
that.windowMouseY = e.stageY/zim.scaY;
});
});
if (slide) {
content.on("slidestop", stageUp);
} else {
content.on("mousedown", function() {
content.stage.on("stagemouseup", stageUp, null, true);
});
}
if (cancelCurrentDrag) {
that.blurEvent = function () {
that.cancelCurrentDrag();
stageUp();
};
document.window.addEventListener("blur", that.blurEvent);
}
function stageUp(e) {
zim.Ticker.remove(swipeMovescrollBars);
swipeCheck = false;
if (hCheck) if (scrollBarFade && scrollBarActive) zim.animate(hscrollBar, {alpha:0}, scrollBar.fadeTime);
if (vCheck) if (scrollBarFade && scrollBarActive) zim.animate(vscrollBar, {alpha:0}, scrollBar.fadeTime);
}
if (interactive) {
// dispatches SELECT (click) and HOVEROVER (500 ms) and gives mouseX and mouseY on content
// CLICKS (in the traditional sense rather than a mouseup replacement)
var downLoc;
var downTime;
content.on("mousedown", function(e){stage=e.target.stage; downLoc=e.stageX/zim.scaX; downTime=Date.now();});
content.on("click", function(e){
if (Date.now()-downTime<600 && Math.abs(e.stageX/zim.scaX-downLoc)<5) {
that.contentMouse = content.globalToLocal(e.stageX/zim.scaX, e.stageY/zim.scaY);
that.dispatchEvent("select");
}
});
// HOVER (must stay within thresh pixels for pauseTime ms)
content.on("mouseover", moveOn);
content.on("mouseout", moveOff);
var startTime;
function moveOn() {
startTime=Date.now();
zim.Ticker.add(timeMouse, content.stage);
}
function moveOff() {
if (!hoverOutCalled) {
that.dispatchEvent("hoverout");
hoverOutCalled = true;
}
zim.Ticker.remove(timeMouse);
}
var lastMouseX = 0;
var lastMouseY = 0;
var lastReportX = 0;
var lastReportY = 0;
var pauseTime = 300;
var thresh = 2;
var hoverOutCalled = false;
function timeMouse() {
if (!content.stage) {
if (!hoverOutCalled) {
that.dispatchEvent("hoverout");
hoverOutCalled = true;
}
zim.Ticker.remove(timeMouse);
return;
}
if (Math.abs(lastMouseX-that.windowMouseX) > thresh || Math.abs(lastMouseY-that.windowMouseY) > thresh) {
if (!hoverOutCalled) {
that.dispatchEvent("hoverout");
hoverOutCalled = true;
}
startTime=Date.now();
lastMouseX=that.windowMouseX;
lastMouseY=that.windowMouseY;
} else {
if (Date.now()-startTime > pauseTime) {
if (Math.abs(lastReportX-that.windowMouseX) > thresh || Math.abs(lastReportY-that.windowMouseY) > thresh) {
that.contentMouse = content.globalToLocal(that.windowMouseX, that.windowMouseY);
that.dispatchEvent("hoverover");
lastReportX=that.windowMouseX;
lastReportY=that.windowMouseY;
hoverOutCalled = false;
}
startTime=Date.now();
}
}
}
}
var scrollEvent1;
var scrollEvent2;
var scrollEvent3;
var desiredY = that.scrollY;
that.scrollWindow = function scrollWindow(e) {
if (vCheck && that.stage && that.hitTestPoint(that.windowMouseX, that.windowMouseY) && that.contains(that.stage.getObjectUnderPoint(that.windowMouseX*zim.scaX, that.windowMouseY*zim.scaY))) {
if (zot(e)) e = event;
var delta = e.detail ? e.detail*(-19) : e.wheelDelta;
if (zot(delta)) delta = e.deltaY*(-19);
desiredY += delta;
desiredY = Math.max(-that.scrollYMax, Math.min(0, desiredY));
if (!damp) {
that.scrollY = desiredY;
content.stage.update();
}
}
}
if (scrollWheel) {
window.addEventListener("mousewheel", that.scrollWindow);
window.addEventListener("wheel", that.scrollWindow);
window.addEventListener("DOMMouseScroll", that.scrollWindow);
}
var dampCheck = false;
var dampY;
function makeDamp(obj) {
if (damp && !dampCheck && obj.stage) {
dampCheck = true;
dampY = new zim.Damp(that.scrollY, damp);
that.dampTicker = zim.Ticker.add(function() {
if (swipeCheck) return;
if (!zot(desiredY)) that.scrollY = dampY.convert(desiredY);
}, obj.stage);
}
}
this._enabled = true;
Object.defineProperty(that, 'enabled', {
get: function() {
return that._enabled;
},
set: function(value) {
if (!value) {
clearTimeout(that.dTimeout);
zim.noDrag(content);
} else {
setDrag();
}
zenable(that, value);
}
});
this._scrollEnabled = true;
Object.defineProperty(that, 'scrollEnabled', {
get: function() {
return that._scrollEnabled;
},
set: function(value) {
if (!value) {
clearTimeout(that.dTimeout);
zim.noDrag(content);
if (scrollBarDrag) {
if (hEvent) hscrollBar.mouseEnabled = false; // hscrollBar.off("pressmove", vEvent);
if (vEvent) vscrollBar.mouseEnabled = false; // vscrollBar.off("pressmove", vEvent);
}
window.removeEventListener("mousewheel", that.scrollWindow);
window.removeEventListener("wheel", that.scrollWindow);
window.removeEventListener("DOMMouseScroll", that.scrollWindow);
} else {
setDrag();
if (scrollBarDrag) {
if (hEvent) hscrollBar.mouseEnabled = true; //hEvent = hscrollBar.on("pressmove", vEvent);
if (vEvent) vscrollBar.mouseEnabled = true; //vEvent = vscrollBar.on("pressmove", vEvent);
}
window.addEventListener("mousewheel", that.scrollWindow);
window.addEventListener("wheel", that.scrollWindow);
window.addEventListener("DOMMouseScroll", that.scrollWindow);
}
that._scrollEnabled = value;
}
});
Object.defineProperty(that, 'scrollX', {
get: function() {
return content.x;
},
set: function(value) {
content.x = value;
clearTimeout(that.d2Timeout);
if (content.zimDragImmediate) content.zimDragImmediate(content.x, content.y);
movescrollBars();
}
});
Object.defineProperty(that, 'scrollY', {
get: function() {
return content.y;
},
set: function(value) {
content.y = value;
clearTimeout(that.d2Timeout);
if (content.zimDragImmediate) content.zimDragImmediate(content.x, content.y);
movescrollBars();
}
});
if (style!==false) zim.styleTransforms(this, DS);
this.clone = function(recursive) {
if (zot(recursive)) recursive = true;
var w = that.cloneProps(new zim.Window(width, height, backgroundColor, originalBorderColor, originalBorderWidth, padding, corner, swipe, scrollBarActive, scrollBarDrag, scrollBar.color, scrollBarAlpha, scrollBarFade, scrollBarH, scrollBarV, slide, slideDamp, slideSnap, interactive, shadowColor, shadowBlur, paddingHorizontal, paddingVertical, titleBar, titleBarColor, titleBarBackgroundColor, titleBarHeight, draggable, boundary, onTop, close, closeColor, cancelCurrentDrag, fullSize, fullSizeColor, resizeHandle, style, group, inherit));
if (recursive) {
that.content.cloneChildren(w.content);
w.update();
}
return w;
};
this.doDispose = function(a,b,disposing) {
if (scrollWheel) {
window.removeEventListener("mousewheel", that.scrollWindow);
window.removeEventListener("wheel", that.scrollWindow);
window.removeEventListener("DOMMouseScroll", that.scrollWindow);
}
if (stageEvent && stage) stage.off("stagemousemove", stageEvent);
if (that.resizeHandle) that.resizeHandle.removeAllEventListeners();
if (that.blurEvent) document.window.removeEventListener("blur", that.blurEvent);
if (typeof timeMouse != "undefined") zim.Ticker.remove(timeMouse);
if (!zot(swipeMovescrollBars)) zim.Ticker.remove(swipeMovescrollBars);
if (!disposing) this.zimContainer_dispose(true);
content = that.content = null;
return true;
};
};
zim.extend(zim.Window, zim.Container, ["clone", "dispose"], "zimContainer", false);
zim.Window.prototype.dispose = function(disposing) {return this.doDispose(null,null,disposing);};
//-58.1
/*--
zim.Page = function(width, height, color, color2, vertical, pattern, scalePattern, cache, style, group, inherit)
Page
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
ZIM Page() is a Container() with Rectangle() backing.
For years, many questions were asked - how to make a page in ZIM.
Now, we have decided to officially answer that! ZIM Page().
An easy way to handle linear gradients is provided as well as a custom background
such as a ZIM Pizzazz pattern.
To keep things brief, Page is expected to fit the stage.
So border, corner, dashed, etc. has been left out.
If the page is smaller and these are desired...
old-school-it and make a Container and add the desired Rectangle.
SEE: https://zimjs.com/cat/page.html
SEE: Docs for ZIM Pages() as well to handle multiple pages.
SEE: ZIM Panel(), ZIM Pane() and ZIM Window() for alternatives.
NOTE A Page object will start with one child or two children if a pattern is specified.
NOTE Do not use Page with Layout as it will overlay the region backgroundColors - instead use a Container
NOTE as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
EXAMPLE
var page = new Page(stageW, stageH, red, pink).addTo();
page.title = new Label("A Page!").loc(100,100,page);
page.content = new Circle().center(page);
page.nav = new Tabs().pos(0,100,CENTER,BOTTOM,page);
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
width - (default zimDefaultFrame.width) the width of the Page
but backing is sized to screen.width if no width is provided
height - (default zimDefaultFrame.height) the height of the Page
but backing is sized to screen.height if no height is provided
color - (default zim.light) the color of the page
color2 - (default null) a second color which would form a zim.GradientColor() as the color
vertical - (default true) the direction for the gradient if there is a gradient
pattern - (default null) a DisplayObject that will be added to the page above the backing
For instance, import ZIM pizzazz_03.js and use:
pizzazz.makePattern("slants", series([grey,dark]), 20, 52, 40).alp(.2)
scalePattern - (default "fill") scale the pattern so it fills the window (formerly "bigger" or "outside")
set to false for no scaling or:
"fit" fits inside the Page keeping proportion (formerly "smallest")
"fill" fills the Page keeping proportion (formerly "biggest" or "outside")
"full" keeps both x and y scales - may stretch object (formerly "both")
cache - (default false or true for gradient or pattern) whether the backing and pattern is cached
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
clone(recursive) - makes a copy with properties such as x, y, etc. also copied
recursive (default false) - set to true to copy children of the object (these will not get custom properties, no drag, events, etc.)
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), cache(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
backing - access the backing Rectangle
pattern - access the pattern object if one is provided
color - get or set the color of the backing Rectangle
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
EVENTS
See the CreateJS Easel Docs for Container events such as:
added, click, dblclick, mousedown, mouseout, mouseover, pressdown (ZIM), pressmove, pressup, removed, rollout, rollover
--*///+58.3
zim.Page = function(width, height, color, color2, vertical, pattern, scalePattern, cache, style, group, inherit) {
var sig = "width, height, color, color2, vertical, pattern, scalePattern, cache, style, group, inherit";
var duo; if (duo = zob(zim.Page, arguments, sig, this)) return duo;
z_d("58.3");
this.group = group;
var DS = style===false?{}:zim.getStyle("Page", this.group, inherit);
if (zot(width)) width=DS.width!=null?DS.width:zdf.width;
if (zot(height)) height=DS.height!=null?DS.height:zdf.height;
this.zimContainer_constructor(0,0,width,height,false);
this.type = "Page";
// if (zot(width)) width = screen?screen.width:zdf.width;
// if (zot(height)) height = screen?screen.height:zdf.height;
var that = this;
if (zot(vertical)) vertical=DS.vertical!=null?DS.vertical:true;
if (zot(color)) color=DS.color!=null?DS.color:zim.light;
if (zot(color2)) color2=DS.color2!=null?DS.color2:null;
if (zot(pattern)) pattern=DS.pattern!=null?DS.pattern:null;
if (zot(scalePattern)) scalePattern=DS.scalePattern!=null?DS.scalePattern:"fill";
if (zot(cache)) cache=DS.cache!=null?DS.cache:false;
if (!zot(color2)) {
color = new zim.GradientColor([color, color2], [0,1], 0,0, vertical?0:width, vertical?height:0);
color2 = null;
}
var backing = this.backing = new zim.Rectangle({width:width, height:height, color:color, style:false}).addTo(this);
if (zot(cache) && (!zot(color2) || !zot(pattern))) cache = true;
if (cache) backing.cache();
if (!zot(pattern)) {
this.pattern = pattern.addTo(this);
if (scalePattern) pattern.scaleTo(this, 100, 100, scalePattern).center(this);
if (cache) pattern.cache();
}
Object.defineProperty(that, 'color', {
get: function() {
return color;
},
set: function(value) {
if (zot(value)) value = "black";
color = value;
that.backing.color = value;
}
});
if (style!==false) zim.styleTransforms(this, DS);
this.clone = function(recursive) {
if (zot(recursive)) recursive = false;
if (color.type) color2 = null;
var w = that.cloneProps(new zim.Page(width, height, color, color2, vertical, pattern, scalePattern, cache, style, group, inherit));
if (recursive) {
that.cloneChildren(w);
}
return w;
};
};
zim.extend(zim.Page, zim.Container, ["clone"], "zimContainer", false);
//-58.3
/*--
zim.Layer = function(width, height, titleBar, titleBarContainer, backgroundColor, rollBackgroundColor, selectedBackgroundColor, selectedRollBackgroundColor, color, rollColor, selectedColor, selectedRollColor, borderWidth, borderColor, dashed, transformObject, titleBarWidth, titleBarHeight, titleBarX, titleBarY, titleBarDraggable, close, closeColor, closeBackgroundColor, closeIndicatorColor, anchor, style, group, inherit)
Layer
zim class - extends a zim.Container which extends a createjs.Container
DESCRIPTION
Layer is a ZIM Container with transform controls.
ZIM transform() objects have their mousechildren turned off so they can be dragged and transformed.
This means there can be no interactivity inside the transformed object.
Layer provides a solution to nest transformed objects in transformable containers.
It does so by providing a titleBar that can be used to turn on and off the transform of the container
and allow its contents to be transformed when the transform controls of the Layer are turned off.
This is more than just hiding the transform tools but rather removing and adding them.
The Layer titleBar will always remain visible on the stage
If the Layer is moved (not by its titleBar) so that the titleBar hits the edge,
then the titleBar will become anchored to the edge (unless anchor is set to false)
This creates an independent titleBar that can be moved to any location.
The titleBarPos() method can also be used to separate the titleBar at any time.
Drop the titleBar on the top left corner of the Layer or doubleClick it to snap it back on to the layer
NOTE: Layers can be added to a Transform Manager and saved with the persist sytem.
NOTE: Layers can be added to Layers (nested) along with any other type of DisplayObject content.
NOTE: as of ZIM 5.5.0 the zim namespace is no longer required (unless zns is set to true before running zim)
SEE: https://zimjs.com/explore/layer.html
EXAMPLE
// adding the Layers above the content will allow pressing Layer titleBar objects inside other Layers
// adding everything right on the stage would not allow pressing titleBars inside other Layers - either way may be best, depending on content
var content = new Container(stageW, stageH).addTo();
var layers = new Container(stageW, stageH).addTo();
// create an outer layer with two inner layers - one holding a circle and the other two circles
var layer0 = new Layer(800, 500, "LAYER 0", layers).center(content);
var layer1 = new Layer(300, 400, "LAYER 1", layers).loc(50,50,layer0);
var circle1 = new Circle(50, pink).center(layer1).transform({visible:false});
var layer2 = new Layer(300, 400, "LAYER 2", layers).pos(50,50,true,false,layer0);
var circle2 = new Circle(50, green).center(layer2).mov(0, -80).transform({visible:false});
var circle3 = new Circle(50, blue).center(layer2).mov(0, 80).transform({visible:false});
// optionally store transforms
var t = new TransformManager([layer0, layer1, layer2, circle1, circle2, circle3], "layersID");
// t.clearPersist("layersID")
timeout(1, function () {
layer2.resetTitleBar();
layer2.turnOn();
// if moving manually, must call resize()
layer2.mov(30);
layer2.resize();
stage.update();
});
END EXAMPLE
PARAMETERS
** supports DUO - parameters or single object with properties below
** supports OCT - parameter defaults can be set with STYLE control (like CSS)
width - (default 500) the width of the Layer Container
height - (default 500) the height of the Layer Container not including the titleBar (which is not in the Container)
titleBar - (default "LAYER") a String or ZIM Label for the titleBar
titleBarContainer - (default null - zdf' stage) a container for the titleBar
can group these with other Layers and hide them all by hiding the container for instance
this also can help layer the titleBars above the content
backgroundColor - (default #eee) the background color of the titleBar
rollBackgroundColor - (default #fff) the roll background color of the titleBar
selectedBackgroundColor - (default #666) the selected background color of the titleBar
color - (default #666) the color of the titleBar text
rollColor - (default #666) the roll color of the titleBar text
selectedColor - (default #ddd) the selected color of the titleBar text
borderWidth - (default 1) the width of the ghost outline when the Layer is not selected
to adjust the transform controls border width use the transformObject parameter and set the borderWidth property
borderColor - (default borderColor) the color of the ghost outline when the Layer is not selected
to adjust the transform controls border color use the transformObject parameter and set the borderColor property
dashed - (default true) the dashed of the ghost outline when the Layer is not selected
to adjust the transform controls border dashed use the transformObject parameter and set the dashed property
transformObject - (default {borderColor:selectedBackgroundColor}) any of the transform parameters as an object literal
certain properties are overwritten by Layer as follows:
{events:true, visible:false, ghostColor:borderColor, ghostWidth:borderWidth, ghostDashed:dashed, ghostHidden:true}
use the transformControls.show() to show the transform controls once the Layer is made for instance:
timeout(100, function(){layer.transformControls.show();}); // a timeout is needed as Layer gets created - sorry.
titleBarWidth - (default 100 + 30 if close) the width of the titleBar. 30 pixels will be added if close is true
titleBarHeight - (default 40) the height of the titleBar
titleBarX - (default null) the starting x position of the titleBar - see also titleBarPos() and resetTitleBar() methods
titleBarY - (default null) the starting y position of the titleBar - see also titleBarPos() and resetTitleBar() methods
titleBarDraggable - (default true) set to false to not let the titleBar be dragged.
this is useful with the titleBarPos() to create a stationary menu for the layers - for instance along the edge like tabs
close - (default true) - set to false to not use the close checkbox
WARNING: without the close checkbox, the user may make the layer bigger than the stage and not be able to deselect the layer
closeColor - (default selectedBackgroundColor) the border of the close checkBox
closeBackgroundColor - (default selectedBackgroundColor) the backgroundColor of the close checkBox
closeIndicatorColor - (default selectedColor) the indicator color of the close checkBox
anchor - (default true) set to false to not anchor the titleBar to the edge if dragged with the Layer (not the titleBar)
with anchor true, the user can dock the titleBar to the edges and then drag them to any desired location
the user can snap the titleBar back on the layer by dropping it on the top left corner of the layer or double clicking the titleBar
style - (default true) set to false to ignore styles set with the STYLE - will receive original parameter defaults
group - (default null) set to String (or comma delimited String) so STYLE can set default styles to the group(s) (like a CSS class)
inherit - (default null) used internally but can receive an {} of styles directly
METHODS
titleBarPos(x, y, right, bottom) - position the titleBar in the titleBarContainer - returns object for chaining
This will undock the titleBar from the Layer so it can be moved independently
unless titleBarDraggable is set to false
See also titleBarX and titleBarY parameters to start titleBars at a certain position
resetTitleBar() - dock the titleBar back on the Layer - returns object for chaining
toggle(state) - toggle the controls or turn on or off the controls by providing a Boolean state - returns object for chaining
resize(dispatch) - resize the Layer and its children if Layer is manually adjusted - returns object for chaining
for instance, layer.x = 10; layer.resize(); otherwise, the transform controls are broken!
normal layer transforming using the controls automatically resize.
Setting dispatch to true will dispatch a "transformed" event
hasProp(property as String) - returns true if property exists on object else returns false
clone() - makes a copy with properties such as x, y, etc. also copied (returns the new waiter for chaining)
dispose() - removes from parent, removes event listeners - must still set outside references to null for garbage collection
ALSO: ZIM 4TH adds all the methods listed under Container (see above), such as:
drag(), hitTestRect(), animate(), sca(), reg(), mov(), center(), centerReg(),
addTo(), removeFrom(), loop(), outline(), place(), pos(), alp(), rot(), setMask(), etc.
ALSO: see the CreateJS Easel Docs for Container methods, such as:
on(), off(), getBounds(), setBounds(), cache(), uncache(), updateCache(), dispatchEvent(),
addChild(), removeChild(), addChildAt(), getChildAt(), contains(), removeAllChildren(), etc.
PROPERTIES
type - holds the class name as a String
transformControls - the transform transformControls object - see below for a description
anchor - get or set whether the titleBar will anchor to the edges of the titleBarContainer
toggled - read only if Layer has its transform turned on - or use transformControls.visible
use toggle(state) to toggle controls or pass in true for show controls or false for hide controls
titleBar - access to the ZIM Container that holds the titleBar
titleBarDraggable - get or set whether the titleBar can be dragged
use with titleBarPos() to permanently positing the titleBar
checkBox - access to the ZIM CheckBox that shows when the Layer is active and close is true
button - access to the ZIM Button that makes up the titleBar
label - access to the ZIM Label that is on the Button for the titleBar
ALSO: see ZIM Container for properties such as:
width, height, widthOnly, heightOnly, draggable, level, depth, group
blendMode, hue, saturation, brightness, contrast, etc.
ALSO: see the transformControls property described below for more options.
ALSO: see the CreateJS Easel Docs for Container properties, such as:
x, y, rotation, scaleX, scaleY, regX, regY, skewX, skewY,
alpha, cursor, shadow, name, mouseChildren, mouseEnabled, parent, numChildren, etc.
TRANSFORM CONTROLS OBJECT
Layer receives a transformControls property
This may be slightly delayed as Layer is prepared on stage
var layer = new Layer().center();
timeout(100, function(){zog(layer.transformControls);}); // will probably do the trick
The transformControls property holds the following:
TRANSFORM CONTROL OBJECT PROPERTIES
visible - read only whether the controls are visible
ghost - read only as to whether the ghost outline is showing - set with showGhost and hideGhost
ghostEnabled - read only as to whether the ghost outline will be turned on and off - set with addGhost and removeGhost
scaleControls - reference to the Container that holds the corner boxes for scaling
stretchXControls - reference to the Container that holds the left and right boxes for stretching
stretchYControls - reference to the Container that holds the top and bottom boxes for stretching
rotateControls - reference to the Container that holds the outer circles for rotating
TRANSFORM CONTROL OBJECT METHODS
hide() - hides the controls - returns object for chaining
show() - shows the controls - returns objec
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment