Created
June 26, 2021 01:47
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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