| /* |
| Copyright (c) 2004-2009, The Dojo Foundation All Rights Reserved. |
| Available via Academic Free License >= 2.1 OR the modified BSD license. |
| see: http://dojotoolkit.org/license for details |
| */ |
| |
| /* |
| This is a compiled version of Dojo, built for deployment and not for |
| development. To get an editable version, please visit: |
| |
| http://dojotoolkit.org |
| |
| for documentation and information on getting the source. |
| */ |
| |
| if(!dojo._hasResource["dijit._base.manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.manager"] = true; |
| dojo.provide("dijit._base.manager"); |
| |
| dojo.declare("dijit.WidgetSet", null, { |
| // summary: |
| // A set of widgets indexed by id. A default instance of this class is |
| // available as `dijit.registry` |
| // |
| // example: |
| // Create a small list of widgets: |
| // | var ws = new dijit.WidgetSet(); |
| // | ws.add(dijit.byId("one")); |
| // | ws.add(dijit.byId("two")); |
| // | // destroy both: |
| // | ws.forEach(function(w){ w.destroy(); }); |
| // |
| // example: |
| // Using dijit.registry: |
| // | dijit.registry.forEach(function(w){ /* do something */ }); |
| |
| constructor: function(){ |
| this._hash = {}; |
| this.length = 0; |
| }, |
| |
| add: function(/*dijit._Widget*/ widget){ |
| // summary: |
| // Add a widget to this list. If a duplicate ID is detected, a error is thrown. |
| // |
| // widget: dijit._Widget |
| // Any dijit._Widget subclass. |
| if(this._hash[widget.id]){ |
| throw new Error("Tried to register widget with id==" + widget.id + " but that id is already registered"); |
| } |
| this._hash[widget.id] = widget; |
| this.length++; |
| }, |
| |
| remove: function(/*String*/ id){ |
| // summary: |
| // Remove a widget from this WidgetSet. Does not destroy the widget; simply |
| // removes the reference. |
| if(this._hash[id]){ |
| delete this._hash[id]; |
| this.length--; |
| } |
| }, |
| |
| forEach: function(/*Function*/ func, /* Object? */thisObj){ |
| // summary: |
| // Call specified function for each widget in this set. |
| // |
| // func: |
| // A callback function to run for each item. Is passed the widget, the index |
| // in the iteration, and the full hash, similar to `dojo.forEach`. |
| // |
| // thisObj: |
| // An optional scope parameter |
| // |
| // example: |
| // Using the default `dijit.registry` instance: |
| // | dijit.registry.forEach(function(widget){ |
| // | console.log(widget.declaredClass); |
| // | }); |
| // |
| // returns: |
| // Returns self, in order to allow for further chaining. |
| |
| thisObj = thisObj || dojo.global; |
| var i = 0, id; |
| for(id in this._hash){ |
| func.call(thisObj, this._hash[id], i++, this._hash); |
| } |
| return this; // dijit.WidgetSet |
| }, |
| |
| filter: function(/*Function*/ filter, /* Object? */thisObj){ |
| // summary: |
| // Filter down this WidgetSet to a smaller new WidgetSet |
| // Works the same as `dojo.filter` and `dojo.NodeList.filter` |
| // |
| // filter: |
| // Callback function to test truthiness. Is passed the widget |
| // reference and the pseudo-index in the object. |
| // |
| // thisObj: Object? |
| // Option scope to use for the filter function. |
| // |
| // example: |
| // Arbitrary: select the odd widgets in this list |
| // | dijit.registry.filter(function(w, i){ |
| // | return i % 2 == 0; |
| // | }).forEach(function(w){ /* odd ones */ }); |
| |
| thisObj = thisObj || dojo.global; |
| var res = new dijit.WidgetSet(), i = 0, id; |
| for(id in this._hash){ |
| var w = this._hash[id]; |
| if(filter.call(thisObj, w, i++, this._hash)){ |
| res.add(w); |
| } |
| } |
| return res; // dijit.WidgetSet |
| }, |
| |
| byId: function(/*String*/ id){ |
| // summary: |
| // Find a widget in this list by it's id. |
| // example: |
| // Test if an id is in a particular WidgetSet |
| // | var ws = new dijit.WidgetSet(); |
| // | ws.add(dijit.byId("bar")); |
| // | var t = ws.byId("bar") // returns a widget |
| // | var x = ws.byId("foo"); // returns undefined |
| |
| return this._hash[id]; // dijit._Widget |
| }, |
| |
| byClass: function(/*String*/ cls){ |
| // summary: |
| // Reduce this widgetset to a new WidgetSet of a particular `declaredClass` |
| // |
| // cls: String |
| // The Class to scan for. Full dot-notated string. |
| // |
| // example: |
| // Find all `dijit.TitlePane`s in a page: |
| // | dijit.registry.byClass("dijit.TitlePane").forEach(function(tp){ tp.close(); }); |
| |
| var res = new dijit.WidgetSet(), id, widget; |
| for(id in this._hash){ |
| widget = this._hash[id]; |
| if(widget.declaredClass == cls){ |
| res.add(widget); |
| } |
| } |
| return res; // dijit.WidgetSet |
| }, |
| |
| toArray: function(){ |
| // summary: |
| // Convert this WidgetSet into a true Array |
| // |
| // example: |
| // Work with the widget .domNodes in a real Array |
| // | dojo.map(dijit.registry.toArray(), function(w){ return w.domNode; }); |
| |
| var ar = []; |
| for(var id in this._hash){ |
| ar.push(this._hash[id]); |
| } |
| return ar; // dijit._Widget[] |
| }, |
| |
| map: function(/* Function */func, /* Object? */thisObj){ |
| // summary: |
| // Create a new Array from this WidgetSet, following the same rules as `dojo.map` |
| // example: |
| // | var nodes = dijit.registry.map(function(w){ return w.domNode; }); |
| // |
| // returns: |
| // A new array of the returned values. |
| return dojo.map(this.toArray(), func, thisObj); // Array |
| }, |
| |
| every: function(func, thisObj){ |
| // summary: |
| // A synthetic clone of `dojo.every` acting explictly on this WidgetSet |
| // |
| // func: Function |
| // A callback function run for every widget in this list. Exits loop |
| // when the first false return is encountered. |
| // |
| // thisObj: Object? |
| // Optional scope parameter to use for the callback |
| |
| thisObj = thisObj || dojo.global; |
| var x = 0, i; |
| for(i in this._hash){ |
| if(!func.call(thisObj, this._hash[i], x++, this._hash)){ |
| return false; // Boolean |
| } |
| } |
| return true; // Boolean |
| }, |
| |
| some: function(func, thisObj){ |
| // summary: |
| // A synthetic clone of `dojo.some` acting explictly on this WidgetSet |
| // |
| // func: Function |
| // A callback function run for every widget in this list. Exits loop |
| // when the first true return is encountered. |
| // |
| // thisObj: Object? |
| // Optional scope parameter to use for the callback |
| |
| thisObj = thisObj || dojo.global; |
| var x = 0, i; |
| for(i in this._hash){ |
| if(func.call(thisObj, this._hash[i], x++, this._hash)){ |
| return true; // Boolean |
| } |
| } |
| return false; // Boolean |
| } |
| |
| }); |
| |
| /*===== |
| dijit.registry = { |
| // summary: |
| // A list of widgets on a page. |
| // description: |
| // Is an instance of `dijit.WidgetSet` |
| }; |
| =====*/ |
| dijit.registry= new dijit.WidgetSet(); |
| |
| dijit._widgetTypeCtr = {}; |
| |
| dijit.getUniqueId = function(/*String*/widgetType){ |
| // summary: |
| // Generates a unique id for a given widgetType |
| |
| var id; |
| do{ |
| id = widgetType + "_" + |
| (widgetType in dijit._widgetTypeCtr ? |
| ++dijit._widgetTypeCtr[widgetType] : dijit._widgetTypeCtr[widgetType] = 0); |
| }while(dijit.byId(id)); |
| return dijit._scopeName == "dijit" ? id : dijit._scopeName + "_" + id; // String |
| }; |
| |
| dijit.findWidgets = function(/*DomNode*/ root){ |
| // summary: |
| // Search subtree under root returning widgets found. |
| // Doesn't search for nested widgets (ie, widgets inside other widgets). |
| |
| var outAry = []; |
| |
| function getChildrenHelper(root){ |
| for(var node = root.firstChild; node; node = node.nextSibling){ |
| if(node.nodeType == 1){ |
| var widgetId = node.getAttribute("widgetId"); |
| if(widgetId){ |
| var widget = dijit.byId(widgetId); |
| outAry.push(widget); |
| }else{ |
| getChildrenHelper(node); |
| } |
| } |
| } |
| } |
| |
| getChildrenHelper(root); |
| return outAry; |
| }; |
| |
| dijit._destroyAll = function(){ |
| // summary: |
| // Code to destroy all widgets and do other cleanup on page unload |
| |
| // Clean up focus manager lingering references to widgets and nodes |
| dijit._curFocus = null; |
| dijit._prevFocus = null; |
| dijit._activeStack = []; |
| |
| // Destroy all the widgets, top down |
| dojo.forEach(dijit.findWidgets(dojo.body()), function(widget){ |
| // Avoid double destroy of widgets like Menu that are attached to <body> |
| // even though they are logically children of other widgets. |
| if(!widget._destroyed){ |
| if(widget.destroyRecursive){ |
| widget.destroyRecursive(); |
| }else if(widget.destroy){ |
| widget.destroy(); |
| } |
| } |
| }); |
| }; |
| |
| if(dojo.isIE){ |
| // Only run _destroyAll() for IE because we think it's only necessary in that case, |
| // and because it causes problems on FF. See bug #3531 for details. |
| dojo.addOnWindowUnload(function(){ |
| dijit._destroyAll(); |
| }); |
| } |
| |
| dijit.byId = function(/*String|Widget*/id){ |
| // summary: |
| // Returns a widget by it's id, or if passed a widget, no-op (like dojo.byId()) |
| return typeof id == "string" ? dijit.registry._hash[id] : id; // dijit._Widget |
| }; |
| |
| dijit.byNode = function(/* DOMNode */ node){ |
| // summary: |
| // Returns the widget corresponding to the given DOMNode |
| return dijit.registry.byId(node.getAttribute("widgetId")); // dijit._Widget |
| }; |
| |
| dijit.getEnclosingWidget = function(/* DOMNode */ node){ |
| // summary: |
| // Returns the widget whose DOM tree contains the specified DOMNode, or null if |
| // the node is not contained within the DOM tree of any widget |
| while(node){ |
| var id = node.getAttribute && node.getAttribute("widgetId"); |
| if(id){ |
| return dijit.byId(id); |
| } |
| node = node.parentNode; |
| } |
| return null; |
| }; |
| |
| dijit._isElementShown = function(/*Element*/elem){ |
| var style = dojo.style(elem); |
| return (style.visibility != "hidden") |
| && (style.visibility != "collapsed") |
| && (style.display != "none") |
| && (dojo.attr(elem, "type") != "hidden"); |
| } |
| |
| dijit.isTabNavigable = function(/*Element*/elem){ |
| // summary: |
| // Tests if an element is tab-navigable |
| |
| // TODO: convert (and rename method) to return effectivite tabIndex; will save time in _getTabNavigable() |
| if(dojo.attr(elem, "disabled")){ |
| return false; |
| }else if(dojo.hasAttr(elem, "tabIndex")){ |
| // Explicit tab index setting |
| return dojo.attr(elem, "tabIndex") >= 0; // boolean |
| }else{ |
| // No explicit tabIndex setting, need to investigate node type |
| switch(elem.nodeName.toLowerCase()){ |
| case "a": |
| // An <a> w/out a tabindex is only navigable if it has an href |
| return dojo.hasAttr(elem, "href"); |
| case "area": |
| case "button": |
| case "input": |
| case "object": |
| case "select": |
| case "textarea": |
| // These are navigable by default |
| return true; |
| case "iframe": |
| // If it's an editor <iframe> then it's tab navigable. |
| if(dojo.isMoz){ |
| return elem.contentDocument.designMode == "on"; |
| }else if(dojo.isWebKit){ |
| var doc = elem.contentDocument, |
| body = doc && doc.body; |
| return body && body.contentEditable == 'true'; |
| }else{ |
| // contentWindow.document isn't accessible within IE7/8 |
| // if the iframe.src points to a foreign url and this |
| // page contains an element, that could get focus |
| try{ |
| doc = elem.contentWindow.document; |
| body = doc && doc.body; |
| return body && body.firstChild && body.firstChild.contentEditable == 'true'; |
| }catch(e){ |
| return false; |
| } |
| } |
| default: |
| return elem.contentEditable == 'true'; |
| } |
| } |
| }; |
| |
| dijit._getTabNavigable = function(/*DOMNode*/root){ |
| // summary: |
| // Finds descendants of the specified root node. |
| // |
| // description: |
| // Finds the following descendants of the specified root node: |
| // * the first tab-navigable element in document order |
| // without a tabIndex or with tabIndex="0" |
| // * the last tab-navigable element in document order |
| // without a tabIndex or with tabIndex="0" |
| // * the first element in document order with the lowest |
| // positive tabIndex value |
| // * the last element in document order with the highest |
| // positive tabIndex value |
| var first, last, lowest, lowestTabindex, highest, highestTabindex; |
| var walkTree = function(/*DOMNode*/parent){ |
| dojo.query("> *", parent).forEach(function(child){ |
| var isShown = dijit._isElementShown(child); |
| if(isShown && dijit.isTabNavigable(child)){ |
| var tabindex = dojo.attr(child, "tabIndex"); |
| if(!dojo.hasAttr(child, "tabIndex") || tabindex == 0){ |
| if(!first){ first = child; } |
| last = child; |
| }else if(tabindex > 0){ |
| if(!lowest || tabindex < lowestTabindex){ |
| lowestTabindex = tabindex; |
| lowest = child; |
| } |
| if(!highest || tabindex >= highestTabindex){ |
| highestTabindex = tabindex; |
| highest = child; |
| } |
| } |
| } |
| if(isShown && child.nodeName.toUpperCase() != 'SELECT'){ walkTree(child) } |
| }); |
| }; |
| if(dijit._isElementShown(root)){ walkTree(root) } |
| return { first: first, last: last, lowest: lowest, highest: highest }; |
| } |
| dijit.getFirstInTabbingOrder = function(/*String|DOMNode*/root){ |
| // summary: |
| // Finds the descendant of the specified root node |
| // that is first in the tabbing order |
| var elems = dijit._getTabNavigable(dojo.byId(root)); |
| return elems.lowest ? elems.lowest : elems.first; // DomNode |
| }; |
| |
| dijit.getLastInTabbingOrder = function(/*String|DOMNode*/root){ |
| // summary: |
| // Finds the descendant of the specified root node |
| // that is last in the tabbing order |
| var elems = dijit._getTabNavigable(dojo.byId(root)); |
| return elems.last ? elems.last : elems.highest; // DomNode |
| }; |
| |
| /*===== |
| dojo.mixin(dijit, { |
| // defaultDuration: Integer |
| // The default animation speed (in ms) to use for all Dijit |
| // transitional animations, unless otherwise specified |
| // on a per-instance basis. Defaults to 200, overrided by |
| // `djConfig.defaultDuration` |
| defaultDuration: 300 |
| }); |
| =====*/ |
| |
| dijit.defaultDuration = dojo.config["defaultDuration"] || 200; |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base.focus"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.focus"] = true; |
| dojo.provide("dijit._base.focus"); |
| |
| // for dijit.isTabNavigable() |
| |
| // summary: |
| // These functions are used to query or set the focus and selection. |
| // |
| // Also, they trace when widgets become activated/deactivated, |
| // so that the widget can fire _onFocus/_onBlur events. |
| // "Active" here means something similar to "focused", but |
| // "focus" isn't quite the right word because we keep track of |
| // a whole stack of "active" widgets. Example: ComboButton --> Menu --> |
| // MenuItem. The onBlur event for ComboButton doesn't fire due to focusing |
| // on the Menu or a MenuItem, since they are considered part of the |
| // ComboButton widget. It only happens when focus is shifted |
| // somewhere completely different. |
| |
| dojo.mixin(dijit, { |
| // _curFocus: DomNode |
| // Currently focused item on screen |
| _curFocus: null, |
| |
| // _prevFocus: DomNode |
| // Previously focused item on screen |
| _prevFocus: null, |
| |
| isCollapsed: function(){ |
| // summary: |
| // Returns true if there is no text selected |
| return dijit.getBookmark().isCollapsed; |
| }, |
| |
| getBookmark: function(){ |
| // summary: |
| // Retrieves a bookmark that can be used with moveToBookmark to return to the same range |
| var bm, rg, tg, sel = dojo.doc.selection, cf = dijit._curFocus; |
| |
| if(dojo.global.getSelection){ |
| //W3C Range API for selections. |
| sel = dojo.global.getSelection(); |
| if(sel){ |
| if(sel.isCollapsed){ |
| tg = cf? cf.tagName : ""; |
| if(tg){ |
| //Create a fake rangelike item to restore selections. |
| tg = tg.toLowerCase(); |
| if(tg == "textarea" || |
| (tg == "input" && (!cf.type || cf.type.toLowerCase() == "text"))){ |
| sel = { |
| start: cf.selectionStart, |
| end: cf.selectionEnd, |
| node: cf, |
| pRange: true |
| }; |
| return {isCollapsed: (sel.end <= sel.start), mark: sel}; //Object. |
| } |
| } |
| bm = {isCollapsed:true}; |
| }else{ |
| rg = sel.getRangeAt(0); |
| bm = {isCollapsed: false, mark: rg.cloneRange()}; |
| } |
| } |
| }else if(sel){ |
| // If the current focus was a input of some sort and no selection, don't bother saving |
| // a native bookmark. This is because it causes issues with dialog/page selection restore. |
| // So, we need to create psuedo bookmarks to work with. |
| tg = cf ? cf.tagName : ""; |
| tg = tg.toLowerCase(); |
| if(cf && tg && (tg == "button" || tg == "textarea" || tg == "input")){ |
| if(sel.type && sel.type.toLowerCase() == "none"){ |
| return { |
| isCollapsed: true, |
| mark: null |
| } |
| }else{ |
| rg = sel.createRange(); |
| return { |
| isCollapsed: rg.text && rg.text.length?false:true, |
| mark: { |
| range: rg, |
| pRange: true |
| } |
| }; |
| } |
| } |
| bm = {}; |
| |
| //'IE' way for selections. |
| try{ |
| // createRange() throws exception when dojo in iframe |
| //and nothing selected, see #9632 |
| rg = sel.createRange(); |
| bm.isCollapsed = !(sel.type == 'Text' ? rg.htmlText.length : rg.length); |
| }catch(e){ |
| bm.isCollapsed = true; |
| return bm; |
| } |
| if(sel.type.toUpperCase() == 'CONTROL'){ |
| if(rg.length){ |
| bm.mark=[]; |
| var i=0,len=rg.length; |
| while(i<len){ |
| bm.mark.push(rg.item(i++)); |
| } |
| }else{ |
| bm.isCollapsed = true; |
| bm.mark = null; |
| } |
| }else{ |
| bm.mark = rg.getBookmark(); |
| } |
| }else{ |
| console.warn("No idea how to store the current selection for this browser!"); |
| } |
| return bm; // Object |
| }, |
| |
| moveToBookmark: function(/*Object*/bookmark){ |
| // summary: |
| // Moves current selection to a bookmark |
| // bookmark: |
| // This should be a returned object from dijit.getBookmark() |
| |
| var _doc = dojo.doc, |
| mark = bookmark.mark; |
| if(mark){ |
| if(dojo.global.getSelection){ |
| //W3C Rangi API (FF, WebKit, Opera, etc) |
| var sel = dojo.global.getSelection(); |
| if(sel && sel.removeAllRanges){ |
| if(mark.pRange){ |
| var r = mark; |
| var n = r.node; |
| n.selectionStart = r.start; |
| n.selectionEnd = r.end; |
| }else{ |
| sel.removeAllRanges(); |
| sel.addRange(mark); |
| } |
| }else{ |
| console.warn("No idea how to restore selection for this browser!"); |
| } |
| }else if(_doc.selection && mark){ |
| //'IE' way. |
| var rg; |
| if(mark.pRange){ |
| rg = mark.range; |
| }else if(dojo.isArray(mark)){ |
| rg = _doc.body.createControlRange(); |
| //rg.addElement does not have call/apply method, so can not call it directly |
| //rg is not available in "range.addElement(item)", so can't use that either |
| dojo.forEach(mark, function(n){ |
| rg.addElement(n); |
| }); |
| }else{ |
| rg = _doc.body.createTextRange(); |
| rg.moveToBookmark(mark); |
| } |
| rg.select(); |
| } |
| } |
| }, |
| |
| getFocus: function(/*Widget?*/ menu, /*Window?*/ openedForWindow){ |
| // summary: |
| // Called as getFocus(), this returns an Object showing the current focus |
| // and selected text. |
| // |
| // Called as getFocus(widget), where widget is a (widget representing) a button |
| // that was just pressed, it returns where focus was before that button |
| // was pressed. (Pressing the button may have either shifted focus to the button, |
| // or removed focus altogether.) In this case the selected text is not returned, |
| // since it can't be accurately determined. |
| // |
| // menu: dijit._Widget or {domNode: DomNode} structure |
| // The button that was just pressed. If focus has disappeared or moved |
| // to this button, returns the previous focus. In this case the bookmark |
| // information is already lost, and null is returned. |
| // |
| // openedForWindow: |
| // iframe in which menu was opened |
| // |
| // returns: |
| // A handle to restore focus/selection, to be passed to `dijit.focus` |
| var node = !dijit._curFocus || (menu && dojo.isDescendant(dijit._curFocus, menu.domNode)) ? dijit._prevFocus : dijit._curFocus; |
| return { |
| node: node, |
| bookmark: (node == dijit._curFocus) && dojo.withGlobal(openedForWindow || dojo.global, dijit.getBookmark), |
| openedForWindow: openedForWindow |
| }; // Object |
| }, |
| |
| focus: function(/*Object || DomNode */ handle){ |
| // summary: |
| // Sets the focused node and the selection according to argument. |
| // To set focus to an iframe's content, pass in the iframe itself. |
| // handle: |
| // object returned by get(), or a DomNode |
| |
| if(!handle){ return; } |
| |
| var node = "node" in handle ? handle.node : handle, // because handle is either DomNode or a composite object |
| bookmark = handle.bookmark, |
| openedForWindow = handle.openedForWindow, |
| collapsed = bookmark ? bookmark.isCollapsed : false; |
| |
| // Set the focus |
| // Note that for iframe's we need to use the <iframe> to follow the parentNode chain, |
| // but we need to set focus to iframe.contentWindow |
| if(node){ |
| var focusNode = (node.tagName.toLowerCase() == "iframe") ? node.contentWindow : node; |
| if(focusNode && focusNode.focus){ |
| try{ |
| // Gecko throws sometimes if setting focus is impossible, |
| // node not displayed or something like that |
| focusNode.focus(); |
| }catch(e){/*quiet*/} |
| } |
| dijit._onFocusNode(node); |
| } |
| |
| // set the selection |
| // do not need to restore if current selection is not empty |
| // (use keyboard to select a menu item) or if previous selection was collapsed |
| // as it may cause focus shift (Esp in IE). |
| if(bookmark && dojo.withGlobal(openedForWindow || dojo.global, dijit.isCollapsed) && !collapsed){ |
| if(openedForWindow){ |
| openedForWindow.focus(); |
| } |
| try{ |
| dojo.withGlobal(openedForWindow || dojo.global, dijit.moveToBookmark, null, [bookmark]); |
| }catch(e2){ |
| /*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */ |
| } |
| } |
| }, |
| |
| // _activeStack: dijit._Widget[] |
| // List of currently active widgets (focused widget and it's ancestors) |
| _activeStack: [], |
| |
| registerIframe: function(/*DomNode*/ iframe){ |
| // summary: |
| // Registers listeners on the specified iframe so that any click |
| // or focus event on that iframe (or anything in it) is reported |
| // as a focus/click event on the <iframe> itself. |
| // description: |
| // Currently only used by editor. |
| // returns: |
| // Handle to pass to unregisterIframe() |
| return dijit.registerWin(iframe.contentWindow, iframe); |
| }, |
| |
| unregisterIframe: function(/*Object*/ handle){ |
| // summary: |
| // Unregisters listeners on the specified iframe created by registerIframe. |
| // After calling be sure to delete or null out the handle itself. |
| // handle: |
| // Handle returned by registerIframe() |
| |
| dijit.unregisterWin(handle); |
| }, |
| |
| registerWin: function(/*Window?*/targetWindow, /*DomNode?*/ effectiveNode){ |
| // summary: |
| // Registers listeners on the specified window (either the main |
| // window or an iframe's window) to detect when the user has clicked somewhere |
| // or focused somewhere. |
| // description: |
| // Users should call registerIframe() instead of this method. |
| // targetWindow: |
| // If specified this is the window associated with the iframe, |
| // i.e. iframe.contentWindow. |
| // effectiveNode: |
| // If specified, report any focus events inside targetWindow as |
| // an event on effectiveNode, rather than on evt.target. |
| // returns: |
| // Handle to pass to unregisterWin() |
| |
| // TODO: make this function private in 2.0; Editor/users should call registerIframe(), |
| |
| var mousedownListener = function(evt){ |
| dijit._justMouseDowned = true; |
| setTimeout(function(){ dijit._justMouseDowned = false; }, 0); |
| dijit._onTouchNode(effectiveNode || evt.target || evt.srcElement, "mouse"); |
| }; |
| //dojo.connect(targetWindow, "onscroll", ???); |
| |
| // Listen for blur and focus events on targetWindow's document. |
| // IIRC, I'm using attachEvent() rather than dojo.connect() because focus/blur events don't bubble |
| // through dojo.connect(), and also maybe to catch the focus events early, before onfocus handlers |
| // fire. |
| // Connect to <html> (rather than document) on IE to avoid memory leaks, but document on other browsers because |
| // (at least for FF) the focus event doesn't fire on <html> or <body>. |
| var doc = dojo.isIE ? targetWindow.document.documentElement : targetWindow.document; |
| if(doc){ |
| if(dojo.isIE){ |
| doc.attachEvent('onmousedown', mousedownListener); |
| var activateListener = function(evt){ |
| // IE reports that nodes like <body> have gotten focus, even though they have tabIndex=-1, |
| // Should consider those more like a mouse-click than a focus.... |
| if(evt.srcElement.tagName.toLowerCase() != "#document" && |
| dijit.isTabNavigable(evt.srcElement)){ |
| dijit._onFocusNode(effectiveNode || evt.srcElement); |
| }else{ |
| dijit._onTouchNode(effectiveNode || evt.srcElement); |
| } |
| }; |
| doc.attachEvent('onactivate', activateListener); |
| var deactivateListener = function(evt){ |
| dijit._onBlurNode(effectiveNode || evt.srcElement); |
| }; |
| doc.attachEvent('ondeactivate', deactivateListener); |
| |
| return function(){ |
| doc.detachEvent('onmousedown', mousedownListener); |
| doc.detachEvent('onactivate', activateListener); |
| doc.detachEvent('ondeactivate', deactivateListener); |
| doc = null; // prevent memory leak (apparent circular reference via closure) |
| }; |
| }else{ |
| doc.addEventListener('mousedown', mousedownListener, true); |
| var focusListener = function(evt){ |
| dijit._onFocusNode(effectiveNode || evt.target); |
| }; |
| doc.addEventListener('focus', focusListener, true); |
| var blurListener = function(evt){ |
| dijit._onBlurNode(effectiveNode || evt.target); |
| }; |
| doc.addEventListener('blur', blurListener, true); |
| |
| return function(){ |
| doc.removeEventListener('mousedown', mousedownListener, true); |
| doc.removeEventListener('focus', focusListener, true); |
| doc.removeEventListener('blur', blurListener, true); |
| doc = null; // prevent memory leak (apparent circular reference via closure) |
| }; |
| } |
| } |
| }, |
| |
| unregisterWin: function(/*Handle*/ handle){ |
| // summary: |
| // Unregisters listeners on the specified window (either the main |
| // window or an iframe's window) according to handle returned from registerWin(). |
| // After calling be sure to delete or null out the handle itself. |
| |
| // Currently our handle is actually a function |
| handle && handle(); |
| }, |
| |
| _onBlurNode: function(/*DomNode*/ node){ |
| // summary: |
| // Called when focus leaves a node. |
| // Usually ignored, _unless_ it *isn't* follwed by touching another node, |
| // which indicates that we tabbed off the last field on the page, |
| // in which case every widget is marked inactive |
| dijit._prevFocus = dijit._curFocus; |
| dijit._curFocus = null; |
| |
| if(dijit._justMouseDowned){ |
| // the mouse down caused a new widget to be marked as active; this blur event |
| // is coming late, so ignore it. |
| return; |
| } |
| |
| // if the blur event isn't followed by a focus event then mark all widgets as inactive. |
| if(dijit._clearActiveWidgetsTimer){ |
| clearTimeout(dijit._clearActiveWidgetsTimer); |
| } |
| dijit._clearActiveWidgetsTimer = setTimeout(function(){ |
| delete dijit._clearActiveWidgetsTimer; |
| dijit._setStack([]); |
| dijit._prevFocus = null; |
| }, 100); |
| }, |
| |
| _onTouchNode: function(/*DomNode*/ node, /*String*/ by){ |
| // summary: |
| // Callback when node is focused or mouse-downed |
| // node: |
| // The node that was touched. |
| // by: |
| // "mouse" if the focus/touch was caused by a mouse down event |
| |
| // ignore the recent blurNode event |
| if(dijit._clearActiveWidgetsTimer){ |
| clearTimeout(dijit._clearActiveWidgetsTimer); |
| delete dijit._clearActiveWidgetsTimer; |
| } |
| |
| // compute stack of active widgets (ex: ComboButton --> Menu --> MenuItem) |
| var newStack=[]; |
| try{ |
| while(node){ |
| var popupParent = dojo.attr(node, "dijitPopupParent"); |
| if(popupParent){ |
| node=dijit.byId(popupParent).domNode; |
| }else if(node.tagName && node.tagName.toLowerCase() == "body"){ |
| // is this the root of the document or just the root of an iframe? |
| if(node === dojo.body()){ |
| // node is the root of the main document |
| break; |
| } |
| // otherwise, find the iframe this node refers to (can't access it via parentNode, |
| // need to do this trick instead). window.frameElement is supported in IE/FF/Webkit |
| node=dijit.getDocumentWindow(node.ownerDocument).frameElement; |
| }else{ |
| var id = node.getAttribute && node.getAttribute("widgetId"); |
| if(id){ |
| newStack.unshift(id); |
| } |
| node=node.parentNode; |
| } |
| } |
| }catch(e){ /* squelch */ } |
| |
| dijit._setStack(newStack, by); |
| }, |
| |
| _onFocusNode: function(/*DomNode*/ node){ |
| // summary: |
| // Callback when node is focused |
| |
| if(!node){ |
| return; |
| } |
| |
| if(node.nodeType == 9){ |
| // Ignore focus events on the document itself. This is here so that |
| // (for example) clicking the up/down arrows of a spinner |
| // (which don't get focus) won't cause that widget to blur. (FF issue) |
| return; |
| } |
| |
| dijit._onTouchNode(node); |
| |
| if(node == dijit._curFocus){ return; } |
| if(dijit._curFocus){ |
| dijit._prevFocus = dijit._curFocus; |
| } |
| dijit._curFocus = node; |
| dojo.publish("focusNode", [node]); |
| }, |
| |
| _setStack: function(/*String[]*/ newStack, /*String*/ by){ |
| // summary: |
| // The stack of active widgets has changed. Send out appropriate events and records new stack. |
| // newStack: |
| // array of widget id's, starting from the top (outermost) widget |
| // by: |
| // "mouse" if the focus/touch was caused by a mouse down event |
| |
| var oldStack = dijit._activeStack; |
| dijit._activeStack = newStack; |
| |
| // compare old stack to new stack to see how many elements they have in common |
| for(var nCommon=0; nCommon<Math.min(oldStack.length, newStack.length); nCommon++){ |
| if(oldStack[nCommon] != newStack[nCommon]){ |
| break; |
| } |
| } |
| |
| var widget; |
| // for all elements that have gone out of focus, send blur event |
| for(var i=oldStack.length-1; i>=nCommon; i--){ |
| widget = dijit.byId(oldStack[i]); |
| if(widget){ |
| widget._focused = false; |
| widget._hasBeenBlurred = true; |
| if(widget._onBlur){ |
| widget._onBlur(by); |
| } |
| if(widget._setStateClass){ |
| widget._setStateClass(); |
| } |
| dojo.publish("widgetBlur", [widget, by]); |
| } |
| } |
| |
| // for all element that have come into focus, send focus event |
| for(i=nCommon; i<newStack.length; i++){ |
| widget = dijit.byId(newStack[i]); |
| if(widget){ |
| widget._focused = true; |
| if(widget._onFocus){ |
| widget._onFocus(by); |
| } |
| if(widget._setStateClass){ |
| widget._setStateClass(); |
| } |
| dojo.publish("widgetFocus", [widget, by]); |
| } |
| } |
| } |
| }); |
| |
| // register top window and all the iframes it contains |
| dojo.addOnLoad(function(){ |
| var handle = dijit.registerWin(window); |
| if(dojo.isIE){ |
| dojo.addOnWindowUnload(function(){ |
| dijit.unregisterWin(handle); |
| handle = null; |
| }) |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojo.AdapterRegistry"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo.AdapterRegistry"] = true; |
| dojo.provide("dojo.AdapterRegistry"); |
| |
| dojo.AdapterRegistry = function(/*Boolean?*/ returnWrappers){ |
| // summary: |
| // A registry to make contextual calling/searching easier. |
| // description: |
| // Objects of this class keep list of arrays in the form [name, check, |
| // wrap, directReturn] that are used to determine what the contextual |
| // result of a set of checked arguments is. All check/wrap functions |
| // in this registry should be of the same arity. |
| // example: |
| // | // create a new registry |
| // | var reg = new dojo.AdapterRegistry(); |
| // | reg.register("handleString", |
| // | dojo.isString, |
| // | function(str){ |
| // | // do something with the string here |
| // | } |
| // | ); |
| // | reg.register("handleArr", |
| // | dojo.isArray, |
| // | function(arr){ |
| // | // do something with the array here |
| // | } |
| // | ); |
| // | |
| // | // now we can pass reg.match() *either* an array or a string and |
| // | // the value we pass will get handled by the right function |
| // | reg.match("someValue"); // will call the first function |
| // | reg.match(["someValue"]); // will call the second |
| |
| this.pairs = []; |
| this.returnWrappers = returnWrappers || false; // Boolean |
| } |
| |
| dojo.extend(dojo.AdapterRegistry, { |
| register: function(/*String*/ name, /*Function*/ check, /*Function*/ wrap, /*Boolean?*/ directReturn, /*Boolean?*/ override){ |
| // summary: |
| // register a check function to determine if the wrap function or |
| // object gets selected |
| // name: |
| // a way to identify this matcher. |
| // check: |
| // a function that arguments are passed to from the adapter's |
| // match() function. The check function should return true if the |
| // given arguments are appropriate for the wrap function. |
| // directReturn: |
| // If directReturn is true, the value passed in for wrap will be |
| // returned instead of being called. Alternately, the |
| // AdapterRegistry can be set globally to "return not call" using |
| // the returnWrappers property. Either way, this behavior allows |
| // the registry to act as a "search" function instead of a |
| // function interception library. |
| // override: |
| // If override is given and true, the check function will be given |
| // highest priority. Otherwise, it will be the lowest priority |
| // adapter. |
| this.pairs[((override) ? "unshift" : "push")]([name, check, wrap, directReturn]); |
| }, |
| |
| match: function(/* ... */){ |
| // summary: |
| // Find an adapter for the given arguments. If no suitable adapter |
| // is found, throws an exception. match() accepts any number of |
| // arguments, all of which are passed to all matching functions |
| // from the registered pairs. |
| for(var i = 0; i < this.pairs.length; i++){ |
| var pair = this.pairs[i]; |
| if(pair[1].apply(this, arguments)){ |
| if((pair[3])||(this.returnWrappers)){ |
| return pair[2]; |
| }else{ |
| return pair[2].apply(this, arguments); |
| } |
| } |
| } |
| throw new Error("No match found"); |
| }, |
| |
| unregister: function(name){ |
| // summary: Remove a named adapter from the registry |
| |
| // FIXME: this is kind of a dumb way to handle this. On a large |
| // registry this will be slow-ish and we can use the name as a lookup |
| // should we choose to trade memory for speed. |
| for(var i = 0; i < this.pairs.length; i++){ |
| var pair = this.pairs[i]; |
| if(pair[0] == name){ |
| this.pairs.splice(i, 1); |
| return true; |
| } |
| } |
| return false; |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base.place"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.place"] = true; |
| dojo.provide("dijit._base.place"); |
| |
| |
| |
| // ported from dojo.html.util |
| |
| dijit.getViewport = function(){ |
| // summary: |
| // Returns the dimensions and scroll position of the viewable area of a browser window |
| |
| var scrollRoot = (dojo.doc.compatMode == 'BackCompat')? dojo.body() : dojo.doc.documentElement; |
| |
| // get scroll position |
| var scroll = dojo._docScroll(); // scrollRoot.scrollTop/Left should work |
| return { w: scrollRoot.clientWidth, h: scrollRoot.clientHeight, l: scroll.x, t: scroll.y }; |
| }; |
| |
| /*===== |
| dijit.__Position = function(){ |
| // x: Integer |
| // horizontal coordinate in pixels, relative to document body |
| // y: Integer |
| // vertical coordinate in pixels, relative to document body |
| |
| thix.x = x; |
| this.y = y; |
| } |
| =====*/ |
| |
| |
| dijit.placeOnScreen = function( |
| /* DomNode */ node, |
| /* dijit.__Position */ pos, |
| /* String[] */ corners, |
| /* dijit.__Position? */ padding){ |
| // summary: |
| // Positions one of the node's corners at specified position |
| // such that node is fully visible in viewport. |
| // description: |
| // NOTE: node is assumed to be absolutely or relatively positioned. |
| // pos: |
| // Object like {x: 10, y: 20} |
| // corners: |
| // Array of Strings representing order to try corners in, like ["TR", "BL"]. |
| // Possible values are: |
| // * "BL" - bottom left |
| // * "BR" - bottom right |
| // * "TL" - top left |
| // * "TR" - top right |
| // padding: |
| // set padding to put some buffer around the element you want to position. |
| // example: |
| // Try to place node's top right corner at (10,20). |
| // If that makes node go (partially) off screen, then try placing |
| // bottom left corner at (10,20). |
| // | placeOnScreen(node, {x: 10, y: 20}, ["TR", "BL"]) |
| |
| var choices = dojo.map(corners, function(corner){ |
| var c = { corner: corner, pos: {x:pos.x,y:pos.y} }; |
| if(padding){ |
| c.pos.x += corner.charAt(1) == 'L' ? padding.x : -padding.x; |
| c.pos.y += corner.charAt(0) == 'T' ? padding.y : -padding.y; |
| } |
| return c; |
| }); |
| |
| return dijit._place(node, choices); |
| } |
| |
| dijit._place = function(/*DomNode*/ node, /* Array */ choices, /* Function */ layoutNode){ |
| // summary: |
| // Given a list of spots to put node, put it at the first spot where it fits, |
| // of if it doesn't fit anywhere then the place with the least overflow |
| // choices: Array |
| // Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} } |
| // Above example says to put the top-left corner of the node at (10,20) |
| // layoutNode: Function(node, aroundNodeCorner, nodeCorner) |
| // for things like tooltip, they are displayed differently (and have different dimensions) |
| // based on their orientation relative to the parent. This adjusts the popup based on orientation. |
| |
| // get {x: 10, y: 10, w: 100, h:100} type obj representing position of |
| // viewport over document |
| var view = dijit.getViewport(); |
| |
| // This won't work if the node is inside a <div style="position: relative">, |
| // so reattach it to dojo.doc.body. (Otherwise, the positioning will be wrong |
| // and also it might get cutoff) |
| if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){ |
| dojo.body().appendChild(node); |
| } |
| |
| var best = null; |
| dojo.some(choices, function(choice){ |
| var corner = choice.corner; |
| var pos = choice.pos; |
| |
| // configure node to be displayed in given position relative to button |
| // (need to do this in order to get an accurate size for the node, because |
| // a tooltips size changes based on position, due to triangle) |
| if(layoutNode){ |
| layoutNode(node, choice.aroundCorner, corner); |
| } |
| |
| // get node's size |
| var style = node.style; |
| var oldDisplay = style.display; |
| var oldVis = style.visibility; |
| style.visibility = "hidden"; |
| style.display = ""; |
| var mb = dojo.marginBox(node); |
| style.display = oldDisplay; |
| style.visibility = oldVis; |
| |
| // coordinates and size of node with specified corner placed at pos, |
| // and clipped by viewport |
| var startX = Math.max(view.l, corner.charAt(1) == 'L' ? pos.x : (pos.x - mb.w)), |
| startY = Math.max(view.t, corner.charAt(0) == 'T' ? pos.y : (pos.y - mb.h)), |
| endX = Math.min(view.l + view.w, corner.charAt(1) == 'L' ? (startX + mb.w) : pos.x), |
| endY = Math.min(view.t + view.h, corner.charAt(0) == 'T' ? (startY + mb.h) : pos.y), |
| width = endX - startX, |
| height = endY - startY, |
| overflow = (mb.w - width) + (mb.h - height); |
| |
| if(best == null || overflow < best.overflow){ |
| best = { |
| corner: corner, |
| aroundCorner: choice.aroundCorner, |
| x: startX, |
| y: startY, |
| w: width, |
| h: height, |
| overflow: overflow |
| }; |
| } |
| return !overflow; |
| }); |
| |
| node.style.left = best.x + "px"; |
| node.style.top = best.y + "px"; |
| if(best.overflow && layoutNode){ |
| layoutNode(node, best.aroundCorner, best.corner); |
| } |
| return best; |
| } |
| |
| dijit.placeOnScreenAroundNode = function( |
| /* DomNode */ node, |
| /* DomNode */ aroundNode, |
| /* Object */ aroundCorners, |
| /* Function? */ layoutNode){ |
| |
| // summary: |
| // Position node adjacent or kitty-corner to aroundNode |
| // such that it's fully visible in viewport. |
| // |
| // description: |
| // Place node such that corner of node touches a corner of |
| // aroundNode, and that node is fully visible. |
| // |
| // aroundCorners: |
| // Ordered list of pairs of corners to try matching up. |
| // Each pair of corners is represented as a key/value in the hash, |
| // where the key corresponds to the aroundNode's corner, and |
| // the value corresponds to the node's corner: |
| // |
| // | { aroundNodeCorner1: nodeCorner1, aroundNodeCorner2: nodeCorner2, ...} |
| // |
| // The following strings are used to represent the four corners: |
| // * "BL" - bottom left |
| // * "BR" - bottom right |
| // * "TL" - top left |
| // * "TR" - top right |
| // |
| // layoutNode: Function(node, aroundNodeCorner, nodeCorner) |
| // For things like tooltip, they are displayed differently (and have different dimensions) |
| // based on their orientation relative to the parent. This adjusts the popup based on orientation. |
| // |
| // example: |
| // | dijit.placeOnScreenAroundNode(node, aroundNode, {'BL':'TL', 'TR':'BR'}); |
| // This will try to position node such that node's top-left corner is at the same position |
| // as the bottom left corner of the aroundNode (ie, put node below |
| // aroundNode, with left edges aligned). If that fails it will try to put |
| // the bottom-right corner of node where the top right corner of aroundNode is |
| // (ie, put node above aroundNode, with right edges aligned) |
| // |
| |
| // get coordinates of aroundNode |
| aroundNode = dojo.byId(aroundNode); |
| var oldDisplay = aroundNode.style.display; |
| aroundNode.style.display=""; |
| // #3172: use the slightly tighter border box instead of marginBox |
| var aroundNodePos = dojo.position(aroundNode, true); |
| aroundNode.style.display=oldDisplay; |
| |
| // place the node around the calculated rectangle |
| return dijit._placeOnScreenAroundRect(node, |
| aroundNodePos.x, aroundNodePos.y, aroundNodePos.w, aroundNodePos.h, // rectangle |
| aroundCorners, layoutNode); |
| }; |
| |
| /*===== |
| dijit.__Rectangle = function(){ |
| // x: Integer |
| // horizontal offset in pixels, relative to document body |
| // y: Integer |
| // vertical offset in pixels, relative to document body |
| // width: Integer |
| // width in pixels |
| // height: Integer |
| // height in pixels |
| |
| this.x = x; |
| this.y = y; |
| this.width = width; |
| this.height = height; |
| } |
| =====*/ |
| |
| |
| dijit.placeOnScreenAroundRectangle = function( |
| /* DomNode */ node, |
| /* dijit.__Rectangle */ aroundRect, |
| /* Object */ aroundCorners, |
| /* Function */ layoutNode){ |
| |
| // summary: |
| // Like dijit.placeOnScreenAroundNode(), except that the "around" |
| // parameter is an arbitrary rectangle on the screen (x, y, width, height) |
| // instead of a dom node. |
| |
| return dijit._placeOnScreenAroundRect(node, |
| aroundRect.x, aroundRect.y, aroundRect.width, aroundRect.height, // rectangle |
| aroundCorners, layoutNode); |
| }; |
| |
| dijit._placeOnScreenAroundRect = function( |
| /* DomNode */ node, |
| /* Number */ x, |
| /* Number */ y, |
| /* Number */ width, |
| /* Number */ height, |
| /* Object */ aroundCorners, |
| /* Function */ layoutNode){ |
| |
| // summary: |
| // Like dijit.placeOnScreenAroundNode(), except it accepts coordinates |
| // of a rectangle to place node adjacent to. |
| |
| // TODO: combine with placeOnScreenAroundRectangle() |
| |
| // Generate list of possible positions for node |
| var choices = []; |
| for(var nodeCorner in aroundCorners){ |
| choices.push( { |
| aroundCorner: nodeCorner, |
| corner: aroundCorners[nodeCorner], |
| pos: { |
| x: x + (nodeCorner.charAt(1) == 'L' ? 0 : width), |
| y: y + (nodeCorner.charAt(0) == 'T' ? 0 : height) |
| } |
| }); |
| } |
| |
| return dijit._place(node, choices, layoutNode); |
| }; |
| |
| dijit.placementRegistry= new dojo.AdapterRegistry(); |
| dijit.placementRegistry.register("node", |
| function(n, x){ |
| return typeof x == "object" && |
| typeof x.offsetWidth != "undefined" && typeof x.offsetHeight != "undefined"; |
| }, |
| dijit.placeOnScreenAroundNode); |
| dijit.placementRegistry.register("rect", |
| function(n, x){ |
| return typeof x == "object" && |
| "x" in x && "y" in x && "width" in x && "height" in x; |
| }, |
| dijit.placeOnScreenAroundRectangle); |
| |
| dijit.placeOnScreenAroundElement = function( |
| /* DomNode */ node, |
| /* Object */ aroundElement, |
| /* Object */ aroundCorners, |
| /* Function */ layoutNode){ |
| |
| // summary: |
| // Like dijit.placeOnScreenAroundNode(), except it accepts an arbitrary object |
| // for the "around" argument and finds a proper processor to place a node. |
| |
| return dijit.placementRegistry.match.apply(dijit.placementRegistry, arguments); |
| }; |
| |
| dijit.getPopupAlignment = function(/*Array*/ position, /*Boolean*/ leftToRight){ |
| // summary: |
| // Transforms the passed array of preferred positions into a format suitable for passing as the aroundCorners argument to dijit.placeOnScreenAroundElement. |
| // |
| // position: String[] |
| // This variable controls the position of the drop down. |
| // It's an array of strings with the following values: |
| // |
| // * before: places drop down to the left of the target node/widget, or to the right in |
| // the case of RTL scripts like Hebrew and Arabic |
| // * after: places drop down to the right of the target node/widget, or to the left in |
| // the case of RTL scripts like Hebrew and Arabic |
| // * above: drop down goes above target node |
| // * below: drop down goes below target node |
| // |
| // The list is positions is tried, in order, until a position is found where the drop down fits |
| // within the viewport. |
| // |
| // leftToRight: Boolean |
| // Whether the popup will be displaying in leftToRight mode. |
| // |
| var align = {}; |
| dojo.forEach(position, function(pos){ |
| switch(pos){ |
| case "after": |
| align[leftToRight ? "BR" : "BL"] = leftToRight ? "BL" : "BR"; |
| break; |
| case "before": |
| align[leftToRight ? "BL" : "BR"] = leftToRight ? "BR" : "BL"; |
| break; |
| case "below": |
| // first try to align left borders, next try to align right borders (or reverse for RTL mode) |
| align[leftToRight ? "BL" : "BR"] = leftToRight ? "TL" : "TR"; |
| align[leftToRight ? "BR" : "BL"] = leftToRight ? "TR" : "TL"; |
| break; |
| case "above": |
| default: |
| // first try to align left borders, next try to align right borders (or reverse for RTL mode) |
| align[leftToRight ? "TL" : "TR"] = leftToRight ? "BL" : "BR"; |
| align[leftToRight ? "TR" : "TL"] = leftToRight ? "BR" : "BL"; |
| break; |
| } |
| }); |
| return align; |
| }; |
| dijit.getPopupAroundAlignment = function(/*Array*/ position, /*Boolean*/ leftToRight){ |
| // summary: |
| // Transforms the passed array of preferred positions into a format suitable for passing as the aroundCorners argument to dijit.placeOnScreenAroundElement. |
| // |
| // position: String[] |
| // This variable controls the position of the drop down. |
| // It's an array of strings with the following values: |
| // |
| // * before: places drop down to the left of the target node/widget, or to the right in |
| // the case of RTL scripts like Hebrew and Arabic |
| // * after: places drop down to the right of the target node/widget, or to the left in |
| // the case of RTL scripts like Hebrew and Arabic |
| // * above: drop down goes above target node |
| // * below: drop down goes below target node |
| // |
| // The list is positions is tried, in order, until a position is found where the drop down fits |
| // within the viewport. |
| // |
| // leftToRight: Boolean |
| // Whether the popup will be displaying in leftToRight mode. |
| // |
| var align = {}; |
| dojo.forEach(position, function(pos){ |
| switch(pos){ |
| case "after": |
| align[leftToRight ? "BR" : "BL"] = leftToRight ? "BL" : "BR"; |
| break; |
| case "before": |
| align[leftToRight ? "BL" : "BR"] = leftToRight ? "BR" : "BL"; |
| break; |
| case "below": |
| // first try to align left borders, next try to align right borders (or reverse for RTL mode) |
| align[leftToRight ? "BL" : "BR"] = leftToRight ? "TL" : "TR"; |
| align[leftToRight ? "BR" : "BL"] = leftToRight ? "TR" : "TL"; |
| break; |
| case "above": |
| default: |
| // first try to align left borders, next try to align right borders (or reverse for RTL mode) |
| align[leftToRight ? "TL" : "TR"] = leftToRight ? "BL" : "BR"; |
| align[leftToRight ? "TR" : "TL"] = leftToRight ? "BR" : "BL"; |
| break; |
| } |
| }); |
| return align; |
| }; |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.window"] = true; |
| dojo.provide("dijit._base.window"); |
| |
| // TODO: remove this in 2.0, it's not used anymore, or at least not internally |
| |
| dijit.getDocumentWindow = function(doc){ |
| // summary: |
| // Get window object associated with document doc |
| |
| // In some IE versions (at least 6.0), document.parentWindow does not return a |
| // reference to the real window object (maybe a copy), so we must fix it as well |
| // We use IE specific execScript to attach the real window reference to |
| // document._parentWindow for later use |
| if(dojo.isIE && window !== document.parentWindow && !doc._parentWindow){ |
| /* |
| In IE 6, only the variable "window" can be used to connect events (others |
| may be only copies). |
| */ |
| doc.parentWindow.execScript("document._parentWindow = window;", "Javascript"); |
| //to prevent memory leak, unset it after use |
| //another possibility is to add an onUnload handler which seems overkill to me (liucougar) |
| var win = doc._parentWindow; |
| doc._parentWindow = null; |
| return win; // Window |
| } |
| |
| return doc._parentWindow || doc.parentWindow || doc.defaultView; // Window |
| } |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base.popup"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.popup"] = true; |
| dojo.provide("dijit._base.popup"); |
| |
| |
| |
| |
| |
| dijit.popup = new function(){ |
| // summary: |
| // This class is used to show/hide widgets as popups. |
| |
| var stack = [], |
| beginZIndex=1000, |
| idGen = 1; |
| |
| this.moveOffScreen = function(/*DomNode*/ node){ |
| // summary: |
| // Moves node offscreen without hiding it (so that all layout widgets included |
| // in this node can still layout properly) |
| // |
| // description: |
| // Attaches node to dojo.doc.body, and |
| // positions it off screen, but not display:none, so that |
| // the widget doesn't appear in the page flow and/or cause a blank |
| // area at the bottom of the viewport (making scrollbar longer), but |
| // initialization of contained widgets works correctly |
| |
| var s = node.style; |
| s.visibility = "hidden"; // so TAB key doesn't navigate to hidden popup |
| s.position = "absolute"; |
| s.top = "-9999px"; |
| if(s.display == "none"){ |
| s.display=""; |
| } |
| dojo.body().appendChild(node); |
| }; |
| |
| /*===== |
| dijit.popup.__OpenArgs = function(){ |
| // popup: Widget |
| // widget to display |
| // parent: Widget |
| // the button etc. that is displaying this popup |
| // around: DomNode |
| // DOM node (typically a button); place popup relative to this node. (Specify this *or* "x" and "y" parameters.) |
| // x: Integer |
| // Absolute horizontal position (in pixels) to place node at. (Specify this *or* "around" parameter.) |
| // y: Integer |
| // Absolute vertical position (in pixels) to place node at. (Specity this *or* "around" parameter.) |
| // orient: Object || String |
| // When the around parameter is specified, orient should be an |
| // ordered list of tuples of the form (around-node-corner, popup-node-corner). |
| // dijit.popup.open() tries to position the popup according to each tuple in the list, in order, |
| // until the popup appears fully within the viewport. |
| // |
| // The default value is {BL:'TL', TL:'BL'}, which represents a list of two tuples: |
| // 1. (BL, TL) |
| // 2. (TL, BL) |
| // where BL means "bottom left" and "TL" means "top left". |
| // So by default, it first tries putting the popup below the around node, left-aligning them, |
| // and then tries to put it above the around node, still left-aligning them. Note that the |
| // default is horizontally reversed when in RTL mode. |
| // |
| // When an (x,y) position is specified rather than an around node, orient is either |
| // "R" or "L". R (for right) means that it tries to put the popup to the right of the mouse, |
| // specifically positioning the popup's top-right corner at the mouse position, and if that doesn't |
| // fit in the viewport, then it tries, in order, the bottom-right corner, the top left corner, |
| // and the top-right corner. |
| // onCancel: Function |
| // callback when user has canceled the popup by |
| // 1. hitting ESC or |
| // 2. by using the popup widget's proprietary cancel mechanism (like a cancel button in a dialog); |
| // i.e. whenever popupWidget.onCancel() is called, args.onCancel is called |
| // onClose: Function |
| // callback whenever this popup is closed |
| // onExecute: Function |
| // callback when user "executed" on the popup/sub-popup by selecting a menu choice, etc. (top menu only) |
| // padding: dijit.__Position |
| // adding a buffer around the opening position. This is only useful when around is not set. |
| this.popup = popup; |
| this.parent = parent; |
| this.around = around; |
| this.x = x; |
| this.y = y; |
| this.orient = orient; |
| this.onCancel = onCancel; |
| this.onClose = onClose; |
| this.onExecute = onExecute; |
| this.padding = padding; |
| } |
| =====*/ |
| |
| // Compute the closest ancestor popup that's *not* a child of another popup. |
| // Ex: For a TooltipDialog with a button that spawns a tree of menus, find the popup of the button. |
| var getTopPopup = function(){ |
| for(var pi=stack.length-1; pi > 0 && stack[pi].parent === stack[pi-1].widget; pi--){ |
| /* do nothing, just trying to get right value for pi */ |
| } |
| return stack[pi]; |
| }; |
| |
| var wrappers=[]; |
| this.open = function(/*dijit.popup.__OpenArgs*/ args){ |
| // summary: |
| // Popup the widget at the specified position |
| // |
| // example: |
| // opening at the mouse position |
| // | dijit.popup.open({popup: menuWidget, x: evt.pageX, y: evt.pageY}); |
| // |
| // example: |
| // opening the widget as a dropdown |
| // | dijit.popup.open({parent: this, popup: menuWidget, around: this.domNode, onClose: function(){...}}); |
| // |
| // Note that whatever widget called dijit.popup.open() should also listen to its own _onBlur callback |
| // (fired from _base/focus.js) to know that focus has moved somewhere else and thus the popup should be closed. |
| |
| var widget = args.popup, |
| orient = args.orient || ( |
| dojo._isBodyLtr() ? |
| {'BL':'TL', 'BR':'TR', 'TL':'BL', 'TR':'BR'} : |
| {'BR':'TR', 'BL':'TL', 'TR':'BR', 'TL':'BL'} |
| ), |
| around = args.around, |
| id = (args.around && args.around.id) ? (args.around.id+"_dropdown") : ("popup_"+idGen++); |
| |
| // make wrapper div to hold widget and possibly hold iframe behind it. |
| // we can't attach the iframe as a child of the widget.domNode because |
| // widget.domNode might be a <table>, <ul>, etc. |
| |
| var wrapperobj = wrappers.pop(), wrapper, iframe; |
| if(!wrapperobj){ |
| wrapper = dojo.create("div",{ |
| "class":"dijitPopup" |
| }, dojo.body()); |
| dijit.setWaiRole(wrapper, "presentation"); |
| }else{ |
| // recycled a old wrapper, so that we don't need to reattach the iframe |
| // which is slow even if the iframe is empty, see #10167 |
| wrapper = wrapperobj[0]; |
| iframe = wrapperobj[1]; |
| } |
| |
| dojo.attr(wrapper,{ |
| id: id, |
| style:{ |
| zIndex: beginZIndex + stack.length, |
| visibility:"hidden", |
| // prevent transient scrollbar causing misalign (#5776), and initial flash in upper left (#10111) |
| top: "-9999px" |
| }, |
| dijitPopupParent: args.parent ? args.parent.id : "" |
| }); |
| |
| var s = widget.domNode.style; |
| s.display = ""; |
| s.visibility = ""; |
| s.position = ""; |
| s.top = "0px"; |
| wrapper.appendChild(widget.domNode); |
| |
| if(!iframe){ |
| iframe = new dijit.BackgroundIframe(wrapper); |
| }else{ |
| iframe.resize(wrapper) |
| } |
| |
| // position the wrapper node |
| var best = around ? |
| dijit.placeOnScreenAroundElement(wrapper, around, orient, widget.orient ? dojo.hitch(widget, "orient") : null) : |
| dijit.placeOnScreen(wrapper, args, orient == 'R' ? ['TR','BR','TL','BL'] : ['TL','BL','TR','BR'], args.padding); |
| |
| wrapper.style.visibility = "visible"; |
| // TODO: use effects to fade in wrapper |
| |
| var handlers = []; |
| |
| // provide default escape and tab key handling |
| // (this will work for any widget, not just menu) |
| handlers.push(dojo.connect(wrapper, "onkeypress", this, function(evt){ |
| if(evt.charOrCode == dojo.keys.ESCAPE && args.onCancel){ |
| dojo.stopEvent(evt); |
| args.onCancel(); |
| }else if(evt.charOrCode === dojo.keys.TAB){ |
| dojo.stopEvent(evt); |
| var topPopup = getTopPopup(); |
| if(topPopup && topPopup.onCancel){ |
| topPopup.onCancel(); |
| } |
| } |
| })); |
| |
| // watch for cancel/execute events on the popup and notify the caller |
| // (for a menu, "execute" means clicking an item) |
| if(widget.onCancel){ |
| handlers.push(dojo.connect(widget, "onCancel", args.onCancel)); |
| } |
| |
| handlers.push(dojo.connect(widget, widget.onExecute ? "onExecute" : "onChange", function(){ |
| var topPopup = getTopPopup(); |
| if(topPopup && topPopup.onExecute){ |
| topPopup.onExecute(); |
| } |
| })); |
| |
| stack.push({ |
| wrapper: wrapper, |
| iframe: iframe, |
| widget: widget, |
| parent: args.parent, |
| onExecute: args.onExecute, |
| onCancel: args.onCancel, |
| onClose: args.onClose, |
| handlers: handlers |
| }); |
| |
| if(widget.onOpen){ |
| // TODO: in 2.0 standardize onShow() (used by StackContainer) and onOpen() (used here) |
| widget.onOpen(best); |
| } |
| |
| return best; |
| }; |
| |
| this.close = function(/*dijit._Widget*/ popup){ |
| // summary: |
| // Close specified popup and any popups that it parented |
| |
| // Basically work backwards from the top of the stack closing popups |
| // until we hit the specified popup, but IIRC there was some issue where closing |
| // a popup would cause others to close too. Thus if we are trying to close B in [A,B,C] |
| // closing C might close B indirectly and then the while() condition will run where stack==[A]... |
| // so the while condition is constructed defensively. |
| while(dojo.some(stack, function(elem){return elem.widget == popup;})){ |
| var top = stack.pop(), |
| wrapper = top.wrapper, |
| iframe = top.iframe, |
| widget = top.widget, |
| onClose = top.onClose; |
| |
| if(widget.onClose){ |
| // TODO: in 2.0 standardize onHide() (used by StackContainer) and onClose() (used here) |
| widget.onClose(); |
| } |
| dojo.forEach(top.handlers, dojo.disconnect); |
| |
| // Move the widget offscreen, unless it has already been destroyed in above onClose() etc. |
| if(widget && widget.domNode){ |
| this.moveOffScreen(widget.domNode); |
| } |
| |
| // recycle the wrapper plus iframe, so we prevent reattaching iframe everytime an popup opens |
| // don't use moveOffScreen which would also reattach the wrapper to body, which causes reloading of iframe |
| wrapper.style.top = "-9999px"; |
| wrapper.style.visibility = "hidden"; |
| wrappers.push([wrapper,iframe]); |
| |
| if(onClose){ |
| onClose(); |
| } |
| } |
| }; |
| }(); |
| |
| dijit._frames = new function(){ |
| // summary: |
| // cache of iframes |
| var queue = []; |
| |
| this.pop = function(){ |
| var iframe; |
| if(queue.length){ |
| iframe = queue.pop(); |
| iframe.style.display=""; |
| }else{ |
| if(dojo.isIE){ |
| var burl = dojo.config["dojoBlankHtmlUrl"] || (dojo.moduleUrl("dojo", "resources/blank.html")+"") || "javascript:\"\""; |
| var html="<iframe src='" + burl + "'" |
| + " style='position: absolute; left: 0px; top: 0px;" |
| + "z-index: -1; filter:Alpha(Opacity=\"0\");'>"; |
| iframe = dojo.doc.createElement(html); |
| }else{ |
| iframe = dojo.create("iframe"); |
| iframe.src = 'javascript:""'; |
| iframe.className = "dijitBackgroundIframe"; |
| dojo.style(iframe, "opacity", 0.1); |
| } |
| iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didnt work. |
| } |
| return iframe; |
| }; |
| |
| this.push = function(iframe){ |
| iframe.style.display="none"; |
| queue.push(iframe); |
| } |
| }(); |
| |
| |
| dijit.BackgroundIframe = function(/* DomNode */node){ |
| // summary: |
| // For IE/FF z-index schenanigans. id attribute is required. |
| // |
| // description: |
| // new dijit.BackgroundIframe(node) |
| // Makes a background iframe as a child of node, that fills |
| // area (and position) of node |
| |
| if(!node.id){ throw new Error("no id"); } |
| if(dojo.isIE || dojo.isMoz){ |
| var iframe = dijit._frames.pop(); |
| node.appendChild(iframe); |
| if(dojo.isIE<7){ |
| this.resize(node); |
| this._conn = dojo.connect(node, 'onresize', this, function(){ |
| this.resize(node); |
| }); |
| }else{ |
| dojo.style(iframe, { |
| width: '100%', |
| height: '100%' |
| }); |
| } |
| this.iframe = iframe; |
| } |
| }; |
| |
| dojo.extend(dijit.BackgroundIframe, { |
| resize: function(node){ |
| // summary: |
| // resize the iframe so its the same size as node |
| // description: |
| // this function is a no-op in all browsers except |
| // IE6, which does not support 100% width/height |
| // of absolute positioned iframes |
| if(this.iframe && dojo.isIE<7){ |
| dojo.style(this.iframe, { |
| width: node.offsetWidth + 'px', |
| height: node.offsetHeight + 'px' |
| }); |
| } |
| }, |
| destroy: function(){ |
| // summary: |
| // destroy the iframe |
| if(this._conn){ |
| dojo.disconnect(this._conn); |
| this._conn = null; |
| } |
| if(this.iframe){ |
| dijit._frames.push(this.iframe); |
| delete this.iframe; |
| } |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base.scroll"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.scroll"] = true; |
| dojo.provide("dijit._base.scroll"); |
| |
| dijit.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){ |
| // summary: |
| // Scroll the passed node into view, if it is not already. |
| |
| // don't rely on that node.scrollIntoView works just because the function is there |
| |
| try{ // catch unexpected/unrecreatable errors (#7808) since we can recover using a semi-acceptable native method |
| node = dojo.byId(node); |
| var doc = node.ownerDocument || dojo.doc, |
| body = doc.body || dojo.body(), |
| html = doc.documentElement || body.parentNode, |
| isIE = dojo.isIE, isWK = dojo.isWebKit; |
| // if an untested browser, then use the native method |
| if((!(dojo.isMoz || isIE || isWK) || node == body || node == html) && (typeof node.scrollIntoView != "undefined")){ |
| node.scrollIntoView(false); // short-circuit to native if possible |
| return; |
| } |
| var backCompat = doc.compatMode == 'BackCompat', |
| clientAreaRoot = backCompat? body : html, |
| scrollRoot = isWK ? body : clientAreaRoot, |
| rootWidth = clientAreaRoot.clientWidth, |
| rootHeight = clientAreaRoot.clientHeight, |
| rtl = !dojo._isBodyLtr(), |
| nodePos = pos || dojo.position(node), |
| el = node.parentNode, |
| isFixed = function(el){ |
| return ((isIE <= 6 || (isIE && backCompat))? false : (dojo.style(el, 'position').toLowerCase() == "fixed")); |
| }; |
| if(isFixed(node)){ return; } // nothing to do |
| while(el){ |
| if(el == body){ el = scrollRoot; } |
| var elPos = dojo.position(el), |
| fixedPos = isFixed(el); |
| with(elPos){ |
| if(el == scrollRoot){ |
| w = rootWidth, h = rootHeight; |
| if(scrollRoot == html && isIE && rtl){ x += scrollRoot.offsetWidth-w; } // IE workaround where scrollbar causes negative x |
| if(x < 0 || !isIE){ x = 0; } // IE can have values > 0 |
| if(y < 0 || !isIE){ y = 0; } |
| }else{ |
| var pb = dojo._getPadBorderExtents(el); |
| w -= pb.w; h -= pb.h; x += pb.l; y += pb.t; |
| } |
| with(el){ |
| if(el != scrollRoot){ // body, html sizes already have the scrollbar removed |
| var clientSize = clientWidth, |
| scrollBarSize = w - clientSize; |
| if(clientSize > 0 && scrollBarSize > 0){ |
| w = clientSize; |
| if(isIE && rtl){ x += scrollBarSize; } |
| } |
| clientSize = clientHeight; |
| scrollBarSize = h - clientSize; |
| if(clientSize > 0 && scrollBarSize > 0){ |
| h = clientSize; |
| } |
| } |
| if(fixedPos){ // bounded by viewport, not parents |
| if(y < 0){ |
| h += y, y = 0; |
| } |
| if(x < 0){ |
| w += x, x = 0; |
| } |
| if(y + h > rootHeight){ |
| h = rootHeight - y; |
| } |
| if(x + w > rootWidth){ |
| w = rootWidth - x; |
| } |
| } |
| // calculate overflow in all 4 directions |
| var l = nodePos.x - x, // beyond left: < 0 |
| t = nodePos.y - Math.max(y, 0), // beyond top: < 0 |
| r = l + nodePos.w - w, // beyond right: > 0 |
| bot = t + nodePos.h - h; // beyond bottom: > 0 |
| if(r * l > 0){ |
| var s = Math[l < 0? "max" : "min"](l, r); |
| nodePos.x += scrollLeft; |
| scrollLeft += (isIE >= 8 && !backCompat && rtl)? -s : s; |
| nodePos.x -= scrollLeft; |
| } |
| if(bot * t > 0){ |
| nodePos.y += scrollTop; |
| scrollTop += Math[t < 0? "max" : "min"](t, bot); |
| nodePos.y -= scrollTop; |
| } |
| } |
| } |
| el = (el != scrollRoot) && !fixedPos && el.parentNode; |
| } |
| }catch(error){ |
| console.error('scrollIntoView: ' + error); |
| node.scrollIntoView(false); |
| } |
| }; |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base.sniff"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.sniff"] = true; |
| // summary: |
| // Applies pre-set CSS classes to the top-level HTML node, based on: |
| // - browser (ex: dj_ie) |
| // - browser version (ex: dj_ie6) |
| // - box model (ex: dj_contentBox) |
| // - text direction (ex: dijitRtl) |
| // |
| // In addition, browser, browser version, and box model are |
| // combined with an RTL flag when browser text is RTL. ex: dj_ie-rtl. |
| // |
| // Simply doing a require on this module will |
| // establish this CSS. Modified version of Morris' CSS hack. |
| |
| dojo.provide("dijit._base.sniff"); |
| |
| (function(){ |
| |
| var d = dojo, |
| html = d.doc.documentElement, |
| ie = d.isIE, |
| opera = d.isOpera, |
| maj = Math.floor, |
| ff = d.isFF, |
| boxModel = d.boxModel.replace(/-/,''), |
| |
| classes = { |
| dj_ie: ie, |
| dj_ie6: maj(ie) == 6, |
| dj_ie7: maj(ie) == 7, |
| dj_ie8: maj(ie) == 8, |
| dj_iequirks: ie && d.isQuirks, |
| |
| // NOTE: Opera not supported by dijit |
| dj_opera: opera, |
| |
| dj_khtml: d.isKhtml, |
| |
| dj_webkit: d.isWebKit, |
| dj_safari: d.isSafari, |
| dj_chrome: d.isChrome, |
| |
| dj_gecko: d.isMozilla, |
| dj_ff3: maj(ff) == 3 |
| }; // no dojo unsupported browsers |
| |
| classes["dj_" + boxModel] = true; |
| |
| // apply browser, browser version, and box model class names |
| for(var p in classes){ |
| if(classes[p]){ |
| if(html.className){ |
| html.className += " " + p; |
| }else{ |
| html.className = p; |
| } |
| } |
| } |
| |
| // If RTL mode then add dijitRtl flag plus repeat existing classes |
| // with -rtl extension |
| // (unshift is to make this code run after <body> node is loaded but before parser runs) |
| dojo._loaders.unshift(function(){ |
| if(!dojo._isBodyLtr()){ |
| html.className += " dijitRtl"; |
| for(var p in classes){ |
| if(classes[p]){ |
| html.className += " " + p + "-rtl"; |
| } |
| } |
| } |
| }); |
| |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base.typematic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.typematic"] = true; |
| dojo.provide("dijit._base.typematic"); |
| |
| dijit.typematic = { |
| // summary: |
| // These functions are used to repetitively call a user specified callback |
| // method when a specific key or mouse click over a specific DOM node is |
| // held down for a specific amount of time. |
| // Only 1 such event is allowed to occur on the browser page at 1 time. |
| |
| _fireEventAndReload: function(){ |
| this._timer = null; |
| this._callback(++this._count, this._node, this._evt); |
| |
| // Schedule next event, reducing the timer a little bit each iteration, bottoming-out at 10 to avoid |
| // browser overload (particularly avoiding starving DOH robot so it never gets to send a mouseup) |
| this._currentTimeout = Math.max( |
| this._currentTimeout < 0 ? this._initialDelay : |
| (this._subsequentDelay > 1 ? this._subsequentDelay : Math.round(this._currentTimeout * this._subsequentDelay)), |
| 10); |
| this._timer = setTimeout(dojo.hitch(this, "_fireEventAndReload"), this._currentTimeout); |
| }, |
| |
| trigger: function(/*Event*/ evt, /* Object */ _this, /*DOMNode*/ node, /* Function */ callback, /* Object */ obj, /* Number */ subsequentDelay, /* Number */ initialDelay){ |
| // summary: |
| // Start a timed, repeating callback sequence. |
| // If already started, the function call is ignored. |
| // This method is not normally called by the user but can be |
| // when the normal listener code is insufficient. |
| // evt: |
| // key or mouse event object to pass to the user callback |
| // _this: |
| // pointer to the user's widget space. |
| // node: |
| // the DOM node object to pass the the callback function |
| // callback: |
| // function to call until the sequence is stopped called with 3 parameters: |
| // count: |
| // integer representing number of repeated calls (0..n) with -1 indicating the iteration has stopped |
| // node: |
| // the DOM node object passed in |
| // evt: |
| // key or mouse event object |
| // obj: |
| // user space object used to uniquely identify each typematic sequence |
| // subsequentDelay: |
| // if > 1, the number of milliseconds until the 3->n events occur |
| // or else the fractional time multiplier for the next event's delay, default=0.9 |
| // initialDelay: |
| // the number of milliseconds until the 2nd event occurs, default=500ms |
| if(obj != this._obj){ |
| this.stop(); |
| this._initialDelay = initialDelay || 500; |
| this._subsequentDelay = subsequentDelay || 0.90; |
| this._obj = obj; |
| this._evt = evt; |
| this._node = node; |
| this._currentTimeout = -1; |
| this._count = -1; |
| this._callback = dojo.hitch(_this, callback); |
| this._fireEventAndReload(); |
| } |
| }, |
| |
| stop: function(){ |
| // summary: |
| // Stop an ongoing timed, repeating callback sequence. |
| if(this._timer){ |
| clearTimeout(this._timer); |
| this._timer = null; |
| } |
| if(this._obj){ |
| this._callback(-1, this._node, this._evt); |
| this._obj = null; |
| } |
| }, |
| |
| addKeyListener: function(/*DOMNode*/ node, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay){ |
| // summary: |
| // Start listening for a specific typematic key. |
| // See also the trigger method for other parameters. |
| // keyObject: |
| // an object defining the key to listen for. |
| // charOrCode: |
| // the printable character (string) or keyCode (number) to listen for. |
| // keyCode: |
| // (deprecated - use charOrCode) the keyCode (number) to listen for (implies charCode = 0). |
| // charCode: |
| // (deprecated - use charOrCode) the charCode (number) to listen for. |
| // ctrlKey: |
| // desired ctrl key state to initiate the calback sequence: |
| // - pressed (true) |
| // - released (false) |
| // - either (unspecified) |
| // altKey: |
| // same as ctrlKey but for the alt key |
| // shiftKey: |
| // same as ctrlKey but for the shift key |
| // returns: |
| // an array of dojo.connect handles |
| if(keyObject.keyCode){ |
| keyObject.charOrCode = keyObject.keyCode; |
| dojo.deprecated("keyCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0"); |
| }else if(keyObject.charCode){ |
| keyObject.charOrCode = String.fromCharCode(keyObject.charCode); |
| dojo.deprecated("charCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0"); |
| } |
| return [ |
| dojo.connect(node, "onkeypress", this, function(evt){ |
| if(evt.charOrCode == keyObject.charOrCode && |
| (keyObject.ctrlKey === undefined || keyObject.ctrlKey == evt.ctrlKey) && |
| (keyObject.altKey === undefined || keyObject.altKey == evt.altKey) && |
| (keyObject.metaKey === undefined || keyObject.metaKey == (evt.metaKey || false)) && // IE doesn't even set metaKey |
| (keyObject.shiftKey === undefined || keyObject.shiftKey == evt.shiftKey)){ |
| dojo.stopEvent(evt); |
| dijit.typematic.trigger(keyObject, _this, node, callback, keyObject, subsequentDelay, initialDelay); |
| }else if(dijit.typematic._obj == keyObject){ |
| dijit.typematic.stop(); |
| } |
| }), |
| dojo.connect(node, "onkeyup", this, function(evt){ |
| if(dijit.typematic._obj == keyObject){ |
| dijit.typematic.stop(); |
| } |
| }) |
| ]; |
| }, |
| |
| addMouseListener: function(/*DOMNode*/ node, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay){ |
| // summary: |
| // Start listening for a typematic mouse click. |
| // See the trigger method for other parameters. |
| // returns: |
| // an array of dojo.connect handles |
| var dc = dojo.connect; |
| return [ |
| dc(node, "mousedown", this, function(evt){ |
| dojo.stopEvent(evt); |
| dijit.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay); |
| }), |
| dc(node, "mouseup", this, function(evt){ |
| dojo.stopEvent(evt); |
| dijit.typematic.stop(); |
| }), |
| dc(node, "mouseout", this, function(evt){ |
| dojo.stopEvent(evt); |
| dijit.typematic.stop(); |
| }), |
| dc(node, "mousemove", this, function(evt){ |
| dojo.stopEvent(evt); |
| }), |
| dc(node, "dblclick", this, function(evt){ |
| dojo.stopEvent(evt); |
| if(dojo.isIE){ |
| dijit.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay); |
| setTimeout(dojo.hitch(this, dijit.typematic.stop), 50); |
| } |
| }) |
| ]; |
| }, |
| |
| addListener: function(/*Node*/ mouseNode, /*Node*/ keyNode, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay){ |
| // summary: |
| // Start listening for a specific typematic key and mouseclick. |
| // This is a thin wrapper to addKeyListener and addMouseListener. |
| // See the addMouseListener and addKeyListener methods for other parameters. |
| // mouseNode: |
| // the DOM node object to listen on for mouse events. |
| // keyNode: |
| // the DOM node object to listen on for key events. |
| // returns: |
| // an array of dojo.connect handles |
| return this.addKeyListener(keyNode, keyObject, _this, callback, subsequentDelay, initialDelay).concat( |
| this.addMouseListener(mouseNode, _this, callback, subsequentDelay, initialDelay)); |
| } |
| }; |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base.wai"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base.wai"] = true; |
| dojo.provide("dijit._base.wai"); |
| |
| dijit.wai = { |
| onload: function(){ |
| // summary: |
| // Detects if we are in high-contrast mode or not |
| |
| // This must be a named function and not an anonymous |
| // function, so that the widget parsing code can make sure it |
| // registers its onload function after this function. |
| // DO NOT USE "this" within this function. |
| |
| // create div for testing if high contrast mode is on or images are turned off |
| var div = dojo.create("div",{ |
| id: "a11yTestNode", |
| style:{ |
| cssText:'border: 1px solid;' |
| + 'border-color:red green;' |
| + 'position: absolute;' |
| + 'height: 5px;' |
| + 'top: -999px;' |
| + 'background-image: url("' + (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")) + '");' |
| } |
| }, dojo.body()); |
| |
| // test it |
| var cs = dojo.getComputedStyle(div); |
| if(cs){ |
| var bkImg = cs.backgroundImage; |
| var needsA11y = (cs.borderTopColor == cs.borderRightColor) || (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)" )); |
| dojo[needsA11y ? "addClass" : "removeClass"](dojo.body(), "dijit_a11y"); |
| if(dojo.isIE){ |
| div.outerHTML = ""; // prevent mixed-content warning, see http://support.microsoft.com/kb/925014 |
| }else{ |
| dojo.body().removeChild(div); |
| } |
| } |
| } |
| }; |
| |
| // Test if computer is in high contrast mode. |
| // Make sure the a11y test runs first, before widgets are instantiated. |
| if(dojo.isIE || dojo.isMoz){ // NOTE: checking in Safari messes things up |
| dojo._loaders.unshift(dijit.wai.onload); |
| } |
| |
| dojo.mixin(dijit, { |
| _XhtmlRoles: /banner|contentinfo|definition|main|navigation|search|note|secondary|seealso/, |
| |
| hasWaiRole: function(/*Element*/ elem, /*String*/ role){ |
| // summary: |
| // Determines if an element has a particular non-XHTML role. |
| // returns: |
| // True if elem has the specific non-XHTML role attribute and false if not. |
| // For backwards compatibility if role parameter not provided, |
| // returns true if has non XHTML role |
| var waiRole = this.getWaiRole(elem); |
| return role ? (waiRole.indexOf(role) > -1) : (waiRole.length > 0); |
| }, |
| |
| getWaiRole: function(/*Element*/ elem){ |
| // summary: |
| // Gets the non-XHTML role for an element (which should be a wai role). |
| // returns: |
| // The non-XHTML role of elem or an empty string if elem |
| // does not have a role. |
| return dojo.trim((dojo.attr(elem, "role") || "").replace(this._XhtmlRoles,"").replace("wairole:","")); |
| }, |
| |
| setWaiRole: function(/*Element*/ elem, /*String*/ role){ |
| // summary: |
| // Sets the role on an element. |
| // description: |
| // Replace existing role attribute with new role. |
| // If elem already has an XHTML role, append this role to XHTML role |
| // and remove other ARIA roles. |
| |
| var curRole = dojo.attr(elem, "role") || ""; |
| if(!this._XhtmlRoles.test(curRole)){ |
| dojo.attr(elem, "role", role); |
| }else{ |
| if((" "+ curRole +" ").indexOf(" " + role + " ") < 0){ |
| var clearXhtml = dojo.trim(curRole.replace(this._XhtmlRoles, "")); |
| var cleanRole = dojo.trim(curRole.replace(clearXhtml, "")); |
| dojo.attr(elem, "role", cleanRole + (cleanRole ? ' ' : '') + role); |
| } |
| } |
| }, |
| |
| removeWaiRole: function(/*Element*/ elem, /*String*/ role){ |
| // summary: |
| // Removes the specified non-XHTML role from an element. |
| // Removes role attribute if no specific role provided (for backwards compat.) |
| |
| var roleValue = dojo.attr(elem, "role"); |
| if(!roleValue){ return; } |
| if(role){ |
| var t = dojo.trim((" " + roleValue + " ").replace(" " + role + " ", " ")); |
| dojo.attr(elem, "role", t); |
| }else{ |
| elem.removeAttribute("role"); |
| } |
| }, |
| |
| hasWaiState: function(/*Element*/ elem, /*String*/ state){ |
| // summary: |
| // Determines if an element has a given state. |
| // description: |
| // Checks for an attribute called "aria-"+state. |
| // returns: |
| // true if elem has a value for the given state and |
| // false if it does not. |
| |
| return elem.hasAttribute ? elem.hasAttribute("aria-"+state) : !!elem.getAttribute("aria-"+state); |
| }, |
| |
| getWaiState: function(/*Element*/ elem, /*String*/ state){ |
| // summary: |
| // Gets the value of a state on an element. |
| // description: |
| // Checks for an attribute called "aria-"+state. |
| // returns: |
| // The value of the requested state on elem |
| // or an empty string if elem has no value for state. |
| |
| return elem.getAttribute("aria-"+state) || ""; |
| }, |
| |
| setWaiState: function(/*Element*/ elem, /*String*/ state, /*String*/ value){ |
| // summary: |
| // Sets a state on an element. |
| // description: |
| // Sets an attribute called "aria-"+state. |
| |
| elem.setAttribute("aria-"+state, value); |
| }, |
| |
| removeWaiState: function(/*Element*/ elem, /*String*/ state){ |
| // summary: |
| // Removes a state from an element. |
| // description: |
| // Sets an attribute called "aria-"+state. |
| |
| elem.removeAttribute("aria-"+state); |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dijit._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._base"] = true; |
| dojo.provide("dijit._base"); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| } |
| |
| if(!dojo._hasResource["dijit._Widget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._Widget"] = true; |
| dojo.provide("dijit._Widget"); |
| |
| dojo.require( "dijit._base" ); |
| |
| |
| // This code is to assist deferring dojo.connect() calls in widgets (connecting to events on the widgets' |
| // DOM nodes) until someone actually needs to monitor that event. |
| dojo.connect(dojo, "_connect", |
| function(/*dijit._Widget*/ widget, /*String*/ event){ |
| if(widget && dojo.isFunction(widget._onConnect)){ |
| widget._onConnect(event); |
| } |
| }); |
| |
| dijit._connectOnUseEventHandler = function(/*Event*/ event){}; |
| |
| // Keep track of where the last keydown event was, to help avoid generating |
| // spurious ondijitclick events when: |
| // 1. focus is on a <button> or <a> |
| // 2. user presses then releases the ENTER key |
| // 3. onclick handler fires and shifts focus to another node, with an ondijitclick handler |
| // 4. onkeyup event fires, causing the ondijitclick handler to fire |
| dijit._lastKeyDownNode = null; |
| if(dojo.isIE){ |
| (function(){ |
| var keydownCallback = function(evt){ |
| dijit._lastKeyDownNode = evt.srcElement; |
| }; |
| dojo.doc.attachEvent('onkeydown', keydownCallback); |
| dojo.addOnWindowUnload(function(){ |
| dojo.doc.detachEvent('onkeydown', keydownCallback); |
| }); |
| })(); |
| }else{ |
| dojo.doc.addEventListener('keydown', function(evt){ |
| dijit._lastKeyDownNode = evt.target; |
| }, true); |
| } |
| |
| (function(){ |
| |
| var _attrReg = {}, // cached results from getSetterAttributes |
| getSetterAttributes = function(widget){ |
| // summary: |
| // Returns list of attributes with custom setters for specified widget |
| var dc = widget.declaredClass; |
| if(!_attrReg[dc]){ |
| var r = [], |
| attrs, |
| proto = widget.constructor.prototype; |
| for(var fxName in proto){ |
| if(dojo.isFunction(proto[fxName]) && (attrs = fxName.match(/^_set([a-zA-Z]*)Attr$/)) && attrs[1]){ |
| r.push(attrs[1].charAt(0).toLowerCase() + attrs[1].substr(1)); |
| } |
| } |
| _attrReg[dc] = r; |
| } |
| return _attrReg[dc] || []; // String[] |
| }; |
| |
| dojo.declare("dijit._Widget", null, { |
| // summary: |
| // Base class for all Dijit widgets. |
| |
| // id: [const] String |
| // A unique, opaque ID string that can be assigned by users or by the |
| // system. If the developer passes an ID which is known not to be |
| // unique, the specified ID is ignored and the system-generated ID is |
| // used instead. |
| id: "", |
| |
| // lang: [const] String |
| // Rarely used. Overrides the default Dojo locale used to render this widget, |
| // as defined by the [HTML LANG](http://www.w3.org/TR/html401/struct/dirlang.html#adef-lang) attribute. |
| // Value must be among the list of locales specified during by the Dojo bootstrap, |
| // formatted according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt) (like en-us). |
| lang: "", |
| |
| // dir: [const] String |
| // Unsupported by Dijit, but here for completeness. Dijit only supports setting text direction on the |
| // entire document. |
| // Bi-directional support, as defined by the [HTML DIR](http://www.w3.org/TR/html401/struct/dirlang.html#adef-dir) |
| // attribute. Either left-to-right "ltr" or right-to-left "rtl". |
| dir: "", |
| |
| // class: String |
| // HTML class attribute |
| "class": "", |
| |
| // style: String||Object |
| // HTML style attributes as cssText string or name/value hash |
| style: "", |
| |
| // title: String |
| // HTML title attribute. |
| // |
| // For form widgets this specifies a tooltip to display when hovering over |
| // the widget (just like the native HTML title attribute). |
| // |
| // For TitlePane or for when this widget is a child of a TabContainer, AccordionContainer, |
| // etc., it's used to specify the tab label, accordion pane title, etc. |
| title: "", |
| |
| // tooltip: String |
| // When this widget's title attribute is used to for a tab label, accordion pane title, etc., |
| // this specifies the tooltip to appear when the mouse is hovered over that text. |
| tooltip: "", |
| |
| // srcNodeRef: [readonly] DomNode |
| // pointer to original DOM node |
| srcNodeRef: null, |
| |
| // domNode: [readonly] DomNode |
| // This is our visible representation of the widget! Other DOM |
| // Nodes may by assigned to other properties, usually through the |
| // template system's dojoAttachPoint syntax, but the domNode |
| // property is the canonical "top level" node in widget UI. |
| domNode: null, |
| |
| // containerNode: [readonly] DomNode |
| // Designates where children of the source DOM node will be placed. |
| // "Children" in this case refers to both DOM nodes and widgets. |
| // For example, for myWidget: |
| // |
| // | <div dojoType=myWidget> |
| // | <b> here's a plain DOM node |
| // | <span dojoType=subWidget>and a widget</span> |
| // | <i> and another plain DOM node </i> |
| // | </div> |
| // |
| // containerNode would point to: |
| // |
| // | <b> here's a plain DOM node |
| // | <span dojoType=subWidget>and a widget</span> |
| // | <i> and another plain DOM node </i> |
| // |
| // In templated widgets, "containerNode" is set via a |
| // dojoAttachPoint assignment. |
| // |
| // containerNode must be defined for any widget that accepts innerHTML |
| // (like ContentPane or BorderContainer or even Button), and conversely |
| // is null for widgets that don't, like TextBox. |
| containerNode: null, |
| |
| /*===== |
| // _started: Boolean |
| // startup() has completed. |
| _started: false, |
| =====*/ |
| |
| // attributeMap: [protected] Object |
| // attributeMap sets up a "binding" between attributes (aka properties) |
| // of the widget and the widget's DOM. |
| // Changes to widget attributes listed in attributeMap will be |
| // reflected into the DOM. |
| // |
| // For example, calling attr('title', 'hello') |
| // on a TitlePane will automatically cause the TitlePane's DOM to update |
| // with the new title. |
| // |
| // attributeMap is a hash where the key is an attribute of the widget, |
| // and the value reflects a binding to a: |
| // |
| // - DOM node attribute |
| // | focus: {node: "focusNode", type: "attribute"} |
| // Maps this.focus to this.focusNode.focus |
| // |
| // - DOM node innerHTML |
| // | title: { node: "titleNode", type: "innerHTML" } |
| // Maps this.title to this.titleNode.innerHTML |
| // |
| // - DOM node innerText |
| // | title: { node: "titleNode", type: "innerText" } |
| // Maps this.title to this.titleNode.innerText |
| // |
| // - DOM node CSS class |
| // | myClass: { node: "domNode", type: "class" } |
| // Maps this.myClass to this.domNode.className |
| // |
| // If the value is an array, then each element in the array matches one of the |
| // formats of the above list. |
| // |
| // There are also some shorthands for backwards compatibility: |
| // - string --> { node: string, type: "attribute" }, for example: |
| // | "focusNode" ---> { node: "focusNode", type: "attribute" } |
| // - "" --> { node: "domNode", type: "attribute" } |
| attributeMap: {id:"", dir:"", lang:"", "class":"", style:"", title:""}, |
| |
| // _deferredConnects: [protected] Object |
| // attributeMap addendum for event handlers that should be connected only on first use |
| _deferredConnects: { |
| onClick: "", |
| onDblClick: "", |
| onKeyDown: "", |
| onKeyPress: "", |
| onKeyUp: "", |
| onMouseMove: "", |
| onMouseDown: "", |
| onMouseOut: "", |
| onMouseOver: "", |
| onMouseLeave: "", |
| onMouseEnter: "", |
| onMouseUp: "" |
| }, |
| |
| onClick: dijit._connectOnUseEventHandler, |
| /*===== |
| onClick: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of mouse click events. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onDblClick: dijit._connectOnUseEventHandler, |
| /*===== |
| onDblClick: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of mouse double click events. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onKeyDown: dijit._connectOnUseEventHandler, |
| /*===== |
| onKeyDown: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of keys being pressed down. |
| // event: |
| // key Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onKeyPress: dijit._connectOnUseEventHandler, |
| /*===== |
| onKeyPress: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of printable keys being typed. |
| // event: |
| // key Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onKeyUp: dijit._connectOnUseEventHandler, |
| /*===== |
| onKeyUp: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of keys being released. |
| // event: |
| // key Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onMouseDown: dijit._connectOnUseEventHandler, |
| /*===== |
| onMouseDown: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of when the mouse button is pressed down. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onMouseMove: dijit._connectOnUseEventHandler, |
| /*===== |
| onMouseMove: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of when the mouse moves over nodes contained within this widget. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onMouseOut: dijit._connectOnUseEventHandler, |
| /*===== |
| onMouseOut: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of when the mouse moves off of nodes contained within this widget. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onMouseOver: dijit._connectOnUseEventHandler, |
| /*===== |
| onMouseOver: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of when the mouse moves onto nodes contained within this widget. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onMouseLeave: dijit._connectOnUseEventHandler, |
| /*===== |
| onMouseLeave: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of when the mouse moves off of this widget. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onMouseEnter: dijit._connectOnUseEventHandler, |
| /*===== |
| onMouseEnter: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of when the mouse moves onto this widget. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| onMouseUp: dijit._connectOnUseEventHandler, |
| /*===== |
| onMouseUp: function(event){ |
| // summary: |
| // Connect to this function to receive notifications of when the mouse button is released. |
| // event: |
| // mouse Event |
| // tags: |
| // callback |
| }, |
| =====*/ |
| |
| // Constants used in templates |
| |
| // _blankGif: [protected] String |
| // Path to a blank 1x1 image. |
| // Used by <img> nodes in templates that really get their image via CSS background-image. |
| _blankGif: (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")).toString(), |
| |
| //////////// INITIALIZATION METHODS /////////////////////////////////////// |
| |
| postscript: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){ |
| // summary: |
| // Kicks off widget instantiation. See create() for details. |
| // tags: |
| // private |
| this.create(params, srcNodeRef); |
| }, |
| |
| create: function(/*Object?*/params, /*DomNode|String?*/srcNodeRef){ |
| // summary: |
| // Kick off the life-cycle of a widget |
| // params: |
| // Hash of initialization parameters for widget, including |
| // scalar values (like title, duration etc.) and functions, |
| // typically callbacks like onClick. |
| // srcNodeRef: |
| // If a srcNodeRef (DOM node) is specified: |
| // - use srcNodeRef.innerHTML as my contents |
| // - if this is a behavioral widget then apply behavior |
| // to that srcNodeRef |
| // - otherwise, replace srcNodeRef with my generated DOM |
| // tree |
| // description: |
| // Create calls a number of widget methods (postMixInProperties, buildRendering, postCreate, |
| // etc.), some of which of you'll want to override. See http://docs.dojocampus.org/dijit/_Widget |
| // for a discussion of the widget creation lifecycle. |
| // |
| // Of course, adventurous developers could override create entirely, but this should |
| // only be done as a last resort. |
| // tags: |
| // private |
| |
| // store pointer to original DOM tree |
| this.srcNodeRef = dojo.byId(srcNodeRef); |
| |
| // For garbage collection. An array of handles returned by Widget.connect() |
| // Each handle returned from Widget.connect() is an array of handles from dojo.connect() |
| this._connects = []; |
| |
| // For garbage collection. An array of handles returned by Widget.subscribe() |
| // The handle returned from Widget.subscribe() is the handle returned from dojo.subscribe() |
| this._subscribes = []; |
| |
| // To avoid double-connects, remove entries from _deferredConnects |
| // that have been setup manually by a subclass (ex, by dojoAttachEvent). |
| // If a subclass has redefined a callback (ex: onClick) then assume it's being |
| // connected to manually. |
| this._deferredConnects = dojo.clone(this._deferredConnects); |
| for(var attr in this.attributeMap){ |
| delete this._deferredConnects[attr]; // can't be in both attributeMap and _deferredConnects |
| } |
| for(attr in this._deferredConnects){ |
| if(this[attr] !== dijit._connectOnUseEventHandler){ |
| delete this._deferredConnects[attr]; // redefined, probably dojoAttachEvent exists |
| } |
| } |
| |
| //mixin our passed parameters |
| if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; } |
| if(params){ |
| this.params = params; |
| dojo.mixin(this,params); |
| } |
| this.postMixInProperties(); |
| |
| // generate an id for the widget if one wasn't specified |
| // (be sure to do this before buildRendering() because that function might |
| // expect the id to be there.) |
| if(!this.id){ |
| this.id = dijit.getUniqueId(this.declaredClass.replace(/\./g,"_")); |
| } |
| dijit.registry.add(this); |
| |
| this.buildRendering(); |
| |
| if(this.domNode){ |
| // Copy attributes listed in attributeMap into the [newly created] DOM for the widget. |
| this._applyAttributes(); |
| |
| var source = this.srcNodeRef; |
| if(source && source.parentNode){ |
| source.parentNode.replaceChild(this.domNode, source); |
| } |
| |
| // If the developer has specified a handler as a widget parameter |
| // (ex: new Button({onClick: ...}) |
| // then naturally need to connect from DOM node to that handler immediately, |
| for(attr in this.params){ |
| this._onConnect(attr); |
| } |
| } |
| |
| if(this.domNode){ |
| this.domNode.setAttribute("widgetId", this.id); |
| } |
| this.postCreate(); |
| |
| // If srcNodeRef has been processed and removed from the DOM (e.g. TemplatedWidget) then delete it to allow GC. |
| if(this.srcNodeRef && !this.srcNodeRef.parentNode){ |
| delete this.srcNodeRef; |
| } |
| |
| this._created = true; |
| }, |
| |
| _applyAttributes: function(){ |
| // summary: |
| // Step during widget creation to copy all widget attributes to the |
| // DOM as per attributeMap and _setXXXAttr functions. |
| // description: |
| // Skips over blank/false attribute values, unless they were explicitly specified |
| // as parameters to the widget, since those are the default anyway, |
| // and setting tabIndex="" is different than not setting tabIndex at all. |
| // |
| // It processes the attributes in the attribute map first, and then |
| // it goes through and processes the attributes for the _setXXXAttr |
| // functions that have been specified |
| // tags: |
| // private |
| var condAttrApply = function(attr, scope){ |
| if((scope.params && attr in scope.params) || scope[attr]){ |
| scope.attr(attr, scope[attr]); |
| } |
| }; |
| |
| // Do the attributes in attributeMap |
| for(var attr in this.attributeMap){ |
| condAttrApply(attr, this); |
| } |
| |
| // And also any attributes with custom setters |
| dojo.forEach(getSetterAttributes(this), function(a){ |
| if(!(a in this.attributeMap)){ |
| condAttrApply(a, this); |
| } |
| }, this); |
| }, |
| |
| postMixInProperties: function(){ |
| // summary: |
| // Called after the parameters to the widget have been read-in, |
| // but before the widget template is instantiated. Especially |
| // useful to set properties that are referenced in the widget |
| // template. |
| // tags: |
| // protected |
| }, |
| |
| buildRendering: function(){ |
| // summary: |
| // Construct the UI for this widget, setting this.domNode |
| // description: |
| // Most widgets will mixin `dijit._Templated`, which implements this |
| // method. |
| // tags: |
| // protected |
| this.domNode = this.srcNodeRef || dojo.create('div'); |
| }, |
| |
| postCreate: function(){ |
| // summary: |
| // Processing after the DOM fragment is created |
| // description: |
| // Called after the DOM fragment has been created, but not necessarily |
| // added to the document. Do not include any operations which rely on |
| // node dimensions or placement. |
| // tags: |
| // protected |
| }, |
| |
| startup: function(){ |
| // summary: |
| // Processing after the DOM fragment is added to the document |
| // description: |
| // Called after a widget and its children have been created and added to the page, |
| // and all related widgets have finished their create() cycle, up through postCreate(). |
| // This is useful for composite widgets that need to control or layout sub-widgets. |
| // Many layout widgets can use this as a wiring phase. |
| this._started = true; |
| }, |
| |
| //////////// DESTROY FUNCTIONS //////////////////////////////// |
| |
| destroyRecursive: function(/*Boolean?*/ preserveDom){ |
| // summary: |
| // Destroy this widget and its descendants |
| // description: |
| // This is the generic "destructor" function that all widget users |
| // should call to cleanly discard with a widget. Once a widget is |
| // destroyed, it is removed from the manager object. |
| // preserveDom: |
| // If true, this method will leave the original DOM structure |
| // alone of descendant Widgets. Note: This will NOT work with |
| // dijit._Templated widgets. |
| |
| this._beingDestroyed = true; |
| this.destroyDescendants(preserveDom); |
| this.destroy(preserveDom); |
| }, |
| |
| destroy: function(/*Boolean*/ preserveDom){ |
| // summary: |
| // Destroy this widget, but not its descendants. |
| // This method will, however, destroy internal widgets such as those used within a template. |
| // preserveDom: Boolean |
| // If true, this method will leave the original DOM structure alone. |
| // Note: This will not yet work with _Templated widgets |
| |
| this._beingDestroyed = true; |
| this.uninitialize(); |
| var d = dojo, |
| dfe = d.forEach, |
| dun = d.unsubscribe; |
| dfe(this._connects, function(array){ |
| dfe(array, d.disconnect); |
| }); |
| dfe(this._subscribes, function(handle){ |
| dun(handle); |
| }); |
| |
| // destroy widgets created as part of template, etc. |
| dfe(this._supportingWidgets || [], function(w){ |
| if(w.destroyRecursive){ |
| w.destroyRecursive(); |
| }else if(w.destroy){ |
| w.destroy(); |
| } |
| }); |
| |
| this.destroyRendering(preserveDom); |
| dijit.registry.remove(this.id); |
| this._destroyed = true; |
| }, |
| |
| destroyRendering: function(/*Boolean?*/ preserveDom){ |
| // summary: |
| // Destroys the DOM nodes associated with this widget |
| // preserveDom: |
| // If true, this method will leave the original DOM structure alone |
| // during tear-down. Note: this will not work with _Templated |
| // widgets yet. |
| // tags: |
| // protected |
| |
| if(this.bgIframe){ |
| this.bgIframe.destroy(preserveDom); |
| delete this.bgIframe; |
| } |
| |
| if(this.domNode){ |
| if(preserveDom){ |
| dojo.removeAttr(this.domNode, "widgetId"); |
| }else{ |
| dojo.destroy(this.domNode); |
| } |
| delete this.domNode; |
| } |
| |
| if(this.srcNodeRef){ |
| if(!preserveDom){ |
| dojo.destroy(this.srcNodeRef); |
| } |
| delete this.srcNodeRef; |
| } |
| }, |
| |
| destroyDescendants: function(/*Boolean?*/ preserveDom){ |
| // summary: |
| // Recursively destroy the children of this widget and their |
| // descendants. |
| // preserveDom: |
| // If true, the preserveDom attribute is passed to all descendant |
| // widget's .destroy() method. Not for use with _Templated |
| // widgets. |
| |
| // get all direct descendants and destroy them recursively |
| dojo.forEach(this.getChildren(), function(widget){ |
| if(widget.destroyRecursive){ |
| widget.destroyRecursive(preserveDom); |
| } |
| }); |
| }, |
| |
| |
| uninitialize: function(){ |
| // summary: |
| // Stub function. Override to implement custom widget tear-down |
| // behavior. |
| // tags: |
| // protected |
| return false; |
| }, |
| |
| ////////////////// MISCELLANEOUS METHODS /////////////////// |
| |
| onFocus: function(){ |
| // summary: |
| // Called when the widget becomes "active" because |
| // it or a widget inside of it either has focus, or has recently |
| // been clicked. |
| // tags: |
| // callback |
| }, |
| |
| onBlur: function(){ |
| // summary: |
| // Called when the widget stops being "active" because |
| // focus moved to something outside of it, or the user |
| // clicked somewhere outside of it, or the widget was |
| // hidden. |
| // tags: |
| // callback |
| }, |
| |
| _onFocus: function(e){ |
| // summary: |
| // This is where widgets do processing for when they are active, |
| // such as changing CSS classes. See onFocus() for more details. |
| // tags: |
| // protected |
| this.onFocus(); |
| }, |
| |
| _onBlur: function(){ |
| // summary: |
| // This is where widgets do processing for when they stop being active, |
| // such as changing CSS classes. See onBlur() for more details. |
| // tags: |
| // protected |
| this.onBlur(); |
| }, |
| |
| _onConnect: function(/*String*/ event){ |
| // summary: |
| // Called when someone connects to one of my handlers. |
| // "Turn on" that handler if it isn't active yet. |
| // |
| // This is also called for every single initialization parameter |
| // so need to do nothing for parameters like "id". |
| // tags: |
| // private |
| if(event in this._deferredConnects){ |
| var mapNode = this[this._deferredConnects[event] || 'domNode']; |
| this.connect(mapNode, event.toLowerCase(), event); |
| delete this._deferredConnects[event]; |
| } |
| }, |
| |
| _setClassAttr: function(/*String*/ value){ |
| // summary: |
| // Custom setter for the CSS "class" attribute |
| // tags: |
| // protected |
| var mapNode = this[this.attributeMap["class"] || 'domNode']; |
| dojo.removeClass(mapNode, this["class"]) |
| this["class"] = value; |
| dojo.addClass(mapNode, value); |
| }, |
| |
| _setStyleAttr: function(/*String||Object*/ value){ |
| // summary: |
| // Sets the style attribut of the widget according to value, |
| // which is either a hash like {height: "5px", width: "3px"} |
| // or a plain string |
| // description: |
| // Determines which node to set the style on based on style setting |
| // in attributeMap. |
| // tags: |
| // protected |
| |
| var mapNode = this[this.attributeMap.style || 'domNode']; |
| |
| // Note: technically we should revert any style setting made in a previous call |
| // to his method, but that's difficult to keep track of. |
| |
| if(dojo.isObject(value)){ |
| dojo.style(mapNode, value); |
| }else{ |
| if(mapNode.style.cssText){ |
| mapNode.style.cssText += "; " + value; |
| }else{ |
| mapNode.style.cssText = value; |
| } |
| } |
| |
| this.style = value; |
| }, |
| |
| setAttribute: function(/*String*/ attr, /*anything*/ value){ |
| // summary: |
| // Deprecated. Use attr() instead. |
| // tags: |
| // deprecated |
| dojo.deprecated(this.declaredClass+"::setAttribute() is deprecated. Use attr() instead.", "", "2.0"); |
| this.attr(attr, value); |
| }, |
| |
| _attrToDom: function(/*String*/ attr, /*String*/ value){ |
| // summary: |
| // Reflect a widget attribute (title, tabIndex, duration etc.) to |
| // the widget DOM, as specified in attributeMap. |
| // |
| // description: |
| // Also sets this["attr"] to the new value. |
| // Note some attributes like "type" |
| // cannot be processed this way as they are not mutable. |
| // |
| // tags: |
| // private |
| |
| var commands = this.attributeMap[attr]; |
| dojo.forEach(dojo.isArray(commands) ? commands : [commands], function(command){ |
| |
| // Get target node and what we are doing to that node |
| var mapNode = this[command.node || command || "domNode"]; // DOM node |
| var type = command.type || "attribute"; // class, innerHTML, innerText, or attribute |
| |
| switch(type){ |
| case "attribute": |
| if(dojo.isFunction(value)){ // functions execute in the context of the widget |
| value = dojo.hitch(this, value); |
| } |
| |
| // Get the name of the DOM node attribute; usually it's the same |
| // as the name of the attribute in the widget (attr), but can be overridden. |
| // Also maps handler names to lowercase, like onSubmit --> onsubmit |
| var attrName = command.attribute ? command.attribute : |
| (/^on[A-Z][a-zA-Z]*$/.test(attr) ? attr.toLowerCase() : attr); |
| |
| dojo.attr(mapNode, attrName, value); |
| break; |
| case "innerText": |
| mapNode.innerHTML = ""; |
| mapNode.appendChild(dojo.doc.createTextNode(value)); |
| break; |
| case "innerHTML": |
| mapNode.innerHTML = value; |
| break; |
| case "class": |
| dojo.removeClass(mapNode, this[attr]); |
| dojo.addClass(mapNode, value); |
| break; |
| } |
| }, this); |
| this[attr] = value; |
| }, |
| |
| attr: function(/*String|Object*/name, /*Object?*/value){ |
| // summary: |
| // Set or get properties on a widget instance. |
| // name: |
| // The property to get or set. If an object is passed here and not |
| // a string, its keys are used as names of attributes to be set |
| // and the value of the object as values to set in the widget. |
| // value: |
| // Optional. If provided, attr() operates as a setter. If omitted, |
| // the current value of the named property is returned. |
| // description: |
| // Get or set named properties on a widget. If no value is |
| // provided, the current value of the attribute is returned, |
| // potentially via a getter method. If a value is provided, then |
| // the method acts as a setter, assigning the value to the name, |
| // potentially calling any explicitly provided setters to handle |
| // the operation. For instance, if the widget has properties "foo" |
| // and "bar" and a method named "_setFooAttr", calling: |
| // | myWidget.attr("foo", "Howdy!"); |
| // would be equivalent to calling: |
| // | widget._setFooAttr("Howdy!"); |
| // while calling: |
| // | myWidget.attr("bar", "Howdy!"); |
| // would be the same as writing: |
| // | widget.bar = "Howdy!"; |
| // It also tries to copy the changes to the widget's DOM according |
| // to settings in attributeMap (see description of `dijit._Widget.attributeMap` |
| // for details) |
| // For example, calling: |
| // | myTitlePane.attr("title", "Howdy!"); |
| // will do |
| // | myTitlePane.title = "Howdy!"; |
| // | myTitlePane.title.innerHTML = "Howdy!"; |
| // It works for DOM node attributes too. Calling |
| // | widget.attr("disabled", true) |
| // will set the disabled attribute on the widget's focusNode, |
| // among other housekeeping for a change in disabled state. |
| |
| // open questions: |
| // - how to handle build shortcut for attributes which want to map |
| // into DOM attributes? |
| // - what relationship should setAttribute()/attr() have to |
| // layout() calls? |
| var args = arguments.length; |
| if(args == 1 && !dojo.isString(name)){ |
| for(var x in name){ this.attr(x, name[x]); } |
| return this; |
| } |
| var names = this._getAttrNames(name); |
| if(args >= 2){ // setter |
| if(this[names.s]){ |
| // use the explicit setter |
| args = dojo._toArray(arguments, 1); |
| return this[names.s].apply(this, args) || this; |
| }else{ |
| // if param is specified as DOM node attribute, copy it |
| if(name in this.attributeMap){ |
| this._attrToDom(name, value); |
| } |
| |
| // FIXME: what about function assignments? Any way to connect() here? |
| this[name] = value; |
| } |
| return this; |
| }else{ // getter |
| return this[names.g] ? this[names.g]() : this[name]; |
| } |
| }, |
| |
| _attrPairNames: {}, // shared between all widgets |
| _getAttrNames: function(name){ |
| // summary: |
| // Helper function for Widget.attr(). |
| // Caches attribute name values so we don't do the string ops every time. |
| // tags: |
| // private |
| |
| var apn = this._attrPairNames; |
| if(apn[name]){ return apn[name]; } |
| var uc = name.charAt(0).toUpperCase() + name.substr(1); |
| return (apn[name] = { |
| n: name+"Node", |
| s: "_set"+uc+"Attr", |
| g: "_get"+uc+"Attr" |
| }); |
| }, |
| |
| toString: function(){ |
| // summary: |
| // Returns a string that represents the widget |
| // description: |
| // When a widget is cast to a string, this method will be used to generate the |
| // output. Currently, it does not implement any sort of reversible |
| // serialization. |
| return '[Widget ' + this.declaredClass + ', ' + (this.id || 'NO ID') + ']'; // String |
| }, |
| |
| getDescendants: function(){ |
| // summary: |
| // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode. |
| // This method should generally be avoided as it returns widgets declared in templates, which are |
| // supposed to be internal/hidden, but it's left here for back-compat reasons. |
| |
| return this.containerNode ? dojo.query('[widgetId]', this.containerNode).map(dijit.byNode) : []; // dijit._Widget[] |
| }, |
| |
| getChildren: function(){ |
| // summary: |
| // Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode. |
| // Does not return nested widgets, nor widgets that are part of this widget's template. |
| return this.containerNode ? dijit.findWidgets(this.containerNode) : []; // dijit._Widget[] |
| }, |
| |
| // nodesWithKeyClick: [private] String[] |
| // List of nodes that correctly handle click events via native browser support, |
| // and don't need dijit's help |
| nodesWithKeyClick: ["input", "button"], |
| |
| connect: function( |
| /*Object|null*/ obj, |
| /*String|Function*/ event, |
| /*String|Function*/ method){ |
| // summary: |
| // Connects specified obj/event to specified method of this object |
| // and registers for disconnect() on widget destroy. |
| // description: |
| // Provide widget-specific analog to dojo.connect, except with the |
| // implicit use of this widget as the target object. |
| // This version of connect also provides a special "ondijitclick" |
| // event which triggers on a click or space or enter keyup |
| // returns: |
| // A handle that can be passed to `disconnect` in order to disconnect before |
| // the widget is destroyed. |
| // example: |
| // | var btn = new dijit.form.Button(); |
| // | // when foo.bar() is called, call the listener we're going to |
| // | // provide in the scope of btn |
| // | btn.connect(foo, "bar", function(){ |
| // | console.debug(this.toString()); |
| // | }); |
| // tags: |
| // protected |
| |
| var d = dojo, |
| dc = d._connect, |
| handles = []; |
| if(event == "ondijitclick"){ |
| // add key based click activation for unsupported nodes. |
| // do all processing onkey up to prevent spurious clicks |
| // for details see comments at top of this file where _lastKeyDownNode is defined |
| if(!this.nodesWithKeyClick[obj.tagName.toLowerCase()]){ |
| var m = d.hitch(this, method); |
| handles.push( |
| dc(obj, "onkeydown", this, function(e){ |
| //console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode)); |
| if((e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) && |
| !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){ |
| // needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work |
| dijit._lastKeyDownNode = e.target; |
| d.stopEvent(e); // stop event to prevent scrolling on space key in IE |
| } |
| }), |
| dc(obj, "onkeyup", this, function(e){ |
| //console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode)); |
| if( (e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) && |
| e.target === dijit._lastKeyDownNode && |
| !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){ |
| //need reset here or have problems in FF when focus returns to trigger element after closing popup/alert |
| dijit._lastKeyDownNode = null; |
| return m(e); |
| } |
| }) |
| ); |
| } |
| event = "onclick"; |
| } |
| handles.push(dc(obj, event, this, method)); |
| |
| this._connects.push(handles); |
| return handles; // _Widget.Handle |
| }, |
| |
| disconnect: function(/* _Widget.Handle */ handles){ |
| // summary: |
| // Disconnects handle created by `connect`. |
| // Also removes handle from this widget's list of connects. |
| // tags: |
| // protected |
| for(var i=0; i<this._connects.length; i++){ |
| if(this._connects[i] == handles){ |
| dojo.forEach(handles, dojo.disconnect); |
| this._connects.splice(i, 1); |
| return; |
| } |
| } |
| }, |
| |
| subscribe: function( |
| /*String*/ topic, |
| /*String|Function*/ method){ |
| // summary: |
| // Subscribes to the specified topic and calls the specified method |
| // of this object and registers for unsubscribe() on widget destroy. |
| // description: |
| // Provide widget-specific analog to dojo.subscribe, except with the |
| // implicit use of this widget as the target object. |
| // example: |
| // | var btn = new dijit.form.Button(); |
| // | // when /my/topic is published, this button changes its label to |
| // | // be the parameter of the topic. |
| // | btn.subscribe("/my/topic", function(v){ |
| // | this.attr("label", v); |
| // | }); |
| var d = dojo, |
| handle = d.subscribe(topic, this, method); |
| |
| // return handles for Any widget that may need them |
| this._subscribes.push(handle); |
| return handle; |
| }, |
| |
| unsubscribe: function(/*Object*/ handle){ |
| // summary: |
| // Unsubscribes handle created by this.subscribe. |
| // Also removes handle from this widget's list of subscriptions |
| for(var i=0; i<this._subscribes.length; i++){ |
| if(this._subscribes[i] == handle){ |
| dojo.unsubscribe(handle); |
| this._subscribes.splice(i, 1); |
| return; |
| } |
| } |
| }, |
| |
| isLeftToRight: function(){ |
| // summary: |
| // Checks the page for text direction |
| // tags: |
| // protected |
| return dojo._isBodyLtr(); //Boolean |
| }, |
| |
| isFocusable: function(){ |
| // summary: |
| // Return true if this widget can currently be focused |
| // and false if not |
| return this.focus && (dojo.style(this.domNode, "display") != "none"); |
| }, |
| |
| placeAt: function(/* String|DomNode|_Widget */reference, /* String?|Int? */position){ |
| // summary: |
| // Place this widget's domNode reference somewhere in the DOM based |
| // on standard dojo.place conventions, or passing a Widget reference that |
| // contains and addChild member. |
| // |
| // description: |
| // A convenience function provided in all _Widgets, providing a simple |
| // shorthand mechanism to put an existing (or newly created) Widget |
| // somewhere in the dom, and allow chaining. |
| // |
| // reference: |
| // The String id of a domNode, a domNode reference, or a reference to a Widget posessing |
| // an addChild method. |
| // |
| // position: |
| // If passed a string or domNode reference, the position argument |
| // accepts a string just as dojo.place does, one of: "first", "last", |
| // "before", or "after". |
| // |
| // If passed a _Widget reference, and that widget reference has an ".addChild" method, |
| // it will be called passing this widget instance into that method, supplying the optional |
| // position index passed. |
| // |
| // returns: |
| // dijit._Widget |
| // Provides a useful return of the newly created dijit._Widget instance so you |
| // can "chain" this function by instantiating, placing, then saving the return value |
| // to a variable. |
| // |
| // example: |
| // | // create a Button with no srcNodeRef, and place it in the body: |
| // | var button = new dijit.form.Button({ label:"click" }).placeAt(dojo.body()); |
| // | // now, 'button' is still the widget reference to the newly created button |
| // | dojo.connect(button, "onClick", function(e){ console.log('click'); }); |
| // |
| // example: |
| // | // create a button out of a node with id="src" and append it to id="wrapper": |
| // | var button = new dijit.form.Button({},"src").placeAt("wrapper"); |
| // |
| // example: |
| // | // place a new button as the first element of some div |
| // | var button = new dijit.form.Button({ label:"click" }).placeAt("wrapper","first"); |
| // |
| // example: |
| // | // create a contentpane and add it to a TabContainer |
| // | var tc = dijit.byId("myTabs"); |
| // | new dijit.layout.ContentPane({ href:"foo.html", title:"Wow!" }).placeAt(tc) |
| |
| if(reference.declaredClass && reference.addChild){ |
| reference.addChild(this, position); |
| }else{ |
| dojo.place(this.domNode, reference, position); |
| } |
| return this; |
| }, |
| |
| _onShow: function(){ |
| // summary: |
| // Internal method called when this widget is made visible. |
| // See `onShow` for details. |
| this.onShow(); |
| }, |
| |
| onShow: function(){ |
| // summary: |
| // Called when this widget becomes the selected pane in a |
| // `dijit.layout.TabContainer`, `dijit.layout.StackContainer`, |
| // `dijit.layout.AccordionContainer`, etc. |
| // |
| // Also called to indicate display of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`. |
| // tags: |
| // callback |
| }, |
| |
| onHide: function(){ |
| // summary: |
| // Called when another widget becomes the selected pane in a |
| // `dijit.layout.TabContainer`, `dijit.layout.StackContainer`, |
| // `dijit.layout.AccordionContainer`, etc. |
| // |
| // Also called to indicate hide of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`. |
| // tags: |
| // callback |
| } |
| }); |
| |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.gfx.matrix"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.gfx.matrix"] = true; |
| dojo.provide("dojox.gfx.matrix"); |
| |
| (function(){ |
| var m = dojox.gfx.matrix; |
| |
| // candidates for dojox.math: |
| var _degToRadCache = {}; |
| m._degToRad = function(degree){ |
| return _degToRadCache[degree] || (_degToRadCache[degree] = (Math.PI * degree / 180)); |
| }; |
| m._radToDeg = function(radian){ return radian / Math.PI * 180; }; |
| |
| m.Matrix2D = function(arg){ |
| // summary: a 2D matrix object |
| // description: Normalizes a 2D matrix-like object. If arrays is passed, |
| // all objects of the array are normalized and multiplied sequentially. |
| // arg: Object |
| // a 2D matrix-like object, a number, or an array of such objects |
| if(arg){ |
| if(typeof arg == "number"){ |
| this.xx = this.yy = arg; |
| }else if(arg instanceof Array){ |
| if(arg.length > 0){ |
| var matrix = m.normalize(arg[0]); |
| // combine matrices |
| for(var i = 1; i < arg.length; ++i){ |
| var l = matrix, r = dojox.gfx.matrix.normalize(arg[i]); |
| matrix = new m.Matrix2D(); |
| matrix.xx = l.xx * r.xx + l.xy * r.yx; |
| matrix.xy = l.xx * r.xy + l.xy * r.yy; |
| matrix.yx = l.yx * r.xx + l.yy * r.yx; |
| matrix.yy = l.yx * r.xy + l.yy * r.yy; |
| matrix.dx = l.xx * r.dx + l.xy * r.dy + l.dx; |
| matrix.dy = l.yx * r.dx + l.yy * r.dy + l.dy; |
| } |
| dojo.mixin(this, matrix); |
| } |
| }else{ |
| dojo.mixin(this, arg); |
| } |
| } |
| }; |
| |
| // the default (identity) matrix, which is used to fill in missing values |
| dojo.extend(m.Matrix2D, {xx: 1, xy: 0, yx: 0, yy: 1, dx: 0, dy: 0}); |
| |
| dojo.mixin(m, { |
| // summary: class constants, and methods of dojox.gfx.matrix |
| |
| // matrix constants |
| |
| // identity: dojox.gfx.matrix.Matrix2D |
| // an identity matrix constant: identity * (x, y) == (x, y) |
| identity: new m.Matrix2D(), |
| |
| // flipX: dojox.gfx.matrix.Matrix2D |
| // a matrix, which reflects points at x = 0 line: flipX * (x, y) == (-x, y) |
| flipX: new m.Matrix2D({xx: -1}), |
| |
| // flipY: dojox.gfx.matrix.Matrix2D |
| // a matrix, which reflects points at y = 0 line: flipY * (x, y) == (x, -y) |
| flipY: new m.Matrix2D({yy: -1}), |
| |
| // flipXY: dojox.gfx.matrix.Matrix2D |
| // a matrix, which reflects points at the origin of coordinates: flipXY * (x, y) == (-x, -y) |
| flipXY: new m.Matrix2D({xx: -1, yy: -1}), |
| |
| // matrix creators |
| |
| translate: function(a, b){ |
| // summary: forms a translation matrix |
| // description: The resulting matrix is used to translate (move) points by specified offsets. |
| // a: Number: an x coordinate value |
| // b: Number: a y coordinate value |
| if(arguments.length > 1){ |
| return new m.Matrix2D({dx: a, dy: b}); // dojox.gfx.matrix.Matrix2D |
| } |
| // branch |
| // a: dojox.gfx.Point: a point-like object, which specifies offsets for both dimensions |
| // b: null |
| return new m.Matrix2D({dx: a.x, dy: a.y}); // dojox.gfx.matrix.Matrix2D |
| }, |
| scale: function(a, b){ |
| // summary: forms a scaling matrix |
| // description: The resulting matrix is used to scale (magnify) points by specified offsets. |
| // a: Number: a scaling factor used for the x coordinate |
| // b: Number: a scaling factor used for the y coordinate |
| if(arguments.length > 1){ |
| return new m.Matrix2D({xx: a, yy: b}); // dojox.gfx.matrix.Matrix2D |
| } |
| if(typeof a == "number"){ |
| // branch |
| // a: Number: a uniform scaling factor used for the both coordinates |
| // b: null |
| return new m.Matrix2D({xx: a, yy: a}); // dojox.gfx.matrix.Matrix2D |
| } |
| // branch |
| // a: dojox.gfx.Point: a point-like object, which specifies scale factors for both dimensions |
| // b: null |
| return new m.Matrix2D({xx: a.x, yy: a.y}); // dojox.gfx.matrix.Matrix2D |
| }, |
| rotate: function(angle){ |
| // summary: forms a rotating matrix |
| // description: The resulting matrix is used to rotate points |
| // around the origin of coordinates (0, 0) by specified angle. |
| // angle: Number: an angle of rotation in radians (>0 for CW) |
| var c = Math.cos(angle); |
| var s = Math.sin(angle); |
| return new m.Matrix2D({xx: c, xy: -s, yx: s, yy: c}); // dojox.gfx.matrix.Matrix2D |
| }, |
| rotateg: function(degree){ |
| // summary: forms a rotating matrix |
| // description: The resulting matrix is used to rotate points |
| // around the origin of coordinates (0, 0) by specified degree. |
| // See dojox.gfx.matrix.rotate() for comparison. |
| // degree: Number: an angle of rotation in degrees (>0 for CW) |
| return m.rotate(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D |
| }, |
| skewX: function(angle) { |
| // summary: forms an x skewing matrix |
| // description: The resulting matrix is used to skew points in the x dimension |
| // around the origin of coordinates (0, 0) by specified angle. |
| // angle: Number: an skewing angle in radians |
| return new m.Matrix2D({xy: Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D |
| }, |
| skewXg: function(degree){ |
| // summary: forms an x skewing matrix |
| // description: The resulting matrix is used to skew points in the x dimension |
| // around the origin of coordinates (0, 0) by specified degree. |
| // See dojox.gfx.matrix.skewX() for comparison. |
| // degree: Number: an skewing angle in degrees |
| return m.skewX(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D |
| }, |
| skewY: function(angle){ |
| // summary: forms a y skewing matrix |
| // description: The resulting matrix is used to skew points in the y dimension |
| // around the origin of coordinates (0, 0) by specified angle. |
| // angle: Number: an skewing angle in radians |
| return new m.Matrix2D({yx: Math.tan(angle)}); // dojox.gfx.matrix.Matrix2D |
| }, |
| skewYg: function(degree){ |
| // summary: forms a y skewing matrix |
| // description: The resulting matrix is used to skew points in the y dimension |
| // around the origin of coordinates (0, 0) by specified degree. |
| // See dojox.gfx.matrix.skewY() for comparison. |
| // degree: Number: an skewing angle in degrees |
| return m.skewY(m._degToRad(degree)); // dojox.gfx.matrix.Matrix2D |
| }, |
| reflect: function(a, b){ |
| // summary: forms a reflection matrix |
| // description: The resulting matrix is used to reflect points around a vector, |
| // which goes through the origin. |
| // a: dojox.gfx.Point: a point-like object, which specifies a vector of reflection |
| // b: null |
| if(arguments.length == 1){ |
| b = a.y; |
| a = a.x; |
| } |
| // branch |
| // a: Number: an x coordinate value |
| // b: Number: a y coordinate value |
| |
| // make a unit vector |
| var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = 2 * a * b / n2; |
| return new m.Matrix2D({xx: 2 * a2 / n2 - 1, xy: xy, yx: xy, yy: 2 * b2 / n2 - 1}); // dojox.gfx.matrix.Matrix2D |
| }, |
| project: function(a, b){ |
| // summary: forms an orthogonal projection matrix |
| // description: The resulting matrix is used to project points orthogonally on a vector, |
| // which goes through the origin. |
| // a: dojox.gfx.Point: a point-like object, which specifies a vector of projection |
| // b: null |
| if(arguments.length == 1){ |
| b = a.y; |
| a = a.x; |
| } |
| // branch |
| // a: Number: an x coordinate value |
| // b: Number: a y coordinate value |
| |
| // make a unit vector |
| var a2 = a * a, b2 = b * b, n2 = a2 + b2, xy = a * b / n2; |
| return new m.Matrix2D({xx: a2 / n2, xy: xy, yx: xy, yy: b2 / n2}); // dojox.gfx.matrix.Matrix2D |
| }, |
| |
| // ensure matrix 2D conformance |
| normalize: function(matrix){ |
| // summary: converts an object to a matrix, if necessary |
| // description: Converts any 2D matrix-like object or an array of |
| // such objects to a valid dojox.gfx.matrix.Matrix2D object. |
| // matrix: Object: an object, which is converted to a matrix, if necessary |
| return (matrix instanceof m.Matrix2D) ? matrix : new m.Matrix2D(matrix); // dojox.gfx.matrix.Matrix2D |
| }, |
| |
| // common operations |
| |
| clone: function(matrix){ |
| // summary: creates a copy of a 2D matrix |
| // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be cloned |
| var obj = new m.Matrix2D(); |
| for(var i in matrix){ |
| if(typeof(matrix[i]) == "number" && typeof(obj[i]) == "number" && obj[i] != matrix[i]) obj[i] = matrix[i]; |
| } |
| return obj; // dojox.gfx.matrix.Matrix2D |
| }, |
| invert: function(matrix){ |
| // summary: inverts a 2D matrix |
| // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object to be inverted |
| var M = m.normalize(matrix), |
| D = M.xx * M.yy - M.xy * M.yx, |
| M = new m.Matrix2D({ |
| xx: M.yy/D, xy: -M.xy/D, |
| yx: -M.yx/D, yy: M.xx/D, |
| dx: (M.xy * M.dy - M.yy * M.dx) / D, |
| dy: (M.yx * M.dx - M.xx * M.dy) / D |
| }); |
| return M; // dojox.gfx.matrix.Matrix2D |
| }, |
| _multiplyPoint: function(matrix, x, y){ |
| // summary: applies a matrix to a point |
| // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied |
| // x: Number: an x coordinate of a point |
| // y: Number: a y coordinate of a point |
| return {x: matrix.xx * x + matrix.xy * y + matrix.dx, y: matrix.yx * x + matrix.yy * y + matrix.dy}; // dojox.gfx.Point |
| }, |
| multiplyPoint: function(matrix, /* Number||Point */ a, /* Number, optional */ b){ |
| // summary: applies a matrix to a point |
| // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied |
| // a: Number: an x coordinate of a point |
| // b: Number: a y coordinate of a point |
| var M = m.normalize(matrix); |
| if(typeof a == "number" && typeof b == "number"){ |
| return m._multiplyPoint(M, a, b); // dojox.gfx.Point |
| } |
| // branch |
| // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix object to be applied |
| // a: dojox.gfx.Point: a point |
| // b: null |
| return m._multiplyPoint(M, a.x, a.y); // dojox.gfx.Point |
| }, |
| multiply: function(matrix){ |
| // summary: combines matrices by multiplying them sequentially in the given order |
| // matrix: dojox.gfx.matrix.Matrix2D...: a 2D matrix-like object, |
| // all subsequent arguments are matrix-like objects too |
| var M = m.normalize(matrix); |
| // combine matrices |
| for(var i = 1; i < arguments.length; ++i){ |
| var l = M, r = m.normalize(arguments[i]); |
| M = new m.Matrix2D(); |
| M.xx = l.xx * r.xx + l.xy * r.yx; |
| M.xy = l.xx * r.xy + l.xy * r.yy; |
| M.yx = l.yx * r.xx + l.yy * r.yx; |
| M.yy = l.yx * r.xy + l.yy * r.yy; |
| M.dx = l.xx * r.dx + l.xy * r.dy + l.dx; |
| M.dy = l.yx * r.dx + l.yy * r.dy + l.dy; |
| } |
| return M; // dojox.gfx.matrix.Matrix2D |
| }, |
| |
| // high level operations |
| |
| _sandwich: function(matrix, x, y){ |
| // summary: applies a matrix at a centrtal point |
| // matrix: dojox.gfx.matrix.Matrix2D: a 2D matrix-like object, which is applied at a central point |
| // x: Number: an x component of the central point |
| // y: Number: a y component of the central point |
| return m.multiply(m.translate(x, y), matrix, m.translate(-x, -y)); // dojox.gfx.matrix.Matrix2D |
| }, |
| scaleAt: function(a, b, c, d){ |
| // summary: scales a picture using a specified point as a center of scaling |
| // description: Compare with dojox.gfx.matrix.scale(). |
| // a: Number: a scaling factor used for the x coordinate |
| // b: Number: a scaling factor used for the y coordinate |
| // c: Number: an x component of a central point |
| // d: Number: a y component of a central point |
| |
| // accepts several signatures: |
| // 1) uniform scale factor, Point |
| // 2) uniform scale factor, x, y |
| // 3) x scale, y scale, Point |
| // 4) x scale, y scale, x, y |
| |
| switch(arguments.length){ |
| case 4: |
| // a and b are scale factor components, c and d are components of a point |
| return m._sandwich(m.scale(a, b), c, d); // dojox.gfx.matrix.Matrix2D |
| case 3: |
| if(typeof c == "number"){ |
| // branch |
| // a: Number: a uniform scaling factor used for both coordinates |
| // b: Number: an x component of a central point |
| // c: Number: a y component of a central point |
| // d: null |
| return m._sandwich(m.scale(a), b, c); // dojox.gfx.matrix.Matrix2D |
| } |
| // branch |
| // a: Number: a scaling factor used for the x coordinate |
| // b: Number: a scaling factor used for the y coordinate |
| // c: dojox.gfx.Point: a central point |
| // d: null |
| return m._sandwich(m.scale(a, b), c.x, c.y); // dojox.gfx.matrix.Matrix2D |
| } |
| // branch |
| // a: Number: a uniform scaling factor used for both coordinates |
| // b: dojox.gfx.Point: a central point |
| // c: null |
| // d: null |
| return m._sandwich(m.scale(a), b.x, b.y); // dojox.gfx.matrix.Matrix2D |
| }, |
| rotateAt: function(angle, a, b){ |
| // summary: rotates a picture using a specified point as a center of rotation |
| // description: Compare with dojox.gfx.matrix.rotate(). |
| // angle: Number: an angle of rotation in radians (>0 for CW) |
| // a: Number: an x component of a central point |
| // b: Number: a y component of a central point |
| |
| // accepts several signatures: |
| // 1) rotation angle in radians, Point |
| // 2) rotation angle in radians, x, y |
| |
| if(arguments.length > 2){ |
| return m._sandwich(m.rotate(angle), a, b); // dojox.gfx.matrix.Matrix2D |
| } |
| |
| // branch |
| // angle: Number: an angle of rotation in radians (>0 for CCW) |
| // a: dojox.gfx.Point: a central point |
| // b: null |
| return m._sandwich(m.rotate(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
| }, |
| rotategAt: function(degree, a, b){ |
| // summary: rotates a picture using a specified point as a center of rotation |
| // description: Compare with dojox.gfx.matrix.rotateg(). |
| // degree: Number: an angle of rotation in degrees (>0 for CW) |
| // a: Number: an x component of a central point |
| // b: Number: a y component of a central point |
| |
| // accepts several signatures: |
| // 1) rotation angle in degrees, Point |
| // 2) rotation angle in degrees, x, y |
| |
| if(arguments.length > 2){ |
| return m._sandwich(m.rotateg(degree), a, b); // dojox.gfx.matrix.Matrix2D |
| } |
| |
| // branch |
| // degree: Number: an angle of rotation in degrees (>0 for CCW) |
| // a: dojox.gfx.Point: a central point |
| // b: null |
| return m._sandwich(m.rotateg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
| }, |
| skewXAt: function(angle, a, b){ |
| // summary: skews a picture along the x axis using a specified point as a center of skewing |
| // description: Compare with dojox.gfx.matrix.skewX(). |
| // angle: Number: an skewing angle in radians |
| // a: Number: an x component of a central point |
| // b: Number: a y component of a central point |
| |
| // accepts several signatures: |
| // 1) skew angle in radians, Point |
| // 2) skew angle in radians, x, y |
| |
| if(arguments.length > 2){ |
| return m._sandwich(m.skewX(angle), a, b); // dojox.gfx.matrix.Matrix2D |
| } |
| |
| // branch |
| // angle: Number: an skewing angle in radians |
| // a: dojox.gfx.Point: a central point |
| // b: null |
| return m._sandwich(m.skewX(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
| }, |
| skewXgAt: function(degree, a, b){ |
| // summary: skews a picture along the x axis using a specified point as a center of skewing |
| // description: Compare with dojox.gfx.matrix.skewXg(). |
| // degree: Number: an skewing angle in degrees |
| // a: Number: an x component of a central point |
| // b: Number: a y component of a central point |
| |
| // accepts several signatures: |
| // 1) skew angle in degrees, Point |
| // 2) skew angle in degrees, x, y |
| |
| if(arguments.length > 2){ |
| return m._sandwich(m.skewXg(degree), a, b); // dojox.gfx.matrix.Matrix2D |
| } |
| |
| // branch |
| // degree: Number: an skewing angle in degrees |
| // a: dojox.gfx.Point: a central point |
| // b: null |
| return m._sandwich(m.skewXg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
| }, |
| skewYAt: function(angle, a, b){ |
| // summary: skews a picture along the y axis using a specified point as a center of skewing |
| // description: Compare with dojox.gfx.matrix.skewY(). |
| // angle: Number: an skewing angle in radians |
| // a: Number: an x component of a central point |
| // b: Number: a y component of a central point |
| |
| // accepts several signatures: |
| // 1) skew angle in radians, Point |
| // 2) skew angle in radians, x, y |
| |
| if(arguments.length > 2){ |
| return m._sandwich(m.skewY(angle), a, b); // dojox.gfx.matrix.Matrix2D |
| } |
| |
| // branch |
| // angle: Number: an skewing angle in radians |
| // a: dojox.gfx.Point: a central point |
| // b: null |
| return m._sandwich(m.skewY(angle), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
| }, |
| skewYgAt: function(/* Number */ degree, /* Number||Point */ a, /* Number, optional */ b){ |
| // summary: skews a picture along the y axis using a specified point as a center of skewing |
| // description: Compare with dojox.gfx.matrix.skewYg(). |
| // degree: Number: an skewing angle in degrees |
| // a: Number: an x component of a central point |
| // b: Number: a y component of a central point |
| |
| // accepts several signatures: |
| // 1) skew angle in degrees, Point |
| // 2) skew angle in degrees, x, y |
| |
| if(arguments.length > 2){ |
| return m._sandwich(m.skewYg(degree), a, b); // dojox.gfx.matrix.Matrix2D |
| } |
| |
| // branch |
| // degree: Number: an skewing angle in degrees |
| // a: dojox.gfx.Point: a central point |
| // b: null |
| return m._sandwich(m.skewYg(degree), a.x, a.y); // dojox.gfx.matrix.Matrix2D |
| } |
| |
| //TODO: rect-to-rect mapping, scale-to-fit (isotropic and anisotropic versions) |
| |
| }); |
| })(); |
| |
| // propagate Matrix2D up |
| dojox.gfx.Matrix2D = dojox.gfx.matrix.Matrix2D; |
| |
| } |
| |
| if(!dojo._hasResource["dojox.gfx._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.gfx._base"] = true; |
| dojo.provide("dojox.gfx._base"); |
| |
| (function(){ |
| var g = dojox.gfx, b = g._base; |
| |
| // candidates for dojox.style (work on VML and SVG nodes) |
| g._hasClass = function(/*DomNode*/node, /*String*/classStr){ |
| // summary: |
| // Returns whether or not the specified classes are a portion of the |
| // class list currently applied to the node. |
| // return (new RegExp('(^|\\s+)'+classStr+'(\\s+|$)')).test(node.className) // Boolean |
| var cls = node.getAttribute("className"); |
| return cls && (" " + cls + " ").indexOf(" " + classStr + " ") >= 0; // Boolean |
| } |
| g._addClass = function(/*DomNode*/node, /*String*/classStr){ |
| // summary: |
| // Adds the specified classes to the end of the class list on the |
| // passed node. |
| var cls = node.getAttribute("className") || ""; |
| if(!cls || (" " + cls + " ").indexOf(" " + classStr + " ") < 0){ |
| node.setAttribute("className", cls + (cls ? " " : "") + classStr); |
| } |
| } |
| g._removeClass = function(/*DomNode*/node, /*String*/classStr){ |
| // summary: Removes classes from node. |
| var cls = node.getAttribute("className"); |
| if(cls){ |
| node.setAttribute( |
| "className", |
| cls.replace(new RegExp('(^|\\s+)' + classStr + '(\\s+|$)'), "$1$2") |
| ); |
| } |
| } |
| |
| // candidate for dojox.html.metrics (dynamic font resize handler is not implemented here) |
| |
| // derived from Morris John's emResized measurer |
| b._getFontMeasurements = function(){ |
| // summary: |
| // Returns an object that has pixel equivilents of standard font |
| // size values. |
| var heights = { |
| '1em': 0, '1ex': 0, '100%': 0, '12pt': 0, '16px': 0, 'xx-small': 0, |
| 'x-small': 0, 'small': 0, 'medium': 0, 'large': 0, 'x-large': 0, |
| 'xx-large': 0 |
| }; |
| |
| if(dojo.isIE){ |
| // we do a font-size fix if and only if one isn't applied already. |
| // NOTE: If someone set the fontSize on the HTML Element, this will kill it. |
| dojo.doc.documentElement.style.fontSize="100%"; |
| } |
| |
| // set up the measuring node. |
| var div = dojo.doc.createElement("div"); |
| var s = div.style; |
| s.position = "absolute"; |
| s.left = "-100px"; |
| s.top = "0px"; |
| s.width = "30px"; |
| s.height = "1000em"; |
| s.border = "0px"; |
| s.margin = "0px"; |
| s.padding = "0px"; |
| s.outline = "none"; |
| s.lineHeight = "1"; |
| s.overflow = "hidden"; |
| dojo.body().appendChild(div); |
| |
| // do the measurements. |
| for(var p in heights){ |
| div.style.fontSize = p; |
| heights[p] = Math.round(div.offsetHeight * 12/16) * 16/12 / 1000; |
| } |
| |
| dojo.body().removeChild(div); |
| div = null; |
| return heights; // object |
| }; |
| |
| var fontMeasurements = null; |
| |
| b._getCachedFontMeasurements = function(recalculate){ |
| if(recalculate || !fontMeasurements){ |
| fontMeasurements = b._getFontMeasurements(); |
| } |
| return fontMeasurements; |
| }; |
| |
| // candidate for dojox.html.metrics |
| |
| var measuringNode = null, empty = {}; |
| b._getTextBox = function( /*String*/ text, |
| /*Object*/ style, |
| /*String?*/ className){ |
| var m, s, al = arguments.length; |
| if(!measuringNode){ |
| m = measuringNode = dojo.doc.createElement("div"); |
| s = m.style; |
| s.position = "absolute"; |
| s.left = "-10000px"; |
| s.top = "0"; |
| dojo.body().appendChild(m); |
| }else{ |
| m = measuringNode; |
| s = m.style; |
| } |
| // reset styles |
| m.className = ""; |
| s.border = "0"; |
| s.margin = "0"; |
| s.padding = "0"; |
| s.outline = "0"; |
| // set new style |
| if(al > 1 && style){ |
| for(var i in style){ |
| if(i in empty){ continue; } |
| s[i] = style[i]; |
| } |
| } |
| // set classes |
| if(al > 2 && className){ |
| m.className = className; |
| } |
| // take a measure |
| m.innerHTML = text; |
| |
| if(m["getBoundingClientRect"]){ |
| var bcr = m.getBoundingClientRect(); |
| return {l: bcr.left, t: bcr.top, w: bcr.width || (bcr.right - bcr.left), h: bcr.height || (bcr.bottom - bcr.top)}; |
| }else{ |
| return dojo.marginBox(m); |
| } |
| }; |
| |
| // candidate for dojo.dom |
| |
| var uniqueId = 0; |
| b._getUniqueId = function(){ |
| // summary: returns a unique string for use with any DOM element |
| var id; |
| do{ |
| id = dojo._scopeName + "Unique" + (++uniqueId); |
| }while(dojo.byId(id)); |
| return id; |
| }; |
| })(); |
| |
| dojo.mixin(dojox.gfx, { |
| // summary: |
| // defines constants, prototypes, and utility functions |
| |
| // default shapes, which are used to fill in missing parameters |
| defaultPath: { |
| type: "path", path: "" |
| }, |
| defaultPolyline: { |
| type: "polyline", points: [] |
| }, |
| defaultRect: { |
| type: "rect", x: 0, y: 0, width: 100, height: 100, r: 0 |
| }, |
| defaultEllipse: { |
| type: "ellipse", cx: 0, cy: 0, rx: 200, ry: 100 |
| }, |
| defaultCircle: { |
| type: "circle", cx: 0, cy: 0, r: 100 |
| }, |
| defaultLine: { |
| type: "line", x1: 0, y1: 0, x2: 100, y2: 100 |
| }, |
| defaultImage: { |
| type: "image", x: 0, y: 0, width: 0, height: 0, src: "" |
| }, |
| defaultText: { |
| type: "text", x: 0, y: 0, text: "", align: "start", |
| decoration: "none", rotated: false, kerning: true |
| }, |
| defaultTextPath: { |
| type: "textpath", text: "", align: "start", |
| decoration: "none", rotated: false, kerning: true |
| }, |
| |
| // default geometric attributes |
| defaultStroke: { |
| type: "stroke", color: "black", style: "solid", width: 1, |
| cap: "butt", join: 4 |
| }, |
| defaultLinearGradient: { |
| type: "linear", x1: 0, y1: 0, x2: 100, y2: 100, |
| colors: [ |
| { offset: 0, color: "black" }, { offset: 1, color: "white" } |
| ] |
| }, |
| defaultRadialGradient: { |
| type: "radial", cx: 0, cy: 0, r: 100, |
| colors: [ |
| { offset: 0, color: "black" }, { offset: 1, color: "white" } |
| ] |
| }, |
| defaultPattern: { |
| type: "pattern", x: 0, y: 0, width: 0, height: 0, src: "" |
| }, |
| defaultFont: { |
| type: "font", style: "normal", variant: "normal", |
| weight: "normal", size: "10pt", family: "serif" |
| }, |
| |
| getDefault: (function(){ |
| var typeCtorCache = {}; |
| // a memoized delegate() |
| return function(/*String*/ type){ |
| var t = typeCtorCache[type]; |
| if(t){ |
| return new t(); |
| } |
| t = typeCtorCache[type] = new Function; |
| t.prototype = dojox.gfx[ "default" + type ]; |
| return new t(); |
| } |
| })(), |
| |
| normalizeColor: function(/*Color*/ color){ |
| // summary: |
| // converts any legal color representation to normalized |
| // dojo.Color object |
| return (color instanceof dojo.Color) ? color : new dojo.Color(color); // dojo.Color |
| }, |
| normalizeParameters: function(existed, update){ |
| // summary: |
| // updates an existing object with properties from an "update" |
| // object |
| // existed: Object |
| // the "target" object to be updated |
| // update: Object |
| // the "update" object, whose properties will be used to update |
| // the existed object |
| if(update){ |
| var empty = {}; |
| for(var x in existed){ |
| if(x in update && !(x in empty)){ |
| existed[x] = update[x]; |
| } |
| } |
| } |
| return existed; // Object |
| }, |
| makeParameters: function(defaults, update){ |
| // summary: |
| // copies the original object, and all copied properties from the |
| // "update" object |
| // defaults: Object |
| // the object to be cloned before updating |
| // update: Object |
| // the object, which properties are to be cloned during updating |
| if(!update){ |
| // return dojo.clone(defaults); |
| return dojo.delegate(defaults); |
| } |
| var result = {}; |
| for(var i in defaults){ |
| if(!(i in result)){ |
| result[i] = dojo.clone((i in update) ? update[i] : defaults[i]); |
| } |
| } |
| return result; // Object |
| }, |
| formatNumber: function(x, addSpace){ |
| // summary: converts a number to a string using a fixed notation |
| // x: Number: number to be converted |
| // addSpace: Boolean?: if it is true, add a space before a positive number |
| var val = x.toString(); |
| if(val.indexOf("e") >= 0){ |
| val = x.toFixed(4); |
| }else{ |
| var point = val.indexOf("."); |
| if(point >= 0 && val.length - point > 5){ |
| val = x.toFixed(4); |
| } |
| } |
| if(x < 0){ |
| return val; // String |
| } |
| return addSpace ? " " + val : val; // String |
| }, |
| // font operations |
| makeFontString: function(font){ |
| // summary: converts a font object to a CSS font string |
| // font: Object: font object (see dojox.gfx.defaultFont) |
| return font.style + " " + font.variant + " " + font.weight + " " + font.size + " " + font.family; // Object |
| }, |
| splitFontString: function(str){ |
| // summary: |
| // converts a CSS font string to a font object |
| // description: |
| // Converts a CSS font string to a gfx font object. The CSS font |
| // string components should follow the W3C specified order |
| // (see http://www.w3.org/TR/CSS2/fonts.html#font-shorthand): |
| // style, variant, weight, size, optional line height (will be |
| // ignored), and family. |
| // str: String |
| // a CSS font string |
| var font = dojox.gfx.getDefault("Font"); |
| var t = str.split(/\s+/); |
| do{ |
| if(t.length < 5){ break; } |
| font.style = t[0]; |
| font.variant = t[1]; |
| font.weight = t[2]; |
| var i = t[3].indexOf("/"); |
| font.size = i < 0 ? t[3] : t[3].substring(0, i); |
| var j = 4; |
| if(i < 0){ |
| if(t[4] == "/"){ |
| j = 6; |
| }else if(t[4].charAt(0) == "/"){ |
| j = 5; |
| } |
| } |
| if(j < t.length){ |
| font.family = t.slice(j).join(" "); |
| } |
| }while(false); |
| return font; // Object |
| }, |
| // length operations |
| cm_in_pt: 72 / 2.54, // Number: points per centimeter |
| mm_in_pt: 7.2 / 2.54, // Number: points per millimeter |
| px_in_pt: function(){ |
| // summary: returns a number of pixels per point |
| return dojox.gfx._base._getCachedFontMeasurements()["12pt"] / 12; // Number |
| }, |
| pt2px: function(len){ |
| // summary: converts points to pixels |
| // len: Number: a value in points |
| return len * dojox.gfx.px_in_pt(); // Number |
| }, |
| px2pt: function(len){ |
| // summary: converts pixels to points |
| // len: Number: a value in pixels |
| return len / dojox.gfx.px_in_pt(); // Number |
| }, |
| normalizedLength: function(len) { |
| // summary: converts any length value to pixels |
| // len: String: a length, e.g., "12pc" |
| if(len.length == 0) return 0; |
| if(len.length > 2){ |
| var px_in_pt = dojox.gfx.px_in_pt(); |
| var val = parseFloat(len); |
| switch(len.slice(-2)){ |
| case "px": return val; |
| case "pt": return val * px_in_pt; |
| case "in": return val * 72 * px_in_pt; |
| case "pc": return val * 12 * px_in_pt; |
| case "mm": return val * dojox.gfx.mm_in_pt * px_in_pt; |
| case "cm": return val * dojox.gfx.cm_in_pt * px_in_pt; |
| } |
| } |
| return parseFloat(len); // Number |
| }, |
| |
| // a constant used to split a SVG/VML path into primitive components |
| pathVmlRegExp: /([A-Za-z]+)|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g, |
| pathSvgRegExp: /([A-Za-z])|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g, |
| |
| equalSources: function(a, b){ |
| // summary: compares event sources, returns true if they are equal |
| return a && b && a == b; |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.gfx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.gfx"] = true; |
| dojo.provide("dojox.gfx"); |
| |
| |
| |
| |
| dojo.loadInit(function(){ |
| //Since loaderInit can be fired before any dojo.provide/require calls, |
| //make sure the dojox.gfx object exists and only run this logic if dojox.gfx.renderer |
| //has not been defined yet. |
| var gfx = dojo.getObject("dojox.gfx", true), sl, flag, match; |
| if(!gfx.renderer){ |
| //Have a way to force a GFX renderer, if so desired. |
| //Useful for being able to serialize GFX data in a particular format. |
| if(dojo.config.forceGfxRenderer){ |
| dojox.gfx.renderer = dojo.config.forceGfxRenderer; |
| return; |
| } |
| var renderers = (typeof dojo.config.gfxRenderer == "string" ? |
| dojo.config.gfxRenderer : "svg,vml,silverlight,canvas").split(","); |
| |
| // mobile platform detection |
| // TODO: move to the base? |
| |
| var ua = navigator.userAgent, iPhoneOsBuild = 0, androidVersion = 0; |
| if(dojo.isSafari >= 3){ |
| // detect mobile version of WebKit starting with "version 3" |
| |
| // comprehensive iPhone test. Have to figure out whether it's SVG or Canvas based on the build. |
| // iPhone OS build numbers from en.wikipedia.org. |
| if(ua.indexOf("iPhone") >= 0 || ua.indexOf("iPod") >= 0){ |
| // grab the build out of this. Expression is a little nasty because we want |
| // to be sure we have the whole version string. |
| match = ua.match(/Version\/(\d(\.\d)?(\.\d)?)\sMobile\/([^\s]*)\s?/); |
| if(match){ |
| // grab the build out of the match. Only use the first three because of specific builds. |
| iPhoneOsBuild = parseInt(match[4].substr(0,3), 16); |
| } |
| } |
| } |
| if(dojo.isWebKit){ |
| // Android detection |
| if(!iPhoneOsBuild){ |
| match = ua.match(/Android\s+(\d+\.\d+)/); |
| if(match){ |
| androidVersion = parseFloat(match[1]); |
| // Android 1.0-1.1 doesn't support SVG but supports Canvas |
| } |
| } |
| } |
| |
| for(var i = 0; i < renderers.length; ++i){ |
| switch(renderers[i]){ |
| case "svg": |
| // iPhone OS builds greater than 5F1 should have SVG. |
| if(!dojo.isIE && (!iPhoneOsBuild || iPhoneOsBuild >= 0x5f1) && !androidVersion && !dojo.isAIR){ |
| dojox.gfx.renderer = "svg"; |
| } |
| break; |
| case "vml": |
| if(dojo.isIE){ |
| dojox.gfx.renderer = "vml"; |
| } |
| break; |
| case "silverlight": |
| try{ |
| if(dojo.isIE){ |
| sl = new ActiveXObject("AgControl.AgControl"); |
| if(sl && sl.IsVersionSupported("1.0")){ |
| flag = true; |
| } |
| }else{ |
| if(navigator.plugins["Silverlight Plug-In"]){ |
| flag = true; |
| } |
| } |
| }catch(e){ |
| flag = false; |
| }finally{ |
| sl = null; |
| } |
| if(flag){ dojox.gfx.renderer = "silverlight"; } |
| break; |
| case "canvas": |
| //TODO: need more comprehensive test for Canvas |
| if(!dojo.isIE){ |
| dojox.gfx.renderer = "canvas"; |
| } |
| break; |
| } |
| if(dojox.gfx.renderer){ break; } |
| } |
| if(dojo.config.isDebug){ |
| console.log("gfx renderer = " + dojox.gfx.renderer); |
| } |
| } |
| }); |
| |
| // include a renderer conditionally |
| dojo.requireIf(dojox.gfx.renderer == "svg", "dojox.gfx.svg"); |
| dojo.requireIf(dojox.gfx.renderer == "vml", "dojox.gfx.vml"); |
| dojo.requireIf(dojox.gfx.renderer == "silverlight", "dojox.gfx.silverlight"); |
| dojo.requireIf(dojox.gfx.renderer == "canvas", "dojox.gfx.canvas"); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.lang.functional.lambda"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.lang.functional.lambda"] = true; |
| dojo.provide("dojox.lang.functional.lambda"); |
| |
| // This module adds high-level functions and related constructs: |
| // - anonymous functions built from the string |
| |
| // Acknoledgements: |
| // - lambda() is based on work by Oliver Steele |
| // (http://osteele.com/sources/javascript/functional/functional.js) |
| // which was published under MIT License |
| |
| // Notes: |
| // - lambda() produces functions, which after the compilation step are |
| // as fast as regular JS functions (at least theoretically). |
| |
| // Lambda input values: |
| // - returns functions unchanged |
| // - converts strings to functions |
| // - converts arrays to a functional composition |
| |
| (function(){ |
| var df = dojox.lang.functional, lcache = {}; |
| |
| // split() is augmented on IE6 to ensure the uniform behavior |
| var split = "ab".split(/a*/).length > 1 ? String.prototype.split : |
| function(sep){ |
| var r = this.split.call(this, sep), |
| m = sep.exec(this); |
| if(m && m.index == 0){ r.unshift(""); } |
| return r; |
| }; |
| |
| var lambda = function(/*String*/ s){ |
| var args = [], sects = split.call(s, /\s*->\s*/m); |
| if(sects.length > 1){ |
| while(sects.length){ |
| s = sects.pop(); |
| args = sects.pop().split(/\s*,\s*|\s+/m); |
| if(sects.length){ sects.push("(function(" + args + "){return (" + s + ")})"); } |
| } |
| }else if(s.match(/\b_\b/)){ |
| args = ["_"]; |
| }else{ |
| var l = s.match(/^\s*(?:[+*\/%&|\^\.=<>]|!=)/m), |
| r = s.match(/[+\-*\/%&|\^\.=<>!]\s*$/m); |
| if(l || r){ |
| if(l){ |
| args.push("$1"); |
| s = "$1" + s; |
| } |
| if(r){ |
| args.push("$2"); |
| s = s + "$2"; |
| } |
| }else{ |
| // the point of the long regex below is to exclude all well-known |
| // lower-case words from the list of potential arguments |
| var vars = s. |
| replace(/(?:\b[A-Z]|\.[a-zA-Z_$])[a-zA-Z_$\d]*|[a-zA-Z_$][a-zA-Z_$\d]*:|this|true|false|null|undefined|typeof|instanceof|in|delete|new|void|arguments|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|escape|eval|isFinite|isNaN|parseFloat|parseInt|unescape|dojo|dijit|dojox|window|document|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"/g, ""). |
| match(/([a-z_$][a-z_$\d]*)/gi) || [], t = {}; |
| dojo.forEach(vars, function(v){ |
| if(!(v in t)){ |
| args.push(v); |
| t[v] = 1; |
| } |
| }); |
| } |
| } |
| return {args: args, body: s}; // Object |
| }; |
| |
| var compose = function(/*Array*/ a){ |
| return a.length ? |
| function(){ |
| var i = a.length - 1, x = df.lambda(a[i]).apply(this, arguments); |
| for(--i; i >= 0; --i){ x = df.lambda(a[i]).call(this, x); } |
| return x; |
| } |
| : |
| // identity |
| function(x){ return x; }; |
| }; |
| |
| dojo.mixin(df, { |
| // lambda |
| rawLambda: function(/*String*/ s){ |
| // summary: |
| // builds a function from a snippet, or array (composing), |
| // returns an object describing the function; functions are |
| // passed through unmodified. |
| // description: |
| // This method is to normalize a functional representation (a |
| // text snippet) to an object that contains an array of |
| // arguments, and a body , which is used to calculate the |
| // returning value. |
| return lambda(s); // Object |
| }, |
| buildLambda: function(/*String*/ s){ |
| // summary: |
| // builds a function from a snippet, returns a string, which |
| // represents the function. |
| // description: |
| // This method returns a textual representation of a function |
| // built from the snippet. It is meant to be evaled in the |
| // proper context, so local variables can be pulled from the |
| // environment. |
| s = lambda(s); |
| return "function(" + s.args.join(",") + "){return (" + s.body + ");}"; // String |
| }, |
| lambda: function(/*Function|String|Array*/ s){ |
| // summary: |
| // builds a function from a snippet, or array (composing), |
| // returns a function object; functions are passed through |
| // unmodified. |
| // description: |
| // This method is used to normalize a functional |
| // representation (a text snippet, an array, or a function) to |
| // a function object. |
| if(typeof s == "function"){ return s; } |
| if(s instanceof Array){ return compose(s); } |
| if(s in lcache){ return lcache[s]; } |
| s = lambda(s); |
| return lcache[s] = new Function(s.args, "return (" + s.body + ");"); // Function |
| }, |
| clearLambdaCache: function(){ |
| // summary: |
| // clears internal cache of lambdas |
| lcache = {}; |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.lang.functional.array"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.lang.functional.array"] = true; |
| dojo.provide("dojox.lang.functional.array"); |
| |
| |
| |
| // This module adds high-level functions and related constructs: |
| // - array-processing functions similar to standard JS functions |
| |
| // Notes: |
| // - this module provides JS standard methods similar to high-level functions in dojo/_base/array.js: |
| // forEach, map, filter, every, some |
| |
| // Defined methods: |
| // - take any valid lambda argument as the functional argument |
| // - operate on dense arrays |
| // - take a string as the array argument |
| // - take an iterator objects as the array argument |
| |
| (function(){ |
| var d = dojo, df = dojox.lang.functional, empty = {}; |
| |
| d.mixin(df, { |
| // JS 1.6 standard array functions, which can take a lambda as a parameter. |
| // Consider using dojo._base.array functions, if you don't need the lambda support. |
| filter: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ |
| // summary: creates a new array with all elements that pass the test |
| // implemented by the provided function. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| var t = [], v, i, n; |
| if(d.isArray(a)){ |
| // array |
| for(i = 0, n = a.length; i < n; ++i){ |
| v = a[i]; |
| if(f.call(o, v, i, a)){ t.push(v); } |
| } |
| }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ |
| // iterator |
| for(i = 0; a.hasNext();){ |
| v = a.next(); |
| if(f.call(o, v, i++, a)){ t.push(v); } |
| } |
| }else{ |
| // object/dictionary |
| for(i in a){ |
| if(!(i in empty)){ |
| v = a[i]; |
| if(f.call(o, v, i, a)){ t.push(v); } |
| } |
| } |
| } |
| return t; // Array |
| }, |
| forEach: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ |
| // summary: executes a provided function once per array element. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| var i, n; |
| if(d.isArray(a)){ |
| // array |
| for(i = 0, n = a.length; i < n; f.call(o, a[i], i, a), ++i); |
| }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ |
| // iterator |
| for(i = 0; a.hasNext(); f.call(o, a.next(), i++, a)); |
| }else{ |
| // object/dictionary |
| for(i in a){ |
| if(!(i in empty)){ |
| f.call(o, a[i], i, a); |
| } |
| } |
| } |
| return o; // Object |
| }, |
| map: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ |
| // summary: creates a new array with the results of calling |
| // a provided function on every element in this array. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| var t, n, i; |
| if(d.isArray(a)){ |
| // array |
| t = new Array(n = a.length); |
| for(i = 0; i < n; t[i] = f.call(o, a[i], i, a), ++i); |
| }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ |
| // iterator |
| t = []; |
| for(i = 0; a.hasNext(); t.push(f.call(o, a.next(), i++, a))); |
| }else{ |
| // object/dictionary |
| t = []; |
| for(i in a){ |
| if(!(i in empty)){ |
| t.push(f.call(o, a[i], i, a)); |
| } |
| } |
| } |
| return t; // Array |
| }, |
| every: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ |
| // summary: tests whether all elements in the array pass the test |
| // implemented by the provided function. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| var i, n; |
| if(d.isArray(a)){ |
| // array |
| for(i = 0, n = a.length; i < n; ++i){ |
| if(!f.call(o, a[i], i, a)){ |
| return false; // Boolean |
| } |
| } |
| }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ |
| // iterator |
| for(i = 0; a.hasNext();){ |
| if(!f.call(o, a.next(), i++, a)){ |
| return false; // Boolean |
| } |
| } |
| }else{ |
| // object/dictionary |
| for(i in a){ |
| if(!(i in empty)){ |
| if(!f.call(o, a[i], i, a)){ |
| return false; // Boolean |
| } |
| } |
| } |
| } |
| return true; // Boolean |
| }, |
| some: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ |
| // summary: tests whether some element in the array passes the test |
| // implemented by the provided function. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| var i, n; |
| if(d.isArray(a)){ |
| // array |
| for(i = 0, n = a.length; i < n; ++i){ |
| if(f.call(o, a[i], i, a)){ |
| return true; // Boolean |
| } |
| } |
| }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ |
| // iterator |
| for(i = 0; a.hasNext();){ |
| if(f.call(o, a.next(), i++, a)){ |
| return true; // Boolean |
| } |
| } |
| }else{ |
| // object/dictionary |
| for(i in a){ |
| if(!(i in empty)){ |
| if(f.call(o, a[i], i, a)){ |
| return true; // Boolean |
| } |
| } |
| } |
| } |
| return false; // Boolean |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.lang.functional.object"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.lang.functional.object"] = true; |
| dojo.provide("dojox.lang.functional.object"); |
| |
| |
| |
| // This module adds high-level functions and related constructs: |
| // - object/dictionary helpers |
| |
| // Defined methods: |
| // - take any valid lambda argument as the functional argument |
| // - skip all attributes that are present in the empty object |
| // (IE and/or 3rd-party libraries). |
| |
| (function(){ |
| var d = dojo, df = dojox.lang.functional, empty = {}; |
| |
| d.mixin(df, { |
| // object helpers |
| keys: function(/*Object*/ obj){ |
| // summary: returns an array of all keys in the object |
| var t = []; |
| for(var i in obj){ |
| if(!(i in empty)){ |
| t.push(i); |
| } |
| } |
| return t; // Array |
| }, |
| values: function(/*Object*/ obj){ |
| // summary: returns an array of all values in the object |
| var t = []; |
| for(var i in obj){ |
| if(!(i in empty)){ |
| t.push(obj[i]); |
| } |
| } |
| return t; // Array |
| }, |
| filterIn: function(/*Object*/ obj, /*Function|String|Array*/ f, /*Object?*/ o){ |
| // summary: creates new object with all attributes that pass the test |
| // implemented by the provided function. |
| o = o || d.global; f = df.lambda(f); |
| var t = {}, v, i; |
| for(i in obj){ |
| if(!(i in empty)){ |
| v = obj[i]; |
| if(f.call(o, v, i, obj)){ t[i] = v; } |
| } |
| } |
| return t; // Object |
| }, |
| forIn: function(/*Object*/ obj, /*Function|String|Array*/ f, /*Object?*/ o){ |
| // summary: iterates over all object attributes. |
| o = o || d.global; f = df.lambda(f); |
| for(var i in obj){ |
| if(!(i in empty)){ |
| f.call(o, obj[i], i, obj); |
| } |
| } |
| return o; // Object |
| }, |
| mapIn: function(/*Object*/ obj, /*Function|String|Array*/ f, /*Object?*/ o){ |
| // summary: creates new object with the results of calling |
| // a provided function on every attribute in this object. |
| o = o || d.global; f = df.lambda(f); |
| var t = {}, i; |
| for(i in obj){ |
| if(!(i in empty)){ |
| t[i] = f.call(o, obj[i], i, obj); |
| } |
| } |
| return t; // Object |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.lang.functional"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.lang.functional"] = true; |
| dojo.provide("dojox.lang.functional"); |
| |
| |
| |
| |
| |
| } |
| |
| if(!dojo._hasResource["dojox.lang.functional.fold"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.lang.functional.fold"] = true; |
| dojo.provide("dojox.lang.functional.fold"); |
| |
| |
| |
| // This module adds high-level functions and related constructs: |
| // - "fold" family of functions |
| |
| // Notes: |
| // - missing high-level functions are provided with the compatible API: |
| // foldl, foldl1, foldr, foldr1 |
| // - missing JS standard functions are provided with the compatible API: |
| // reduce, reduceRight |
| // - the fold's counterpart: unfold |
| |
| // Defined methods: |
| // - take any valid lambda argument as the functional argument |
| // - operate on dense arrays |
| // - take a string as the array argument |
| // - take an iterator objects as the array argument (only foldl, foldl1, and reduce) |
| |
| (function(){ |
| var d = dojo, df = dojox.lang.functional, empty = {}; |
| |
| d.mixin(df, { |
| // classic reduce-class functions |
| foldl: function(/*Array|String|Object*/ a, /*Function*/ f, /*Object*/ z, /*Object?*/ o){ |
| // summary: repeatedly applies a binary function to an array from left |
| // to right using a seed value as a starting point; returns the final |
| // value. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| var i, n; |
| if(d.isArray(a)){ |
| // array |
| for(i = 0, n = a.length; i < n; z = f.call(o, z, a[i], i, a), ++i); |
| }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ |
| // iterator |
| for(i = 0; a.hasNext(); z = f.call(o, z, a.next(), i++, a)); |
| }else{ |
| // object/dictionary |
| for(i in a){ |
| if(!(i in empty)){ |
| z = f.call(o, z, a[i], i, a); |
| } |
| } |
| } |
| return z; // Object |
| }, |
| foldl1: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ |
| // summary: repeatedly applies a binary function to an array from left |
| // to right; returns the final value. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| var z, i, n; |
| if(d.isArray(a)){ |
| // array |
| z = a[0]; |
| for(i = 1, n = a.length; i < n; z = f.call(o, z, a[i], i, a), ++i); |
| }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ |
| // iterator |
| if(a.hasNext()){ |
| z = a.next(); |
| for(i = 1; a.hasNext(); z = f.call(o, z, a.next(), i++, a)); |
| } |
| }else{ |
| // object/dictionary |
| var first = true; |
| for(i in a){ |
| if(!(i in empty)){ |
| if(first){ |
| z = a[i]; |
| first = false; |
| }else{ |
| z = f.call(o, z, a[i], i, a); |
| } |
| } |
| } |
| } |
| return z; // Object |
| }, |
| foldr: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){ |
| // summary: repeatedly applies a binary function to an array from right |
| // to left using a seed value as a starting point; returns the final |
| // value. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| for(var i = a.length; i > 0; --i, z = f.call(o, z, a[i], i, a)); |
| return z; // Object |
| }, |
| foldr1: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ |
| // summary: repeatedly applies a binary function to an array from right |
| // to left; returns the final value. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| var n = a.length, z = a[n - 1], i = n - 1; |
| for(; i > 0; --i, z = f.call(o, z, a[i], i, a)); |
| return z; // Object |
| }, |
| // JS 1.8 standard array functions, which can take a lambda as a parameter. |
| reduce: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ z){ |
| // summary: apply a function simultaneously against two values of the array |
| // (from left-to-right) as to reduce it to a single value. |
| return arguments.length < 3 ? df.foldl1(a, f) : df.foldl(a, f, z); // Object |
| }, |
| reduceRight: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ z){ |
| // summary: apply a function simultaneously against two values of the array |
| // (from right-to-left) as to reduce it to a single value. |
| return arguments.length < 3 ? df.foldr1(a, f) : df.foldr(a, f, z); // Object |
| }, |
| // the fold's counterpart: unfold |
| unfold: function(/*Function|String|Array*/ pr, /*Function|String|Array*/ f, |
| /*Function|String|Array*/ g, /*Object*/ z, /*Object?*/ o){ |
| // summary: builds an array by unfolding a value |
| o = o || d.global; f = df.lambda(f); g = df.lambda(g); pr = df.lambda(pr); |
| var t = []; |
| for(; !pr.call(o, z); t.push(f.call(o, z)), z = g.call(o, z)); |
| return t; // Array |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.lang.functional.reversed"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.lang.functional.reversed"] = true; |
| dojo.provide("dojox.lang.functional.reversed"); |
| |
| |
| |
| // This module adds high-level functions and related constructs: |
| // - reversed versions of array-processing functions similar to standard JS functions |
| |
| // Notes: |
| // - this module provides reversed versions of standard array-processing functions: |
| // forEachRev, mapRev, filterRev |
| |
| // Defined methods: |
| // - take any valid lambda argument as the functional argument |
| // - operate on dense arrays |
| // - take a string as the array argument |
| |
| (function(){ |
| var d = dojo, df = dojox.lang.functional; |
| |
| d.mixin(df, { |
| // JS 1.6 standard array functions, which can take a lambda as a parameter. |
| // Consider using dojo._base.array functions, if you don't need the lambda support. |
| filterRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ |
| // summary: creates a new array with all elements that pass the test |
| // implemented by the provided function. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| var t = [], v, i = a.length - 1; |
| for(; i >= 0; --i){ |
| v = a[i]; |
| if(f.call(o, v, i, a)){ t.push(v); } |
| } |
| return t; // Array |
| }, |
| forEachRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ |
| // summary: executes a provided function once per array element. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| for(var i = a.length - 1; i >= 0; f.call(o, a[i], i, a), --i); |
| }, |
| mapRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ |
| // summary: creates a new array with the results of calling |
| // a provided function on every element in this array. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| var n = a.length, t = new Array(n), i = n - 1, j = 0; |
| for(; i >= 0; t[j++] = f.call(o, a[i], i, a), --i); |
| return t; // Array |
| }, |
| everyRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ |
| // summary: tests whether all elements in the array pass the test |
| // implemented by the provided function. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| for(var i = a.length - 1; i >= 0; --i){ |
| if(!f.call(o, a[i], i, a)){ |
| return false; // Boolean |
| } |
| } |
| return true; // Boolean |
| }, |
| someRev: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ |
| // summary: tests whether some element in the array passes the test |
| // implemented by the provided function. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| for(var i = a.length - 1; i >= 0; --i){ |
| if(f.call(o, a[i], i, a)){ |
| return true; // Boolean |
| } |
| } |
| return false; // Boolean |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojo.colors"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo.colors"] = true; |
| dojo.provide("dojo.colors"); |
| |
| //TODO: this module appears to break naming conventions |
| |
| /*===== |
| dojo.colors = { |
| // summary: Color utilities |
| } |
| =====*/ |
| |
| (function(){ |
| // this is a standard conversion prescribed by the CSS3 Color Module |
| var hue2rgb = function(m1, m2, h){ |
| if(h < 0){ ++h; } |
| if(h > 1){ --h; } |
| var h6 = 6 * h; |
| if(h6 < 1){ return m1 + (m2 - m1) * h6; } |
| if(2 * h < 1){ return m2; } |
| if(3 * h < 2){ return m1 + (m2 - m1) * (2 / 3 - h) * 6; } |
| return m1; |
| }; |
| |
| dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){ |
| // summary: |
| // get rgb(a) array from css-style color declarations |
| // description: |
| // this function can handle all 4 CSS3 Color Module formats: rgb, |
| // rgba, hsl, hsla, including rgb(a) with percentage values. |
| var m = color.toLowerCase().match(/^(rgba?|hsla?)\(([\s\.\-,%0-9]+)\)/); |
| if(m){ |
| var c = m[2].split(/\s*,\s*/), l = c.length, t = m[1], a; |
| if((t == "rgb" && l == 3) || (t == "rgba" && l == 4)){ |
| var r = c[0]; |
| if(r.charAt(r.length - 1) == "%"){ |
| // 3 rgb percentage values |
| a = dojo.map(c, function(x){ |
| return parseFloat(x) * 2.56; |
| }); |
| if(l == 4){ a[3] = c[3]; } |
| return dojo.colorFromArray(a, obj); // dojo.Color |
| } |
| return dojo.colorFromArray(c, obj); // dojo.Color |
| } |
| if((t == "hsl" && l == 3) || (t == "hsla" && l == 4)){ |
| // normalize hsl values |
| var H = ((parseFloat(c[0]) % 360) + 360) % 360 / 360, |
| S = parseFloat(c[1]) / 100, |
| L = parseFloat(c[2]) / 100, |
| // calculate rgb according to the algorithm |
| // recommended by the CSS3 Color Module |
| m2 = L <= 0.5 ? L * (S + 1) : L + S - L * S, |
| m1 = 2 * L - m2; |
| a = [ |
| hue2rgb(m1, m2, H + 1 / 3) * 256, |
| hue2rgb(m1, m2, H) * 256, |
| hue2rgb(m1, m2, H - 1 / 3) * 256, |
| 1 |
| ]; |
| if(l == 4){ a[3] = c[3]; } |
| return dojo.colorFromArray(a, obj); // dojo.Color |
| } |
| } |
| return null; // dojo.Color |
| }; |
| |
| var confine = function(c, low, high){ |
| // summary: |
| // sanitize a color component by making sure it is a number, |
| // and clamping it to valid values |
| c = Number(c); |
| return isNaN(c) ? high : c < low ? low : c > high ? high : c; // Number |
| }; |
| |
| dojo.Color.prototype.sanitize = function(){ |
| // summary: makes sure that the object has correct attributes |
| var t = this; |
| t.r = Math.round(confine(t.r, 0, 255)); |
| t.g = Math.round(confine(t.g, 0, 255)); |
| t.b = Math.round(confine(t.b, 0, 255)); |
| t.a = confine(t.a, 0, 1); |
| return this; // dojo.Color |
| }; |
| })(); |
| |
| |
| dojo.colors.makeGrey = function(/*Number*/ g, /*Number?*/ a){ |
| // summary: creates a greyscale color with an optional alpha |
| return dojo.colorFromArray([g, g, g, a]); |
| }; |
| |
| // mixin all CSS3 named colors not already in _base, along with SVG 1.0 variant spellings |
| dojo.mixin(dojo.Color.named, { |
| aliceblue: [240,248,255], |
| antiquewhite: [250,235,215], |
| aquamarine: [127,255,212], |
| azure: [240,255,255], |
| beige: [245,245,220], |
| bisque: [255,228,196], |
| blanchedalmond: [255,235,205], |
| blueviolet: [138,43,226], |
| brown: [165,42,42], |
| burlywood: [222,184,135], |
| cadetblue: [95,158,160], |
| chartreuse: [127,255,0], |
| chocolate: [210,105,30], |
| coral: [255,127,80], |
| cornflowerblue: [100,149,237], |
| cornsilk: [255,248,220], |
| crimson: [220,20,60], |
| cyan: [0,255,255], |
| darkblue: [0,0,139], |
| darkcyan: [0,139,139], |
| darkgoldenrod: [184,134,11], |
| darkgray: [169,169,169], |
| darkgreen: [0,100,0], |
| darkgrey: [169,169,169], |
| darkkhaki: [189,183,107], |
| darkmagenta: [139,0,139], |
| darkolivegreen: [85,107,47], |
| darkorange: [255,140,0], |
| darkorchid: [153,50,204], |
| darkred: [139,0,0], |
| darksalmon: [233,150,122], |
| darkseagreen: [143,188,143], |
| darkslateblue: [72,61,139], |
| darkslategray: [47,79,79], |
| darkslategrey: [47,79,79], |
| darkturquoise: [0,206,209], |
| darkviolet: [148,0,211], |
| deeppink: [255,20,147], |
| deepskyblue: [0,191,255], |
| dimgray: [105,105,105], |
| dimgrey: [105,105,105], |
| dodgerblue: [30,144,255], |
| firebrick: [178,34,34], |
| floralwhite: [255,250,240], |
| forestgreen: [34,139,34], |
| gainsboro: [220,220,220], |
| ghostwhite: [248,248,255], |
| gold: [255,215,0], |
| goldenrod: [218,165,32], |
| greenyellow: [173,255,47], |
| grey: [128,128,128], |
| honeydew: [240,255,240], |
| hotpink: [255,105,180], |
| indianred: [205,92,92], |
| indigo: [75,0,130], |
| ivory: [255,255,240], |
| khaki: [240,230,140], |
| lavender: [230,230,250], |
| lavenderblush: [255,240,245], |
| lawngreen: [124,252,0], |
| lemonchiffon: [255,250,205], |
| lightblue: [173,216,230], |
| lightcoral: [240,128,128], |
| lightcyan: [224,255,255], |
| lightgoldenrodyellow: [250,250,210], |
| lightgray: [211,211,211], |
| lightgreen: [144,238,144], |
| lightgrey: [211,211,211], |
| lightpink: [255,182,193], |
| lightsalmon: [255,160,122], |
| lightseagreen: [32,178,170], |
| lightskyblue: [135,206,250], |
| lightslategray: [119,136,153], |
| lightslategrey: [119,136,153], |
| lightsteelblue: [176,196,222], |
| lightyellow: [255,255,224], |
| limegreen: [50,205,50], |
| linen: [250,240,230], |
| magenta: [255,0,255], |
| mediumaquamarine: [102,205,170], |
| mediumblue: [0,0,205], |
| mediumorchid: [186,85,211], |
| mediumpurple: [147,112,219], |
| mediumseagreen: [60,179,113], |
| mediumslateblue: [123,104,238], |
| mediumspringgreen: [0,250,154], |
| mediumturquoise: [72,209,204], |
| mediumvioletred: [199,21,133], |
| midnightblue: [25,25,112], |
| mintcream: [245,255,250], |
| mistyrose: [255,228,225], |
| moccasin: [255,228,181], |
| navajowhite: [255,222,173], |
| oldlace: [253,245,230], |
| olivedrab: [107,142,35], |
| orange: [255,165,0], |
| orangered: [255,69,0], |
| orchid: [218,112,214], |
| palegoldenrod: [238,232,170], |
| palegreen: [152,251,152], |
| paleturquoise: [175,238,238], |
| palevioletred: [219,112,147], |
| papayawhip: [255,239,213], |
| peachpuff: [255,218,185], |
| peru: [205,133,63], |
| pink: [255,192,203], |
| plum: [221,160,221], |
| powderblue: [176,224,230], |
| rosybrown: [188,143,143], |
| royalblue: [65,105,225], |
| saddlebrown: [139,69,19], |
| salmon: [250,128,114], |
| sandybrown: [244,164,96], |
| seagreen: [46,139,87], |
| seashell: [255,245,238], |
| sienna: [160,82,45], |
| skyblue: [135,206,235], |
| slateblue: [106,90,205], |
| slategray: [112,128,144], |
| slategrey: [112,128,144], |
| snow: [255,250,250], |
| springgreen: [0,255,127], |
| steelblue: [70,130,180], |
| tan: [210,180,140], |
| thistle: [216,191,216], |
| tomato: [255,99,71], |
| transparent: [0, 0, 0, 0], |
| turquoise: [64,224,208], |
| violet: [238,130,238], |
| wheat: [245,222,179], |
| whitesmoke: [245,245,245], |
| yellowgreen: [154,205,50] |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.color._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.color._base"] = true; |
| dojo.provide("dojox.color._base"); |
| |
| |
| // alias all the dojo.Color mechanisms |
| dojox.color.Color=dojo.Color; |
| dojox.color.blend=dojo.blendColors; |
| dojox.color.fromRgb=dojo.colorFromRgb; |
| dojox.color.fromHex=dojo.colorFromHex; |
| dojox.color.fromArray=dojo.colorFromArray; |
| dojox.color.fromString=dojo.colorFromString; |
| |
| // alias the dojo.colors mechanisms |
| dojox.color.greyscale=dojo.colors.makeGrey; |
| |
| // static methods |
| dojo.mixin(dojox.color, { |
| fromCmy: function(/* Object|Array|int */cyan, /*int*/magenta, /*int*/yellow){ |
| // summary |
| // Create a dojox.color.Color from a CMY defined color. |
| // All colors should be expressed as 0-100 (percentage) |
| |
| if(dojo.isArray(cyan)){ |
| magenta=cyan[1], yellow=cyan[2], cyan=cyan[0]; |
| } else if(dojo.isObject(cyan)){ |
| magenta=cyan.m, yellow=cyan.y, cyan=cyan.c; |
| } |
| cyan/=100, magenta/=100, yellow/=100; |
| |
| var r=1-cyan, g=1-magenta, b=1-yellow; |
| return new dojox.color.Color({ r:Math.round(r*255), g:Math.round(g*255), b:Math.round(b*255) }); // dojox.color.Color |
| }, |
| |
| fromCmyk: function(/* Object|Array|int */cyan, /*int*/magenta, /*int*/yellow, /*int*/black){ |
| // summary |
| // Create a dojox.color.Color from a CMYK defined color. |
| // All colors should be expressed as 0-100 (percentage) |
| |
| if(dojo.isArray(cyan)){ |
| magenta=cyan[1], yellow=cyan[2], black=cyan[3], cyan=cyan[0]; |
| } else if(dojo.isObject(cyan)){ |
| magenta=cyan.m, yellow=cyan.y, black=cyan.b, cyan=cyan.c; |
| } |
| cyan/=100, magenta/=100, yellow/=100, black/=100; |
| var r,g,b; |
| r = 1-Math.min(1, cyan*(1-black)+black); |
| g = 1-Math.min(1, magenta*(1-black)+black); |
| b = 1-Math.min(1, yellow*(1-black)+black); |
| return new dojox.color.Color({ r:Math.round(r*255), g:Math.round(g*255), b:Math.round(b*255) }); // dojox.color.Color |
| }, |
| |
| fromHsl: function(/* Object|Array|int */hue, /* int */saturation, /* int */luminosity){ |
| // summary |
| // Create a dojox.color.Color from an HSL defined color. |
| // hue from 0-359 (degrees), saturation and luminosity 0-100. |
| |
| if(dojo.isArray(hue)){ |
| saturation=hue[1], luminosity=hue[2], hue=hue[0]; |
| } else if(dojo.isObject(hue)){ |
| saturation=hue.s, luminosity=hue.l, hue=hue.h; |
| } |
| saturation/=100; |
| luminosity/=100; |
| |
| while(hue<0){ hue+=360; } |
| while(hue>=360){ hue-=360; } |
| |
| var r, g, b; |
| if(hue<120){ |
| r=(120-hue)/60, g=hue/60, b=0; |
| } else if (hue<240){ |
| r=0, g=(240-hue)/60, b=(hue-120)/60; |
| } else { |
| r=(hue-240)/60, g=0, b=(360-hue)/60; |
| } |
| |
| r=2*saturation*Math.min(r, 1)+(1-saturation); |
| g=2*saturation*Math.min(g, 1)+(1-saturation); |
| b=2*saturation*Math.min(b, 1)+(1-saturation); |
| if(luminosity<0.5){ |
| r*=luminosity, g*=luminosity, b*=luminosity; |
| }else{ |
| r=(1-luminosity)*r+2*luminosity-1; |
| g=(1-luminosity)*g+2*luminosity-1; |
| b=(1-luminosity)*b+2*luminosity-1; |
| } |
| return new dojox.color.Color({ r:Math.round(r*255), g:Math.round(g*255), b:Math.round(b*255) }); // dojox.color.Color |
| }, |
| |
| fromHsv: function(/* Object|Array|int */hue, /* int */saturation, /* int */value){ |
| // summary |
| // Create a dojox.color.Color from an HSV defined color. |
| // hue from 0-359 (degrees), saturation and value 0-100. |
| |
| if(dojo.isArray(hue)){ |
| saturation=hue[1], value=hue[2], hue=hue[0]; |
| } else if (dojo.isObject(hue)){ |
| saturation=hue.s, value=hue.v, hue=hue.h; |
| } |
| |
| if(hue==360){ hue=0; } |
| saturation/=100; |
| value/=100; |
| |
| var r, g, b; |
| if(saturation==0){ |
| r=value, b=value, g=value; |
| }else{ |
| var hTemp=hue/60, i=Math.floor(hTemp), f=hTemp-i; |
| var p=value*(1-saturation); |
| var q=value*(1-(saturation*f)); |
| var t=value*(1-(saturation*(1-f))); |
| switch(i){ |
| case 0:{ r=value, g=t, b=p; break; } |
| case 1:{ r=q, g=value, b=p; break; } |
| case 2:{ r=p, g=value, b=t; break; } |
| case 3:{ r=p, g=q, b=value; break; } |
| case 4:{ r=t, g=p, b=value; break; } |
| case 5:{ r=value, g=p, b=q; break; } |
| } |
| } |
| return new dojox.color.Color({ r:Math.round(r*255), g:Math.round(g*255), b:Math.round(b*255) }); // dojox.color.Color |
| } |
| }); |
| |
| // Conversions directly on dojox.color.Color |
| dojo.extend(dojox.color.Color, { |
| toCmy: function(){ |
| // summary |
| // Convert this Color to a CMY definition. |
| var cyan=1-(this.r/255), magenta=1-(this.g/255), yellow=1-(this.b/255); |
| return { c:Math.round(cyan*100), m:Math.round(magenta*100), y:Math.round(yellow*100) }; // Object |
| }, |
| |
| toCmyk: function(){ |
| // summary |
| // Convert this Color to a CMYK definition. |
| var cyan, magenta, yellow, black; |
| var r=this.r/255, g=this.g/255, b=this.b/255; |
| black = Math.min(1-r, 1-g, 1-b); |
| cyan = (1-r-black)/(1-black); |
| magenta = (1-g-black)/(1-black); |
| yellow = (1-b-black)/(1-black); |
| return { c:Math.round(cyan*100), m:Math.round(magenta*100), y:Math.round(yellow*100), b:Math.round(black*100) }; // Object |
| }, |
| |
| toHsl: function(){ |
| // summary |
| // Convert this Color to an HSL definition. |
| var r=this.r/255, g=this.g/255, b=this.b/255; |
| var min = Math.min(r, b, g), max = Math.max(r, g, b); |
| var delta = max-min; |
| var h=0, s=0, l=(min+max)/2; |
| if(l>0 && l<1){ |
| s = delta/((l<0.5)?(2*l):(2-2*l)); |
| } |
| if(delta>0){ |
| if(max==r && max!=g){ |
| h+=(g-b)/delta; |
| } |
| if(max==g && max!=b){ |
| h+=(2+(b-r)/delta); |
| } |
| if(max==b && max!=r){ |
| h+=(4+(r-g)/delta); |
| } |
| h*=60; |
| } |
| return { h:h, s:Math.round(s*100), l:Math.round(l*100) }; // Object |
| }, |
| |
| toHsv: function(){ |
| // summary |
| // Convert this Color to an HSV definition. |
| var r=this.r/255, g=this.g/255, b=this.b/255; |
| var min = Math.min(r, b, g), max = Math.max(r, g, b); |
| var delta = max-min; |
| var h = null, s = (max==0)?0:(delta/max); |
| if(s==0){ |
| h = 0; |
| }else{ |
| if(r==max){ |
| h = 60*(g-b)/delta; |
| }else if(g==max){ |
| h = 120 + 60*(b-r)/delta; |
| }else{ |
| h = 240 + 60*(r-g)/delta; |
| } |
| |
| if(h<0){ h+=360; } |
| } |
| return { h:h, s:Math.round(s*100), v:Math.round(max*100) }; // Object |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.color"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.color"] = true; |
| dojo.provide("dojox.color"); |
| |
| |
| } |
| |
| if(!dojo._hasResource["dojox.color.Palette"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.color.Palette"] = true; |
| dojo.provide("dojox.color.Palette"); |
| |
| |
| (function(){ |
| var dxc = dojox.color; |
| /*************************************************************** |
| * dojox.color.Palette |
| * |
| * The Palette object is loosely based on the color palettes |
| * at Kuler (http://kuler.adobe.com). They are 5 color palettes |
| * with the base color considered to be the third color in the |
| * palette (for generation purposes). |
| * |
| * Palettes can be generated from well-known algorithms or they |
| * can be manually created by passing an array to the constructor. |
| * |
| * Palettes can be transformed, using a set of specific params |
| * similar to the way shapes can be transformed with dojox.gfx. |
| * However, unlike with transformations in dojox.gfx, transforming |
| * a palette will return you a new Palette object, in effect |
| * a clone of the original. |
| ***************************************************************/ |
| |
| // ctor ---------------------------------------------------------------------------- |
| dxc.Palette = function(/* String|Array|dojox.color.Color|dojox.color.Palette */base){ |
| // summary |
| // An object that represents a palette of colors. |
| // description |
| // A Palette is a representation of a set of colors. While the standard |
| // number of colors contained in a palette is 5, it can really handle any |
| // number of colors. |
| // |
| // A palette is useful for the ability to transform all the colors in it |
| // using a simple object-based approach. In addition, you can generate |
| // palettes using dojox.color.Palette.generate; these generated palettes |
| // are based on the palette generators at http://kuler.adobe.com. |
| // |
| // colors: dojox.color.Color[] |
| // The actual color references in this palette. |
| this.colors = []; |
| if(base instanceof dojox.color.Palette){ |
| this.colors = base.colors.slice(0); |
| } |
| else if(base instanceof dojox.color.Color){ |
| this.colors = [ null, null, base, null, null ]; |
| } |
| else if(dojo.isArray(base)){ |
| this.colors = dojo.map(base.slice(0), function(item){ |
| if(dojo.isString(item)){ return new dojox.color.Color(item); } |
| return item; |
| }); |
| } |
| else if (dojo.isString(base)){ |
| this.colors = [ null, null, new dojox.color.Color(base), null, null ]; |
| } |
| } |
| |
| // private functions --------------------------------------------------------------- |
| |
| // transformations |
| function tRGBA(p, param, val){ |
| var ret = new dojox.color.Palette(); |
| ret.colors = []; |
| dojo.forEach(p.colors, function(item){ |
| var r=(param=="dr")?item.r+val:item.r, |
| g=(param=="dg")?item.g+val:item.g, |
| b=(param=="db")?item.b+val:item.b, |
| a=(param=="da")?item.a+val:item.a |
| ret.colors.push(new dojox.color.Color({ |
| r: Math.min(255, Math.max(0, r)), |
| g: Math.min(255, Math.max(0, g)), |
| b: Math.min(255, Math.max(0, b)), |
| a: Math.min(1, Math.max(0, a)) |
| })); |
| }); |
| console.log("The return colors are ", ret.colors, " from the original colors ", p.colors); |
| return ret; |
| } |
| |
| function tCMY(p, param, val){ |
| var ret = new dojox.color.Palette(); |
| ret.colors = []; |
| dojo.forEach(p.colors, function(item){ |
| var o=item.toCmy(), |
| c=(param=="dc")?o.c+val:o.c, |
| m=(param=="dm")?o.m+val:o.m, |
| y=(param=="dy")?o.y+val:o.y; |
| ret.colors.push(dojox.color.fromCmy( |
| Math.min(100, Math.max(0, c)), |
| Math.min(100, Math.max(0, m)), |
| Math.min(100, Math.max(0, y)) |
| )); |
| }); |
| return ret; |
| } |
| |
| function tCMYK(p, param, val){ |
| var ret = new dojox.color.Palette(); |
| ret.colors = []; |
| dojo.forEach(p.colors, function(item){ |
| var o=item.toCmyk(), |
| c=(param=="dc")?o.c+val:o.c, |
| m=(param=="dm")?o.m+val:o.m, |
| y=(param=="dy")?o.y+val:o.y, |
| k=(param=="dk")?o.b+val:o.b; |
| ret.colors.push(dojox.color.fromCmyk( |
| Math.min(100, Math.max(0, c)), |
| Math.min(100, Math.max(0, m)), |
| Math.min(100, Math.max(0, y)), |
| Math.min(100, Math.max(0, k)) |
| )); |
| }); |
| return ret; |
| } |
| |
| function tHSL(p, param, val){ |
| var ret = new dojox.color.Palette(); |
| ret.colors = []; |
| dojo.forEach(p.colors, function(item){ |
| var o=item.toHsl(), |
| h=(param=="dh")?o.h+val:o.h, |
| s=(param=="ds")?o.s+val:o.s, |
| l=(param=="dl")?o.l+val:o.l; |
| ret.colors.push(dojox.color.fromHsl(h%360, Math.min(100, Math.max(0, s)), Math.min(100, Math.max(0, l)))); |
| }); |
| return ret; |
| } |
| |
| function tHSV(p, param, val){ |
| var ret = new dojox.color.Palette(); |
| ret.colors = []; |
| dojo.forEach(p.colors, function(item){ |
| var o=item.toHsv(), |
| h=(param=="dh")?o.h+val:o.h, |
| s=(param=="ds")?o.s+val:o.s, |
| v=(param=="dv")?o.v+val:o.v; |
| ret.colors.push(dojox.color.fromHsv(h%360, Math.min(100, Math.max(0, s)), Math.min(100, Math.max(0, v)))); |
| }); |
| return ret; |
| } |
| |
| // helper functions |
| function rangeDiff(val, low, high){ |
| // given the value in a range from 0 to high, find the equiv |
| // using the range low to high. |
| return high-((high-val)*((high-low)/high)); |
| } |
| |
| // object methods --------------------------------------------------------------- |
| dojo.extend(dxc.Palette, { |
| transform: function(/* Object */kwArgs){ |
| // summary |
| // Transform the palette using a specific transformation function |
| // and a set of transformation parameters. |
| // description |
| // {palette}.transform is a simple way to uniformly transform |
| // all of the colors in a palette using any of 5 formulae: |
| // RGBA, HSL, HSV, CMYK or CMY. |
| // |
| // Once the forumula to be used is determined, you can pass any |
| // number of parameters based on the formula "d"[param]; for instance, |
| // { use: "rgba", dr: 20, dg: -50 } will take all of the colors in |
| // palette, add 20 to the R value and subtract 50 from the G value. |
| // |
| // Unlike other types of transformations, transform does *not* alter |
| // the original palette but will instead return a new one. |
| var fn=tRGBA; // the default transform function. |
| if(kwArgs.use){ |
| // we are being specific about the algo we want to use. |
| var use=kwArgs.use.toLowerCase(); |
| if(use.indexOf("hs")==0){ |
| if(use.charAt(2)=="l"){ fn=tHSL; } |
| else { fn=tHSV; } |
| } |
| else if(use.indexOf("cmy")==0){ |
| if(use.charAt(3)=="k"){ fn=tCMYK; } |
| else { fn=tCMY; } |
| } |
| } |
| // try to guess the best choice. |
| else if("dc" in kwArgs || "dm" in kwArgs || "dy" in kwArgs){ |
| if("dk" in kwArgs){ fn = tCMYK; } |
| else { fn = tCMY; } |
| } |
| else if("dh" in kwArgs || "ds" in kwArgs){ |
| if("dv" in kwArgs){ fn = tHSV; } |
| else { fn = tHSL; } |
| } |
| |
| var palette = this; |
| for(var p in kwArgs){ |
| // ignore use |
| if(p=="use"){ continue; } |
| palette = fn(palette, p, kwArgs[p]); |
| } |
| return palette; // dojox.color.Palette |
| }, |
| clone: function(){ |
| // summary |
| // Clones the current palette. |
| return new dxc.Palette(this); // dojox.color.Palette |
| } |
| }); |
| |
| // static methods --------------------------------------------------------------- |
| dojo.mixin(dxc.Palette, { |
| generators: { |
| analogous:function(/* Object */args){ |
| var high=args.high||60, // delta between base hue and highest hue (subtracted from base) |
| low=args.low||18, // delta between base hue and lowest hue (added to base) |
| base = dojo.isString(args.base)?new dojox.color.Color(args.base):args.base, |
| hsv=base.toHsv(); |
| |
| // generate our hue angle differences |
| var h=[ |
| (hsv.h+low+360)%360, |
| (hsv.h+Math.round(low/2)+360)%360, |
| hsv.h, |
| (hsv.h-Math.round(high/2)+360)%360, |
| (hsv.h-high+360)%360 |
| ]; |
| |
| var s1=Math.max(10, (hsv.s<=95)?hsv.s+5:(100-(hsv.s-95))), |
| s2=(hsv.s>1)?hsv.s-1:21-hsv.s, |
| v1=(hsv.v>=92)?hsv.v-9:Math.max(hsv.v+9, 20), |
| v2=(hsv.v<=90)?Math.max(hsv.v+5, 20):(95+Math.ceil((hsv.v-90)/2)), |
| s=[ s1, s2, hsv.s, s1, s1 ], |
| v=[ v1, v2, hsv.v, v1, v2 ] |
| |
| return new dxc.Palette(dojo.map(h, function(hue, i){ |
| return dojox.color.fromHsv(hue, s[i], v[i]); |
| })); // dojox.color.Palette |
| }, |
| |
| monochromatic: function(/* Object */args){ |
| var base = dojo.isString(args.base)?new dojox.color.Color(args.base):args.base, |
| hsv = base.toHsv(); |
| |
| // figure out the saturation and value |
| var s1 = (hsv.s-30>9)?hsv.s-30:hsv.s+30, |
| s2 = hsv.s, |
| v1 = rangeDiff(hsv.v, 20, 100), |
| v2 = (hsv.v-20>20)?hsv.v-20:hsv.v+60, |
| v3 = (hsv.v-50>20)?hsv.v-50:hsv.v+30; |
| |
| return new dxc.Palette([ |
| dojox.color.fromHsv(hsv.h, s1, v1), |
| dojox.color.fromHsv(hsv.h, s2, v3), |
| base, |
| dojox.color.fromHsv(hsv.h, s1, v3), |
| dojox.color.fromHsv(hsv.h, s2, v2) |
| ]); // dojox.color.Palette |
| }, |
| |
| triadic: function(/* Object */args){ |
| var base = dojo.isString(args.base)?new dojox.color.Color(args.base):args.base, |
| hsv = base.toHsv(); |
| |
| var h1 = (hsv.h+57+360)%360, |
| h2 = (hsv.h-157+360)%360, |
| s1 = (hsv.s>20)?hsv.s-10:hsv.s+10, |
| s2 = (hsv.s>90)?hsv.s-10:hsv.s+10, |
| s3 = (hsv.s>95)?hsv.s-5:hsv.s+5, |
| v1 = (hsv.v-20>20)?hsv.v-20:hsv.v+20, |
| v2 = (hsv.v-30>20)?hsv.v-30:hsv.v+30, |
| v3 = (hsv.v-30>70)?hsv.v-30:hsv.v+30; |
| |
| return new dxc.Palette([ |
| dojox.color.fromHsv(h1, s1, hsv.v), |
| dojox.color.fromHsv(hsv.h, s2, v2), |
| base, |
| dojox.color.fromHsv(h2, s2, v1), |
| dojox.color.fromHsv(h2, s3, v3) |
| ]); // dojox.color.Palette |
| }, |
| |
| complementary: function(/* Object */args){ |
| var base = dojo.isString(args.base)?new dojox.color.Color(args.base):args.base, |
| hsv = base.toHsv(); |
| |
| var h1 = ((hsv.h*2)+137<360)?(hsv.h*2)+137:Math.floor(hsv.h/2)-137, |
| s1 = Math.max(hsv.s-10, 0), |
| s2 = rangeDiff(hsv.s, 10, 100), |
| s3 = Math.min(100, hsv.s+20), |
| v1 = Math.min(100, hsv.v+30), |
| v2 = (hsv.v>20)?hsv.v-30:hsv.v+30; |
| |
| return new dxc.Palette([ |
| dojox.color.fromHsv(hsv.h, s1, v1), |
| dojox.color.fromHsv(hsv.h, s2, v2), |
| base, |
| dojox.color.fromHsv(h1, s3, v2), |
| dojox.color.fromHsv(h1, hsv.s, hsv.v) |
| ]); // dojox.color.Palette |
| }, |
| |
| splitComplementary: function(/* Object */args){ |
| var base = dojo.isString(args.base)?new dojox.color.Color(args.base):args.base, |
| dangle = args.da || 30, |
| hsv = base.toHsv(); |
| |
| var baseh = ((hsv.h*2)+137<360)?(hsv.h*2)+137:Math.floor(hsv.h/2)-137, |
| h1 = (baseh-dangle+360)%360, |
| h2 = (baseh+dangle)%360, |
| s1 = Math.max(hsv.s-10, 0), |
| s2 = rangeDiff(hsv.s, 10, 100), |
| s3 = Math.min(100, hsv.s+20), |
| v1 = Math.min(100, hsv.v+30), |
| v2 = (hsv.v>20)?hsv.v-30:hsv.v+30; |
| |
| return new dxc.Palette([ |
| dojox.color.fromHsv(h1, s1, v1), |
| dojox.color.fromHsv(h1, s2, v2), |
| base, |
| dojox.color.fromHsv(h2, s3, v2), |
| dojox.color.fromHsv(h2, hsv.s, hsv.v) |
| ]); // dojox.color.Palette |
| }, |
| |
| compound: function(/* Object */args){ |
| var base = dojo.isString(args.base)?new dojox.color.Color(args.base):args.base, |
| hsv = base.toHsv(); |
| |
| var h1 = ((hsv.h*2)+18<360)?(hsv.h*2)+18:Math.floor(hsv.h/2)-18, |
| h2 = ((hsv.h*2)+120<360)?(hsv.h*2)+120:Math.floor(hsv.h/2)-120, |
| h3 = ((hsv.h*2)+99<360)?(hsv.h*2)+99:Math.floor(hsv.h/2)-99, |
| s1 = (hsv.s-40>10)?hsv.s-40:hsv.s+40, |
| s2 = (hsv.s-10>80)?hsv.s-10:hsv.s+10, |
| s3 = (hsv.s-25>10)?hsv.s-25:hsv.s+25, |
| v1 = (hsv.v-40>10)?hsv.v-40:hsv.v+40, |
| v2 = (hsv.v-20>80)?hsv.v-20:hsv.v+20, |
| v3 = Math.max(hsv.v, 20); |
| |
| return new dxc.Palette([ |
| dojox.color.fromHsv(h1, s1, v1), |
| dojox.color.fromHsv(h1, s2, v2), |
| base, |
| dojox.color.fromHsv(h2, s3, v3), |
| dojox.color.fromHsv(h3, s2, v2) |
| ]); // dojox.color.Palette |
| }, |
| |
| shades: function(/* Object */args){ |
| var base = dojo.isString(args.base)?new dojox.color.Color(args.base):args.base, |
| hsv = base.toHsv(); |
| |
| var s = (hsv.s==100 && hsv.v==0)?0:hsv.s, |
| v1 = (hsv.v-50>20)?hsv.v-50:hsv.v+30, |
| v2 = (hsv.v-25>=20)?hsv.v-25:hsv.v+55, |
| v3 = (hsv.v-75>=20)?hsv.v-75:hsv.v+5, |
| v4 = Math.max(hsv.v-10, 20); |
| |
| return new dxc.Palette([ |
| new dojox.color.fromHsv(hsv.h, s, v1), |
| new dojox.color.fromHsv(hsv.h, s, v2), |
| base, |
| new dojox.color.fromHsv(hsv.h, s, v3), |
| new dojox.color.fromHsv(hsv.h, s, v4) |
| ]); // dojox.color.Palette |
| } |
| }, |
| generate: function(/* String|dojox.color.Color */base, /* Function|String */type){ |
| // summary |
| // Generate a new Palette using any of the named functions in |
| // dojox.color.Palette.generators or an optional function definition. |
| if(dojo.isFunction(type)){ |
| return type({ base: base }); // dojox.color.Palette |
| } |
| else if(dxc.Palette.generators[type]){ |
| return dxc.Palette.generators[type]({ base: base }); // dojox.color.Palette |
| } |
| throw new Error("dojox.color.Palette.generate: the specified generator ('" + type + "') does not exist."); |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.Theme"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.Theme"] = true; |
| dojo.provide("dojox.charting.Theme"); |
| |
| |
| |
| (function(){ |
| var dxc=dojox.charting; |
| // TODO: Legend information |
| |
| dxc.Theme = function(/*Object?*/ kwArgs){ |
| kwArgs=kwArgs||{}; |
| var def = dxc.Theme._def; |
| dojo.forEach(["chart", "plotarea", "axis", "series", "marker"], function(n){ |
| this[n] = dojo.delegate(def[n], kwArgs[n]||{}); |
| }, this); |
| this.markers = dojo.delegate(dxc.Theme.Markers, kwArgs.markers||{}); |
| this.colors = []; |
| this.antiAlias = ("antiAlias" in kwArgs)?kwArgs.antiAlias:true; |
| this.assignColors = ("assignColors" in kwArgs)?kwArgs.assignColors:true; |
| this.assignMarkers = ("assignMarkers" in kwArgs)?kwArgs.assignMarkers:true; |
| |
| // push the colors, use _def colors if none passed. |
| kwArgs.colors = kwArgs.colors||def.colors; |
| dojo.forEach(kwArgs.colors, function(item){ |
| this.colors.push(item); |
| }, this); |
| |
| // private variables for color and marker indexing |
| this._current = { color:0, marker: 0 }; |
| this._markers = []; |
| this._buildMarkerArray(); |
| }; |
| |
| // "static" fields |
| // default markers. |
| // A marker is defined by an SVG path segment; it should be defined as |
| // relative motion, and with the assumption that the path segment |
| // will be moved to the value point (i.e prepend Mx,y) |
| dxc.Theme.Markers={ |
| CIRCLE: "m-3,0 c0,-4 6,-4 6,0 m-6,0 c0,4 6,4 6,0", |
| SQUARE: "m-3,-3 l0,6 6,0 0,-6 z", |
| DIAMOND: "m0,-3 l3,3 -3,3 -3,-3 z", |
| CROSS: "m0,-3 l0,6 m-3,-3 l6,0", |
| X: "m-3,-3 l6,6 m0,-6 l-6,6", |
| TRIANGLE: "m-3,3 l3,-6 3,6 z", |
| TRIANGLE_INVERTED:"m-3,-3 l3,6 3,-6 z" |
| }; |
| dxc.Theme._def={ |
| // all objects are structs used directly in dojox.gfx |
| chart:{ |
| stroke:null, |
| fill: "white" |
| }, |
| plotarea:{ |
| stroke:null, |
| fill: "white" |
| }, |
| // TODO: label rotation on axis |
| axis:{ |
| stroke: { // the axis itself |
| color:"#333", |
| width:1 |
| }, |
| /* |
| line: { // in the future can be used for gridlines |
| color:"#ccc", |
| width:1, |
| style:"Dot", |
| cap:"round" |
| }, |
| */ |
| majorTick: { // major ticks on axis, and used for major gridlines |
| color:"#666", |
| width:1, |
| length:6, |
| position:"center" |
| }, |
| minorTick: { // minor ticks on axis, and used for minor gridlines |
| color:"#666", |
| width:0.8, |
| length:3, |
| position:"center" |
| }, |
| microTick: { // minor ticks on axis, and used for minor gridlines |
| color:"#666", |
| width:0.5, |
| length:1, |
| position:"center" |
| }, |
| font: "normal normal normal 7pt Tahoma", // labels on axis |
| fontColor:"#333" // color of labels |
| }, |
| series:{ |
| outline: {width: 0.1, color: "#ccc"}, // line or outline |
| stroke: {width: 1.5, color: "#333"}, // line or outline |
| fill: "#ccc", // fill, if appropriate |
| font: "normal normal normal 7pt Tahoma", // if there's a label |
| fontColor: "#000" // color of labels |
| }, |
| marker:{ // any markers on a series. |
| stroke: {width:1}, // stroke or outline |
| fill: "#333", // fill if needed |
| font: "normal normal normal 7pt Tahoma", // label |
| fontColor: "#000" |
| }, |
| colors:[ "#54544c","#858e94","#6e767a","#948585","#474747" ] |
| }; |
| |
| // prototype methods |
| dojo.extend(dxc.Theme, { |
| defineColors: function(obj){ |
| // summary: |
| // Generate a set of colors for the theme based on keyword |
| // arguments |
| var kwArgs=obj||{}; |
| |
| // note that we've changed the default number from 32 to 4 colors |
| // are cycled anyways. |
| var c=[], n=kwArgs.num||5; // the number of colors to generate |
| if(kwArgs.colors){ |
| // we have an array of colors predefined, so fix for the number of series. |
| var l=kwArgs.colors.length; |
| for(var i=0; i<n; i++){ |
| c.push(kwArgs.colors[i%l]); |
| } |
| this.colors=c; |
| }else if(kwArgs.hue){ |
| // single hue, generate a set based on brightness |
| var s=kwArgs.saturation||100; // saturation |
| var st=kwArgs.low||30; |
| var end=kwArgs.high||90; |
| // we'd like it to be a little on the darker side. |
| var l=(end+st)/2; |
| |
| // alternately, use "shades" |
| this.colors = dojox.color.Palette.generate( |
| dojox.color.fromHsv(kwArgs.hue, s, l), "monochromatic" |
| ).colors; |
| }else if(kwArgs.generator){ |
| // pass a base color and the name of a generator |
| this.colors=dojox.color.Palette.generate(kwArgs.base, kwArgs.generator).colors; |
| } |
| }, |
| |
| _buildMarkerArray: function(){ |
| this._markers = []; |
| for(var p in this.markers){ this._markers.push(this.markers[p]); } |
| // reset the position |
| this._current.marker=0; |
| }, |
| |
| _clone: function(){ |
| // summary: |
| // Return a clone of this theme, with the position vars reset to 0. |
| return new dxc.Theme({ |
| chart: this.chart, |
| plotarea: this.plotarea, |
| axis: this.axis, |
| series: this.series, |
| marker: this.marker, |
| antiAlias: this.antiAlias, |
| assignColors: this.assignColors, |
| assignMarkers: this.assigneMarkers, |
| colors: dojo.delegate(this.colors) |
| }); |
| }, |
| |
| addMarker:function(/*String*/ name, /*String*/ segment){ |
| // summary: |
| // Add a custom marker to this theme. |
| // example: |
| // | myTheme.addMarker("Ellipse", foo); |
| this.markers[name]=segment; |
| this._buildMarkerArray(); |
| }, |
| setMarkers:function(/*Object*/ obj){ |
| // summary: |
| // Set all the markers of this theme at once. obj should be a |
| // dictionary of keys and path segments. |
| // |
| // example: |
| // | myTheme.setMarkers({ "CIRCLE": foo }); |
| this.markers=obj; |
| this._buildMarkerArray(); |
| }, |
| |
| next: function(/*String?*/ type){ |
| // summary: |
| // get either the next color or the next marker, depending on |
| // what was passed. If type is not passed, it assumes color. |
| // type: |
| // Optional. One of either "color" or "marker". Defaults to |
| // "color". |
| // example: |
| // | var color = myTheme.next(); |
| // | var color = myTheme.next("color"); |
| // | var marker = myTheme.next("marker"); |
| if(type == "marker"){ |
| return this._markers[ this._current.marker++ % this._markers.length ]; |
| }else{ |
| return this.colors[ this._current.color++ % this.colors.length ]; |
| } |
| }, |
| clear: function(){ |
| // summary: |
| // resets both marker and color counters back to the start. |
| // Subsequent calls to `next` will retrievie the first value |
| // of each depending on the passed type. |
| this._current = {color: 0, marker: 0}; |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.Element"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.Element"] = true; |
| dojo.provide("dojox.charting.Element"); |
| |
| dojo.declare("dojox.charting.Element", null, { |
| constructor: function(chart){ |
| this.chart = chart; |
| this.group = null; |
| this.htmlElements = []; |
| this.dirty = true; |
| }, |
| createGroup: function(creator){ |
| if(!creator){ creator = this.chart.surface; } |
| if(!this.group){ |
| this.group = creator.createGroup(); |
| } |
| return this; |
| }, |
| purgeGroup: function(){ |
| this.destroyHtmlElements(); |
| if(this.group){ |
| this.group.clear(); |
| this.group.removeShape(); |
| this.group = null; |
| } |
| this.dirty = true; |
| return this; |
| }, |
| cleanGroup: function(creator){ |
| this.destroyHtmlElements(); |
| if(!creator){ creator = this.chart.surface; } |
| if(this.group){ |
| this.group.clear(); |
| }else{ |
| this.group = creator.createGroup(); |
| } |
| this.dirty = true; |
| return this; |
| }, |
| destroyHtmlElements: function(){ |
| if(this.htmlElements.length){ |
| dojo.forEach(this.htmlElements, dojo.destroy); |
| this.htmlElements = []; |
| } |
| }, |
| destroy: function(){ |
| this.purgeGroup(); |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.Series"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.Series"] = true; |
| dojo.provide("dojox.charting.Series"); |
| |
| |
| |
| dojo.declare("dojox.charting.Series", dojox.charting.Element, { |
| constructor: function(chart, data, kwArgs){ |
| dojo.mixin(this, kwArgs); |
| if(typeof this.plot != "string"){ this.plot = "default"; } |
| this.data = data; |
| this.dirty = true; |
| this.clear(); |
| }, |
| clear: function(){ |
| this.dyn = {}; |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.scaler.common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.scaler.common"] = true; |
| dojo.provide("dojox.charting.scaler.common"); |
| |
| (function(){ |
| var eq = function(/*Number*/ a, /*Number*/ b){ |
| // summary: compare two FP numbers for equality |
| return Math.abs(a - b) <= 1e-6 * (Math.abs(a) + Math.abs(b)); // Boolean |
| }; |
| |
| dojo.mixin(dojox.charting.scaler.common, { |
| findString: function(/*String*/ val, /*Array*/ text){ |
| val = val.toLowerCase(); |
| for(var i = 0; i < text.length; ++i){ |
| if(val == text[i]){ return true; } |
| } |
| return false; |
| }, |
| getNumericLabel: function(/*Number*/ number, /*Number*/ precision, /*Object*/ kwArgs){ |
| var def = kwArgs.fixed ? |
| number.toFixed(precision < 0 ? -precision : 0) : |
| number.toString(); |
| if(kwArgs.labelFunc){ |
| var r = kwArgs.labelFunc(def, number, precision); |
| if(r){ return r; } |
| // else fall through to the regular labels search |
| } |
| if(kwArgs.labels){ |
| // classic binary search |
| var l = kwArgs.labels, lo = 0, hi = l.length; |
| while(lo < hi){ |
| var mid = Math.floor((lo + hi) / 2), val = l[mid].value; |
| if(val < number){ |
| lo = mid + 1; |
| }else{ |
| hi = mid; |
| } |
| } |
| // lets take into account FP errors |
| if(lo < l.length && eq(l[lo].value, number)){ |
| return l[lo].text; |
| } |
| --lo; |
| if(lo >= 0 && lo < l.length && eq(l[lo].value, number)){ |
| return l[lo].text; |
| } |
| lo += 2; |
| if(lo < l.length && eq(l[lo].value, number)){ |
| return l[lo].text; |
| } |
| // otherwise we will produce a number |
| } |
| return def; |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.scaler.linear"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.scaler.linear"] = true; |
| dojo.provide("dojox.charting.scaler.linear"); |
| |
| |
| (function(){ |
| var deltaLimit = 3, // pixels |
| dc = dojox.charting, dcs = dc.scaler, dcsc = dcs.common, |
| findString = dcsc.findString, |
| getLabel = dcsc.getNumericLabel; |
| |
| var calcTicks = function(min, max, kwArgs, majorTick, minorTick, microTick, span){ |
| kwArgs = dojo.delegate(kwArgs); |
| if(!majorTick){ |
| if(kwArgs.fixUpper == "major"){ kwArgs.fixUpper = "minor"; } |
| if(kwArgs.fixLower == "major"){ kwArgs.fixLower = "minor"; } |
| } |
| if(!minorTick){ |
| if(kwArgs.fixUpper == "minor"){ kwArgs.fixUpper = "micro"; } |
| if(kwArgs.fixLower == "minor"){ kwArgs.fixLower = "micro"; } |
| } |
| if(!microTick){ |
| if(kwArgs.fixUpper == "micro"){ kwArgs.fixUpper = "none"; } |
| if(kwArgs.fixLower == "micro"){ kwArgs.fixLower = "none"; } |
| } |
| var lowerBound = findString(kwArgs.fixLower, ["major"]) ? |
| Math.floor(kwArgs.min / majorTick) * majorTick : |
| findString(kwArgs.fixLower, ["minor"]) ? |
| Math.floor(kwArgs.min / minorTick) * minorTick : |
| findString(kwArgs.fixLower, ["micro"]) ? |
| Math.floor(kwArgs.min / microTick) * microTick : kwArgs.min, |
| upperBound = findString(kwArgs.fixUpper, ["major"]) ? |
| Math.ceil(kwArgs.max / majorTick) * majorTick : |
| findString(kwArgs.fixUpper, ["minor"]) ? |
| Math.ceil(kwArgs.max / minorTick) * minorTick : |
| findString(kwArgs.fixUpper, ["micro"]) ? |
| Math.ceil(kwArgs.max / microTick) * microTick : kwArgs.max; |
| |
| if(kwArgs.useMin){ min = lowerBound; } |
| if(kwArgs.useMax){ max = upperBound; } |
| |
| var majorStart = (!majorTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major"])) ? |
| min : Math.ceil(min / majorTick) * majorTick, |
| minorStart = (!minorTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major", "minor"])) ? |
| min : Math.ceil(min / minorTick) * minorTick, |
| microStart = (! microTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major", "minor", "micro"])) ? |
| min : Math.ceil(min / microTick) * microTick, |
| majorCount = !majorTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major"]) ? |
| Math.round((max - majorStart) / majorTick) : |
| Math.floor((max - majorStart) / majorTick)) + 1, |
| minorCount = !minorTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major", "minor"]) ? |
| Math.round((max - minorStart) / minorTick) : |
| Math.floor((max - minorStart) / minorTick)) + 1, |
| microCount = !microTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major", "minor", "micro"]) ? |
| Math.round((max - microStart) / microTick) : |
| Math.floor((max - microStart) / microTick)) + 1, |
| minorPerMajor = minorTick ? Math.round(majorTick / minorTick) : 0, |
| microPerMinor = microTick ? Math.round(minorTick / microTick) : 0, |
| majorPrecision = majorTick ? Math.floor(Math.log(majorTick) / Math.LN10) : 0, |
| minorPrecision = minorTick ? Math.floor(Math.log(minorTick) / Math.LN10) : 0, |
| scale = span / (max - min); |
| if(!isFinite(scale)){ scale = 1; } |
| |
| return { |
| bounds: { |
| lower: lowerBound, |
| upper: upperBound, |
| from: min, |
| to: max, |
| scale: scale, |
| span: span |
| }, |
| major: { |
| tick: majorTick, |
| start: majorStart, |
| count: majorCount, |
| prec: majorPrecision |
| }, |
| minor: { |
| tick: minorTick, |
| start: minorStart, |
| count: minorCount, |
| prec: minorPrecision |
| }, |
| micro: { |
| tick: microTick, |
| start: microStart, |
| count: microCount, |
| prec: 0 |
| }, |
| minorPerMajor: minorPerMajor, |
| microPerMinor: microPerMinor, |
| scaler: dcs.linear |
| }; |
| }; |
| |
| dojo.mixin(dojox.charting.scaler.linear, { |
| buildScaler: function(/*Number*/ min, /*Number*/ max, /*Number*/ span, /*Object*/ kwArgs){ |
| var h = {fixUpper: "none", fixLower: "none", natural: false}; |
| if(kwArgs){ |
| if("fixUpper" in kwArgs){ h.fixUpper = String(kwArgs.fixUpper); } |
| if("fixLower" in kwArgs){ h.fixLower = String(kwArgs.fixLower); } |
| if("natural" in kwArgs){ h.natural = Boolean(kwArgs.natural); } |
| } |
| |
| // update bounds |
| if("min" in kwArgs){ min = kwArgs.min; } |
| if("max" in kwArgs){ max = kwArgs.max; } |
| if(kwArgs.includeZero){ |
| if(min > 0){ min = 0; } |
| if(max < 0){ max = 0; } |
| } |
| h.min = min; |
| h.useMin = true; |
| h.max = max; |
| h.useMax = true; |
| |
| if("from" in kwArgs){ |
| min = kwArgs.from; |
| h.useMin = false; |
| } |
| if("to" in kwArgs){ |
| max = kwArgs.to; |
| h.useMax = false; |
| } |
| |
| // check for erroneous condition |
| if(max <= min){ |
| return calcTicks(min, max, h, 0, 0, 0, span); // Object |
| } |
| |
| var mag = Math.floor(Math.log(max - min) / Math.LN10), |
| major = kwArgs && ("majorTickStep" in kwArgs) ? kwArgs.majorTickStep : Math.pow(10, mag), |
| minor = 0, micro = 0, ticks; |
| |
| // calculate minor ticks |
| if(kwArgs && ("minorTickStep" in kwArgs)){ |
| minor = kwArgs.minorTickStep; |
| }else{ |
| do{ |
| minor = major / 10; |
| if(!h.natural || minor > 0.9){ |
| ticks = calcTicks(min, max, h, major, minor, 0, span); |
| if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; } |
| } |
| minor = major / 5; |
| if(!h.natural || minor > 0.9){ |
| ticks = calcTicks(min, max, h, major, minor, 0, span); |
| if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; } |
| } |
| minor = major / 2; |
| if(!h.natural || minor > 0.9){ |
| ticks = calcTicks(min, max, h, major, minor, 0, span); |
| if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; } |
| } |
| return calcTicks(min, max, h, major, 0, 0, span); // Object |
| }while(false); |
| } |
| |
| // calculate micro ticks |
| if(kwArgs && ("microTickStep" in kwArgs)){ |
| micro = kwArgs.microTickStep; |
| ticks = calcTicks(min, max, h, major, minor, micro, span); |
| }else{ |
| do{ |
| micro = minor / 10; |
| if(!h.natural || micro > 0.9){ |
| ticks = calcTicks(min, max, h, major, minor, micro, span); |
| if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; } |
| } |
| micro = minor / 5; |
| if(!h.natural || micro > 0.9){ |
| ticks = calcTicks(min, max, h, major, minor, micro, span); |
| if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; } |
| } |
| micro = minor / 2; |
| if(!h.natural || micro > 0.9){ |
| ticks = calcTicks(min, max, h, major, minor, micro, span); |
| if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; } |
| } |
| micro = 0; |
| }while(false); |
| } |
| |
| return micro ? ticks : calcTicks(min, max, h, major, minor, 0, span); // Object |
| }, |
| buildTicks: function(/*Object*/ scaler, /*Object*/ kwArgs){ |
| var step, next, tick, |
| nextMajor = scaler.major.start, |
| nextMinor = scaler.minor.start, |
| nextMicro = scaler.micro.start; |
| if(kwArgs.microTicks && scaler.micro.tick){ |
| step = scaler.micro.tick, next = nextMicro; |
| }else if(kwArgs.minorTicks && scaler.minor.tick){ |
| step = scaler.minor.tick, next = nextMinor; |
| }else if(scaler.major.tick){ |
| step = scaler.major.tick, next = nextMajor; |
| }else{ |
| // no ticks |
| return null; |
| } |
| // make sure that we have finite bounds |
| var revScale = 1 / scaler.bounds.scale; |
| if(scaler.bounds.to <= scaler.bounds.from || isNaN(revScale) || !isFinite(revScale) || |
| step <= 0 || isNaN(step) || !isFinite(step)){ |
| // no ticks |
| return null; |
| } |
| // loop over all ticks |
| var majorTicks = [], minorTicks = [], microTicks = []; |
| while(next <= scaler.bounds.to + revScale){ |
| if(Math.abs(nextMajor - next) < step / 2){ |
| // major tick |
| tick = {value: nextMajor}; |
| if(kwArgs.majorLabels){ |
| tick.label = getLabel(nextMajor, scaler.major.prec, kwArgs); |
| } |
| majorTicks.push(tick); |
| nextMajor += scaler.major.tick; |
| nextMinor += scaler.minor.tick; |
| nextMicro += scaler.micro.tick; |
| }else if(Math.abs(nextMinor - next) < step / 2){ |
| // minor tick |
| if(kwArgs.minorTicks){ |
| tick = {value: nextMinor}; |
| if(kwArgs.minorLabels && (scaler.minMinorStep <= scaler.minor.tick * scaler.bounds.scale)){ |
| tick.label = getLabel(nextMinor, scaler.minor.prec, kwArgs); |
| } |
| minorTicks.push(tick); |
| } |
| nextMinor += scaler.minor.tick; |
| nextMicro += scaler.micro.tick; |
| }else{ |
| // micro tick |
| if(kwArgs.microTicks){ |
| microTicks.push({value: nextMicro}); |
| } |
| nextMicro += scaler.micro.tick; |
| } |
| next += step; |
| } |
| return {major: majorTicks, minor: minorTicks, micro: microTicks}; // Object |
| }, |
| getTransformerFromModel: function(/*Object*/ scaler){ |
| var offset = scaler.bounds.from, scale = scaler.bounds.scale; |
| return function(x){ return (x - offset) * scale; }; // Function |
| }, |
| getTransformerFromPlot: function(/*Object*/ scaler){ |
| var offset = scaler.bounds.from, scale = scaler.bounds.scale; |
| return function(x){ return x / scale + offset; }; // Function |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.axis2d.common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.axis2d.common"] = true; |
| dojo.provide("dojox.charting.axis2d.common"); |
| |
| |
| |
| (function(){ |
| var g = dojox.gfx; |
| |
| var clearNode = function(s){ |
| s.marginLeft = "0px"; |
| s.marginTop = "0px"; |
| s.marginRight = "0px"; |
| s.marginBottom = "0px"; |
| s.paddingLeft = "0px"; |
| s.paddingTop = "0px"; |
| s.paddingRight = "0px"; |
| s.paddingBottom = "0px"; |
| s.borderLeftWidth = "0px"; |
| s.borderTopWidth = "0px"; |
| s.borderRightWidth = "0px"; |
| s.borderBottomWidth = "0px"; |
| }; |
| |
| var getBoxWidth = function(n){ |
| // marginBox is incredibly slow, so avoid it if we can |
| if(n["getBoundingClientRect"]){ |
| var bcr = n.getBoundingClientRect(); |
| return bcr.width || (bcr.right - bcr.left); |
| }else{ |
| return dojo.marginBox(n).w; |
| } |
| }; |
| |
| dojo.mixin(dojox.charting.axis2d.common, { |
| createText: { |
| gfx: function(chart, creator, x, y, align, text, font, fontColor){ |
| return creator.createText({ |
| x: x, y: y, text: text, align: align |
| }).setFont(font).setFill(fontColor); |
| }, |
| html: function(chart, creator, x, y, align, text, font, fontColor, labelWidth){ |
| // setup the text node |
| var p = dojo.doc.createElement("div"), s = p.style, boxWidth; |
| clearNode(s); |
| s.font = font; |
| p.innerHTML = String(text).replace(/\s/g, " "); |
| s.color = fontColor; |
| // measure the size |
| s.position = "absolute"; |
| s.left = "-10000px"; |
| dojo.body().appendChild(p); |
| var size = g.normalizedLength(g.splitFontString(font).size); |
| |
| // do we need to calculate the label width? |
| if(!labelWidth){ |
| boxWidth = getBoxWidth(p); |
| } |
| |
| // new settings for the text node |
| dojo.body().removeChild(p); |
| |
| s.position = "relative"; |
| if(labelWidth){ |
| s.width = labelWidth + "px"; |
| // s.border = "1px dotted grey"; |
| switch(align){ |
| case "middle": |
| s.textAlign = "center"; |
| s.left = (x - labelWidth / 2) + "px"; |
| break; |
| case "end": |
| s.textAlign = "right"; |
| s.left = (x - labelWidth) + "px"; |
| break; |
| default: |
| s.left = x + "px"; |
| s.textAlign = "left"; |
| break; |
| } |
| }else{ |
| switch(align){ |
| case "middle": |
| s.left = Math.floor(x - boxWidth / 2) + "px"; |
| // s.left = Math.floor(x - p.offsetWidth / 2) + "px"; |
| break; |
| case "end": |
| s.left = Math.floor(x - boxWidth) + "px"; |
| // s.left = Math.floor(x - p.offsetWidth) + "px"; |
| break; |
| //case "start": |
| default: |
| s.left = Math.floor(x) + "px"; |
| break; |
| } |
| } |
| s.top = Math.floor(y - size) + "px"; |
| // setup the wrapper node |
| var wrap = dojo.doc.createElement("div"), w = wrap.style; |
| clearNode(w); |
| w.width = "0px"; |
| w.height = "0px"; |
| // insert nodes |
| wrap.appendChild(p) |
| chart.node.insertBefore(wrap, chart.node.firstChild); |
| return wrap; |
| } |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.axis2d.Base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.axis2d.Base"] = true; |
| dojo.provide("dojox.charting.axis2d.Base"); |
| |
| |
| |
| dojo.declare("dojox.charting.axis2d.Base", dojox.charting.Element, { |
| constructor: function(chart, kwArgs){ |
| this.vertical = kwArgs && kwArgs.vertical; |
| }, |
| clear: function(){ |
| return this; |
| }, |
| initialized: function(){ |
| return false; |
| }, |
| calculate: function(min, max, span){ |
| return this; |
| }, |
| getScaler: function(){ |
| return null; |
| }, |
| getTicks: function(){ |
| return null; |
| }, |
| getOffsets: function(){ |
| return {l: 0, r: 0, t: 0, b: 0}; |
| }, |
| render: function(dim, offsets){ |
| return this; |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojo.string"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo.string"] = true; |
| dojo.provide("dojo.string"); |
| |
| /*===== |
| dojo.string = { |
| // summary: String utilities for Dojo |
| }; |
| =====*/ |
| |
| dojo.string.rep = function(/*String*/str, /*Integer*/num){ |
| // summary: |
| // Efficiently replicate a string `n` times. |
| // str: |
| // the string to replicate |
| // num: |
| // number of times to replicate the string |
| |
| if(num <= 0 || !str){ return ""; } |
| |
| var buf = []; |
| for(;;){ |
| if(num & 1){ |
| buf.push(str); |
| } |
| if(!(num >>= 1)){ break; } |
| str += str; |
| } |
| return buf.join(""); // String |
| }; |
| |
| dojo.string.pad = function(/*String*/text, /*Integer*/size, /*String?*/ch, /*Boolean?*/end){ |
| // summary: |
| // Pad a string to guarantee that it is at least `size` length by |
| // filling with the character `ch` at either the start or end of the |
| // string. Pads at the start, by default. |
| // text: |
| // the string to pad |
| // size: |
| // length to provide padding |
| // ch: |
| // character to pad, defaults to '0' |
| // end: |
| // adds padding at the end if true, otherwise pads at start |
| // example: |
| // | // Fill the string to length 10 with "+" characters on the right. Yields "Dojo++++++". |
| // | dojo.string.pad("Dojo", 10, "+", true); |
| |
| if(!ch){ |
| ch = '0'; |
| } |
| var out = String(text), |
| pad = dojo.string.rep(ch, Math.ceil((size - out.length) / ch.length)); |
| return end ? out + pad : pad + out; // String |
| }; |
| |
| dojo.string.substitute = function( /*String*/ template, |
| /*Object|Array*/map, |
| /*Function?*/ transform, |
| /*Object?*/ thisObject){ |
| // summary: |
| // Performs parameterized substitutions on a string. Throws an |
| // exception if any parameter is unmatched. |
| // template: |
| // a string with expressions in the form `${key}` to be replaced or |
| // `${key:format}` which specifies a format function. keys are case-sensitive. |
| // map: |
| // hash to search for substitutions |
| // transform: |
| // a function to process all parameters before substitution takes |
| // place, e.g. mylib.encodeXML |
| // thisObject: |
| // where to look for optional format function; default to the global |
| // namespace |
| // example: |
| // Substitutes two expressions in a string from an Array or Object |
| // | // returns "File 'foo.html' is not found in directory '/temp'." |
| // | // by providing substitution data in an Array |
| // | dojo.string.substitute( |
| // | "File '${0}' is not found in directory '${1}'.", |
| // | ["foo.html","/temp"] |
| // | ); |
| // | |
| // | // also returns "File 'foo.html' is not found in directory '/temp'." |
| // | // but provides substitution data in an Object structure. Dotted |
| // | // notation may be used to traverse the structure. |
| // | dojo.string.substitute( |
| // | "File '${name}' is not found in directory '${info.dir}'.", |
| // | { name: "foo.html", info: { dir: "/temp" } } |
| // | ); |
| // example: |
| // Use a transform function to modify the values: |
| // | // returns "file 'foo.html' is not found in directory '/temp'." |
| // | dojo.string.substitute( |
| // | "${0} is not found in ${1}.", |
| // | ["foo.html","/temp"], |
| // | function(str){ |
| // | // try to figure out the type |
| // | var prefix = (str.charAt(0) == "/") ? "directory": "file"; |
| // | return prefix + " '" + str + "'"; |
| // | } |
| // | ); |
| // example: |
| // Use a formatter |
| // | // returns "thinger -- howdy" |
| // | dojo.string.substitute( |
| // | "${0:postfix}", ["thinger"], null, { |
| // | postfix: function(value, key){ |
| // | return value + " -- howdy"; |
| // | } |
| // | } |
| // | ); |
| |
| thisObject = thisObject || dojo.global; |
| transform = transform ? |
| dojo.hitch(thisObject, transform) : function(v){ return v; }; |
| |
| return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g, |
| function(match, key, format){ |
| var value = dojo.getObject(key, false, map); |
| if(format){ |
| value = dojo.getObject(format, false, thisObject).call(thisObject, value, key); |
| } |
| return transform(value, key).toString(); |
| }); // String |
| }; |
| |
| /*===== |
| dojo.string.trim = function(str){ |
| // summary: |
| // Trims whitespace from both sides of the string |
| // str: String |
| // String to be trimmed |
| // returns: String |
| // Returns the trimmed string |
| // description: |
| // This version of trim() was taken from [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript). |
| // The short yet performant version of this function is dojo.trim(), |
| // which is part of Dojo base. Uses String.prototype.trim instead, if available. |
| return ""; // String |
| } |
| =====*/ |
| |
| dojo.string.trim = String.prototype.trim ? |
| dojo.trim : // aliasing to the native function |
| function(str){ |
| str = str.replace(/^\s+/, ''); |
| for(var i = str.length - 1; i >= 0; i--){ |
| if(/\S/.test(str.charAt(i))){ |
| str = str.substring(0, i + 1); |
| break; |
| } |
| } |
| return str; |
| }; |
| |
| } |
| |
| if(!dojo._hasResource["dojox.lang.utils"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.lang.utils"] = true; |
| dojo.provide("dojox.lang.utils"); |
| |
| (function(){ |
| var empty = {}, du = dojox.lang.utils; |
| |
| var clone = function(o){ |
| if(dojo.isArray(o)){ |
| return dojo._toArray(o); |
| } |
| if(!dojo.isObject(o) || dojo.isFunction(o)){ |
| return o; |
| } |
| return dojo.delegate(o); |
| } |
| |
| dojo.mixin(du, { |
| coerceType: function(target, source){ |
| switch(typeof target){ |
| case "number": return Number(eval("(" + source + ")")); |
| case "string": return String(source); |
| case "boolean": return Boolean(eval("(" + source + ")")); |
| } |
| return eval("(" + source + ")"); |
| }, |
| |
| updateWithObject: function(target, source, conv){ |
| // summary: updates an existing object in place with properties from an "source" object. |
| // target: Object: the "target" object to be updated |
| // source: Object: the "source" object, whose properties will be used to source the existed object. |
| // conv: Boolean?: force conversion to the original type |
| if(!source){ return target; } |
| for(var x in target){ |
| if(x in source && !(x in empty)){ |
| var t = target[x]; |
| if(t && typeof t == "object"){ |
| du.updateWithObject(t, source[x], conv); |
| }else{ |
| target[x] = conv ? du.coerceType(t, source[x]) : clone(source[x]); |
| } |
| } |
| } |
| return target; // Object |
| }, |
| |
| updateWithPattern: function(target, source, pattern, conv){ |
| // summary: updates an existing object in place with properties from an "source" object. |
| // target: Object: the "target" object to be updated |
| // source: Object: the "source" object, whose properties will be used to source the existed object. |
| // pattern: Array: an array of properties to be copied |
| // conv: Boolean?: force conversion to the original type |
| if(!source || !pattern){ return target; } |
| for(var x in pattern){ |
| if(x in source && !(x in empty)){ |
| target[x] = conv ? du.coerceType(pattern[x], source[x]) : clone(source[x]); |
| } |
| } |
| return target; // Object |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.axis2d.Default"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.axis2d.Default"] = true; |
| dojo.provide("dojox.charting.axis2d.Default"); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| (function(){ |
| var dc = dojox.charting, |
| df = dojox.lang.functional, |
| du = dojox.lang.utils, |
| g = dojox.gfx, |
| lin = dc.scaler.linear, |
| labelGap = 4; // in pixels |
| |
| dojo.declare("dojox.charting.axis2d.Default", dojox.charting.axis2d.Base, { |
| defaultParams: { |
| vertical: false, // true for vertical axis |
| fixUpper: "none", // align the upper on ticks: "major", "minor", "micro", "none" |
| fixLower: "none", // align the lower on ticks: "major", "minor", "micro", "none" |
| natural: false, // all tick marks should be made on natural numbers |
| leftBottom: true, // position of the axis, used with "vertical" |
| includeZero: false, // 0 should be included |
| fixed: true, // all labels are fixed numbers |
| majorLabels: true, // draw major labels |
| minorTicks: true, // draw minor ticks |
| minorLabels: true, // draw minor labels |
| microTicks: false, // draw micro ticks |
| htmlLabels: true // use HTML to draw labels |
| }, |
| optionalParams: { |
| min: 0, // minimal value on this axis |
| max: 1, // maximal value on this axis |
| from: 0, // visible from this value |
| to: 1, // visible to this value |
| majorTickStep: 4, // major tick step |
| minorTickStep: 2, // minor tick step |
| microTickStep: 1, // micro tick step |
| labels: [], // array of labels for major ticks |
| // with corresponding numeric values |
| // ordered by values |
| labelFunc: null, // function to compute label values |
| maxLabelSize: 0, // size in px. For use with labelFunc |
| |
| // TODO: add support for minRange! |
| // minRange: 1, // smallest distance from min allowed on the axis |
| |
| // theme components |
| stroke: {}, // stroke for an axis |
| majorTick: {}, // stroke + length for a tick |
| minorTick: {}, // stroke + length for a tick |
| microTick: {}, // stroke + length for a tick |
| font: "", // font for labels |
| fontColor: "" // color for labels as a string |
| }, |
| |
| constructor: function(chart, kwArgs){ |
| this.opt = dojo.delegate(this.defaultParams, kwArgs); |
| // du.updateWithObject(this.opt, kwArgs); |
| du.updateWithPattern(this.opt, kwArgs, this.optionalParams); |
| }, |
| dependOnData: function(){ |
| return !("min" in this.opt) || !("max" in this.opt); |
| }, |
| clear: function(){ |
| delete this.scaler; |
| delete this.ticks; |
| this.dirty = true; |
| return this; |
| }, |
| initialized: function(){ |
| return "scaler" in this && !(this.dirty && this.dependOnData()); |
| }, |
| setWindow: function(scale, offset){ |
| this.scale = scale; |
| this.offset = offset; |
| return this.clear(); |
| }, |
| getWindowScale: function(){ |
| return "scale" in this ? this.scale : 1; |
| }, |
| getWindowOffset: function(){ |
| return "offset" in this ? this.offset : 0; |
| }, |
| _groupLabelWidth: function(labels, font){ |
| if(labels[0]["text"]){ |
| labels = df.map(labels, function(label){ return label.text; }); |
| } |
| var s = labels.join("<br>"); |
| return dojox.gfx._base._getTextBox(s, {font: font}).w || 0; |
| }, |
| calculate: function(min, max, span, labels){ |
| if(this.initialized()){ |
| return this; |
| } |
| var o = this.opt; |
| this.labels = "labels" in o ? o.labels : labels; |
| this.scaler = lin.buildScaler(min, max, span, o); |
| var tsb = this.scaler.bounds; |
| if("scale" in this){ |
| // calculate new range |
| o.from = tsb.lower + this.offset; |
| o.to = (tsb.upper - tsb.lower) / this.scale + o.from; |
| // make sure that bounds are correct |
| if( !isFinite(o.from) || |
| isNaN(o.from) || |
| !isFinite(o.to) || |
| isNaN(o.to) || |
| o.to - o.from >= tsb.upper - tsb.lower |
| ){ |
| // any error --- remove from/to bounds |
| delete o.from; |
| delete o.to; |
| delete this.scale; |
| delete this.offset; |
| }else{ |
| // shift the window, if we are out of bounds |
| if(o.from < tsb.lower){ |
| o.to += tsb.lower - o.from; |
| o.from = tsb.lower; |
| }else if(o.to > tsb.upper){ |
| o.from += tsb.upper - o.to; |
| o.to = tsb.upper; |
| } |
| // update the offset |
| this.offset = o.from - tsb.lower; |
| } |
| // re-calculate the scaler |
| this.scaler = lin.buildScaler(min, max, span, o); |
| tsb = this.scaler.bounds; |
| // cleanup |
| if(this.scale == 1 && this.offset == 0){ |
| delete this.scale; |
| delete this.offset; |
| } |
| } |
| var minMinorStep = 0, ta = this.chart.theme.axis, |
| taFont = "font" in o ? o.font : ta.font, |
| size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0; |
| if(this.vertical){ |
| if(size){ |
| minMinorStep = size + labelGap; |
| } |
| }else{ |
| if(size){ |
| var labelWidth, i; |
| if(o.labelFunc && o.maxLabelSize){ |
| labelWidth = o.maxLabelSize; |
| }else if(this.labels){ |
| labelWidth = this._groupLabelWidth(this.labels, taFont); |
| }else{ |
| var labelLength = Math.ceil( |
| Math.log( |
| Math.max( |
| Math.abs(tsb.from), |
| Math.abs(tsb.to) |
| ) |
| ) / Math.LN10 |
| ), |
| t = []; |
| if(tsb.from < 0 || tsb.to < 0){ |
| t.push("-"); |
| } |
| t.push(dojo.string.rep("9", labelLength)); |
| var precision = Math.floor( |
| Math.log( tsb.to - tsb.from ) / Math.LN10 |
| ); |
| if(precision > 0){ |
| t.push("."); |
| for(i = 0; i < precision; ++i){ |
| t.push("9"); |
| } |
| } |
| labelWidth = dojox.gfx._base._getTextBox( |
| t.join(""), |
| { font: taFont } |
| ).w; |
| } |
| minMinorStep = labelWidth + labelGap; |
| } |
| } |
| this.scaler.minMinorStep = minMinorStep; |
| this.ticks = lin.buildTicks(this.scaler, o); |
| return this; |
| }, |
| getScaler: function(){ |
| return this.scaler; |
| }, |
| getTicks: function(){ |
| return this.ticks; |
| }, |
| getOffsets: function(){ |
| var o = this.opt; |
| var offsets = { l: 0, r: 0, t: 0, b: 0 }, |
| labelWidth, |
| a, |
| b, |
| c, |
| d, |
| gl = dc.scaler.common.getNumericLabel, |
| offset = 0, |
| ta = this.chart.theme.axis, |
| taFont = "font" in o ? o.font : ta.font, |
| taMajorTick = "majorTick" in o ? o.majorTick : ta.majorTick, |
| taMinorTick = "minorTick" in o ? o.minorTick : ta.minorTick, |
| size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0, |
| s = this.scaler; |
| if(!s){ |
| return offsets; |
| } |
| var ma = s.major, mi = s.minor; |
| if(this.vertical){ |
| if(size){ |
| if(o.labelFunc && o.maxLabelSize){ |
| labelWidth = o.maxLabelSize; |
| }else if(this.labels){ |
| labelWidth = this._groupLabelWidth( |
| this.labels, |
| taFont |
| ); |
| }else{ |
| labelWidth = this._groupLabelWidth([ |
| gl(ma.start, ma.prec, o), |
| gl(ma.start + ma.count * ma.tick, ma.prec, o), |
| gl(mi.start, mi.prec, o), |
| gl(mi.start + mi.count * mi.tick, mi.prec, o) |
| ], taFont); |
| } |
| offset = labelWidth + labelGap; |
| } |
| offset += labelGap + Math.max(taMajorTick.length, taMinorTick.length); |
| offsets[o.leftBottom ? "l" : "r"] = offset; |
| offsets.t = offsets.b = size / 2; |
| }else{ |
| if(size){ |
| offset = size + labelGap; |
| } |
| offset += labelGap + Math.max(taMajorTick.length, taMinorTick.length); |
| offsets[o.leftBottom ? "b" : "t"] = offset; |
| if(size){ |
| if(o.labelFunc && o.maxLabelSize){ |
| labelWidth = o.maxLabelSize; |
| }else if(this.labels){ |
| labelWidth = this._groupLabelWidth(this.labels, taFont); |
| }else{ |
| labelWidth = this._groupLabelWidth([ |
| gl(ma.start, ma.prec, o), |
| gl(ma.start + ma.count * ma.tick, ma.prec, o), |
| gl(mi.start, mi.prec, o), |
| gl(mi.start + mi.count * mi.tick, mi.prec, o) |
| ], taFont); |
| } |
| offsets.l = offsets.r = labelWidth / 2; |
| } |
| } |
| if(labelWidth){ |
| this._cachedLabelWidth = labelWidth; |
| } |
| return offsets; |
| }, |
| render: function(dim, offsets){ |
| if(!this.dirty){ |
| return this; |
| } |
| // prepare variable |
| var o = this.opt; |
| var start, |
| stop, |
| axisVector, |
| tickVector, |
| labelOffset, |
| labelAlign, |
| ta = this.chart.theme.axis, |
| taStroke = "stroke" in o ? o.stroke : ta.stroke, |
| taMajorTick = "majorTick" in o ? o.majorTick : ta.majorTick, |
| taMinorTick = "minorTick" in o ? o.minorTick : ta.minorTick, |
| taMicroTick = "microTick" in o ? o.microTick : ta.minorTick, |
| taFont = "font" in o ? o.font : ta.font, |
| taFontColor = "fontColor" in o ? o.fontColor : ta.fontColor, |
| tickSize = Math.max(taMajorTick.length, taMinorTick.length), |
| size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0; |
| if(this.vertical){ |
| start = { y: dim.height - offsets.b }; |
| stop = { y: offsets.t }; |
| axisVector = { x: 0, y: -1 }; |
| if(o.leftBottom){ |
| start.x = stop.x = offsets.l; |
| tickVector = { x: -1, y: 0 }; |
| labelAlign = "end"; |
| }else{ |
| start.x = stop.x = dim.width - offsets.r; |
| tickVector = { x: 1, y: 0 }; |
| labelAlign = "start"; |
| } |
| labelOffset = { |
| x: tickVector.x * (tickSize + labelGap), |
| y: size * 0.4 |
| }; |
| }else{ |
| start = { x: offsets.l }; |
| stop = { x: dim.width - offsets.r }; |
| axisVector = { x: 1, y: 0 }; |
| labelAlign = "middle"; |
| if(o.leftBottom){ |
| start.y = stop.y = dim.height - offsets.b; |
| tickVector = { x: 0, y: 1 }; |
| labelOffset = { y: tickSize + labelGap + size }; |
| }else{ |
| start.y = stop.y = offsets.t; |
| tickVector = { x: 0, y: -1 }; |
| labelOffset = { y: -tickSize - labelGap }; |
| } |
| labelOffset.x = 0; |
| } |
| |
| // render shapes |
| |
| this.cleanGroup(); |
| |
| try{ |
| var s = this.group, |
| c = this.scaler, |
| t = this.ticks, |
| canLabel, |
| f = lin.getTransformerFromModel(this.scaler), |
| forceHtmlLabels = (dojox.gfx.renderer == "canvas"), |
| labelType = forceHtmlLabels || this.opt.htmlLabels && !dojo.isIE && !dojo.isOpera ? "html" : "gfx", |
| dx = tickVector.x * taMajorTick.length, |
| dy = tickVector.y * taMajorTick.length; |
| |
| s.createLine({ |
| x1: start.x, |
| y1: start.y, |
| x2: stop.x, |
| y2: stop.y |
| }).setStroke(taStroke); |
| |
| dojo.forEach(t.major, function(tick){ |
| var offset = f(tick.value), elem, |
| x = start.x + axisVector.x * offset, |
| y = start.y + axisVector.y * offset; |
| s.createLine({ |
| x1: x, y1: y, |
| x2: x + dx, |
| y2: y + dy |
| }).setStroke(taMajorTick); |
| if(tick.label){ |
| elem = dc.axis2d.common.createText[labelType]( |
| this.chart, |
| s, |
| x + labelOffset.x, |
| y + labelOffset.y, |
| labelAlign, |
| tick.label, |
| taFont, |
| taFontColor, |
| this._cachedLabelWidth |
| ); |
| if(labelType == "html"){ |
| this.htmlElements.push(elem); |
| } |
| } |
| }, this); |
| |
| dx = tickVector.x * taMinorTick.length; |
| dy = tickVector.y * taMinorTick.length; |
| canLabel = c.minMinorStep <= c.minor.tick * c.bounds.scale; |
| dojo.forEach(t.minor, function(tick){ |
| var offset = f(tick.value), elem, |
| x = start.x + axisVector.x * offset, |
| y = start.y + axisVector.y * offset; |
| s.createLine({ |
| x1: x, y1: y, |
| x2: x + dx, |
| y2: y + dy |
| }).setStroke(taMinorTick); |
| if(canLabel && tick.label){ |
| elem = dc.axis2d.common.createText[labelType]( |
| this.chart, |
| s, |
| x + labelOffset.x, |
| y + labelOffset.y, |
| labelAlign, |
| tick.label, |
| taFont, |
| taFontColor, |
| this._cachedLabelWidth |
| ); |
| if(labelType == "html"){ |
| this.htmlElements.push(elem); |
| } |
| } |
| }, this); |
| |
| dx = tickVector.x * taMicroTick.length; |
| dy = tickVector.y * taMicroTick.length; |
| dojo.forEach(t.micro, function(tick){ |
| var offset = f(tick.value), elem, |
| x = start.x + axisVector.x * offset, |
| y = start.y + axisVector.y * offset; |
| s.createLine({ |
| x1: x, y1: y, |
| x2: x + dx, |
| y2: y + dy |
| }).setStroke(taMicroTick); |
| }, this); |
| }catch(e){ |
| // squelch |
| } |
| |
| this.dirty = false; |
| return this; |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.common"] = true; |
| dojo.provide("dojox.charting.plot2d.common"); |
| |
| |
| |
| |
| |
| (function(){ |
| var df = dojox.lang.functional, dc = dojox.charting.plot2d.common; |
| |
| dojo.mixin(dojox.charting.plot2d.common, { |
| makeStroke: function(stroke){ |
| if(!stroke){ return stroke; } |
| if(typeof stroke == "string" || stroke instanceof dojo.Color){ |
| stroke = {color: stroke}; |
| } |
| return dojox.gfx.makeParameters(dojox.gfx.defaultStroke, stroke); |
| }, |
| augmentColor: function(target, color){ |
| var t = new dojo.Color(target), |
| c = new dojo.Color(color); |
| c.a = t.a; |
| return c; |
| }, |
| augmentStroke: function(stroke, color){ |
| var s = dc.makeStroke(stroke); |
| if(s){ |
| s.color = dc.augmentColor(s.color, color); |
| } |
| return s; |
| }, |
| augmentFill: function(fill, color){ |
| var fc, c = new dojo.Color(color); |
| if(typeof fill == "string" || fill instanceof dojo.Color){ |
| return dc.augmentColor(fill, color); |
| } |
| return fill; |
| }, |
| |
| defaultStats: { |
| hmin: Number.POSITIVE_INFINITY, hmax: Number.NEGATIVE_INFINITY, |
| vmin: Number.POSITIVE_INFINITY, vmax: Number.NEGATIVE_INFINITY |
| }, |
| |
| collectSimpleStats: function(series){ |
| var stats = dojo.clone(dc.defaultStats); |
| for(var i = 0; i < series.length; ++i){ |
| var run = series[i]; |
| if(!run.data.length){ continue; } |
| if(typeof run.data[0] == "number"){ |
| // 1D case |
| var old_vmin = stats.vmin, old_vmax = stats.vmax; |
| if(!("ymin" in run) || !("ymax" in run)){ |
| dojo.forEach(run.data, function(val, i){ |
| var x = i + 1, y = val; |
| if(isNaN(y)){ y = 0; } |
| stats.hmin = Math.min(stats.hmin, x); |
| stats.hmax = Math.max(stats.hmax, x); |
| stats.vmin = Math.min(stats.vmin, y); |
| stats.vmax = Math.max(stats.vmax, y); |
| }); |
| } |
| if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); } |
| if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); } |
| }else{ |
| // 2D case |
| var old_hmin = stats.hmin, old_hmax = stats.hmax, |
| old_vmin = stats.vmin, old_vmax = stats.vmax; |
| if(!("xmin" in run) || !("xmax" in run) || !("ymin" in run) || !("ymax" in run)){ |
| dojo.forEach(run.data, function(val, i){ |
| var x = "x" in val ? val.x : i + 1, y = val.y; |
| if(isNaN(x)){ x = 0; } |
| if(isNaN(y)){ y = 0; } |
| stats.hmin = Math.min(stats.hmin, x); |
| stats.hmax = Math.max(stats.hmax, x); |
| stats.vmin = Math.min(stats.vmin, y); |
| stats.vmax = Math.max(stats.vmax, y); |
| }); |
| } |
| if("xmin" in run){ stats.hmin = Math.min(old_hmin, run.xmin); } |
| if("xmax" in run){ stats.hmax = Math.max(old_hmax, run.xmax); } |
| if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); } |
| if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); } |
| } |
| } |
| return stats; |
| }, |
| |
| calculateBarSize: function(/* Number */ availableSize, /* Object */ opt, /* Number? */ clusterSize){ |
| if(!clusterSize){ |
| clusterSize = 1; |
| } |
| var gap = opt.gap, size = (availableSize - 2 * gap) / clusterSize; |
| if("minBarSize" in opt){ |
| size = Math.max(size, opt.minBarSize); |
| } |
| if("maxBarSize" in opt){ |
| size = Math.min(size, opt.maxBarSize); |
| } |
| size = Math.max(size, 1); |
| gap = (availableSize - size * clusterSize) / 2; |
| return {size: size, gap: gap}; // Object |
| }, |
| |
| collectStackedStats: function(series){ |
| // collect statistics |
| var stats = dojo.clone(dc.defaultStats); |
| if(series.length){ |
| // 1st pass: find the maximal length of runs |
| stats.hmin = Math.min(stats.hmin, 1); |
| stats.hmax = df.foldl(series, "seed, run -> Math.max(seed, run.data.length)", stats.hmax); |
| // 2nd pass: stack values |
| for(var i = 0; i < stats.hmax; ++i){ |
| var v = series[0].data[i]; |
| if(isNaN(v)){ v = 0; } |
| stats.vmin = Math.min(stats.vmin, v); |
| for(var j = 1; j < series.length; ++j){ |
| var t = series[j].data[i]; |
| if(isNaN(t)){ t = 0; } |
| v += t; |
| } |
| stats.vmax = Math.max(stats.vmax, v); |
| } |
| } |
| return stats; |
| }, |
| |
| curve: function(/* Number[] */a, /* Number|String */tension){ |
| // FIX for #7235, submitted by Enzo Michelangeli. |
| // Emulates the smoothing algorithms used in a famous, unnamed spreadsheet |
| // program ;) |
| var arr = a.slice(0); |
| if(tension == "x") { |
| arr[arr.length] = arr[0]; // add a last element equal to the first, closing the loop |
| } |
| var p=dojo.map(arr, function(item, i){ |
| if(i==0){ return "M" + item.x + "," + item.y; } |
| if(!isNaN(tension)) { // use standard Dojo smoothing in tension is numeric |
| var dx=item.x-arr[i-1].x, dy=arr[i-1].y; |
| return "C"+(item.x-(tension-1)*(dx/tension))+","+dy+" "+(item.x-(dx/tension))+","+item.y+" "+item.x+","+item.y; |
| } else if(tension == "X" || tension == "x" || tension == "S") { |
| // use Excel "line smoothing" algorithm (http://xlrotor.com/resources/files.shtml) |
| var p0, p1 = arr[i-1], p2 = arr[i], p3; |
| var bz1x, bz1y, bz2x, bz2y; |
| var f = 1/6; |
| if(i==1) { |
| if(tension == "x") { |
| p0 = arr[arr.length-2]; |
| } else { // "tension == X || tension == "S" |
| p0 = p1; |
| } |
| f = 1/3; |
| } else { |
| p0 = arr[i-2]; |
| } |
| if(i==(arr.length-1)) { |
| if(tension == "x") { |
| p3 = arr[1]; |
| } else { // "tension == X || tension == "S" |
| p3 = p2; |
| } |
| f = 1/3; |
| } else { |
| p3 = arr[i+1]; |
| } |
| var p1p2 = Math.sqrt((p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y)); |
| var p0p2 = Math.sqrt((p2.x-p0.x)*(p2.x-p0.x)+(p2.y-p0.y)*(p2.y-p0.y)); |
| var p1p3 = Math.sqrt((p3.x-p1.x)*(p3.x-p1.x)+(p3.y-p1.y)*(p3.y-p1.y)); |
| |
| var p0p2f = p0p2 * f; |
| var p1p3f = p1p3 * f; |
| |
| if(p0p2f > p1p2/2 && p1p3f > p1p2/2) { |
| p0p2f = p1p2/2; |
| p1p3f = p1p2/2; |
| } else if(p0p2f > p1p2/2) { |
| p0p2f = p1p2/2; |
| p1p3f = p1p2/2 * p1p3/p0p2; |
| } else if(p1p3f > p1p2/2) { |
| p1p3f = p1p2/2; |
| p0p2f = p1p2/2 * p0p2/p1p3; |
| } |
| |
| if(tension == "S") { |
| if(p0 == p1) { p0p2f = 0; } |
| if(p2 == p3) { p1p3f = 0; } |
| } |
| |
| bz1x = p1.x + p0p2f*(p2.x - p0.x)/p0p2; |
| bz1y = p1.y + p0p2f*(p2.y - p0.y)/p0p2; |
| bz2x = p2.x - p1p3f*(p3.x - p1.x)/p1p3; |
| bz2y = p2.y - p1p3f*(p3.y - p1.y)/p1p3; |
| } |
| return "C"+(bz1x+","+bz1y+" "+bz2x+","+bz2y+" "+p2.x+","+p2.y); |
| }); |
| return p.join(" "); |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.scaler.primitive"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.scaler.primitive"] = true; |
| dojo.provide("dojox.charting.scaler.primitive"); |
| |
| dojox.charting.scaler.primitive = { |
| buildScaler: function(/*Number*/ min, /*Number*/ max, /*Number*/ span, /*Object*/ kwArgs){ |
| return { |
| bounds: { |
| lower: min, |
| upper: max, |
| from: min, |
| to: max, |
| scale: span / (max - min), |
| span: span |
| }, |
| scaler: dojox.charting.scaler.primitive |
| }; |
| }, |
| buildTicks: function(/*Object*/ scaler, /*Object*/ kwArgs){ |
| return {major: [], minor: [], micro: []}; // Object |
| }, |
| getTransformerFromModel: function(/*Object*/ scaler){ |
| var offset = scaler.bounds.from, scale = scaler.bounds.scale; |
| return function(x){ return (x - offset) * scale; }; // Function |
| }, |
| getTransformerFromPlot: function(/*Object*/ scaler){ |
| var offset = scaler.bounds.from, scale = scaler.bounds.scale; |
| return function(x){ return x / scale + offset; }; // Function |
| } |
| }; |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.Base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.Base"] = true; |
| dojo.provide("dojox.charting.plot2d.Base"); |
| |
| |
| |
| |
| |
| dojo.declare("dojox.charting.plot2d.Base", dojox.charting.Element, { |
| destroy: function(){ |
| this.resetEvents(); |
| this.inherited(arguments); |
| }, |
| clear: function(){ |
| this.series = []; |
| this._hAxis = null; |
| this._vAxis = null; |
| this.dirty = true; |
| return this; |
| }, |
| setAxis: function(axis){ |
| if(axis){ |
| this[axis.vertical ? "_vAxis" : "_hAxis"] = axis; |
| } |
| return this; |
| }, |
| addSeries: function(run){ |
| this.series.push(run); |
| return this; |
| }, |
| calculateAxes: function(dim){ |
| return this; |
| }, |
| isDirty: function(){ |
| return this.dirty || this._hAxis && this._hAxis.dirty || this._vAxis && this._vAxis.dirty; |
| }, |
| render: function(dim, offsets){ |
| return this; |
| }, |
| getRequiredColors: function(){ |
| return this.series.length; |
| }, |
| |
| // events |
| plotEvent: function(o){ |
| // intentionally empty --- used for events |
| }, |
| connect: function(object, method){ |
| this.dirty = true; |
| return dojo.connect(this, "plotEvent", object, method); |
| }, |
| events: function(){ |
| var ls = this.plotEvent._listeners; |
| if(!ls || !ls.length){ return false; } |
| for(var i in ls){ |
| if(!(i in Array.prototype)){ |
| return true; |
| } |
| } |
| return false; |
| }, |
| resetEvents: function(){ |
| this.plotEvent({type: "onplotreset", plot: this}); |
| }, |
| |
| // utilities |
| _calc: function(dim, stats){ |
| // calculate scaler |
| if(this._hAxis){ |
| if(!this._hAxis.initialized()){ |
| this._hAxis.calculate(stats.hmin, stats.hmax, dim.width); |
| } |
| this._hScaler = this._hAxis.getScaler(); |
| }else{ |
| this._hScaler = dojox.charting.scaler.primitive.buildScaler(stats.hmin, stats.hmax, dim.width); |
| } |
| if(this._vAxis){ |
| if(!this._vAxis.initialized()){ |
| this._vAxis.calculate(stats.vmin, stats.vmax, dim.height); |
| } |
| this._vScaler = this._vAxis.getScaler(); |
| }else{ |
| this._vScaler = dojox.charting.scaler.primitive.buildScaler(stats.vmin, stats.vmax, dim.height); |
| } |
| }, |
| |
| _connectEvents: function(shape, o){ |
| shape.connect("onmouseover", this, function(e){ |
| o.type = "onmouseover"; |
| o.event = e; |
| this.plotEvent(o); |
| }); |
| shape.connect("onmouseout", this, function(e){ |
| o.type = "onmouseout"; |
| o.event = e; |
| this.plotEvent(o); |
| }); |
| shape.connect("onclick", this, function(e){ |
| o.type = "onclick"; |
| o.event = e; |
| this.plotEvent(o); |
| }); |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.Default"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.Default"] = true; |
| dojo.provide("dojox.charting.plot2d.Default"); |
| |
| |
| |
| |
| |
| |
| |
| |
| (function(){ |
| var df = dojox.lang.functional, du = dojox.lang.utils, |
| dc = dojox.charting.plot2d.common, |
| purgeGroup = df.lambda("item.purgeGroup()"); |
| |
| dojo.declare("dojox.charting.plot2d.Default", dojox.charting.plot2d.Base, { |
| defaultParams: { |
| hAxis: "x", // use a horizontal axis named "x" |
| vAxis: "y", // use a vertical axis named "y" |
| lines: true, // draw lines |
| areas: false, // draw areas |
| markers: false, // draw markers |
| shadows: 0, // draw shadows |
| tension: 0 // draw curved lines (tension>0) |
| }, |
| optionalParams: {}, // no optional parameters |
| |
| constructor: function(chart, kwArgs){ |
| this.opt = dojo.clone(this.defaultParams); |
| du.updateWithObject(this.opt, kwArgs); |
| this.series = []; |
| this.hAxis = this.opt.hAxis; |
| this.vAxis = this.opt.vAxis; |
| }, |
| |
| calculateAxes: function(dim){ |
| this._calc(dim, dc.collectSimpleStats(this.series)); |
| return this; |
| }, |
| render: function(dim, offsets){ |
| this.dirty = this.isDirty(); |
| if(this.dirty){ |
| dojo.forEach(this.series, purgeGroup); |
| this.cleanGroup(); |
| var s = this.group; |
| df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); |
| } |
| var t = this.chart.theme, stroke, outline, color, marker, events = this.events(); |
| this.resetEvents(); |
| for(var i = this.series.length - 1; i >= 0; --i){ |
| var run = this.series[i]; |
| if(!this.dirty && !run.dirty){ continue; } |
| run.cleanGroup(); |
| if(!run.data.length){ |
| run.dirty = false; |
| continue; |
| } |
| |
| var s = run.group, lpoly, |
| ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), |
| vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler); |
| if(typeof run.data[0] == "number"){ |
| lpoly = dojo.map(run.data, function(v, i){ |
| return { |
| x: ht(i + 1) + offsets.l, |
| y: dim.height - offsets.b - vt(v) |
| }; |
| }, this); |
| }else{ |
| lpoly = dojo.map(run.data, function(v, i){ |
| return { |
| x: ht(v.x) + offsets.l, |
| y: dim.height - offsets.b - vt(v.y) |
| }; |
| }, this); |
| } |
| if(!run.fill || !run.stroke){ |
| // need autogenerated color |
| color = run.dyn.color = new dojo.Color(t.next("color")); |
| } |
| |
| var lpath = this.opt.tension ? dc.curve(lpoly, this.opt.tension) : ""; |
| |
| if(this.opt.areas){ |
| var fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); |
| var apoly = dojo.clone(lpoly); |
| if(this.opt.tension){ |
| var apath = "L" + apoly[apoly.length-1].x + "," + (dim.height - offsets.b) + |
| " L" + apoly[0].x + "," + (dim.height - offsets.b) + |
| " L" + apoly[0].x + "," + apoly[0].y; |
| run.dyn.fill = s.createPath(lpath + " " + apath).setFill(fill).getFill(); |
| } else { |
| apoly.push({x: lpoly[lpoly.length - 1].x, y: dim.height - offsets.b}); |
| apoly.push({x: lpoly[0].x, y: dim.height - offsets.b}); |
| apoly.push(lpoly[0]); |
| run.dyn.fill = s.createPolyline(apoly).setFill(fill).getFill(); |
| } |
| } |
| if(this.opt.lines || this.opt.markers){ |
| // need a stroke |
| stroke = run.dyn.stroke = run.stroke ? dc.makeStroke(run.stroke) : dc.augmentStroke(t.series.stroke, color); |
| if(run.outline || t.series.outline){ |
| outline = run.dyn.outline = dc.makeStroke(run.outline ? run.outline : t.series.outline); |
| outline.width = 2 * outline.width + stroke.width; |
| } |
| } |
| if(this.opt.markers){ |
| // need a marker |
| marker = run.dyn.marker = run.marker ? run.marker : t.next("marker"); |
| } |
| var frontMarkers = null, outlineMarkers = null, shadowMarkers = null; |
| if(this.opt.shadows && stroke){ |
| var sh = this.opt.shadows, shadowColor = new dojo.Color([0, 0, 0, 0.3]), |
| spoly = dojo.map(lpoly, function(c){ |
| return {x: c.x + sh.dx, y: c.y + sh.dy}; |
| }), |
| shadowStroke = dojo.clone(outline ? outline : stroke); |
| shadowStroke.color = shadowColor; |
| shadowStroke.width += sh.dw ? sh.dw : 0; |
| if(this.opt.lines){ |
| if(this.opt.tension){ |
| run.dyn.shadow = s.createPath(dc.curve(spoly, this.opt.tension)).setStroke(shadowStroke).getStroke(); |
| } else { |
| run.dyn.shadow = s.createPolyline(spoly).setStroke(shadowStroke).getStroke(); |
| } |
| } |
| if(this.opt.markers){ |
| shadowMarkers = dojo.map(spoly, function(c){ |
| return s.createPath("M" + c.x + " " + c.y + " " + marker). |
| setStroke(shadowStroke).setFill(shadowColor); |
| }, this); |
| } |
| } |
| if(this.opt.lines){ |
| if(outline){ |
| if(this.opt.tension){ |
| run.dyn.outline = s.createPath(lpath).setStroke(outline).getStroke(); |
| } else { |
| run.dyn.outline = s.createPolyline(lpoly).setStroke(outline).getStroke(); |
| } |
| } |
| if(this.opt.tension){ |
| run.dyn.stroke = s.createPath(lpath).setStroke(stroke).getStroke(); |
| } else { |
| run.dyn.stroke = s.createPolyline(lpoly).setStroke(stroke).getStroke(); |
| } |
| } |
| if(this.opt.markers){ |
| frontMarkers = new Array(lpoly.length); |
| outlineMarkers = new Array(lpoly.length); |
| dojo.forEach(lpoly, function(c, i){ |
| var path = "M" + c.x + " " + c.y + " " + marker; |
| if(outline){ |
| outlineMarkers[i] = s.createPath(path).setStroke(outline); |
| } |
| frontMarkers[i] = s.createPath(path).setStroke(stroke).setFill(stroke.color); |
| }, this); |
| if(events){ |
| dojo.forEach(frontMarkers, function(s, i){ |
| var o = { |
| element: "marker", |
| index: i, |
| run: run, |
| plot: this, |
| hAxis: this.hAxis || null, |
| vAxis: this.vAxis || null, |
| shape: s, |
| outline: outlineMarkers[i] || null, |
| shadow: shadowMarkers && shadowMarkers[i] || null, |
| cx: lpoly[i].x, |
| cy: lpoly[i].y |
| }; |
| if(typeof run.data[0] == "number"){ |
| o.x = i + 1; |
| o.y = run.data[i]; |
| }else{ |
| o.x = run.data[i].x; |
| o.y = run.data[i].y; |
| } |
| this._connectEvents(s, o); |
| }, this); |
| } |
| } |
| run.dirty = false; |
| } |
| this.dirty = false; |
| return this; |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.Lines"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.Lines"] = true; |
| dojo.provide("dojox.charting.plot2d.Lines"); |
| |
| |
| |
| dojo.declare("dojox.charting.plot2d.Lines", dojox.charting.plot2d.Default, { |
| constructor: function(){ |
| this.opt.lines = true; |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.Areas"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.Areas"] = true; |
| dojo.provide("dojox.charting.plot2d.Areas"); |
| |
| |
| |
| dojo.declare("dojox.charting.plot2d.Areas", dojox.charting.plot2d.Default, { |
| constructor: function(){ |
| this.opt.lines = true; |
| this.opt.areas = true; |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.Markers"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.Markers"] = true; |
| dojo.provide("dojox.charting.plot2d.Markers"); |
| |
| |
| |
| dojo.declare("dojox.charting.plot2d.Markers", dojox.charting.plot2d.Default, { |
| constructor: function(){ |
| this.opt.markers = true; |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.MarkersOnly"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.MarkersOnly"] = true; |
| dojo.provide("dojox.charting.plot2d.MarkersOnly"); |
| |
| |
| |
| dojo.declare("dojox.charting.plot2d.MarkersOnly", dojox.charting.plot2d.Default, { |
| constructor: function(){ |
| this.opt.lines = false; |
| this.opt.markers = true; |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.Scatter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.Scatter"] = true; |
| dojo.provide("dojox.charting.plot2d.Scatter"); |
| |
| |
| |
| dojo.declare("dojox.charting.plot2d.Scatter", dojox.charting.plot2d.Default, { |
| constructor: function(){ |
| this.opt.lines = false; |
| this.opt.markers = true; |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.lang.functional.sequence"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.lang.functional.sequence"] = true; |
| dojo.provide("dojox.lang.functional.sequence"); |
| |
| |
| |
| // This module adds high-level functions and related constructs: |
| // - sequence generators |
| |
| // If you want more general sequence builders check out listcomp.js and |
| // unfold() (in fold.js). |
| |
| // Defined methods: |
| // - take any valid lambda argument as the functional argument |
| |
| (function(){ |
| var d = dojo, df = dojox.lang.functional; |
| |
| d.mixin(df, { |
| // sequence generators |
| repeat: function(/*Number*/ n, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){ |
| // summary: builds an array by repeatedly applying a unary function N times |
| // with a seed value Z. N should be greater than 0. |
| o = o || d.global; f = df.lambda(f); |
| var t = new Array(n), i = 1; |
| t[0] = z; |
| for(; i < n; t[i] = z = f.call(o, z), ++i); |
| return t; // Array |
| }, |
| until: function(/*Function|String|Array*/ pr, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){ |
| // summary: builds an array by repeatedly applying a unary function with |
| // a seed value Z until the predicate is satisfied. |
| o = o || d.global; f = df.lambda(f); pr = df.lambda(pr); |
| var t = []; |
| for(; !pr.call(o, z); t.push(z), z = f.call(o, z)); |
| return t; // Array |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.Stacked"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.Stacked"] = true; |
| dojo.provide("dojox.charting.plot2d.Stacked"); |
| |
| |
| |
| |
| |
| |
| |
| |
| (function(){ |
| var df = dojox.lang.functional, dc = dojox.charting.plot2d.common, |
| purgeGroup = df.lambda("item.purgeGroup()"); |
| |
| dojo.declare("dojox.charting.plot2d.Stacked", dojox.charting.plot2d.Default, { |
| calculateAxes: function(dim){ |
| var stats = dc.collectStackedStats(this.series); |
| this._maxRunLength = stats.hmax; |
| this._calc(dim, stats); |
| return this; |
| }, |
| render: function(dim, offsets){ |
| if(this._maxRunLength <= 0){ |
| return this; |
| } |
| |
| // stack all values |
| var acc = df.repeat(this._maxRunLength, "-> 0", 0); |
| for(var i = 0; i < this.series.length; ++i){ |
| var run = this.series[i]; |
| for(var j = 0; j < run.data.length; ++j){ |
| var v = run.data[j]; |
| if(isNaN(v)){ v = 0; } |
| acc[j] += v; |
| } |
| } |
| // draw runs in backwards |
| this.dirty = this.isDirty(); |
| if(this.dirty){ |
| dojo.forEach(this.series, purgeGroup); |
| this.cleanGroup(); |
| var s = this.group; |
| df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); |
| } |
| |
| var t = this.chart.theme, stroke, outline, color, marker, events = this.events(), |
| ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), |
| vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler); |
| this.resetEvents(); |
| |
| for(var i = this.series.length - 1; i >= 0; --i){ |
| var run = this.series[i]; |
| if(!this.dirty && !run.dirty){ continue; } |
| run.cleanGroup(); |
| var s = run.group, |
| lpoly = dojo.map(acc, function(v, i){ |
| return { |
| x: ht(i + 1) + offsets.l, |
| y: dim.height - offsets.b - vt(v) |
| }; |
| }, this); |
| if(!run.fill || !run.stroke){ |
| // need autogenerated color |
| color = new dojo.Color(t.next("color")); |
| } |
| |
| var lpath = this.opt.tension ? dc.curve(lpoly, this.opt.tension) : ""; |
| |
| if(this.opt.areas){ |
| var apoly = dojo.clone(lpoly); |
| var fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); |
| if(this.opt.tension){ |
| var p=dc.curve(apoly, this.opt.tension); |
| p += " L" + lpoly[lpoly.length - 1].x + "," + (dim.height - offsets.b) + |
| " L" + lpoly[0].x + "," + (dim.height - offsets.b) + |
| " L" + lpoly[0].x + "," + lpoly[0].y; |
| run.dyn.fill = s.createPath(p).setFill(fill).getFill(); |
| } else { |
| apoly.push({x: lpoly[lpoly.length - 1].x, y: dim.height - offsets.b}); |
| apoly.push({x: lpoly[0].x, y: dim.height - offsets.b}); |
| apoly.push(lpoly[0]); |
| run.dyn.fill = s.createPolyline(apoly).setFill(fill).getFill(); |
| } |
| } |
| if(this.opt.lines || this.opt.markers){ |
| // need a stroke |
| stroke = run.stroke ? dc.makeStroke(run.stroke) : dc.augmentStroke(t.series.stroke, color); |
| if(run.outline || t.series.outline){ |
| outline = dc.makeStroke(run.outline ? run.outline : t.series.outline); |
| outline.width = 2 * outline.width + stroke.width; |
| } |
| } |
| if(this.opt.markers){ |
| // need a marker |
| marker = run.dyn.marker = run.marker ? run.marker : t.next("marker"); |
| } |
| var frontMarkers, outlineMarkers, shadowMarkers; |
| if(this.opt.shadows && stroke){ |
| var sh = this.opt.shadows, shadowColor = new dojo.Color([0, 0, 0, 0.3]), |
| spoly = dojo.map(lpoly, function(c){ |
| return {x: c.x + sh.dx, y: c.y + sh.dy}; |
| }), |
| shadowStroke = dojo.clone(outline ? outline : stroke); |
| shadowStroke.color = shadowColor; |
| shadowStroke.width += sh.dw ? sh.dw : 0; |
| if(this.opt.lines){ |
| if(this.opt.tension){ |
| run.dyn.shadow = s.createPath(dc.curve(spoly, this.opt.tension)).setStroke(shadowStroke).getStroke(); |
| } else { |
| run.dyn.shadow = s.createPolyline(spoly).setStroke(shadowStroke).getStroke(); |
| } |
| } |
| if(this.opt.markers){ |
| shadowMarkers = dojo.map(spoly, function(c){ |
| return s.createPath("M" + c.x + " " + c.y + " " + marker). |
| setStroke(shadowStroke).setFill(shadowColor); |
| }, this); |
| } |
| } |
| if(this.opt.lines){ |
| if(outline){ |
| if(this.opt.tension){ |
| run.dyn.outline = s.createPath(lpath).setStroke(outline).getStroke(); |
| } else { |
| run.dyn.outline = s.createPolyline(lpoly).setStroke(outline).getStroke(); |
| } |
| } |
| if(this.opt.tension){ |
| run.dyn.stroke = s.createPath(lpath).setStroke(stroke).getStroke(); |
| } else { |
| run.dyn.stroke = s.createPolyline(lpoly).setStroke(stroke).getStroke(); |
| } |
| } |
| if(this.opt.markers){ |
| frontMarkers = new Array(lpoly.length); |
| outlineMarkers = new Array(lpoly.length); |
| dojo.forEach(lpoly, function(c, i){ |
| var path = "M" + c.x + " " + c.y + " " + marker; |
| if(outline){ |
| outlineMarkers[i] = s.createPath(path).setStroke(outline); |
| } |
| frontMarkers[i] = s.createPath(path).setStroke(stroke).setFill(stroke.color); |
| }, this); |
| if(events){ |
| dojo.forEach(frontMarkers, function(s, i){ |
| var o = { |
| element: "marker", |
| index: i, |
| run: run, |
| plot: this, |
| hAxis: this.hAxis || null, |
| vAxis: this.vAxis || null, |
| shape: s, |
| outline: outlineMarkers[i] || null, |
| shadow: shadowMarkers && shadowMarkers[i] || null, |
| cx: lpoly[i].x, |
| cy: lpoly[i].y, |
| x: i + 1, |
| y: run.data[i] |
| }; |
| this._connectEvents(s, o); |
| }, this); |
| } |
| } |
| run.dirty = false; |
| // update the accumulator |
| for(var j = 0; j < run.data.length; ++j){ |
| var v = run.data[j]; |
| if(isNaN(v)){ v = 0; } |
| acc[j] -= v; |
| } |
| } |
| this.dirty = false; |
| return this; |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.StackedLines"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.StackedLines"] = true; |
| dojo.provide("dojox.charting.plot2d.StackedLines"); |
| |
| |
| |
| dojo.declare("dojox.charting.plot2d.StackedLines", dojox.charting.plot2d.Stacked, { |
| constructor: function(){ |
| this.opt.lines = true; |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.StackedAreas"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.StackedAreas"] = true; |
| dojo.provide("dojox.charting.plot2d.StackedAreas"); |
| |
| |
| |
| dojo.declare("dojox.charting.plot2d.StackedAreas", dojox.charting.plot2d.Stacked, { |
| constructor: function(){ |
| this.opt.lines = true; |
| this.opt.areas = true; |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.gfx.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.gfx.fx"] = true; |
| dojo.provide("dojox.gfx.fx"); |
| |
| |
| |
| (function(){ |
| var d = dojo, g = dojox.gfx, m = g.matrix; |
| |
| // Generic interpolators. Should they be moved to dojox.fx? |
| |
| var InterpolNumber = function(start, end){ |
| this.start = start, this.end = end; |
| }; |
| d.extend(InterpolNumber, { |
| getValue: function(r){ |
| return (this.end - this.start) * r + this.start; |
| } |
| }); |
| |
| var InterpolUnit = function(start, end, units){ |
| this.start = start, this.end = end; |
| this.units = units; |
| }; |
| d.extend(InterpolUnit, { |
| getValue: function(r){ |
| return (this.end - this.start) * r + this.start + this.units; |
| } |
| }); |
| |
| var InterpolColor = function(start, end){ |
| this.start = start, this.end = end; |
| this.temp = new dojo.Color(); |
| }; |
| d.extend(InterpolColor, { |
| getValue: function(r){ |
| return d.blendColors(this.start, this.end, r, this.temp); |
| } |
| }); |
| |
| var InterpolValues = function(values){ |
| this.values = values; |
| this.length = values.length; |
| }; |
| d.extend(InterpolValues, { |
| getValue: function(r){ |
| return this.values[Math.min(Math.floor(r * this.length), this.length - 1)]; |
| } |
| }); |
| |
| var InterpolObject = function(values, def){ |
| this.values = values; |
| this.def = def ? def : {}; |
| }; |
| d.extend(InterpolObject, { |
| getValue: function(r){ |
| var ret = dojo.clone(this.def); |
| for(var i in this.values){ |
| ret[i] = this.values[i].getValue(r); |
| } |
| return ret; |
| } |
| }); |
| |
| var InterpolTransform = function(stack, original){ |
| this.stack = stack; |
| this.original = original; |
| }; |
| d.extend(InterpolTransform, { |
| getValue: function(r){ |
| var ret = []; |
| dojo.forEach(this.stack, function(t){ |
| if(t instanceof m.Matrix2D){ |
| ret.push(t); |
| return; |
| } |
| if(t.name == "original" && this.original){ |
| ret.push(this.original); |
| return; |
| } |
| if(!(t.name in m)){ return; } |
| var f = m[t.name]; |
| if(typeof f != "function"){ |
| // constant |
| ret.push(f); |
| return; |
| } |
| var val = dojo.map(t.start, function(v, i){ |
| return (t.end[i] - v) * r + v; |
| }), |
| matrix = f.apply(m, val); |
| if(matrix instanceof m.Matrix2D){ |
| ret.push(matrix); |
| } |
| }, this); |
| return ret; |
| } |
| }); |
| |
| var transparent = new d.Color(0, 0, 0, 0); |
| |
| var getColorInterpol = function(prop, obj, name, def){ |
| if(prop.values){ |
| return new InterpolValues(prop.values); |
| } |
| var value, start, end; |
| if(prop.start){ |
| start = g.normalizeColor(prop.start); |
| }else{ |
| start = value = obj ? (name ? obj[name] : obj) : def; |
| } |
| if(prop.end){ |
| end = g.normalizeColor(prop.end); |
| }else{ |
| if(!value){ |
| value = obj ? (name ? obj[name] : obj) : def; |
| } |
| end = value; |
| } |
| return new InterpolColor(start, end); |
| }; |
| |
| var getNumberInterpol = function(prop, obj, name, def){ |
| if(prop.values){ |
| return new InterpolValues(prop.values); |
| } |
| var value, start, end; |
| if(prop.start){ |
| start = prop.start; |
| }else{ |
| start = value = obj ? obj[name] : def; |
| } |
| if(prop.end){ |
| end = prop.end; |
| }else{ |
| if(typeof value != "number"){ |
| value = obj ? obj[name] : def; |
| } |
| end = value; |
| } |
| return new InterpolNumber(start, end); |
| }; |
| |
| g.fx.animateStroke = function(/*Object*/ args){ |
| // summary: |
| // Returns an animation which will change stroke properties over time |
| // example: |
| // | dojox.gfx.fx.animateStroke{{ |
| // | shape: shape, |
| // | duration: 500, |
| // | color: {start: "red", end: "green"}, |
| // | width: {end: 15}, |
| // | join: {values: ["miter", "bevel", "round"]} |
| // | }).play(); |
| if(!args.easing){ args.easing = d._defaultEasing; } |
| var anim = new d.Animation(args), shape = args.shape, stroke; |
| d.connect(anim, "beforeBegin", anim, function(){ |
| stroke = shape.getStroke(); |
| var prop = args.color, values = {}, value, start, end; |
| if(prop){ |
| values.color = getColorInterpol(prop, stroke, "color", transparent); |
| } |
| prop = args.style; |
| if(prop && prop.values){ |
| values.style = new InterpolValues(prop.values); |
| } |
| prop = args.width; |
| if(prop){ |
| values.width = getNumberInterpol(prop, stroke, "width", 1); |
| } |
| prop = args.cap; |
| if(prop && prop.values){ |
| values.cap = new InterpolValues(prop.values); |
| } |
| prop = args.join; |
| if(prop){ |
| if(prop.values){ |
| values.join = new InterpolValues(prop.values); |
| }else{ |
| start = prop.start ? prop.start : (stroke && stroke.join || 0); |
| end = prop.end ? prop.end : (stroke && stroke.join || 0); |
| if(typeof start == "number" && typeof end == "number"){ |
| values.join = new InterpolNumber(start, end); |
| } |
| } |
| } |
| this.curve = new InterpolObject(values, stroke); |
| }); |
| d.connect(anim, "onAnimate", shape, "setStroke"); |
| return anim; // dojo.Animation |
| }; |
| |
| g.fx.animateFill = function(/*Object*/ args){ |
| // summary: |
| // Returns an animation which will change fill color over time. |
| // Only solid fill color is supported at the moment |
| // example: |
| // | dojox.gfx.fx.animateFill{{ |
| // | shape: shape, |
| // | duration: 500, |
| // | color: {start: "red", end: "green"} |
| // | }).play(); |
| if(!args.easing){ args.easing = d._defaultEasing; } |
| var anim = new d.Animation(args), shape = args.shape, fill; |
| d.connect(anim, "beforeBegin", anim, function(){ |
| fill = shape.getFill(); |
| var prop = args.color, values = {}; |
| if(prop){ |
| this.curve = getColorInterpol(prop, fill, "", transparent); |
| } |
| }); |
| d.connect(anim, "onAnimate", shape, "setFill"); |
| return anim; // dojo.Animation |
| }; |
| |
| g.fx.animateFont = function(/*Object*/ args){ |
| // summary: |
| // Returns an animation which will change font properties over time |
| // example: |
| // | dojox.gfx.fx.animateFont{{ |
| // | shape: shape, |
| // | duration: 500, |
| // | variant: {values: ["normal", "small-caps"]}, |
| // | size: {end: 10, units: "pt"} |
| // | }).play(); |
| if(!args.easing){ args.easing = d._defaultEasing; } |
| var anim = new d.Animation(args), shape = args.shape, font; |
| d.connect(anim, "beforeBegin", anim, function(){ |
| font = shape.getFont(); |
| var prop = args.style, values = {}, value, start, end; |
| if(prop && prop.values){ |
| values.style = new InterpolValues(prop.values); |
| } |
| prop = args.variant; |
| if(prop && prop.values){ |
| values.variant = new InterpolValues(prop.values); |
| } |
| prop = args.weight; |
| if(prop && prop.values){ |
| values.weight = new InterpolValues(prop.values); |
| } |
| prop = args.family; |
| if(prop && prop.values){ |
| values.family = new InterpolValues(prop.values); |
| } |
| prop = args.size; |
| if(prop && prop.units){ |
| start = parseFloat(prop.start ? prop.start : (shape.font && shape.font.size || "0")); |
| end = parseFloat(prop.end ? prop.end : (shape.font && shape.font.size || "0")); |
| values.size = new InterpolUnit(start, end, prop.units); |
| } |
| this.curve = new InterpolObject(values, font); |
| }); |
| d.connect(anim, "onAnimate", shape, "setFont"); |
| return anim; // dojo.Animation |
| }; |
| |
| g.fx.animateTransform = function(/*Object*/ args){ |
| // summary: |
| // Returns an animation which will change transformation over time |
| // example: |
| // | dojox.gfx.fx.animateTransform{{ |
| // | shape: shape, |
| // | duration: 500, |
| // | transform: [ |
| // | {name: "translate", start: [0, 0], end: [200, 200]}, |
| // | {name: "original"} |
| // | ] |
| // | }).play(); |
| if(!args.easing){ args.easing = d._defaultEasing; } |
| var anim = new d.Animation(args), shape = args.shape, original; |
| d.connect(anim, "beforeBegin", anim, function(){ |
| original = shape.getTransform(); |
| this.curve = new InterpolTransform(args.transform, original); |
| }); |
| d.connect(anim, "onAnimate", shape, "setTransform"); |
| return anim; // dojo.Animation |
| }; |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.Columns"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.Columns"] = true; |
| dojo.provide("dojox.charting.plot2d.Columns"); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| (function(){ |
| var df = dojox.lang.functional, du = dojox.lang.utils, |
| dc = dojox.charting.plot2d.common, |
| purgeGroup = df.lambda("item.purgeGroup()"); |
| |
| dojo.declare("dojox.charting.plot2d.Columns", dojox.charting.plot2d.Base, { |
| defaultParams: { |
| hAxis: "x", // use a horizontal axis named "x" |
| vAxis: "y", // use a vertical axis named "y" |
| gap: 0, // gap between columns in pixels |
| shadows: null, // draw shadows |
| animate: null // animate bars into place |
| }, |
| optionalParams: { |
| minBarSize: 1, // minimal bar size in pixels |
| maxBarSize: 1 // maximal bar size in pixels |
| }, |
| |
| constructor: function(chart, kwArgs){ |
| this.opt = dojo.clone(this.defaultParams); |
| du.updateWithObject(this.opt, kwArgs); |
| du.updateWithPattern(this.opt, kwArgs, this.optionalParams); |
| this.series = []; |
| this.hAxis = this.opt.hAxis; |
| this.vAxis = this.opt.vAxis; |
| this.animate = this.opt.animate; |
| }, |
| |
| calculateAxes: function(dim){ |
| var stats = dc.collectSimpleStats(this.series); |
| stats.hmin -= 0.5; |
| stats.hmax += 0.5; |
| this._calc(dim, stats); |
| return this; |
| }, |
| render: function(dim, offsets){ |
| this.dirty = this.isDirty(); |
| if(this.dirty){ |
| dojo.forEach(this.series, purgeGroup); |
| this.cleanGroup(); |
| var s = this.group; |
| df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); |
| } |
| var t = this.chart.theme, color, stroke, fill, f, gap, width, |
| ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), |
| vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), |
| baseline = Math.max(0, this._vScaler.bounds.lower), |
| baselineHeight = vt(baseline), |
| events = this.events(); |
| f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt); |
| gap = f.gap; |
| width = f.size; |
| this.resetEvents(); |
| for(var i = this.series.length - 1; i >= 0; --i){ |
| var run = this.series[i]; |
| if(!this.dirty && !run.dirty){ continue; } |
| run.cleanGroup(); |
| var s = run.group; |
| if(!run.fill || !run.stroke){ |
| // need autogenerated color |
| color = run.dyn.color = new dojo.Color(t.next("color")); |
| } |
| stroke = run.stroke ? run.stroke : dc.augmentStroke(t.series.stroke, color); |
| fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); |
| for(var j = 0; j < run.data.length; ++j){ |
| var value = run.data[j], |
| v = typeof value == "number" ? value : value.y, |
| vv = vt(v), |
| height = vv - baselineHeight, |
| h = Math.abs(height), |
| specialColor = color, |
| specialFill = fill, |
| specialStroke = stroke; |
| if(typeof value != "number"){ |
| if(value.color){ |
| specialColor = new dojo.Color(value.color); |
| } |
| if("fill" in value){ |
| specialFill = value.fill; |
| }else if(value.color){ |
| specialFill = dc.augmentFill(t.series.fill, specialColor); |
| } |
| if("stroke" in value){ |
| specialStroke = value.stroke; |
| }else if(value.color){ |
| specialStroke = dc.augmentStroke(t.series.stroke, specialColor); |
| } |
| } |
| if(width >= 1 && h >= 1){ |
| var shape = s.createRect({ |
| x: offsets.l + ht(j + 0.5) + gap, |
| y: dim.height - offsets.b - (v > baseline ? vv : baselineHeight), |
| width: width, height: h |
| }).setFill(specialFill).setStroke(specialStroke); |
| run.dyn.fill = shape.getFill(); |
| run.dyn.stroke = shape.getStroke(); |
| if(events){ |
| var o = { |
| element: "column", |
| index: j, |
| run: run, |
| plot: this, |
| hAxis: this.hAxis || null, |
| vAxis: this.vAxis || null, |
| shape: shape, |
| x: j + 0.5, |
| y: v |
| }; |
| this._connectEvents(shape, o); |
| } |
| if(this.animate){ |
| this._animateColumn(shape, dim.height - offsets.b - baselineHeight, h); |
| } |
| } |
| } |
| run.dirty = false; |
| } |
| this.dirty = false; |
| return this; |
| }, |
| _animateColumn: function(shape, voffset, vsize){ |
| dojox.gfx.fx.animateTransform(dojo.delegate({ |
| shape: shape, |
| duration: 1200, |
| transform: [ |
| {name: "translate", start: [0, voffset - (voffset/vsize)], end: [0, 0]}, |
| {name: "scale", start: [1, 1/vsize], end: [1, 1]}, |
| {name: "original"} |
| ] |
| }, this.animate)).play(); |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.StackedColumns"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.StackedColumns"] = true; |
| dojo.provide("dojox.charting.plot2d.StackedColumns"); |
| |
| |
| |
| |
| |
| |
| |
| (function(){ |
| var df = dojox.lang.functional, dc = dojox.charting.plot2d.common, |
| purgeGroup = df.lambda("item.purgeGroup()"); |
| |
| dojo.declare("dojox.charting.plot2d.StackedColumns", dojox.charting.plot2d.Columns, { |
| calculateAxes: function(dim){ |
| var stats = dc.collectStackedStats(this.series); |
| this._maxRunLength = stats.hmax; |
| stats.hmin -= 0.5; |
| stats.hmax += 0.5; |
| this._calc(dim, stats); |
| return this; |
| }, |
| render: function(dim, offsets){ |
| if(this._maxRunLength <= 0){ |
| return this; |
| } |
| |
| // stack all values |
| var acc = df.repeat(this._maxRunLength, "-> 0", 0); |
| for(var i = 0; i < this.series.length; ++i){ |
| var run = this.series[i]; |
| for(var j = 0; j < run.data.length; ++j){ |
| var value = run.data[j], v = typeof value == "number" ? value : value.y; |
| if(isNaN(v)){ v = 0; } |
| acc[j] += v; |
| } |
| } |
| // draw runs in backwards |
| this.dirty = this.isDirty(); |
| if(this.dirty){ |
| dojo.forEach(this.series, purgeGroup); |
| this.cleanGroup(); |
| var s = this.group; |
| df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); |
| } |
| var t = this.chart.theme, color, stroke, fill, f, gap, width, |
| ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), |
| vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), |
| events = this.events(); |
| f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt); |
| gap = f.gap; |
| width = f.size; |
| this.resetEvents(); |
| for(var i = this.series.length - 1; i >= 0; --i){ |
| var run = this.series[i]; |
| if(!this.dirty && !run.dirty){ continue; } |
| run.cleanGroup(); |
| var s = run.group; |
| if(!run.fill || !run.stroke){ |
| // need autogenerated color |
| color = run.dyn.color = new dojo.Color(t.next("color")); |
| } |
| stroke = run.stroke ? run.stroke : dc.augmentStroke(t.series.stroke, color); |
| fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); |
| for(var j = 0; j < acc.length; ++j){ |
| var v = acc[j], |
| height = vt(v), |
| value = run.data[j], |
| specialColor = color, |
| specialFill = fill, |
| specialStroke = stroke; |
| if(typeof value != "number"){ |
| if(value.color){ |
| specialColor = new dojo.Color(value.color); |
| } |
| if("fill" in value){ |
| specialFill = value.fill; |
| }else if(value.color){ |
| specialFill = dc.augmentFill(t.series.fill, specialColor); |
| } |
| if("stroke" in value){ |
| specialStroke = value.stroke; |
| }else if(value.color){ |
| specialStroke = dc.augmentStroke(t.series.stroke, specialColor); |
| } |
| } |
| if(width >= 1 && height >= 1){ |
| var shape = s.createRect({ |
| x: offsets.l + ht(j + 0.5) + gap, |
| y: dim.height - offsets.b - vt(v), |
| width: width, height: height |
| }).setFill(specialFill).setStroke(specialStroke); |
| run.dyn.fill = shape.getFill(); |
| run.dyn.stroke = shape.getStroke(); |
| if(events){ |
| var o = { |
| element: "column", |
| index: j, |
| run: run, |
| plot: this, |
| hAxis: this.hAxis || null, |
| vAxis: this.vAxis || null, |
| shape: shape, |
| x: j + 0.5, |
| y: v |
| }; |
| this._connectEvents(shape, o); |
| } |
| if(this.animate){ |
| this._animateColumn(shape, dim.height - offsets.b, height); |
| } |
| } |
| } |
| run.dirty = false; |
| // update the accumulator |
| for(var j = 0; j < run.data.length; ++j){ |
| var value = run.data[j], v = typeof value == "number" ? value : value.y; |
| if(isNaN(v)){ v = 0; } |
| acc[j] -= v; |
| } |
| } |
| this.dirty = false; |
| return this; |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.ClusteredColumns"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.ClusteredColumns"] = true; |
| dojo.provide("dojox.charting.plot2d.ClusteredColumns"); |
| |
| |
| |
| |
| |
| |
| |
| (function(){ |
| var df = dojox.lang.functional, dc = dojox.charting.plot2d.common, |
| purgeGroup = df.lambda("item.purgeGroup()"); |
| |
| dojo.declare("dojox.charting.plot2d.ClusteredColumns", dojox.charting.plot2d.Columns, { |
| render: function(dim, offsets){ |
| this.dirty = this.isDirty(); |
| if(this.dirty){ |
| dojo.forEach(this.series, purgeGroup); |
| this.cleanGroup(); |
| var s = this.group; |
| df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); |
| } |
| var t = this.chart.theme, color, stroke, fill, f, gap, width, thickness, |
| ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), |
| vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), |
| baseline = Math.max(0, this._vScaler.bounds.lower), |
| baselineHeight = vt(baseline), |
| events = this.events(); |
| f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt, this.series.length); |
| gap = f.gap; |
| width = thickness = f.size; |
| this.resetEvents(); |
| for(var i = 0; i < this.series.length; ++i){ |
| var run = this.series[i], shift = thickness * i; |
| if(!this.dirty && !run.dirty){ continue; } |
| run.cleanGroup(); |
| var s = run.group; |
| if(!run.fill || !run.stroke){ |
| // need autogenerated color |
| color = run.dyn.color = new dojo.Color(t.next("color")); |
| } |
| stroke = run.stroke ? run.stroke : dc.augmentStroke(t.series.stroke, color); |
| fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); |
| for(var j = 0; j < run.data.length; ++j){ |
| var value = run.data[j], |
| v = typeof value == "number" ? value : value.y, |
| vv = vt(v), |
| height = vv - baselineHeight, |
| h = Math.abs(height), |
| specialColor = color, |
| specialFill = fill, |
| specialStroke = stroke; |
| if(typeof value != "number"){ |
| if(value.color){ |
| specialColor = new dojo.Color(value.color); |
| } |
| if("fill" in value){ |
| specialFill = value.fill; |
| }else if(value.color){ |
| specialFill = dc.augmentFill(t.series.fill, specialColor); |
| } |
| if("stroke" in value){ |
| specialStroke = value.stroke; |
| }else if(value.color){ |
| specialStroke = dc.augmentStroke(t.series.stroke, specialColor); |
| } |
| } |
| if(width >= 1 && h >= 1){ |
| var shape = s.createRect({ |
| x: offsets.l + ht(j + 0.5) + gap + shift, |
| y: dim.height - offsets.b - (v > baseline ? vv : baselineHeight), |
| width: width, height: h |
| }).setFill(specialFill).setStroke(specialStroke); |
| run.dyn.fill = shape.getFill(); |
| run.dyn.stroke = shape.getStroke(); |
| if(events){ |
| var o = { |
| element: "column", |
| index: j, |
| run: run, |
| plot: this, |
| hAxis: this.hAxis || null, |
| vAxis: this.vAxis || null, |
| shape: shape, |
| x: j + 0.5, |
| y: v |
| }; |
| this._connectEvents(shape, o); |
| } |
| if(this.animate){ |
| this._animateColumn(shape, dim.height - offsets.b - baselineHeight, h); |
| } |
| } |
| } |
| run.dirty = false; |
| } |
| this.dirty = false; |
| return this; |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.Bars"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.Bars"] = true; |
| dojo.provide("dojox.charting.plot2d.Bars"); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| (function(){ |
| var df = dojox.lang.functional, du = dojox.lang.utils, |
| dc = dojox.charting.plot2d.common, |
| purgeGroup = df.lambda("item.purgeGroup()"); |
| |
| dojo.declare("dojox.charting.plot2d.Bars", dojox.charting.plot2d.Base, { |
| defaultParams: { |
| hAxis: "x", // use a horizontal axis named "x" |
| vAxis: "y", // use a vertical axis named "y" |
| gap: 0, // gap between columns in pixels |
| shadows: null, // draw shadows |
| animate: null // animate bars into place |
| }, |
| optionalParams: { |
| minBarSize: 1, // minimal bar size in pixels |
| maxBarSize: 1 // maximal bar size in pixels |
| }, |
| |
| constructor: function(chart, kwArgs){ |
| this.opt = dojo.clone(this.defaultParams); |
| du.updateWithObject(this.opt, kwArgs); |
| du.updateWithPattern(this.opt, kwArgs, this.optionalParams); |
| this.series = []; |
| this.hAxis = this.opt.hAxis; |
| this.vAxis = this.opt.vAxis; |
| this.animate = this.opt.animate; |
| }, |
| |
| calculateAxes: function(dim){ |
| var stats = dc.collectSimpleStats(this.series), t; |
| stats.hmin -= 0.5; |
| stats.hmax += 0.5; |
| t = stats.hmin, stats.hmin = stats.vmin, stats.vmin = t; |
| t = stats.hmax, stats.hmax = stats.vmax, stats.vmax = t; |
| this._calc(dim, stats); |
| return this; |
| }, |
| render: function(dim, offsets){ |
| this.dirty = this.isDirty(); |
| if(this.dirty){ |
| dojo.forEach(this.series, purgeGroup); |
| this.cleanGroup(); |
| var s = this.group; |
| df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); |
| } |
| var t = this.chart.theme, color, stroke, fill, f, gap, height, |
| ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), |
| vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), |
| baseline = Math.max(0, this._hScaler.bounds.lower), |
| baselineWidth = ht(baseline), |
| events = this.events(); |
| f = dc.calculateBarSize(this._vScaler.bounds.scale, this.opt); |
| gap = f.gap; |
| height = f.size; |
| this.resetEvents(); |
| for(var i = this.series.length - 1; i >= 0; --i){ |
| var run = this.series[i]; |
| if(!this.dirty && !run.dirty){ continue; } |
| run.cleanGroup(); |
| var s = run.group; |
| if(!run.fill || !run.stroke){ |
| // need autogenerated color |
| color = run.dyn.color = new dojo.Color(t.next("color")); |
| } |
| stroke = run.stroke ? run.stroke : dc.augmentStroke(t.series.stroke, color); |
| fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); |
| for(var j = 0; j < run.data.length; ++j){ |
| var value = run.data[j], |
| v = typeof value == "number" ? value : value.y, |
| hv = ht(v), |
| width = hv - baselineWidth, |
| w = Math.abs(width), |
| specialColor = color, |
| specialFill = fill, |
| specialStroke = stroke; |
| if(typeof value != "number"){ |
| if(value.color){ |
| specialColor = new dojo.Color(value.color); |
| } |
| if("fill" in value){ |
| specialFill = value.fill; |
| }else if(value.color){ |
| specialFill = dc.augmentFill(t.series.fill, specialColor); |
| } |
| if("stroke" in value){ |
| specialStroke = value.stroke; |
| }else if(value.color){ |
| specialStroke = dc.augmentStroke(t.series.stroke, specialColor); |
| } |
| } |
| if(w >= 1 && height >= 1){ |
| var shape = s.createRect({ |
| x: offsets.l + (v < baseline ? hv : baselineWidth), |
| y: dim.height - offsets.b - vt(j + 1.5) + gap, |
| width: w, height: height |
| }).setFill(specialFill).setStroke(specialStroke); |
| run.dyn.fill = shape.getFill(); |
| run.dyn.stroke = shape.getStroke(); |
| if(events){ |
| var o = { |
| element: "bar", |
| index: j, |
| run: run, |
| plot: this, |
| hAxis: this.hAxis || null, |
| vAxis: this.vAxis || null, |
| shape: shape, |
| x: v, |
| y: j + 1.5 |
| }; |
| this._connectEvents(shape, o); |
| } |
| if(this.animate){ |
| this._animateBar(shape, offsets.l + baselineWidth, -w); |
| } |
| } |
| } |
| run.dirty = false; |
| } |
| this.dirty = false; |
| return this; |
| }, |
| _animateBar: function(shape, hoffset, hsize){ |
| dojox.gfx.fx.animateTransform(dojo.delegate({ |
| shape: shape, |
| duration: 1200, |
| transform: [ |
| {name: "translate", start: [hoffset - (hoffset/hsize), 0], end: [0, 0]}, |
| {name: "scale", start: [1/hsize, 1], end: [1, 1]}, |
| {name: "original"} |
| ] |
| }, this.animate)).play(); |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.StackedBars"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.StackedBars"] = true; |
| dojo.provide("dojox.charting.plot2d.StackedBars"); |
| |
| |
| |
| |
| |
| |
| |
| (function(){ |
| var df = dojox.lang.functional, dc = dojox.charting.plot2d.common, |
| purgeGroup = df.lambda("item.purgeGroup()"); |
| |
| dojo.declare("dojox.charting.plot2d.StackedBars", dojox.charting.plot2d.Bars, { |
| calculateAxes: function(dim){ |
| var stats = dc.collectStackedStats(this.series), t; |
| this._maxRunLength = stats.hmax; |
| stats.hmin -= 0.5; |
| stats.hmax += 0.5; |
| t = stats.hmin, stats.hmin = stats.vmin, stats.vmin = t; |
| t = stats.hmax, stats.hmax = stats.vmax, stats.vmax = t; |
| this._calc(dim, stats); |
| return this; |
| }, |
| render: function(dim, offsets){ |
| if(this._maxRunLength <= 0){ |
| return this; |
| } |
| |
| // stack all values |
| var acc = df.repeat(this._maxRunLength, "-> 0", 0); |
| for(var i = 0; i < this.series.length; ++i){ |
| var run = this.series[i]; |
| for(var j = 0; j < run.data.length; ++j){ |
| var value = run.data[j], v = typeof value == "number" ? value : value.y; |
| if(isNaN(v)){ v = 0; } |
| acc[j] += v; |
| } |
| } |
| // draw runs in backwards |
| this.dirty = this.isDirty(); |
| if(this.dirty){ |
| dojo.forEach(this.series, purgeGroup); |
| this.cleanGroup(); |
| var s = this.group; |
| df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); |
| } |
| var t = this.chart.theme, color, stroke, fill, f, gap, height, |
| ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), |
| vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), |
| events = this.events(); |
| f = dc.calculateBarSize(this._vScaler.bounds.scale, this.opt); |
| gap = f.gap; |
| height = f.size; |
| this.resetEvents(); |
| for(var i = this.series.length - 1; i >= 0; --i){ |
| var run = this.series[i]; |
| if(!this.dirty && !run.dirty){ continue; } |
| run.cleanGroup(); |
| var s = run.group; |
| if(!run.fill || !run.stroke){ |
| // need autogenerated color |
| color = run.dyn.color = new dojo.Color(t.next("color")); |
| } |
| stroke = run.stroke ? run.stroke : dc.augmentStroke(t.series.stroke, color); |
| fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); |
| for(var j = 0; j < acc.length; ++j){ |
| var v = acc[j], |
| width = ht(v), |
| value = run.data[j], |
| specialColor = color, |
| specialFill = fill, |
| specialStroke = stroke; |
| if(typeof value != "number"){ |
| if(value.color){ |
| specialColor = new dojo.Color(value.color); |
| } |
| if("fill" in value){ |
| specialFill = value.fill; |
| }else if(value.color){ |
| specialFill = dc.augmentFill(t.series.fill, specialColor); |
| } |
| if("stroke" in value){ |
| specialStroke = value.stroke; |
| }else if(value.color){ |
| specialStroke = dc.augmentStroke(t.series.stroke, specialColor); |
| } |
| } |
| if(width >= 1 && height >= 1){ |
| var shape = s.createRect({ |
| x: offsets.l, |
| y: dim.height - offsets.b - vt(j + 1.5) + gap, |
| width: width, height: height |
| }).setFill(specialFill).setStroke(specialStroke); |
| run.dyn.fill = shape.getFill(); |
| run.dyn.stroke = shape.getStroke(); |
| if(events){ |
| var o = { |
| element: "bar", |
| index: j, |
| run: run, |
| plot: this, |
| hAxis: this.hAxis || null, |
| vAxis: this.vAxis || null, |
| shape: shape, |
| x: v, |
| y: j + 1.5 |
| }; |
| this._connectEvents(shape, o); |
| } |
| if(this.animate){ |
| this._animateBar(shape, offsets.l, -width); |
| } |
| } |
| } |
| run.dirty = false; |
| // update the accumulator |
| for(var j = 0; j < run.data.length; ++j){ |
| var value = run.data[j], v = typeof value == "number" ? value : value.y; |
| if(isNaN(v)){ v = 0; } |
| acc[j] -= v; |
| } |
| } |
| this.dirty = false; |
| return this; |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.ClusteredBars"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.ClusteredBars"] = true; |
| dojo.provide("dojox.charting.plot2d.ClusteredBars"); |
| |
| |
| |
| |
| |
| |
| |
| (function(){ |
| var df = dojox.lang.functional, dc = dojox.charting.plot2d.common, |
| purgeGroup = df.lambda("item.purgeGroup()"); |
| |
| dojo.declare("dojox.charting.plot2d.ClusteredBars", dojox.charting.plot2d.Bars, { |
| render: function(dim, offsets){ |
| this.dirty = this.isDirty(); |
| if(this.dirty){ |
| dojo.forEach(this.series, purgeGroup); |
| this.cleanGroup(); |
| var s = this.group; |
| df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); |
| } |
| var t = this.chart.theme, color, stroke, fill, f, gap, height, thickness, |
| ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), |
| vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), |
| baseline = Math.max(0, this._hScaler.bounds.lower), |
| baselineWidth = ht(baseline), |
| events = this.events(); |
| f = dc.calculateBarSize(this._vScaler.bounds.scale, this.opt, this.series.length); |
| gap = f.gap; |
| height = thickness = f.size; |
| this.resetEvents(); |
| for(var i = this.series.length - 1; i >= 0; --i){ |
| var run = this.series[i], shift = thickness * (this.series.length - i - 1); |
| if(!this.dirty && !run.dirty){ continue; } |
| run.cleanGroup(); |
| var s = run.group; |
| if(!run.fill || !run.stroke){ |
| // need autogenerated color |
| color = run.dyn.color = new dojo.Color(t.next("color")); |
| } |
| stroke = run.stroke ? run.stroke : dc.augmentStroke(t.series.stroke, color); |
| fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); |
| for(var j = 0; j < run.data.length; ++j){ |
| var value = run.data[j], |
| v = typeof value == "number" ? value : value.y, |
| hv = ht(v), |
| width = hv - baselineWidth, |
| w = Math.abs(width), |
| specialColor = color, |
| specialFill = fill, |
| specialStroke = stroke; |
| if(typeof value != "number"){ |
| if(value.color){ |
| specialColor = new dojo.Color(value.color); |
| } |
| if("fill" in value){ |
| specialFill = value.fill; |
| }else if(value.color){ |
| specialFill = dc.augmentFill(t.series.fill, specialColor); |
| } |
| if("stroke" in value){ |
| specialStroke = value.stroke; |
| }else if(value.color){ |
| specialStroke = dc.augmentStroke(t.series.stroke, specialColor); |
| } |
| } |
| if(w >= 1 && height >= 1){ |
| var shape = s.createRect({ |
| x: offsets.l + (v < baseline ? hv : baselineWidth), |
| y: dim.height - offsets.b - vt(j + 1.5) + gap + shift, |
| width: w, height: height |
| }).setFill(specialFill).setStroke(specialStroke); |
| run.dyn.fill = shape.getFill(); |
| run.dyn.stroke = shape.getStroke(); |
| if(events){ |
| var o = { |
| element: "bar", |
| index: j, |
| run: run, |
| plot: this, |
| hAxis: this.hAxis || null, |
| vAxis: this.vAxis || null, |
| shape: shape, |
| x: v, |
| y: j + 1.5 |
| }; |
| this._connectEvents(shape, o); |
| } |
| if(this.animate){ |
| this._animateBar(shape, offsets.l + baselineWidth, -width); |
| } |
| } |
| } |
| run.dirty = false; |
| } |
| this.dirty = false; |
| return this; |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.Grid"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.Grid"] = true; |
| dojo.provide("dojox.charting.plot2d.Grid"); |
| |
| |
| |
| |
| |
| (function(){ |
| var du = dojox.lang.utils; |
| |
| dojo.declare("dojox.charting.plot2d.Grid", dojox.charting.Element, { |
| defaultParams: { |
| hAxis: "x", // use a horizontal axis named "x" |
| vAxis: "y", // use a vertical axis named "y" |
| hMajorLines: true, // draw horizontal major lines |
| hMinorLines: false, // draw horizontal minor lines |
| vMajorLines: true, // draw vertical major lines |
| vMinorLines: false, // draw vertical minor lines |
| hStripes: "none", // TBD |
| vStripes: "none" // TBD |
| }, |
| optionalParams: {}, // no optional parameters |
| |
| constructor: function(chart, kwArgs){ |
| this.opt = dojo.clone(this.defaultParams); |
| du.updateWithObject(this.opt, kwArgs); |
| this.hAxis = this.opt.hAxis; |
| this.vAxis = this.opt.vAxis; |
| this.dirty = true; |
| }, |
| clear: function(){ |
| this._hAxis = null; |
| this._vAxis = null; |
| this.dirty = true; |
| return this; |
| }, |
| setAxis: function(axis){ |
| if(axis){ |
| this[axis.vertical ? "_vAxis" : "_hAxis"] = axis; |
| } |
| return this; |
| }, |
| addSeries: function(run){ |
| // nothing |
| return this; |
| }, |
| calculateAxes: function(dim){ |
| // nothing |
| return this; |
| }, |
| isDirty: function(){ |
| return this.dirty || this._hAxis && this._hAxis.dirty || this._vAxis && this._vAxis.dirty; |
| }, |
| getRequiredColors: function(){ |
| return 0; |
| }, |
| render: function(dim, offsets){ |
| this.dirty = this.isDirty(); |
| if(!this.dirty){ return this; } |
| this.cleanGroup(); |
| var s = this.group, ta = this.chart.theme.axis; |
| // draw horizontal stripes and lines |
| try{ |
| var vScaler = this._vAxis.getScaler(), |
| vt = vScaler.scaler.getTransformerFromModel(vScaler), |
| ticks = this._vAxis.getTicks(); |
| if(this.opt.hMinorLines){ |
| dojo.forEach(ticks.minor, function(tick){ |
| var y = dim.height - offsets.b - vt(tick.value); |
| s.createLine({ |
| x1: offsets.l, |
| y1: y, |
| x2: dim.width - offsets.r, |
| y2: y |
| }).setStroke(ta.minorTick); |
| }); |
| } |
| if(this.opt.hMajorLines){ |
| dojo.forEach(ticks.major, function(tick){ |
| var y = dim.height - offsets.b - vt(tick.value); |
| s.createLine({ |
| x1: offsets.l, |
| y1: y, |
| x2: dim.width - offsets.r, |
| y2: y |
| }).setStroke(ta.majorTick); |
| }); |
| } |
| }catch(e){ |
| // squelch |
| } |
| // draw vertical stripes and lines |
| try{ |
| var hScaler = this._hAxis.getScaler(), |
| ht = hScaler.scaler.getTransformerFromModel(hScaler), |
| ticks = this._hAxis.getTicks(); |
| if(ticks && this.opt.vMinorLines){ |
| dojo.forEach(ticks.minor, function(tick){ |
| var x = offsets.l + ht(tick.value); |
| s.createLine({ |
| x1: x, |
| y1: offsets.t, |
| x2: x, |
| y2: dim.height - offsets.b |
| }).setStroke(ta.minorTick); |
| }); |
| } |
| if(ticks && this.opt.vMajorLines){ |
| dojo.forEach(ticks.major, function(tick){ |
| var x = offsets.l + ht(tick.value); |
| s.createLine({ |
| x1: x, |
| y1: offsets.t, |
| x2: x, |
| y2: dim.height - offsets.b |
| }).setStroke(ta.majorTick); |
| }); |
| } |
| }catch(e){ |
| // squelch |
| } |
| this.dirty = false; |
| return this; |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.Pie"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.Pie"] = true; |
| dojo.provide("dojox.charting.plot2d.Pie"); |
| |
| |
| |
| |
| |
| |
| |
| |
| (function(){ |
| var df = dojox.lang.functional, du = dojox.lang.utils, |
| dc = dojox.charting.plot2d.common, |
| da = dojox.charting.axis2d.common, |
| g = dojox.gfx; |
| |
| dojo.declare("dojox.charting.plot2d.Pie", dojox.charting.Element, { |
| defaultParams: { |
| labels: true, |
| ticks: false, |
| fixed: true, |
| precision: 1, |
| labelOffset: 20, |
| labelStyle: "default", // default/rows/auto |
| htmlLabels: true // use HTML to draw labels |
| }, |
| optionalParams: { |
| font: "", |
| fontColor: "", |
| radius: 0 |
| }, |
| |
| constructor: function(chart, kwArgs){ |
| this.opt = dojo.clone(this.defaultParams); |
| du.updateWithObject(this.opt, kwArgs); |
| du.updateWithPattern(this.opt, kwArgs, this.optionalParams); |
| this.run = null; |
| this.dyn = []; |
| }, |
| destroy: function(){ |
| this.resetEvents(); |
| this.inherited(arguments); |
| }, |
| clear: function(){ |
| this.dirty = true; |
| this.dyn = []; |
| this.run = null; |
| return this; |
| }, |
| setAxis: function(axis){ |
| // nothing |
| return this; |
| }, |
| addSeries: function(run){ |
| this.run = run; |
| return this; |
| }, |
| calculateAxes: function(dim){ |
| // nothing |
| return this; |
| }, |
| getRequiredColors: function(){ |
| return this.run ? this.run.data.length : 0; |
| }, |
| |
| // events |
| plotEvent: function(o){ |
| // intentionally empty --- used for events |
| }, |
| connect: function(object, method){ |
| this.dirty = true; |
| return dojo.connect(this, "plotEvent", object, method); |
| }, |
| events: function(){ |
| var ls = this.plotEvent._listeners; |
| if(!ls || !ls.length){ return false; } |
| for(var i in ls){ |
| if(!(i in Array.prototype)){ |
| return true; |
| } |
| } |
| return false; |
| }, |
| resetEvents: function(){ |
| this.plotEvent({type: "onplotreset", plot: this}); |
| }, |
| _connectEvents: function(shape, o){ |
| shape.connect("onmouseover", this, function(e){ |
| o.type = "onmouseover"; |
| o.event = e; |
| this.plotEvent(o); |
| }); |
| shape.connect("onmouseout", this, function(e){ |
| o.type = "onmouseout"; |
| o.event = e; |
| this.plotEvent(o); |
| }); |
| shape.connect("onclick", this, function(e){ |
| o.type = "onclick"; |
| o.event = e; |
| this.plotEvent(o); |
| }); |
| }, |
| |
| render: function(dim, offsets){ |
| if(!this.dirty){ return this; } |
| this.dirty = false; |
| this.cleanGroup(); |
| var s = this.group, color, t = this.chart.theme; |
| this.resetEvents(); |
| |
| if(!this.run || !this.run.data.length){ |
| return this; |
| } |
| |
| // calculate the geometry |
| var rx = (dim.width - offsets.l - offsets.r) / 2, |
| ry = (dim.height - offsets.t - offsets.b) / 2, |
| r = Math.min(rx, ry), |
| taFont = "font" in this.opt ? this.opt.font : t.axis.font, |
| size = taFont ? g.normalizedLength(g.splitFontString(taFont).size) : 0, |
| taFontColor = "fontColor" in this.opt ? this.opt.fontColor : t.axis.fontColor, |
| start = 0, step, filteredRun, slices, labels, shift, labelR, |
| run = this.run.data, |
| events = this.events(); |
| if(typeof run[0] == "number"){ |
| filteredRun = df.map(run, "Math.max(x, 0)"); |
| if(df.every(filteredRun, "<= 0")){ |
| return this; |
| } |
| slices = df.map(filteredRun, "/this", df.foldl(filteredRun, "+", 0)); |
| if(this.opt.labels){ |
| labels = dojo.map(slices, function(x){ |
| return x > 0 ? this._getLabel(x * 100) + "%" : ""; |
| }, this); |
| } |
| }else{ |
| filteredRun = df.map(run, "Math.max(x.y, 0)"); |
| if(df.every(filteredRun, "<= 0")){ |
| return this; |
| } |
| slices = df.map(filteredRun, "/this", df.foldl(filteredRun, "+", 0)); |
| if(this.opt.labels){ |
| labels = dojo.map(slices, function(x, i){ |
| if(x <= 0){ return ""; } |
| var v = run[i]; |
| return "text" in v ? v.text : this._getLabel(x * 100) + "%"; |
| }, this); |
| } |
| } |
| if(this.opt.labels){ |
| shift = df.foldl1(df.map(labels, function(label){ |
| return dojox.gfx._base._getTextBox(label, {font: taFont}).w; |
| }, this), "Math.max(a, b)") / 2; |
| if(this.opt.labelOffset < 0){ |
| r = Math.min(rx - 2 * shift, ry - size) + this.opt.labelOffset; |
| } |
| labelR = r - this.opt.labelOffset; |
| } |
| if("radius" in this.opt){ |
| r = this.opt.radius; |
| labelR = r - this.opt.labelOffset; |
| } |
| var circle = { |
| cx: offsets.l + rx, |
| cy: offsets.t + ry, |
| r: r |
| }; |
| |
| this.dyn = []; |
| // draw slices |
| dojo.some(slices, function(slice, i){ |
| if(slice <= 0){ |
| // degenerated slice |
| return false; // continue |
| } |
| var v = run[i]; |
| if(slice >= 1){ |
| // whole pie |
| var color, fill, stroke; |
| if(typeof v == "object"){ |
| color = "color" in v ? v.color : new dojo.Color(t.next("color")); |
| fill = "fill" in v ? v.fill : dc.augmentFill(t.series.fill, color); |
| stroke = "stroke" in v ? v.stroke : dc.augmentStroke(t.series.stroke, color); |
| }else{ |
| color = new dojo.Color(t.next("color")); |
| fill = dc.augmentFill(t.series.fill, color); |
| stroke = dc.augmentStroke(t.series.stroke, color); |
| } |
| var shape = s.createCircle(circle).setFill(fill).setStroke(stroke); |
| this.dyn.push({color: color, fill: fill, stroke: stroke}); |
| |
| if(events){ |
| var o = { |
| element: "slice", |
| index: i, |
| run: this.run, |
| plot: this, |
| shape: shape, |
| x: i, |
| y: typeof v == "number" ? v : v.y, |
| cx: circle.cx, |
| cy: circle.cy, |
| cr: r |
| }; |
| this._connectEvents(shape, o); |
| } |
| |
| return true; // stop iteration |
| } |
| // calculate the geometry of the slice |
| var end = start + slice * 2 * Math.PI; |
| if(i + 1 == slices.length){ |
| end = 2 * Math.PI; |
| } |
| var step = end - start, |
| x1 = circle.cx + r * Math.cos(start), |
| y1 = circle.cy + r * Math.sin(start), |
| x2 = circle.cx + r * Math.cos(end), |
| y2 = circle.cy + r * Math.sin(end); |
| // draw the slice |
| var color, fill, stroke; |
| if(typeof v == "object"){ |
| color = "color" in v ? v.color : new dojo.Color(t.next("color")); |
| fill = "fill" in v ? v.fill : dc.augmentFill(t.series.fill, color); |
| stroke = "stroke" in v ? v.stroke : dc.augmentStroke(t.series.stroke, color); |
| }else{ |
| color = new dojo.Color(t.next("color")); |
| fill = dc.augmentFill(t.series.fill, color); |
| stroke = dc.augmentStroke(t.series.stroke, color); |
| } |
| var shape = s.createPath({}). |
| moveTo(circle.cx, circle.cy). |
| lineTo(x1, y1). |
| arcTo(r, r, 0, step > Math.PI, true, x2, y2). |
| lineTo(circle.cx, circle.cy). |
| closePath(). |
| setFill(fill). |
| setStroke(stroke); |
| this.dyn.push({color: color, fill: fill, stroke: stroke}); |
| |
| if(events){ |
| var o = { |
| element: "slice", |
| index: i, |
| run: this.run, |
| plot: this, |
| shape: shape, |
| x: i, |
| y: typeof v == "number" ? v : v.y, |
| cx: circle.cx, |
| cy: circle.cy, |
| cr: r |
| }; |
| this._connectEvents(shape, o); |
| } |
| |
| start = end; |
| |
| return false; // continue |
| }, this); |
| // draw labels |
| if(this.opt.labels){ |
| start = 0; |
| dojo.some(slices, function(slice, i){ |
| if(slice <= 0){ |
| // degenerated slice |
| return false; // continue |
| } |
| if(slice >= 1){ |
| // whole pie |
| var v = run[i], elem = da.createText[this.opt.htmlLabels && dojox.gfx.renderer != "vml" ? "html" : "gfx"] |
| (this.chart, s, circle.cx, circle.cy + size / 2, "middle", |
| labels[i], taFont, (typeof v == "object" && "fontColor" in v) ? v.fontColor : taFontColor); |
| if(this.opt.htmlLabels){ this.htmlElements.push(elem); } |
| return true; // stop iteration |
| } |
| // calculate the geometry of the slice |
| var end = start + slice * 2 * Math.PI, v = run[i]; |
| if(i + 1 == slices.length){ |
| end = 2 * Math.PI; |
| } |
| var labelAngle = (start + end) / 2, |
| x = circle.cx + labelR * Math.cos(labelAngle), |
| y = circle.cy + labelR * Math.sin(labelAngle) + size / 2; |
| // draw the label |
| var elem = da.createText[this.opt.htmlLabels && dojox.gfx.renderer != "vml" ? "html" : "gfx"] |
| (this.chart, s, x, y, "middle", |
| labels[i], taFont, |
| (typeof v == "object" && "fontColor" in v) |
| ? v.fontColor : taFontColor); |
| if(this.opt.htmlLabels){ this.htmlElements.push(elem); } |
| start = end; |
| return false; // continue |
| }, this); |
| } |
| return this; |
| }, |
| |
| // utilities |
| _getLabel: function(number){ |
| return this.opt.fixed ? number.toFixed(this.opt.precision) : number.toString(); |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.Bubble"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.Bubble"] = true; |
| dojo.provide("dojox.charting.plot2d.Bubble"); |
| |
| |
| |
| |
| (function(){ |
| var df = dojox.lang.functional, du = dojox.lang.utils, |
| dc = dojox.charting.plot2d.common, |
| purgeGroup = df.lambda("item.purgeGroup()"); |
| |
| dojo.declare("dojox.charting.plot2d.Bubble", dojox.charting.plot2d.Base, { |
| defaultParams: { |
| hAxis: "x", // use a horizontal axis named "x" |
| vAxis: "y" // use a vertical axis named "y" |
| }, |
| optionalParams: {}, // no optional parameters |
| |
| constructor: function(chart, kwArgs){ |
| this.opt = dojo.clone(this.defaultParams); |
| du.updateWithObject(this.opt, kwArgs); |
| this.series = []; |
| this.hAxis = this.opt.hAxis; |
| this.vAxis = this.opt.vAxis; |
| }, |
| |
| calculateAxes: function(dim){ |
| this._calc(dim, dc.collectSimpleStats(this.series)); |
| return this; |
| }, |
| |
| // override the render so that we are plotting only circles. |
| render: function(dim, offsets){ |
| this.dirty = this.isDirty(); |
| if(this.dirty){ |
| dojo.forEach(this.series, purgeGroup); |
| this.cleanGroup(); |
| var s = this.group; |
| df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); |
| } |
| |
| var t = this.chart.theme, stroke, outline, color, shadowStroke, shadowColor, |
| ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), |
| vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), |
| events = this.events(); |
| |
| this.resetEvents(); |
| |
| for(var i = this.series.length - 1; i >= 0; --i){ |
| var run = this.series[i]; |
| if(!this.dirty && !run.dirty){ continue; } |
| run.cleanGroup(); |
| if(!run.data.length){ |
| run.dirty = false; |
| continue; |
| } |
| |
| if(typeof run.data[0] == "number"){ |
| console.warn("dojox.charting.plot2d.Bubble: the data in the following series cannot be rendered as a bubble chart; ", run); |
| continue; |
| } |
| |
| var s = run.group, |
| points = dojo.map(run.data, function(v, i){ |
| return { |
| x: ht(v.x) + offsets.l, |
| y: dim.height - offsets.b - vt(v.y), |
| radius: this._vScaler.bounds.scale * (v.size / 2) |
| }; |
| }, this); |
| |
| if(run.fill){ |
| color = run.fill; |
| }else if(run.stroke){ |
| color = run.stroke; |
| }else{ |
| color = run.dyn.color = new dojo.Color(t.next("color")); |
| } |
| run.dyn.fill = color; |
| |
| stroke = run.dyn.stroke = run.stroke ? dc.makeStroke(run.stroke) : dc.augmentStroke(t.series.stroke, color); |
| |
| var frontCircles = null, outlineCircles = null, shadowCircles = null; |
| |
| // make shadows if needed |
| if(this.opt.shadows && stroke){ |
| var sh = this.opt.shadows, shadowColor = new dojo.Color([0, 0, 0, 0.2]), |
| shadowStroke = dojo.clone(outline ? outline : stroke); |
| shadowStroke.color = shadowColor; |
| shadowStroke.width += sh.dw ? sh.dw : 0; |
| run.dyn.shadow = shadowStroke; |
| var shadowMarkers = dojo.map(points, function(item){ |
| var sh = this.opt.shadows; |
| return s.createCircle({ |
| cx: item.x + sh.dx, cy: item.y + sh.dy, r: item.radius |
| }).setStroke(shadowStroke).setFill(shadowColor); |
| }, this); |
| } |
| |
| // make outlines if needed |
| if(run.outline || t.series.outline){ |
| outline = dc.makeStroke(run.outline ? run.outline : t.series.outline); |
| outline.width = 2 * outline.width + stroke.width; |
| run.dyn.outline = outline; |
| outlineCircles = dojo.map(points, function(item){ |
| s.createCircle({ cx: item.x, cy: item.y, r: item.radius }).setStroke(outline); |
| }, this); |
| } |
| |
| // run through the data and add the circles. |
| frontCircles = dojo.map(points, function(item){ |
| return s.createCircle({ cx: item.x, cy: item.y, r: item.radius }).setStroke(stroke).setFill(color); |
| }, this); |
| |
| if(events){ |
| dojo.forEach(frontCircles, function(s, i){ |
| var o = { |
| element: "circle", |
| index: i, |
| run: run, |
| plot: this, |
| hAxis: this.hAxis || null, |
| vAxis: this.vAxis || null, |
| shape: s, |
| outline: outlineCircles && outlineCircles[i] || null, |
| shadow: shadowCircles && shadowCircles[i] || null, |
| x: run.data[i].x, |
| y: run.data[i].y, |
| r: run.data[i].size / 2, |
| cx: points[i].x, |
| cy: points[i].y, |
| cr: points[i].radius |
| }; |
| this._connectEvents(s, o); |
| }, this); |
| } |
| |
| run.dirty = false; |
| } |
| this.dirty = false; |
| return this; |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.Candlesticks"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.Candlesticks"] = true; |
| dojo.provide("dojox.charting.plot2d.Candlesticks"); |
| |
| |
| |
| |
| |
| |
| |
| |
| (function(){ |
| var df = dojox.lang.functional, du = dojox.lang.utils, |
| dc = dojox.charting.plot2d.common, |
| purgeGroup = df.lambda("item.purgeGroup()"); |
| |
| // Candlesticks are based on the Bars plot type; we expect the following passed |
| // as values in a series: |
| // { x?, open, close, high, low, mid? } |
| // if x is not provided, the array index is used. |
| // failing to provide the OHLC values will throw an error. |
| dojo.declare("dojox.charting.plot2d.Candlesticks", dojox.charting.plot2d.Base, { |
| defaultParams: { |
| hAxis: "x", // use a horizontal axis named "x" |
| vAxis: "y", // use a vertical axis named "y" |
| gap: 2, // gap between columns in pixels |
| shadows: null // draw shadows |
| }, |
| optionalParams: { |
| minBarSize: 1, // minimal bar size in pixels |
| maxBarSize: 1 // maximal bar size in pixels |
| }, |
| |
| constructor: function(chart, kwArgs){ |
| this.opt = dojo.clone(this.defaultParams); |
| du.updateWithObject(this.opt, kwArgs); |
| du.updateWithPattern(this.opt, kwArgs, this.optionalParams); |
| this.series = []; |
| this.hAxis = this.opt.hAxis; |
| this.vAxis = this.opt.vAxis; |
| }, |
| |
| collectStats: function(series){ |
| // we have to roll our own, since we need to use all four passed |
| // values to figure out our stats, and common only assumes x and y. |
| var stats = dojo.clone(dc.defaultStats); |
| for(var i=0; i<series.length; i++){ |
| var run = series[i]; |
| if(!run.data.length){ continue; } |
| var old_vmin = stats.vmin, old_vmax = stats.vmax; |
| if(!("ymin" in run) || !("ymax" in run)){ |
| dojo.forEach(run.data, function(val, idx){ |
| var x = val.x || idx + 1; |
| stats.hmin = Math.min(stats.hmin, x); |
| stats.hmax = Math.max(stats.hmax, x); |
| stats.vmin = Math.min(stats.vmin, val.open, val.close, val.high, val.low); |
| stats.vmax = Math.max(stats.vmax, val.open, val.close, val.high, val.low); |
| }); |
| } |
| if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); } |
| if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); } |
| } |
| return stats; |
| }, |
| |
| calculateAxes: function(dim){ |
| var stats = this.collectStats(this.series), t; |
| stats.hmin -= 0.5; |
| stats.hmax += 0.5; |
| this._calc(dim, stats); |
| return this; |
| }, |
| |
| render: function(dim, offsets){ |
| this.dirty = this.isDirty(); |
| if(this.dirty){ |
| dojo.forEach(this.series, purgeGroup); |
| this.cleanGroup(); |
| var s = this.group; |
| df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); |
| } |
| var t = this.chart.theme, color, stroke, fill, f, gap, width, |
| ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), |
| vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), |
| baseline = Math.max(0, this._vScaler.bounds.lower), |
| baselineHeight = vt(baseline), |
| events = this.events(); |
| f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt); |
| gap = f.gap; |
| width = f.size; |
| this.resetEvents(); |
| for(var i = this.series.length - 1; i >= 0; --i){ |
| var run = this.series[i]; |
| if(!this.dirty && !run.dirty){ continue; } |
| run.cleanGroup(); |
| var s = run.group; |
| if(!run.fill || !run.stroke){ |
| // need autogenerated color |
| color = run.dyn.color = new dojo.Color(t.next("color")); |
| } |
| stroke = run.stroke ? run.stroke : dc.augmentStroke(t.series.stroke, color); |
| fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); |
| |
| for(var j = 0; j < run.data.length; ++j){ |
| var v = run.data[j]; |
| |
| // calculate the points we need for OHLC |
| var x = ht(v.x || (j+0.5)) + offsets.l + gap, |
| y = dim.height - offsets.b, |
| open = vt(v.open), |
| close = vt(v.close), |
| high = vt(v.high), |
| low = vt(v.low); |
| if("mid" in v){ |
| var mid = vt(v.mid); |
| } |
| if(low > high){ |
| var tmp = high; |
| high = low; |
| low = tmp; |
| } |
| |
| if(width >= 1){ |
| // draw the line and rect, set up as a group and pass that to the events. |
| var doFill = open > close; |
| var line = { x1: width/2, x2: width/2, y1: y - high, y2: y - low }, |
| rect = { |
| x: 0, y: y-Math.max(open, close), |
| width: width, height: Math.max(doFill ? open-close : close-open, 1) |
| }; |
| shape = s.createGroup(); |
| shape.setTransform({dx: x, dy: 0 }); |
| var inner = shape.createGroup(); |
| inner.createLine(line).setStroke(stroke); |
| inner.createRect(rect).setStroke(stroke).setFill(doFill?fill:"white"); |
| if("mid" in v){ |
| // add the mid line. |
| inner.createLine({ x1: (stroke.width||1), x2: width-(stroke.width||1), y1: y - mid, y2: y - mid}) |
| .setStroke(doFill?{color:"white"}:stroke); |
| } |
| |
| // TODO: double check this. |
| run.dyn.fill = fill; |
| run.dyn.stroke = stroke; |
| if(events){ |
| var o = { |
| element: "candlestick", |
| index: j, |
| run: run, |
| plot: this, |
| hAxis: this.hAxis || null, |
| vAxis: this.vAxis || null, |
| shape: inner, |
| x: x, |
| y: y-Math.max(open, close), |
| cx: width/2, |
| cy: (y-Math.max(open, close)) + (Math.max(doFill ? open-close : close-open, 1)/2), |
| width: width, |
| height: Math.max(doFill ? open-close : close-open, 1), |
| data: v |
| }; |
| this._connectEvents(shape, o); |
| } |
| } |
| } |
| run.dirty = false; |
| } |
| this.dirty = false; |
| return this; |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.plot2d.OHLC"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.plot2d.OHLC"] = true; |
| dojo.provide("dojox.charting.plot2d.OHLC"); |
| |
| |
| |
| |
| |
| |
| |
| |
| (function(){ |
| var df = dojox.lang.functional, du = dojox.lang.utils, |
| dc = dojox.charting.plot2d.common, |
| purgeGroup = df.lambda("item.purgeGroup()"); |
| |
| // Candlesticks are based on the Bars plot type; we expect the following passed |
| // as values in a series: |
| // { x?, open, close, high, low } |
| // if x is not provided, the array index is used. |
| // failing to provide the OHLC values will throw an error. |
| dojo.declare("dojox.charting.plot2d.OHLC", dojox.charting.plot2d.Base, { |
| defaultParams: { |
| hAxis: "x", // use a horizontal axis named "x" |
| vAxis: "y", // use a vertical axis named "y" |
| gap: 2, // gap between columns in pixels |
| shadows: null // draw shadows |
| }, |
| optionalParams: { |
| minBarSize: 1, // minimal bar size in pixels |
| maxBarSize: 1 // maximal bar size in pixels |
| }, |
| |
| constructor: function(chart, kwArgs){ |
| this.opt = dojo.clone(this.defaultParams); |
| du.updateWithObject(this.opt, kwArgs); |
| du.updateWithPattern(this.opt, kwArgs, this.optionalParams); |
| this.series = []; |
| this.hAxis = this.opt.hAxis; |
| this.vAxis = this.opt.vAxis; |
| }, |
| |
| collectStats: function(series){ |
| // we have to roll our own, since we need to use all four passed |
| // values to figure out our stats, and common only assumes x and y. |
| var stats = dojo.clone(dc.defaultStats); |
| for(var i=0; i<series.length; i++){ |
| var run = series[i]; |
| if(!run.data.length){ continue; } |
| var old_vmin = stats.vmin, old_vmax = stats.vmax; |
| if(!("ymin" in run) || !("ymax" in run)){ |
| dojo.forEach(run.data, function(val, idx){ |
| var x = val.x || idx + 1; |
| stats.hmin = Math.min(stats.hmin, x); |
| stats.hmax = Math.max(stats.hmax, x); |
| stats.vmin = Math.min(stats.vmin, val.open, val.close, val.high, val.low); |
| stats.vmax = Math.max(stats.vmax, val.open, val.close, val.high, val.low); |
| }); |
| } |
| if("ymin" in run){ stats.vmin = Math.min(old_vmin, run.ymin); } |
| if("ymax" in run){ stats.vmax = Math.max(old_vmax, run.ymax); } |
| } |
| return stats; |
| }, |
| |
| calculateAxes: function(dim){ |
| var stats = this.collectStats(this.series), t; |
| stats.hmin -= 0.5; |
| stats.hmax += 0.5; |
| this._calc(dim, stats); |
| return this; |
| }, |
| |
| render: function(dim, offsets){ |
| this.dirty = this.isDirty(); |
| if(this.dirty){ |
| dojo.forEach(this.series, purgeGroup); |
| this.cleanGroup(); |
| var s = this.group; |
| df.forEachRev(this.series, function(item){ item.cleanGroup(s); }); |
| } |
| var t = this.chart.theme, color, stroke, fill, f, gap, width, |
| ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler), |
| vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler), |
| baseline = Math.max(0, this._vScaler.bounds.lower), |
| baselineHeight = vt(baseline), |
| events = this.events(); |
| f = dc.calculateBarSize(this._hScaler.bounds.scale, this.opt); |
| gap = f.gap; |
| width = f.size; |
| this.resetEvents(); |
| for(var i = this.series.length - 1; i >= 0; --i){ |
| var run = this.series[i]; |
| if(!this.dirty && !run.dirty){ continue; } |
| run.cleanGroup(); |
| var s = run.group; |
| if(!run.fill || !run.stroke){ |
| // need autogenerated color |
| color = run.dyn.color = new dojo.Color(t.next("color")); |
| } |
| // note that fill does not get used with this |
| stroke = run.stroke ? run.stroke : dc.augmentStroke(t.series.stroke, color); |
| fill = run.fill ? run.fill : dc.augmentFill(t.series.fill, color); |
| |
| for(var j = 0; j < run.data.length; ++j){ |
| var v = run.data[j]; |
| |
| // calculate the points we need for OHLC |
| var x = ht(v.x || (j+0.5)) + offsets.l + gap, |
| y = dim.height - offsets.b, |
| open = vt(v.open), |
| close = vt(v.close), |
| high = vt(v.high), |
| low = vt(v.low); |
| if(low > high){ |
| var tmp = high; |
| high = low; |
| low = tmp; |
| } |
| |
| if(width >= 1){ |
| var hl = { x1: width/2, x2: width/2, y1: y - high, y2: y - low }, |
| op = { x1: 0, x2: ((width/2) + ((stroke.width||1)/2)), y1: y-open, y2: y-open}, |
| cl = { x1: ((width/2) - ((stroke.width||1)/2)), x2: width, y1: y-close, y2: y-close }; |
| shape = s.createGroup(); |
| shape.setTransform({dx: x, dy: 0 }); |
| var inner = shape.createGroup(); |
| inner.createLine(hl).setStroke(stroke); |
| inner.createLine(op).setStroke(stroke); |
| inner.createLine(cl).setStroke(stroke); |
| |
| // TODO: double check this. |
| run.dyn.fill = fill; |
| run.dyn.stroke = stroke; |
| if(events){ |
| var o = { |
| element: "candlestick", |
| index: j, |
| run: run, |
| plot: this, |
| hAxis: this.hAxis || null, |
| vAxis: this.vAxis || null, |
| shape: inner, |
| x: x, |
| y: y-Math.max(open, close), |
| cx: width/2, |
| cy: (y-Math.max(open, close)) + (Math.max(open > close ? open-close : close-open, 1)/2), |
| width: width, |
| height: Math.max(open > close ? open-close : close-open, 1), |
| data: v |
| }; |
| this._connectEvents(shape, o); |
| } |
| } |
| } |
| run.dirty = false; |
| } |
| this.dirty = false; |
| return this; |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.Chart2D"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.Chart2D"] = true; |
| dojo.provide("dojox.charting.Chart2D"); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| // require all axes to support references by name |
| |
| |
| // require all plots to support references by name |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| (function(){ |
| var df = dojox.lang.functional, dc = dojox.charting, |
| clear = df.lambda("item.clear()"), |
| purge = df.lambda("item.purgeGroup()"), |
| destroy = df.lambda("item.destroy()"), |
| makeClean = df.lambda("item.dirty = false"), |
| makeDirty = df.lambda("item.dirty = true"); |
| |
| dojo.declare("dojox.charting.Chart2D", null, { |
| constructor: function(node, kwArgs){ |
| // initialize parameters |
| if(!kwArgs){ kwArgs = {}; } |
| this.margins = kwArgs.margins ? kwArgs.margins : {l: 10, t: 10, r: 10, b: 10}; |
| this.stroke = kwArgs.stroke; |
| this.fill = kwArgs.fill; |
| |
| // default initialization |
| this.theme = null; |
| this.axes = {}; // map of axes |
| this.stack = []; // stack of plotters |
| this.plots = {}; // map of plotter indices |
| this.series = []; // stack of data runs |
| this.runs = {}; // map of data run indices |
| this.dirty = true; |
| this.coords = null; |
| |
| // create a surface |
| this.node = dojo.byId(node); |
| var box = dojo.marginBox(node); |
| this.surface = dojox.gfx.createSurface(this.node, box.w, box.h); |
| }, |
| destroy: function(){ |
| dojo.forEach(this.series, destroy); |
| dojo.forEach(this.stack, destroy); |
| df.forIn(this.axes, destroy); |
| this.surface.destroy(); |
| }, |
| getCoords: function(){ |
| if(!this.coords){ |
| this.coords = dojo.coords(this.node, true); |
| } |
| return this.coords; |
| }, |
| setTheme: function(theme){ |
| this.theme = theme._clone(); |
| this.dirty = true; |
| return this; |
| }, |
| addAxis: function(name, kwArgs){ |
| var axis; |
| if(!kwArgs || !("type" in kwArgs)){ |
| axis = new dc.axis2d.Default(this, kwArgs); |
| }else{ |
| axis = typeof kwArgs.type == "string" ? |
| new dc.axis2d[kwArgs.type](this, kwArgs) : |
| new kwArgs.type(this, kwArgs); |
| } |
| axis.name = name; |
| axis.dirty = true; |
| if(name in this.axes){ |
| this.axes[name].destroy(); |
| } |
| this.axes[name] = axis; |
| this.dirty = true; |
| return this; |
| }, |
| getAxis: function(name){ |
| return this.axes[name]; |
| }, |
| removeAxis: function(name){ |
| if(name in this.axes){ |
| // destroy the axis |
| this.axes[name].destroy(); |
| delete this.axes[name]; |
| // mark the chart as dirty |
| this.dirty = true; |
| } |
| return this; // self |
| }, |
| addPlot: function(name, kwArgs){ |
| var plot; |
| if(!kwArgs || !("type" in kwArgs)){ |
| plot = new dc.plot2d.Default(this, kwArgs); |
| }else{ |
| plot = typeof kwArgs.type == "string" ? |
| new dc.plot2d[kwArgs.type](this, kwArgs) : |
| new kwArgs.type(this, kwArgs); |
| } |
| plot.name = name; |
| plot.dirty = true; |
| if(name in this.plots){ |
| this.stack[this.plots[name]].destroy(); |
| this.stack[this.plots[name]] = plot; |
| }else{ |
| this.plots[name] = this.stack.length; |
| this.stack.push(plot); |
| } |
| this.dirty = true; |
| return this; |
| }, |
| removePlot: function(name){ |
| if(name in this.plots){ |
| // get the index and remove the name |
| var index = this.plots[name]; |
| delete this.plots[name]; |
| // destroy the plot |
| this.stack[index].destroy(); |
| // remove the plot from the stack |
| this.stack.splice(index, 1); |
| // update indices to reflect the shift |
| df.forIn(this.plots, function(idx, name, plots){ |
| if(idx > index){ |
| plots[name] = idx - 1; |
| } |
| }); |
| // mark the chart as dirty |
| this.dirty = true; |
| } |
| return this; // self |
| }, |
| addSeries: function(name, data, kwArgs){ |
| var run = new dc.Series(this, data, kwArgs); |
| if(name in this.runs){ |
| this.series[this.runs[name]].destroy(); |
| this.series[this.runs[name]] = run; |
| }else{ |
| this.runs[name] = this.series.length; |
| this.series.push(run); |
| } |
| run.name = name; |
| this.dirty = true; |
| // fix min/max |
| if(!("ymin" in run) && "min" in run){ run.ymin = run.min; } |
| if(!("ymax" in run) && "max" in run){ run.ymax = run.max; } |
| return this; |
| }, |
| removeSeries: function(name){ |
| if(name in this.runs){ |
| // get the index and remove the name |
| var index = this.runs[name], |
| plotName = this.series[index].plot; |
| delete this.runs[name]; |
| // destroy the run |
| this.series[index].destroy(); |
| // remove the run from the stack of series |
| this.series.splice(index, 1); |
| // update indices to reflect the shift |
| df.forIn(this.runs, function(idx, name, runs){ |
| if(idx > index){ |
| runs[name] = idx - 1; |
| } |
| }); |
| this.dirty = true; |
| } |
| return this; // self |
| }, |
| updateSeries: function(name, data){ |
| if(name in this.runs){ |
| var run = this.series[this.runs[name]]; |
| run.data = data; |
| run.dirty = true; |
| this._invalidateDependentPlots(run.plot, false); |
| this._invalidateDependentPlots(run.plot, true); |
| } |
| return this; |
| }, |
| resize: function(width, height){ |
| var box; |
| switch(arguments.length){ |
| case 0: |
| box = dojo.marginBox(this.node); |
| break; |
| case 1: |
| box = width; |
| break; |
| default: |
| box = { w: width, h: height }; |
| break; |
| } |
| dojo.marginBox(this.node, box); |
| this.surface.setDimensions(box.w, box.h); |
| this.dirty = true; |
| this.coords = null; |
| return this.render(); |
| }, |
| getGeometry: function(){ |
| var ret = {}; |
| df.forIn(this.axes, function(axis){ |
| if(axis.initialized()){ |
| ret[axis.name] = { |
| name: axis.name, |
| vertical: axis.vertical, |
| scaler: axis.scaler, |
| ticks: axis.ticks |
| }; |
| } |
| }); |
| return ret; |
| }, |
| setAxisWindow: function(name, scale, offset){ |
| var axis = this.axes[name]; |
| if(axis){ |
| axis.setWindow(scale, offset); |
| } |
| return this; |
| }, |
| setWindow: function(sx, sy, dx, dy){ |
| if(!("plotArea" in this)){ |
| this.calculateGeometry(); |
| } |
| df.forIn(this.axes, function(axis){ |
| var scale, offset, bounds = axis.getScaler().bounds, |
| s = bounds.span / (bounds.upper - bounds.lower); |
| if(axis.vertical){ |
| scale = sy; |
| offset = dy / s / scale; |
| }else{ |
| scale = sx; |
| offset = dx / s / scale; |
| } |
| axis.setWindow(scale, offset); |
| }); |
| return this; |
| }, |
| calculateGeometry: function(){ |
| if(this.dirty){ |
| return this.fullGeometry(); |
| } |
| |
| // calculate geometry |
| dojo.forEach(this.stack, function(plot){ |
| if( plot.dirty || |
| (plot.hAxis && this.axes[plot.hAxis].dirty) || |
| (plot.vAxis && this.axes[plot.vAxis].dirty) |
| ){ |
| plot.calculateAxes(this.plotArea); |
| } |
| }, this); |
| |
| return this; |
| }, |
| fullGeometry: function(){ |
| this._makeDirty(); |
| |
| // clear old values |
| dojo.forEach(this.stack, clear); |
| |
| // rebuild new connections, and add defaults |
| |
| // set up a theme |
| if(!this.theme){ |
| this.setTheme(new dojox.charting.Theme(dojox.charting._def)); |
| } |
| |
| // assign series |
| dojo.forEach(this.series, function(run){ |
| if(!(run.plot in this.plots)){ |
| var plot = new dc.plot2d.Default(this, {}); |
| plot.name = run.plot; |
| this.plots[run.plot] = this.stack.length; |
| this.stack.push(plot); |
| } |
| this.stack[this.plots[run.plot]].addSeries(run); |
| }, this); |
| // assign axes |
| dojo.forEach(this.stack, function(plot){ |
| if(plot.hAxis){ |
| plot.setAxis(this.axes[plot.hAxis]); |
| } |
| if(plot.vAxis){ |
| plot.setAxis(this.axes[plot.vAxis]); |
| } |
| }, this); |
| |
| // calculate geometry |
| |
| // 1st pass |
| var dim = this.dim = this.surface.getDimensions(); |
| dim.width = dojox.gfx.normalizedLength(dim.width); |
| dim.height = dojox.gfx.normalizedLength(dim.height); |
| df.forIn(this.axes, clear); |
| dojo.forEach(this.stack, function(p){ p.calculateAxes(dim); }); |
| |
| // assumption: we don't have stacked axes yet |
| var offsets = this.offsets = { l: 0, r: 0, t: 0, b: 0 }; |
| df.forIn(this.axes, function(axis){ |
| df.forIn(axis.getOffsets(), function(o, i){ offsets[i] += o; }); |
| }); |
| // add margins |
| df.forIn(this.margins, function(o, i){ offsets[i] += o; }); |
| |
| // 2nd pass with realistic dimensions |
| this.plotArea = { |
| width: dim.width - offsets.l - offsets.r, |
| height: dim.height - offsets.t - offsets.b |
| }; |
| df.forIn(this.axes, clear); |
| dojo.forEach(this.stack, function(plot){ plot.calculateAxes(this.plotArea); }, this); |
| |
| return this; |
| }, |
| render: function(){ |
| if(this.theme){ |
| this.theme.clear(); |
| } |
| |
| if(this.dirty){ |
| return this.fullRender(); |
| } |
| |
| this.calculateGeometry(); |
| |
| // go over the stack backwards |
| df.forEachRev(this.stack, function(plot){ plot.render(this.dim, this.offsets); }, this); |
| |
| // go over axes |
| df.forIn(this.axes, function(axis){ axis.render(this.dim, this.offsets); }, this); |
| |
| this._makeClean(); |
| |
| // BEGIN FOR HTML CANVAS |
| if(this.surface.render){ this.surface.render(); }; |
| // END FOR HTML CANVAS |
| |
| return this; |
| }, |
| fullRender: function(){ |
| // calculate geometry |
| this.fullGeometry(); |
| var offsets = this.offsets, dim = this.dim; |
| |
| // get required colors |
| var requiredColors = df.foldl(this.stack, "z + plot.getRequiredColors()", 0); |
| this.theme.defineColors({num: requiredColors, cache: false}); |
| |
| // clear old shapes |
| dojo.forEach(this.series, purge); |
| df.forIn(this.axes, purge); |
| dojo.forEach(this.stack, purge); |
| this.surface.clear(); |
| |
| // generate shapes |
| |
| // draw a plot background |
| var t = this.theme, |
| fill = t.plotarea && t.plotarea.fill, |
| stroke = t.plotarea && t.plotarea.stroke; |
| if(fill){ |
| this.surface.createRect({ |
| x: offsets.l, y: offsets.t, |
| width: dim.width - offsets.l - offsets.r, |
| height: dim.height - offsets.t - offsets.b |
| }).setFill(fill); |
| } |
| if(stroke){ |
| this.surface.createRect({ |
| x: offsets.l, y: offsets.t, |
| width: dim.width - offsets.l - offsets.r - 1, |
| height: dim.height - offsets.t - offsets.b - 1 |
| }).setStroke(stroke); |
| } |
| |
| // go over the stack backwards |
| df.foldr(this.stack, function(z, plot){ return plot.render(dim, offsets), 0; }, 0); |
| |
| // pseudo-clipping: matting |
| fill = this.fill ? this.fill : (t.chart && t.chart.fill); |
| stroke = this.stroke ? this.stroke : (t.chart && t.chart.stroke); |
| |
| // TRT: support for "inherit" as a named value in a theme. |
| if(fill == "inherit"){ |
| // find the background color of the nearest ancestor node, and use that explicitly. |
| var node = this.node, fill = new dojo.Color(dojo.style(node, "backgroundColor")); |
| while(fill.a==0 && node!=document.documentElement){ |
| fill = new dojo.Color(dojo.style(node, "backgroundColor")); |
| node = node.parentNode; |
| } |
| } |
| |
| if(fill){ |
| if(offsets.l){ // left |
| this.surface.createRect({ |
| width: offsets.l, |
| height: dim.height + 1 |
| }).setFill(fill); |
| } |
| if(offsets.r){ // right |
| this.surface.createRect({ |
| x: dim.width - offsets.r, |
| width: offsets.r + 1, |
| height: dim.height + 1 |
| }).setFill(fill); |
| } |
| if(offsets.t){ // top |
| this.surface.createRect({ |
| width: dim.width + 1, |
| height: offsets.t |
| }).setFill(fill); |
| } |
| if(offsets.b){ // bottom |
| this.surface.createRect({ |
| y: dim.height - offsets.b, |
| width: dim.width + 1, |
| height: offsets.b + 2 |
| }).setFill(fill); |
| } |
| } |
| if(stroke){ |
| this.surface.createRect({ |
| width: dim.width - 1, |
| height: dim.height - 1 |
| }).setStroke(stroke); |
| } |
| |
| // go over axes |
| df.forIn(this.axes, function(axis){ axis.render(dim, offsets); }); |
| |
| this._makeClean(); |
| |
| // BEGIN FOR HTML CANVAS |
| if(this.surface.render){ this.surface.render(); }; |
| // END FOR HTML CANVAS |
| |
| return this; |
| }, |
| connectToPlot: function(name, object, method){ |
| return name in this.plots ? this.stack[this.plots[name]].connect(object, method) : null; |
| }, |
| _makeClean: function(){ |
| // reset dirty flags |
| dojo.forEach(this.axes, makeClean); |
| dojo.forEach(this.stack, makeClean); |
| dojo.forEach(this.series, makeClean); |
| this.dirty = false; |
| }, |
| _makeDirty: function(){ |
| // reset dirty flags |
| dojo.forEach(this.axes, makeDirty); |
| dojo.forEach(this.stack, makeDirty); |
| dojo.forEach(this.series, makeDirty); |
| this.dirty = true; |
| }, |
| _invalidateDependentPlots: function(plotName, /* Boolean */ verticalAxis){ |
| if(plotName in this.plots){ |
| var plot = this.stack[this.plots[plotName]], axis, |
| axisName = verticalAxis ? "vAxis" : "hAxis"; |
| if(plot[axisName]){ |
| axis = this.axes[plot[axisName]]; |
| if(axis && axis.dependOnData()){ |
| axis.dirty = true; |
| // find all plots and mark them dirty |
| dojo.forEach(this.stack, function(p){ |
| if(p[axisName] && p[axisName] == plot[axisName]){ |
| p.dirty = true; |
| } |
| }); |
| } |
| }else{ |
| plot.dirty = true; |
| } |
| } |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojo.fx.easing"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo.fx.easing"] = true; |
| dojo.provide("dojo.fx.easing"); |
| |
| dojo.fx.easing = { |
| // summary: |
| // Collection of easing functions to use beyond the default |
| // `dojo._defaultEasing` function. |
| // |
| // description: |
| // |
| // Easing functions are used to manipulate the iteration through |
| // an `dojo.Animation`s _Line. _Line being the properties of an Animation, |
| // and the easing function progresses through that Line determing |
| // how quickly (or slowly) it should go. Or more accurately: modify |
| // the value of the _Line based on the percentage of animation completed. |
| // |
| // All functions follow a simple naming convention of "ease type" + "when". |
| // If the name of the function ends in Out, the easing described appears |
| // towards the end of the animation. "In" means during the beginning, |
| // and InOut means both ranges of the Animation will applied, both |
| // beginning and end. |
| // |
| // One does not call the easing function directly, it must be passed to |
| // the `easing` property of an animation. |
| // |
| // example: |
| // | |
| // | var anim = dojo.fadeOut({ |
| // | node: 'node', |
| // | duration: 2000, |
| // | // note there is no () |
| // | easing: dojo.fx.easing.quadIn |
| // | }).play(); |
| // |
| |
| linear: function(/* Decimal? */n){ |
| // summary: A linear easing function |
| return n; |
| }, |
| |
| quadIn: function(/* Decimal? */n){ |
| return Math.pow(n, 2); |
| }, |
| |
| quadOut: function(/* Decimal? */n){ |
| return n * (n - 2) * -1; |
| }, |
| |
| quadInOut: function(/* Decimal? */n){ |
| n = n * 2; |
| if(n < 1){ return Math.pow(n, 2) / 2; } |
| return -1 * ((--n) * (n - 2) - 1) / 2; |
| }, |
| |
| cubicIn: function(/* Decimal? */n){ |
| return Math.pow(n, 3); |
| }, |
| |
| cubicOut: function(/* Decimal? */n){ |
| return Math.pow(n - 1, 3) + 1; |
| }, |
| |
| cubicInOut: function(/* Decimal? */n){ |
| n = n * 2; |
| if(n < 1){ return Math.pow(n, 3) / 2; } |
| n -= 2; |
| return (Math.pow(n, 3) + 2) / 2; |
| }, |
| |
| quartIn: function(/* Decimal? */n){ |
| return Math.pow(n, 4); |
| }, |
| |
| quartOut: function(/* Decimal? */n){ |
| return -1 * (Math.pow(n - 1, 4) - 1); |
| }, |
| |
| quartInOut: function(/* Decimal? */n){ |
| n = n * 2; |
| if(n < 1){ return Math.pow(n, 4) / 2; } |
| n -= 2; |
| return -1 / 2 * (Math.pow(n, 4) - 2); |
| }, |
| |
| quintIn: function(/* Decimal? */n){ |
| return Math.pow(n, 5); |
| }, |
| |
| quintOut: function(/* Decimal? */n){ |
| return Math.pow(n - 1, 5) + 1; |
| }, |
| |
| quintInOut: function(/* Decimal? */n){ |
| n = n * 2; |
| if(n < 1){ return Math.pow(n, 5) / 2; }; |
| n -= 2; |
| return (Math.pow(n, 5) + 2) / 2; |
| }, |
| |
| sineIn: function(/* Decimal? */n){ |
| return -1 * Math.cos(n * (Math.PI / 2)) + 1; |
| }, |
| |
| sineOut: function(/* Decimal? */n){ |
| return Math.sin(n * (Math.PI / 2)); |
| }, |
| |
| sineInOut: function(/* Decimal? */n){ |
| return -1 * (Math.cos(Math.PI * n) - 1) / 2; |
| }, |
| |
| expoIn: function(/* Decimal? */n){ |
| return (n == 0) ? 0 : Math.pow(2, 10 * (n - 1)); |
| }, |
| |
| expoOut: function(/* Decimal? */n){ |
| return (n == 1) ? 1 : (-1 * Math.pow(2, -10 * n) + 1); |
| }, |
| |
| expoInOut: function(/* Decimal? */n){ |
| if(n == 0){ return 0; } |
| if(n == 1){ return 1; } |
| n = n * 2; |
| if(n < 1){ return Math.pow(2, 10 * (n - 1)) / 2; } |
| --n; |
| return (-1 * Math.pow(2, -10 * n) + 2) / 2; |
| }, |
| |
| circIn: function(/* Decimal? */n){ |
| return -1 * (Math.sqrt(1 - Math.pow(n, 2)) - 1); |
| }, |
| |
| circOut: function(/* Decimal? */n){ |
| n = n - 1; |
| return Math.sqrt(1 - Math.pow(n, 2)); |
| }, |
| |
| circInOut: function(/* Decimal? */n){ |
| n = n * 2; |
| if(n < 1){ return -1 / 2 * (Math.sqrt(1 - Math.pow(n, 2)) - 1); } |
| n -= 2; |
| return 1 / 2 * (Math.sqrt(1 - Math.pow(n, 2)) + 1); |
| }, |
| |
| backIn: function(/* Decimal? */n){ |
| // summary: |
| // An easing function that starts away from the target, |
| // and quickly accelerates towards the end value. |
| // |
| // Use caution when the easing will cause values to become |
| // negative as some properties cannot be set to negative values. |
| var s = 1.70158; |
| return Math.pow(n, 2) * ((s + 1) * n - s); |
| }, |
| |
| backOut: function(/* Decimal? */n){ |
| // summary: |
| // An easing function that pops past the range briefly, and slowly comes back. |
| // |
| // description: |
| // An easing function that pops past the range briefly, and slowly comes back. |
| // |
| // Use caution when the easing will cause values to become negative as some |
| // properties cannot be set to negative values. |
| |
| n = n - 1; |
| var s = 1.70158; |
| return Math.pow(n, 2) * ((s + 1) * n + s) + 1; |
| }, |
| |
| backInOut: function(/* Decimal? */n){ |
| // summary: |
| // An easing function combining the effects of `backIn` and `backOut` |
| // |
| // description: |
| // An easing function combining the effects of `backIn` and `backOut`. |
| // Use caution when the easing will cause values to become negative |
| // as some properties cannot be set to negative values. |
| var s = 1.70158 * 1.525; |
| n = n * 2; |
| if(n < 1){ return (Math.pow(n, 2) * ((s + 1) * n - s)) / 2; } |
| n-=2; |
| return (Math.pow(n, 2) * ((s + 1) * n + s) + 2) / 2; |
| }, |
| |
| elasticIn: function(/* Decimal? */n){ |
| // summary: |
| // An easing function the elastically snaps from the start value |
| // |
| // description: |
| // An easing function the elastically snaps from the start value |
| // |
| // Use caution when the elasticity will cause values to become negative |
| // as some properties cannot be set to negative values. |
| if(n == 0 || n == 1){ return n; } |
| var p = .3; |
| var s = p / 4; |
| n = n - 1; |
| return -1 * Math.pow(2, 10 * n) * Math.sin((n - s) * (2 * Math.PI) / p); |
| }, |
| |
| elasticOut: function(/* Decimal? */n){ |
| // summary: |
| // An easing function that elasticly snaps around the target value, |
| // near the end of the Animation |
| // |
| // description: |
| // An easing function that elasticly snaps around the target value, |
| // near the end of the Animation |
| // |
| // Use caution when the elasticity will cause values to become |
| // negative as some properties cannot be set to negative values. |
| if(n==0 || n == 1){ return n; } |
| var p = .3; |
| var s = p / 4; |
| return Math.pow(2, -10 * n) * Math.sin((n - s) * (2 * Math.PI) / p) + 1; |
| }, |
| |
| elasticInOut: function(/* Decimal? */n){ |
| // summary: |
| // An easing function that elasticly snaps around the value, near |
| // the beginning and end of the Animation. |
| // |
| // description: |
| // An easing function that elasticly snaps around the value, near |
| // the beginning and end of the Animation. |
| // |
| // Use caution when the elasticity will cause values to become |
| // negative as some properties cannot be set to negative values. |
| if(n == 0) return 0; |
| n = n * 2; |
| if(n == 2) return 1; |
| var p = .3 * 1.5; |
| var s = p / 4; |
| if(n < 1){ |
| n -= 1; |
| return -.5 * (Math.pow(2, 10 * n) * Math.sin((n - s) * (2 * Math.PI) / p)); |
| } |
| n -= 1; |
| return .5 * (Math.pow(2, -10 * n) * Math.sin((n - s) * (2 * Math.PI) / p)) + 1; |
| }, |
| |
| bounceIn: function(/* Decimal? */n){ |
| // summary: |
| // An easing function that 'bounces' near the beginning of an Animation |
| return (1 - dojo.fx.easing.bounceOut(1 - n)); // Decimal |
| }, |
| |
| bounceOut: function(/* Decimal? */n){ |
| // summary: |
| // An easing function that 'bounces' near the end of an Animation |
| var s = 7.5625; |
| var p = 2.75; |
| var l; |
| if(n < (1 / p)){ |
| l = s * Math.pow(n, 2); |
| }else if(n < (2 / p)){ |
| n -= (1.5 / p); |
| l = s * Math.pow(n, 2) + .75; |
| }else if(n < (2.5 / p)){ |
| n -= (2.25 / p); |
| l = s * Math.pow(n, 2) + .9375; |
| }else{ |
| n -= (2.625 / p); |
| l = s * Math.pow(n, 2) + .984375; |
| } |
| return l; |
| }, |
| |
| bounceInOut: function(/* Decimal? */n){ |
| // summary: |
| // An easing function that 'bounces' at the beginning and end of the Animation |
| if(n < 0.5){ return dojo.fx.easing.bounceIn(n * 2) / 2; } |
| return (dojo.fx.easing.bounceOut(n * 2 - 1) / 2) + 0.5; // Decimal |
| } |
| }; |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.action2d.Base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.action2d.Base"] = true; |
| dojo.provide("dojox.charting.action2d.Base"); |
| |
| |
| |
| |
| |
| (function(){ |
| var DEFAULT_DURATION = 400, // ms |
| DEFAULT_EASING = dojo.fx.easing.backOut, |
| df = dojox.lang.functional; |
| |
| dojo.declare("dojox.charting.action2d.Base", null, { |
| |
| overOutEvents: {onmouseover: 1, onmouseout: 1}, |
| |
| constructor: function(chart, plot, kwargs){ |
| this.chart = chart; |
| this.plot = plot ? plot : "default"; |
| this.anim = {}; |
| |
| // process common optional named parameters |
| if(!kwargs){ kwargs = {}; } |
| this.duration = kwargs.duration ? kwargs.duration : DEFAULT_DURATION; |
| this.easing = kwargs.easing ? kwargs.easing : DEFAULT_EASING; |
| }, |
| |
| connect: function(){ |
| this.handle = this.chart.connectToPlot(this.plot, this, "process"); |
| }, |
| |
| disconnect: function(){ |
| if(this.handle){ |
| dojo.disconnect(this.handle); |
| this.handle = null; |
| } |
| }, |
| |
| reset: function(){ |
| // nothing by default |
| }, |
| |
| destroy: function(){ |
| if(this.handle){ |
| this.disconnect(); |
| } |
| df.forIn(this.anim, function(o){ |
| df.forIn(o, function(anim){ |
| anim.action.stop(true); |
| }); |
| }); |
| this.anim = {}; |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.action2d.Highlight"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.action2d.Highlight"] = true; |
| dojo.provide("dojox.charting.action2d.Highlight"); |
| |
| |
| |
| |
| (function(){ |
| var DEFAULT_SATURATION = 100, // % |
| DEFAULT_LUMINOSITY1 = 75, // % |
| DEFAULT_LUMINOSITY2 = 50, // % |
| |
| c = dojox.color, |
| |
| cc = function(color){ |
| return function(){ return color; }; |
| }, |
| |
| hl = function(color){ |
| var a = new c.Color(color), |
| x = a.toHsl(); |
| if(x.s == 0){ |
| x.l = x.l < 50 ? 100 : 0; |
| }else{ |
| x.s = DEFAULT_SATURATION; |
| if(x.l < DEFAULT_LUMINOSITY2){ |
| x.l = DEFAULT_LUMINOSITY1; |
| }else if(x.l > DEFAULT_LUMINOSITY1){ |
| x.l = DEFAULT_LUMINOSITY2; |
| }else{ |
| x.l = x.l - DEFAULT_LUMINOSITY2 > DEFAULT_LUMINOSITY1 - x.l ? |
| DEFAULT_LUMINOSITY2 : DEFAULT_LUMINOSITY1; |
| } |
| } |
| return c.fromHsl(x); |
| }; |
| |
| dojo.declare("dojox.charting.action2d.Highlight", dojox.charting.action2d.Base, { |
| // the data description block for the widget parser |
| defaultParams: { |
| duration: 400, // duration of the action in ms |
| easing: dojo.fx.easing.backOut // easing for the action |
| }, |
| optionalParams: { |
| highlight: "red" // name for the highlight color |
| // programmatic instantiation can use functions and color objects |
| }, |
| |
| constructor: function(chart, plot, kwArgs){ |
| // process optional named parameters |
| var a = kwArgs && kwArgs.highlight; |
| this.colorFun = a ? (dojo.isFunction(a) ? a : cc(a)) : hl; |
| |
| this.connect(); |
| }, |
| |
| process: function(o){ |
| if(!o.shape || !(o.type in this.overOutEvents)){ return; } |
| |
| var runName = o.run.name, index = o.index, anim, startFill, endFill; |
| |
| if(runName in this.anim){ |
| anim = this.anim[runName][index]; |
| }else{ |
| this.anim[runName] = {}; |
| } |
| |
| if(anim){ |
| anim.action.stop(true); |
| }else{ |
| var color = o.shape.getFill(); |
| if(!color || !(color instanceof dojo.Color)){ |
| return; |
| } |
| this.anim[runName][index] = anim = { |
| start: color, |
| end: this.colorFun(color) |
| }; |
| } |
| |
| var start = anim.start, end = anim.end; |
| if(o.type == "onmouseout"){ |
| // swap colors |
| var t = start; |
| start = end; |
| end = t; |
| } |
| |
| anim.action = dojox.gfx.fx.animateFill({ |
| shape: o.shape, |
| duration: this.duration, |
| easing: this.easing, |
| color: {start: start, end: end} |
| }); |
| if(o.type == "onmouseout"){ |
| dojo.connect(anim.action, "onEnd", this, function(){ |
| if(this.anim[runName]){ |
| delete this.anim[runName][index]; |
| } |
| }); |
| } |
| anim.action.play(); |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojo.fx.Toggler"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo.fx.Toggler"] = true; |
| dojo.provide("dojo.fx.Toggler"); |
| |
| dojo.declare("dojo.fx.Toggler", null, { |
| // summary: |
| // A simple `dojo.Animation` toggler API. |
| // |
| // description: |
| // class constructor for an animation toggler. It accepts a packed |
| // set of arguments about what type of animation to use in each |
| // direction, duration, etc. All available members are mixed into |
| // these animations from the constructor (for example, `node`, |
| // `showDuration`, `hideDuration`). |
| // |
| // example: |
| // | var t = new dojo.fx.Toggler({ |
| // | node: "nodeId", |
| // | showDuration: 500, |
| // | // hideDuration will default to "200" |
| // | showFunc: dojo.fx.wipeIn, |
| // | // hideFunc will default to "fadeOut" |
| // | }); |
| // | t.show(100); // delay showing for 100ms |
| // | // ...time passes... |
| // | t.hide(); |
| |
| // node: DomNode |
| // the node to target for the showing and hiding animations |
| node: null, |
| |
| // showFunc: Function |
| // The function that returns the `dojo.Animation` to show the node |
| showFunc: dojo.fadeIn, |
| |
| // hideFunc: Function |
| // The function that returns the `dojo.Animation` to hide the node |
| hideFunc: dojo.fadeOut, |
| |
| // showDuration: |
| // Time in milliseconds to run the show Animation |
| showDuration: 200, |
| |
| // hideDuration: |
| // Time in milliseconds to run the hide Animation |
| hideDuration: 200, |
| |
| // FIXME: need a policy for where the toggler should "be" the next |
| // time show/hide are called if we're stopped somewhere in the |
| // middle. |
| // FIXME: also would be nice to specify individual showArgs/hideArgs mixed into |
| // each animation individually. |
| // FIXME: also would be nice to have events from the animations exposed/bridged |
| |
| /*===== |
| _showArgs: null, |
| _showAnim: null, |
| |
| _hideArgs: null, |
| _hideAnim: null, |
| |
| _isShowing: false, |
| _isHiding: false, |
| =====*/ |
| |
| constructor: function(args){ |
| var _t = this; |
| |
| dojo.mixin(_t, args); |
| _t.node = args.node; |
| _t._showArgs = dojo.mixin({}, args); |
| _t._showArgs.node = _t.node; |
| _t._showArgs.duration = _t.showDuration; |
| _t.showAnim = _t.showFunc(_t._showArgs); |
| |
| _t._hideArgs = dojo.mixin({}, args); |
| _t._hideArgs.node = _t.node; |
| _t._hideArgs.duration = _t.hideDuration; |
| _t.hideAnim = _t.hideFunc(_t._hideArgs); |
| |
| dojo.connect(_t.showAnim, "beforeBegin", dojo.hitch(_t.hideAnim, "stop", true)); |
| dojo.connect(_t.hideAnim, "beforeBegin", dojo.hitch(_t.showAnim, "stop", true)); |
| }, |
| |
| show: function(delay){ |
| // summary: Toggle the node to showing |
| // delay: Integer? |
| // Ammount of time to stall playing the show animation |
| return this.showAnim.play(delay || 0); |
| }, |
| |
| hide: function(delay){ |
| // summary: Toggle the node to hidden |
| // delay: Integer? |
| // Ammount of time to stall playing the hide animation |
| return this.hideAnim.play(delay || 0); |
| } |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dojo.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo.fx"] = true; |
| dojo.provide("dojo.fx"); |
| // FIXME: remove this back-compat require in 2.0 |
| /*===== |
| dojo.fx = { |
| // summary: Effects library on top of Base animations |
| }; |
| =====*/ |
| (function(){ |
| |
| var d = dojo, |
| _baseObj = { |
| _fire: function(evt, args){ |
| if(this[evt]){ |
| this[evt].apply(this, args||[]); |
| } |
| return this; |
| } |
| }; |
| |
| var _chain = function(animations){ |
| this._index = -1; |
| this._animations = animations||[]; |
| this._current = this._onAnimateCtx = this._onEndCtx = null; |
| |
| this.duration = 0; |
| d.forEach(this._animations, function(a){ |
| this.duration += a.duration; |
| if(a.delay){ this.duration += a.delay; } |
| }, this); |
| }; |
| d.extend(_chain, { |
| _onAnimate: function(){ |
| this._fire("onAnimate", arguments); |
| }, |
| _onEnd: function(){ |
| d.disconnect(this._onAnimateCtx); |
| d.disconnect(this._onEndCtx); |
| this._onAnimateCtx = this._onEndCtx = null; |
| if(this._index + 1 == this._animations.length){ |
| this._fire("onEnd"); |
| }else{ |
| // switch animations |
| this._current = this._animations[++this._index]; |
| this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate"); |
| this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd"); |
| this._current.play(0, true); |
| } |
| }, |
| play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){ |
| if(!this._current){ this._current = this._animations[this._index = 0]; } |
| if(!gotoStart && this._current.status() == "playing"){ return this; } |
| var beforeBegin = d.connect(this._current, "beforeBegin", this, function(){ |
| this._fire("beforeBegin"); |
| }), |
| onBegin = d.connect(this._current, "onBegin", this, function(arg){ |
| this._fire("onBegin", arguments); |
| }), |
| onPlay = d.connect(this._current, "onPlay", this, function(arg){ |
| this._fire("onPlay", arguments); |
| d.disconnect(beforeBegin); |
| d.disconnect(onBegin); |
| d.disconnect(onPlay); |
| }); |
| if(this._onAnimateCtx){ |
| d.disconnect(this._onAnimateCtx); |
| } |
| this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate"); |
| if(this._onEndCtx){ |
| d.disconnect(this._onEndCtx); |
| } |
| this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd"); |
| this._current.play.apply(this._current, arguments); |
| return this; |
| }, |
| pause: function(){ |
| if(this._current){ |
| var e = d.connect(this._current, "onPause", this, function(arg){ |
| this._fire("onPause", arguments); |
| d.disconnect(e); |
| }); |
| this._current.pause(); |
| } |
| return this; |
| }, |
| gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){ |
| this.pause(); |
| var offset = this.duration * percent; |
| this._current = null; |
| d.some(this._animations, function(a){ |
| if(a.duration <= offset){ |
| this._current = a; |
| return true; |
| } |
| offset -= a.duration; |
| return false; |
| }); |
| if(this._current){ |
| this._current.gotoPercent(offset / this._current.duration, andPlay); |
| } |
| return this; |
| }, |
| stop: function(/*boolean?*/ gotoEnd){ |
| if(this._current){ |
| if(gotoEnd){ |
| for(; this._index + 1 < this._animations.length; ++this._index){ |
| this._animations[this._index].stop(true); |
| } |
| this._current = this._animations[this._index]; |
| } |
| var e = d.connect(this._current, "onStop", this, function(arg){ |
| this._fire("onStop", arguments); |
| d.disconnect(e); |
| }); |
| this._current.stop(); |
| } |
| return this; |
| }, |
| status: function(){ |
| return this._current ? this._current.status() : "stopped"; |
| }, |
| destroy: function(){ |
| if(this._onAnimateCtx){ d.disconnect(this._onAnimateCtx); } |
| if(this._onEndCtx){ d.disconnect(this._onEndCtx); } |
| } |
| }); |
| d.extend(_chain, _baseObj); |
| |
| dojo.fx.chain = function(/*dojo.Animation[]*/ animations){ |
| // summary: |
| // Chain a list of `dojo.Animation`s to run in sequence |
| // |
| // description: |
| // Return a `dojo.Animation` which will play all passed |
| // `dojo.Animation` instances in sequence, firing its own |
| // synthesized events simulating a single animation. (eg: |
| // onEnd of this animation means the end of the chain, |
| // not the individual animations within) |
| // |
| // example: |
| // Once `node` is faded out, fade in `otherNode` |
| // | dojo.fx.chain([ |
| // | dojo.fadeIn({ node:node }), |
| // | dojo.fadeOut({ node:otherNode }) |
| // | ]).play(); |
| // |
| return new _chain(animations) // dojo.Animation |
| }; |
| |
| var _combine = function(animations){ |
| this._animations = animations||[]; |
| this._connects = []; |
| this._finished = 0; |
| |
| this.duration = 0; |
| d.forEach(animations, function(a){ |
| var duration = a.duration; |
| if(a.delay){ duration += a.delay; } |
| if(this.duration < duration){ this.duration = duration; } |
| this._connects.push(d.connect(a, "onEnd", this, "_onEnd")); |
| }, this); |
| |
| this._pseudoAnimation = new d.Animation({curve: [0, 1], duration: this.duration}); |
| var self = this; |
| d.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop", "onEnd"], |
| function(evt){ |
| self._connects.push(d.connect(self._pseudoAnimation, evt, |
| function(){ self._fire(evt, arguments); } |
| )); |
| } |
| ); |
| }; |
| d.extend(_combine, { |
| _doAction: function(action, args){ |
| d.forEach(this._animations, function(a){ |
| a[action].apply(a, args); |
| }); |
| return this; |
| }, |
| _onEnd: function(){ |
| if(++this._finished > this._animations.length){ |
| this._fire("onEnd"); |
| } |
| }, |
| _call: function(action, args){ |
| var t = this._pseudoAnimation; |
| t[action].apply(t, args); |
| }, |
| play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){ |
| this._finished = 0; |
| this._doAction("play", arguments); |
| this._call("play", arguments); |
| return this; |
| }, |
| pause: function(){ |
| this._doAction("pause", arguments); |
| this._call("pause", arguments); |
| return this; |
| }, |
| gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){ |
| var ms = this.duration * percent; |
| d.forEach(this._animations, function(a){ |
| a.gotoPercent(a.duration < ms ? 1 : (ms / a.duration), andPlay); |
| }); |
| this._call("gotoPercent", arguments); |
| return this; |
| }, |
| stop: function(/*boolean?*/ gotoEnd){ |
| this._doAction("stop", arguments); |
| this._call("stop", arguments); |
| return this; |
| }, |
| status: function(){ |
| return this._pseudoAnimation.status(); |
| }, |
| destroy: function(){ |
| d.forEach(this._connects, dojo.disconnect); |
| } |
| }); |
| d.extend(_combine, _baseObj); |
| |
| dojo.fx.combine = function(/*dojo.Animation[]*/ animations){ |
| // summary: |
| // Combine a list of `dojo.Animation`s to run in parallel |
| // |
| // description: |
| // Combine an array of `dojo.Animation`s to run in parallel, |
| // providing a new `dojo.Animation` instance encompasing each |
| // animation, firing standard animation events. |
| // |
| // example: |
| // Fade out `node` while fading in `otherNode` simultaneously |
| // | dojo.fx.combine([ |
| // | dojo.fadeIn({ node:node }), |
| // | dojo.fadeOut({ node:otherNode }) |
| // | ]).play(); |
| // |
| // example: |
| // When the longest animation ends, execute a function: |
| // | var anim = dojo.fx.combine([ |
| // | dojo.fadeIn({ node: n, duration:700 }), |
| // | dojo.fadeOut({ node: otherNode, duration: 300 }) |
| // | ]); |
| // | dojo.connect(anim, "onEnd", function(){ |
| // | // overall animation is done. |
| // | }); |
| // | anim.play(); // play the animation |
| // |
| return new _combine(animations); // dojo.Animation |
| }; |
| |
| dojo.fx.wipeIn = function(/*Object*/ args){ |
| // summary: |
| // Expand a node to it's natural height. |
| // |
| // description: |
| // Returns an animation that will expand the |
| // node defined in 'args' object from it's current height to |
| // it's natural height (with no scrollbar). |
| // Node must have no margin/border/padding. |
| // |
| // args: Object |
| // A hash-map of standard `dojo.Animation` constructor properties |
| // (such as easing: node: duration: and so on) |
| // |
| // example: |
| // | dojo.fx.wipeIn({ |
| // | node:"someId" |
| // | }).play() |
| var node = args.node = d.byId(args.node), s = node.style, o; |
| |
| var anim = d.animateProperty(d.mixin({ |
| properties: { |
| height: { |
| // wrapped in functions so we wait till the last second to query (in case value has changed) |
| start: function(){ |
| // start at current [computed] height, but use 1px rather than 0 |
| // because 0 causes IE to display the whole panel |
| o = s.overflow; |
| s.overflow = "hidden"; |
| if(s.visibility == "hidden" || s.display == "none"){ |
| s.height = "1px"; |
| s.display = ""; |
| s.visibility = ""; |
| return 1; |
| }else{ |
| var height = d.style(node, "height"); |
| return Math.max(height, 1); |
| } |
| }, |
| end: function(){ |
| return node.scrollHeight; |
| } |
| } |
| } |
| }, args)); |
| |
| d.connect(anim, "onEnd", function(){ |
| s.height = "auto"; |
| s.overflow = o; |
| }); |
| |
| return anim; // dojo.Animation |
| } |
| |
| dojo.fx.wipeOut = function(/*Object*/ args){ |
| // summary: |
| // Shrink a node to nothing and hide it. |
| // |
| // description: |
| // Returns an animation that will shrink node defined in "args" |
| // from it's current height to 1px, and then hide it. |
| // |
| // args: Object |
| // A hash-map of standard `dojo.Animation` constructor properties |
| // (such as easing: node: duration: and so on) |
| // |
| // example: |
| // | dojo.fx.wipeOut({ node:"someId" }).play() |
| |
| var node = args.node = d.byId(args.node), s = node.style, o; |
| |
| var anim = d.animateProperty(d.mixin({ |
| properties: { |
| height: { |
| end: 1 // 0 causes IE to display the whole panel |
| } |
| } |
| }, args)); |
| |
| d.connect(anim, "beforeBegin", function(){ |
| o = s.overflow; |
| s.overflow = "hidden"; |
| s.display = ""; |
| }); |
| d.connect(anim, "onEnd", function(){ |
| s.overflow = o; |
| s.height = "auto"; |
| s.display = "none"; |
| }); |
| |
| return anim; // dojo.Animation |
| } |
| |
| dojo.fx.slideTo = function(/*Object*/ args){ |
| // summary: |
| // Slide a node to a new top/left position |
| // |
| // description: |
| // Returns an animation that will slide "node" |
| // defined in args Object from its current position to |
| // the position defined by (args.left, args.top). |
| // |
| // args: Object |
| // A hash-map of standard `dojo.Animation` constructor properties |
| // (such as easing: node: duration: and so on). Special args members |
| // are `top` and `left`, which indicate the new position to slide to. |
| // |
| // example: |
| // | dojo.fx.slideTo({ node: node, left:"40", top:"50", units:"px" }).play() |
| |
| var node = args.node = d.byId(args.node), |
| top = null, left = null; |
| |
| var init = (function(n){ |
| return function(){ |
| var cs = d.getComputedStyle(n); |
| var pos = cs.position; |
| top = (pos == 'absolute' ? n.offsetTop : parseInt(cs.top) || 0); |
| left = (pos == 'absolute' ? n.offsetLeft : parseInt(cs.left) || 0); |
| if(pos != 'absolute' && pos != 'relative'){ |
| var ret = d.position(n, true); |
| top = ret.y; |
| left = ret.x; |
| n.style.position="absolute"; |
| n.style.top=top+"px"; |
| n.style.left=left+"px"; |
| } |
| }; |
| })(node); |
| init(); |
| |
| var anim = d.animateProperty(d.mixin({ |
| properties: { |
| top: args.top || 0, |
| left: args.left || 0 |
| } |
| }, args)); |
| d.connect(anim, "beforeBegin", anim, init); |
| |
| return anim; // dojo.Animation |
| } |
| |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.action2d.Magnify"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.action2d.Magnify"] = true; |
| dojo.provide("dojox.charting.action2d.Magnify"); |
| |
| |
| |
| |
| |
| (function(){ |
| var DEFAULT_SCALE = 2, |
| m = dojox.gfx.matrix, |
| gf = dojox.gfx.fx; |
| |
| dojo.declare("dojox.charting.action2d.Magnify", dojox.charting.action2d.Base, { |
| // the data description block for the widget parser |
| defaultParams: { |
| duration: 400, // duration of the action in ms |
| easing: dojo.fx.easing.backOut, // easing for the action |
| scale: DEFAULT_SCALE // scale of magnification |
| }, |
| optionalParams: {}, // no optional parameters |
| |
| constructor: function(chart, plot, kwArgs){ |
| // process optional named parameters |
| this.scale = kwArgs && typeof kwArgs.scale == "number" ? kwArgs.scale : DEFAULT_SCALE; |
| |
| this.connect(); |
| }, |
| |
| process: function(o){ |
| if(!o.shape || !(o.type in this.overOutEvents) || |
| !("cx" in o) || !("cy" in o)){ return; } |
| |
| var runName = o.run.name, index = o.index, vector = [], anim, init, scale; |
| |
| if(runName in this.anim){ |
| anim = this.anim[runName][index]; |
| }else{ |
| this.anim[runName] = {}; |
| } |
| |
| if(anim){ |
| anim.action.stop(true); |
| }else{ |
| this.anim[runName][index] = anim = {}; |
| } |
| |
| if(o.type == "onmouseover"){ |
| init = m.identity; |
| scale = this.scale; |
| }else{ |
| init = m.scaleAt(this.scale, o.cx, o.cy); |
| scale = 1 / this.scale; |
| } |
| |
| var kwArgs = { |
| shape: o.shape, |
| duration: this.duration, |
| easing: this.easing, |
| transform: [ |
| {name: "scaleAt", start: [1, o.cx, o.cy], end: [scale, o.cx, o.cy]}, |
| init |
| ] |
| }; |
| if(o.shape){ |
| vector.push(gf.animateTransform(kwArgs)); |
| } |
| if(o.oultine){ |
| kwArgs.shape = o.outline; |
| vector.push(gf.animateTransform(kwArgs)); |
| } |
| if(o.shadow){ |
| kwArgs.shape = o.shadow; |
| vector.push(gf.animateTransform(kwArgs)); |
| } |
| |
| if(!vector.length){ |
| delete this.anim[runName][index]; |
| return; |
| } |
| |
| anim.action = dojo.fx.combine(vector); |
| if(o.type == "onmouseout"){ |
| dojo.connect(anim.action, "onEnd", this, function(){ |
| if(this.anim[runName]){ |
| delete this.anim[runName][index]; |
| } |
| }); |
| } |
| anim.action.play(); |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.lang.functional.scan"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.lang.functional.scan"] = true; |
| dojo.provide("dojox.lang.functional.scan"); |
| |
| |
| |
| // This module adds high-level functions and related constructs: |
| // - "scan" family of functions |
| |
| // Notes: |
| // - missing high-level functions are provided with the compatible API: |
| // scanl, scanl1, scanr, scanr1 |
| |
| // Defined methods: |
| // - take any valid lambda argument as the functional argument |
| // - operate on dense arrays |
| // - take a string as the array argument |
| // - take an iterator objects as the array argument (only scanl, and scanl1) |
| |
| (function(){ |
| var d = dojo, df = dojox.lang.functional, empty = {}; |
| |
| d.mixin(df, { |
| // classic reduce-class functions |
| scanl: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){ |
| // summary: repeatedly applies a binary function to an array from left |
| // to right using a seed value as a starting point; returns an array |
| // of values produced by foldl() at that point. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| var t, n, i; |
| if(d.isArray(a)){ |
| // array |
| t = new Array((n = a.length) + 1); |
| t[0] = z; |
| for(i = 0; i < n; z = f.call(o, z, a[i], i, a), t[++i] = z); |
| }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ |
| // iterator |
| t = [z]; |
| for(i = 0; a.hasNext(); t.push(z = f.call(o, z, a.next(), i++, a))); |
| }else{ |
| // object/dictionary |
| t = [z]; |
| for(i in a){ |
| if(!(i in empty)){ |
| t.push(z = f.call(o, z, a[i], i, a)); |
| } |
| } |
| } |
| return t; // Array |
| }, |
| scanl1: function(/*Array|String|Object*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ |
| // summary: repeatedly applies a binary function to an array from left |
| // to right; returns an array of values produced by foldl1() at that |
| // point. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| var t, n, z, first = true; |
| if(d.isArray(a)){ |
| // array |
| t = new Array(n = a.length); |
| t[0] = z = a[0]; |
| for(var i = 1; i < n; t[i] = z = f.call(o, z, a[i], i, a), ++i); |
| }else if(typeof a.hasNext == "function" && typeof a.next == "function"){ |
| // iterator |
| if(a.hasNext()){ |
| t = [z = a.next()]; |
| for(var i = 1; a.hasNext(); t.push(z = f.call(o, z, a.next(), i++, a))); |
| } |
| }else{ |
| // object/dictionary |
| for(var i in a){ |
| if(!(i in empty)){ |
| if(first){ |
| t = [z = a[i]]; |
| first = false; |
| }else{ |
| t.push(z = f.call(o, z, a[i], i, a)); |
| } |
| } |
| } |
| } |
| return t; // Array |
| }, |
| scanr: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object*/ z, /*Object?*/ o){ |
| // summary: repeatedly applies a binary function to an array from right |
| // to left using a seed value as a starting point; returns an array |
| // of values produced by foldr() at that point. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| var n = a.length, t = new Array(n + 1), i = n; |
| t[n] = z; |
| for(; i > 0; --i, z = f.call(o, z, a[i], i, a), t[i] = z); |
| return t; // Array |
| }, |
| scanr1: function(/*Array|String*/ a, /*Function|String|Array*/ f, /*Object?*/ o){ |
| // summary: repeatedly applies a binary function to an array from right |
| // to left; returns an array of values produced by foldr1() at that |
| // point. |
| if(typeof a == "string"){ a = a.split(""); } |
| o = o || d.global; f = df.lambda(f); |
| var n = a.length, t = new Array(n), z = a[n - 1], i = n - 1; |
| t[i] = z; |
| for(; i > 0; --i, z = f.call(o, z, a[i], i, a), t[i] = z); |
| return t; // Array |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.action2d.MoveSlice"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.action2d.MoveSlice"] = true; |
| dojo.provide("dojox.charting.action2d.MoveSlice"); |
| |
| |
| |
| |
| |
| |
| |
| |
| (function(){ |
| var DEFAULT_SCALE = 1.05, |
| DEFAULT_SHIFT = 7, // px |
| m = dojox.gfx.matrix, |
| gf = dojox.gfx.fx, |
| df = dojox.lang.functional; |
| |
| dojo.declare("dojox.charting.action2d.MoveSlice", dojox.charting.action2d.Base, { |
| // the data description block for the widget parser |
| defaultParams: { |
| duration: 400, // duration of the action in ms |
| easing: dojo.fx.easing.backOut, // easing for the action |
| scale: DEFAULT_SCALE, // scale of magnification |
| shift: DEFAULT_SHIFT // shift of the slice |
| }, |
| optionalParams: {}, // no optional parameters |
| |
| constructor: function(chart, plot, kwArgs){ |
| // process optional named parameters |
| if(!kwArgs){ kwArgs = {}; } |
| this.scale = typeof kwArgs.scale == "number" ? kwArgs.scale : DEFAULT_SCALE; |
| this.shift = typeof kwArgs.shift == "number" ? kwArgs.shift : DEFAULT_SHIFT; |
| |
| this.connect(); |
| }, |
| |
| process: function(o){ |
| if(!o.shape || o.element != "slice" || !(o.type in this.overOutEvents)){ return; } |
| |
| if(!this.angles){ |
| // calculate the running total of slice angles |
| if(typeof o.run.data[0] == "number"){ |
| this.angles = df.map(df.scanl(o.run.data, "+", 0), |
| "* 2 * Math.PI / this", df.foldl(o.run.data, "+", 0)); |
| }else{ |
| this.angles = df.map(df.scanl(o.run.data, "a + b.y", 0), |
| "* 2 * Math.PI / this", df.foldl(o.run.data, "a + b.y", 0)); |
| } |
| } |
| |
| var index = o.index, anim, startScale, endScale, startOffset, endOffset, |
| angle = (this.angles[index] + this.angles[index + 1]) / 2, |
| rotateTo0 = m.rotateAt(-angle, o.cx, o.cy), |
| rotateBack = m.rotateAt( angle, o.cx, o.cy); |
| |
| anim = this.anim[index]; |
| |
| if(anim){ |
| anim.action.stop(true); |
| }else{ |
| this.anim[index] = anim = {}; |
| } |
| |
| if(o.type == "onmouseover"){ |
| startOffset = 0; |
| endOffset = this.shift; |
| startScale = 1; |
| endScale = this.scale; |
| }else{ |
| startOffset = this.shift; |
| endOffset = 0; |
| startScale = this.scale; |
| endScale = 1; |
| } |
| |
| anim.action = dojox.gfx.fx.animateTransform({ |
| shape: o.shape, |
| duration: this.duration, |
| easing: this.easing, |
| transform: [ |
| rotateBack, |
| {name: "translate", start: [startOffset, 0], end: [endOffset, 0]}, |
| {name: "scaleAt", start: [startScale, o.cx, o.cy], end: [endScale, o.cx, o.cy]}, |
| rotateTo0 |
| ] |
| }); |
| |
| if(o.type == "onmouseout"){ |
| dojo.connect(anim.action, "onEnd", this, function(){ |
| delete this.anim[index]; |
| }); |
| } |
| anim.action.play(); |
| }, |
| |
| reset: function(){ |
| delete this.angles; |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.action2d.Shake"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.action2d.Shake"] = true; |
| dojo.provide("dojox.charting.action2d.Shake"); |
| |
| |
| |
| |
| |
| (function(){ |
| var DEFAULT_SHIFT = 3, |
| m = dojox.gfx.matrix, |
| gf = dojox.gfx.fx; |
| |
| dojo.declare("dojox.charting.action2d.Shake", dojox.charting.action2d.Base, { |
| // the data description block for the widget parser |
| defaultParams: { |
| duration: 400, // duration of the action in ms |
| easing: dojo.fx.easing.backOut, // easing for the action |
| shiftX: DEFAULT_SHIFT, // shift of the element along the X axis |
| shiftY: DEFAULT_SHIFT // shift of the element along the Y axis |
| }, |
| optionalParams: {}, // no optional parameters |
| |
| constructor: function(chart, plot, kwArgs){ |
| // process optional named parameters |
| if(!kwArgs){ kwArgs = {}; } |
| this.shiftX = typeof kwArgs.shiftX == "number" ? kwArgs.shiftX : DEFAULT_SHIFT; |
| this.shiftY = typeof kwArgs.shiftY == "number" ? kwArgs.shiftY : DEFAULT_SHIFT; |
| |
| this.connect(); |
| }, |
| |
| process: function(o){ |
| if(!o.shape || !(o.type in this.overOutEvents)){ return; } |
| |
| var runName = o.run.name, index = o.index, vector = [], anim, |
| shiftX = o.type == "onmouseover" ? this.shiftX : -this.shiftX, |
| shiftY = o.type == "onmouseover" ? this.shiftY : -this.shiftY; |
| |
| if(runName in this.anim){ |
| anim = this.anim[runName][index]; |
| }else{ |
| this.anim[runName] = {}; |
| } |
| |
| if(anim){ |
| anim.action.stop(true); |
| }else{ |
| this.anim[runName][index] = anim = {}; |
| } |
| |
| var kwArgs = { |
| shape: o.shape, |
| duration: this.duration, |
| easing: this.easing, |
| transform: [ |
| {name: "translate", start: [this.shiftX, this.shiftY], end: [0, 0]}, |
| m.identity |
| ] |
| }; |
| if(o.shape){ |
| vector.push(gf.animateTransform(kwArgs)); |
| } |
| if(o.oultine){ |
| kwArgs.shape = o.outline; |
| vector.push(gf.animateTransform(kwArgs)); |
| } |
| if(o.shadow){ |
| kwArgs.shape = o.shadow; |
| vector.push(gf.animateTransform(kwArgs)); |
| } |
| |
| if(!vector.length){ |
| delete this.anim[runName][index]; |
| return; |
| } |
| |
| anim.action = dojo.fx.combine(vector); |
| if(o.type == "onmouseout"){ |
| dojo.connect(anim.action, "onEnd", this, function(){ |
| if(this.anim[runName]){ |
| delete this.anim[runName][index]; |
| } |
| }); |
| } |
| anim.action.play(); |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojo.date.stamp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo.date.stamp"] = true; |
| dojo.provide("dojo.date.stamp"); |
| |
| // Methods to convert dates to or from a wire (string) format using well-known conventions |
| |
| dojo.date.stamp.fromISOString = function(/*String*/formattedString, /*Number?*/defaultTime){ |
| // summary: |
| // Returns a Date object given a string formatted according to a subset of the ISO-8601 standard. |
| // |
| // description: |
| // Accepts a string formatted according to a profile of ISO8601 as defined by |
| // [RFC3339](http://www.ietf.org/rfc/rfc3339.txt), except that partial input is allowed. |
| // Can also process dates as specified [by the W3C](http://www.w3.org/TR/NOTE-datetime) |
| // The following combinations are valid: |
| // |
| // * dates only |
| // | * yyyy |
| // | * yyyy-MM |
| // | * yyyy-MM-dd |
| // * times only, with an optional time zone appended |
| // | * THH:mm |
| // | * THH:mm:ss |
| // | * THH:mm:ss.SSS |
| // * and "datetimes" which could be any combination of the above |
| // |
| // timezones may be specified as Z (for UTC) or +/- followed by a time expression HH:mm |
| // Assumes the local time zone if not specified. Does not validate. Improperly formatted |
| // input may return null. Arguments which are out of bounds will be handled |
| // by the Date constructor (e.g. January 32nd typically gets resolved to February 1st) |
| // Only years between 100 and 9999 are supported. |
| // |
| // formattedString: |
| // A string such as 2005-06-30T08:05:00-07:00 or 2005-06-30 or T08:05:00 |
| // |
| // defaultTime: |
| // Used for defaults for fields omitted in the formattedString. |
| // Uses 1970-01-01T00:00:00.0Z by default. |
| |
| if(!dojo.date.stamp._isoRegExp){ |
| dojo.date.stamp._isoRegExp = |
| //TODO: could be more restrictive and check for 00-59, etc. |
| /^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(.\d+)?)?((?:[+-](\d{2}):(\d{2}))|Z)?)?$/; |
| } |
| |
| var match = dojo.date.stamp._isoRegExp.exec(formattedString), |
| result = null; |
| |
| if(match){ |
| match.shift(); |
| if(match[1]){match[1]--;} // Javascript Date months are 0-based |
| if(match[6]){match[6] *= 1000;} // Javascript Date expects fractional seconds as milliseconds |
| |
| if(defaultTime){ |
| // mix in defaultTime. Relatively expensive, so use || operators for the fast path of defaultTime === 0 |
| defaultTime = new Date(defaultTime); |
| dojo.map(["FullYear", "Month", "Date", "Hours", "Minutes", "Seconds", "Milliseconds"], function(prop){ |
| return defaultTime["get" + prop](); |
| }).forEach(function(value, index){ |
| if(match[index] === undefined){ |
| match[index] = value; |
| } |
| }); |
| } |
| result = new Date(match[0]||1970, match[1]||0, match[2]||1, match[3]||0, match[4]||0, match[5]||0, match[6]||0); //TODO: UTC defaults |
| if(match[0] < 100){ |
| result.setFullYear(match[0] || 1970); |
| } |
| |
| var offset = 0, |
| zoneSign = match[7] && match[7].charAt(0); |
| if(zoneSign != 'Z'){ |
| offset = ((match[8] || 0) * 60) + (Number(match[9]) || 0); |
| if(zoneSign != '-'){ offset *= -1; } |
| } |
| if(zoneSign){ |
| offset -= result.getTimezoneOffset(); |
| } |
| if(offset){ |
| result.setTime(result.getTime() + offset * 60000); |
| } |
| } |
| |
| return result; // Date or null |
| } |
| |
| /*===== |
| dojo.date.stamp.__Options = function(){ |
| // selector: String |
| // "date" or "time" for partial formatting of the Date object. |
| // Both date and time will be formatted by default. |
| // zulu: Boolean |
| // if true, UTC/GMT is used for a timezone |
| // milliseconds: Boolean |
| // if true, output milliseconds |
| this.selector = selector; |
| this.zulu = zulu; |
| this.milliseconds = milliseconds; |
| } |
| =====*/ |
| |
| dojo.date.stamp.toISOString = function(/*Date*/dateObject, /*dojo.date.stamp.__Options?*/options){ |
| // summary: |
| // Format a Date object as a string according a subset of the ISO-8601 standard |
| // |
| // description: |
| // When options.selector is omitted, output follows [RFC3339](http://www.ietf.org/rfc/rfc3339.txt) |
| // The local time zone is included as an offset from GMT, except when selector=='time' (time without a date) |
| // Does not check bounds. Only years between 100 and 9999 are supported. |
| // |
| // dateObject: |
| // A Date object |
| |
| var _ = function(n){ return (n < 10) ? "0" + n : n; }; |
| options = options || {}; |
| var formattedDate = [], |
| getter = options.zulu ? "getUTC" : "get", |
| date = ""; |
| if(options.selector != "time"){ |
| var year = dateObject[getter+"FullYear"](); |
| date = ["0000".substr((year+"").length)+year, _(dateObject[getter+"Month"]()+1), _(dateObject[getter+"Date"]())].join('-'); |
| } |
| formattedDate.push(date); |
| if(options.selector != "date"){ |
| var time = [_(dateObject[getter+"Hours"]()), _(dateObject[getter+"Minutes"]()), _(dateObject[getter+"Seconds"]())].join(':'); |
| var millis = dateObject[getter+"Milliseconds"](); |
| if(options.milliseconds){ |
| time += "."+ (millis < 100 ? "0" : "") + _(millis); |
| } |
| if(options.zulu){ |
| time += "Z"; |
| }else if(options.selector != "time"){ |
| var timezoneOffset = dateObject.getTimezoneOffset(); |
| var absOffset = Math.abs(timezoneOffset); |
| time += (timezoneOffset > 0 ? "-" : "+") + |
| _(Math.floor(absOffset/60)) + ":" + _(absOffset%60); |
| } |
| formattedDate.push(time); |
| } |
| return formattedDate.join('T'); // String |
| } |
| |
| } |
| |
| if(!dojo._hasResource["dojo.parser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo.parser"] = true; |
| dojo.provide("dojo.parser"); |
| |
| |
| dojo.parser = new function(){ |
| // summary: The Dom/Widget parsing package |
| |
| var d = dojo; |
| this._attrName = d._scopeName + "Type"; |
| this._query = "[" + this._attrName + "]"; |
| |
| function val2type(/*Object*/ value){ |
| // summary: |
| // Returns name of type of given value. |
| |
| if(d.isString(value)){ return "string"; } |
| if(typeof value == "number"){ return "number"; } |
| if(typeof value == "boolean"){ return "boolean"; } |
| if(d.isFunction(value)){ return "function"; } |
| if(d.isArray(value)){ return "array"; } // typeof [] == "object" |
| if(value instanceof Date) { return "date"; } // assume timestamp |
| if(value instanceof d._Url){ return "url"; } |
| return "object"; |
| } |
| |
| function str2obj(/*String*/ value, /*String*/ type){ |
| // summary: |
| // Convert given string value to given type |
| switch(type){ |
| case "string": |
| return value; |
| case "number": |
| return value.length ? Number(value) : NaN; |
| case "boolean": |
| // for checked/disabled value might be "" or "checked". interpret as true. |
| return typeof value == "boolean" ? value : !(value.toLowerCase()=="false"); |
| case "function": |
| if(d.isFunction(value)){ |
| // IE gives us a function, even when we say something like onClick="foo" |
| // (in which case it gives us an invalid function "function(){ foo }"). |
| // Therefore, convert to string |
| value=value.toString(); |
| value=d.trim(value.substring(value.indexOf('{')+1, value.length-1)); |
| } |
| try{ |
| if(value.search(/[^\w\.]+/i) != -1){ |
| // The user has specified some text for a function like "return x+5" |
| return new Function(value); |
| }else{ |
| // The user has specified the name of a function like "myOnClick" |
| return d.getObject(value, false); |
| } |
| }catch(e){ return new Function(); } |
| case "array": |
| return value ? value.split(/\s*,\s*/) : []; |
| case "date": |
| switch(value){ |
| case "": return new Date(""); // the NaN of dates |
| case "now": return new Date(); // current date |
| default: return d.date.stamp.fromISOString(value); |
| } |
| case "url": |
| return d.baseUrl + value; |
| default: |
| return d.fromJson(value); |
| } |
| } |
| |
| var instanceClasses = { |
| // map from fully qualified name (like "dijit.Button") to structure like |
| // { cls: dijit.Button, params: {label: "string", disabled: "boolean"} } |
| }; |
| |
| // Widgets like BorderContainer add properties to _Widget via dojo.extend(). |
| // If BorderContainer is loaded after _Widget's parameter list has been cached, |
| // we need to refresh that parameter list (for _Widget and all widgets that extend _Widget). |
| dojo.connect(dojo, "extend", function(){ |
| instanceClasses = {}; |
| }); |
| |
| function getClassInfo(/*String*/ className){ |
| // className: |
| // fully qualified name (like "dijit.form.Button") |
| // returns: |
| // structure like |
| // { |
| // cls: dijit.Button, |
| // params: { label: "string", disabled: "boolean"} |
| // } |
| |
| if(!instanceClasses[className]){ |
| // get pointer to widget class |
| var cls = d.getObject(className); |
| if(!d.isFunction(cls)){ |
| throw new Error("Could not load class '" + className + |
| "'. Did you spell the name correctly and use a full path, like 'dijit.form.Button'?"); |
| } |
| var proto = cls.prototype; |
| |
| // get table of parameter names & types |
| var params = {}, dummyClass = {}; |
| for(var name in proto){ |
| if(name.charAt(0)=="_"){ continue; } // skip internal properties |
| if(name in dummyClass){ continue; } // skip "constructor" and "toString" |
| var defVal = proto[name]; |
| params[name]=val2type(defVal); |
| } |
| |
| instanceClasses[className] = { cls: cls, params: params }; |
| } |
| return instanceClasses[className]; |
| } |
| |
| this._functionFromScript = function(script){ |
| var preamble = ""; |
| var suffix = ""; |
| var argsStr = script.getAttribute("args"); |
| if(argsStr){ |
| d.forEach(argsStr.split(/\s*,\s*/), function(part, idx){ |
| preamble += "var "+part+" = arguments["+idx+"]; "; |
| }); |
| } |
| var withStr = script.getAttribute("with"); |
| if(withStr && withStr.length){ |
| d.forEach(withStr.split(/\s*,\s*/), function(part){ |
| preamble += "with("+part+"){"; |
| suffix += "}"; |
| }); |
| } |
| return new Function(preamble+script.innerHTML+suffix); |
| } |
| |
| this.instantiate = function(/* Array */nodes, /* Object? */mixin, /* Object? */args){ |
| // summary: |
| // Takes array of nodes, and turns them into class instances and |
| // potentially calls a layout method to allow them to connect with |
| // any children |
| // mixin: Object? |
| // An object that will be mixed in with each node in the array. |
| // Values in the mixin will override values in the node, if they |
| // exist. |
| // args: Object? |
| // An object used to hold kwArgs for instantiation. |
| // Only supports 'noStart' currently. |
| var thelist = [], dp = dojo.parser; |
| mixin = mixin||{}; |
| args = args||{}; |
| |
| d.forEach(nodes, function(node){ |
| if(!node){ return; } |
| var type = dp._attrName in mixin?mixin[dp._attrName]:node.getAttribute(dp._attrName); |
| if(!type || !type.length){ return; } |
| var clsInfo = getClassInfo(type), |
| clazz = clsInfo.cls, |
| ps = clazz._noScript || clazz.prototype._noScript; |
| |
| // read parameters (ie, attributes). |
| // clsInfo.params lists expected params like {"checked": "boolean", "n": "number"} |
| var params = {}, |
| attributes = node.attributes; |
| for(var name in clsInfo.params){ |
| var item = name in mixin?{value:mixin[name],specified:true}:attributes.getNamedItem(name); |
| if(!item || (!item.specified && (!dojo.isIE || name.toLowerCase()!="value"))){ continue; } |
| var value = item.value; |
| // Deal with IE quirks for 'class' and 'style' |
| switch(name){ |
| case "class": |
| value = "className" in mixin?mixin.className:node.className; |
| break; |
| case "style": |
| value = "style" in mixin?mixin.style:(node.style && node.style.cssText); // FIXME: Opera? |
| } |
| var _type = clsInfo.params[name]; |
| if(typeof value == "string"){ |
| params[name] = str2obj(value, _type); |
| }else{ |
| params[name] = value; |
| } |
| } |
| |
| // Process <script type="dojo/*"> script tags |
| // <script type="dojo/method" event="foo"> tags are added to params, and passed to |
| // the widget on instantiation. |
| // <script type="dojo/method"> tags (with no event) are executed after instantiation |
| // <script type="dojo/connect" event="foo"> tags are dojo.connected after instantiation |
| // note: dojo/* script tags cannot exist in self closing widgets, like <input /> |
| if(!ps){ |
| var connects = [], // functions to connect after instantiation |
| calls = []; // functions to call after instantiation |
| |
| d.query("> script[type^='dojo/']", node).orphan().forEach(function(script){ |
| var event = script.getAttribute("event"), |
| type = script.getAttribute("type"), |
| nf = d.parser._functionFromScript(script); |
| if(event){ |
| if(type == "dojo/connect"){ |
| connects.push({event: event, func: nf}); |
| }else{ |
| params[event] = nf; |
| } |
| }else{ |
| calls.push(nf); |
| } |
| }); |
| } |
| |
| var markupFactory = clazz.markupFactory || clazz.prototype && clazz.prototype.markupFactory; |
| // create the instance |
| var instance = markupFactory ? markupFactory(params, node, clazz) : new clazz(params, node); |
| thelist.push(instance); |
| |
| // map it to the JS namespace if that makes sense |
| var jsname = node.getAttribute("jsId"); |
| if(jsname){ |
| d.setObject(jsname, instance); |
| } |
| |
| // process connections and startup functions |
| if(!ps){ |
| d.forEach(connects, function(connect){ |
| d.connect(instance, connect.event, null, connect.func); |
| }); |
| d.forEach(calls, function(func){ |
| func.call(instance); |
| }); |
| } |
| }); |
| |
| // Call startup on each top level instance if it makes sense (as for |
| // widgets). Parent widgets will recursively call startup on their |
| // (non-top level) children |
| if(!mixin._started){ |
| d.forEach(thelist, function(instance){ |
| if( !args.noStart && instance && |
| instance.startup && |
| !instance._started && |
| (!instance.getParent || !instance.getParent()) |
| ){ |
| instance.startup(); |
| } |
| }); |
| } |
| return thelist; |
| }; |
| |
| this.parse = function(/*DomNode?*/ rootNode, /* Object? */ args){ |
| // summary: |
| // Scan the DOM for class instances, and instantiate them. |
| // |
| // description: |
| // Search specified node (or root node) recursively for class instances, |
| // and instantiate them Searches for |
| // dojoType="qualified.class.name" |
| // |
| // rootNode: DomNode? |
| // A default starting root node from which to start the parsing. Can be |
| // omitted, defaulting to the entire document. If omitted, the `args` |
| // object can be passed in this place. If the `args` object has a |
| // `rootNode` member, that is used. |
| // |
| // args: |
| // a kwArgs object passed along to instantiate() |
| // |
| // * noStart: Boolean? |
| // when set will prevent the parser from calling .startup() |
| // when locating the nodes. |
| // * rootNode: DomNode? |
| // identical to the function's `rootNode` argument, though |
| // allowed to be passed in via this `args object. |
| // |
| // example: |
| // Parse all widgets on a page: |
| // | dojo.parser.parse(); |
| // |
| // example: |
| // Parse all classes within the node with id="foo" |
| // | dojo.parser.parse(dojo.byId(foo)); |
| // |
| // example: |
| // Parse all classes in a page, but do not call .startup() on any |
| // child |
| // | dojo.parser.parse({ noStart: true }) |
| // |
| // example: |
| // Parse all classes in a node, but do not call .startup() |
| // | dojo.parser.parse(someNode, { noStart:true }); |
| // | // or |
| // | dojo.parser.parse({ noStart:true, rootNode: someNode }); |
| |
| // determine the root node based on the passed arguments. |
| var root; |
| if(!args && rootNode && rootNode.rootNode){ |
| args = rootNode; |
| root = args.rootNode; |
| }else{ |
| root = rootNode; |
| } |
| |
| var list = d.query(this._query, root); |
| // go build the object instances |
| return this.instantiate(list, null, args); // Array |
| |
| }; |
| }(); |
| |
| //Register the parser callback. It should be the first callback |
| //after the a11y test. |
| |
| (function(){ |
| var parseRunner = function(){ |
| if(dojo.config.parseOnLoad){ |
| dojo.parser.parse(); |
| } |
| }; |
| |
| // FIXME: need to clobber cross-dependency!! |
| if(dojo.exists("dijit.wai.onload") && (dijit.wai.onload === dojo._loaders[0])){ |
| dojo._loaders.splice(1, 0, parseRunner); |
| }else{ |
| dojo._loaders.unshift(parseRunner); |
| } |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojo.cache"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojo.cache"] = true; |
| dojo.provide("dojo.cache"); |
| |
| /*===== |
| dojo.cache = { |
| // summary: |
| // A way to cache string content that is fetchable via `dojo.moduleUrl`. |
| }; |
| =====*/ |
| |
| (function(){ |
| var cache = {}; |
| dojo.cache = function(/*String||Object*/module, /*String*/url, /*String||Object?*/value){ |
| // summary: |
| // A getter and setter for storing the string content associated with the |
| // module and url arguments. |
| // description: |
| // module and url are used to call `dojo.moduleUrl()` to generate a module URL. |
| // If value is specified, the cache value for the moduleUrl will be set to |
| // that value. Otherwise, dojo.cache will fetch the moduleUrl and store it |
| // in its internal cache and return that cached value for the URL. To clear |
| // a cache value pass null for value. Since XMLHttpRequest (XHR) is used to fetch the |
| // the URL contents, only modules on the same domain of the page can use this capability. |
| // The build system can inline the cache values though, to allow for xdomain hosting. |
| // module: String||Object |
| // If a String, the module name to use for the base part of the URL, similar to module argument |
| // to `dojo.moduleUrl`. If an Object, something that has a .toString() method that |
| // generates a valid path for the cache item. For example, a dojo._Url object. |
| // url: String |
| // The rest of the path to append to the path derived from the module argument. If |
| // module is an object, then this second argument should be the "value" argument instead. |
| // value: String||Object? |
| // If a String, the value to use in the cache for the module/url combination. |
| // If an Object, it can have two properties: value and sanitize. The value property |
| // should be the value to use in the cache, and sanitize can be set to true or false, |
| // to indicate if XML declarations should be removed from the value and if the HTML |
| // inside a body tag in the value should be extracted as the real value. The value argument |
| // or the value property on the value argument are usually only used by the build system |
| // as it inlines cache content. |
| // example: |
| // To ask dojo.cache to fetch content and store it in the cache (the dojo["cache"] style |
| // of call is used to avoid an issue with the build system erroneously trying to intern |
| // this example. To get the build system to intern your dojo.cache calls, use the |
| // "dojo.cache" style of call): |
| // | //If template.html contains "<h1>Hello</h1>" that will be |
| // | //the value for the text variable. |
| // | var text = dojo["cache"]("my.module", "template.html"); |
| // example: |
| // To ask dojo.cache to fetch content and store it in the cache, and sanitize the input |
| // (the dojo["cache"] style of call is used to avoid an issue with the build system |
| // erroneously trying to intern this example. To get the build system to intern your |
| // dojo.cache calls, use the "dojo.cache" style of call): |
| // | //If template.html contains "<html><body><h1>Hello</h1></body></html>", the |
| // | //text variable will contain just "<h1>Hello</h1>". |
| // | var text = dojo["cache"]("my.module", "template.html", {sanitize: true}); |
| // example: |
| // Same example as previous, but demostrates how an object can be passed in as |
| // the first argument, then the value argument can then be the second argument. |
| // | //If template.html contains "<html><body><h1>Hello</h1></body></html>", the |
| // | //text variable will contain just "<h1>Hello</h1>". |
| // | var text = dojo["cache"](new dojo._Url("my/module/template.html"), {sanitize: true}); |
| |
| //Module could be a string, or an object that has a toString() method |
| //that will return a useful path. If it is an object, then the "url" argument |
| //will actually be the value argument. |
| if(typeof module == "string"){ |
| var pathObj = dojo.moduleUrl(module, url); |
| }else{ |
| pathObj = module; |
| value = url; |
| } |
| var key = pathObj.toString(); |
| |
| var val = value; |
| if(value !== undefined && !dojo.isString(value)){ |
| val = ("value" in value ? value.value : undefined); |
| } |
| |
| var sanitize = value && value.sanitize ? true : false; |
| |
| if(val || val === null){ |
| //We have a value, either clear or set the cache value. |
| if(val == null){ |
| delete cache[key]; |
| }else{ |
| val = cache[key] = sanitize ? dojo.cache._sanitize(val) : val; |
| } |
| }else{ |
| //Allow cache values to be empty strings. If key property does |
| //not exist, fetch it. |
| if(!(key in cache)){ |
| val = dojo._getText(key); |
| cache[key] = sanitize ? dojo.cache._sanitize(val) : val; |
| } |
| val = cache[key]; |
| } |
| return val; //String |
| }; |
| |
| dojo.cache._sanitize = function(/*String*/val){ |
| // summary: |
| // Strips <?xml ...?> declarations so that external SVG and XML |
| // documents can be added to a document without worry. Also, if the string |
| // is an HTML document, only the part inside the body tag is returned. |
| // description: |
| // Copied from dijit._Templated._sanitizeTemplateString. |
| if(val){ |
| val = val.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, ""); |
| var matches = val.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im); |
| if(matches){ |
| val = matches[1]; |
| } |
| }else{ |
| val = ""; |
| } |
| return val; //String |
| }; |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dijit._Templated"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit._Templated"] = true; |
| dojo.provide("dijit._Templated"); |
| |
| |
| |
| |
| |
| |
| dojo.declare("dijit._Templated", |
| null, |
| { |
| // summary: |
| // Mixin for widgets that are instantiated from a template |
| |
| // templateString: [protected] String |
| // A string that represents the widget template. Pre-empts the |
| // templatePath. In builds that have their strings "interned", the |
| // templatePath is converted to an inline templateString, thereby |
| // preventing a synchronous network call. |
| // |
| // Use in conjunction with dojo.cache() to load from a file. |
| templateString: null, |
| |
| // templatePath: [protected deprecated] String |
| // Path to template (HTML file) for this widget relative to dojo.baseUrl. |
| // Deprecated: use templateString with dojo.cache() instead. |
| templatePath: null, |
| |
| // widgetsInTemplate: [protected] Boolean |
| // Should we parse the template to find widgets that might be |
| // declared in markup inside it? False by default. |
| widgetsInTemplate: false, |
| |
| // skipNodeCache: [protected] Boolean |
| // If using a cached widget template node poses issues for a |
| // particular widget class, it can set this property to ensure |
| // that its template is always re-built from a string |
| _skipNodeCache: false, |
| |
| // _earlyTemplatedStartup: Boolean |
| // A fallback to preserve the 1.0 - 1.3 behavior of children in |
| // templates having their startup called before the parent widget |
| // fires postCreate. Defaults to 'false', causing child widgets to |
| // have their .startup() called immediately before a parent widget |
| // .startup(), but always after the parent .postCreate(). Set to |
| // 'true' to re-enable to previous, arguably broken, behavior. |
| _earlyTemplatedStartup: false, |
| |
| // _attachPoints: [private] String[] |
| // List of widget attribute names associated with dojoAttachPoint=... in the |
| // template, ex: ["containerNode", "labelNode"] |
| /*===== |
| _attachPoints: [], |
| =====*/ |
| |
| constructor: function(){ |
| this._attachPoints = []; |
| }, |
| |
| _stringRepl: function(tmpl){ |
| // summary: |
| // Does substitution of ${foo} type properties in template string |
| // tags: |
| // private |
| var className = this.declaredClass, _this = this; |
| // Cache contains a string because we need to do property replacement |
| // do the property replacement |
| return dojo.string.substitute(tmpl, this, function(value, key){ |
| if(key.charAt(0) == '!'){ value = dojo.getObject(key.substr(1), false, _this); } |
| if(typeof value == "undefined"){ throw new Error(className+" template:"+key); } // a debugging aide |
| if(value == null){ return ""; } |
| |
| // Substitution keys beginning with ! will skip the transform step, |
| // in case a user wishes to insert unescaped markup, e.g. ${!foo} |
| return key.charAt(0) == "!" ? value : |
| // Safer substitution, see heading "Attribute values" in |
| // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2 |
| value.toString().replace(/"/g,"""); //TODO: add &? use encodeXML method? |
| }, this); |
| }, |
| |
| // method over-ride |
| buildRendering: function(){ |
| // summary: |
| // Construct the UI for this widget from a template, setting this.domNode. |
| // tags: |
| // protected |
| |
| // Lookup cached version of template, and download to cache if it |
| // isn't there already. Returns either a DomNode or a string, depending on |
| // whether or not the template contains ${foo} replacement parameters. |
| var cached = dijit._Templated.getCachedTemplate(this.templatePath, this.templateString, this._skipNodeCache); |
| |
| var node; |
| if(dojo.isString(cached)){ |
| node = dojo._toDom(this._stringRepl(cached)); |
| if(node.nodeType != 1){ |
| // Flag common problems such as templates with multiple top level nodes (nodeType == 11) |
| throw new Error("Invalid template: " + cached); |
| } |
| }else{ |
| // if it's a node, all we have to do is clone it |
| node = cached.cloneNode(true); |
| } |
| |
| this.domNode = node; |
| |
| // recurse through the node, looking for, and attaching to, our |
| // attachment points and events, which should be defined on the template node. |
| this._attachTemplateNodes(node); |
| |
| if(this.widgetsInTemplate){ |
| // Make sure dojoType is used for parsing widgets in template. |
| // The dojo.parser.query could be changed from multiversion support. |
| var parser = dojo.parser, qry, attr; |
| if(parser._query != "[dojoType]"){ |
| qry = parser._query; |
| attr = parser._attrName; |
| parser._query = "[dojoType]"; |
| parser._attrName = "dojoType"; |
| } |
| |
| // Store widgets that we need to start at a later point in time |
| var cw = (this._startupWidgets = dojo.parser.parse(node, { |
| noStart: !this._earlyTemplatedStartup |
| })); |
| |
| // Restore the query. |
| if(qry){ |
| parser._query = qry; |
| parser._attrName = attr; |
| } |
| |
| this._supportingWidgets = dijit.findWidgets(node); |
| |
| this._attachTemplateNodes(cw, function(n,p){ |
| return n[p]; |
| }); |
| } |
| |
| this._fillContent(this.srcNodeRef); |
| }, |
| |
| _fillContent: function(/*DomNode*/ source){ |
| // summary: |
| // Relocate source contents to templated container node. |
| // this.containerNode must be able to receive children, or exceptions will be thrown. |
| // tags: |
| // protected |
| var dest = this.containerNode; |
| if(source && dest){ |
| while(source.hasChildNodes()){ |
| dest.appendChild(source.firstChild); |
| } |
| } |
| }, |
| |
| _attachTemplateNodes: function(rootNode, getAttrFunc){ |
| // summary: |
| // Iterate through the template and attach functions and nodes accordingly. |
| // description: |
| // Map widget properties and functions to the handlers specified in |
| // the dom node and it's descendants. This function iterates over all |
| // nodes and looks for these properties: |
| // * dojoAttachPoint |
| // * dojoAttachEvent |
| // * waiRole |
| // * waiState |
| // rootNode: DomNode|Array[Widgets] |
| // the node to search for properties. All children will be searched. |
| // getAttrFunc: Function? |
| // a function which will be used to obtain property for a given |
| // DomNode/Widget |
| // tags: |
| // private |
| |
| getAttrFunc = getAttrFunc || function(n,p){ return n.getAttribute(p); }; |
| |
| var nodes = dojo.isArray(rootNode) ? rootNode : (rootNode.all || rootNode.getElementsByTagName("*")); |
| var x = dojo.isArray(rootNode) ? 0 : -1; |
| for(; x<nodes.length; x++){ |
| var baseNode = (x == -1) ? rootNode : nodes[x]; |
| if(this.widgetsInTemplate && getAttrFunc(baseNode, "dojoType")){ |
| continue; |
| } |
| // Process dojoAttachPoint |
| var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint"); |
| if(attachPoint){ |
| var point, points = attachPoint.split(/\s*,\s*/); |
| while((point = points.shift())){ |
| if(dojo.isArray(this[point])){ |
| this[point].push(baseNode); |
| }else{ |
| this[point]=baseNode; |
| } |
| this._attachPoints.push(point); |
| } |
| } |
| |
| // Process dojoAttachEvent |
| var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent"); |
| if(attachEvent){ |
| // NOTE: we want to support attributes that have the form |
| // "domEvent: nativeEvent; ..." |
| var event, events = attachEvent.split(/\s*,\s*/); |
| var trim = dojo.trim; |
| while((event = events.shift())){ |
| if(event){ |
| var thisFunc = null; |
| if(event.indexOf(":") != -1){ |
| // oh, if only JS had tuple assignment |
| var funcNameArr = event.split(":"); |
| event = trim(funcNameArr[0]); |
| thisFunc = trim(funcNameArr[1]); |
| }else{ |
| event = trim(event); |
| } |
| if(!thisFunc){ |
| thisFunc = event; |
| } |
| this.connect(baseNode, event, thisFunc); |
| } |
| } |
| } |
| |
| // waiRole, waiState |
| var role = getAttrFunc(baseNode, "waiRole"); |
| if(role){ |
| dijit.setWaiRole(baseNode, role); |
| } |
| var values = getAttrFunc(baseNode, "waiState"); |
| if(values){ |
| dojo.forEach(values.split(/\s*,\s*/), function(stateValue){ |
| if(stateValue.indexOf('-') != -1){ |
| var pair = stateValue.split('-'); |
| dijit.setWaiState(baseNode, pair[0], pair[1]); |
| } |
| }); |
| } |
| } |
| }, |
| |
| startup: function(){ |
| dojo.forEach(this._startupWidgets, function(w){ |
| if(w && !w._started && w.startup){ |
| w.startup(); |
| } |
| }); |
| this.inherited(arguments); |
| }, |
| |
| destroyRendering: function(){ |
| // Delete all attach points to prevent IE6 memory leaks. |
| dojo.forEach(this._attachPoints, function(point){ |
| delete this[point]; |
| }, this); |
| this._attachPoints = []; |
| |
| this.inherited(arguments); |
| } |
| } |
| ); |
| |
| // key is either templatePath or templateString; object is either string or DOM tree |
| dijit._Templated._templateCache = {}; |
| |
| dijit._Templated.getCachedTemplate = function(templatePath, templateString, alwaysUseString){ |
| // summary: |
| // Static method to get a template based on the templatePath or |
| // templateString key |
| // templatePath: String||dojo.uri.Uri |
| // The URL to get the template from. |
| // templateString: String? |
| // a string to use in lieu of fetching the template from a URL. Takes precedence |
| // over templatePath |
| // returns: Mixed |
| // Either string (if there are ${} variables that need to be replaced) or just |
| // a DOM tree (if the node can be cloned directly) |
| |
| // is it already cached? |
| var tmplts = dijit._Templated._templateCache; |
| var key = templateString || templatePath; |
| var cached = tmplts[key]; |
| if(cached){ |
| try{ |
| // if the cached value is an innerHTML string (no ownerDocument) or a DOM tree created within the current document, then use the current cached value |
| if(!cached.ownerDocument || cached.ownerDocument == dojo.doc){ |
| // string or node of the same document |
| return cached; |
| } |
| }catch(e){ /* squelch */ } // IE can throw an exception if cached.ownerDocument was reloaded |
| dojo.destroy(cached); |
| } |
| |
| // If necessary, load template string from template path |
| if(!templateString){ |
| templateString = dojo.cache(templatePath, {sanitize: true}); |
| } |
| templateString = dojo.string.trim(templateString); |
| |
| if(alwaysUseString || templateString.match(/\$\{([^\}]+)\}/g)){ |
| // there are variables in the template so all we can do is cache the string |
| return (tmplts[key] = templateString); //String |
| }else{ |
| // there are no variables in the template so we can cache the DOM tree |
| var node = dojo._toDom(templateString); |
| if(node.nodeType != 1){ |
| throw new Error("Invalid template: " + templateString); |
| } |
| return (tmplts[key] = node); //Node |
| } |
| }; |
| |
| if(dojo.isIE){ |
| dojo.addOnWindowUnload(function(){ |
| var cache = dijit._Templated._templateCache; |
| for(var key in cache){ |
| var value = cache[key]; |
| if(typeof value == "object"){ // value is either a string or a DOM node template |
| dojo.destroy(value); |
| } |
| delete cache[key]; |
| } |
| }); |
| } |
| |
| // These arguments can be specified for widgets which are used in templates. |
| // Since any widget can be specified as sub widgets in template, mix it |
| // into the base widget class. (This is a hack, but it's effective.) |
| dojo.extend(dijit._Widget,{ |
| dojoAttachEvent: "", |
| dojoAttachPoint: "", |
| waiRole: "", |
| waiState:"" |
| }); |
| |
| } |
| |
| if(!dojo._hasResource["dijit.Tooltip"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dijit.Tooltip"] = true; |
| dojo.provide("dijit.Tooltip"); |
| |
| |
| |
| |
| dojo.declare( |
| "dijit._MasterTooltip", |
| [dijit._Widget, dijit._Templated], |
| { |
| // summary: |
| // Internal widget that holds the actual tooltip markup, |
| // which occurs once per page. |
| // Called by Tooltip widgets which are just containers to hold |
| // the markup |
| // tags: |
| // protected |
| |
| // duration: Integer |
| // Milliseconds to fade in/fade out |
| duration: dijit.defaultDuration, |
| |
| templateString: dojo.cache("dijit", "templates/Tooltip.html", "<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\">\n\t<div class=\"dijitTooltipContainer dijitTooltipContents\" dojoAttachPoint=\"containerNode\" waiRole='alert'></div>\n\t<div class=\"dijitTooltipConnector\"></div>\n</div>\n"), |
| |
| postCreate: function(){ |
| dojo.body().appendChild(this.domNode); |
| |
| this.bgIframe = new dijit.BackgroundIframe(this.domNode); |
| |
| // Setup fade-in and fade-out functions. |
| this.fadeIn = dojo.fadeIn({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onShow") }); |
| this.fadeOut = dojo.fadeOut({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onHide") }); |
| |
| }, |
| |
| show: function(/*String*/ innerHTML, /*DomNode*/ aroundNode, /*String[]?*/ position){ |
| // summary: |
| // Display tooltip w/specified contents to right of specified node |
| // (To left if there's no space on the right, or if LTR==right) |
| |
| if(this.aroundNode && this.aroundNode === aroundNode){ |
| return; |
| } |
| |
| if(this.fadeOut.status() == "playing"){ |
| // previous tooltip is being hidden; wait until the hide completes then show new one |
| this._onDeck=arguments; |
| return; |
| } |
| this.containerNode.innerHTML=innerHTML; |
| |
| // Firefox bug. when innerHTML changes to be shorter than previous |
| // one, the node size will not be updated until it moves. |
| this.domNode.style.top = (this.domNode.offsetTop + 1) + "px"; |
| |
| var pos = dijit.placeOnScreenAroundElement(this.domNode, aroundNode, dijit.getPopupAroundAlignment((position && position.length) ? position : dijit.Tooltip.defaultPosition, this.isLeftToRight()), dojo.hitch(this, "orient")); |
| |
| // show it |
| dojo.style(this.domNode, "opacity", 0); |
| this.fadeIn.play(); |
| this.isShowingNow = true; |
| this.aroundNode = aroundNode; |
| }, |
| |
| orient: function(/* DomNode */ node, /* String */ aroundCorner, /* String */ tooltipCorner){ |
| // summary: |
| // Private function to set CSS for tooltip node based on which position it's in. |
| // This is called by the dijit popup code. |
| // tags: |
| // protected |
| |
| node.className = "dijitTooltip " + |
| { |
| "BL-TL": "dijitTooltipBelow dijitTooltipABLeft", |
| "TL-BL": "dijitTooltipAbove dijitTooltipABLeft", |
| "BR-TR": "dijitTooltipBelow dijitTooltipABRight", |
| "TR-BR": "dijitTooltipAbove dijitTooltipABRight", |
| "BR-BL": "dijitTooltipRight", |
| "BL-BR": "dijitTooltipLeft" |
| }[aroundCorner + "-" + tooltipCorner]; |
| }, |
| |
| _onShow: function(){ |
| // summary: |
| // Called at end of fade-in operation |
| // tags: |
| // protected |
| if(dojo.isIE){ |
| // the arrow won't show up on a node w/an opacity filter |
| this.domNode.style.filter=""; |
| } |
| }, |
| |
| hide: function(aroundNode){ |
| // summary: |
| // Hide the tooltip |
| if(this._onDeck && this._onDeck[1] == aroundNode){ |
| // this hide request is for a show() that hasn't even started yet; |
| // just cancel the pending show() |
| this._onDeck=null; |
| }else if(this.aroundNode === aroundNode){ |
| // this hide request is for the currently displayed tooltip |
| this.fadeIn.stop(); |
| this.isShowingNow = false; |
| this.aroundNode = null; |
| this.fadeOut.play(); |
| }else{ |
| // just ignore the call, it's for a tooltip that has already been erased |
| } |
| }, |
| |
| _onHide: function(){ |
| // summary: |
| // Called at end of fade-out operation |
| // tags: |
| // protected |
| |
| this.domNode.style.cssText=""; // to position offscreen again |
| if(this._onDeck){ |
| // a show request has been queued up; do it now |
| this.show.apply(this, this._onDeck); |
| this._onDeck=null; |
| } |
| } |
| |
| } |
| ); |
| |
| dijit.showTooltip = function(/*String*/ innerHTML, /*DomNode*/ aroundNode, /*String[]?*/ position){ |
| // summary: |
| // Display tooltip w/specified contents in specified position. |
| // See description of dijit.Tooltip.defaultPosition for details on position parameter. |
| // If position is not specified then dijit.Tooltip.defaultPosition is used. |
| if(!dijit._masterTT){ dijit._masterTT = new dijit._MasterTooltip(); } |
| return dijit._masterTT.show(innerHTML, aroundNode, position); |
| }; |
| |
| dijit.hideTooltip = function(aroundNode){ |
| // summary: |
| // Hide the tooltip |
| if(!dijit._masterTT){ dijit._masterTT = new dijit._MasterTooltip(); } |
| return dijit._masterTT.hide(aroundNode); |
| }; |
| |
| dojo.declare( |
| "dijit.Tooltip", |
| dijit._Widget, |
| { |
| // summary: |
| // Pops up a tooltip (a help message) when you hover over a node. |
| |
| // label: String |
| // Text to display in the tooltip. |
| // Specified as innerHTML when creating the widget from markup. |
| label: "", |
| |
| // showDelay: Integer |
| // Number of milliseconds to wait after hovering over/focusing on the object, before |
| // the tooltip is displayed. |
| showDelay: 400, |
| |
| // connectId: [const] String[] |
| // Id's of domNodes to attach the tooltip to. |
| // When user hovers over any of the specified dom nodes, the tooltip will appear. |
| // |
| // Note: Currently connectId can only be specified on initialization, it cannot |
| // be changed via attr('connectId', ...) |
| // |
| // Note: in 2.0 this will be renamed to connectIds for less confusion. |
| connectId: [], |
| |
| // position: String[] |
| // See description of `dijit.Tooltip.defaultPosition` for details on position parameter. |
| position: [], |
| |
| constructor: function(){ |
| // Map id's of nodes I'm connected to to a list of the this.connect() handles |
| this._nodeConnectionsById = {}; |
| }, |
| |
| _setConnectIdAttr: function(newIds){ |
| for(var oldId in this._nodeConnectionsById){ |
| this.removeTarget(oldId); |
| } |
| dojo.forEach(dojo.isArrayLike(newIds) ? newIds : [newIds], this.addTarget, this); |
| }, |
| |
| _getConnectIdAttr: function(){ |
| var ary = []; |
| for(var id in this._nodeConnectionsById){ |
| ary.push(id); |
| } |
| return ary; |
| }, |
| |
| addTarget: function(/*DOMNODE || String*/ id){ |
| // summary: |
| // Attach tooltip to specified node, if it's not already connected |
| var node = dojo.byId(id); |
| if(!node){ return; } |
| if(node.id in this._nodeConnectionsById){ return; }//Already connected |
| |
| this._nodeConnectionsById[node.id] = [ |
| this.connect(node, "onmouseenter", "_onTargetMouseEnter"), |
| this.connect(node, "onmouseleave", "_onTargetMouseLeave"), |
| this.connect(node, "onfocus", "_onTargetFocus"), |
| this.connect(node, "onblur", "_onTargetBlur") |
| ]; |
| if(dojo.isIE && !node.style.zoom){//preserve zoom |
| // BiDi workaround |
| node.style.zoom = 1; |
| } |
| }, |
| |
| removeTarget: function(/*DOMNODE || String*/ node){ |
| // summary: |
| // Detach tooltip from specified node |
| |
| // map from DOMNode back to plain id string |
| var id = node.id || node; |
| |
| if(id in this._nodeConnectionsById){ |
| dojo.forEach(this._nodeConnectionsById[id], this.disconnect, this); |
| delete this._nodeConnectionsById[id]; |
| } |
| }, |
| |
| postCreate: function(){ |
| dojo.addClass(this.domNode,"dijitTooltipData"); |
| }, |
| |
| startup: function(){ |
| this.inherited(arguments); |
| |
| // If this tooltip was created in a template, or for some other reason the specified connectId[s] |
| // didn't exist during the widget's initialization, then connect now. |
| var ids = this.connectId; |
| dojo.forEach(dojo.isArrayLike(ids) ? ids : [ids], this.addTarget, this); |
| }, |
| |
| _onTargetMouseEnter: function(/*Event*/ e){ |
| // summary: |
| // Handler for mouseenter event on the target node |
| // tags: |
| // private |
| this._onHover(e); |
| }, |
| |
| _onTargetMouseLeave: function(/*Event*/ e){ |
| // summary: |
| // Handler for mouseleave event on the target node |
| // tags: |
| // private |
| this._onUnHover(e); |
| }, |
| |
| _onTargetFocus: function(/*Event*/ e){ |
| // summary: |
| // Handler for focus event on the target node |
| // tags: |
| // private |
| |
| this._focus = true; |
| this._onHover(e); |
| }, |
| |
| _onTargetBlur: function(/*Event*/ e){ |
| // summary: |
| // Handler for blur event on the target node |
| // tags: |
| // private |
| |
| this._focus = false; |
| this._onUnHover(e); |
| }, |
| |
| _onHover: function(/*Event*/ e){ |
| // summary: |
| // Despite the name of this method, it actually handles both hover and focus |
| // events on the target node, setting a timer to show the tooltip. |
| // tags: |
| // private |
| if(!this._showTimer){ |
| var target = e.target; |
| this._showTimer = setTimeout(dojo.hitch(this, function(){this.open(target)}), this.showDelay); |
| } |
| }, |
| |
| _onUnHover: function(/*Event*/ e){ |
| // summary: |
| // Despite the name of this method, it actually handles both mouseleave and blur |
| // events on the target node, hiding the tooltip. |
| // tags: |
| // private |
| |
| // keep a tooltip open if the associated element still has focus (even though the |
| // mouse moved away) |
| if(this._focus){ return; } |
| |
| if(this._showTimer){ |
| clearTimeout(this._showTimer); |
| delete this._showTimer; |
| } |
| this.close(); |
| }, |
| |
| open: function(/*DomNode*/ target){ |
| // summary: |
| // Display the tooltip; usually not called directly. |
| // tags: |
| // private |
| |
| if(this._showTimer){ |
| clearTimeout(this._showTimer); |
| delete this._showTimer; |
| } |
| dijit.showTooltip(this.label || this.domNode.innerHTML, target, this.position); |
| |
| this._connectNode = target; |
| this.onShow(target, this.position); |
| }, |
| |
| close: function(){ |
| // summary: |
| // Hide the tooltip or cancel timer for show of tooltip |
| // tags: |
| // private |
| |
| if(this._connectNode){ |
| // if tooltip is currently shown |
| dijit.hideTooltip(this._connectNode); |
| delete this._connectNode; |
| this.onHide(); |
| } |
| if(this._showTimer){ |
| // if tooltip is scheduled to be shown (after a brief delay) |
| clearTimeout(this._showTimer); |
| delete this._showTimer; |
| } |
| }, |
| |
| onShow: function(target, position){ |
| // summary: |
| // Called when the tooltip is shown |
| // tags: |
| // callback |
| }, |
| |
| onHide: function(){ |
| // summary: |
| // Called when the tooltip is hidden |
| // tags: |
| // callback |
| }, |
| |
| uninitialize: function(){ |
| this.close(); |
| this.inherited(arguments); |
| } |
| } |
| ); |
| |
| // dijit.Tooltip.defaultPosition: String[] |
| // This variable controls the position of tooltips, if the position is not specified to |
| // the Tooltip widget or *TextBox widget itself. It's an array of strings with the following values: |
| // |
| // * before: places tooltip to the left of the target node/widget, or to the right in |
| // the case of RTL scripts like Hebrew and Arabic |
| // * after: places tooltip to the right of the target node/widget, or to the left in |
| // the case of RTL scripts like Hebrew and Arabic |
| // * above: tooltip goes above target node |
| // * below: tooltip goes below target node |
| // |
| // The list is positions is tried, in order, until a position is found where the tooltip fits |
| // within the viewport. |
| // |
| // Be careful setting this parameter. A value of "above" may work fine until the user scrolls |
| // the screen so that there's no room above the target node. Nodes with drop downs, like |
| // DropDownButton or FilteringSelect, are especially problematic, in that you need to be sure |
| // that the drop down and tooltip don't overlap, even when the viewport is scrolled so that there |
| // is only room below (or above) the target node, but not both. |
| dijit.Tooltip.defaultPosition = ["after", "before"]; |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.action2d.Tooltip"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.action2d.Tooltip"] = true; |
| dojo.provide("dojox.charting.action2d.Tooltip"); |
| |
| |
| |
| |
| |
| |
| |
| |
| (function(){ |
| var DEFAULT_TEXT = function(o){ |
| var t = o.run && o.run.data && o.run.data[o.index]; |
| if(t && typeof t != "number" && (t.tooltip || t.text)){ |
| return t.tooltip || t.text; |
| } |
| if(o.element == "candlestick"){ |
| return '<table cellpadding="1" cellspacing="0" border="0" style="font-size:0.9em;">' |
| + '<tr><td>Open:</td><td align="right"><strong>' + o.data.open + '</strong></td></tr>' |
| + '<tr><td>High:</td><td align="right"><strong>' + o.data.high + '</strong></td></tr>' |
| + '<tr><td>Low:</td><td align="right"><strong>' + o.data.low + '</strong></td></tr>' |
| + '<tr><td>Close:</td><td align="right"><strong>' + o.data.close + '</strong></td></tr>' |
| + (o.data.mid !== undefined ? '<tr><td>Mid:</td><td align="right"><strong>' + o.data.mid + '</strong></td></tr>' : '') |
| + '</table>'; |
| } |
| return o.element == "bar" ? o.x : o.y; |
| }; |
| |
| var df = dojox.lang.functional, pi4 = Math.PI / 4, pi2 = Math.PI / 2; |
| |
| dojo.declare("dojox.charting.action2d.Tooltip", dojox.charting.action2d.Base, { |
| // the data description block for the widget parser |
| defaultParams: { |
| text: DEFAULT_TEXT // the function to produce a tooltip from the object |
| }, |
| optionalParams: {}, // no optional parameters |
| |
| constructor: function(chart, plot, kwArgs){ |
| // process optional named parameters |
| this.text = kwArgs && kwArgs.text ? kwArgs.text : DEFAULT_TEXT; |
| |
| this.connect(); |
| }, |
| |
| process: function(o){ |
| if(o.type === "onplotreset" || o.type === "onmouseout"){ |
| dijit.hideTooltip(this.aroundRect); |
| this.aroundRect = null; |
| return; |
| } |
| |
| if(!o.shape || o.type !== "onmouseover"){ return; } |
| |
| // calculate relative coordinates and the position |
| var aroundRect = {type: "rect"}, position = ["after", "before"]; |
| switch(o.element){ |
| case "marker": |
| aroundRect.x = o.cx; |
| aroundRect.y = o.cy; |
| aroundRect.width = aroundRect.height = 1; |
| break; |
| case "circle": |
| aroundRect.x = o.cx - o.cr; |
| aroundRect.y = o.cy - o.cr; |
| aroundRect.width = aroundRect.height = 2 * o.cr; |
| break; |
| case "column": |
| position = ["above", "below"]; |
| // intentional fall down |
| case "bar": |
| aroundRect = dojo.clone(o.shape.getShape()); |
| break; |
| case "candlestick": |
| aroundRect.x = o.x; |
| aroundRect.y = o.y; |
| aroundRect.width = o.width; |
| aroundRect.height = o.height; |
| break; |
| default: |
| //case "slice": |
| if(!this.angles){ |
| // calculate the running total of slice angles |
| if(typeof o.run.data[0] == "number"){ |
| this.angles = df.map(df.scanl(o.run.data, "+", 0), |
| "* 2 * Math.PI / this", df.foldl(o.run.data, "+", 0)); |
| }else{ |
| this.angles = df.map(df.scanl(o.run.data, "a + b.y", 0), |
| "* 2 * Math.PI / this", df.foldl(o.run.data, "a + b.y", 0)); |
| } |
| } |
| var angle = (this.angles[o.index] + this.angles[o.index + 1]) / 2; |
| aroundRect.x = o.cx + o.cr * Math.cos(angle); |
| aroundRect.y = o.cy + o.cr * Math.sin(angle); |
| aroundRect.width = aroundRect.height = 1; |
| // calculate the position |
| if(angle < pi4){ |
| // do nothing: the position is right |
| }else if(angle < pi2 + pi4){ |
| position = ["below", "above"]; |
| }else if(angle < Math.PI + pi4){ |
| position = ["before", "after"]; |
| }else if(angle < 2 * Math.PI - pi4){ |
| position = ["above", "below"]; |
| } |
| /* |
| else{ |
| // do nothing: the position is right |
| } |
| */ |
| break; |
| } |
| |
| // adjust relative coordinates to absolute, and remove fractions |
| var lt = dojo.coords(this.chart.node, true); |
| aroundRect.x += lt.x; |
| aroundRect.y += lt.y; |
| aroundRect.x = Math.round(aroundRect.x); |
| aroundRect.y = Math.round(aroundRect.y); |
| aroundRect.width = Math.ceil(aroundRect.width); |
| aroundRect.height = Math.ceil(aroundRect.height); |
| this.aroundRect = aroundRect; |
| |
| dijit.showTooltip(this.text(o), this.aroundRect, position); |
| } |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.widget.Chart2D"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.widget.Chart2D"] = true; |
| dojo.provide("dojox.charting.widget.Chart2D"); |
| |
| |
| |
| |
| |
| // require all actions to support references by name |
| |
| |
| |
| |
| |
| |
| (function(){ |
| var collectParams, collectAxisParams, collectPlotParams, |
| collectActionParams, collectDataParams, |
| notNull = function(o){ return o; }, |
| df = dojox.lang.functional, |
| du = dojox.lang.utils, |
| dc = dojox.charting, |
| d = dojo; |
| |
| dojo.declare("dojox.charting.widget.Chart2D", dijit._Widget, { |
| // parameters for the markup |
| |
| // theme for the chart |
| theme: null, |
| |
| // margins for the chart: {l: 10, r: 10, t: 10, b: 10} |
| margins: null, |
| |
| // chart area |
| stroke: null, |
| fill: null, |
| |
| // methods |
| |
| buildRendering: function(){ |
| var n = this.domNode = this.srcNodeRef; |
| |
| // collect chart parameters |
| var axes = d.query("> .axis", n).map(collectAxisParams).filter(notNull), |
| plots = d.query("> .plot", n).map(collectPlotParams).filter(notNull), |
| actions = d.query("> .action", n).map(collectActionParams).filter(notNull), |
| series = d.query("> .series", n).map(collectDataParams).filter(notNull); |
| |
| // build the chart |
| n.innerHTML = ""; |
| var c = this.chart = new dc.Chart2D(n, { |
| margins: this.margins, |
| stroke: this.stroke, |
| fill: this.fill |
| }); |
| |
| // add collected parameters |
| if(this.theme){ |
| c.setTheme(this.theme); |
| } |
| axes.forEach(function(axis){ |
| c.addAxis(axis.name, axis.kwArgs); |
| }); |
| plots.forEach(function(plot){ |
| c.addPlot(plot.name, plot.kwArgs); |
| }); |
| |
| this.actions = actions.map(function(action){ |
| return new action.action(c, action.plot, action.kwArgs) |
| }); |
| |
| var render = df.foldl(series, function(render, series){ |
| if(series.type == "data"){ |
| c.addSeries(series.name, series.data, series.kwArgs); |
| render = true; |
| }else{ |
| c.addSeries(series.name, [0], series.kwArgs); |
| var kw = {}; |
| du.updateWithPattern( |
| kw, |
| series.kwArgs, |
| { |
| "query": "", |
| "queryOptions": null, |
| "start": 0, |
| "count": 1 //, |
| // "sort": [] |
| }, |
| true |
| ); |
| if(series.kwArgs.sort){ |
| // sort is a complex object type and doesn't survive coercian |
| kw.sort = dojo.clone(series.kwArgs.sort); |
| } |
| d.mixin(kw, { |
| onComplete: function(data){ |
| var values; |
| if("valueFn" in series.kwArgs){ |
| var fn = series.kwArgs.valueFn; |
| values = d.map(data, function(x){ |
| return fn(series.data.getValue(x, series.field, 0)); |
| }); |
| }else{ |
| values = d.map(data, function(x){ |
| return series.data.getValue(x, series.field, 0); |
| }); |
| } |
| c.addSeries(series.name, values, series.kwArgs).render(); |
| } |
| }); |
| series.data.fetch(kw); |
| } |
| return render; |
| }, false); |
| if(render){ c.render(); } |
| }, |
| destroy: function(){ |
| // summary: properly destroy the widget |
| this.chart.destroy(); |
| this.inherited(arguments); |
| }, |
| resize: function(box){ |
| // summary: resize the widget |
| if(box.w > 0 && box.h > 0){ |
| dojo.marginBox(this.domNode, box); |
| this.chart.resize(); |
| } |
| } |
| }); |
| |
| collectParams = function(node, type, kw){ |
| var dp = eval("(" + type + ".prototype.defaultParams)"); |
| var x, attr; |
| for(x in dp){ |
| if(x in kw){ continue; } |
| attr = node.getAttribute(x); |
| kw[x] = du.coerceType(dp[x], attr == null || typeof attr == "undefined" ? dp[x] : attr); |
| } |
| var op = eval("(" + type + ".prototype.optionalParams)"); |
| for(x in op){ |
| if(x in kw){ continue; } |
| attr = node.getAttribute(x); |
| if(attr != null){ |
| kw[x] = du.coerceType(op[x], attr); |
| } |
| } |
| }; |
| |
| collectAxisParams = function(node){ |
| var name = node.getAttribute("name"), type = node.getAttribute("type"); |
| if(!name){ return null; } |
| var o = {name: name, kwArgs: {}}, kw = o.kwArgs; |
| if(type){ |
| if(dc.axis2d[type]){ |
| type = dojox._scopeName + ".charting.axis2d." + type; |
| } |
| var axis = eval("(" + type + ")"); |
| if(axis){ kw.type = axis; } |
| }else{ |
| type = dojox._scopeName + ".charting.axis2d.Default"; |
| } |
| collectParams(node, type, kw); |
| return o; |
| }; |
| |
| collectPlotParams = function(node){ |
| // var name = d.attr(node, "name"), type = d.attr(node, "type"); |
| var name = node.getAttribute("name"), type = node.getAttribute("type"); |
| if(!name){ return null; } |
| var o = {name: name, kwArgs: {}}, kw = o.kwArgs; |
| if(type){ |
| if(dc.plot2d[type]){ |
| type = dojox._scopeName + ".charting.plot2d." + type; |
| } |
| var plot = eval("(" + type + ")"); |
| if(plot){ kw.type = plot; } |
| }else{ |
| type = dojox._scopeName + ".charting.plot2d.Default"; |
| } |
| collectParams(node, type, kw); |
| return o; |
| }; |
| |
| collectActionParams = function(node){ |
| // var plot = d.attr(node, "plot"), type = d.attr(node, "type"); |
| var plot = node.getAttribute("plot"), type = node.getAttribute("type"); |
| if(!plot){ plot = "default"; } |
| var o = {plot: plot, kwArgs: {}}, kw = o.kwArgs; |
| if(type){ |
| if(dc.action2d[type]){ |
| type = dojox._scopeName + ".charting.action2d." + type; |
| } |
| var action = eval("(" + type + ")"); |
| if(!action){ return null; } |
| o.action = action; |
| }else{ |
| return null; |
| } |
| collectParams(node, type, kw); |
| return o; |
| }; |
| |
| collectDataParams = function(node){ |
| var ga = d.partial(d.attr, node); |
| var name = ga("name"); |
| if(!name){ return null; } |
| var o = { name: name, kwArgs: {} }, kw = o.kwArgs, t; |
| t = ga("plot"); |
| if(t != null){ kw.plot = t; } |
| t = ga("marker"); |
| if(t != null){ kw.marker = t; } |
| t = ga("stroke"); |
| if(t != null){ kw.stroke = eval("(" + t + ")"); } |
| t = ga("fill"); |
| if(t != null){ kw.fill = eval("(" + t + ")"); } |
| t = ga("legend"); |
| if(t != null){ kw.legend = t; } |
| t = ga("data"); |
| if(t != null){ |
| o.type = "data"; |
| o.data = dojo.map(String(t).split(','), Number); |
| return o; |
| } |
| t = ga("array"); |
| if(t != null){ |
| o.type = "data"; |
| o.data = eval("(" + t + ")"); |
| return o; |
| } |
| t = ga("store"); |
| if(t != null){ |
| o.type = "store"; |
| o.data = eval("(" + t + ")"); |
| t = ga("field"); |
| o.field = t != null ? t : "value"; |
| t = ga("query"); |
| if(!!t){ kw.query = t; } |
| t = ga("queryOptions"); |
| if(!!t){ kw.queryOptions = eval("(" + t + ")"); } |
| t = ga("start"); |
| if(!!t){ kw.start = Number(t); } |
| t = ga("count"); |
| if(!!t){ kw.count = Number(t); } |
| t = ga("sort"); |
| if(!!t){ kw.sort = eval("("+t+")"); } |
| t = ga("valueFn"); |
| if(!!t){ kw.valueFn = df.lambda(t); } |
| return o; |
| } |
| return null; |
| }; |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.themes.ET.greys"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.themes.ET.greys"] = true; |
| dojo.provide("dojox.charting.themes.ET.greys"); |
| |
| dojo.deprecated("dojox.charting.themes.ET.greys", "1.3"); |
| |
| (function(){ |
| var dxc=dojox.charting; |
| dxc.themes.ET.greys = new dxc.Theme({ |
| antiAlias: false, |
| chart: { |
| stroke: null, |
| fill: "inherit" |
| }, |
| plotarea: { |
| // stroke: { width: 0.2, color: "#666666" }, |
| stroke: null, |
| fill: "transparent" |
| }, |
| axis:{ |
| stroke:{ width: 0 }, |
| line:{ width: 0 }, |
| majorTick:{ |
| color: "#666666", |
| width: 1, |
| length: 5 |
| }, |
| minorTick: { |
| color: "black", |
| width: 0.5, |
| length: 2 |
| }, |
| font:"normal normal normal 8pt Tahoma", |
| fontColor:"#999999" |
| }, |
| series:{ |
| outline:{ width: 0, color: "black" }, |
| stroke: { width: 1, color: "black" }, |
| fill: dojo.colorFromHex("#3b444b"), |
| font: "normal normal normal 7pt Tahoma", // label |
| fontColor: "#717171" |
| }, |
| marker:{ // any markers on a series. |
| stroke:{ width:1 }, |
| fill:"#333", |
| font:"normal normal normal 7pt Tahoma", // label |
| fontColor:"#000" |
| }, |
| colors:[ |
| dojo.colorFromHex("#8a8c8f"), |
| dojo.colorFromHex("#4b4b4b"), |
| dojo.colorFromHex("#3b444b"), |
| dojo.colorFromHex("#2e2d30"), |
| dojo.colorFromHex("#000000") |
| ] |
| }); |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.widget.Sparkline"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.widget.Sparkline"] = true; |
| dojo.provide("dojox.charting.widget.Sparkline"); |
| |
| |
| |
| |
| (function(){ |
| |
| var d = dojo; |
| |
| dojo.declare("dojox.charting.widget.Sparkline", |
| dojox.charting.widget.Chart2D, |
| { |
| theme: dojox.charting.themes.ET.greys, |
| margins: { l: 0, r: 0, t: 0, b: 0 }, |
| type: "Lines", |
| valueFn: "Number(x)", |
| store: "", |
| field: "", |
| query: "", |
| queryOptions: "", |
| start: "0", |
| count: "Infinity", |
| sort: "", |
| data: "", |
| name: "default", |
| buildRendering: function(){ |
| var n = this.srcNodeRef; |
| if( !n.childNodes.length || // shortcut the query |
| !d.query("> .axis, > .plot, > .action, > .series", n).length){ |
| var plot = document.createElement("div"); |
| d.attr(plot, { |
| "class": "plot", |
| "name": "default", |
| "type": this.type |
| }); |
| n.appendChild(plot); |
| |
| var series = document.createElement("div"); |
| d.attr(series, { |
| "class": "series", |
| plot: "default", |
| name: this.name, |
| start: this.start, |
| count: this.count, |
| valueFn: this.valueFn |
| }); |
| d.forEach( |
| ["store", "field", "query", "queryOptions", "sort", "data"], |
| function(i){ |
| if(this[i].length){ |
| d.attr(series, i, this[i]); |
| } |
| }, |
| this |
| ); |
| n.appendChild(series); |
| } |
| this.inherited(arguments); |
| } |
| } |
| ); |
| |
| })(); |
| |
| } |
| |
| if(!dojo._hasResource["dojox.charting.widget.Legend"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
| dojo._hasResource["dojox.charting.widget.Legend"] = true; |
| dojo.provide("dojox.charting.widget.Legend"); |
| |
| |
| |
| |
| |
| |
| |
| dojo.declare("dojox.charting.widget.Legend", [dijit._Widget, dijit._Templated], { |
| // summary: A legend for a chart. A legend contains summary labels for |
| // each series of data contained in the chart. |
| // |
| // Set the boolean horizontal attribute to false to layout legend labels vertically. |
| // |
| // (Line or Scatter charts (colored lines with shape symbols) ) |
| // -o- Series1 -X- Series2 -v- Series3 |
| // |
| // (Area/Bar/Pie charts (letters represent colors)) |
| // [a] Series1 [b] Series2 [c] Series3 |
| |
| chartRef: "", |
| horizontal: true, |
| swatchSize: 18, |
| |
| templateString: "<table dojoAttachPoint='legendNode' class='dojoxLegendNode'><tbody dojoAttachPoint='legendBody'></tbody></table>", |
| |
| legendNode: null, |
| legendBody: null, |
| |
| postCreate: function(){ |
| if(!this.chart){ |
| if(!this.chartRef){ return; } |
| this.chart = dijit.byId(this.chartRef); |
| if(!this.chart){ |
| var node = dojo.byId(this.chartRef); |
| if(node){ |
| this.chart = dijit.byNode(node); |
| }else{ |
| console.log("Could not find chart instance with id: " + this.chartRef); |
| return; |
| } |
| } |
| this.series = this.chart.chart.series; |
| }else{ |
| this.series = this.chart.series; |
| } |
| |
| this.refresh(); |
| }, |
| refresh: function(){ |
| // summary: regenerates the legend to reflect changes to the chart |
| |
| var df = dojox.lang.functional; |
| |
| // cleanup |
| if(this._surfaces){ |
| dojo.forEach(this._surfaces, function(surface){ |
| surface.destroy(); |
| }); |
| } |
| this._surfaces = []; |
| while(this.legendBody.lastChild){ |
| dojo.destroy(this.legendBody.lastChild); |
| } |
| |
| if(this.horizontal){ |
| dojo.addClass(this.legendNode, "dojoxLegendHorizontal"); |
| // make a container <tr> |
| this._tr = dojo.doc.createElement("tr"); |
| this.legendBody.appendChild(this._tr); |
| } |
| |
| var s = this.series; |
| if(s.length == 0){ |
| return; |
| } |
| if(s[0].chart.stack[0].declaredClass == "dojox.charting.plot2d.Pie"){ |
| var t = s[0].chart.stack[0]; |
| if(typeof t.run.data[0] == "number"){ |
| var filteredRun = df.map(t.run.data, "Math.max(x, 0)"); |
| if(df.every(filteredRun, "<= 0")){ |
| return; |
| } |
| var slices = df.map(filteredRun, "/this", df.foldl(filteredRun, "+", 0)); |
| dojo.forEach(slices, function(x, i){ |
| this._addLabel(t.dyn[i], t._getLabel(x * 100) + "%"); |
| }, this); |
| }else{ |
| dojo.forEach(t.run.data, function(x, i){ |
| this._addLabel(t.dyn[i], x.legend || x.text || x.y); |
| }, this); |
| } |
| }else{ |
| dojo.forEach(s, function(x){ |
| this._addLabel(x.dyn, x.legend || x.name); |
| }, this); |
| } |
| }, |
| _addLabel: function(dyn, label){ |
| // create necessary elements |
| var icon = dojo.doc.createElement("td"), |
| text = dojo.doc.createElement("td"), |
| div = dojo.doc.createElement("div"); |
| dojo.addClass(icon, "dojoxLegendIcon"); |
| dojo.addClass(text, "dojoxLegendText"); |
| div.style.width = this.swatchSize + "px"; |
| div.style.height = this.swatchSize + "px"; |
| icon.appendChild(div); |
| |
| // create a skeleton |
| if(this._tr){ |
| // horizontal |
| this._tr.appendChild(icon); |
| this._tr.appendChild(text); |
| }else{ |
| // vertical |
| var tr = dojo.doc.createElement("tr"); |
| this.legendBody.appendChild(tr); |
| tr.appendChild(icon); |
| tr.appendChild(text); |
| } |
| |
| // populate the skeleton |
| this._makeIcon(div, dyn); |
| text.innerHTML = String(label); |
| }, |
| _makeIcon: function(div, dyn){ |
| var mb = { h: this.swatchSize, w: this.swatchSize }; |
| var surface = dojox.gfx.createSurface(div, mb.w, mb.h); |
| this._surfaces.push(surface); |
| if(dyn.fill){ |
| // regions |
| surface.createRect({x: 2, y: 2, width: mb.w - 4, height: mb.h - 4}). |
| setFill(dyn.fill).setStroke(dyn.stroke); |
| }else if(dyn.stroke || dyn.marker){ |
| // draw line |
| var line = {x1: 0, y1: mb.h / 2, x2: mb.w, y2: mb.h / 2}; |
| if(dyn.stroke){ |
| surface.createLine(line).setStroke(dyn.stroke); |
| } |
| if(dyn.marker){ |
| // draw marker on top |
| var c = {x: mb.w / 2, y: mb.h / 2}; |
| if(dyn.stroke){ |
| surface.createPath({path: "M" + c.x + " " + c.y + " " + dyn.marker}). |
| setFill(dyn.stroke.color).setStroke(dyn.stroke); |
| }else{ |
| surface.createPath({path: "M" + c.x + " " + c.y + " " + dyn.marker}). |
| setFill(dyn.color).setStroke(dyn.color); |
| } |
| } |
| }else{ |
| // nothing |
| surface.createRect({x: 2, y: 2, width: mb.w - 4, height: mb.h - 4}). |
| setStroke("black"); |
| surface.createLine({x1: 2, y1: 2, x2: mb.w - 2, y2: mb.h - 2}).setStroke("black"); |
| surface.createLine({x1: 2, y1: mb.h - 2, x2: mb.w - 2, y2: 2}).setStroke("black"); |
| } |
| } |
| }); |
| |
| } |
| |