| /** |
| * |
| * Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany) |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation |
| * |
| * |
| * This copyright notice shows up in the generated Java code |
| * |
| */ |
| |
| package org.eclipse.osbp.xtext.chart.jvmmodel |
| |
| import com.vaadin.data.Property.ValueChangeListener |
| import com.vaadin.server.Page |
| import com.vaadin.server.Page.Styles |
| import com.vaadin.ui.HorizontalLayout |
| import com.vaadin.ui.JavaScriptFunction |
| import com.vaadin.ui.Label |
| import com.vaadin.ui.Panel |
| import com.vaadin.ui.TabSheet |
| import com.vaadin.ui.UI |
| import elemental.json.JsonArray |
| import elemental.json.JsonException |
| import elemental.json.JsonObject |
| import java.util.ArrayList |
| import java.util.Collection |
| import java.util.Date |
| import java.util.HashMap |
| import java.util.List |
| import java.util.Locale |
| import java.util.Map |
| import java.util.ResourceBundle |
| import java.util.concurrent.Executors |
| import javax.inject.Inject |
| import mondrian.olap.Member.MemberType |
| import org.dussan.vaadin.dcharts.DCharts |
| import org.dussan.vaadin.dcharts.DownloadButtonLocation |
| import org.dussan.vaadin.dcharts.base.elements.Trendline |
| import org.dussan.vaadin.dcharts.base.elements.XYaxis |
| import org.dussan.vaadin.dcharts.base.elements.XYseries |
| import org.dussan.vaadin.dcharts.data.DataSeries |
| import org.dussan.vaadin.dcharts.data.Ticks |
| import org.dussan.vaadin.dcharts.metadata.LegendPlacements |
| import org.dussan.vaadin.dcharts.metadata.PyramidSides |
| import org.dussan.vaadin.dcharts.metadata.SeriesToggles |
| import org.dussan.vaadin.dcharts.metadata.TooltipAxes |
| import org.dussan.vaadin.dcharts.metadata.XYaxes |
| import org.dussan.vaadin.dcharts.metadata.Xaxes |
| import org.dussan.vaadin.dcharts.metadata.Yaxes |
| import org.dussan.vaadin.dcharts.metadata.directions.BarDirections |
| import org.dussan.vaadin.dcharts.metadata.locations.TooltipLocations |
| import org.dussan.vaadin.dcharts.metadata.renderers.AxisRenderers |
| import org.dussan.vaadin.dcharts.metadata.renderers.SeriesRenderers |
| import org.dussan.vaadin.dcharts.options.Axes |
| import org.dussan.vaadin.dcharts.options.AxesDefaults |
| import org.dussan.vaadin.dcharts.options.Cursor |
| import org.dussan.vaadin.dcharts.options.Highlighter |
| import org.dussan.vaadin.dcharts.options.Legend |
| import org.dussan.vaadin.dcharts.options.Options |
| import org.dussan.vaadin.dcharts.options.Series |
| import org.dussan.vaadin.dcharts.options.SeriesDefaults |
| import org.dussan.vaadin.dcharts.options.Title |
| import org.dussan.vaadin.dcharts.renderers.axis.LinearAxisRenderer |
| import org.dussan.vaadin.dcharts.renderers.legend.EnhancedLegendRenderer |
| import org.dussan.vaadin.dcharts.renderers.series.BarRenderer |
| import org.dussan.vaadin.dcharts.renderers.series.BubbleRenderer |
| import org.dussan.vaadin.dcharts.renderers.series.DonutRenderer |
| import org.dussan.vaadin.dcharts.renderers.series.MeterGaugeRenderer |
| import org.dussan.vaadin.dcharts.renderers.series.PieRenderer |
| import org.dussan.vaadin.dcharts.renderers.series.PyramidRenderer |
| import org.dussan.vaadin.dcharts.renderers.tick.AxisTickRenderer |
| import org.dussan.vaadin.dcharts.renderers.tick.CanvasAxisTickRenderer |
| import org.eclipse.e4.core.di.extensions.EventUtils |
| import org.eclipse.e4.core.services.events.IEventBroker |
| import org.eclipse.e4.ui.model.application.ui.MUIElement |
| import org.eclipse.e4.ui.model.application.ui.basic.MPartStack |
| import org.eclipse.e4.ui.model.application.ui.impl.UIElementImpl |
| import org.eclipse.e4.ui.model.application.ui.impl.UiPackageImpl |
| import org.eclipse.emf.common.notify.Adapter |
| import org.eclipse.emf.common.notify.Notification |
| import org.eclipse.emf.common.notify.impl.AdapterImpl |
| import org.eclipse.emf.ecore.EObject |
| import org.eclipse.emf.ecore.resource.Resource |
| import org.eclipse.osbp.eventbroker.EventBrokerMsg |
| import org.eclipse.osbp.runtime.common.event.EventDispatcherEvent |
| import org.eclipse.osbp.ui.api.datamart.DatamartFilter |
| import org.eclipse.osbp.ui.api.datamart.IDatamartFilterGenerator |
| import org.eclipse.osbp.utils.vaadin.ViewLayoutManager |
| import org.eclipse.osbp.xtext.basic.generator.BasicDslGeneratorUtils |
| import org.eclipse.osbp.xtext.chart.Chart |
| import org.eclipse.osbp.xtext.chart.ChartModel |
| import org.eclipse.osbp.xtext.chart.ChartTree |
| import org.eclipse.osbp.xtext.datamart.common.DatamartFilterGenerator |
| import org.eclipse.osbp.xtext.datamart.common.olap.CellSetToD3JsonConverter |
| import org.eclipse.osbp.xtext.datamart.common.olap.DerivedAxis |
| import org.eclipse.osbp.xtext.datamart.common.olap.DerivedCell |
| import org.eclipse.osbp.xtext.datamart.common.olap.DerivedHierarchy |
| import org.eclipse.osbp.xtext.datamart.common.olap.DerivedLevel |
| import org.eclipse.osbp.xtext.datamart.common.olap.DerivedMember |
| import org.eclipse.osbp.xtext.datamart.common.olap.DerivedPosition |
| import org.eclipse.osbp.xtext.i18n.I18NModelGenerator |
| import org.eclipse.xtext.generator.IFileSystemAccess |
| import org.eclipse.xtext.naming.IQualifiedNameProvider |
| import org.eclipse.xtext.xbase.compiler.GeneratorConfig |
| import org.eclipse.xtext.xbase.compiler.ImportManager |
| import org.osgi.service.event.Event |
| import org.osgi.service.event.EventHandler |
| |
| class ChartModelGenerator extends I18NModelGenerator { |
| @Inject extension IQualifiedNameProvider |
| @Inject extension D3JsJavaUtil |
| @Inject extension BasicDslGeneratorUtils |
| |
| override createAppendable(EObject context, ImportManager importManager, GeneratorConfig config) { |
| // required to initialize the needed builder to avoid deprecated methods |
| builder = context.eResource |
| // --------- |
| importManager.addImportFor(_typeReferenceBuilder.typeRef(HashMap, _typeReferenceBuilder.typeRef(String), _typeReferenceBuilder.typeRef(String)).type) |
| importManager.addImportFor(_typeReferenceBuilder.typeRef(Map, _typeReferenceBuilder.typeRef(String), _typeReferenceBuilder.typeRef(String)).type) |
| importManager.addImportFor(_typeReferenceBuilder.typeRef(Collection, _typeReferenceBuilder.typeRef(String)).type) |
| addImportFor(importManager, _typeReferenceBuilder |
| , ValueChangeListener |
| , DCharts |
| , Label |
| , List |
| , ArrayList |
| , Page |
| , Styles |
| , DerivedAxis |
| , DerivedCell |
| , DerivedPosition |
| , DerivedMember |
| , HorizontalLayout |
| , TabSheet |
| , Series |
| , XYseries |
| , Ticks |
| , DataSeries |
| , SeriesDefaults |
| , SeriesRenderers |
| , CanvasAxisTickRenderer |
| , DonutRenderer |
| , PieRenderer |
| , BubbleRenderer |
| , BarRenderer |
| , BarDirections |
| , MeterGaugeRenderer |
| , PyramidRenderer |
| , PyramidSides |
| , Trendline |
| , Cursor |
| , Legend |
| , LegendPlacements |
| , EnhancedLegendRenderer |
| , SeriesToggles |
| , Highlighter |
| , Title |
| , TooltipLocations |
| , TooltipAxes |
| , Axes |
| , XYaxes |
| , XYaxis |
| , Xaxes |
| , Yaxes |
| , AxisTickRenderer |
| , AxisRenderers |
| , LinearAxisRenderer |
| , AxesDefaults |
| , DownloadButtonLocation |
| , Options |
| , DerivedHierarchy |
| , DerivedLevel |
| , IEventBroker |
| , CellSetToD3JsonConverter |
| , Date |
| , JavaScriptFunction |
| , JsonArray |
| , JsonObject |
| , JsonException |
| , EventHandler |
| , Event |
| , EventUtils |
| , EventBrokerMsg |
| , Executors |
| , Page.BrowserWindowResizeEvent |
| , Page.BrowserWindowResizeListener |
| , Notification |
| , Adapter |
| , AdapterImpl |
| , EObject |
| , UIElementImpl |
| , UiPackageImpl |
| , MUIElement |
| , MPartStack |
| , UI |
| , ResourceBundle |
| , Locale |
| , DatamartFilterGenerator |
| , ViewLayoutManager |
| , IDatamartFilterGenerator.FilterChangeListener |
| , EventDispatcherEvent |
| , EventDispatcherEvent.EventDispatcherDataTag |
| , EventDispatcherEvent.EventDispatcherCommand |
| , DatamartFilter |
| , MemberType |
| , Panel |
| |
| ) |
| super.createAppendable(context, importManager, config) |
| } |
| |
| override void doGenerate(Resource input, IFileSystemAccess fsa) { |
| super.addTranslatables("download") |
| super.doGenerate(input, fsa ) |
| for (obj : input.contents) { |
| obj.internalDoGenerate(fsa) |
| } |
| } |
| |
| def dispatch void internalDoGenerate(ChartModel chartModel, IFileSystemAccess fsa) { |
| for (pkg : chartModel.packages) { |
| for (chart : pkg.charts) { |
| if ((chart.charttype instanceof ChartTree)) { |
| var pckgName = pkg.fullyQualifiedName.toString |
| // println(pckgName) |
| var strBuilder = new StringBuilder |
| var pckgNamePath = pckgName.replaceAll("\\.","/") |
| // var propOutputFile = '''«pckgNamePath»/«chart.createChartJsFilename(chartTree)»''' |
| var propOutputFile = '''«pckgNamePath»/«chart.createChartJsFilename»''' |
| // println("********************* Property-Output *********************") |
| chart.generateJsFile(strBuilder) |
| if (strBuilder.length > 0){ |
| fsa.generateFile(propOutputFile, strBuilder) |
| // println(strBuilder.toString) |
| } |
| } |
| } |
| } |
| } |
| |
| def void generateJsFile(Chart chart,StringBuilder strBuilder){ |
| var chartFilePath = chart.createfullyQualifiedChartFilename.replaceAll("\\.","_") |
| if (chart.charttype instanceof ChartTree){ |
| var chartTree = chart.charttype as ChartTree |
| if (chartTree.map){ |
| strBuilder.generateTreeMapJsFile(chartFilePath) |
| } else if (chartTree.collapsible) { |
| strBuilder.generateCollTreeJsFile(chartFilePath) |
| } |
| } |
| } |
| |
| def void generateTreeMapJsFile(StringBuilder strBuilder, String chartJavaFileName){ |
| strBuilder.append('''«chartJavaFileName» = function() { |
| |
| var margin = { |
| top: 40, |
| right: 10, |
| bottom: 10, |
| left: 10 |
| }, |
| width = 960 - margin.left - margin.right, |
| height = 500 - margin.top - margin.bottom; |
| |
| var color = d3.scale.category20c(); |
| |
| function position() { |
| this.style("left", function (d) { |
| return d.x + "px"; |
| }) |
| .style("top", function (d) { |
| return d.y + "px"; |
| }) |
| .style("width", function (d) { |
| return Math.max(0, d.dx - 1) + "px"; |
| }) |
| .style("height", function (d) { |
| return Math.max(0, d.dy - 1) + "px"; |
| }); |
| } |
| |
| var cxD3TreeMapJsHTMLRootComponent = this.getElement(); |
| var cxD3TreeMapJsComponentHtmlTagId = this.getState().htmlTagId; |
| var checked = ""; |
| var connector = this; |
| var dataColumn = ""; |
| |
| var preValueLabel = ""; |
| |
| for (var i=0;i < this.getState().dataColumnList.length;i++) { |
| if (i == 0){ |
| checked = " checked"; |
| preValueLabel = this.getState().dataColumnList[0]; |
| } else { |
| checked = ""; |
| } |
| dataColumn = dataColumn + "\t<label><input id=\""+this.getState().htmlTagId+"_input\" type=\"radio\" name=\"mode\" value=\""+ this.getState().dataColumnList[i] + "\"" + checked + "> "+ this.getState().dataColumnList[i] + "</label>\n"; |
| } |
| var treemap = d3.layout.treemap() |
| .size([width, height]) |
| .sticky(true) |
| .value(function (d) { |
| return eval("d." + preValueLabel); |
| }); |
| // alert("dataColumn: " + dataColumn); |
| cxD3TreeMapJsHTMLRootComponent.innerHTML = "<form>\n" + |
| dataColumn + |
| "</form>\n" + |
| "<div id=\""+this.getState().htmlTagId+"_div\">" + "</div>"; |
| var cxD3TreeMapJsHTMLRootComponentSelection = d3.select(cxD3TreeMapJsHTMLRootComponent).select("#"+this.getState().htmlTagId+"_div"); |
| // alert("selection: " + selection); |
| var cxD3TreeMapJsHTMLRootComponentDiv = cxD3TreeMapJsHTMLRootComponentSelection.append("div") |
| .style("position", "relative") |
| .style("width", (width + margin.left + margin.right) + "px") |
| .style("height", (height + margin.top + margin.bottom) + "px") |
| .style("left", margin.left + "px") |
| .style("top", margin.top + "px"); |
| |
| jsonTreeMapFunction = function(jsonObj) { |
| var node = cxD3TreeMapJsHTMLRootComponentDiv.datum(jsonObj).selectAll(".node") |
| .data(treemap.nodes) |
| .enter().append("div") |
| .attr("class", "node") |
| .attr("title", function(d) { return d.children ? "" : d.tooltipName + "\n" + preValueLabel + ": " + eval("d." + preValueLabel); }) |
| .call(position) |
| .style("background", function(d) { return d.children ? color(d.name) : null; }) |
| // .style("background", function(d) { return d.children ? d3.rgb("red") : null; }) |
| .text(function(d) { return d.children ? null : d.name; }); |
| |
| d3.select(cxD3TreeMapJsHTMLRootComponent).selectAll("#"+cxD3TreeMapJsComponentHtmlTagId+"_input").on("change", function change() { |
| var valueLabel = this.value; |
| // alert("valueOut: " + valueOut); |
| var value = this.value === "count" |
| ? function() { return 1; } |
| : function (d) { return eval("d." + valueLabel); }; |
| // : function (d) { return d.size; }; |
| |
| node.data(treemap.value(value).nodes) |
| .attr("title", function(d) { return d.children ? "" : d.tooltipName + "\n" + valueLabel + ": " + eval("d." + valueLabel); }) |
| .transition() |
| .duration(1500) |
| .call(position); |
| }); |
| } |
| |
| var jsonString = this.getState().jsonData; |
| jsonTreeMapFunction(JSON.parse(jsonString)); |
| } |
| ''') |
| } |
| |
| def void generateCollTreeJsFile(StringBuilder strBuilder, String chartJavaFileName){ |
| strBuilder.append('''«chartJavaFileName» = function() { |
| |
| var margin = {top: 20, right: 120, bottom: 20, left: 120}, |
| width = 1460 - margin.right - margin.left, |
| height = 1000 - margin.top - margin.bottom; |
| |
| var i = 0, |
| duration = 750, |
| cxD3TreeJsComponent_jsonRoot; |
| |
| var tree = d3.layout.tree() |
| .size([height, width]); |
| |
| var diagonal = d3.svg.diagonal() |
| .projection(function(d) { return [d.y, d.x]; }); |
| |
| var cxD3TreeJsHTMLRootComponent = this.getElement(); |
| cxD3TreeJsHTMLRootComponent.innerHTML = |
| "<label><input id=\""+this.getState().htmlTagId+"_input\" type=\"radio\" name=\"mode\" value=\"expand\">Expand</label>\n" + |
| "<label><input id=\""+this.getState().htmlTagId+"_input\" type=\"radio\" name=\"mode\" value=\"collapse\" checked>Collapse</label>\n" + |
| "<div id=\""+this.getState().htmlTagId+"_div\">" + "</div>"; |
| |
| var cxD3TreeJsHTMLRootComponentSelection = d3.select(cxD3TreeJsHTMLRootComponent).select("#"+this.getState().htmlTagId+"_div"); |
| |
| var cxD3TreeJsHTMLRootComponentSvg = cxD3TreeJsHTMLRootComponentSelection.append("svg") |
| .attr("width", width + margin.right + margin.left) |
| .attr("height", height + margin.top + margin.bottom) |
| .append("g") |
| .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); |
| |
| function collapse(d) { |
| if (d.children) { |
| d._children = d.children; |
| d._children.forEach(collapse); |
| d.children = null; |
| } |
| } |
| |
| function expand(d) { |
| if (d._children) { |
| d.children = d._children; |
| d.children.forEach(expand); |
| d._children = null; |
| } |
| } |
| |
| jsonTreeFunction = function(jsonData) { |
| cxD3TreeJsComponent_jsonRoot = jsonData; |
| cxD3TreeJsComponent_jsonRoot.x0 = height / 2; |
| cxD3TreeJsComponent_jsonRoot.y0 = 0; |
| |
| |
| cxD3TreeJsComponent_jsonRoot.children.forEach(collapse); |
| update(cxD3TreeJsComponent_jsonRoot); |
| } |
| |
| jsonTreeFunction(JSON.parse(this.getState().jsonData)); |
| |
| d3.select(cxD3TreeJsHTMLRootComponent).select(self.frameElement).style("height", "800px"); |
| |
| d3.select(cxD3TreeJsHTMLRootComponent).selectAll("#"+this.getState().htmlTagId+"_input").on("change", function change() { |
| // alert("this.value = " + this.value); |
| if (this.value === "expand"){ |
| cxD3TreeJsComponent_jsonRoot.children.forEach(expand); |
| } else { |
| cxD3TreeJsComponent_jsonRoot.children.forEach(collapse); |
| } |
| update(cxD3TreeJsComponent_jsonRoot); |
| }); |
| |
| function update(source) { |
| |
| // Compute the new tree layout. |
| var nodes = tree.nodes(cxD3TreeJsComponent_jsonRoot).reverse(), |
| links = tree.links(nodes); |
| |
| // Normalize for fixed-depth. |
| nodes.forEach(function(d) { d.y = d.depth * 180; }); |
| |
| // Update the nodes€¦ |
| var node = cxD3TreeJsHTMLRootComponentSvg.selectAll("g.node") |
| .data(nodes, function(d) { return d.id || (d.id = ++i); }); |
| |
| // Enter any new nodes at the parent's previous position. |
| var nodeEnter = node.enter().append("g") |
| .attr("class", "node") |
| .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) |
| .on("click", click); |
| |
| nodeEnter.append("circle") |
| .attr("r", 1e-6) |
| .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); |
| |
| nodeEnter.append("text") |
| .attr("x", function(d) { return d.children || d._children ? -10 : 10; }) |
| .attr("dy", ".35em") |
| .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; }) |
| .text(function(d) { return d.name; }) |
| .style("fill-opacity", 1e-6); |
| |
| // Transition nodes to their new position. |
| var nodeUpdate = node.transition() |
| .duration(duration) |
| .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; }); |
| |
| nodeUpdate.select("circle") |
| .attr("r", 4.5) |
| .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); |
| |
| nodeUpdate.select("text") |
| .style("fill-opacity", 1); |
| |
| // Transition exiting nodes to the parent's new position. |
| var nodeExit = node.exit().transition() |
| .duration(duration) |
| .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; }) |
| .remove(); |
| |
| nodeExit.select("circle") |
| .attr("r", 1e-6); |
| |
| nodeExit.select("text") |
| .style("fill-opacity", 1e-6); |
| |
| // Update the links€¦ |
| var link = cxD3TreeJsHTMLRootComponentSvg.selectAll("path.link") |
| .data(links, function(d) { return d.target.id; }); |
| |
| // Enter any new links at the parent's previous position. |
| link.enter().insert("path", "g") |
| .attr("class", "link") |
| .attr("d", function(d) { |
| var o = {x: source.x0, y: source.y0}; |
| return diagonal({source: o, target: o}); |
| }); |
| |
| // Transition links to their new position. |
| link.transition() |
| .duration(duration) |
| .attr("d", diagonal); |
| |
| // Transition exiting nodes to the parent's new position. |
| link.exit().transition() |
| .duration(duration) |
| .attr("d", function(d) { |
| var o = {x: source.x, y: source.y}; |
| return diagonal({source: o, target: o}); |
| }) |
| .remove(); |
| |
| // Stash the old positions for transition. |
| nodes.forEach(function(d) { |
| d.x0 = d.x; |
| d.y0 = d.y; |
| }); |
| } |
| |
| // Toggle children on click. |
| function click(d) { |
| if (d.children) { |
| d._children = d.children; |
| d.children = null; |
| } else { |
| d.children = d._children; |
| d._children = null; |
| } |
| update(d); |
| } |
| |
| } |
| ''') |
| } |
| |
| } |