forked from p81075629/datagear
看板添加loadChart异步加载图表支持
This commit is contained in:
parent
1508c4c1c6
commit
92bd7ae0b0
|
@ -11,6 +11,7 @@ import org.datagear.analysis.ChartPlugin;
|
|||
import org.datagear.analysis.ChartPluginManager;
|
||||
import org.datagear.analysis.RenderContext;
|
||||
import org.datagear.analysis.RenderException;
|
||||
import org.datagear.util.IDUtil;
|
||||
|
||||
/**
|
||||
* 图表部件。
|
||||
|
@ -81,10 +82,6 @@ public class ChartWidget<T extends RenderContext> extends ChartDefinition
|
|||
|
||||
/**
|
||||
* 生成图表ID。
|
||||
* <p>
|
||||
* 同一个渲染上下文内,允许多次使用同一个{@linkplain ChartWidget},
|
||||
* 为了保证{@linkplain Chart#getId()}不重复,所以这里要生成新的ID。
|
||||
* </p>
|
||||
*
|
||||
* @param renderContext
|
||||
* @return
|
||||
|
@ -92,13 +89,6 @@ public class ChartWidget<T extends RenderContext> extends ChartDefinition
|
|||
*/
|
||||
protected String generateChartId(T renderContext) throws RenderException
|
||||
{
|
||||
String key = "chartIndex-" + getId();
|
||||
Integer index = renderContext.getAttribute(key);
|
||||
if (index == null)
|
||||
index = 0;
|
||||
|
||||
renderContext.setAttribute(key, index + 1);
|
||||
|
||||
return getId() + "-" + index.toString();
|
||||
return IDUtil.uuid();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -224,8 +224,12 @@ public class HtmlChartPlugin<T extends HtmlRenderContext> extends AbstractChartP
|
|||
{
|
||||
Writer out = renderContext.getWriter();
|
||||
|
||||
getHtmlChartScriptObjectWriter().write(out, chart, optionInitialized.getRenderContextVarName(),
|
||||
optionInitialized.getPluginVarName());
|
||||
if (optionInitialized.isWriteChartJson())
|
||||
getHtmlChartScriptObjectWriter().writeJson(out, chart, optionInitialized.getRenderContextVarName(),
|
||||
optionInitialized.getPluginVarName());
|
||||
else
|
||||
getHtmlChartScriptObjectWriter().write(out, chart, optionInitialized.getRenderContextVarName(),
|
||||
optionInitialized.getPluginVarName());
|
||||
|
||||
if (!optionInitialized.isNotWriteInvoke())
|
||||
{
|
||||
|
@ -306,6 +310,7 @@ public class HtmlChartPlugin<T extends HtmlRenderContext> extends AbstractChartP
|
|||
option.setNotWriteRenderContextObject(false);
|
||||
option.setNotWriteScriptTag(false);
|
||||
option.setNotWriteInvoke(false);
|
||||
option.setWriteChartJson(false);
|
||||
}
|
||||
|
||||
String chartElementId = option.getChartElementId();
|
||||
|
|
|
@ -48,6 +48,9 @@ public class HtmlChartPluginRenderOption implements Serializable
|
|||
/** 是否不输出调用渲染函数 */
|
||||
private boolean notWriteInvoke = false;
|
||||
|
||||
/** 写入图表JSON对象而非JS对象 */
|
||||
private boolean writeChartJson = false;
|
||||
|
||||
public HtmlChartPluginRenderOption()
|
||||
{
|
||||
super();
|
||||
|
@ -217,6 +220,21 @@ public class HtmlChartPluginRenderOption implements Serializable
|
|||
this.notWriteInvoke = notWriteInvoke;
|
||||
}
|
||||
|
||||
public boolean isWriteChartJson()
|
||||
{
|
||||
return writeChartJson;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置写入图表JSON对象而非JS对象。
|
||||
*
|
||||
* @param writeChartJson
|
||||
*/
|
||||
public void setWriteChartJson(boolean writeChartJson)
|
||||
{
|
||||
this.writeChartJson = writeChartJson;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
@ -224,7 +242,8 @@ public class HtmlChartPluginRenderOption implements Serializable
|
|||
+ notWriteChartElement + ", pluginVarName=" + pluginVarName + ", notWritePluginObject="
|
||||
+ notWritePluginObject + ", chartVarName=" + chartVarName + ", renderContextVarName="
|
||||
+ renderContextVarName + ", notWriteRenderContextObject=" + notWriteRenderContextObject
|
||||
+ ", notWriteScriptTag=" + notWriteScriptTag + ", notWriteInvoke=" + notWriteInvoke + "]";
|
||||
+ ", notWriteScriptTag=" + notWriteScriptTag + ", notWriteInvoke=" + notWriteInvoke
|
||||
+ ", writeChartJson=" + writeChartJson + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -67,6 +67,36 @@ public class HtmlChartScriptObjectWriter extends AbstractHtmlScriptObjectWriter
|
|||
writeNewLine(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将{@linkplain HtmlChart}的JSON对象写入输出流。
|
||||
* <p>
|
||||
* 格式为:
|
||||
* </p>
|
||||
* <code>
|
||||
* <pre>
|
||||
* {
|
||||
* ...,
|
||||
* renderContext : [renderContextVarName],
|
||||
* plugin : [pluginVarName],
|
||||
* ...
|
||||
* }
|
||||
* <pre>
|
||||
* </code>
|
||||
*
|
||||
* @param out
|
||||
* @param chart
|
||||
* @param renderContextVarName
|
||||
* @param pluginVarName
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeJson(Writer out, HtmlChart chart, String renderContextVarName, String pluginVarName)
|
||||
throws IOException
|
||||
{
|
||||
chart = new JsonHtmlChart(chart, renderContextVarName, pluginVarName);
|
||||
|
||||
writeJsonObject(out, chart);
|
||||
}
|
||||
|
||||
/**
|
||||
* 支持JSON输出的{@linkplain HtmlChart}。
|
||||
*
|
||||
|
|
|
@ -8,6 +8,7 @@ import java.io.File;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
|
@ -21,11 +22,15 @@ import javax.servlet.ServletContext;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.datagear.analysis.Chart;
|
||||
import org.datagear.analysis.ChartTheme;
|
||||
import org.datagear.analysis.DashboardTheme;
|
||||
import org.datagear.analysis.DataSetResult;
|
||||
import org.datagear.analysis.RenderStyle;
|
||||
import org.datagear.analysis.TemplateDashboardWidgetResManager;
|
||||
import org.datagear.analysis.support.ChartWidget;
|
||||
import org.datagear.analysis.support.ChartWidgetSource;
|
||||
import org.datagear.analysis.support.html.HtmlChartPluginRenderOption;
|
||||
import org.datagear.analysis.support.html.HtmlRenderAttributes;
|
||||
import org.datagear.analysis.support.html.HtmlRenderContext;
|
||||
import org.datagear.analysis.support.html.HtmlRenderContext.WebContext;
|
||||
|
@ -742,54 +747,51 @@ public class DashboardController extends AbstractDataAnalysisController implemen
|
|||
response.setHeader("Cache-Control", "no-cache");
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
response.setContentType(CONTENT_TYPE_CSS);
|
||||
Writer out = response.getWriter();
|
||||
PrintWriter out = response.getWriter();
|
||||
|
||||
StringBuilder style = new StringBuilder();
|
||||
DashboardTheme dashboardTheme = getDashboardThemeAttribute(request.getSession());
|
||||
ChartTheme chartTheme = (dashboardTheme == null ? null : dashboardTheme.getChartTheme());
|
||||
|
||||
if (chartTheme != null)
|
||||
{
|
||||
// 表格行
|
||||
style.append(".dg-chart-table .dg-chart-table-content table.dataTable tbody tr{\n");
|
||||
style.append("background:" + chartTheme.getBackgroundColor() + ";\n");
|
||||
style.append("}\n");
|
||||
out.println(".dg-chart-table .dg-chart-table-content table.dataTable tbody tr{");
|
||||
out.println(" background:" + chartTheme.getBackgroundColor() + ";");
|
||||
out.println("}");
|
||||
|
||||
// 表格奇数行
|
||||
style.append(".dg-chart-table .dg-chart-table-content table.dataTable.stripe tbody tr.odd,\n"
|
||||
+ " .dg-chart-table .dg-chart-table-content table.dataTable.display tbody tr.odd{\n");
|
||||
style.append("background:" + chartTheme.getBorderColor() + ";\n");
|
||||
style.append("}\n");
|
||||
out.println(".dg-chart-table .dg-chart-table-content table.dataTable.stripe tbody tr.odd,"
|
||||
+ " .dg-chart-table .dg-chart-table-content table.dataTable.display tbody tr.odd{");
|
||||
out.println(" background:" + chartTheme.getBorderColor() + ";");
|
||||
out.println("}");
|
||||
|
||||
// 表格选中、悬浮,拷贝自/src/main/resources/org/datagear/web/webapp/static/theme/lightness/common.css
|
||||
style.append(".dg-chart-table .dg-chart-table-content table.dataTable.hover tbody tr.hover,\n");
|
||||
style.append(".dg-chart-table .dg-chart-table-content table.dataTable.hover tbody tr:hover,\n");
|
||||
style.append(".dg-chart-table .dg-chart-table-content table.dataTable.display tbody tr:hover {\n");
|
||||
style.append(" background-color: " + chartTheme.getAxisScaleLineColor() + ";\n");
|
||||
style.append("}\n");
|
||||
out.println(".dg-chart-table .dg-chart-table-content table.dataTable.hover tbody tr.hover,");
|
||||
out.println(".dg-chart-table .dg-chart-table-content table.dataTable.hover tbody tr:hover,");
|
||||
out.println(".dg-chart-table .dg-chart-table-content table.dataTable.display tbody tr:hover {");
|
||||
out.println(" background-color: " + chartTheme.getAxisScaleLineColor() + ";");
|
||||
out.println("}");
|
||||
|
||||
style.append(".dg-chart-table .dg-chart-table-content table.dataTable.hover tbody tr.hover.selected,\n");
|
||||
style.append(".dg-chart-table .dg-chart-table-content table.dataTable tbody > tr.selected,\n");
|
||||
style.append(".dg-chart-table .dg-chart-table-content table.dataTable tbody > tr > .selected,\n");
|
||||
style.append(".dg-chart-table .dg-chart-table-content table.dataTable.stripe tbody > tr.odd.selected,\n");
|
||||
style.append(
|
||||
".dg-chart-table .dg-chart-table-content table.dataTable.stripe tbody > tr.odd > .selected,\n");
|
||||
style.append(".dg-chart-table .dg-chart-table-content table.dataTable.display tbody > tr.odd.selected,\n");
|
||||
style.append(
|
||||
".dg-chart-table .dg-chart-table-content table.dataTable.display tbody > tr.odd > .selected,\n");
|
||||
style.append(".dg-chart-table .dg-chart-table-content table.dataTable.hover tbody > tr.selected:hover,\n");
|
||||
style.append(
|
||||
".dg-chart-table .dg-chart-table-content table.dataTable.hover tbody > tr > .selected:hover,\n");
|
||||
style.append(
|
||||
".dg-chart-table .dg-chart-table-content table.dataTable.display tbody > tr.selected:hover,\n");
|
||||
style.append(
|
||||
".dg-chart-table .dg-chart-table-content table.dataTable.display tbody > tr > .selected:hover {\n");
|
||||
style.append(" background-color: " + chartTheme.getHighlightTheme().getBackgroundColor() + ";\n");
|
||||
style.append(" color: " + chartTheme.getHighlightTheme().getColor() + ";\n");
|
||||
style.append("}\n");
|
||||
out.println(".dg-chart-table .dg-chart-table-content table.dataTable.hover tbody tr.hover.selected,");
|
||||
out.println(".dg-chart-table .dg-chart-table-content table.dataTable tbody > tr.selected,");
|
||||
out.println(".dg-chart-table .dg-chart-table-content table.dataTable tbody > tr > .selected,");
|
||||
out.println(".dg-chart-table .dg-chart-table-content table.dataTable.stripe tbody > tr.odd.selected,");
|
||||
out.println(
|
||||
".dg-chart-table .dg-chart-table-content table.dataTable.stripe tbody > tr.odd > .selected,");
|
||||
out.println(".dg-chart-table .dg-chart-table-content table.dataTable.display tbody > tr.odd.selected,");
|
||||
out.println(
|
||||
".dg-chart-table .dg-chart-table-content table.dataTable.display tbody > tr.odd > .selected,");
|
||||
out.println(".dg-chart-table .dg-chart-table-content table.dataTable.hover tbody > tr.selected:hover,");
|
||||
out.println(
|
||||
".dg-chart-table .dg-chart-table-content table.dataTable.hover tbody > tr > .selected:hover,");
|
||||
out.println(
|
||||
".dg-chart-table .dg-chart-table-content table.dataTable.display tbody > tr.selected:hover,");
|
||||
out.println(
|
||||
".dg-chart-table .dg-chart-table-content table.dataTable.display tbody > tr > .selected:hover {");
|
||||
out.println(" background-color: " + chartTheme.getHighlightTheme().getBackgroundColor() + ";");
|
||||
out.println(" color: " + chartTheme.getHighlightTheme().getColor() + ";");
|
||||
out.println("}");
|
||||
}
|
||||
|
||||
out.write(style.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -810,6 +812,74 @@ public class DashboardController extends AbstractDataAnalysisController implemen
|
|||
return getDashboardData(request, response, model, webContext, paramData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态加载看板图表。
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param model
|
||||
* @param dashbaordId
|
||||
* @throws Throwable
|
||||
*/
|
||||
@RequestMapping(value = "/loadChart", produces = CONTENT_TYPE_JSON)
|
||||
public void loadChart(HttpServletRequest request, HttpServletResponse response, org.springframework.ui.Model model,
|
||||
@RequestParam("dashboardId") String dashboardId, @RequestParam("chartWidgetId") String chartWidgetId,
|
||||
@RequestParam("chartElementId") String chartElementId)
|
||||
throws Throwable
|
||||
{
|
||||
SessionHtmlTplDashboardManager dashboardManager = getSessionHtmlTplDashboardManagerNotNull(request);
|
||||
HtmlTplDashboard dashboard = dashboardManager.get(dashboardId);
|
||||
|
||||
if (dashboard == null)
|
||||
throw new RecordNotFoundException();
|
||||
|
||||
HtmlTplDashboardWidgetEntity dashboardWidget = (HtmlTplDashboardWidgetEntity) dashboard.getWidget();
|
||||
|
||||
// 确保看板创建用户对看板模板内定义的图表有权限
|
||||
ChartWidgetSourceContext.set(new ChartWidgetSourceContext(dashboardWidget.getCreateUser()));
|
||||
|
||||
ChartWidgetSource chartWidgetSource = getHtmlTplDashboardWidgetEntityService()
|
||||
.getHtmlTplDashboardWidgetRenderer().getChartWidgetSource();
|
||||
|
||||
ChartWidget<HtmlRenderContext> chartWidget = chartWidgetSource.getChartWidget(chartWidgetId);
|
||||
|
||||
if (chartWidget == null)
|
||||
throw new RecordNotFoundException();
|
||||
|
||||
// 不缓存
|
||||
response.setContentType(CONTENT_TYPE_JSON);
|
||||
PrintWriter out = response.getWriter();
|
||||
|
||||
RenderStyle renderStyle = resolveRenderStyle(request);
|
||||
HtmlRenderContext renderContext = createHtmlRenderContext(request, createWebContext(request), renderStyle,
|
||||
out);
|
||||
|
||||
HtmlChartPluginRenderOption renderOption = new HtmlChartPluginRenderOption();
|
||||
renderOption.setChartElementId(chartElementId);
|
||||
renderOption.setNotWriteChartElement(true);
|
||||
renderOption.setPluginVarName(
|
||||
"{\"id\": \"" + WebUtils.escapeJavaScriptStringValue(chartWidget.getPlugin().getId()) + "\"}");
|
||||
renderOption.setNotWritePluginObject(true);
|
||||
renderOption.setChartVarName("undefined");
|
||||
renderOption.setRenderContextVarName("{}");
|
||||
renderOption.setNotWriteRenderContextObject(true);
|
||||
renderOption.setNotWriteScriptTag(true);
|
||||
renderOption.setNotWriteInvoke(true);
|
||||
renderOption.setWriteChartJson(true);
|
||||
HtmlChartPluginRenderOption.setOption(renderContext, renderOption);
|
||||
|
||||
Chart chart = chartWidget.render(renderContext);
|
||||
|
||||
synchronized (dashboard)
|
||||
{
|
||||
List<Chart> charts = dashboard.getCharts();
|
||||
List<Chart> newCharts = (charts == null || charts.isEmpty() ? new ArrayList<Chart>()
|
||||
: new ArrayList<Chart>(charts));
|
||||
newCharts.add(chart);
|
||||
dashboard.setCharts(newCharts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析HTML模板的字符编码。
|
||||
*
|
||||
|
|
|
@ -89,6 +89,14 @@
|
|||
$.extend(global.chartFactory.echartsMapURLs, mapUrls);
|
||||
};
|
||||
|
||||
dashboardFactory.loadChartConfig = (dashboardFactory.loadChartConfig ||
|
||||
{
|
||||
url: "/analysis/dashboard/loadChart",
|
||||
dashboardIdParamName: "dashboardId",
|
||||
chartWidgetIdParamName: "chartWidgetId",
|
||||
chartElementIdParamName: "chartElementId"
|
||||
});
|
||||
|
||||
//----------------------------------------
|
||||
// dashboardBase start
|
||||
//----------------------------------------
|
||||
|
@ -165,17 +173,31 @@
|
|||
data : JSON.stringify(data),
|
||||
success : function(resultsMap)
|
||||
{
|
||||
dashboard.updateCharts(resultsMap);
|
||||
try
|
||||
{
|
||||
dashboard.updateCharts(resultsMap);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
global.chartFactory.logException(e);
|
||||
}
|
||||
|
||||
dashboard.doHandleCharts();
|
||||
},
|
||||
error : function()
|
||||
{
|
||||
var updateTime = new Date().getTime();
|
||||
|
||||
for(var i=0; i<dashboard.charts.length; i++)
|
||||
dashboard.chartUpdateTime(dashboard.charts[i], updateTime);
|
||||
},
|
||||
complete : function()
|
||||
{
|
||||
try
|
||||
{
|
||||
for(var i=0; i<dashboard.charts.length; i++)
|
||||
dashboard.chartUpdateTime(dashboard.charts[i], updateTime);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
global.chartFactory.logException(e);
|
||||
}
|
||||
|
||||
dashboard.doHandleCharts();
|
||||
}
|
||||
});
|
||||
|
@ -361,6 +383,100 @@
|
|||
return data;
|
||||
};
|
||||
|
||||
/**
|
||||
* 异步加载图表。
|
||||
*
|
||||
* @param chartWidgetId 图表部件ID
|
||||
* @param chartElementId 图表HTML元素ID
|
||||
* @param ajaxOptions 选填参数,参数格式可以是ajax配置项:{...}、也可以是图表加载成功回调函数:function(chart){ ... }。
|
||||
* 如果ajax配置项的success函数、图表加载成功回调函数返回false,则后续不会自动调用dashboardBase.initLoadedChart函数。
|
||||
*/
|
||||
dashboardBase.loadChart = function(chartWidgetId, chartElementId, ajaxOptions)
|
||||
{
|
||||
var webContext = this.renderContext.webContext;
|
||||
var loadChartConfig = dashboardFactory.loadChartConfig;
|
||||
var _this = this;
|
||||
|
||||
if(!ajaxOptions)
|
||||
ajaxOptions = {};
|
||||
else if(typeof(ajaxOptions) == "function")
|
||||
{
|
||||
var successHandler = ajaxOptions;
|
||||
ajaxOptions =
|
||||
{
|
||||
success: successHandler
|
||||
};
|
||||
}
|
||||
|
||||
var data = {};
|
||||
data[loadChartConfig.dashboardIdParamName] = _this.id;
|
||||
data[loadChartConfig.chartWidgetIdParamName] = chartWidgetId;
|
||||
data[loadChartConfig.chartElementIdParamName] = chartElementId;
|
||||
|
||||
var myAjaxOptions = $.extend(
|
||||
{
|
||||
url: webContext.contextPath + dashboardFactory.loadChartConfig.url,
|
||||
data: data,
|
||||
error: function(jqXHR, textStatus, errorThrown)
|
||||
{
|
||||
var msg = (jqXHR.responseJSON ? jqXHR.responseJSON.message : undefined);
|
||||
if(!msg)
|
||||
msg = textStatus;
|
||||
|
||||
$("#" + chartElementId).html(msg);
|
||||
}
|
||||
},
|
||||
ajaxOptions);
|
||||
|
||||
if(!myAjaxOptions.success)
|
||||
{
|
||||
myAjaxOptions.success = function(chart, textStatus, jqXHR)
|
||||
{
|
||||
_this.inflateLoadedChart(chart);
|
||||
_this.initLoadedChart(chart);
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
var successHandler = myAjaxOptions.success;
|
||||
|
||||
myAjaxOptions.success = function(chart, textStatus, jqXHR)
|
||||
{
|
||||
_this.inflateLoadedChart(chart);
|
||||
var re = successHandler.call(this, chart, textStatus, jqXHR);
|
||||
|
||||
if(re != false)
|
||||
_this.initLoadedChart(chart);
|
||||
};
|
||||
}
|
||||
|
||||
$.ajax(myAjaxOptions);
|
||||
};
|
||||
|
||||
/**
|
||||
* 填充异步加载的图表。
|
||||
*
|
||||
* @param chart 图表JSON对象
|
||||
*/
|
||||
dashboardBase.inflateLoadedChart = function(chart)
|
||||
{
|
||||
chart.plugin = chartPluginManager.get(chart.plugin.id);
|
||||
chart.renderContext = this.renderContext;
|
||||
};
|
||||
|
||||
/**
|
||||
* 初始化异步加载的图表,将其加入看板对象,准备渲染。
|
||||
*
|
||||
* @param chart 图表对象
|
||||
*/
|
||||
dashboardBase.initLoadedChart = function(chart)
|
||||
{
|
||||
global.chartFactory.init(chart);
|
||||
|
||||
var charts = (this.charts || []);
|
||||
this.charts = charts.concat([ chart ]);
|
||||
};
|
||||
|
||||
//----------------------------------------
|
||||
// dashboardBase end
|
||||
//----------------------------------------
|
||||
|
|
Loading…
Reference in New Issue