[analysis]将HTML图表插件定义文件规范properties.json、chart.js合并为单个plugin.js文件规范,以简化插件定义方式

This commit is contained in:
datagear 2020-01-23 21:18:04 +08:00
parent 2cb38798b1
commit 25f188add6
42 changed files with 1380 additions and 438 deletions

View File

@ -22,6 +22,16 @@ import org.datagear.util.i18n.Label;
*/
public interface ChartPlugin<T extends RenderContext> extends Identifiable
{
String PROPERTY_ID = "id";
String PROPERTY_NAME_LABEL = "nameLabel";
String PROPERTY_DESC_LABEL = "descLabel";
String PROPERTY_MANUAL_LABEL = "manualLabel";
String PROPERTY_ICONS = "icons";
String PROPERTY_CHART_PROPERTIES = "chartProperties";
String PROPERTY_DATA_SIGNS = "dataSigns";
String PROPERTY_VERSION = "version";
String PROPERTY_ORDER = "order";
/**
* 获取名称标签
*

View File

@ -20,6 +20,13 @@ import org.datagear.util.i18n.Label;
*/
public class ChartProperty
{
public static final String PROPERTY_NAME = "name";
public static final String PROPERTY_TYPE = "type";
public static final String PROPERTY_NAME_LABEL = "nameLabel";
public static final String PROPERTY_DESC_LABEL = "descLabel";
public static final String PROPERTY_DEFAULT_VALUE = "defaultValue";
public static final String PROPERTY_CONSTRAINTS = "constraints";
/** 名称 */
private String name;

View File

@ -20,6 +20,11 @@ import java.util.Map;
*/
public class Dashboard extends AbstractIdentifiable
{
public static final String PROPERTY_ID = "id";
public static final String PROPERTY_RENDER_CONTEXT = "renderContext";
public static final String PROPERTY_WIDGET = "widget";
public static final String PROPERTY_CHARTS = "charts";
private RenderContext renderContext;
private DashboardWidget<?> widget;

View File

@ -14,6 +14,8 @@ public class DashboardTheme extends Theme
{
private static final long serialVersionUID = 1L;
public static final String PROPERTY_CHART_THEME = "chartTheme";
private ChartTheme chartTheme;
public DashboardTheme()

View File

@ -27,6 +27,12 @@ public class DataSign implements Serializable
{
private static final long serialVersionUID = 1L;
public static final String PROPERTY_NAME = "name";
public static final String PROPERTY_OCCUR_REQUIRED = "occurRequired";
public static final String PROPERTY_OCCUR_MULTIPLE = "occurMultiple";
public static final String PROPERTY_NAME_LABEL = "nameLabel";
public static final String PROPERTY_DESC_LABEL = "descLabel";
/** 名称 */
private String name;

View File

@ -21,6 +21,8 @@ import java.util.Map;
*/
public interface RenderContext
{
String PROPERTY_ATTRIBUTES = "attributes";
/**
* 获取属性
*

View File

@ -69,52 +69,6 @@ import com.alibaba.fastjson.JSON;
*/
public class JsonChartPluginPropertiesResolver
{
public static final String CHART_PLUGIN_ID = "id";
public static final String CHART_PLUGIN_NAME_LABEL = "nameLabel";
public static final String CHART_PLUGIN_DESC_LABEL = "descLabel";
public static final String CHART_PLUGIN_MANUAL_LABEL = "manualLabel";
public static final String CHART_PLUGIN_ICONS = "icons";
public static final String CHART_PLUGIN_CHART_PROPERTIES = "chartProperties";
public static final String CHART_PLUGIN_DATA_SIGNS = "dataSigns";
public static final String CHART_PLUGIN_VERSION = "version";
public static final String CHART_PLUGIN_ORDER = "order";
public static final String LABEL_VALUE = "value";
public static final String LABEL_LOCALE_VALUES = "localeValues";
public static final String LOCATION_ICON_LOCATION = "location";
public static final String CHART_PROPERTY_NAME = "name";
public static final String CHART_PROPERTY_TYPE = "type";
public static final String CHART_PROPERTY_NAME_LABEL = "nameLabel";
public static final String CHART_PROPERTY_DESC_LABEL = "descLabel";
public static final String CHART_PROPERTY_DEFAULT_VALUE = "defaultValue";
public static final String CHART_PROPERTY_CONSTRAINTS = "constraints";
public static final String DATA_SIGN_PROPERTY_NAME = "name";
public static final String DATA_SIGN_PROPERTY_OCCUR_REQUIRED = "occurRequired";
public static final String DATA_SIGN_PROPERTY_OCCUR_MULTIPLE = "occurMultiple";
public static final String DATA_SIGN_PROPERTY_NAME_LABEL = "nameLabel";
public static final String DATA_SIGN_PROPERTY_DESC_LABEL = "descLabel";
private PropertyTypeValueConverter propertyTypeValueConverter = new PropertyTypeValueConverter();
private ConcurrentMap<String, Locale> _localeCache = new ConcurrentHashMap<String, Locale>();
@ -150,12 +104,13 @@ public class JsonChartPluginPropertiesResolver
Map<String, Object> properties = new HashMap<String, Object>(map);
properties.put(CHART_PLUGIN_NAME_LABEL, convertToLabel(map.get(CHART_PLUGIN_NAME_LABEL)));
properties.put(CHART_PLUGIN_DESC_LABEL, convertToLabel(map.get(CHART_PLUGIN_DESC_LABEL)));
properties.put(CHART_PLUGIN_MANUAL_LABEL, convertToLabel(map.get(CHART_PLUGIN_MANUAL_LABEL)));
properties.put(CHART_PLUGIN_ICONS, convertToIcons(map.get(CHART_PLUGIN_ICONS)));
properties.put(CHART_PLUGIN_CHART_PROPERTIES, convertToChartProperties(map.get(CHART_PLUGIN_CHART_PROPERTIES)));
properties.put(CHART_PLUGIN_DATA_SIGNS, convertToDataSigns(map.get(CHART_PLUGIN_DATA_SIGNS)));
properties.put(ChartPlugin.PROPERTY_NAME_LABEL, convertToLabel(map.get(ChartPlugin.PROPERTY_NAME_LABEL)));
properties.put(ChartPlugin.PROPERTY_DESC_LABEL, convertToLabel(map.get(ChartPlugin.PROPERTY_DESC_LABEL)));
properties.put(ChartPlugin.PROPERTY_MANUAL_LABEL, convertToLabel(map.get(ChartPlugin.PROPERTY_MANUAL_LABEL)));
properties.put(ChartPlugin.PROPERTY_ICONS, convertToIcons(map.get(ChartPlugin.PROPERTY_ICONS)));
properties.put(ChartPlugin.PROPERTY_CHART_PROPERTIES,
convertToChartProperties(map.get(ChartPlugin.PROPERTY_CHART_PROPERTIES)));
properties.put(ChartPlugin.PROPERTY_DATA_SIGNS, convertToDataSigns(map.get(ChartPlugin.PROPERTY_DATA_SIGNS)));
return properties;
}
@ -214,18 +169,18 @@ public class JsonChartPluginPropertiesResolver
@SuppressWarnings("unchecked")
public void setChartPluginProperties(AbstractChartPlugin<?> chartPlugin, Map<String, ?> properties)
{
chartPlugin.setId((String) properties.get(CHART_PLUGIN_ID));
chartPlugin.setNameLabel((Label) properties.get(CHART_PLUGIN_NAME_LABEL));
chartPlugin.setDescLabel((Label) properties.get(CHART_PLUGIN_DESC_LABEL));
chartPlugin.setManualLabel((Label) properties.get(CHART_PLUGIN_MANUAL_LABEL));
chartPlugin.setIcons((Map<RenderStyle, Icon>) properties.get(CHART_PLUGIN_ICONS));
chartPlugin.setChartProperties((List<ChartProperty>) properties.get(CHART_PLUGIN_CHART_PROPERTIES));
chartPlugin.setDataSigns((List<DataSign>) properties.get(CHART_PLUGIN_DATA_SIGNS));
chartPlugin.setVersion((String) properties.get(CHART_PLUGIN_VERSION));
chartPlugin.setId((String) properties.get(ChartPlugin.PROPERTY_ID));
chartPlugin.setNameLabel((Label) properties.get(ChartPlugin.PROPERTY_NAME_LABEL));
chartPlugin.setDescLabel((Label) properties.get(ChartPlugin.PROPERTY_DESC_LABEL));
chartPlugin.setManualLabel((Label) properties.get(ChartPlugin.PROPERTY_MANUAL_LABEL));
chartPlugin.setIcons((Map<RenderStyle, Icon>) properties.get(ChartPlugin.PROPERTY_ICONS));
chartPlugin.setChartProperties((List<ChartProperty>) properties.get(ChartPlugin.PROPERTY_CHART_PROPERTIES));
chartPlugin.setDataSigns((List<DataSign>) properties.get(ChartPlugin.PROPERTY_DATA_SIGNS));
chartPlugin.setVersion((String) properties.get(ChartPlugin.PROPERTY_VERSION));
Integer order = null;
Object orderObj = properties.get(CHART_PLUGIN_ORDER);
Object orderObj = properties.get(ChartPlugin.PROPERTY_ORDER);
if (orderObj instanceof Number)
order = ((Number) orderObj).intValue();
else if (orderObj instanceof String)
@ -268,9 +223,9 @@ public class JsonChartPluginPropertiesResolver
Map<String, ?> map = (Map<String, ?>) obj;
Label label = createLabel();
label.setValue((String) map.get(LABEL_VALUE));
label.setValue((String) map.get(Label.PROPERTY_VALUE));
Object localeValuesObj = map.get(LABEL_LOCALE_VALUES);
Object localeValuesObj = map.get(Label.PROPERTY_LOCALE_VALUES);
if (localeValuesObj != null)
{
Map<Locale, String> localeValues = new HashMap<Locale, String>();
@ -367,7 +322,7 @@ public class JsonChartPluginPropertiesResolver
@SuppressWarnings("unchecked")
Map<String, ?> map = (Map<String, String>) obj;
String location = (String) map.get(LOCATION_ICON_LOCATION);
String location = (String) map.get(LocationIcon.PROPERTY_LOCATION);
if (location == null)
return null;
@ -455,22 +410,23 @@ public class JsonChartPluginPropertiesResolver
@SuppressWarnings("unchecked")
Map<String, ?> map = (Map<String, ?>) obj;
String name = (String) map.get(CHART_PROPERTY_NAME);
String name = (String) map.get(ChartProperty.PROPERTY_NAME);
if (name == null || name.isEmpty())
return null;
ChartProperty chartProperty = createChartProperty();
chartProperty.setName(name);
PropertyType type = convertToPropertyType(map.get(CHART_PROPERTY_TYPE));
PropertyType type = convertToPropertyType(map.get(ChartProperty.PROPERTY_TYPE));
if (type == null)
type = PropertyType.STRING;
chartProperty.setType(type);
chartProperty.setNameLabel(convertToLabel(map.get(CHART_PROPERTY_NAME_LABEL)));
chartProperty.setDescLabel(convertToLabel(map.get(CHART_PROPERTY_DESC_LABEL)));
chartProperty.setDefaultValue(convertToPropertyTypeValue(type, map.get(CHART_PROPERTY_DEFAULT_VALUE)));
chartProperty.setConstraints(convertToConstraints(map.get(CHART_PROPERTY_CONSTRAINTS)));
chartProperty.setNameLabel(convertToLabel(map.get(ChartProperty.PROPERTY_NAME_LABEL)));
chartProperty.setDescLabel(convertToLabel(map.get(ChartProperty.PROPERTY_DESC_LABEL)));
chartProperty
.setDefaultValue(convertToPropertyTypeValue(type, map.get(ChartProperty.PROPERTY_DEFAULT_VALUE)));
chartProperty.setConstraints(convertToConstraints(map.get(ChartProperty.PROPERTY_CONSTRAINTS)));
return chartProperty;
}
@ -669,17 +625,17 @@ public class JsonChartPluginPropertiesResolver
@SuppressWarnings("unchecked")
Map<String, ?> map = (Map<String, ?>) obj;
String name = (String) map.get(DATA_SIGN_PROPERTY_NAME);
String name = (String) map.get(DataSign.PROPERTY_NAME);
if (name == null || name.isEmpty())
return null;
DataSign dataSign = createDataSign();
dataSign.setName(name);
dataSign.setOccurRequired(convertToBoolean(map.get(DATA_SIGN_PROPERTY_OCCUR_REQUIRED), true));
dataSign.setOccurMultiple(convertToBoolean(map.get(DATA_SIGN_PROPERTY_OCCUR_MULTIPLE), true));
dataSign.setNameLabel(convertToLabel(map.get(DATA_SIGN_PROPERTY_NAME_LABEL)));
dataSign.setDescLabel(convertToLabel(map.get(DATA_SIGN_PROPERTY_DESC_LABEL)));
dataSign.setOccurRequired(convertToBoolean(map.get(DataSign.PROPERTY_OCCUR_REQUIRED), true));
dataSign.setOccurMultiple(convertToBoolean(map.get(DataSign.PROPERTY_OCCUR_MULTIPLE), true));
dataSign.setNameLabel(convertToLabel(map.get(DataSign.PROPERTY_NAME_LABEL)));
dataSign.setDescLabel(convertToLabel(map.get(DataSign.PROPERTY_DESC_LABEL)));
return dataSign;
}

View File

@ -24,6 +24,8 @@ public class LocationIcon extends LocationResource implements Icon
{
private static final long serialVersionUID = 1L;
public static final String PROPERTY_LOCATION = "location";
private String type = "";
private long lastModified = System.currentTimeMillis();

View File

@ -438,7 +438,7 @@ public class DirectoryHtmlChartPluginManager extends ConcurrentChartPluginManage
{
HtmlChartPlugin<?> htmlChartPlugin = (HtmlChartPlugin<?>) chartPlugin;
if (htmlChartPlugin.getJsChartRenderer() == null)
if (htmlChartPlugin.getChartRenderer() == null)
legal = false;
}
}

View File

@ -102,6 +102,8 @@ import org.datagear.util.i18n.Label;
*/
public class HtmlChartPlugin<T extends HtmlRenderContext> extends AbstractChartPlugin<T>
{
public static final String PROPERTY_CHART_RENDER = "chartRender";
/** HTML换行符 */
public static final String HTML_NEW_LINE = "\n";
@ -113,7 +115,7 @@ public class HtmlChartPlugin<T extends HtmlRenderContext> extends AbstractChartP
public static final String DEFAULT_SCRIPT_CHART_REF_PLACEHOLDER = "$CHART";
/** JS图表渲染器 */
private JsChartRenderer jsChartRenderer;
private JsChartRenderer chartRenderer;
/** 图表HTML元素标签名 */
private String elementTagName = "div";
@ -126,20 +128,20 @@ public class HtmlChartPlugin<T extends HtmlRenderContext> extends AbstractChartP
super();
}
public HtmlChartPlugin(String id, Label nameLabel, JsChartRenderer jsChartRenderer)
public HtmlChartPlugin(String id, Label nameLabel, JsChartRenderer chartRenderer)
{
super(id, nameLabel);
this.jsChartRenderer = jsChartRenderer;
this.chartRenderer = chartRenderer;
}
public JsChartRenderer getJsChartRenderer()
public JsChartRenderer getChartRenderer()
{
return jsChartRenderer;
return chartRenderer;
}
public void setJsChartRenderer(JsChartRenderer jsChartRenderer)
public void setChartRenderer(JsChartRenderer chartRenderer)
{
this.jsChartRenderer = jsChartRenderer;
this.chartRenderer = chartRenderer;
}
public String getElementTagName()
@ -256,9 +258,8 @@ public class HtmlChartPlugin<T extends HtmlRenderContext> extends AbstractChartP
if (!optionInitialized.isNotWriteInvoke())
{
out.write(
optionInitialized.getPluginVarName() + "." + HtmlChartPluginScriptObjectWriter.JS_CHART_RENDER_NAME
+ "." + JsChartRenderer.RENDER_FUNCTION_NAME + "(" + chart.getVarName() + ");");
out.write(optionInitialized.getPluginVarName() + "." + PROPERTY_CHART_RENDER + "."
+ JsChartRenderer.RENDER_FUNCTION_NAME + "(" + chart.getVarName() + ");");
writeNewLine(out);
}
}

View File

@ -0,0 +1,268 @@
/*
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
*/
/**
*
*/
package org.datagear.analysis.support.html;
import java.io.IOException;
import java.io.Reader;
import java.io.Serializable;
import org.datagear.util.IOUtil;
/**
* {@linkplain HtmlChartPlugin}的JS定义格式解析器
* <p>
* 支持的JS定义格式
* </p>
* <code>
* <pre>
* {
* id: ...,
* nameLabel: ...,
* ...,
* chartRender: {...},
* ...
* }
* </pre>
* </code>
* <p>
* 此类从上述格式的输入流解析{@linkplain JsDefContent}对象其中
* </p>
* <p>
* {@linkplain JsDefContent#getPluginJson()}为上述格式中将<code>chartRender: {...}</code>替换为<code>chartRender: {}</code>的内容
* </p>
* <p>
* {@linkplain JsDefContent#getPluginChartRender()}为上述格式中<code>chartRender</code>属性值部分的内容<code>{...}</code>
* </p>
*
* @author datagear@163.com
*
*/
public class HtmlChartPluginJsDefResolver extends TextParserSupport
{
protected static final char PROPERTY_CHART_RENDER_FIRST = HtmlChartPlugin.PROPERTY_CHART_RENDER.charAt(0);
protected static final String PROPERTY_CHART_RENDER_DQ = "\"" + HtmlChartPlugin.PROPERTY_CHART_RENDER + "\"";
protected static final String PROPERTY_CHART_RENDER_SQ = "'" + HtmlChartPlugin.PROPERTY_CHART_RENDER + "'";
public HtmlChartPluginJsDefResolver()
{
super();
}
/**
* 解析
*
* @param str
* @return
* @throws IOException
*/
public JsDefContent resolve(String str) throws IOException
{
if (str == null)
str = "";
Reader reader = null;
try
{
reader = IOUtil.getReader(str);
return resolve(reader);
}
finally
{
IOUtil.close(reader);
}
}
/**
* 解析
*
* @param reader
* @return
* @throws IOException
*/
public JsDefContent resolve(Reader reader) throws IOException
{
StringBuilder jsonBuilder = new StringBuilder();
StringBuilder chartRenderBuilder = new StringBuilder();
resolveJsDefContent(reader, jsonBuilder, chartRenderBuilder);
return new JsDefContent(jsonBuilder.toString(), chartRenderBuilder.toString());
}
protected void resolveJsDefContent(Reader in, StringBuilder jsonBuilder, StringBuilder chartRenderBuilder)
throws IOException
{
StringBuilder token = createStringBuilder();
int c = in.read();
while (c > -1)
{
appendChar(jsonBuilder, c);
if (isWhitespace(c))
{
c = in.read();
}
else if (c == ':')
{
String tokenStr = token.toString();
clear(token);
if (tokenStr.equals(HtmlChartPlugin.PROPERTY_CHART_RENDER) || tokenStr.equals(PROPERTY_CHART_RENDER_DQ)
|| tokenStr.equals(PROPERTY_CHART_RENDER_SQ))
{
readChartRenderObjectContent(in, chartRenderBuilder);
jsonBuilder.append("{}");
}
c = in.read();
}
else if (c == '{' || c == ',')
{
clear(token);
c = in.read();
}
// 注释
else if (c == '/')
{
c = in.read();
if (c == '/')
{
appendChar(jsonBuilder, c);
c = skipLineComment(in, jsonBuilder, false);
}
else if (c == '*')
{
appendChar(jsonBuilder, c);
c = skipBlockComment(in, jsonBuilder, false);
}
else
{
appendChar(token, '/');
appendCharIfValid(token, c);
}
}
// 字符串
else if (c == '\'' || c == '"')
{
appendChar(token, c);
c = readQuoted(in, token, c);
jsonBuilder.append(token.substring(1));
}
else
{
appendChar(token, c);
c = in.read();
}
}
}
/**
* <code>{</code>之前的位置开始读取{@linkplain JsChartRenderer}内容
* <p>
* 读取停止位置为<code>}</code>
* </p>
*
* @param in
* @param chartRenderBuilder
* @throws IOException
*/
protected void readChartRenderObjectContent(Reader in, StringBuilder chartRenderBuilder) throws IOException
{
int qcount = 0;
int c = -1;
while ((c = in.read()) > -1)
{
appendChar(chartRenderBuilder, c);
if (c == '{')
{
qcount++;
}
else if (c == '}')
{
qcount--;
if (qcount == 0)
break;
}
// 字符串
else if (c == '\'' || c == '"')
{
c = readQuoted(in, chartRenderBuilder, c);
appendCharIfValid(chartRenderBuilder, c);
}
// 注释
else if (c == '/')
{
int next = in.read();
appendCharIfValid(chartRenderBuilder, next);
// 行注释
if (next == '/')
skipLineComment(in, chartRenderBuilder, true);
else if (next == '*')
skipBlockComment(in, chartRenderBuilder, true);
}
}
}
public static class JsDefContent implements Serializable
{
private static final long serialVersionUID = 1L;
/** 插件定义JSON */
private String pluginJson;
/** 插件JS渲染器对象内容 */
private String pluginChartRender;
public JsDefContent()
{
super();
}
public JsDefContent(String pluginJson, String pluginChartRender)
{
super();
this.pluginJson = pluginJson;
this.pluginChartRender = pluginChartRender;
}
public String getPluginJson()
{
return pluginJson;
}
public void setPluginJson(String pluginJson)
{
this.pluginJson = pluginJson;
}
public String getPluginChartRender()
{
return pluginChartRender;
}
public void setPluginChartRender(String pluginChartRender)
{
this.pluginChartRender = pluginChartRender;
}
@Override
public String toString()
{
return getClass().getSimpleName() + " [pluginJson=" + pluginJson + ", pluginChartRender="
+ pluginChartRender + "]";
}
}
}

View File

@ -10,6 +10,7 @@ package org.datagear.analysis.support.html;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@ -22,6 +23,7 @@ import org.datagear.analysis.RenderStyle;
import org.datagear.analysis.support.BytesIcon;
import org.datagear.analysis.support.JsonChartPluginPropertiesResolver;
import org.datagear.analysis.support.LocationIcon;
import org.datagear.analysis.support.html.HtmlChartPluginJsDefResolver.JsDefContent;
import org.datagear.util.FileUtil;
import org.datagear.util.IOUtil;
import org.datagear.util.StringUtil;
@ -36,15 +38,25 @@ import org.datagear.util.StringUtil;
* </p>
* <code>
* <pre>
* |---- properties.json
* |---- chart.js
* |---- plugin.js
* </pre>
* </code>
* <p>
* <code>properties.json</code>用于定义{@linkplain HtmlChartPlugin}本身的属性
* 上述文件格式规范如下
* </p>
* <code>
* <pre>
* {
* id : "...",
* nameLabel : { value : "...", localeValues : { "zh" : "...", "en" : "..." }},
* ...,
* chartRender: { ... },
* ...
* }
* </pre>
* </code>
* <p>
* 如果<code>properties.json</code>中定义了插件图标比如
* 如果<code>plugin.js</code>中定义了插件图标比如
* </p>
* <p>
* <code>icons : { "LIGHT" : "icons/light.png" }</code>
@ -52,10 +64,10 @@ import org.datagear.util.StringUtil;
* <p>
* 那么上述文件结构中还应有<code>icons/light.png</code>文件
* </p>
* <code>chart.js</code>用于定义{@linkplain HtmlChartPlugin}的图表渲染逻辑
* <code>chartRender</code>用于定义{@linkplain HtmlChartPlugin#getChartRenderer()}内容
* </p>
* <p>
* 默认地上述两个文件应该为<code>UTF-8</code>编码
* 默认地上述文件应该为<code>UTF-8</code>编码
* </p>
*
* @author datagear@163.com
@ -63,9 +75,9 @@ import org.datagear.util.StringUtil;
*/
public class HtmlChartPluginLoader
{
public static final String NAME_PROPERTIES = "properties.json";
public static final String FILE_NAME_PLUGIN = "plugin.js";
public static final String NAME_CHART = "chart.js";
private HtmlChartPluginJsDefResolver htmlChartPluginJsDefResolver = new HtmlChartPluginJsDefResolver();
private JsonChartPluginPropertiesResolver jsonChartPluginPropertiesResolver = new JsonChartPluginPropertiesResolver();
@ -77,6 +89,16 @@ public class HtmlChartPluginLoader
super();
}
public HtmlChartPluginJsDefResolver getHtmlChartPluginJsDefResolver()
{
return htmlChartPluginJsDefResolver;
}
public void setHtmlChartPluginJsDefResolver(HtmlChartPluginJsDefResolver htmlChartPluginJsDefResolver)
{
this.htmlChartPluginJsDefResolver = htmlChartPluginJsDefResolver;
}
public JsonChartPluginPropertiesResolver getJsonChartPluginPropertiesResolver()
{
return jsonChartPluginPropertiesResolver;
@ -109,10 +131,9 @@ public class HtmlChartPluginLoader
if (!directory.exists())
return false;
File propFile = new File(directory, NAME_PROPERTIES);
File chartFile = new File(directory, NAME_CHART);
File pluginFile = new File(directory, FILE_NAME_PLUGIN);
return (propFile.exists() && chartFile.exists());
return (pluginFile.exists());
}
/**
@ -165,11 +186,7 @@ public class HtmlChartPluginLoader
if (zipEntry.isDirectory())
;
else if (name.equals(NAME_PROPERTIES))
{
yes += 1;
}
else if (name.equals(NAME_CHART))
else if (name.equals(FILE_NAME_PLUGIN))
{
yes += 1;
}
@ -182,7 +199,7 @@ public class HtmlChartPluginLoader
throw new HtmlChartPluginLoadException(e);
}
return (yes >= 2);
return (yes >= 1);
}
/**
@ -326,32 +343,34 @@ public class HtmlChartPluginLoader
protected HtmlChartPlugin<?> loadSingleForDirectory(File directory) throws HtmlChartPluginLoadException
{
File propFile = new File(directory, NAME_PROPERTIES);
File chartFile = new File(directory, NAME_CHART);
File chartFile = new File(directory, FILE_NAME_PLUGIN);
if (!propFile.exists() || !chartFile.exists())
if (!chartFile.exists())
return null;
HtmlChartPlugin<?> plugin = null;
InputStream propIn = null;
InputStream chartIn = null;
Reader chartIn = null;
try
{
propIn = IOUtil.getInputStream(propFile);
chartIn = IOUtil.getInputStream(chartFile);
chartIn = IOUtil.getReader(chartFile, this.encoding);
Map<String, Object> properties = this.jsonChartPluginPropertiesResolver.resolveChartPluginProperties(propIn,
this.encoding);
String scriptContent = readScriptContent(chartIn, false);
JsDefContent jsDefContent = this.htmlChartPluginJsDefResolver.resolve(chartIn);
plugin = createHtmlChartPlugin();
if (!StringUtil.isEmpty(jsDefContent.getPluginJson())
&& !StringUtil.isEmpty(jsDefContent.getPluginChartRender()))
{
Map<String, Object> properties = this.jsonChartPluginPropertiesResolver
.resolveChartPluginProperties(jsDefContent.getPluginJson());
this.jsonChartPluginPropertiesResolver.setChartPluginProperties(plugin, properties);
plugin.setJsChartRenderer(new StringJsChartRenderer(scriptContent));
plugin = createHtmlChartPlugin();
plugin.setIcons(toBytesIconsInDirectory(directory, plugin.getIcons()));
this.jsonChartPluginPropertiesResolver.setChartPluginProperties(plugin, properties);
plugin.setChartRenderer(new StringJsChartRenderer(jsDefContent.getPluginChartRender()));
plugin.setIcons(toBytesIconsInDirectory(directory, plugin.getIcons()));
}
}
catch (Exception e)
{
@ -359,7 +378,6 @@ public class HtmlChartPluginLoader
}
finally
{
IOUtil.close(propIn);
IOUtil.close(chartIn);
}

View File

@ -28,8 +28,6 @@ import org.datagear.util.IOUtil;
*/
public class HtmlChartPluginScriptObjectWriter extends AbstractHtmlScriptObjectWriter
{
public static final String JS_CHART_RENDER_NAME = "jsChartRender";
public HtmlChartPluginScriptObjectWriter()
{
super();
@ -44,7 +42,7 @@ public class HtmlChartPluginScriptObjectWriter extends AbstractHtmlScriptObjectW
* <pre>
* var [varName]=
* { ... };
* [varName].jsChartRender=
* [varName].chartRender=
* {...};
* <pre>
* </code>
@ -63,7 +61,7 @@ public class HtmlChartPluginScriptObjectWriter extends AbstractHtmlScriptObjectW
writeJsonObject(out, jsonPlugin);
out.write(";");
writeNewLine(out);
writeJsChartRender(out, plugin, varName);
writeHtmlChartRender(out, plugin, varName);
}
/**
@ -73,14 +71,14 @@ public class HtmlChartPluginScriptObjectWriter extends AbstractHtmlScriptObjectW
* @param chart
* @throws IOException
*/
protected void writeJsChartRender(Writer out, HtmlChartPlugin<?> plugin, String varName) throws IOException
protected void writeHtmlChartRender(Writer out, HtmlChartPlugin<?> plugin, String varName) throws IOException
{
out.write(varName + "." + JS_CHART_RENDER_NAME + "=");
out.write(varName + "." + HtmlChartPlugin.PROPERTY_CHART_RENDER + "=");
writeNewLine(out);
JsChartRenderer jsChartRenderer = plugin.getJsChartRenderer();
JsChartRenderer chartRenderer = plugin.getChartRenderer();
Reader reader = jsChartRenderer.getReader();
Reader reader = chartRenderer.getReader();
try
{

View File

@ -206,6 +206,28 @@ public class HtmlTplDashboardWidgetFmkRenderer<T extends HtmlRenderContext> exte
return dataModel;
}
/**
* 设置用于渲染Freemark看板图表的{@linkplain HtmlChartPluginRenderOption}
*
* @param renderContext
* @param dashboardVarName
* @return
*/
protected HtmlChartPluginRenderOption setHtmlChartPluginRenderOption(RenderContext renderContext,
String dashboardVarName)
{
HtmlChartPluginRenderOption option = new HtmlChartPluginRenderOption();
option.setNotWriteChartElement(false);
option.setNotWriteScriptTag(false);
option.setNotWriteInvoke(true);
option.setNotWriteRenderContextObject(true);
option.setRenderContextVarName(dashboardVarName + ".renderContext");
HtmlChartPluginRenderOption.setOption(renderContext, option);
return option;
}
/**
* HTML看板渲染数据模型
*
@ -401,28 +423,6 @@ public class HtmlTplDashboardWidgetFmkRenderer<T extends HtmlRenderContext> exte
}
}
/**
* 设置用于渲染Freemark看板图表的{@linkplain HtmlChartPluginRenderOption}
*
* @param renderContext
* @param dashboardVarName
* @return
*/
protected HtmlChartPluginRenderOption setHtmlChartPluginRenderOption(RenderContext renderContext,
String dashboardVarName)
{
HtmlChartPluginRenderOption option = new HtmlChartPluginRenderOption();
option.setNotWriteChartElement(false);
option.setNotWriteScriptTag(false);
option.setNotWriteInvoke(true);
option.setNotWriteRenderContextObject(true);
option.setRenderContextVarName(dashboardVarName + ".renderContext");
HtmlChartPluginRenderOption.setOption(renderContext, option);
return option;
}
/**
* @chart指令
*
@ -461,7 +461,7 @@ public class HtmlTplDashboardWidgetFmkRenderer<T extends HtmlRenderContext> exte
option.setChartElementId(elementId);
option.setChartVarName(var);
HtmlChart chart = chartWidget.render(renderContext);
HtmlChart chart = writeHtmlChart(chartWidget, renderContext);
List<Chart> charts = htmlDashboard.getCharts();
if (charts == null)

View File

@ -387,7 +387,7 @@ public class HtmlTplDashboardWidgetHtmlRenderer<T extends HtmlRenderContext> ext
option.setPluginVarName(chartPluginVarNames.get(i));
option.setChartVarName(chartVarName);
HtmlChart chart = chartWidget.render(renderContext);
HtmlChart chart = writeHtmlChart(chartWidget, renderContext);
charts.add(chart);
}

View File

@ -21,6 +21,7 @@ import org.datagear.analysis.ChartTheme;
import org.datagear.analysis.Dashboard;
import org.datagear.analysis.DashboardTheme;
import org.datagear.analysis.DashboardThemeSource;
import org.datagear.analysis.RenderContext;
import org.datagear.analysis.RenderException;
import org.datagear.analysis.RenderStyle;
import org.datagear.analysis.Theme;
@ -91,6 +92,10 @@ public abstract class HtmlTplDashboardWidgetRenderer<T extends HtmlRenderContext
public static final String DEFAULT_DASHBOARD_VAR = "dashboard";
public static final String PROPERTY_VALUE_FOR_NOT_FOUND = "targetHtmlChartWidgetNotFoundMessage";
public static final String PROPERTY_VALUE_FOR_RENDER_EXCEPTION = "targetHtmlChartRenderExceptionMessage";
private DashboardWidgetResManager dashboardWidgetResManager;
private ChartWidgetSource chartWidgetSource;
@ -104,7 +109,12 @@ public abstract class HtmlTplDashboardWidgetRenderer<T extends HtmlRenderContext
private HtmlDashboardScriptObjectWriter htmlDashboardScriptObjectWriter = new HtmlDashboardScriptObjectWriter();
private HtmlChartPlugin<HtmlRenderContext> htmlChartPluginForNotFound = new ValueHtmlChartPlugin<HtmlRenderContext>(
StringUtil.firstLowerCase(Global.PRODUCT_NAME_EN) + "HtmlChartPluginForNotFound");
StringUtil.firstLowerCase(Global.PRODUCT_NAME_EN) + "HtmlChartPluginForNotFound",
PROPERTY_VALUE_FOR_NOT_FOUND);
private HtmlChartPlugin<HtmlRenderContext> htmlChartPluginForRenderException = new ValueHtmlChartPlugin<HtmlRenderContext>(
StringUtil.firstLowerCase(Global.PRODUCT_NAME_EN) + "HtmlChartPluginForRenderException",
PROPERTY_VALUE_FOR_RENDER_EXCEPTION);
/** 内置导入内容 */
private List<HtmlDashboardImport> dashboardImports;
@ -224,6 +234,17 @@ public abstract class HtmlTplDashboardWidgetRenderer<T extends HtmlRenderContext
this.htmlChartPluginForNotFound = htmlChartPluginForNotFound;
}
public HtmlChartPlugin<HtmlRenderContext> getHtmlChartPluginForRenderException()
{
return htmlChartPluginForRenderException;
}
public void setHtmlChartPluginForRenderException(
HtmlChartPlugin<HtmlRenderContext> htmlChartPluginForRenderException)
{
this.htmlChartPluginForRenderException = htmlChartPluginForRenderException;
}
public List<HtmlDashboardImport> getDashboardImports()
{
return dashboardImports;
@ -658,7 +679,7 @@ public abstract class HtmlTplDashboardWidgetRenderer<T extends HtmlRenderContext
HtmlChartWidget<HtmlRenderContext> widget = new HtmlChartWidget<HtmlRenderContext>(IDUtil.uuid(),
"HtmlChartWidgetForNotFound", this.htmlChartPluginForNotFound);
widget.addChartPropertyValue(ValueHtmlChartPlugin.VALUE_CHART_PROPERTY_NAME,
widget.addChartPropertyValue(PROPERTY_VALUE_FOR_NOT_FOUND,
"Chart '" + (notFoundWidgetId == null ? "" : notFoundWidgetId) + "' Not Found");
return widget;
@ -721,10 +742,13 @@ public abstract class HtmlTplDashboardWidgetRenderer<T extends HtmlRenderContext
ChartTheme chartTheme = HtmlRenderAttributes.removeChartTheme(renderContext);
getHtmlRenderContextScriptObjectWriter().writeOnlyAttributes(out, renderContext, tmpRenderContextVar);
out.write(varName + ".renderContext.attributes = " + tmpRenderContextVar + ".attributes;");
out.write(varName + "." + Dashboard.PROPERTY_RENDER_CONTEXT + "." + RenderContext.PROPERTY_ATTRIBUTES + " = "
+ tmpRenderContextVar + "." + RenderContext.PROPERTY_ATTRIBUTES + ";");
writeNewLine(out);
out.write(varName + ".renderContext.attributes." + HtmlRenderAttributes.CHART_THEME + " = "
+ tmpRenderContextVar + ".attributes." + HtmlRenderAttributes.DASHBOARD_THEME + ".chartTheme;");
out.write(varName + "." + Dashboard.PROPERTY_RENDER_CONTEXT + "." + RenderContext.PROPERTY_ATTRIBUTES + "."
+ HtmlRenderAttributes.CHART_THEME + " = " + tmpRenderContextVar + "."
+ RenderContext.PROPERTY_ATTRIBUTES + "." + HtmlRenderAttributes.DASHBOARD_THEME + "."
+ DashboardTheme.PROPERTY_CHART_THEME + ";");
writeNewLine(out);
HtmlRenderAttributes.setChartTheme(renderContext, chartTheme);
@ -737,7 +761,8 @@ public abstract class HtmlTplDashboardWidgetRenderer<T extends HtmlRenderContext
if (!(chart instanceof HtmlChart))
continue;
out.write(varName + ".charts.push(" + ((HtmlChart) chart).getVarName() + ");");
out.write(
varName + "." + Dashboard.PROPERTY_CHARTS + ".push(" + ((HtmlChart) chart).getVarName() + ");");
writeNewLine(out);
}
}
@ -827,6 +852,19 @@ public abstract class HtmlTplDashboardWidgetRenderer<T extends HtmlRenderContext
}
}
/**
* {@linkplain HtmlChart}
*
* @param chartWidget
* @param renderContext
* @return
*/
protected HtmlChart writeHtmlChart(HtmlChartWidget<HtmlRenderContext> chartWidget,
HtmlRenderContext renderContext) throws RenderException
{
return chartWidget.render(renderContext);
}
/**
* 写看板主题样式
*

View File

@ -0,0 +1,458 @@
/*
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
*/
/**
*
*/
package org.datagear.analysis.support.html;
import java.io.IOException;
import java.io.Reader;
/**
* 文本解析支持类
*
* @author datagear@163.com
*
*/
public class TextParserSupport
{
public TextParserSupport()
{
super();
}
/**
* 读取最多指定字符数的字符串
*
* @param reader
* @param count
* @return
* @throws IOException
*/
public String readString(Reader reader, int count) throws IOException
{
char[] chars = new char[count];
int readed = reader.read(chars);
return new String(chars, 0, readed);
}
/**
* 读取最多指定字符
*
* @param reader
* @param cache
* @param count
* @return
* @throws IOException
*/
public void readChars(Reader reader, StringBuilder cache, int count) throws IOException
{
for (int i = 0; i < count; i++)
{
int c = reader.read();
if (isValidReadChar(c))
appendChar(cache, c);
else
break;
}
}
/**
* 读取到{@code '}或者{@code "}引号的下一个字符。
* <p>
* 下一个字符不会写入{@code quoted}
* </p>
*
* @param in
* @param quoted
* @param quote
* {@code '}或者{@code "}
* @return 引号的下一个字符-1
* @throws IOException
*/
public int readQuoted(Reader in, StringBuilder quoted, int quote) throws IOException
{
int c = -1;
boolean inEscape = false;
while ((c = in.read()) > -1)
{
appendChar(quoted, c);
if (inEscape)
inEscape = false;
else
{
if (c == '\\')
inEscape = true;
else if (c == quote)
break;
}
}
if (c == quote)
c = in.read();
return c;
}
/**
* 读取到{@linkplain Predicate#test(char)}{@code false}
*
* @param in
* @param out
* 读取字符写入缓存{@code null}则不写入
* @param predicate
* @param appendLast
* 结束字符是否也写入缓存
* @return
* @throws IOException
*/
public int readUntil(Reader in, StringBuilder out, Predicate predicate, boolean appendLast) throws IOException
{
int c = -1;
while ((c = in.read()) > -1)
{
if (predicate.test(c))
appendCharIfNotNull(out, c);
else
{
if (appendLast)
appendCharIfNotNull(out, c);
break;
}
}
return c;
}
/**
* 跳过空格或者注释
*
* @param in
* @param out
* 读取字符写入缓存{@code null}则不写入
* @param appendLast
* 结束字符是否也写入缓存
* @return 非空格或注释的内容空字符串
* @throws IOException
*/
public String skipWhitespaceOrBlockLineComment(Reader in, StringBuilder out, boolean appendLast) throws IOException
{
int c = skipWhitespace(in, out, false);
if (c == -1)
return new String("");
else if (c == '/')
{
int next = in.read();
boolean isComment = false;
// 行注释
if (next == '/')
{
appendCharIfNotNull(out, c);
appendCharIfNotNull(out, next);
c = skipLineComment(in, out, false);
isComment = true;
}
// 块注释
else if (next == '*')
{
appendCharIfNotNull(out, c);
appendCharIfNotNull(out, next);
c = skipBlockComment(in, out, false);
isComment = true;
}
if (isComment)
{
if (isWhitespace(c))
{
appendCharIfNotNull(out, c);
return skipWhitespaceOrBlockLineComment(in, out, appendLast);
}
else
{
if (appendLast)
appendCharIfNotNull(out, c);
StringBuilder sb = new StringBuilder();
appendChar(sb, c);
return sb.toString();
}
}
else
{
if (appendLast)
appendCharIfNotNull(out, c);
StringBuilder sb = new StringBuilder();
appendChar(sb, c);
if (isValidReadChar(next))
appendChar(sb, next);
return sb.toString();
}
}
else
{
if (appendLast)
appendCharIfNotNull(out, c);
StringBuilder sb = new StringBuilder();
appendChar(sb, c);
return sb.toString();
}
}
/**
* 读取到行注释<code>//</code>结束
*
* @param in
* @param out
* 读取字符写入缓存{@code null}则不写入
* @param appendLast
* 结束字符是否也写入缓存
* @return 注释结束符的下一个字符-1
* @throws IOException
*/
public int skipLineComment(Reader in, StringBuilder out, boolean appendLast) throws IOException
{
int c = -1;
while ((c = in.read()) > -1)
{
appendCharIfNotNull(out, c);
if (c == '\n')
break;
}
if (c == '\n')
{
c = in.read();
if (appendLast)
appendCharIfValid(out, c);
}
return c;
}
/**
* 读取到块注释<code>*</code><code>/</code>结束
*
* @param in
* @param out
* 读取字符写入缓存{@code null}则不写入
* @param appendLast
* 结束字符是否也写入缓存
* @return 注释结束的下一个字符-1
* @throws IOException
*/
public int skipBlockComment(Reader in, StringBuilder out, boolean appendLast) throws IOException
{
int c = -1;
while ((c = in.read()) > -1)
{
appendCharIfNotNull(out, c);
if (c == '/')
{
int len = out.length();
int prev = (len > 1 ? out.charAt(len - 2) : -1);
if (prev == '*')
break;
}
}
if (c == '/')
{
c = in.read();
if (appendLast)
appendCharIfValid(out, c);
}
return c;
}
/**
* 读取到非空格
*
* @param in
* @param out
* 读取字符写入缓存{@code null}则不写入
* @param appendLast
* 结束字符是否也写入缓存
* @return 非空格字符-1
* @throws IOException
*/
public int skipWhitespace(Reader in, StringBuilder out, boolean appendLast) throws IOException
{
int c = -1;
while ((c = in.read()) > -1)
{
if (isWhitespace(c))
appendCharIfNotNull(out, c);
else
{
if (appendLast)
appendCharIfNotNull(out, c);
break;
}
}
return c;
}
/**
* 追加字符
*
* @param sb
* @param c
*/
public void appendChar(StringBuilder sb, int c)
{
sb.appendCodePoint(c);
}
/**
* 追加字符
* <p>
* 如果{@code sb}{@code null}则什么也不做并返回{@code false}
* </p>
*
* @param sb
* @param c
* @return
*/
public boolean appendCharIfNotNull(StringBuilder sb, int c)
{
if (sb == null)
return false;
sb.appendCodePoint(c);
return true;
}
/**
* 追加字符
* <p>
* 如果{@code sb}{@code null}或者{@code c}不是合法字符则什么也不做并返回{@code false}
* </p>
*
* @param sb
* @param c
* @return
*/
public boolean appendCharIfValid(StringBuilder sb, int c)
{
if (sb == null)
return false;
if (!isValidReadChar(c))
return false;
sb.appendCodePoint(c);
return true;
}
/**
* 是否是有效的读取字符
*
* @param c
* @return
*/
public boolean isValidReadChar(int c)
{
return c > -1;
}
/**
* 是否空格字符
*
* @param c
* @return
*/
public boolean isWhitespace(int c)
{
return Character.isWhitespace(c);
}
/**
* 删除末尾字符
*
* @param sb
* @param count
*/
public void deleteTail(StringBuilder sb, int count)
{
int len = sb.length();
sb.delete(len - count, len);
}
/**
* 清除{@linkplain StringBuilder}
*
* @param sb
*/
public void clear(StringBuilder sb)
{
if (sb == null)
return;
sb.delete(0, sb.length());
}
public StringBuilder createStringBuilder()
{
return new StringBuilder();
}
public static interface Predicate
{
/**
* 判断字符是否合法
*
* @param c
* @return
*/
boolean test(int c);
}
public static class WhitespacePredicate implements Predicate
{
@Override
public boolean test(int c)
{
return Character.isWhitespace(c);
}
}
public static class NotWhitespacePredicate implements Predicate
{
@Override
public boolean test(int c)
{
return !Character.isWhitespace(c);
}
}
}

View File

@ -12,12 +12,13 @@ import java.util.Map;
import org.datagear.analysis.ChartDataSet;
import org.datagear.analysis.RenderException;
import org.datagear.util.StringUtil;
import org.datagear.util.i18n.Label;
/**
* 仅渲染指定内容值的{@linkplain HtmlChartPlugin}
* <p>
* 它从{@linkplain HtmlRenderContext}中获取{@linkplain #getValueAttributeName()}的属性值并将其作为图表内容渲染
* 它从{@code chartPropertyValues}中获取{@linkplain #getValueChartPropertyName()}的属性值并将其作为图表内容渲染
* </p>
*
* @author datagear@163.com
@ -25,36 +26,43 @@ import org.datagear.util.i18n.Label;
*/
public class ValueHtmlChartPlugin<T extends HtmlRenderContext> extends HtmlChartPlugin<T>
{
public static final String VALUE_CHART_PROPERTY_NAME = "valueHtmlChartPluginValue";
protected static final StringJsChartRenderer JS_CHART_RENDERER = new StringJsChartRenderer(
"{" + HtmlChartPlugin.HTML_NEW_LINE +
//
" render : function(chart)" + HtmlChartPlugin.HTML_NEW_LINE +
//
" {" + HtmlChartPlugin.HTML_NEW_LINE +
//
" var element = document.getElementById(chart.elementId);" + HtmlChartPlugin.HTML_NEW_LINE +
//
" var propertyValues = (chart.propertyValues || {});" + HtmlChartPlugin.HTML_NEW_LINE +
//
" element.innerHTML=propertyValues['" + VALUE_CHART_PROPERTY_NAME + "'];"
+ HtmlChartPlugin.HTML_NEW_LINE +
//
" }," + HtmlChartPlugin.HTML_NEW_LINE +
//
" update : function(){}" + HtmlChartPlugin.HTML_NEW_LINE +
//
"}");
private String valueChartPropertyName;
public ValueHtmlChartPlugin()
{
super();
}
public ValueHtmlChartPlugin(String id)
public ValueHtmlChartPlugin(String id, String valueChartPropertyName)
{
super(id, new Label("ValueHtmlChartPlugin"), JS_CHART_RENDERER);
super();
super.setId(id);
super.setNameLabel(new Label("ValueHtmlChartPlugin"));
super.setChartRenderer(buildJsChartRenderer(valueChartPropertyName));
this.valueChartPropertyName = valueChartPropertyName;
}
public String getValueChartPropertyName()
{
return valueChartPropertyName;
}
public void setValueChartPropertyName(String valueChartPropertyName)
{
this.valueChartPropertyName = valueChartPropertyName;
super.setChartRenderer(buildJsChartRenderer(valueChartPropertyName));
}
@Override
public JsChartRenderer getChartRenderer()
{
return super.getChartRenderer();
}
@Override
public void setChartRenderer(JsChartRenderer chartRenderer)
{
throw new UnsupportedOperationException();
}
@Override
@ -68,4 +76,27 @@ public class ValueHtmlChartPlugin<T extends HtmlRenderContext> extends HtmlChart
return super.renderChart(renderContext, myChartPropertyValues, chartDataSets);
}
protected StringJsChartRenderer buildJsChartRenderer(String valueChartPropertyName)
{
return new StringJsChartRenderer("{" + HtmlChartPlugin.HTML_NEW_LINE
//
+ " render : function(chart)" + HtmlChartPlugin.HTML_NEW_LINE
//
+ " {" + HtmlChartPlugin.HTML_NEW_LINE +
//
" var element = document.getElementById(chart.elementId);" + HtmlChartPlugin.HTML_NEW_LINE
//
+ " var propertyValues = (chart.propertyValues || {});" + HtmlChartPlugin.HTML_NEW_LINE
//
+ " element.innerHTML=propertyValues['"
+ StringUtil.escapeJavaScriptStringValue(valueChartPropertyName) + "'];" + HtmlChartPlugin.HTML_NEW_LINE
//
+ " }," + HtmlChartPlugin.HTML_NEW_LINE
//
+ " update : function(){}" + HtmlChartPlugin.HTML_NEW_LINE
//
+ "}");
}
}

View File

@ -9,6 +9,7 @@ import java.util.Set;
import org.datagear.analysis.Chart;
import org.datagear.analysis.ChartDataSet;
import org.datagear.analysis.ChartPlugin;
import org.datagear.analysis.ChartProperty;
import org.datagear.analysis.DataSign;
import org.datagear.analysis.PropertyType;
@ -45,24 +46,24 @@ public class JsonChartPluginPropertiesResolverTest
Map<String, Object> properties = jsonChartPluginPropertiesResolver
.resolveChartPluginProperties(jsonInputStream, "UTF-8");
Assert.assertEquals("pie-chart", properties.get(JsonChartPluginPropertiesResolver.CHART_PLUGIN_ID));
Assert.assertEquals("pie-chart", properties.get(ChartPlugin.PROPERTY_ID));
{
Label nameLabel = (Label) properties.get(JsonChartPluginPropertiesResolver.CHART_PLUGIN_NAME_LABEL);
Label nameLabel = (Label) properties.get(ChartPlugin.PROPERTY_NAME_LABEL);
Assert.assertEquals("饼图", nameLabel.getValue());
Assert.assertEquals("pie chart", nameLabel.getValue(Label.toLocale("en")));
Assert.assertEquals("饼图中文", nameLabel.getValue(Label.toLocale("zh")));
}
{
Label descLabel = (Label) properties.get(JsonChartPluginPropertiesResolver.CHART_PLUGIN_DESC_LABEL);
Label descLabel = (Label) properties.get(ChartPlugin.PROPERTY_DESC_LABEL);
Assert.assertEquals("饼图描述", descLabel.getValue());
Assert.assertEquals("pie chart desc", descLabel.getValue(Label.toLocale("en")));
Assert.assertEquals("饼图描述中文", descLabel.getValue(Label.toLocale("zh")));
}
{
Label manualLabel = (Label) properties.get(JsonChartPluginPropertiesResolver.CHART_PLUGIN_MANUAL_LABEL);
Label manualLabel = (Label) properties.get(ChartPlugin.PROPERTY_MANUAL_LABEL);
Assert.assertEquals("饼图指南", manualLabel.getValue());
Assert.assertEquals("pie chart manual", manualLabel.getValue(Label.toLocale("en")));
Assert.assertEquals("饼图指南中文", manualLabel.getValue(Label.toLocale("zh")));
@ -71,7 +72,7 @@ public class JsonChartPluginPropertiesResolverTest
{
@SuppressWarnings("unchecked")
Map<RenderStyle, LocationIcon> icons = (Map<RenderStyle, LocationIcon>) properties
.get(JsonChartPluginPropertiesResolver.CHART_PLUGIN_ICONS);
.get(ChartPlugin.PROPERTY_ICONS);
Assert.assertEquals("icon-0.png", icons.get(RenderStyle.LIGHT).getLocation());
Assert.assertEquals("icon-1.png", icons.get(RenderStyle.DARK).getLocation());
@ -79,7 +80,7 @@ public class JsonChartPluginPropertiesResolverTest
@SuppressWarnings("unchecked")
List<ChartProperty> chartProperties = (List<ChartProperty>) properties
.get(JsonChartPluginPropertiesResolver.CHART_PLUGIN_CHART_PROPERTIES);
.get(ChartPlugin.PROPERTY_CHART_PROPERTIES);
{
ChartProperty chartProperty = chartProperties.get(0);
@ -134,8 +135,7 @@ public class JsonChartPluginPropertiesResolverTest
}
@SuppressWarnings("unchecked")
List<DataSign> dataSigns = (List<DataSign>) properties
.get(JsonChartPluginPropertiesResolver.CHART_PLUGIN_DATA_SIGNS);
List<DataSign> dataSigns = (List<DataSign>) properties.get(ChartPlugin.PROPERTY_DATA_SIGNS);
{
DataSign dataSign = dataSigns.get(0);

View File

@ -0,0 +1,153 @@
/*
* Copyright (c) 2018 datagear.tech. All Rights Reserved.
*/
/**
*
*/
package org.datagear.analysis.support.html;
import java.io.IOException;
import org.datagear.analysis.support.html.HtmlChartPluginJsDefResolver.JsDefContent;
import org.junit.Assert;
import org.junit.Test;
/**
* {@linkplain HtmlChartPluginJsDefResolver}单元测试类
*
* @author datagear@163.com
*
*/
public class HtmlChartPluginJsDefResolverTest
{
private HtmlChartPluginJsDefResolver resolver = new HtmlChartPluginJsDefResolver();
@Test
public void resolveTest() throws IOException
{
// 无引号
{
String text = "{a: 'a', b : 'b', chartRender:{render:function() {}}}";
JsDefContent content = resolver.resolve(text);
Assert.assertEquals("{a: 'a', b : 'b', chartRender:{}}", content.getPluginJson());
Assert.assertEquals("{render:function() {}}", content.getPluginChartRender());
}
{
String text = "{a: 'a', chartRender:{render:function() {}}, b : 'b'}";
JsDefContent content = resolver.resolve(text);
Assert.assertEquals("{a: 'a', chartRender:{}, b : 'b'}", content.getPluginJson());
Assert.assertEquals("{render:function() {}}", content.getPluginChartRender());
}
{
String text = "{chartRender:{render:function() {}}, a: 'a', b : 'b'}";
JsDefContent content = resolver.resolve(text);
Assert.assertEquals("{chartRender:{}, a: 'a', b : 'b'}", content.getPluginJson());
Assert.assertEquals("{render:function() {}}", content.getPluginChartRender());
}
// 单引号
{
String text = "{a: 'a', b : 'b', 'chartRender':{render:function() {}}}";
JsDefContent content = resolver.resolve(text);
Assert.assertEquals("{a: 'a', b : 'b', 'chartRender':{}}", content.getPluginJson());
Assert.assertEquals("{render:function() {}}", content.getPluginChartRender());
}
{
String text = "{a: 'a', 'chartRender':{render:function() {}}, b : 'b'}";
JsDefContent content = resolver.resolve(text);
Assert.assertEquals("{a: 'a', 'chartRender':{}, b : 'b'}", content.getPluginJson());
Assert.assertEquals("{render:function() {}}", content.getPluginChartRender());
}
{
String text = "{'chartRender':{render:function() {}}, a: 'a', b : 'b'}";
JsDefContent content = resolver.resolve(text);
Assert.assertEquals("{'chartRender':{}, a: 'a', b : 'b'}", content.getPluginJson());
Assert.assertEquals("{render:function() {}}", content.getPluginChartRender());
}
// 双引号
{
String text = "{a: 'a', b : 'b', \"chartRender\":{render:function() {}}}";
JsDefContent content = resolver.resolve(text);
Assert.assertEquals("{a: 'a', b : 'b', \"chartRender\":{}}", content.getPluginJson());
Assert.assertEquals("{render:function() {}}", content.getPluginChartRender());
}
{
String text = "{a: 'a', \"chartRender\":{render:function() {}}, b : 'b'}";
JsDefContent content = resolver.resolve(text);
Assert.assertEquals("{a: 'a', \"chartRender\":{}, b : 'b'}", content.getPluginJson());
Assert.assertEquals("{render:function() {}}", content.getPluginChartRender());
}
{
String text = "{\"chartRender\":{render:function() {}}, a: 'a', b : 'b'}";
JsDefContent content = resolver.resolve(text);
Assert.assertEquals("{\"chartRender\":{}, a: 'a', b : 'b'}", content.getPluginJson());
Assert.assertEquals("{render:function() {}}", content.getPluginChartRender());
}
// 带注释
{
String text = "{a: 'a', b : 'b', /*sdf*/chartRender/*sdf*/:{render:function() {}}}";
JsDefContent content = resolver.resolve(text);
Assert.assertEquals("{a: 'a', b : 'b', /*sdf*/chartRender/*sdf*/:{}}", content.getPluginJson());
Assert.assertEquals("{render:function() {}}", content.getPluginChartRender());
}
{
String text = "{a: 'a', b : 'b', /*sdf*/ chartRender /*sdf*/ :{render:function() {}}}";
JsDefContent content = resolver.resolve(text);
Assert.assertEquals("{a: 'a', b : 'b', /*sdf*/ chartRender /*sdf*/ :{}}", content.getPluginJson());
Assert.assertEquals("{render:function() {}}", content.getPluginChartRender());
}
{
String text = "{a: 'a', b : 'b', //sdf\nchartRender//sdf\n:{render:function() {}}}";
JsDefContent content = resolver.resolve(text);
Assert.assertEquals("{a: 'a', b : 'b', //sdf\nchartRender//sdf\n:{}}", content.getPluginJson());
Assert.assertEquals("{render:function() {}}", content.getPluginChartRender());
}
{
String text = "{a: 'a', b : 'b', //sdf\n chartRender //sdf\n :{render:function() {}}}";
JsDefContent content = resolver.resolve(text);
Assert.assertEquals("{a: 'a', b : 'b', //sdf\n chartRender //sdf\n :{}}", content.getPluginJson());
Assert.assertEquals("{render:function() {}}", content.getPluginChartRender());
}
// 复杂内容
{
String text = "{a: 'a', b : 'b', //sdf\n chartRender //sdf\n :{render:function() { if(a==b) {}; /*sdf*/ \n\n //sdf\n var a= {}; }}}";
JsDefContent content = resolver.resolve(text);
Assert.assertEquals("{a: 'a', b : 'b', //sdf\n chartRender //sdf\n :{}}", content.getPluginJson());
Assert.assertEquals("{render:function() { if(a==b) {}; /*sdf*/ \n\n //sdf\n var a= {}; }}",
content.getPluginChartRender());
}
}
}

View File

@ -7,15 +7,12 @@
*/
package org.datagear.analysis.support.html;
import java.io.InputStream;
import java.io.File;
import java.io.StringWriter;
import java.util.Locale;
import java.util.Map;
import org.datagear.analysis.ChartDataSet;
import org.datagear.analysis.RenderStyle;
import org.datagear.analysis.support.JsonChartPluginPropertiesResolver;
import org.datagear.analysis.support.LocationResource;
import org.datagear.analysis.support.SimpleDashboardThemeSource;
import org.datagear.analysis.support.html.HtmlRenderContext.WebContext;
import org.junit.Assert;
@ -27,8 +24,6 @@ import org.junit.Test;
*/
public class HtmlChartPluginTest
{
private static JsonChartPluginPropertiesResolver jsonChartPluginPropertiesResolver = new JsonChartPluginPropertiesResolver();
public HtmlChartPluginTest() throws Throwable
{
super();
@ -74,16 +69,11 @@ public class HtmlChartPluginTest
public static HtmlChartPlugin<HtmlRenderContext> createHtmlChartPlugin() throws Exception
{
InputStream jsonInputStream = HtmlChartPluginTest.class.getClassLoader()
.getResourceAsStream("org/datagear/analysis/support/html/HtmlChartPlugin.config.json");
Map<String, Object> properties = jsonChartPluginPropertiesResolver.resolveChartPluginProperties(jsonInputStream,
"UTF-8");
File directory = new File("src/test/resources/org/datagear/analysis/support/html/HtmlChartPluginTest");
HtmlChartPlugin<HtmlRenderContext> htmlChartPlugin = new HtmlChartPlugin<HtmlRenderContext>();
jsonChartPluginPropertiesResolver.setChartPluginProperties(htmlChartPlugin, properties);
htmlChartPlugin.setJsChartRenderer(new LocationJsChartRenderer(
LocationResource.toClasspathLocation("org/datagear/analysis/support/html/HtmlChartPlugin.chart.js")));
@SuppressWarnings("unchecked")
HtmlChartPlugin<HtmlRenderContext> htmlChartPlugin = (HtmlChartPlugin<HtmlRenderContext>) new HtmlChartPluginLoader()
.load(directory);
return htmlChartPlugin;
}

View File

@ -1,24 +0,0 @@
{
render: function(chart)
{
var element = document.getElementById(chart.elementId);
var innerHtml = "my chart";
if(chart.renderContext && chart.renderContext.attributes && chart.renderContext.attributes.chartTheme)
{
var graphColors = (chart.renderContext.attributes.chartTheme.graphColors || []);
for(var i=0; i< graphColors.length; i++)
{
innerHtml +="<div style='background-color:"+graphColors[i]+";'>&nbsp;</div>";
}
}
element.innerHTML = innerHtml;
},
update: function(chart, results)
{
var element = document.getElementById(chart.elementId);
element.innerHTML += "<div>update</div>";
}
}

View File

@ -1,12 +0,0 @@
{
id : 'pie-chart',
nameLabel :
{
value : '',
localeValues :
{
'en' : 'pie chart',
'zh' : ''
}
}
}

View File

@ -1,6 +0,0 @@
(function(chart)
{
chart.render = function(){};
chart.update = function(dataSets){};
})
($CHART);

View File

@ -1,6 +0,0 @@
(function(chart)
{
chart.render = function(){};
chart.update = function(dataSets){};
})
($CHART);

View File

@ -0,0 +1,37 @@
{
id : 'pie-chart',
nameLabel :
{
value : '饼图',
localeValues :
{
'en' : 'pie chart',
'zh' : '饼图中文'
}
},
chartRender:
{
render: function(chart)
{
var element = document.getElementById(chart.elementId);
var innerHtml = "my chart";
if(chart.renderContext && chart.renderContext.attributes && chart.renderContext.attributes.chartTheme)
{
var graphColors = (chart.renderContext.attributes.chartTheme.graphColors || []);
for(var i=0; i< graphColors.length; i++)
{
innerHtml +="<div style='background-color:"+graphColors[i]+";'>&nbsp;</div>";
}
}
element.innerHTML = innerHtml;
},
update: function(chart, results)
{
var element = document.getElementById(chart.elementId);
element.innerHTML += "<div>update</div>";
}
}
}

View File

@ -10,7 +10,7 @@ var dashboardRenderer =
for(var i=0; i<dashboard.charts.length; i++)
{
var chart = dashboard.charts[i];
chart.plugin.jsChartRender.render(chart);
chart.plugin.chartRender.render(chart);
}
}
};

View File

@ -18,6 +18,9 @@ public class Label implements Serializable
{
private static final long serialVersionUID = 1L;
public static final String PROPERTY_VALUE = "value";
public static final String PROPERTY_LOCALE_VALUES = "localeValues";
private String value;
private Map<Locale, String> localeValues;

View File

@ -1,43 +0,0 @@
{
/**
* 依赖
* chartUtil
* echarts
*/
render: function(chart)
{
chart.echarts = {};
var options =
{
xAxis: {
type: 'category',
boundaryGap: false,
data: []
},
yAxis: {
type: 'value'
},
series: [{
data: [],
type: 'bar'
}]
};
chart.echarts.chart = chartUtil.echarts.init(chart, options);
},
update: function(chart, results)
{
var chartDataSet = chartUtil.firstChartDataSet(chart);
var result = chartUtil.firstResult(results);
var xp = chartUtil.dataSetPropertyOfSign(chartDataSet, "x-value");
var yp = chartUtil.dataSetPropertyOfSign(chartDataSet, "y-value");
var xdatas = chartUtil.dataPropertyValues(result, xp);
var ydatas = chartUtil.dataPropertyValues(result, yp);
var options = { xAxis : { data : xdatas }, series : [ { data : ydatas } ] };
chart.echarts.chart.setOption(options);
}
}

View File

@ -0,0 +1,56 @@
{
id : 'datagear-chart-bar',
nameLabel : '柱状图',
descLabel : '柱状图',
dataSigns :
[
{ name : "x-value", nameLabel : "横坐标", occurRequired: true, occurMultiple: false },
{ name : "y-value", nameLabel : "纵坐标", occurRequired: true, occurMultiple: true }
],
version: "0.1.0",
order : 1,
chartRender:
{
/**
* 依赖
* chartUtil
* echarts
*/
render: function(chart)
{
chart.echarts = {};
var options =
{
xAxis: {
type: 'category',
boundaryGap: false,
data: []
},
yAxis: {
type: 'value'
},
series: [{
data: [],
type: 'bar'
}]
};
chart.echarts.chart = chartUtil.echarts.init(chart, options);
},
update: function(chart, results)
{
var chartDataSet = chartUtil.firstChartDataSet(chart);
var result = chartUtil.firstResult(results);
var xp = chartUtil.dataSetPropertyOfSign(chartDataSet, "x-value");
var yp = chartUtil.dataSetPropertyOfSign(chartDataSet, "y-value");
var xdatas = chartUtil.dataPropertyValues(result, xp);
var ydatas = chartUtil.dataPropertyValues(result, yp);
var options = { xAxis : { data : xdatas }, series : [ { data : ydatas } ] };
chart.echarts.chart.setOption(options);
}
}
}

View File

@ -1,12 +0,0 @@
{
id : 'datagear-chart-bar',
nameLabel : '',
descLabel : '',
dataSigns :
[
{ name : "x-value", nameLabel : "横坐标", occurRequired: true, occurMultiple: false },
{ name : "y-value", nameLabel : "纵坐标", occurRequired: true, occurMultiple: true }
],
version: "0.1.0",
order : 1
}

View File

@ -1,43 +0,0 @@
{
/**
* 依赖
* chartUtil
* echarts
*/
render: function(chart)
{
chart.echarts = {};
var options =
{
xAxis: {
type: 'category',
boundaryGap: false,
data: []
},
yAxis: {
type: 'value',
},
series: [{
data: [],
type: 'line'
}]
};
chart.echarts.chart = chartUtil.echarts.init(chart, options);
},
update: function(chart, results)
{
var chartDataSet = chartUtil.firstChartDataSet(chart);
var result = chartUtil.firstResult(results);
var xp = chartUtil.dataSetPropertyOfSign(chartDataSet, "x-value");
var yp = chartUtil.dataSetPropertyOfSign(chartDataSet, "y-value");
var xdatas = chartUtil.dataPropertyValues(result, xp);
var ydatas = chartUtil.dataPropertyValues(result, yp);
var options = { xAxis : { data : xdatas }, series : [ { data : ydatas } ] };
chart.echarts.chart.setOption(options);
}
}

View File

@ -0,0 +1,56 @@
{
id : 'datagear-chart-line',
nameLabel : '折线图',
descLabel : '折线图',
dataSigns :
[
{ name : "x-value", nameLabel : "横坐标", occurRequired: true, occurMultiple: false },
{ name : "y-value", nameLabel : "纵坐标", occurRequired: true, occurMultiple: true }
],
version: "0.1.0",
order : 0,
chartRender:
{
/**
* 依赖
* chartUtil
* echarts
*/
render: function(chart)
{
chart.echarts = {};
var options =
{
xAxis: {
type: 'category',
boundaryGap: false,
data: []
},
yAxis: {
type: 'value',
},
series: [{
data: [],
type: 'line'
}]
};
chart.echarts.chart = chartUtil.echarts.init(chart, options);
},
update: function(chart, results)
{
var chartDataSet = chartUtil.firstChartDataSet(chart);
var result = chartUtil.firstResult(results);
var xp = chartUtil.dataSetPropertyOfSign(chartDataSet, "x-value");
var yp = chartUtil.dataSetPropertyOfSign(chartDataSet, "y-value");
var xdatas = chartUtil.dataPropertyValues(result, xp);
var ydatas = chartUtil.dataPropertyValues(result, yp);
var options = { xAxis : { data : xdatas }, series : [ { data : ydatas } ] };
chart.echarts.chart.setOption(options);
}
}
}

View File

@ -1,12 +0,0 @@
{
id : 'datagear-chart-line',
nameLabel : '线',
descLabel : '线',
dataSigns :
[
{ name : "x-value", nameLabel : "横坐标", occurRequired: true, occurMultiple: false },
{ name : "y-value", nameLabel : "纵坐标", occurRequired: true, occurMultiple: true }
],
version: "0.1.0",
order : 0
}

View File

@ -1,60 +0,0 @@
{
/**
* 依赖
* chartUtil
* echarts
*/
render: function(chart)
{
chart.echarts = {};
var options =
{
tooltip:
{
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend:
{
orient: 'vertical',
left: 'left'
},
series:
[
{
name : "",
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
data: [],
emphasis:
{
itemStyle:
{
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: chartUtil.chartTheme(chart).envLeastColor
}
}
}
]
};
chart.echarts.chart = chartUtil.echarts.init(chart, options);
},
update: function(chart, results)
{
var chartDataSet = chartUtil.firstChartDataSet(chart);
var result = chartUtil.firstResult(results);
var np = chartUtil.dataSetPropertyOfSign(chartDataSet, "name");
var vp = chartUtil.dataSetPropertyOfSign(chartDataSet, "value");
var legendData = chartUtil.dataPropertyValues(result, np);
var datas = chartUtil.dataNameValueObjects(result, np, vp);
var options = { legend : { data : legendData }, series : [ { name : chartUtil.propertyValueName(chart), data : datas } ] };
chart.echarts.chart.setOption(options);
}
}

View File

@ -0,0 +1,73 @@
{
id : 'datagear-chart-pie',
nameLabel : '饼图',
descLabel : '饼图',
dataSigns :
[
{ name : "name", nameLabel : "名称", occurRequired: true, occurMultiple: false },
{ name : "value", nameLabel : "数值", occurRequired: true, occurMultiple: true }
],
version: "0.1.0",
order : 2,
chartRender:
{
/**
* 依赖
* chartUtil
* echarts
*/
render: function(chart)
{
chart.echarts = {};
var options =
{
tooltip:
{
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend:
{
orient: 'vertical',
left: 'left'
},
series:
[
{
name : "",
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
data: [],
emphasis:
{
itemStyle:
{
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: chartUtil.chartTheme(chart).envLeastColor
}
}
}
]
};
chart.echarts.chart = chartUtil.echarts.init(chart, options);
},
update: function(chart, results)
{
var chartDataSet = chartUtil.firstChartDataSet(chart);
var result = chartUtil.firstResult(results);
var np = chartUtil.dataSetPropertyOfSign(chartDataSet, "name");
var vp = chartUtil.dataSetPropertyOfSign(chartDataSet, "value");
var legendData = chartUtil.dataPropertyValues(result, np);
var datas = chartUtil.dataNameValueObjects(result, np, vp);
var options = { legend : { data : legendData }, series : [ { name : chartUtil.propertyValueName(chart), data : datas } ] };
chart.echarts.chart.setOption(options);
}
}
}

View File

@ -1,12 +0,0 @@
{
id : 'datagear-chart-pie',
nameLabel : '',
descLabel : '',
dataSigns :
[
{ name : "name", nameLabel : "名称", occurRequired: true, occurMultiple: false },
{ name : "value", nameLabel : "数值", occurRequired: true, occurMultiple: true }
],
version: "0.1.0",
order : 2
}

View File

@ -33,7 +33,7 @@
try
{
chart.plugin.jsChartRender.render(chart);
chart.plugin.chartRender.render(chart);
}
catch(e)
{
@ -180,7 +180,7 @@
doUpdate=this.listener.onUpdateChart(dashboard, chart, results, this);
if(doUpdate != false)
chart.plugin.jsChartRender.update(chart, results);
chart.plugin.chartRender.update(chart, results);
};
renderer.handleError = function(e)