forked from github/dataease
commit
d2a5045784
@ -5,11 +5,11 @@ import java.io.Serializable;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
*
|
* 组件图表表
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @author fit2cloud
|
* @author fit2cloud
|
||||||
* @since 2023-08-20
|
* @since 2024-05-07
|
||||||
*/
|
*/
|
||||||
@TableName("core_chart_view")
|
@TableName("core_chart_view")
|
||||||
public class CoreChartView implements Serializable {
|
public class CoreChartView implements Serializable {
|
||||||
@ -191,10 +191,21 @@ public class CoreChartView implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private Boolean jumpActive;
|
private Boolean jumpActive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制来源
|
||||||
|
*/
|
||||||
private Long copyFrom;
|
private Long copyFrom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制ID
|
||||||
|
*/
|
||||||
private Long copyId;
|
private Long copyId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 区间条形图开启时间纬度开启聚合
|
||||||
|
*/
|
||||||
|
private Boolean aggregate;
|
||||||
|
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -491,6 +502,14 @@ public class CoreChartView implements Serializable {
|
|||||||
this.copyId = copyId;
|
this.copyId = copyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getAggregate() {
|
||||||
|
return aggregate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAggregate(Boolean aggregate) {
|
||||||
|
this.aggregate = aggregate;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "CoreChartView{" +
|
return "CoreChartView{" +
|
||||||
@ -531,6 +550,7 @@ public class CoreChartView implements Serializable {
|
|||||||
", jumpActive = " + jumpActive +
|
", jumpActive = " + jumpActive +
|
||||||
", copyFrom = " + copyFrom +
|
", copyFrom = " + copyFrom +
|
||||||
", copyId = " + copyId +
|
", copyId = " + copyId +
|
||||||
|
", aggregate = " + aggregate +
|
||||||
"}";
|
"}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,11 @@ import org.apache.ibatis.annotations.Mapper;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Mapper 接口
|
* 组件图表表 Mapper 接口
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @author fit2cloud
|
* @author fit2cloud
|
||||||
* @since 2023-08-20
|
* @since 2024-05-07
|
||||||
*/
|
*/
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface CoreChartViewMapper extends BaseMapper<CoreChartView> {
|
public interface CoreChartViewMapper extends BaseMapper<CoreChartView> {
|
||||||
|
@ -34,6 +34,7 @@ import io.dataease.utils.JsonUtil;
|
|||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.collections4.MapUtils;
|
import org.apache.commons.collections4.MapUtils;
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -127,6 +128,35 @@ public class ChartDataManage {
|
|||||||
List<ChartViewFieldDTO> yAxisExt = new ArrayList<>(view.getYAxisExt());
|
List<ChartViewFieldDTO> yAxisExt = new ArrayList<>(view.getYAxisExt());
|
||||||
yAxis.addAll(yAxisExt);
|
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> extStack = new ArrayList<>(view.getExtStack());
|
||||||
List<ChartViewFieldDTO> extBubble = new ArrayList<>(view.getExtBubble());
|
List<ChartViewFieldDTO> extBubble = new ArrayList<>(view.getExtBubble());
|
||||||
if (ObjectUtils.isNotEmpty(view.getExtLabel()) && enableExtData(view.getType())) {
|
if (ObjectUtils.isNotEmpty(view.getExtLabel()) && enableExtData(view.getType())) {
|
||||||
@ -753,6 +783,8 @@ public class ChartDataManage {
|
|||||||
mapChart = ChartDataBuild.transLabelChartData(xAxis, yAxis, view, data, isDrill);
|
mapChart = ChartDataBuild.transLabelChartData(xAxis, yAxis, view, data, isDrill);
|
||||||
} else if (StringUtils.containsIgnoreCase(view.getType(), "quadrant")) {
|
} else if (StringUtils.containsIgnoreCase(view.getType(), "quadrant")) {
|
||||||
mapChart = ChartDataBuild.transQuadrantDataAntV(xAxis, yAxis, view, data, extBubble, isDrill);
|
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 {
|
} else {
|
||||||
mapChart = ChartDataBuild.transChartDataAntV(xAxis, yAxis, view, data, isDrill);
|
mapChart = ChartDataBuild.transChartDataAntV(xAxis, yAxis, view, data, isDrill);
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
package io.dataease.chart.utils;
|
package io.dataease.chart.utils;
|
||||||
|
|
||||||
import io.dataease.api.chart.dto.*;
|
import io.dataease.api.chart.dto.*;
|
||||||
|
import io.dataease.i18n.Lang;
|
||||||
|
import io.dataease.i18n.Translator;
|
||||||
import io.dataease.utils.IDUtils;
|
import io.dataease.utils.IDUtils;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -1323,4 +1327,268 @@ public class ChartDataBuild {
|
|||||||
return map;
|
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_schema_is_empty=Schema is empty!
|
||||||
i18n_table_name_repeat=Has duplicate name:
|
i18n_table_name_repeat=Has duplicate name:
|
||||||
i18n_sql_not_empty=SQL cannot be empty!
|
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_menu.parameter=\u7CFB\u7EDF\u53C2\u6570
|
||||||
i18n_user_old_pwd_error=\u539F\u59CB\u5BC6\u7801\u9519\u8BEF
|
i18n_user_old_pwd_error=\u539F\u59CB\u5BC6\u7801\u9519\u8BEF
|
||||||
i18n_menu.toolbox-log=\u64CD\u4F5C\u65E5\u5FD7
|
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_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_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_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
|
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_error_login_type=\u767B\u9304\u985E\u578B\u932F\u8AA4
|
||||||
i18n_schema_is_empty=schema\u70BA\u7A7A\uFF01
|
i18n_schema_is_empty=schema\u70BA\u7A7A\uFF01
|
||||||
i18n_table_name_repeat=\u540D\u7A31\u91CD\u8907:
|
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: '数据预览',
|
data_preview: '数据预览',
|
||||||
dimension: '维度',
|
dimension: '维度',
|
||||||
quota: '指标',
|
quota: '指标',
|
||||||
|
time_dimension_or_quota: '时间维度或指标',
|
||||||
|
aggregate_time: '聚合时间纬度',
|
||||||
title: '标题',
|
title: '标题',
|
||||||
show: '显示',
|
show: '显示',
|
||||||
chart_type: '图表类型',
|
chart_type: '图表类型',
|
||||||
@ -678,6 +680,7 @@ export default {
|
|||||||
chart_bar_horizontal: '横向柱状图',
|
chart_bar_horizontal: '横向柱状图',
|
||||||
chart_bar_stack_horizontal: '横向堆叠柱状图',
|
chart_bar_stack_horizontal: '横向堆叠柱状图',
|
||||||
chart_percentage_bar_stack_horizontal: '横向百分比柱状图',
|
chart_percentage_bar_stack_horizontal: '横向百分比柱状图',
|
||||||
|
chart_bar_range: '区间条形图',
|
||||||
chart_line: '基础折线图',
|
chart_line: '基础折线图',
|
||||||
chart_area_stack: '堆叠折线图',
|
chart_area_stack: '堆叠折线图',
|
||||||
chart_pie: '饼图',
|
chart_pie: '饼图',
|
||||||
@ -760,6 +763,8 @@ export default {
|
|||||||
chart_style: '样式',
|
chart_style: '样式',
|
||||||
drag_block_type_axis: '类别轴',
|
drag_block_type_axis: '类别轴',
|
||||||
drag_block_value_axis: '值轴',
|
drag_block_value_axis: '值轴',
|
||||||
|
drag_block_value_start: '开始值',
|
||||||
|
drag_block_value_end: '结束值',
|
||||||
drag_block_value_axis_left: '左值轴',
|
drag_block_value_axis_left: '左值轴',
|
||||||
drag_block_value_axis_right: '右值轴',
|
drag_block_value_axis_right: '右值轴',
|
||||||
drag_block_table_data_column: '数据列',
|
drag_block_table_data_column: '数据列',
|
||||||
@ -939,6 +944,7 @@ export default {
|
|||||||
value_formatter_unit: '数量单位',
|
value_formatter_unit: '数量单位',
|
||||||
value_formatter_decimal_count: '小数位数',
|
value_formatter_decimal_count: '小数位数',
|
||||||
value_formatter_suffix: '单位后缀',
|
value_formatter_suffix: '单位后缀',
|
||||||
|
show_gap: '显示间隔值',
|
||||||
indicator_suffix_placeholder: '请输入1-10个字符',
|
indicator_suffix_placeholder: '请输入1-10个字符',
|
||||||
indicator_suffix: '后缀',
|
indicator_suffix: '后缀',
|
||||||
indicator_value: '指标值',
|
indicator_value: '指标值',
|
||||||
@ -1101,6 +1107,8 @@ export default {
|
|||||||
error_not_number: '不支持拖拽非数值类型指标',
|
error_not_number: '不支持拖拽非数值类型指标',
|
||||||
error_q_2_d: '不支持拖拽指标至维度',
|
error_q_2_d: '不支持拖拽指标至维度',
|
||||||
error_d_2_q: '不支持拖拽维度至指标',
|
error_d_2_q: '不支持拖拽维度至指标',
|
||||||
|
error_d_not_time_2_q: '不支持拖拽非时间类型的维度',
|
||||||
|
error_bar_range_axis_type_not_equal: '开始值与结束值需要设置相同类型',
|
||||||
only_input_number: '请输入正确数值',
|
only_input_number: '请输入正确数值',
|
||||||
value_min_max_invalid: '最小值必须小于最大值',
|
value_min_max_invalid: '最小值必须小于最大值',
|
||||||
add_assist_line: '添加辅助线',
|
add_assist_line: '添加辅助线',
|
||||||
|
@ -659,6 +659,8 @@ declare interface ChartLabelAttr {
|
|||||||
* 多系列标签设置
|
* 多系列标签设置
|
||||||
*/
|
*/
|
||||||
seriesLabelFormatter: SeriesFormatter[]
|
seriesLabelFormatter: SeriesFormatter[]
|
||||||
|
|
||||||
|
showGap?: boolean
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 提示设置
|
* 提示设置
|
||||||
@ -690,6 +692,8 @@ declare interface ChartTooltipAttr {
|
|||||||
* 多系列提示设置
|
* 多系列提示设置
|
||||||
*/
|
*/
|
||||||
seriesTooltipFormatter: SeriesFormatter[]
|
seriesTooltipFormatter: SeriesFormatter[]
|
||||||
|
|
||||||
|
showGap?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,6 +40,7 @@ declare interface Chart {
|
|||||||
resultCount: number
|
resultCount: number
|
||||||
linkageActive: boolean
|
linkageActive: boolean
|
||||||
jumpActive: boolean
|
jumpActive: boolean
|
||||||
|
aggregate?: boolean
|
||||||
}
|
}
|
||||||
declare type CustomAttr = DeepPartial<ChartAttr> | JSONString<DeepPartial<ChartAttr>>
|
declare type CustomAttr = DeepPartial<ChartAttr> | JSONString<DeepPartial<ChartAttr>>
|
||||||
declare type CustomStyle = DeepPartial<ChartStyle> | JSONString<DeepPartial<ChartStyle>>
|
declare type CustomStyle = DeepPartial<ChartStyle> | JSONString<DeepPartial<ChartStyle>>
|
||||||
|
@ -110,6 +110,7 @@ const sort = param => {
|
|||||||
item.value.index = props.index
|
item.value.index = props.index
|
||||||
item.value.sort = param.type
|
item.value.sort = param.type
|
||||||
item.value.customSort = []
|
item.value.customSort = []
|
||||||
|
delete item.value.axisType
|
||||||
emit('onDimensionItemChange', item.value)
|
emit('onDimensionItemChange', item.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,6 +123,7 @@ const beforeSort = type => {
|
|||||||
|
|
||||||
const dateStyle = param => {
|
const dateStyle = param => {
|
||||||
item.value.dateStyle = param.type
|
item.value.dateStyle = param.type
|
||||||
|
item.value.axisType = props.type
|
||||||
emit('onDimensionItemChange', item.value)
|
emit('onDimensionItemChange', item.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,6 +135,7 @@ const beforeDateStyle = type => {
|
|||||||
|
|
||||||
const datePattern = param => {
|
const datePattern = param => {
|
||||||
item.value.datePattern = param.type
|
item.value.datePattern = param.type
|
||||||
|
item.value.axisType = props.type
|
||||||
emit('onDimensionItemChange', item.value)
|
emit('onDimensionItemChange', item.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,8 +204,23 @@ const showSeriesLabelFormatter = computed(() => {
|
|||||||
})
|
})
|
||||||
const showDivider = computed(() => {
|
const showDivider = computed(() => {
|
||||||
const DIVIDER_PROPS = ['labelFormatter', 'showDimension', 'showQuota', 'showProportion']
|
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(() => {
|
onMounted(() => {
|
||||||
init()
|
init()
|
||||||
})
|
})
|
||||||
@ -329,7 +344,7 @@ onMounted(() => {
|
|||||||
:class="{ 'divider-dark': themes === 'dark' }"
|
:class="{ 'divider-dark': themes === 'dark' }"
|
||||||
v-if="showDivider"
|
v-if="showDivider"
|
||||||
/>
|
/>
|
||||||
<template v-if="showProperty('labelFormatter')">
|
<template v-if="showProperty('labelFormatter') && !isBarRangeTime">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="$t('chart.value_formatter_type')"
|
:label="$t('chart.value_formatter_type')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -803,6 +818,15 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</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>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -151,6 +151,21 @@ const aggregationList = computed(() => {
|
|||||||
}
|
}
|
||||||
return AGGREGATION_TYPE
|
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(
|
watch(
|
||||||
[() => props.chart.customAttr.tooltip, () => props.chart.customAttr.tooltip.show],
|
[() => props.chart.customAttr.tooltip, () => props.chart.customAttr.tooltip.show],
|
||||||
() => {
|
() => {
|
||||||
@ -425,7 +440,7 @@ onMounted(() => {
|
|||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-space>
|
</el-space>
|
||||||
<template v-if="showProperty('tooltipFormatter')">
|
<template v-if="showProperty('tooltipFormatter') && !isBarRangeTime">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="t('chart.value_formatter_type')"
|
:label="t('chart.value_formatter_type')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -707,6 +722,15 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</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>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -52,6 +52,20 @@ const fontSizeList = computed(() => {
|
|||||||
return arr
|
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 => {
|
const changeAxisStyle = prop => {
|
||||||
if (
|
if (
|
||||||
state.axisForm.axisValue.splitCount &&
|
state.axisForm.axisValue.splitCount &&
|
||||||
@ -374,7 +388,7 @@ onMounted(() => {
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<template v-if="showProperty('axisLabelFormatter')">
|
<template v-if="showProperty('axisLabelFormatter') && !isBarRangeTime">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
class="form-item"
|
class="form-item"
|
||||||
:class="'form-item-' + themes"
|
:class="'form-item-' + themes"
|
||||||
|
@ -300,9 +300,22 @@ const startToMove = (e, item) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const dimensionItemChange = () => {
|
const dimensionItemChange = item => {
|
||||||
recordSnapshotInfo('calcData')
|
recordSnapshotInfo('calcData')
|
||||||
// do dimensionItemChange
|
// 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 => {
|
const dimensionItemRemove = item => {
|
||||||
recordSnapshotInfo('calcData')
|
recordSnapshotInfo('calcData')
|
||||||
@ -312,6 +325,10 @@ const dimensionItemRemove = item => {
|
|||||||
view.value.xAxisExt.splice(item.index, 1)
|
view.value.xAxisExt.splice(item.index, 1)
|
||||||
} else if (item.removeType === 'dimensionStack') {
|
} else if (item.removeType === 'dimensionStack') {
|
||||||
view.value.extStack.splice(item.index, 1)
|
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
|
// do quotaItemChange
|
||||||
emitter.emit('updateAxis', { axisType, axis: [axis], editType: 'update' })
|
emitter.emit('updateAxis', { axisType, axis: [axis], editType: 'update' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const aggregateChange = () => {
|
||||||
|
recordSnapshotInfo('calcData')
|
||||||
|
}
|
||||||
|
|
||||||
const quotaItemRemove = item => {
|
const quotaItemRemove = item => {
|
||||||
recordSnapshotInfo('calcData')
|
recordSnapshotInfo('calcData')
|
||||||
let axisType: AxisType = item.removeType
|
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) => {
|
const addAxis = (e, axis: AxisType) => {
|
||||||
recordSnapshotInfo('calcData')
|
recordSnapshotInfo('calcData')
|
||||||
const axisSpec = chartViewInstance.value.axisConfig[axis]
|
const axisSpec = chartViewInstance.value.axisConfig[axis]
|
||||||
@ -450,9 +486,30 @@ const addAxis = (e, axis: AxisType) => {
|
|||||||
}
|
}
|
||||||
const { type, limit, duplicate } = axisSpec
|
const { type, limit, duplicate } = axisSpec
|
||||||
let typeValid, dup
|
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)
|
typeValid = dragCheckType(view.value[axis], type)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 针对指标卡进行数值类型判断
|
// 针对指标卡进行数值类型判断
|
||||||
if (typeValid && type === 'q' && view.value.type === 'indicator') {
|
if (typeValid && type === 'q' && view.value.type === 'indicator') {
|
||||||
const list = view.value[axis]
|
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 (typeValid && view.value.type === 'bar-range') {
|
||||||
if (view.value?.yAxis?.length > 1) {
|
//处理某一个轴有数据的情况
|
||||||
const axis = view.value.yAxis.splice(1)
|
let tempType = null
|
||||||
emitter.emit('removeAxis', { axisType: 'yAxis', axis, editType: 'remove' })
|
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 (tempType !== null) {
|
||||||
if (view.value.type === 'chart-mix') {
|
const list = view.value[axis]
|
||||||
if (view.value?.yAxisExt?.length > 1) {
|
if (list && list.length > 0) {
|
||||||
const axis = view.value.yAxisExt.splice(1)
|
let valid = true
|
||||||
emitter.emit('removeAxis', { axisType: 'yAxisExt', axis, editType: 'remove' })
|
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>
|
</div>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<!--yAxis-->
|
<template v-if="view.type !== 'bar-range'">
|
||||||
<el-row class="padding-lr drag-data" v-if="showAxis('yAxis')">
|
<!--yAxis-->
|
||||||
<div class="form-draggable-title">
|
<el-row class="padding-lr drag-data" v-if="showAxis('yAxis')">
|
||||||
<span>
|
<div class="form-draggable-title">
|
||||||
{{ chartViewInstance.axisConfig.yAxis.name }}
|
<span>
|
||||||
</span>
|
{{ chartViewInstance.axisConfig.yAxis.name }}
|
||||||
<el-tooltip :effect="toolTip" placement="top" :content="t('common.delete')">
|
</span>
|
||||||
<el-icon
|
<el-tooltip
|
||||||
class="remove-icon"
|
:effect="toolTip"
|
||||||
:class="{ 'remove-icon--dark': themes === 'dark' }"
|
placement="top"
|
||||||
size="14px"
|
:content="t('common.delete')"
|
||||||
@click="removeItems('yAxis')"
|
|
||||||
>
|
>
|
||||||
<Icon class-name="inner-class" name="icon_delete-trash_outlined" />
|
<el-icon
|
||||||
</el-icon>
|
class="remove-icon"
|
||||||
</el-tooltip>
|
:class="{ 'remove-icon--dark': themes === 'dark' }"
|
||||||
</div>
|
size="14px"
|
||||||
<div
|
@click="removeItems('yAxis')"
|
||||||
@drop="$event => drop($event, 'yAxis')"
|
>
|
||||||
@dragenter="dragEnter"
|
<Icon class-name="inner-class" name="icon_delete-trash_outlined" />
|
||||||
@dragover="$event => dragOver($event)"
|
</el-icon>
|
||||||
>
|
</el-tooltip>
|
||||||
<draggable
|
</div>
|
||||||
:list="view.yAxis"
|
<div
|
||||||
:move="onMove"
|
@drop="$event => drop($event, 'yAxis')"
|
||||||
item-key="id"
|
@dragenter="dragEnter"
|
||||||
group="drag"
|
@dragover="$event => dragOver($event)"
|
||||||
animation="300"
|
|
||||||
class="drag-block-style"
|
|
||||||
:class="{ dark: themes === 'dark' }"
|
|
||||||
@add="addYaxis"
|
|
||||||
@change="e => onAxisChange(e, 'yAxis')"
|
|
||||||
>
|
>
|
||||||
<template #item="{ element, index }">
|
<draggable
|
||||||
<quota-item
|
:list="view.yAxis"
|
||||||
:dimension-data="state.dimension"
|
:move="onMove"
|
||||||
:quota-data="state.quota"
|
item-key="id"
|
||||||
:chart="view"
|
group="drag"
|
||||||
:item="element"
|
animation="300"
|
||||||
:index="index"
|
class="drag-block-style"
|
||||||
type="quota"
|
:class="{ dark: themes === 'dark' }"
|
||||||
:themes="props.themes"
|
@add="addYaxis"
|
||||||
@onQuotaItemChange="item => quotaItemChange(item, 'yAxis')"
|
@change="e => onAxisChange(e, '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" />
|
<template #item="{ element, index }">
|
||||||
</el-icon>
|
<quota-item
|
||||||
</el-tooltip>
|
:dimension-data="state.dimension"
|
||||||
</div>
|
:quota-data="state.quota"
|
||||||
<div
|
:chart="view"
|
||||||
@drop="$event => drop($event, 'yAxisExt')"
|
:item="element"
|
||||||
@dragenter="dragEnter"
|
:index="index"
|
||||||
@dragover="$event => dragOver($event)"
|
type="quota"
|
||||||
>
|
:themes="props.themes"
|
||||||
<draggable
|
@onQuotaItemChange="item => quotaItemChange(item, 'yAxis')"
|
||||||
:list="view.yAxisExt"
|
@onQuotaItemRemove="quotaItemRemove"
|
||||||
:move="onMove"
|
@onNameEdit="showRename"
|
||||||
item-key="id"
|
@editItemFilter="showQuotaEditFilter"
|
||||||
group="drag"
|
@editItemCompare="showQuotaEditCompare"
|
||||||
animation="300"
|
@valueFormatter="valueFormatter"
|
||||||
class="drag-block-style"
|
/>
|
||||||
:class="{ dark: themes === 'dark' }"
|
</template>
|
||||||
@add="addYaxisExt"
|
</draggable>
|
||||||
@change="e => onAxisChange(e, 'yAxisExt')"
|
<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 }">
|
<draggable
|
||||||
<quota-item
|
:list="view.yAxisExt"
|
||||||
:dimension-data="state.dimension"
|
:move="onMove"
|
||||||
:quota-data="state.quota"
|
item-key="id"
|
||||||
:chart="view"
|
group="drag"
|
||||||
:item="element"
|
animation="300"
|
||||||
:index="index"
|
class="drag-block-style"
|
||||||
type="quotaExt"
|
:class="{ dark: themes === 'dark' }"
|
||||||
:themes="props.themes"
|
@add="addYaxisExt"
|
||||||
@onQuotaItemChange="item => quotaItemChange(item, 'yAxisExt')"
|
@change="e => onAxisChange(e, 'yAxisExt')"
|
||||||
@onQuotaItemRemove="quotaItemRemove"
|
>
|
||||||
@onNameEdit="showRename"
|
<template #item="{ element, index }">
|
||||||
@editItemFilter="showQuotaEditFilter"
|
<quota-item
|
||||||
@editItemCompare="showQuotaEditCompare"
|
:dimension-data="state.dimension"
|
||||||
@valueFormatter="valueFormatter"
|
:quota-data="state.quota"
|
||||||
/>
|
:chart="view"
|
||||||
</template>
|
:item="element"
|
||||||
</draggable>
|
:index="index"
|
||||||
<drag-placeholder :drag-list="view.yAxisExt" />
|
type="quotaExt"
|
||||||
</div>
|
:themes="props.themes"
|
||||||
</el-row>
|
@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 -->
|
<!-- extBubble -->
|
||||||
<el-row class="padding-lr drag-data" v-if="showAxis('extBubble')">
|
<el-row class="padding-lr drag-data" v-if="showAxis('extBubble')">
|
||||||
<div class="form-draggable-title">
|
<div class="form-draggable-title">
|
||||||
@ -1955,6 +2194,22 @@ const drop = (ev: MouseEvent, type = 'xAxis') => {
|
|||||||
<drag-placeholder :drag-list="view.customFilter" />
|
<drag-placeholder :drag-list="view.customFilter" />
|
||||||
</div>
|
</div>
|
||||||
</el-row>
|
</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-scrollbar>
|
||||||
<el-footer :class="{ 'refresh-active-footer': view.refreshViewEnable }">
|
<el-footer :class="{ 'refresh-active-footer': view.refreshViewEnable }">
|
||||||
<el-row class="refresh-area">
|
<el-row class="refresh-area">
|
||||||
|
@ -1198,6 +1198,13 @@ export const CHART_TYPE_CONFIGS = [
|
|||||||
value: 'percentage-bar-stack-horizontal',
|
value: 'percentage-bar-stack-horizontal',
|
||||||
title: t('chart.chart_percentage_bar_stack_horizontal'),
|
title: t('chart.chart_percentage_bar_stack_horizontal'),
|
||||||
icon: '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',
|
'jump-set',
|
||||||
'linkage'
|
'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 = {
|
export const BAR_EDITOR_PROPERTY_INNER: EditorPropertyInner = {
|
||||||
'background-overall-component': ['all'],
|
'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'],
|
...this['axisConfig'],
|
||||||
yAxis: {
|
yAxis: {
|
||||||
name: `${t('chart.drag_block_value_axis_left')} / ${t('chart.quota')}`,
|
name: `${t('chart.drag_block_value_axis_left')} / ${t('chart.quota')}`,
|
||||||
|
limit: 1,
|
||||||
type: 'q'
|
type: 'q'
|
||||||
},
|
},
|
||||||
yAxisExt: {
|
yAxisExt: {
|
||||||
name: `${t('chart.drag_block_value_axis_right')} / ${t('chart.quota')}`,
|
name: `${t('chart.drag_block_value_axis_right')} / ${t('chart.quota')}`,
|
||||||
|
limit: 1,
|
||||||
type: 'q'
|
type: 'q'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ export class IndicatorChartView extends AbstractChartView {
|
|||||||
axisConfig: AxisConfig = {
|
axisConfig: AxisConfig = {
|
||||||
yAxis: {
|
yAxis: {
|
||||||
name: `${t('chart.quota')}`,
|
name: `${t('chart.quota')}`,
|
||||||
|
limit: 1,
|
||||||
type: 'q'
|
type: 'q'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,8 +226,12 @@ const trackClick = trackAction => {
|
|||||||
if (state.pointParam.data.dimensionList.length > 1) {
|
if (state.pointParam.data.dimensionList.length > 1) {
|
||||||
checkName = state.pointParam.data.dimensionList[0].id
|
checkName = state.pointParam.data.dimensionList[0].id
|
||||||
}
|
}
|
||||||
const quotaList = state.pointParam.data.quotaList
|
let quotaList = state.pointParam.data.quotaList
|
||||||
quotaList[0]['value'] = state.pointParam.data.value
|
if (curView.type === 'bar-range') {
|
||||||
|
quotaList = state.pointParam.data.dimensionList
|
||||||
|
} else {
|
||||||
|
quotaList[0]['value'] = state.pointParam.data.value
|
||||||
|
}
|
||||||
const linkageParam = {
|
const linkageParam = {
|
||||||
option: 'linkage',
|
option: 'linkage',
|
||||||
name: checkName,
|
name: checkName,
|
||||||
|
@ -202,4 +202,9 @@ public class ChartViewBaseDTO implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private Boolean jumpActive;
|
private Boolean jumpActive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 区间条形图开启时间纬度开启聚合
|
||||||
|
*/
|
||||||
|
private Boolean aggregate;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user