forked from github/dataease
commit
d2a5045784
@ -5,11 +5,11 @@ import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
*
|
||||
* 组件图表表
|
||||
* </p>
|
||||
*
|
||||
* @author fit2cloud
|
||||
* @since 2023-08-20
|
||||
* @since 2024-05-07
|
||||
*/
|
||||
@TableName("core_chart_view")
|
||||
public class CoreChartView implements Serializable {
|
||||
@ -191,10 +191,21 @@ public class CoreChartView implements Serializable {
|
||||
*/
|
||||
private Boolean jumpActive;
|
||||
|
||||
/**
|
||||
* 复制来源
|
||||
*/
|
||||
private Long copyFrom;
|
||||
|
||||
/**
|
||||
* 复制ID
|
||||
*/
|
||||
private Long copyId;
|
||||
|
||||
/**
|
||||
* 区间条形图开启时间纬度开启聚合
|
||||
*/
|
||||
private Boolean aggregate;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
@ -491,6 +502,14 @@ public class CoreChartView implements Serializable {
|
||||
this.copyId = copyId;
|
||||
}
|
||||
|
||||
public Boolean getAggregate() {
|
||||
return aggregate;
|
||||
}
|
||||
|
||||
public void setAggregate(Boolean aggregate) {
|
||||
this.aggregate = aggregate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CoreChartView{" +
|
||||
@ -531,6 +550,7 @@ public class CoreChartView implements Serializable {
|
||||
", jumpActive = " + jumpActive +
|
||||
", copyFrom = " + copyFrom +
|
||||
", copyId = " + copyId +
|
||||
", aggregate = " + aggregate +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
|
@ -6,11 +6,11 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Mapper 接口
|
||||
* 组件图表表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author fit2cloud
|
||||
* @since 2023-08-20
|
||||
* @since 2024-05-07
|
||||
*/
|
||||
@Mapper
|
||||
public interface CoreChartViewMapper extends BaseMapper<CoreChartView> {
|
||||
|
@ -34,6 +34,7 @@ import io.dataease.utils.JsonUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
@ -127,6 +128,35 @@ public class ChartDataManage {
|
||||
List<ChartViewFieldDTO> yAxisExt = new ArrayList<>(view.getYAxisExt());
|
||||
yAxis.addAll(yAxisExt);
|
||||
}
|
||||
boolean skipBarRange = false;
|
||||
boolean barRangeDate = false;
|
||||
if (StringUtils.equalsIgnoreCase(view.getType(), "bar-range")) { //针对区间条形图进行处理
|
||||
yAxis.clear();
|
||||
if (CollectionUtils.isNotEmpty(view.getYAxis()) && CollectionUtils.isNotEmpty(view.getYAxisExt())) {
|
||||
ChartViewFieldDTO axis1 = view.getYAxis().get(0);
|
||||
ChartViewFieldDTO axis2 = view.getYAxisExt().get(0);
|
||||
|
||||
if (StringUtils.equalsIgnoreCase(axis1.getGroupType(), "q") && StringUtils.equalsIgnoreCase(axis2.getGroupType(), "q")) {
|
||||
yAxis.add(axis1);
|
||||
yAxis.add(axis2);
|
||||
} else if (StringUtils.equalsIgnoreCase(axis1.getGroupType(), "d") && axis1.getDeType() == 1 && StringUtils.equalsIgnoreCase(axis2.getGroupType(), "d") && axis2.getDeType() == 1) {
|
||||
barRangeDate = true;
|
||||
if (BooleanUtils.isTrue(view.getAggregate())) {
|
||||
axis1.setSummary("min");
|
||||
axis2.setSummary("max");
|
||||
yAxis.add(axis1);
|
||||
yAxis.add(axis2);
|
||||
} else {
|
||||
xAxis.add(axis1);
|
||||
xAxis.add(axis2);
|
||||
}
|
||||
} else {
|
||||
skipBarRange = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
List<ChartViewFieldDTO> extStack = new ArrayList<>(view.getExtStack());
|
||||
List<ChartViewFieldDTO> extBubble = new ArrayList<>(view.getExtBubble());
|
||||
if (ObjectUtils.isNotEmpty(view.getExtLabel()) && enableExtData(view.getType())) {
|
||||
@ -753,6 +783,8 @@ public class ChartDataManage {
|
||||
mapChart = ChartDataBuild.transLabelChartData(xAxis, yAxis, view, data, isDrill);
|
||||
} else if (StringUtils.containsIgnoreCase(view.getType(), "quadrant")) {
|
||||
mapChart = ChartDataBuild.transQuadrantDataAntV(xAxis, yAxis, view, data, extBubble, isDrill);
|
||||
} else if (StringUtils.equalsIgnoreCase(view.getType(), "bar-range")) {
|
||||
mapChart = ChartDataBuild.transTimeBarDataAntV(skipBarRange, barRangeDate, xAxisBase, xAxis, yAxis, view, data, isDrill);
|
||||
} else {
|
||||
mapChart = ChartDataBuild.transChartDataAntV(xAxis, yAxis, view, data, isDrill);
|
||||
}
|
||||
|
@ -1,13 +1,17 @@
|
||||
package io.dataease.chart.utils;
|
||||
|
||||
import io.dataease.api.chart.dto.*;
|
||||
import io.dataease.i18n.Lang;
|
||||
import io.dataease.i18n.Translator;
|
||||
import io.dataease.utils.IDUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -1323,4 +1327,268 @@ public class ChartDataBuild {
|
||||
return map;
|
||||
}
|
||||
|
||||
public static Map<String, Object> transTimeBarDataAntV(boolean skipBarRange, boolean isDate, List<ChartViewFieldDTO> xAxisBase, List<ChartViewFieldDTO> xAxis, List<ChartViewFieldDTO> yAxis, ChartViewDTO view, List<String[]> data, boolean isDrill) {
|
||||
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
if (skipBarRange) {
|
||||
map.put("data", new ArrayList<>());
|
||||
return map;
|
||||
}
|
||||
|
||||
List<Date> dates = new ArrayList<>();
|
||||
List<BigDecimal> numbers = new ArrayList<>();
|
||||
|
||||
ChartViewFieldDTO dateAxis1 = null;
|
||||
|
||||
SimpleDateFormat sdf = null;
|
||||
if (isDate) {
|
||||
if (BooleanUtils.isTrue(view.getAggregate())) {
|
||||
dateAxis1 = yAxis.get(0);
|
||||
} else {
|
||||
dateAxis1 = xAxis.get(xAxisBase.size());
|
||||
}
|
||||
sdf = new SimpleDateFormat(getDateFormat(dateAxis1.getDateStyle(), dateAxis1.getDatePattern()));
|
||||
}
|
||||
|
||||
List<Object> dataList = new ArrayList<>();
|
||||
for (int i1 = 0; i1 < data.size(); i1++) {
|
||||
String[] row = data.get(i1);
|
||||
|
||||
StringBuilder xField = new StringBuilder();
|
||||
if (isDrill) {
|
||||
xField.append(row[xAxis.size() - 1]);
|
||||
} else {
|
||||
for (int i = 0; i < xAxisBase.size(); i++) {
|
||||
if (i == xAxisBase.size() - 1) {
|
||||
xField.append(row[i]);
|
||||
} else {
|
||||
xField.append(row[i]).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Map<String, Object> obj = new HashMap<>();
|
||||
obj.put("field", xField.toString());
|
||||
obj.put("category", xField.toString());
|
||||
|
||||
List<ChartDimensionDTO> dimensionList = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < xAxisBase.size(); i++) {
|
||||
ChartDimensionDTO chartDimensionDTO = new ChartDimensionDTO();
|
||||
chartDimensionDTO.setId(xAxis.get(i).getId());
|
||||
chartDimensionDTO.setValue(row[i]);
|
||||
dimensionList.add(chartDimensionDTO);
|
||||
}
|
||||
if (isDrill) {
|
||||
int index = xAxis.size() - 1;
|
||||
ChartDimensionDTO chartDimensionDTO = new ChartDimensionDTO();
|
||||
chartDimensionDTO.setId(xAxis.get(index).getId());
|
||||
chartDimensionDTO.setValue(row[index]);
|
||||
dimensionList.add(chartDimensionDTO);
|
||||
}
|
||||
obj.put("dimensionList", dimensionList);
|
||||
|
||||
|
||||
List<Object> values = new ArrayList<>();
|
||||
|
||||
if (row[xAxisBase.size()] == null || row[xAxisBase.size() + 1] == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isDate) {
|
||||
int index;
|
||||
if (BooleanUtils.isTrue(view.getAggregate())) {
|
||||
index = xAxis.size();
|
||||
} else {
|
||||
index = xAxisBase.size();
|
||||
}
|
||||
|
||||
values.add(row[index]);
|
||||
values.add(row[index + 1]);
|
||||
obj.put("values", values);
|
||||
Date date1 = null, date2 = null;
|
||||
try {
|
||||
date1 = sdf.parse(row[index]);
|
||||
if (date1 != null) {
|
||||
dates.add(date1);
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
try {
|
||||
date2 = sdf.parse(row[index + 1]);
|
||||
if (date2 != null) {
|
||||
dates.add(date2);
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
//间隔时间
|
||||
obj.put("gap", getTimeGap(date1, date2, dateAxis1.getDateStyle()));
|
||||
|
||||
} else {
|
||||
values.add(new BigDecimal(row[xAxis.size()]));
|
||||
values.add(new BigDecimal(row[xAxis.size() + 1]));
|
||||
obj.put("values", values);
|
||||
|
||||
numbers.add(new BigDecimal(row[xAxis.size()]));
|
||||
numbers.add(new BigDecimal(row[xAxis.size() + 1]));
|
||||
|
||||
//间隔差
|
||||
obj.put("gap", new BigDecimal(row[xAxis.size() + 1]).subtract(new BigDecimal(row[xAxis.size()])));
|
||||
}
|
||||
|
||||
dataList.add(obj);
|
||||
}
|
||||
|
||||
if (isDate) {
|
||||
Date minDate = dates.stream().min(Date::compareTo).orElse(null);
|
||||
if (minDate != null) {
|
||||
map.put("minTime", sdf.format(minDate));
|
||||
}
|
||||
Date maxDate = dates.stream().max(Date::compareTo).orElse(null);
|
||||
if (maxDate != null) {
|
||||
map.put("maxTime", sdf.format(maxDate));
|
||||
}
|
||||
} else {
|
||||
map.put("min", numbers.stream().min(BigDecimal::compareTo).orElse(null));
|
||||
map.put("max", numbers.stream().max(BigDecimal::compareTo).orElse(null));
|
||||
}
|
||||
|
||||
map.put("isDate", isDate);
|
||||
map.put("data", dataList);
|
||||
return map;
|
||||
|
||||
}
|
||||
|
||||
private static String getDateFormat(String dateStyle, String datePattern) {
|
||||
String split;
|
||||
if (StringUtils.equalsIgnoreCase(datePattern, "date_split")) {
|
||||
split = "/";
|
||||
} else {
|
||||
split = "-";
|
||||
}
|
||||
switch (dateStyle) {
|
||||
case "y":
|
||||
return "yyyy";
|
||||
case "y_M":
|
||||
return "yyyy" + split + "MM";
|
||||
case "y_M_d":
|
||||
return "yyyy" + split + "MM" + split + "dd";
|
||||
case "H_m_s":
|
||||
return "HH:mm:ss";
|
||||
case "y_M_d_H":
|
||||
return "yyyy" + split + "MM" + split + "dd" + " HH";
|
||||
case "y_M_d_H_m":
|
||||
return "yyyy" + split + "MM" + split + "dd" + " HH:mm";
|
||||
case "y_M_d_H_m_s":
|
||||
return "yyyy" + split + "MM" + split + "dd" + " HH:mm:ss";
|
||||
default:
|
||||
return "yyyy-MM-dd HH:mm:ss";
|
||||
}
|
||||
}
|
||||
|
||||
private static String getTimeGap(Date from, Date to, String dateStyle) {
|
||||
if (from == null || to == null) {
|
||||
return "";
|
||||
}
|
||||
Calendar fromCalender = Calendar.getInstance();
|
||||
fromCalender.setTime(from);
|
||||
|
||||
Calendar toCalender = Calendar.getInstance();
|
||||
toCalender.setTime(to);
|
||||
|
||||
long yearGap = 0;
|
||||
long monthGap = 0;
|
||||
long dayGap = (toCalender.getTimeInMillis() - fromCalender.getTimeInMillis()) / (1000 * 3600 * 24);
|
||||
long hourGap = ((toCalender.getTimeInMillis() - fromCalender.getTimeInMillis()) / (1000 * 3600)) % 24;
|
||||
long minuteGap = ((toCalender.getTimeInMillis() - fromCalender.getTimeInMillis()) / (1000 * 60)) % 60;
|
||||
long secondGap = ((toCalender.getTimeInMillis() - fromCalender.getTimeInMillis()) / 1000) % 60;
|
||||
|
||||
String language = "zh-CN"; //国际化
|
||||
Lang lang = Lang.getLangWithoutDefault(language);
|
||||
boolean isEnUs = Lang.en_US.equals(lang);
|
||||
String splitter = isEnUs ? " " : "";
|
||||
|
||||
String yearGapStr = "";
|
||||
String monthGapStr = "";
|
||||
|
||||
String dayGapStr = "";
|
||||
if (dayGap != 0) {
|
||||
dayGapStr = dayGap + splitter + Translator.get("i18n_day") + (isEnUs && dayGap != 1 ? "s" : "");
|
||||
}
|
||||
String hourGapStr = "";
|
||||
if (hourGap != 0) {
|
||||
hourGapStr = hourGap + splitter + Translator.get("i18n_hour") + (isEnUs && hourGap != 1 ? "s" : "");
|
||||
}
|
||||
String minuteGapStr = "";
|
||||
if (minuteGap != 0) {
|
||||
minuteGapStr = minuteGap + splitter + Translator.get("i18n_minute") + (isEnUs && minuteGap != 1 ? "s" : "");
|
||||
}
|
||||
String secondGapStr = "";
|
||||
if (secondGap != 0) {
|
||||
secondGapStr = secondGap + splitter + Translator.get("i18n_second") + (isEnUs && secondGap != 1 ? "s" : "");
|
||||
}
|
||||
|
||||
List<String> list = new ArrayList<>();
|
||||
|
||||
switch (dateStyle) {
|
||||
case "y":
|
||||
yearGap = toCalender.get(Calendar.YEAR) - fromCalender.get(Calendar.YEAR);
|
||||
yearGapStr = yearGap == 0 ? "" : (yearGap + splitter + Translator.get("i18n_year") + (isEnUs && yearGap != 1 ? "s" : ""));
|
||||
return yearGapStr;
|
||||
case "y_M":
|
||||
yearGap = ((toCalender.get(Calendar.YEAR) - fromCalender.get(Calendar.YEAR)) * 12L + (toCalender.get(Calendar.MONTH) - fromCalender.get(Calendar.MONTH))) / 12;
|
||||
monthGap = ((toCalender.get(Calendar.YEAR) - fromCalender.get(Calendar.YEAR)) * 12L + (toCalender.get(Calendar.MONTH) - fromCalender.get(Calendar.MONTH))) % 12;
|
||||
|
||||
yearGapStr = yearGap == 0 ? "" : (yearGap + splitter + Translator.get("i18n_year") + (isEnUs && yearGap != 1 ? "s" : ""));
|
||||
monthGapStr = monthGap == 0 ? "" : (monthGap + splitter + Translator.get("i18n_month") + (isEnUs && monthGap != 1 ? "s" : ""));
|
||||
|
||||
if (!yearGapStr.isEmpty()) {
|
||||
list.add(yearGapStr);
|
||||
}
|
||||
if (!monthGapStr.isEmpty()) {
|
||||
list.add(monthGapStr);
|
||||
}
|
||||
return StringUtils.join(list, splitter);
|
||||
case "y_M_d":
|
||||
return dayGapStr;
|
||||
case "y_M_d_H":
|
||||
if (!dayGapStr.isEmpty()) {
|
||||
list.add(dayGapStr);
|
||||
}
|
||||
if (!hourGapStr.isEmpty()) {
|
||||
list.add(hourGapStr);
|
||||
}
|
||||
return StringUtils.join(list, splitter);
|
||||
case "y_M_d_H_m":
|
||||
if (!dayGapStr.isEmpty()) {
|
||||
list.add(dayGapStr);
|
||||
}
|
||||
if (!hourGapStr.isEmpty()) {
|
||||
list.add(hourGapStr);
|
||||
}
|
||||
if (!minuteGapStr.isEmpty()) {
|
||||
list.add(minuteGapStr);
|
||||
}
|
||||
return StringUtils.join(list, splitter);
|
||||
case "H_m_s":
|
||||
case "y_M_d_H_m_s":
|
||||
if (!dayGapStr.isEmpty()) {
|
||||
list.add(dayGapStr);
|
||||
}
|
||||
if (!hourGapStr.isEmpty()) {
|
||||
list.add(hourGapStr);
|
||||
}
|
||||
if (!minuteGapStr.isEmpty()) {
|
||||
list.add(minuteGapStr);
|
||||
}
|
||||
if (!secondGapStr.isEmpty()) {
|
||||
list.add(secondGapStr);
|
||||
}
|
||||
return StringUtils.join(list, splitter);
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -51,3 +51,10 @@ i18n_error_login_type=error login type
|
||||
i18n_schema_is_empty=Schema is empty!
|
||||
i18n_table_name_repeat=Has duplicate name:
|
||||
i18n_sql_not_empty=SQL cannot be empty!
|
||||
|
||||
i18n_year=Year
|
||||
i18n_month=Month
|
||||
i18n_day=Day
|
||||
i18n_hour=Hour
|
||||
i18n_minute=Minute
|
||||
i18n_second=Second
|
||||
|
@ -64,3 +64,10 @@ i18n_sql_not_empty=sql \u4E0D\u80FD\u4E3A\u7A7A
|
||||
i18n_menu.parameter=\u7CFB\u7EDF\u53C2\u6570
|
||||
i18n_user_old_pwd_error=\u539F\u59CB\u5BC6\u7801\u9519\u8BEF
|
||||
i18n_menu.toolbox-log=\u64CD\u4F5C\u65E5\u5FD7
|
||||
|
||||
i18n_year=\u5E74
|
||||
i18n_month=\u6708
|
||||
i18n_day=\u5929
|
||||
i18n_hour=\u5C0F\u65F6
|
||||
i18n_minute=\u5206\u949F
|
||||
i18n_second=\u79D2
|
||||
|
@ -31,7 +31,7 @@ i18n_union_field_can_not_empty=\u95DC\u806F\u5B57\u6BB5\u4E0D\u80FD\u70BA\u7A7A
|
||||
i18n_table_duplicate=\u76F8\u540C\u7BC0\u9EDE\u9700\u91CD\u65B0\u62D6\u5165\u624D\u80FD\u7E7C\u7E8C\u65B0\u5EFA\u6578\u64DA\u96C6
|
||||
i18n_no_column_permission=\u6C92\u6709\u5217\u6B0A\u9650
|
||||
i18n_fetch_error=SQL\u57F7\u884C\u5931\u6557\uFF0C\u8ACB\u6AA2\u67E5\u8868\u3001\u5B57\u6BB5\u3001\u95DC\u806F\u95DC\u7CFB\u7B49\u4FE1\u606F\u662F\u5426\u6B63\u78BA\u4E26\u91CD\u65B0\u7DE8\u8F2F\u3002
|
||||
i18n_no_datasource_permission=\u65e0\u6570\u636e\u6e90\u8bbf\u95ee\u6743\u9650
|
||||
i18n_no_datasource_permission=\u65E0\u6570\u636E\u6E90\u8BBF\u95EE\u6743\u9650
|
||||
|
||||
i18n_field_circular_ref=\u5B57\u6BB5\u5B58\u5728\u5FAA\u74B0\u5F15\u7528
|
||||
|
||||
@ -51,4 +51,11 @@ i18n_login_name_pwd_err=\u7528\u6236\u540D\u6216\u5BC6\u78BC\u932F\u8AA4
|
||||
i18n_error_login_type=\u767B\u9304\u985E\u578B\u932F\u8AA4
|
||||
i18n_schema_is_empty=schema\u70BA\u7A7A\uFF01
|
||||
i18n_table_name_repeat=\u540D\u7A31\u91CD\u8907:
|
||||
i18n_sql_not_empty=sql\u4e0d\u80fd\u70ba\u7a7a
|
||||
i18n_sql_not_empty=sql\u4E0D\u80FD\u70BA\u7A7A
|
||||
|
||||
i18n_year=\u5E74
|
||||
i18n_month=\u6708
|
||||
i18n_day=\u5929
|
||||
i18n_hour=\u5C0F\u6642
|
||||
i18n_minute=\u5206\u9418
|
||||
i18n_second=\u79D2
|
||||
|
7
core/core-frontend/src/assets/svg/bar-range-dark.svg
Normal file
7
core/core-frontend/src/assets/svg/bar-range-dark.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<svg width="80" height="56" viewBox="0 0 80 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 2.00391V53.0016V54.0016H4V2.00391H7Z" fill="#434343"/>
|
||||
<path d="M17.5 50C17.2239 50 17 49.7761 17 49.5V42.5C17 42.2239 17.2239 42 17.5 42H52.5C52.7761 42 53 42.2239 53 42.5V49.5C53 49.7761 52.7761 50 52.5 50H17.5Z" fill="#00D6B9"/>
|
||||
<path d="M48.5 38C48.2239 38 48 37.7761 48 37.5V30.5C48 30.2239 48.2239 30 48.5 30H71.5C71.7761 30 72 30.2239 72 30.5V37.5C72 37.7761 71.7761 38 71.5 38H48.5Z" fill="#3370FF"/>
|
||||
<path d="M28.5 26C28.2239 26 28 25.7761 28 25.5V18.5C28 18.2239 28.2239 18 28.5 18H47.5C47.7761 18 48 18.2239 48 18.5V25.5C48 25.7761 47.7761 26 47.5 26H28.5Z" fill="#00D6B9"/>
|
||||
<path d="M9.5 14C9.22386 14 9 13.7761 9 13.5V6.5C9 6.22386 9.22386 6 9.5 6L48.5 6C48.7761 6 49 6.22386 49 6.5V13.5C49 13.7761 48.7761 14 48.5 14L9.5 14Z" fill="#3370FF"/>
|
||||
</svg>
|
After Width: | Height: | Size: 912 B |
7
core/core-frontend/src/assets/svg/bar-range.svg
Normal file
7
core/core-frontend/src/assets/svg/bar-range.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<svg width="80" height="56" viewBox="0 0 80 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 2.00391V53.0016V54.0016H4V2.00391H7Z" fill="#DEE0E3"/>
|
||||
<path d="M17.5 50C17.2239 50 17 49.7761 17 49.5V42.5C17 42.2239 17.2239 42 17.5 42H52.5C52.7761 42 53 42.2239 53 42.5V49.5C53 49.7761 52.7761 50 52.5 50H17.5Z" fill="#00D6B9"/>
|
||||
<path d="M48.5 38C48.2239 38 48 37.7761 48 37.5V30.5C48 30.2239 48.2239 30 48.5 30H71.5C71.7761 30 72 30.2239 72 30.5V37.5C72 37.7761 71.7761 38 71.5 38H48.5Z" fill="#3370FF"/>
|
||||
<path d="M28.5 26C28.2239 26 28 25.7761 28 25.5V18.5C28 18.2239 28.2239 18 28.5 18H47.5C47.7761 18 48 18.2239 48 18.5V25.5C48 25.7761 47.7761 26 47.5 26H28.5Z" fill="#00D6B9"/>
|
||||
<path d="M9.5 14C9.22386 14 9 13.7761 9 13.5V6.5C9 6.22386 9.22386 6 9.5 6L48.5 6C48.7761 6 49 6.22386 49 6.5V13.5C49 13.7761 48.7761 14 48.5 14L9.5 14Z" fill="#3370FF"/>
|
||||
</svg>
|
After Width: | Height: | Size: 912 B |
@ -503,6 +503,8 @@ export default {
|
||||
data_preview: '数据预览',
|
||||
dimension: '维度',
|
||||
quota: '指标',
|
||||
time_dimension_or_quota: '时间维度或指标',
|
||||
aggregate_time: '聚合时间纬度',
|
||||
title: '标题',
|
||||
show: '显示',
|
||||
chart_type: '图表类型',
|
||||
@ -678,6 +680,7 @@ export default {
|
||||
chart_bar_horizontal: '横向柱状图',
|
||||
chart_bar_stack_horizontal: '横向堆叠柱状图',
|
||||
chart_percentage_bar_stack_horizontal: '横向百分比柱状图',
|
||||
chart_bar_range: '区间条形图',
|
||||
chart_line: '基础折线图',
|
||||
chart_area_stack: '堆叠折线图',
|
||||
chart_pie: '饼图',
|
||||
@ -760,6 +763,8 @@ export default {
|
||||
chart_style: '样式',
|
||||
drag_block_type_axis: '类别轴',
|
||||
drag_block_value_axis: '值轴',
|
||||
drag_block_value_start: '开始值',
|
||||
drag_block_value_end: '结束值',
|
||||
drag_block_value_axis_left: '左值轴',
|
||||
drag_block_value_axis_right: '右值轴',
|
||||
drag_block_table_data_column: '数据列',
|
||||
@ -939,6 +944,7 @@ export default {
|
||||
value_formatter_unit: '数量单位',
|
||||
value_formatter_decimal_count: '小数位数',
|
||||
value_formatter_suffix: '单位后缀',
|
||||
show_gap: '显示间隔值',
|
||||
indicator_suffix_placeholder: '请输入1-10个字符',
|
||||
indicator_suffix: '后缀',
|
||||
indicator_value: '指标值',
|
||||
@ -1101,6 +1107,8 @@ export default {
|
||||
error_not_number: '不支持拖拽非数值类型指标',
|
||||
error_q_2_d: '不支持拖拽指标至维度',
|
||||
error_d_2_q: '不支持拖拽维度至指标',
|
||||
error_d_not_time_2_q: '不支持拖拽非时间类型的维度',
|
||||
error_bar_range_axis_type_not_equal: '开始值与结束值需要设置相同类型',
|
||||
only_input_number: '请输入正确数值',
|
||||
value_min_max_invalid: '最小值必须小于最大值',
|
||||
add_assist_line: '添加辅助线',
|
||||
|
@ -659,6 +659,8 @@ declare interface ChartLabelAttr {
|
||||
* 多系列标签设置
|
||||
*/
|
||||
seriesLabelFormatter: SeriesFormatter[]
|
||||
|
||||
showGap?: boolean
|
||||
}
|
||||
/**
|
||||
* 提示设置
|
||||
@ -690,6 +692,8 @@ declare interface ChartTooltipAttr {
|
||||
* 多系列提示设置
|
||||
*/
|
||||
seriesTooltipFormatter: SeriesFormatter[]
|
||||
|
||||
showGap?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -40,6 +40,7 @@ declare interface Chart {
|
||||
resultCount: number
|
||||
linkageActive: boolean
|
||||
jumpActive: boolean
|
||||
aggregate?: boolean
|
||||
}
|
||||
declare type CustomAttr = DeepPartial<ChartAttr> | JSONString<DeepPartial<ChartAttr>>
|
||||
declare type CustomStyle = DeepPartial<ChartStyle> | JSONString<DeepPartial<ChartStyle>>
|
||||
|
@ -110,6 +110,7 @@ const sort = param => {
|
||||
item.value.index = props.index
|
||||
item.value.sort = param.type
|
||||
item.value.customSort = []
|
||||
delete item.value.axisType
|
||||
emit('onDimensionItemChange', item.value)
|
||||
}
|
||||
}
|
||||
@ -122,6 +123,7 @@ const beforeSort = type => {
|
||||
|
||||
const dateStyle = param => {
|
||||
item.value.dateStyle = param.type
|
||||
item.value.axisType = props.type
|
||||
emit('onDimensionItemChange', item.value)
|
||||
}
|
||||
|
||||
@ -133,6 +135,7 @@ const beforeDateStyle = type => {
|
||||
|
||||
const datePattern = param => {
|
||||
item.value.datePattern = param.type
|
||||
item.value.axisType = props.type
|
||||
emit('onDimensionItemChange', item.value)
|
||||
}
|
||||
|
||||
|
@ -204,8 +204,23 @@ const showSeriesLabelFormatter = computed(() => {
|
||||
})
|
||||
const showDivider = computed(() => {
|
||||
const DIVIDER_PROPS = ['labelFormatter', 'showDimension', 'showQuota', 'showProportion']
|
||||
return includesAny(props.propertyInner, ...DIVIDER_PROPS)
|
||||
return includesAny(props.propertyInner, ...DIVIDER_PROPS) && !isBarRangeTime.value
|
||||
})
|
||||
|
||||
const isBarRangeTime = computed<boolean>(() => {
|
||||
if (props.chart.type === 'bar-range') {
|
||||
const tempYAxis = props.chart.yAxis[0]
|
||||
const tempYAxisExt = props.chart.yAxisExt[0]
|
||||
if (
|
||||
(tempYAxis && tempYAxis.groupType === 'd') ||
|
||||
(tempYAxisExt && tempYAxisExt.groupType === 'd')
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
init()
|
||||
})
|
||||
@ -329,7 +344,7 @@ onMounted(() => {
|
||||
:class="{ 'divider-dark': themes === 'dark' }"
|
||||
v-if="showDivider"
|
||||
/>
|
||||
<template v-if="showProperty('labelFormatter')">
|
||||
<template v-if="showProperty('labelFormatter') && !isBarRangeTime">
|
||||
<el-form-item
|
||||
:label="$t('chart.value_formatter_type')"
|
||||
class="form-item"
|
||||
@ -803,6 +818,15 @@ onMounted(() => {
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes" v-show="showProperty('showGap')">
|
||||
<el-checkbox
|
||||
:effect="themes"
|
||||
@change="changeLabelAttr('showGap')"
|
||||
v-model="state.labelForm.showGap"
|
||||
>
|
||||
{{ t('chart.show_gap') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
|
@ -151,6 +151,21 @@ const aggregationList = computed(() => {
|
||||
}
|
||||
return AGGREGATION_TYPE
|
||||
})
|
||||
|
||||
const isBarRangeTime = computed<boolean>(() => {
|
||||
if (props.chart.type === 'bar-range') {
|
||||
const tempYAxis = props.chart.yAxis[0]
|
||||
const tempYAxisExt = props.chart.yAxisExt[0]
|
||||
if (
|
||||
(tempYAxis && tempYAxis.groupType === 'd') ||
|
||||
(tempYAxisExt && tempYAxisExt.groupType === 'd')
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
watch(
|
||||
[() => props.chart.customAttr.tooltip, () => props.chart.customAttr.tooltip.show],
|
||||
() => {
|
||||
@ -425,7 +440,7 @@ onMounted(() => {
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
</el-space>
|
||||
<template v-if="showProperty('tooltipFormatter')">
|
||||
<template v-if="showProperty('tooltipFormatter') && !isBarRangeTime">
|
||||
<el-form-item
|
||||
:label="t('chart.value_formatter_type')"
|
||||
class="form-item"
|
||||
@ -707,6 +722,15 @@ onMounted(() => {
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes" v-show="showProperty('showGap')">
|
||||
<el-checkbox
|
||||
:effect="themes"
|
||||
@change="changeTooltipAttr('showGap')"
|
||||
v-model="state.tooltipForm.showGap"
|
||||
>
|
||||
{{ t('chart.show_gap') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
|
@ -52,6 +52,20 @@ const fontSizeList = computed(() => {
|
||||
return arr
|
||||
})
|
||||
|
||||
const isBarRangeTime = computed<boolean>(() => {
|
||||
if (props.chart.type === 'bar-range') {
|
||||
const tempYAxis = props.chart.yAxis[0]
|
||||
const tempYAxisExt = props.chart.yAxisExt[0]
|
||||
if (
|
||||
(tempYAxis && tempYAxis.groupType === 'd') ||
|
||||
(tempYAxisExt && tempYAxisExt.groupType === 'd')
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
const changeAxisStyle = prop => {
|
||||
if (
|
||||
state.axisForm.axisValue.splitCount &&
|
||||
@ -374,7 +388,7 @@ onMounted(() => {
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<template v-if="showProperty('axisLabelFormatter')">
|
||||
<template v-if="showProperty('axisLabelFormatter') && !isBarRangeTime">
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
|
@ -300,9 +300,22 @@ const startToMove = (e, item) => {
|
||||
)
|
||||
}
|
||||
|
||||
const dimensionItemChange = () => {
|
||||
const dimensionItemChange = item => {
|
||||
recordSnapshotInfo('calcData')
|
||||
// do dimensionItemChange
|
||||
if (view.value.type === 'bar-range') {
|
||||
if (item.axisType === 'quota') {
|
||||
view.value.yAxisExt?.forEach(y => {
|
||||
y.dateStyle = item.dateStyle
|
||||
y.datePattern = item.datePattern
|
||||
})
|
||||
} else if (item.axisType === 'quotaExt') {
|
||||
view.value.yAxis?.forEach(y => {
|
||||
y.dateStyle = item.dateStyle
|
||||
y.datePattern = item.datePattern
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
const dimensionItemRemove = item => {
|
||||
recordSnapshotInfo('calcData')
|
||||
@ -312,6 +325,10 @@ const dimensionItemRemove = item => {
|
||||
view.value.xAxisExt.splice(item.index, 1)
|
||||
} else if (item.removeType === 'dimensionStack') {
|
||||
view.value.extStack.splice(item.index, 1)
|
||||
} else if (item.removeType === 'quota') {
|
||||
view.value.yAxis.splice(item.index, 1)
|
||||
} else if (item.removeType === 'quotaExt') {
|
||||
view.value.yAxisExt.splice(item.index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
@ -320,6 +337,11 @@ const quotaItemChange = (axis: Axis, axisType: AxisType) => {
|
||||
// do quotaItemChange
|
||||
emitter.emit('updateAxis', { axisType, axis: [axis], editType: 'update' })
|
||||
}
|
||||
|
||||
const aggregateChange = () => {
|
||||
recordSnapshotInfo('calcData')
|
||||
}
|
||||
|
||||
const quotaItemRemove = item => {
|
||||
recordSnapshotInfo('calcData')
|
||||
let axisType: AxisType = item.removeType
|
||||
@ -442,6 +464,20 @@ const dragRemoveAggField = (list, e) => {
|
||||
}
|
||||
}
|
||||
|
||||
const showAggregate = computed<boolean>(() => {
|
||||
if (view.value.type === 'bar-range') {
|
||||
const tempYAxis = view.value.yAxis[0]
|
||||
const tempYAxisExt = view.value.yAxisExt[0]
|
||||
if (
|
||||
(tempYAxis && tempYAxis.groupType === 'd') ||
|
||||
(tempYAxisExt && tempYAxisExt.groupType === 'd')
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
const addAxis = (e, axis: AxisType) => {
|
||||
recordSnapshotInfo('calcData')
|
||||
const axisSpec = chartViewInstance.value.axisConfig[axis]
|
||||
@ -450,9 +486,30 @@ const addAxis = (e, axis: AxisType) => {
|
||||
}
|
||||
const { type, limit, duplicate } = axisSpec
|
||||
let typeValid, dup
|
||||
if (type) {
|
||||
|
||||
if (view.value.type === 'bar-range' && (axis === 'yAxis' || axis === 'yAxisExt')) {
|
||||
//区间条形图先排除非时间纬度或者指标的情况
|
||||
const list = view.value[axis]
|
||||
if (list && list.length > 0) {
|
||||
let valid = true
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
if (!(list[i].groupType === 'q' || (list[i].groupType === 'd' && list[i].deType === 1))) {
|
||||
list.splice(i, 1)
|
||||
valid = false
|
||||
}
|
||||
}
|
||||
if (!valid) {
|
||||
ElMessage({
|
||||
message: t('chart.error_d_not_time_2_q'),
|
||||
type: 'warning'
|
||||
})
|
||||
}
|
||||
typeValid = valid
|
||||
}
|
||||
} else if (type) {
|
||||
typeValid = dragCheckType(view.value[axis], type)
|
||||
}
|
||||
|
||||
// 针对指标卡进行数值类型判断
|
||||
if (typeValid && type === 'q' && view.value.type === 'indicator') {
|
||||
const list = view.value[axis]
|
||||
@ -528,16 +585,40 @@ const addAxis = (e, axis: AxisType) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (view.value.type === 'indicator' || view.value.type === 'chart-mix') {
|
||||
if (view.value?.yAxis?.length > 1) {
|
||||
const axis = view.value.yAxis.splice(1)
|
||||
emitter.emit('removeAxis', { axisType: 'yAxis', axis, editType: 'remove' })
|
||||
if (typeValid && view.value.type === 'bar-range') {
|
||||
//处理某一个轴有数据的情况
|
||||
let tempType = null
|
||||
let tempDeType = null
|
||||
if (axis === 'yAxis' && view.value.yAxisExt[0]) {
|
||||
tempType = view.value.yAxisExt[0].groupType
|
||||
tempDeType = view.value.yAxisExt[0].deType
|
||||
} else if (axis === 'yAxisExt' && view.value.yAxis[0]) {
|
||||
tempType = view.value.yAxis[0].groupType
|
||||
tempDeType = view.value.yAxis[0].deType
|
||||
}
|
||||
}
|
||||
if (view.value.type === 'chart-mix') {
|
||||
if (view.value?.yAxisExt?.length > 1) {
|
||||
const axis = view.value.yAxisExt.splice(1)
|
||||
emitter.emit('removeAxis', { axisType: 'yAxisExt', axis, editType: 'remove' })
|
||||
if (tempType !== null) {
|
||||
const list = view.value[axis]
|
||||
if (list && list.length > 0) {
|
||||
let valid = true
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
if (
|
||||
!(
|
||||
list[i].groupType === tempType &&
|
||||
(tempType === 'q' || (tempType === 'd' && list[i].deType === tempDeType))
|
||||
)
|
||||
) {
|
||||
list.splice(i, 1)
|
||||
valid = false
|
||||
}
|
||||
}
|
||||
if (!valid) {
|
||||
ElMessage({
|
||||
message: t('chart.error_bar_range_axis_type_not_equal'),
|
||||
type: 'warning'
|
||||
})
|
||||
}
|
||||
typeValid = valid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1683,114 +1764,272 @@ const drop = (ev: MouseEvent, type = 'xAxis') => {
|
||||
</div>
|
||||
</el-row>
|
||||
|
||||
<!--yAxis-->
|
||||
<el-row class="padding-lr drag-data" v-if="showAxis('yAxis')">
|
||||
<div class="form-draggable-title">
|
||||
<span>
|
||||
{{ chartViewInstance.axisConfig.yAxis.name }}
|
||||
</span>
|
||||
<el-tooltip :effect="toolTip" placement="top" :content="t('common.delete')">
|
||||
<el-icon
|
||||
class="remove-icon"
|
||||
:class="{ 'remove-icon--dark': themes === 'dark' }"
|
||||
size="14px"
|
||||
@click="removeItems('yAxis')"
|
||||
<template v-if="view.type !== 'bar-range'">
|
||||
<!--yAxis-->
|
||||
<el-row class="padding-lr drag-data" v-if="showAxis('yAxis')">
|
||||
<div class="form-draggable-title">
|
||||
<span>
|
||||
{{ chartViewInstance.axisConfig.yAxis.name }}
|
||||
</span>
|
||||
<el-tooltip
|
||||
:effect="toolTip"
|
||||
placement="top"
|
||||
:content="t('common.delete')"
|
||||
>
|
||||
<Icon class-name="inner-class" name="icon_delete-trash_outlined" />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div
|
||||
@drop="$event => drop($event, 'yAxis')"
|
||||
@dragenter="dragEnter"
|
||||
@dragover="$event => dragOver($event)"
|
||||
>
|
||||
<draggable
|
||||
:list="view.yAxis"
|
||||
:move="onMove"
|
||||
item-key="id"
|
||||
group="drag"
|
||||
animation="300"
|
||||
class="drag-block-style"
|
||||
:class="{ dark: themes === 'dark' }"
|
||||
@add="addYaxis"
|
||||
@change="e => onAxisChange(e, 'yAxis')"
|
||||
<el-icon
|
||||
class="remove-icon"
|
||||
:class="{ 'remove-icon--dark': themes === 'dark' }"
|
||||
size="14px"
|
||||
@click="removeItems('yAxis')"
|
||||
>
|
||||
<Icon class-name="inner-class" name="icon_delete-trash_outlined" />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div
|
||||
@drop="$event => drop($event, 'yAxis')"
|
||||
@dragenter="dragEnter"
|
||||
@dragover="$event => dragOver($event)"
|
||||
>
|
||||
<template #item="{ element, index }">
|
||||
<quota-item
|
||||
:dimension-data="state.dimension"
|
||||
:quota-data="state.quota"
|
||||
:chart="view"
|
||||
:item="element"
|
||||
:index="index"
|
||||
type="quota"
|
||||
:themes="props.themes"
|
||||
@onQuotaItemChange="item => quotaItemChange(item, 'yAxis')"
|
||||
@onQuotaItemRemove="quotaItemRemove"
|
||||
@onNameEdit="showRename"
|
||||
@editItemFilter="showQuotaEditFilter"
|
||||
@editItemCompare="showQuotaEditCompare"
|
||||
@valueFormatter="valueFormatter"
|
||||
/>
|
||||
</template>
|
||||
</draggable>
|
||||
<drag-placeholder :drag-list="view.yAxis" />
|
||||
</div>
|
||||
</el-row>
|
||||
<!--yAxisExt-->
|
||||
<el-row class="padding-lr drag-data" v-if="showAxis('yAxisExt')">
|
||||
<div class="form-draggable-title">
|
||||
<span>
|
||||
{{ chartViewInstance.axisConfig.yAxisExt.name }}
|
||||
</span>
|
||||
<el-tooltip :effect="toolTip" placement="top" :content="t('common.delete')">
|
||||
<el-icon
|
||||
class="remove-icon"
|
||||
:class="{ 'remove-icon--dark': themes === 'dark' }"
|
||||
size="14px"
|
||||
@click="removeItems('yAxisExt')"
|
||||
<draggable
|
||||
:list="view.yAxis"
|
||||
:move="onMove"
|
||||
item-key="id"
|
||||
group="drag"
|
||||
animation="300"
|
||||
class="drag-block-style"
|
||||
:class="{ dark: themes === 'dark' }"
|
||||
@add="addYaxis"
|
||||
@change="e => onAxisChange(e, 'yAxis')"
|
||||
>
|
||||
<Icon class-name="inner-class" name="icon_delete-trash_outlined" />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div
|
||||
@drop="$event => drop($event, 'yAxisExt')"
|
||||
@dragenter="dragEnter"
|
||||
@dragover="$event => dragOver($event)"
|
||||
>
|
||||
<draggable
|
||||
:list="view.yAxisExt"
|
||||
:move="onMove"
|
||||
item-key="id"
|
||||
group="drag"
|
||||
animation="300"
|
||||
class="drag-block-style"
|
||||
:class="{ dark: themes === 'dark' }"
|
||||
@add="addYaxisExt"
|
||||
@change="e => onAxisChange(e, 'yAxisExt')"
|
||||
<template #item="{ element, index }">
|
||||
<quota-item
|
||||
:dimension-data="state.dimension"
|
||||
:quota-data="state.quota"
|
||||
:chart="view"
|
||||
:item="element"
|
||||
:index="index"
|
||||
type="quota"
|
||||
:themes="props.themes"
|
||||
@onQuotaItemChange="item => quotaItemChange(item, 'yAxis')"
|
||||
@onQuotaItemRemove="quotaItemRemove"
|
||||
@onNameEdit="showRename"
|
||||
@editItemFilter="showQuotaEditFilter"
|
||||
@editItemCompare="showQuotaEditCompare"
|
||||
@valueFormatter="valueFormatter"
|
||||
/>
|
||||
</template>
|
||||
</draggable>
|
||||
<drag-placeholder :drag-list="view.yAxis" />
|
||||
</div>
|
||||
</el-row>
|
||||
<!--yAxisExt-->
|
||||
<el-row class="padding-lr drag-data" v-if="showAxis('yAxisExt')">
|
||||
<div class="form-draggable-title">
|
||||
<span>
|
||||
{{ chartViewInstance.axisConfig.yAxisExt.name }}
|
||||
</span>
|
||||
<el-tooltip
|
||||
:effect="toolTip"
|
||||
placement="top"
|
||||
:content="t('common.delete')"
|
||||
>
|
||||
<el-icon
|
||||
class="remove-icon"
|
||||
:class="{ 'remove-icon--dark': themes === 'dark' }"
|
||||
size="14px"
|
||||
@click="removeItems('yAxisExt')"
|
||||
>
|
||||
<Icon class-name="inner-class" name="icon_delete-trash_outlined" />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div
|
||||
@drop="$event => drop($event, 'yAxisExt')"
|
||||
@dragenter="dragEnter"
|
||||
@dragover="$event => dragOver($event)"
|
||||
>
|
||||
<template #item="{ element, index }">
|
||||
<quota-item
|
||||
:dimension-data="state.dimension"
|
||||
:quota-data="state.quota"
|
||||
:chart="view"
|
||||
:item="element"
|
||||
:index="index"
|
||||
type="quotaExt"
|
||||
:themes="props.themes"
|
||||
@onQuotaItemChange="item => quotaItemChange(item, 'yAxisExt')"
|
||||
@onQuotaItemRemove="quotaItemRemove"
|
||||
@onNameEdit="showRename"
|
||||
@editItemFilter="showQuotaEditFilter"
|
||||
@editItemCompare="showQuotaEditCompare"
|
||||
@valueFormatter="valueFormatter"
|
||||
/>
|
||||
</template>
|
||||
</draggable>
|
||||
<drag-placeholder :drag-list="view.yAxisExt" />
|
||||
</div>
|
||||
</el-row>
|
||||
<draggable
|
||||
:list="view.yAxisExt"
|
||||
:move="onMove"
|
||||
item-key="id"
|
||||
group="drag"
|
||||
animation="300"
|
||||
class="drag-block-style"
|
||||
:class="{ dark: themes === 'dark' }"
|
||||
@add="addYaxisExt"
|
||||
@change="e => onAxisChange(e, 'yAxisExt')"
|
||||
>
|
||||
<template #item="{ element, index }">
|
||||
<quota-item
|
||||
:dimension-data="state.dimension"
|
||||
:quota-data="state.quota"
|
||||
:chart="view"
|
||||
:item="element"
|
||||
:index="index"
|
||||
type="quotaExt"
|
||||
:themes="props.themes"
|
||||
@onQuotaItemChange="item => quotaItemChange(item, 'yAxisExt')"
|
||||
@onQuotaItemRemove="quotaItemRemove"
|
||||
@onNameEdit="showRename"
|
||||
@editItemFilter="showQuotaEditFilter"
|
||||
@editItemCompare="showQuotaEditCompare"
|
||||
@valueFormatter="valueFormatter"
|
||||
/>
|
||||
</template>
|
||||
</draggable>
|
||||
<drag-placeholder :drag-list="view.yAxisExt" />
|
||||
</div>
|
||||
</el-row>
|
||||
</template>
|
||||
<template v-else-if="view.type === 'bar-range'">
|
||||
<!--yAxis-->
|
||||
<el-row class="padding-lr drag-data" v-if="showAxis('yAxis')">
|
||||
<div class="form-draggable-title">
|
||||
<span>
|
||||
{{ chartViewInstance.axisConfig.yAxis.name }}
|
||||
</span>
|
||||
<el-tooltip
|
||||
:effect="toolTip"
|
||||
placement="top"
|
||||
:content="t('common.delete')"
|
||||
>
|
||||
<el-icon
|
||||
class="remove-icon"
|
||||
:class="{ 'remove-icon--dark': themes === 'dark' }"
|
||||
size="14px"
|
||||
@click="removeItems('yAxis')"
|
||||
>
|
||||
<Icon class-name="inner-class" name="icon_delete-trash_outlined" />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div
|
||||
@drop="$event => drop($event, 'yAxis')"
|
||||
@dragenter="dragEnter"
|
||||
@dragover="$event => dragOver($event)"
|
||||
>
|
||||
<draggable
|
||||
:list="view.yAxis"
|
||||
:move="onMove"
|
||||
item-key="id"
|
||||
group="drag"
|
||||
animation="300"
|
||||
class="drag-block-style"
|
||||
:class="{ dark: themes === 'dark' }"
|
||||
@add="addYaxis"
|
||||
@change="e => onAxisChange(e, 'yAxis')"
|
||||
>
|
||||
<template #item="{ element, index }">
|
||||
<dimension-item
|
||||
v-if="element.groupType === 'd'"
|
||||
:dimension-data="state.dimension"
|
||||
:quota-data="state.quota"
|
||||
:chart="view"
|
||||
:item="element"
|
||||
:index="index"
|
||||
:themes="props.themes"
|
||||
type="quota"
|
||||
@onDimensionItemChange="dimensionItemChange"
|
||||
@onDimensionItemRemove="dimensionItemRemove"
|
||||
@onNameEdit="showRename"
|
||||
@onCustomSort="onExtCustomSort"
|
||||
/>
|
||||
<quota-item
|
||||
v-else-if="element.groupType === 'q'"
|
||||
:dimension-data="state.dimension"
|
||||
:quota-data="state.quota"
|
||||
:chart="view"
|
||||
:item="element"
|
||||
:index="index"
|
||||
type="quota"
|
||||
:themes="props.themes"
|
||||
@onQuotaItemChange="item => quotaItemChange(item, 'yAxis')"
|
||||
@onQuotaItemRemove="quotaItemRemove"
|
||||
@onNameEdit="showRename"
|
||||
@editItemFilter="showQuotaEditFilter"
|
||||
@editItemCompare="showQuotaEditCompare"
|
||||
@valueFormatter="valueFormatter"
|
||||
/>
|
||||
</template>
|
||||
</draggable>
|
||||
<drag-placeholder :drag-list="view.yAxis" />
|
||||
</div>
|
||||
</el-row>
|
||||
<!--yAxisExt-->
|
||||
<el-row class="padding-lr drag-data" v-if="showAxis('yAxisExt')">
|
||||
<div class="form-draggable-title">
|
||||
<span>
|
||||
{{ chartViewInstance.axisConfig.yAxisExt.name }}
|
||||
</span>
|
||||
<el-tooltip
|
||||
:effect="toolTip"
|
||||
placement="top"
|
||||
:content="t('common.delete')"
|
||||
>
|
||||
<el-icon
|
||||
class="remove-icon"
|
||||
:class="{ 'remove-icon--dark': themes === 'dark' }"
|
||||
size="14px"
|
||||
@click="removeItems('yAxisExt')"
|
||||
>
|
||||
<Icon class-name="inner-class" name="icon_delete-trash_outlined" />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div
|
||||
@drop="$event => drop($event, 'yAxisExt')"
|
||||
@dragenter="dragEnter"
|
||||
@dragover="$event => dragOver($event)"
|
||||
>
|
||||
<draggable
|
||||
:list="view.yAxisExt"
|
||||
:move="onMove"
|
||||
item-key="id"
|
||||
group="drag"
|
||||
animation="300"
|
||||
class="drag-block-style"
|
||||
:class="{ dark: themes === 'dark' }"
|
||||
@add="addYaxisExt"
|
||||
@change="e => onAxisChange(e, 'yAxisExt')"
|
||||
>
|
||||
<template #item="{ element, index }">
|
||||
<dimension-item
|
||||
v-if="element.groupType === 'd'"
|
||||
:dimension-data="state.dimension"
|
||||
:quota-data="state.quota"
|
||||
:chart="view"
|
||||
:item="element"
|
||||
:index="index"
|
||||
:themes="props.themes"
|
||||
type="quotaExt"
|
||||
@onDimensionItemChange="dimensionItemChange"
|
||||
@onDimensionItemRemove="dimensionItemRemove"
|
||||
@onNameEdit="showRename"
|
||||
@onCustomSort="onExtCustomSort"
|
||||
/>
|
||||
<quota-item
|
||||
v-else-if="element.groupType === 'q'"
|
||||
:dimension-data="state.dimension"
|
||||
:quota-data="state.quota"
|
||||
:chart="view"
|
||||
:item="element"
|
||||
:index="index"
|
||||
type="quotaExt"
|
||||
:themes="props.themes"
|
||||
@onQuotaItemChange="item => quotaItemChange(item, 'yAxisExt')"
|
||||
@onQuotaItemRemove="quotaItemRemove"
|
||||
@onNameEdit="showRename"
|
||||
@editItemFilter="showQuotaEditFilter"
|
||||
@editItemCompare="showQuotaEditCompare"
|
||||
@valueFormatter="valueFormatter"
|
||||
/>
|
||||
</template>
|
||||
</draggable>
|
||||
<drag-placeholder :drag-list="view.yAxisExt" />
|
||||
</div>
|
||||
</el-row>
|
||||
</template>
|
||||
<!-- extBubble -->
|
||||
<el-row class="padding-lr drag-data" v-if="showAxis('extBubble')">
|
||||
<div class="form-draggable-title">
|
||||
@ -1955,6 +2194,22 @@ const drop = (ev: MouseEvent, type = 'xAxis') => {
|
||||
<drag-placeholder :drag-list="view.customFilter" />
|
||||
</div>
|
||||
</el-row>
|
||||
|
||||
<el-row class="refresh-area" v-if="showAggregate">
|
||||
<el-form-item
|
||||
class="form-item no-margin-bottom"
|
||||
:class="'form-item-' + themes"
|
||||
>
|
||||
<el-checkbox
|
||||
:effect="themes"
|
||||
size="small"
|
||||
v-model="view.aggregate"
|
||||
@change="aggregateChange"
|
||||
>
|
||||
{{ t('chart.aggregate_time') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-row>
|
||||
</el-scrollbar>
|
||||
<el-footer :class="{ 'refresh-active-footer': view.refreshViewEnable }">
|
||||
<el-row class="refresh-area">
|
||||
|
@ -1198,6 +1198,13 @@ export const CHART_TYPE_CONFIGS = [
|
||||
value: 'percentage-bar-stack-horizontal',
|
||||
title: t('chart.chart_percentage_bar_stack_horizontal'),
|
||||
icon: 'percentage-bar-stack-horizontal'
|
||||
},
|
||||
{
|
||||
render: 'antv',
|
||||
category: 'compare',
|
||||
value: 'bar-range',
|
||||
title: t('chart.chart_bar_range'),
|
||||
icon: 'bar-range'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -12,6 +12,19 @@ export const BAR_EDITOR_PROPERTY: EditorProperty[] = [
|
||||
'jump-set',
|
||||
'linkage'
|
||||
]
|
||||
export const BAR_RANGE_EDITOR_PROPERTY: EditorProperty[] = [
|
||||
'background-overall-component',
|
||||
'basic-style-selector',
|
||||
'label-selector',
|
||||
'tooltip-selector',
|
||||
'x-axis-selector',
|
||||
'y-axis-selector',
|
||||
'title-selector',
|
||||
'legend-selector',
|
||||
'function-cfg',
|
||||
'jump-set',
|
||||
'linkage'
|
||||
]
|
||||
|
||||
export const BAR_EDITOR_PROPERTY_INNER: EditorPropertyInner = {
|
||||
'background-overall-component': ['all'],
|
||||
|
@ -0,0 +1,383 @@
|
||||
import {
|
||||
G2PlotChartView,
|
||||
G2PlotDrawOptions
|
||||
} from '@/views/chart/components/js/panel/types/impl/g2plot'
|
||||
import { Bar, BarOptions } from '@antv/g2plot/esm/plots/bar'
|
||||
import { getPadding, setGradientColor } from '@/views/chart/components/js/panel/common/common_antv'
|
||||
import { cloneDeep, find } from 'lodash-es'
|
||||
import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
|
||||
import { valueFormatter } from '@/views/chart/components/js/formatter'
|
||||
import {
|
||||
BAR_AXIS_TYPE,
|
||||
BAR_RANGE_EDITOR_PROPERTY,
|
||||
BAR_EDITOR_PROPERTY_INNER
|
||||
} from '@/views/chart/components/js/panel/charts/bar/common'
|
||||
import { Datum } from '@antv/g2plot/esm/types/common'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
const DEFAULT_DATA = []
|
||||
|
||||
/**
|
||||
* 区间条形图
|
||||
*/
|
||||
export class RangeBar extends G2PlotChartView<BarOptions, Bar> {
|
||||
axisConfig = {
|
||||
...this['axisConfig'],
|
||||
yAxis: {
|
||||
name: `${t('chart.drag_block_value_start')} / ${t('chart.time_dimension_or_quota')}`,
|
||||
limit: 1,
|
||||
type: 'q'
|
||||
},
|
||||
yAxisExt: {
|
||||
name: `${t('chart.drag_block_value_end')} / ${t('chart.time_dimension_or_quota')}`,
|
||||
limit: 1,
|
||||
type: 'q'
|
||||
}
|
||||
}
|
||||
properties = BAR_RANGE_EDITOR_PROPERTY
|
||||
propertyInner = {
|
||||
...BAR_EDITOR_PROPERTY_INNER,
|
||||
'label-selector': ['hPosition', 'color', 'fontSize', 'labelFormatter', 'showGap'],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'showGap'],
|
||||
'x-axis-selector': [...BAR_EDITOR_PROPERTY_INNER['x-axis-selector'], 'axisLabelFormatter']
|
||||
}
|
||||
axis: AxisType[] = [...BAR_AXIS_TYPE, 'yAxisExt']
|
||||
protected baseOptions: BarOptions = {
|
||||
data: [],
|
||||
xField: 'values',
|
||||
yField: 'field',
|
||||
colorFiled: 'category',
|
||||
isGroup: true,
|
||||
interactions: [
|
||||
{
|
||||
type: 'legend-active',
|
||||
cfg: {
|
||||
start: [{ trigger: 'legend-item:mouseenter', action: ['element-active:reset'] }],
|
||||
end: [{ trigger: 'legend-item:mouseleave', action: ['element-active:reset'] }]
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'legend-filter',
|
||||
cfg: {
|
||||
start: [
|
||||
{
|
||||
trigger: 'legend-item:click',
|
||||
action: [
|
||||
'list-unchecked:toggle',
|
||||
'data-filter:filter',
|
||||
'element-active:reset',
|
||||
'element-highlight:reset'
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'tooltip',
|
||||
cfg: {
|
||||
start: [{ trigger: 'interval:mousemove', action: 'tooltip:show' }],
|
||||
end: [{ trigger: 'interval:mouseleave', action: 'tooltip:hide' }]
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'active-region',
|
||||
cfg: {
|
||||
start: [{ trigger: 'interval:mousemove', action: 'active-region:show' }],
|
||||
end: [{ trigger: 'interval:mouseleave', action: 'active-region:hide' }]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
drawChart(drawOptions: G2PlotDrawOptions<Bar>): Bar {
|
||||
const { chart, container, action } = drawOptions
|
||||
if (!chart.data?.data?.length) {
|
||||
return
|
||||
}
|
||||
// data
|
||||
const data: Array<any> = cloneDeep(chart.data.data)
|
||||
|
||||
data.forEach(d => {
|
||||
d.tempId = (Math.random() * 10000000).toString()
|
||||
})
|
||||
|
||||
const ifAggregate = !!chart.aggregate
|
||||
|
||||
const isDate = !!chart.data.isDate
|
||||
|
||||
const minTime = chart.data.minTime
|
||||
const maxTime = chart.data.maxTime
|
||||
|
||||
const minNumber = chart.data.min
|
||||
const maxNumber = chart.data.max
|
||||
|
||||
// options
|
||||
const initOptions: BarOptions = {
|
||||
...this.baseOptions,
|
||||
appendPadding: getPadding(chart),
|
||||
data,
|
||||
seriesField: isDate ? (ifAggregate ? 'category' : undefined) : 'category',
|
||||
isGroup: isDate ? !ifAggregate : false,
|
||||
isStack: isDate ? !ifAggregate : false,
|
||||
meta: isDate
|
||||
? {
|
||||
values: {
|
||||
type: 'time',
|
||||
min: minTime,
|
||||
max: maxTime,
|
||||
mask: 'YYYY-MM-DD HH:mm:ss'
|
||||
},
|
||||
tempId: {
|
||||
key: true
|
||||
}
|
||||
}
|
||||
: {
|
||||
values: {
|
||||
min: minNumber,
|
||||
max: maxNumber,
|
||||
mask: 'YYYY-MM-DD HH:mm:ss'
|
||||
},
|
||||
tempId: {
|
||||
key: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const options = this.setupOptions(chart, initOptions)
|
||||
|
||||
// 开始渲染
|
||||
const newChart = new Bar(container, options)
|
||||
|
||||
newChart.on('interval:click', action)
|
||||
|
||||
return newChart
|
||||
}
|
||||
|
||||
protected configXAxis(chart: Chart, options: BarOptions): BarOptions {
|
||||
const tmpOptions = super.configXAxis(chart, options)
|
||||
if (!tmpOptions.xAxis) {
|
||||
return tmpOptions
|
||||
}
|
||||
const xAxis = parseJson(chart.customStyle).xAxis
|
||||
const axisValue = xAxis.axisValue
|
||||
const isDate = !!chart.data.isDate
|
||||
if (tmpOptions.xAxis.label) {
|
||||
tmpOptions.xAxis.label.formatter = value => {
|
||||
if (isDate) {
|
||||
return value
|
||||
}
|
||||
return valueFormatter(value, xAxis.axisLabelFormatter)
|
||||
}
|
||||
}
|
||||
if (tmpOptions.xAxis.position === 'top') {
|
||||
tmpOptions.xAxis.position = 'left'
|
||||
}
|
||||
if (tmpOptions.xAxis.position === 'bottom') {
|
||||
tmpOptions.xAxis.position = 'right'
|
||||
}
|
||||
if (!axisValue?.auto) {
|
||||
const axis = {
|
||||
xAxis: {
|
||||
...tmpOptions.xAxis,
|
||||
min: axisValue.min,
|
||||
max: axisValue.max,
|
||||
minLimit: axisValue.min,
|
||||
maxLimit: axisValue.max,
|
||||
tickCount: axisValue.splitCount
|
||||
}
|
||||
}
|
||||
return { ...tmpOptions, ...axis }
|
||||
}
|
||||
return tmpOptions
|
||||
}
|
||||
|
||||
protected configTooltip(chart: Chart, options: BarOptions): BarOptions {
|
||||
const isDate = !!chart.data.isDate
|
||||
let tooltip
|
||||
let customAttr: DeepPartial<ChartAttr>
|
||||
if (chart.customAttr) {
|
||||
customAttr = parseJson(chart.customAttr)
|
||||
// tooltip
|
||||
if (customAttr.tooltip) {
|
||||
const t = JSON.parse(JSON.stringify(customAttr.tooltip))
|
||||
if (t.show) {
|
||||
tooltip = {
|
||||
formatter: function (param: Datum) {
|
||||
let res
|
||||
if (isDate) {
|
||||
res = param.values[0] + ' ~ ' + param.values[1]
|
||||
if (t.showGap) {
|
||||
res = res + ' (' + param.gap + ')'
|
||||
}
|
||||
} else {
|
||||
res =
|
||||
valueFormatter(param.values[0], t.tooltipFormatter) +
|
||||
' ~ ' +
|
||||
valueFormatter(param.values[1], t.tooltipFormatter)
|
||||
if (t.showGap) {
|
||||
res = res + ' (' + valueFormatter(param.gap, t.tooltipFormatter) + ')'
|
||||
}
|
||||
}
|
||||
return { value: res, values: param.values, name: param.field }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tooltip = false
|
||||
}
|
||||
}
|
||||
}
|
||||
return { ...options, tooltip }
|
||||
}
|
||||
|
||||
protected configBasicStyle(chart: Chart, options: BarOptions): BarOptions {
|
||||
const isDate = !!chart.data.isDate
|
||||
const ifAggregate = !!chart.aggregate
|
||||
const basicStyle = parseJson(chart.customAttr).basicStyle
|
||||
|
||||
if (isDate && !ifAggregate) {
|
||||
const customColors = []
|
||||
const groups = []
|
||||
for (let i = 0; i < chart.data.data.length; i++) {
|
||||
const name = chart.data.data[i].field
|
||||
if (groups.indexOf(name) < 0) {
|
||||
groups.push(name)
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < groups.length; i++) {
|
||||
const s = groups[i]
|
||||
customColors.push({
|
||||
name: s,
|
||||
color: basicStyle.colors[i % basicStyle.colors.length],
|
||||
isCustom: false
|
||||
})
|
||||
}
|
||||
const color = obj => {
|
||||
const colorObj = find(customColors, o => {
|
||||
return o.name === obj.field
|
||||
})
|
||||
if (colorObj === undefined) {
|
||||
return undefined
|
||||
}
|
||||
const color = hexColorToRGBA(colorObj.color, basicStyle.alpha)
|
||||
if (basicStyle.gradient) {
|
||||
return setGradientColor(color, true)
|
||||
} else {
|
||||
return color
|
||||
}
|
||||
}
|
||||
|
||||
options = {
|
||||
...options,
|
||||
color
|
||||
}
|
||||
} else {
|
||||
if (basicStyle.gradient) {
|
||||
let color = basicStyle.colors
|
||||
color = color.map(ele => {
|
||||
const tmp = hexColorToRGBA(ele, basicStyle.alpha)
|
||||
return setGradientColor(tmp, true)
|
||||
})
|
||||
options = {
|
||||
...options,
|
||||
color
|
||||
}
|
||||
}
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
setupDefaultOptions(chart: ChartObj): ChartObj {
|
||||
const { customAttr, senior } = chart
|
||||
const { label } = customAttr
|
||||
if (!['left', 'middle', 'right'].includes(label.position)) {
|
||||
label.position = 'middle'
|
||||
}
|
||||
senior.functionCfg.emptyDataStrategy = 'ignoreData'
|
||||
return chart
|
||||
}
|
||||
|
||||
protected configLabel(chart: Chart, options: BarOptions): BarOptions {
|
||||
const isDate = !!chart.data.isDate
|
||||
const ifAggregate = !!chart.aggregate
|
||||
|
||||
const tmpOptions = super.configLabel(chart, options)
|
||||
if (!tmpOptions.label) {
|
||||
return {
|
||||
...tmpOptions,
|
||||
label: false
|
||||
}
|
||||
}
|
||||
const labelAttr = parseJson(chart.customAttr).label
|
||||
|
||||
if (isDate && !ifAggregate) {
|
||||
if (!tmpOptions.label.layout) {
|
||||
tmpOptions.label.layout = []
|
||||
}
|
||||
tmpOptions.label.layout.push({ type: 'interval-hide-overlap' })
|
||||
tmpOptions.label.layout.push({ type: 'limit-in-plot', cfg: { action: 'hide' } })
|
||||
}
|
||||
|
||||
const label = {
|
||||
fields: [],
|
||||
...tmpOptions.label,
|
||||
formatter: (param: Datum) => {
|
||||
let res
|
||||
if (isDate) {
|
||||
if (labelAttr.showGap) {
|
||||
res = param.gap
|
||||
} else {
|
||||
res = param.values[0] + ' ~ ' + param.values[1]
|
||||
}
|
||||
} else {
|
||||
if (labelAttr.showGap) {
|
||||
res = valueFormatter(param.gap, labelAttr.labelFormatter)
|
||||
} else {
|
||||
res =
|
||||
valueFormatter(param.values[0], labelAttr.labelFormatter) +
|
||||
' ~ ' +
|
||||
valueFormatter(param.values[1], labelAttr.labelFormatter)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
return {
|
||||
...tmpOptions,
|
||||
label
|
||||
}
|
||||
}
|
||||
|
||||
protected configYAxis(chart: Chart, options: BarOptions): BarOptions {
|
||||
const tmpOptions = super.configYAxis(chart, options)
|
||||
if (!tmpOptions.yAxis) {
|
||||
return tmpOptions
|
||||
}
|
||||
if (tmpOptions.yAxis.position === 'left') {
|
||||
tmpOptions.yAxis.position = 'bottom'
|
||||
}
|
||||
if (tmpOptions.yAxis.position === 'right') {
|
||||
tmpOptions.yAxis.position = 'top'
|
||||
}
|
||||
return tmpOptions
|
||||
}
|
||||
|
||||
protected setupOptions(chart: Chart, options: BarOptions): BarOptions {
|
||||
return flow(
|
||||
this.configTheme,
|
||||
this.configBasicStyle,
|
||||
this.configLabel,
|
||||
this.configTooltip,
|
||||
this.configLegend,
|
||||
this.configXAxis,
|
||||
this.configYAxis,
|
||||
this.configSlider,
|
||||
this.configAnalyseHorizontal,
|
||||
this.configEmptyDataStrategy
|
||||
)(chart, options)
|
||||
}
|
||||
|
||||
constructor(name = 'bar-range') {
|
||||
super(name, DEFAULT_DATA)
|
||||
}
|
||||
}
|
@ -44,10 +44,12 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
|
||||
...this['axisConfig'],
|
||||
yAxis: {
|
||||
name: `${t('chart.drag_block_value_axis_left')} / ${t('chart.quota')}`,
|
||||
limit: 1,
|
||||
type: 'q'
|
||||
},
|
||||
yAxisExt: {
|
||||
name: `${t('chart.drag_block_value_axis_right')} / ${t('chart.quota')}`,
|
||||
limit: 1,
|
||||
type: 'q'
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ export class IndicatorChartView extends AbstractChartView {
|
||||
axisConfig: AxisConfig = {
|
||||
yAxis: {
|
||||
name: `${t('chart.quota')}`,
|
||||
limit: 1,
|
||||
type: 'q'
|
||||
}
|
||||
}
|
||||
|
@ -226,8 +226,12 @@ const trackClick = trackAction => {
|
||||
if (state.pointParam.data.dimensionList.length > 1) {
|
||||
checkName = state.pointParam.data.dimensionList[0].id
|
||||
}
|
||||
const quotaList = state.pointParam.data.quotaList
|
||||
quotaList[0]['value'] = state.pointParam.data.value
|
||||
let quotaList = state.pointParam.data.quotaList
|
||||
if (curView.type === 'bar-range') {
|
||||
quotaList = state.pointParam.data.dimensionList
|
||||
} else {
|
||||
quotaList[0]['value'] = state.pointParam.data.value
|
||||
}
|
||||
const linkageParam = {
|
||||
option: 'linkage',
|
||||
name: checkName,
|
||||
|
@ -202,4 +202,9 @@ public class ChartViewBaseDTO implements Serializable {
|
||||
*/
|
||||
private Boolean jumpActive;
|
||||
|
||||
/**
|
||||
* 区间条形图开启时间纬度开启聚合
|
||||
*/
|
||||
private Boolean aggregate;
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user