var Figure = Class.create({ src: "", initialize: function(id, params){ if (Prototype.Browser.IE) return; var elem = document.getElementById(this.id_ = id); if (!elem) return; elem.JSControl = this; this.hs_ = new HandleStorage(elem); this.container = this.hs_.GetHandle("container"); ["defsSrc", "dataSrc", "gridID"].each(function(key){ if (typeof params[key] !== "undefined") this[key] = params[key]; }, this); this.loader = new RequestLoader(); this.customized = this.defsSrc && String(this.defsSrc).indexOf("/act/") === 0; var vis = elem.getAttribute("visibility"); if ("no" !== vis) this.Load.bind(this).defer(); this.attrs_ = {}; }, ID: function(){ return this.id_; }, SetAttribute: function(nam, val){ this.attrs_[nam] = val; }, Title: function(){ if ("title" in this.attrs_) return this.attrs_["title"]; var grid = this.Grid(); if (grid) return grid.Title() + " — `Grapher`"; return null; }, awnd: function(){ return AControl.GetParentWindow(document.getElementById(this.gridID || this.ID())); }, toggle_confwin: function(){ this[this.confwin && this.confwin.IsVisible() ? "hideConfWin" : "showConfWin"](); }, set_callbacks: function(){ if (this.callbacks_) return; this.callbacks_ = new Array(); [["configure", this.toggle_confwin], ["print", this.printFigure], ["refresh", this.refreshFigure]].each( function(args){ var button = this.hs_.GetHandle(args[0]); if (button) this.callbacks_.push([button, "click", args[1].bind(this)]); }, this); JSControl.add_callbacks(this.callbacks_); }, OnContainerResize: function(cont_w, cont_h){ var diff_w = this.container.parentNode.offsetWidth - this.container.offsetWidth; var diff_h = this.container.parentNode.offsetHeight - this.container.offsetHeight; var new_w = Math.max(cont_w - diff_w, 200); var new_h = Math.max(cont_h - diff_h, 100); Element.setStyle(this.container, {"width": new_w + "px", "height": new_h + "px"}); var sizesnode = this.getXMLPropertiesChildByTagName("sizes"); if (sizesnode){ XMLElement.WriteAttributes(sizesnode, {"width": new_w, "height": new_h}); this.saveElementToCustomization(sizesnode); } this.transformXMLtoSVG(true); }, dataSetFeederLoaded: false, graphsXMLLoaded: false, getDataFeeder: function(){ var thisobj = this; var delayTime = 1; var maxLoadTry = 17; if (this.gridID) this.loader.addRequest({ "id": "DataSetFeeder", "trialNumber": 0, "action": function(){ if (++this.trialNumber > maxLoadTry) return LogE("Number of load trials exceeded.\nFailed to load \"" + this.id + "\"."); var gridJSControl = thisobj.Grid(); if (!gridJSControl) return this.load.bind(this).delay(delayTime); var dataSource = gridJSControl.DataSource(); if (!dataSource) return this.load.bind(this).delay(delayTime); this.trialNumber = 0; thisobj.dataSourceURL = "/srv/" + dataSource.Feeder().ContName() + "/" + dataSource.Feeder().ObjName(); thisobj.columns = gridJSControl.Columns(); } }); else this.loader.addRequest(new Request({ id: "DataSetFeeder", src: function(){ return thisobj.dataSrc; }, usePrototype: false, onFinish: function(){ var dataSetFeeder = this.transport.responseXML.getElementsByTagName("DataSetFeederIF")[0]; dataSetFeeder.normalize(); thisobj.dataSourceURL = "/srv/" + // $A(dataSetFeeder.childNodes).collect(this.node_text, this).join("/"); } })); }, getColumnByName: function(colName){ if (typeof this.columns == "undefined") return {}; if (typeof this.columns[colName] == "undefined") this.columns.each(function(column){ this.columns[column.Name] = column; }, this); return this.columns[colName]; }, Grid: function(){ if (typeof this.gridID === "undefined") return null; var elem = document.getElementById(this.gridID); if (!elem) return null; return elem.JSControl || null; }, appendTypeFiles: function(node){ var grid = this.Grid(); if (!grid) return; var doc = node.ownerDocument; $A(grid.TypeFiles()).each(function(typeFile){ var typeElement = doc.createElement("types"); typeElement.setAttribute("url", "/types/" + typeFile + ".xml"); node.appendChild(typeElement); }); }, TypeXML: function(){ var grid = this.Grid(); if (!grid) return null; return AXML.getTypeSet(grid.TypeFiles()).XML(); }, feeder: function(){ return this.dataSourceURL; }, get_resolution: function(graph){ var res = graph.getAttribute("resolution"); var num = parseInt(res, 10); if (!isNaN(num)) res = num; var xdata = null; for (var child = graph.firstChild; child; child = child.nextSibling){ if (child.nodeType === Node.ELEMENT_NODE && Node.localName(child) === "xdata"){ xdata = child; break; } } if (!xdata) return res; return this.correctResolution(res, xdata.getAttribute("column")); }, get_aggregation: function(graph){ return graph.getAttribute("aggregation") || "sum"; }, graph_attrs: function(graph){ return {"Id": graph.getAttribute("id"),// "Aggregation": this.get_aggregation(graph),// "Resolution": this.get_resolution(graph)}; }, get_series_data: function(args){ if (!args) return null; var result = null; new ServerCall(this.feeder() + "/GetSeriesData", URLSerializeVS({"series": args}), { "thisObject": this, "onSuccess": function(apacket){ result = apacket.Data(); }, "onException": function(err, code){ alert(["Error in \"GetSeriesData\"", "CODE: " + code, "MESSAGE: " + err].join("\n")); } }, false); return result; }, process_series_data: function(sdata, xmldoc, xtype, ytype, toreplace){ if (!(sdata instanceof SeriesData)){ alert("Not an instance of SeriesData:\n" + Object.toJSON(sdata)); return; } var gdata = xmldoc.createElement("data"); if (toreplace && toreplace.parentNode) toreplace.parentNode.replaceChild(gdata, toreplace); else xmldoc.documentElement.appendChild(gdata); gdata.setAttribute("graphID", sdata.ID()); var res = sdata.Resolution(); var xdata; if (res === "unique" && sdata.X().collect(this.is_double, this).all()) xdata = sdata.X(); else{ xdata = new Array(sdata.X().length); for (var iii = 0; iii < xdata.length; ++iii) xdata[iii] = iii + 1; } gdata.appendChild(xmldoc.createElement("xdata")).appendChild(xmldoc.createTextNode(xdata.join(","))); gdata.appendChild(xmldoc.createElement("xlabels")).appendChild(xmldoc.createTextNode(this.format_labels(sdata.X(), res, xtype))); gdata.appendChild(xmldoc.createElement("ydata")).appendChild(xmldoc.createTextNode(this.generate_data(sdata.Y()))); gdata.appendChild(xmldoc.createElement("ylabels")).appendChild(xmldoc.createTextNode(this.format_labels(sdata.Y(), res, ytype))); }, is_double: function(val){ while (val instanceof Optional) val = val.Value(); return val instanceof Double; }, unwrap_optional: function(val){ while (val instanceof Optional) val = val.Value(); return val; }, format_labels: function(arr, res, type){ return $A(arr).collect(this.unwrap_optional, this).collect(function(val){ if (typeof val === "string"){ if (type) for (var item = type.firstChild; item; item = item.nextSibling){ if (item.nodeType === Node.ELEMENT_NODE && item.getAttribute("value") === val){ val = item.getAttribute("label"); break; } } return val.replace(",", ";"); }else if (!val) return ""; if (val.Value) val = val.Value(); if (typeof val === "number"){ return val.toFixed(2); }else if (val instanceof Time){ var adate = val.GetADate(); var atime = val.GetATime(); switch (res){ case "year": val = adate.GetYear(); break; case "month": val = [adate.GetMonth().toPaddedString(2), adate.GetYear()].join("."); break; case "day": val = [adate.GetDay(), adate.GetMonth(), adate.GetYear()].invoke("toPaddedString", 2).join("."); break; case "hour": val = [adate.GetDay(), adate.GetMonth()].invoke("toPaddedString", 2).join(".") + " " + // [atime.GetHours(), 0].invoke("toPaddedString", 2).join(":"); break; case "minute": val = [atime.GetHours(), atime.GetMinutes()].invoke("toPaddedString", 2).join(":"); break; case "second": val = [atime.GetHours(), atime.GetMinutes(), atime.GetSeconds()].invoke("toPaddedString", 2).join(":"); break; default: val = val.IsIncorrect() ? "" : adate.toString() + " " + // [atime.GetHours(), atime.GetMinutes(), atime.GetSeconds()].invoke("toPaddedString", 2).join(":"); break; } } return String(val); }).join(","); }, generate_data: function(arr){ return $A(arr).collect(this.unwrap_optional, this).collect(String, window).join(","); }, column_type: function(colname){ var col = this.getColumnByName(colname); if (!col) return null; var typename = col.TypeName; if (!typename) return null; var types = this.TypeXML(); return AXML.SelectNode(types.documentElement, "st:types/st:type[@id=\"" + typename + "\"]", {"st": STURI}) || null; }, loadDataAndColumnHeaders: function(){ this.loader.AddRequest({ "required": ["DataSetFeeder", "GraphsXML"], "action": function(){ var graphs = this.xmlDOM.getElementsByTagName("graph"); if (graphs && graphs.length > 0) try{ var args = new Array(); var types = new Array(); $A(graphs).each(function(graph){ var xdata = AXML.SelectNode(graph, "xdata", {}); var series = this.graph_attrs(graph); var xtype = this.column_type(series["XColumn"] = xdata.getAttribute("column")); $A(AXML.SelectNodes(graph, "ydata", {})).each(function(ydata){ var myseries = Object.clone(series); var ytype = this.column_type(myseries["YColumn"] = ydata.getAttribute("column")); args.push(new GraphSeries(myseries)); types.push([xtype, ytype]); }, this); }, this); var data = this.get_series_data(args); if (data && data.length > 0){ if (data.length != types.length) throw new Error("data.length != types.length"); for (var iii = 0 ; iii < data.length; ++iii) this.process_series_data(data[iii], this.xmlDOM, types[iii][0], types[iii][1]); } }catch(err){ if (err instanceof Error) alert("ERROR: name=" + err.name + ", message=" + err.message); else alert("ERROR: " + err); return; } this.loader.AddRequest({"required": ["FigureTransformations"], "action": function(){ this.transformXMLtoSVG(true); Element.fire(this.container, "figure:loaded"); this.set_callbacks(); }.bind(this)}); }.bind(this) }); if (!this.gridID){ var thisobj = this; this.loader.addRequest(new Request({ id: "ColumnHeaders", src: function(){ return(thisobj.dataSourceURL + "/PassHeader"); }, useServerCall: true, required: ["DataSetFeeder"], onFinish: function(){ thisobj.columns = this.result.Header; } })); } }, correctResolution: function(resolution, xcolname){ var column = this.getColumnByName(xcolname); if (!column || typeof column["Type"] == "undefined") return resolution; var coltype = parseInt(column["Type"], 10); var is_datetime = coltype == CT_DATETIME; var is_number = [CT_DECIMAL, CT_INTEGER, CT_DOUBLE, CT_INT64].include(coltype); if (!is_number && !is_datetime) return "unique"; else if (is_number && resolution != "unique" && !Object.isNumber(resolution)) return Figure.defaults["resolution"]; return resolution; }, loadStaticData: function(){ var thisobj = this; if (this.customized) this.loader.addRequest({ id: "CustomizationToGraphsTransformations", static: true, src: "/xslt/CustomizationToGraphs.xsl", onFinish: function(){ thisobj.fromCustomizationXSL = this.GetResponseXML(); } }); this.loader.addRequest({ id: "FigureTransformations", static: true, src: "/xslt/figure.xsl", onFinish: function(){ thisobj.xslDOM = this.GetResponseXML();} }); }, loadDynamicData: function(){ this.container.setStyle({"cursor": "wait"}); this.loader.clear(["CustomizedGraphsXML", "GraphsXML", "DataSetFeeder", "ColumnHeaders", "TransformData", "MergeXML", "GetSVG"]); var thisobj = this; if (this.customized){ this.loader.AddRequest({ id: "CustomizedGraphsXML", src: this.defsSrc, onFinish: function(){ thisobj.customizedGraphsXML = this.GetResponseXML(); } }); this.loader.AddRequest({ "id": "GraphsXML", "required": ["CustomizationToGraphsTransformations", "CustomizedGraphsXML"], "action": function(){ this.xmlDOM = JSControl.TransformToDocument(this.customizedGraphsXML, this.fromCustomizationXSL); }.bind(this) }); }else{ this.loader.addRequest(new Request({ id: "GraphsXML", src: this.defsSrc, onFinish: function(){ thisobj.xmlDOM = this.transport.responseXML; } })); } this.getDataFeeder(); this.loadDataAndColumnHeaders(); }, Load: function(){ if (this.loadStarted) return; this.loadStaticData(); this.loadDynamicData(); this.loadStarted = true; }, addCustomization: function(params){ if (typeof this.cust_sc_ === "undefined") this.cust_sc_ = {}; var wnd = params.window; if (this.cust_sc_[wnd]) this.cust_sc_[wnd].Abort(); this.cust_sc_[wnd] = new ServerCall("/srv/WWW/WWWWorker/AddCustomization", URLSerializeVS(params), { "thisObject": this, "onSuccess": function(){ delete this.cust_sc_[wnd]; }, "onException": function(msg, code){ alert(["Error in \"/srv/WWW/WWWWorker/AddCustomization\"", "CODE: " + code, "MESSAGE: " + msg].join("\n")); delete this.cust_sc_[wnd]; } }); }, saveAllToCustomization: function(){ var params = {}; if (this.customized) params["removeExisting"] = true; else{ var awnd = this.awnd(); if (!awnd) throw new Error("Could not find parent AWindow"); var wndsrc = awnd.XMLSource(); var path = wndsrc.split("/"); if (!path[0]) path.shift(); path.length = 2; path.push(Math.uuid()); this.defsSrc = "/" + path.join("/"); var htmlid = AXML.EscapeEntities(this.gridID || this.ID()); var node = AXML.SelectNode(awnd.XML().documentElement, "//ai:ele[@htmlid='" + htmlid + "']", AINS); if (!node) throw new Error("Could not find element [@htmlid=\"" + htmlid + "\"] in window \"" + wndsrc + "\""); this.addCustomization({"window": wndsrc, "xml": Figure.SerializeEleAttribute(node, "def", this.defsSrc)}); } params["window"] = String(this.defsSrc); this.loader.AddRequest({ "id": "GraphsToCustomizationTransformations", "static": true, "src": "/xslt/GraphsToCustomization.xsl", "onFinish": function(request){ params["xml"] = JSControl.TransformDOM(this.xmlDOM, request.GetResponseXML()); this.addCustomization(params); this.customized = true; }.bind(this) }); }, saveElementToCustomization: function(element){ if (!element) return; if (!this.customized) return this.saveAllToCustomization(); element.setAttribute("hide", "no"); this.addCustomization({ "window": String(this.defsSrc), "xml": Figure.deepSerializeGraphNode(element) }); }, saveAttributeToCustomization: function(element, attrName){ this.saveAttributesToCustomization(element, [attrName]); }, saveAttributesToCustomization: function(element, attrNames){ if (!element) return; if (!this.customized) return this.saveAllToCustomization(); this.addCustomization({ "window": String(this.defsSrc), "xml": Figure.serializeGraphNodeAttributes(element, attrNames) }); }, removeElementFromCustomization: function(element){ if (!element) return; element.setAttribute("hide", "yes"); this.saveAttributeToCustomization(element, "hide"); }, transformXMLtoSVG: function(refresh_confwin){ try{ this.svgdoc = JSControl.TransformToDocument(this.xmlDOM, this.xslDOM); this.SVGNode = JSControl.ImportNode(document, this.svgdoc.documentElement, true); }catch(err){ alert(err); } this.clearElement(this.container); this.container.appendChild(this.SVGNode); var root = this.svgdoc.documentElement; if (root){ var style = {}; ["width", "height"].each(function(nam){ style[nam] = root.getAttribute(nam) + "px"; }); Element.setStyle(this.container, style); } this.container.setStyle({"cursor": "auto"}); if (refresh_confwin) this.refreshConfWin(); }, refreshGraphColor: function(graph){ if (!this.confwin) return; var jscontrol = this.confwin.JSControl("color"); if (jscontrol) jscontrol.SetValue(this.getGraphColor(graph)); }, setHandleValue: function(localid, xmlrel){ if (!this.confwin || !xmlrel) return; var jscontrol = this.confwin.JSControl(localid); if (!jscontrol) return; var desc = Figure.ConfWin.Handles[localid]; if (!desc.path) return; var node = xmlrel ? AXML.SelectNode(xmlrel, desc.path, {}) : null; if (!node && desc["svg-path"] && this.SVGNode) node = AXML.SelectNode(this.SVGNode, desc["svg-path"], {"svg": SVGElement.xmlns}); var is_attr = /^\/?([^\/]+\/)*@[^@]+$/.test(desc.path); if (jscontrol instanceof Checkbox){ var val = is_attr ? node && node.value === "true" : !!node; jscontrol.SetValue(val ? "true" : "false"); } else if (jscontrol instanceof Spinner){ jscontrol.SetValue(node ? parseInt(this.node_text(node), 10) : NaN); } else{ jscontrol.SetValue(node ? this.node_text(node) : ""); } new AEvent("WM_INIT", {"__grapher__": true}, jscontrol); var xml = this.confwin.APopupWindow().XML(); if (xml){ var xpath = "ai:ele[@id='" + localid + "']/@handle"; var handle = AXML.SelectNode(xml.documentElement, xpath + "|ai:ele/" + xpath, {"ai": AIURI}); if (handle && String(handle.value).split(" ").indexOf("CHANGE") !== -1) this.add_aevent("CHANGE", {"__grapher__": true}, jscontrol); } }, add_aevent: function(){ if (typeof this.aevents_ === "undefined") this.aevents_ = []; this.aevents_.push(arguments); }, fire_aevents: function(){ if (this.aevents_ && this.aevents_.length > 0){ if (this.aevents_.length <= 1 || !this.confwin){ var ctor = function(){}; ctor.prototype = AEvent.prototype; while (this.aevents_.length > 0){ var aevent = new ctor(); AEvent.apply(aevent, this.aevents_.shift()); } }else{ this.confwin.ApplyDependencies(); this.aevents_.length = 0; } } }, clear_aevents: function(){ if (this.aevents_) this.aevents_.length = 0; }, refreshGraphsList: function(newval){ if (!this.confwin) return; var jscontrol = this.confwin.JSControl("graphid"); if (!jscontrol) return; var graphs = this.getXMLGraphNodes(); var val = {"Selected": newval || jscontrol.Value(), "key": new Array(graphs.length), "show": new Array(graphs.length)}; graphs.each(function(graph, iii){ var id = graph.getAttribute("id"); val.key[iii] = id; val.show[iii] = graph.getAttribute("name") || id; }); jscontrol.SetValue(val); jscontrol.SetAttribute("visibility", graphs.length > 0 ? "yes" : "ro"); }, refreshResolutionOptions: function(){ if (!this.confwin) return; var xdata = this.confwin.JSControl("xdata"); if (!xdata) throw new Error("Could not find xdata control"); var colnam = String(this.unwrap_optional(xdata.Value())); var col = this.getColumnByName(colnam); if (!col) throw new Error("Could not find column \"" + colnam + "\""); else this.confwin.RefreshResolutionList(parseInt(col.Type)) }, refreshConfWin: function(){ var handles = Figure.ConfWin.Handles; for (var key in handles) if (handles[key].scope !== "graph") this.setHandleValue(key, this.xmlDOM.documentElement); this.refreshGraphsList(); this.onGraphChange(); this.fire_aevents(); }, onawndload: function(){ var cntrl = ["xdata", "ydata"].collect(this.confwin.JSControl, this.confwin); var val = new Array(cntrl.length); for (var iii = 0; iii < val.length; ++iii) val[iii] = {"Selected": null, "key": [], "show": []}; this.columns.each(function(column){ var coltype = column["Type"]; var key = column["Name"]; var show = column["Title"] || column["Name"]; val[0].key.push(key); val[0].show.push(show); if ([CT_DECIMAL, CT_INTEGER, CT_DOUBLE, CT_INT64].include(coltype)){ val[1].key.push(key); val[1].show.push(show); } }); for (var iii = 0; iii < 2; ++iii) if (cntrl[iii]) cntrl[iii].SetValue(val[iii]); this.refreshConfWin(); var awnd = this.confwin.APopupWindow(); if (!awnd) return; awnd.Subscribe("CHANGE", this.onConfWinCHANGE, this); awnd.Subscribe("CLICK", this.onConfWinCLICK, this); }, showConfWin: function(){ if (!this.confwin){ this.confwin = new Figure.ConfWin({ "sURL": "/act/Grapher/FigureUpdate", "sParent": AControl.GetParentWindowInstanceID(this.gridID || this.ID()), "alignID": Element.identify(this.hs_.GetHandle("configure")), "fAfterLoadCallback": this.onawndload.bind(this) }); } this.confwin.Show(); }, hideConfWin: function(){ if (this.confwin) this.confwin.Hide(); }, onGraphChange: function(){ if (!this.confwin) return; var curgraph = this.getCurrentGraph(); this.refreshGraphColor(curgraph); var handles = Figure.ConfWin.Handles; for (var key in handles){ if (handles[key].scope === "graph"){ this.setHandleValue(key, curgraph); if (key === "xdata") this.refreshResolutionOptions(); else if (key === "graphtype") this.confwin.RefreshSubtypeList(); } } this.fire_aevents(); }, createNode: function(xmlrel, path, doc){ if (!xmlrel) return; if (path.startsWith("/")){ xmlrel = doc.documentElement; var nextslashpos = path.indexOf("/", 1); if (nextslashpos == -1) return xmlrel; else path = path.substr(nextslashpos + 1); } path.split("/").each(function(component){ if (!component) return; if (xmlrel.nodeType != Node.ELEMENT_NODE) return alert(String(xmlrel) + " is not an element node"); if (component.startsWith("@")){ var attrnam = component.substr(1); xmlrel.setAttribute(attrnam, "true"); xmlrel = xmlrel.getAttributeNode(attrnam); }else{ var child = AXML.SelectNode(xmlrel, component, {}); if (!child){ child = doc.createElement(component); xmlrel.appendChild(child); } xmlrel = child; } }); return xmlrel; }, updateXML: function(localid, curgraph){ if (!this.confwin || !(localid in Figure.ConfWin.Handles)) return; var jscontrol = this.confwin.JSControl(localid); if (!jscontrol) return; var desc = Figure.ConfWin.Handles[localid]; if (!desc) return; var xmlrel = desc["scope"] === "graph" ? curgraph : this.xmlDOM.documentElement; if (!xmlrel) return; var path = desc.path; if (path){ var node = AXML.SelectNode(xmlrel, path, {}); var is_attr = /^\/?([^\/]+\/)*@[^@]+$/.test(path); var attrnam = is_attr ? path.substr(path.lastIndexOf("@") + 1) : ""; var val = this.unwrap_optional(jscontrol.Value()); if (jscontrol instanceof Checkbox){ if (val == "true"){ if (!node) node = this.createNode(xmlrel, path, this.xmlDOM); if (is_attr) node.nodeValue = "true"; }else{ if (node){ if (is_attr) node.nodeValue = "false"; else node.parentNode.removeChild(node); } } } else{ if (JSControl instanceof Spinner){ if (isNaN(val)) val = ""; else val = String(val); } if (!node) node = this.createNode(xmlrel, path, this.xmlDOM); if (typeof val === "undefined" || val === null) val = ""; if (is_attr) node.value = val; else this.clearElement(node).appendChild(this.xmlDOM.createTextNode(val)); } if (localid === "graphtype"){ var color = this.getGraphColor(curgraph); this.updateXML("graphsubtype", curgraph); this.setGraphColor(curgraph, color || Figure.defaults["color"]); } }else if ("color" === localid) this.setGraphColor(curgraph, this.unwrap_optional(jscontrol.Value())); }, getResolution: function(){ if (!this.confwin) return "unique"; var cntrl = ["resolution_str", "resolution_num"].collect(this.confwin.JSControl, this.confwin); if (!cntrl[0]) return "unique"; var val = String(this.unwrap_optional(cntrl[0].Value())); if ("number" !== val) return val; else if (!cntrl[1]) return Figure.defaults["resolution"]; else{ var num = this.unwrap_optional(cntrl[1].Value()); return num instanceof Int ? num.Value() : Figure.defaults["resolution"]; } }, onConfWinCHANGE: function(aevent){ if (!this.confwin || aevent.Data().__grapher__) return; var awnd = this.confwin.APopupWindow(); if (!awnd) return; var emitter = aevent.Emitter(); if (!(emitter.ID().startsWith(awnd.ID()))) return; var localid = emitter.ID().substr(awnd.ID().length + 1); if ("graphid" === localid) return void this.onGraphChange(); else if ("graphtype" === localid) this.confwin.RefreshSubtypeList(); var curgraph = this.getCurrentGraph(); if (!curgraph) return; this.updateXML(localid, curgraph); if (localid === "graphtype") this.refreshGraphColor(curgraph); else if (localid === "graphtitle") this.refreshGraphsList(); else if (["xdata", "ydata", "resolution_str", "resolution_num", "aggregation"].indexOf(localid) !== -1){ if ("xdata" === localid) this.refreshResolutionOptions(); if (["xdata", "resolution_num"].indexOf(localid) !== -1) curgraph.setAttribute("resolution", this.getResolution()); if (curgraph) this.reloadOneGraphData(curgraph, AXML.SelectNode(curgraph, "xdata"), AXML.SelectNode(curgraph, "ydata"), false); } this.saveAllToCustomization(); this.transformXMLtoSVG(false); }, onConfWinCLICK: function(aevent){ if (!this.confwin) return; var awnd = this.confwin.APopupWindow(); if (!awnd) return; var emitter = aevent.Emitter(); if (!(emitter.ID().startsWith(awnd.ID()))) return; var localid = emitter.ID().substr(awnd.ID().length + 1); switch (localid){ case "GraphDelete": var curgraph = this.getCurrentGraph(); if (!curgraph) return; this.removeElementFromCustomization(curgraph); curgraph.parentNode.removeChild(curgraph); this.refreshGraphsList(); this.onGraphChange(); break; case "GraphAdd": if (!this.xmlDOM) return; var is_pie = !!$A(this.xmlDOM.getElementsByTagName("graph")).find(function(graph){ return [String(Figure.PIE), String(Figure.PIPELINE)].include(graph.getAttribute("type")); }); var graphnode = new XMLElement(this.xmlDOM, "", "graph", Figure.defaults[is_pie ? "pieattrs" : "lineattrs"]); var newgraph = graphnode.GetElement(); var id = Math.uuid(); newgraph.setAttribute("id", id); graphnode.AttachTo(this.xmlDOM.documentElement); ["xdata", "ydata", "aggregation"].each(function(localid){ this.updateXML(localid, newgraph); }, this); newgraph.setAttribute("resolution", this.getResolution()); this.loadOneGraphData(newgraph, AXML.SelectNode(newgraph, "xdata"), AXML.SelectNode(newgraph, "ydata"), false); this.refreshGraphsList(id); this.onGraphChange(); this.saveElementToCustomization(newgraph); break; default: return; } this.transformXMLtoSVG(false); }, loadOneGraphData: function(xmlGraphNode, xmlXDataNode, xmlYDataNode, refreshConfigurationWindow, replaceFlag, dataNodeNumber){ if (typeof(replaceFlag) == "undefined") replaceFlag = false; if (typeof(dataNodeNumber) == "undefined") dataNodeNumber = 0; var series = this.graph_attrs(xmlGraphNode); var xtype = this.column_type(series["XColumn"] = xmlXDataNode.getAttribute("column")); var ytype = this.column_type(series["YColumn"] = xmlYDataNode.getAttribute("column")); this.loader.AddRequest({"required": ["DataSetFeeder"], "action": function(){ var data = this.get_series_data([new GraphSeries(series)]); if (!data) return; if (1 === data.length){ var toreplace = null; for (var child = this.xmlDOM.documentElement.firstChild; child; child = child.nextSibling){ if (child.nodeType !== Node.ELEMENT_NODE || Node.localName(child) !== "data") continue; if (child.getAttribute("graphID") == xmlGraphNode.getAttribute("id")) --dataNodeNumber; if (dataNodeNumber < 0){ toreplace = child; break; } } this.process_series_data(data[0], this.xmlDOM, xtype, ytype, toreplace); } }.bind(this)}); }, reloadOneGraphData: function(xmlGraphNode, xmlXDataNode, xmlYDataNode, refreshConfigurationWindow, dataNodeNumber){ this.loadOneGraphData(xmlGraphNode, xmlXDataNode, xmlYDataNode, refreshConfigurationWindow, true, dataNodeNumber); }, clearElement: function(element){ while (element.firstChild) element.removeChild(element.firstChild); return element; }, getXMLPropertiesChildByTagName: function(tagName){ var xmlPropertiesNode = this.xmlDOM.getElementsByTagName("properties")[0]; for (var iii = xmlPropertiesNode.childNodes.length - 1; iii >= 0; --iii){ if (xmlPropertiesNode.childNodes[iii].localName == tagName) return xmlPropertiesNode.childNodes[iii]; } return xmlPropertiesNode.appendChild(this.xmlDOM.createElement(tagName)); }, getGraphColor: function(node){ if (!node) return ""; switch (parseInt(node.getAttribute("type"), 10)){ case Figure.LINE: return node.getAttribute("stroke"); case Figure.VBAR: case Figure.HBAR: return node.getAttribute("fill"); default: return ""; } }, setGraphColor: function(node, color){ if (!node) return; node.removeAttribute("fill"); node.removeAttribute("stroke"); switch (parseInt(node.getAttribute("type"), 10)){ case Figure.LINE: node.setAttribute("stroke", color); break; case Figure.VBAR: case Figure.HBAR: node.setAttribute("fill", color); break; } }, getCurrentGraph: function(){ if (!this.confwin) return null; var jscontrol = this.confwin.JSControl("graphid"); return jscontrol ? this.getXMLGraphById(this.unwrap_optional(jscontrol.Value())) : null; }, getXMLNodeByTagNameAndId: function(tagName, id){ var xmlNodes = this.xmlDOM.getElementsByTagName(tagName); for (var iii = xmlNodes.length - 1; iii >= 0; --iii){ if (xmlNodes[iii].getAttribute("id") == id) return xmlNodes[iii]; } return null; }, getXMLGraphNodes: function(){ if (!this.xmlDOM) return []; else return $A(this.xmlDOM.getElementsByTagName("graph")); }, getXMLGraphById: function(id){ return this.getXMLNodeByTagNameAndId("graph", id); }, node_text: function(node){ if ([Node.ATTRIBUTE_NODE, Node.TEXT_NODE, Node.CDATA_SECTION_NODE].indexOf(node.nodeType) !== -1) return node.nodeValue; if (node.nodeType === Node.ELEMENT_NODE){ var str = new Array(); for (var child = node.firstChild; child; child = child.nextSibling) str.push(arguments.callee(child)); return str.join("\n"); } if (node.nodeType == Node.DOCUMENT_NODE) return arguments.callee(node.documentElement); return ""; }, printFigure: function(){ var containerDimensions = Element.getDimensions(this.container); var newnode = this.container.cloneNode(true); Element.setStyle(newnode, { "border": "1px solid gray", "padding": "0px", "margin": "0px" }); var args = {"width": containerDimensions.width + 2, "height": containerDimensions.height + 2}; if (this.xmlDOM){ var node = AXML.SelectNode(this.xmlDOM.documentElement, "/figure/title"); if (node) args["title"] = this.node_text(node); } JSControl.PrintNode(newnode, args); }, refreshFigure: function(){ this.clearElement(this.container); this.loadDynamicData(); }, setTabOrder: function(nTabBase){ ["configure", "print", "refresh"].each(function(hook){ var button = this.hs_.GetHandle(hook); if (button) button.tabIndex = nTabBase++; }, this); return nTabBase; }, OnClose: function(){ if (this.confwin && this.confwin.IsVisible()) this.hideConfWin(); } }); Figure.addElementWithAttributes = function(currentStr, element, attrNames){ if (!element) return currentStr; var locnam = Node.localName(element); return "<" + locnam + " " + // $A(attrNames).collect(function(attrName){ return (attrName + "=\"" + element.getAttribute(attrName) + "\"") }).join(" ") + // ">" + currentStr + ""; }; Figure.SerializeEleAttribute = function(element, attrName, attrValue){ if (!element) return ""; element.setAttribute(attrName, attrValue); var result = ""; var attributes = [attrName]; while (element){ var isWnd = String(element.nodeName).indexOf("wnd") != -1 attributes.push(isWnd ? "xmlns" : "id"); result = this.addElementWithAttributes(result, element, attributes); if (isWnd) break; element = element.parentNode; attributes.length = 0; } return result; }; Figure.getElementPosition = function(element){ var elementNodeName = element.nodeName; var position = 0; while(element){ if (element.nodeName == elementNodeName) ++position; element = element.previousSibling; } return position; } Figure.getElementParams = function(element){ switch(element.nodeName){ case "graph": return {"nodeName": "ele", "eleType": "graph", "id": element.getAttribute("id")}; case "xdata": case "ydata": return {"nodeName": "ele", "eleType": element.nodeName, "id": element.nodeName + Figure.getElementPosition(element)}; case "figure": return {"nodeName": "wnd"}; default: return {"nodeName": "ele", "eleType": "fromID", "id": element.nodeName}; } }; Figure.getElementStartEnd = function(element){ if (!element) return {"start": "", "end": ""}; var params = Figure.getElementParams(element); if (params.nodeName == "ele") return { "start": "" }; else if (params.nodeName == "wnd") return { "start": "" } return {"start": "", "end": ""}; } Figure.serializeAttributes = function(element, attrNames){ if (!element) return ""; return $A(attrNames).collect(function(attrName){ return(attrName + "=\"" + element.getAttribute(attrName) + "\""); }).join(" "); } Figure.serializeGraphNodeAttributes = function(element, attrNames){ if (!element) return ""; var startEnd = Figure.getElementStartEnd(element); var result = startEnd.start + " " + Figure.serializeAttributes(element, attrNames) + "/>"; element = element.parentNode; while (element){ var startEnd = Figure.getElementStartEnd(element); result = startEnd.start + ">" + result + startEnd.end; if (element.nodeName == "figure") break; element = element.parentNode; } return result; }; Figure.serializeNode = function(element, deep){ if (typeof(deep) == "undefined") deep = false; if (!element) return ""; var childrenStr = deep ? $A(element.childNodes).collect(function(node){ return Figure.serializeNode(node, true); }).join(" ") : ""; var startEnd = Figure.getElementStartEnd(element); var attrsStr = $A(element.attributes).collect(function(attr){ if (attr.name.toLowerCase() == "id" || attr.value.length == 0) return ""; return attr.name + "=\"" + attr.value + "\""; }).join(" "); return startEnd.start + " " + attrsStr + ">" + childrenStr + startEnd.end; }; Figure.deepSerializeGraphNode = function(element){ if (!element) return ""; var result = Figure.serializeNode(element, true); for (element = element.parentNode; element && element.nodeType != Node.DOCUMENT_NODE; element = element.parentNode){ var startEnd = Figure.getElementStartEnd(element); result = startEnd.start + ">" + result + startEnd.end; } return result; }; Figure.LINE = 16; Figure.VBAR = 17; Figure.HBAR = 21; Figure.ADDBAR = 218; Figure.PIE = 2; Figure.PIPELINE = 405; Figure.defaults = { "resolution": 10, "color": "#708080", "lineattrs": { "type": Figure.LINE, "subtype": "solid", "marker": "square", "stroke": "#708080" }, "pieattrs": {"type": Figure.PIE} }; Figure.getNodeText = function(element){ if (!element) return ""; return $A(element.childNodes).collect(function(child){ if (child.nodeType != Node.TEXT_NODE) return ""; return child.nodeValue; }).join(""); } Figure.ConfWin = Class.create({ initialize: function(args){ args["canResize"] = false; args["autoSize"] = true; this.args_ = args; }, Show: function(pos){ if (this.visible_) return; if (!this.wnd_){ this.wnd_ = new APopupWindow(Object.clone(this.args_)); this.wnd_.Subscribe("WM_POPUP_RETURN", this.onWM_POPUP_RETURN, this); }else{ var popup = this.wnd_.Popup(); GPopupContainer.Activate(popup); popup.Show(); } this.visible_ = true; }, Hide: function(){ if (!this.visible_) return; if (this.wnd_) this.wnd_.Popup().Hide(); this.visible_ = false; }, onWM_POPUP_RETURN: function(){ delete this.wnd_; this.visible_ = false; }, IsVisible: function(){ return !!this.visible_; }, APopupWindow: function(){ return this.wnd_ || null; }, JSControl: function(localid){ var awnd = this.APopupWindow(); if (!awnd) return null; var elem = awnd.Control(localid); if (!elem) return null; return elem.JSControl || null; }, ApplyDependencies: function(){ var bell = this.JSControl("bell"); if (bell) new AEvent("CHANGE", {}, bell); }, unwrap_optional: function(val){ while (val instanceof Optional) val = val.Value(); return val; }, RefreshResolutionList: function(coltype){ var cntrl = ["resolution_str", "resolution_num"].collect(this.JSControl, this); if (!cntrl.all()) throw new Error("Could not find controls"); var keys = []; var lbls = []; var val = cntrl[0].Value(); if ([CT_DECIMAL, CT_INTEGER, CT_DOUBLE, CT_INT64].indexOf(coltype) !== -1){ keys.push("number"); lbls.push("`number`"); val = "manual"; } keys.push("unique"); lbls.push("`unique`"); if (coltype === CT_DATETIME){ val = "manual"; keys.push("year", "month", "day", "hour"); lbls.push("`year`", "`month`", "`day`", "`hour`"); } cntrl[0].SetValue({"key": keys, "show": lbls, "Selected": val}); val = String(this.unwrap_optional(cntrl[0].Value())); cntrl[1].SetAttribute("visibility", "number" === val ? "yes" : "no"); if ("number" === val && !(this.unwrap_optional(cntrl[1].Value()) instanceof Int)) cntrl[1].SetValue(Figure.defaults["resolution"]); }, RefreshSubtypeList: function(){ var cntrl = ["graphtype", "graphsubtype"].collect(this.JSControl, this); if (!cntrl.all()) return; var graphtype = String(this.unwrap_optional(cntrl[0].Value())); var keys = []; var lbls = []; var val = cntrl[1].Value(); if (String(Figure.LINE) === graphtype){ keys.push("solid", "dashed", "dotted", "dashdotted"); lbls.push("`solid line`", "`dashed line`", "`dotted line`", "`dashdotted line`"); }else if ([String(Figure.HBAR), String(Figure.VBAR), String(Figure.ADDBAR)].indexOf(graphtype) !== -1){ keys.push("2d-bars", "3d-bars", "cylinders"); lbls.push("`2d-bars`", "`3d-bars`", "`cylinders`"); } cntrl[1].SetAttribute("visibility", keys.length > 0 ? "yes" : "ro"); cntrl[1].SetValue({"Selected": val, "key": keys, "show": lbls}); } }); Figure.ConfWin.Handles = { "zaxis": {"path": "/figure/zaxis"}, "legend": {"path": "/figure/properties/legend"}, "cols": {"path": "/figure/properties/legend/@ncols", "svg-path": "//svg:g[@class='legend']/@ncols", "enabled-iff": "(ShowLegendCheckbox)"}, "title": {"path": "/figure/title"}, "graphtitle": {"scope": "graph", "path": "@name"}, "xdata": {"scope": "graph", "path": "xdata/@column"}, "ydata": {"scope": "graph", "path": "ydata/@column"}, "graphtype": {"scope": "graph", "path": "@type"}, "graphsubtype": {"scope": "graph", "path": "@subtype"}, "aggregation": {"scope": "graph", "path": "@aggregation"}, "resolution_str": {"scope": "graph", "path": "@resolution"}, "color": {"scope": "graph"/*, "path": "@color"*/}, "colormap": {"scope": "graph", "path": "@colormap"}, "marker": {"scope": "graph", "path": "@marker"} }; var GraphSeries = Class.create({ Id: "", XColumn: "", YColumn: "", Aggregation: "sum", Min: null, Max: null, Resolution: Figure.defaults["resolution"], initialize: function(options){ Object.extend(this, options); }, Serialize: function(oSerializer) { oSerializer.BeginType("Series"); oSerializer.Serialize(this.Id); oSerializer.Serialize(this.XColumn); oSerializer.Serialize(this.YColumn); oSerializer.Serialize(this.Aggregation); oSerializer.BeginType("Value"); if (this.Min !== null) oSerializer.Serialize(this.Min); oSerializer.EndType("Value"); oSerializer.BeginType("Value"); if (this.Max !== null) oSerializer.Serialize(this.Max); oSerializer.EndType("Value"); oSerializer.BeginType("Value"); oSerializer.Serialize(this.Resolution); oSerializer.EndType("Value"); oSerializer.EndType("Series"); }, Restore: function(){ LogL("GraphSeries.Restore() not defined"); } }); var GraphicsEditorOpener = Class.create({ initialize: function(button_id, figure_id){ this.button_ = $(this.id_ = button_id); this.button_.JSControl = this; if (!SVGElement.IsSupported || !$(figure_id)) return void Element.setStyle(this.button_, {"display": "none"}); this.figure_ = Element.remove(figure_id); Event.observe(this.button_, "click", this.changeFigureVisibility.bind(this)); }, ID: function(){ return this.id_; }, changeFigureVisibility: function(){ this.visible = !this.visible; this.initializePopup(); if (this.visible){ if (this.figure_.JSControl) this.figure_.JSControl.Load(); GPopupContainer.Activate(this.popup); Element.setStyle(this.figure_, {"display": ""}); if (this.loaded_) this.popup.Show(); else Event.observe(this.figure_, "figure:loaded", function(){ this.loaded_ = true; if (this.visible) this.popup.Show(); Event.stopObserving(this.figure_, "figure:loaded"); }.bind(this)); }else{ this.figure_.JSControl.OnClose(); this.popup.Hide(); Element.setStyle(this.figure_, {"display": "none"}); } }, OnClick: function() { this.changeFigureVisibility(); }, initializePopup: function(){ if (this.popup) return; this.popup = new APopup({ "showState": 'hidden', "showHeader": true, "canResize": true, "fAfterResizeCallback": function(popup){ var cont = popup.Contents(); var cont_w = parseInt(Element.getStyle(cont, "width"), 10) || cont.offsetWidth; var cont_h = parseInt(Element.getStyle(cont, "height"), 10) || cont.offsetHeight; this.figure_.JSControl.OnContainerResize(cont_w, cont_h); Element.setStyle(cont, {"width": "", "height": ""}); }.bind(this), "fCloseCallback": this.changeFigureVisibility.bind(this) }); var nam = this.figure_.JSControl.Title(); if (nam){ this.popup.SetTitle(nam); this.popup.UpdateTitle(); } Element.setStyle(this.figure_, {"borderWidth": "0px", "margin": "0px"}); var popupContents = this.popup.Contents(); Element.clear(popupContents); popupContents.appendChild(this.figure_); Element.setStyle(popupContents, {"overflow": "hidden"}); var buttonAncestor = Element.up(this.button_, "table"); if (buttonAncestor){ var buttonAncestorPosition = Element.cumulativeOffset(buttonAncestor); this.popup.SetPosition(buttonAncestorPosition.left, buttonAncestorPosition.top); } } }); var SeriesData = Class.create({ initialize: function(){}, Restore: function(restorer){ restorer.BeginType("SeriesData"); this.id_ = restorer.RestoreString(); this.min_ = restorer.Restore(); this.max_ = restorer.Restore(); this.resolution_ = restorer.Restore(); this.y_ = restorer.Restore(); this.x_ = restorer.Restore(); restorer.EndType("SeriesData"); }, Serialize: function(serializer){}, ID: function(){ return this.id_; }, Resolution: function(){ return this.resolution_; }, X: function(){ return this.x_; }, Y: function(){ return this.y_; } });