sea-chart 2.0.25 → 2.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  .sea-chart-d3-tooltip-container {
2
2
  position: absolute;
3
3
  transform: translate(-9999px, -9999px);
4
- transition: transform 0.2s;
4
+ transition: transform 0.1s;
5
5
  background-color: rgb(255, 255, 255);
6
6
  box-shadow: rgba(196, 175, 175, 0.1) 0px 0px 1px 1px;
7
7
  border-radius: 3px;
@@ -68,7 +68,8 @@ const ToolTip = _ref => {
68
68
  ref: tooltipRef,
69
69
  className: "sea-chart-d3-tooltip-container",
70
70
  style: {
71
- transform: "translate(".concat(position.offsetX, "px, ").concat(position.offsetY, "px)")
71
+ transform: "translate(".concat(position.offsetX, "px, ").concat(position.offsetY, "px)"),
72
+ display: position.offsetX === -9999 ? 'none' : 'block'
72
73
  }
73
74
  }, title && /*#__PURE__*/_react.default.createElement("div", {
74
75
  className: "sea-chart-d3-tooltip-title"
@@ -69,7 +69,9 @@ const TypesDialog = _ref => {
69
69
  }, [onChange, selectedType, onToggle]);
70
70
  const handleFilterTypes = (0, _react.useCallback)(() => {
71
71
  if (hideTypeToggle) {
72
- const newChartTypes = _constants.CHART_TYPES.filter(item => ['Histogram', 'Bar_chart', 'Line_chart', 'Area', 'Pie_chart', 'Scatter_chart', 'Combination_chart'].includes(item.name));
72
+ const newChartTypes = _constants.CHART_TYPES.filter(item => ['Histogram', 'Bar_chart', 'Line_chart', 'Area', 'Pie_chart', 'Scatter_chart', 'Combination_chart', 'Map'].includes(item.name));
73
+ const newMapChildren = newChartTypes[newChartTypes.length - 1].children.slice(0, 2);
74
+ newChartTypes[newChartTypes.length - 1].children = newMapChildren;
73
75
  return newChartTypes;
74
76
  }
75
77
  return _constants.CHART_TYPES;
@@ -75,7 +75,7 @@ function getMapJsonQueryUrl(mapLevel, mapLocation) {
75
75
  }
76
76
  }
77
77
  function handleLoadedMapJson(url, mapJson) {
78
- const isValid = mapJson && mapJson.features;
78
+ const isValid = mapJson && ((mapJson === null || mapJson === void 0 ? void 0 : mapJson.type) === 'Topology' && (mapJson === null || mapJson === void 0 ? void 0 : mapJson.objects) || (mapJson === null || mapJson === void 0 ? void 0 : mapJson.type) === 'FeatureCollection' && (mapJson === null || mapJson === void 0 ? void 0 : mapJson.features));
79
79
  if (isValid) {
80
80
  setMapJson(url, mapJson);
81
81
  return mapJson;
@@ -645,22 +645,62 @@ class ChartComponent extends _react.Component {
645
645
  return _intl.default.get(name) || name;
646
646
  }
647
647
  };
648
- this.sortLegend = (result, groupColumn, legendName) => {
649
- result.forEach(item => {
650
- const option = groupColumn.data.options.find(option => option.name === item[legendName]);
651
- if (option !== null && option !== void 0 && option.id) {
652
- item['group_name_id'] = option.id;
653
- item['oldName'] = item.name;
654
- item.name = item['group_name_id'];
648
+ // set continuous legend
649
+ this.setContinuousLegend = _ref => {
650
+ var _this$chart$node2;
651
+ let {
652
+ previewType,
653
+ theme,
654
+ colorRange = [],
655
+ legendDirection,
656
+ legendSize,
657
+ legendTextRange,
658
+ bubbleColor,
659
+ type
660
+ } = _ref;
661
+ const {
662
+ width: chartWidth,
663
+ height: chartHeight,
664
+ insertPadding
665
+ } = this.chartBoundingClientRect;
666
+ const legendRectWidth = legendDirection === 'vertical' ? 12 : Math.min(legendSize * 100, chartWidth - insertPadding * 2);
667
+ const legendRectHeight = legendDirection === 'vertical' ? Math.min(legendSize * 100, chartHeight - insertPadding * 2) : 12;
668
+ const legendTextOffset = 2;
669
+ const legendTextHeightSpace = legendDirection === 'vertical' ? 0 : 14 + legendTextOffset;
670
+ if (type !== _constants.CHART_TYPE.MAP_BUBBLE) {
671
+ var _this$chart$node;
672
+ // add linearGradient
673
+ const gradient = this.chart.append('defs').attr('class', 'linear-gradient-wrapper').append('linearGradient').attr("id", "gradient-".concat((_this$chart$node = this.chart.node()) === null || _this$chart$node === void 0 ? void 0 : _this$chart$node.id, "-").concat(previewType)).attr("x1", '0%').attr("y1", '0%').attr("x2", legendDirection === 'vertical' ? '0%' : '100%').attr("y2", legendDirection === 'vertical' ? '100%' : '0%');
674
+ gradient.append('stop').attr('offset', '0%').attr('stop-color', "".concat(colorRange[0]));
675
+ gradient.append('stop').attr('offset', '50%').attr('stop-color', "".concat(colorRange[4]));
676
+ gradient.append('stop').attr('offset', '100%').attr('stop-color', "".concat(colorRange[8]));
677
+ }
678
+
679
+ // add legend
680
+ const continuousLegendWrapper = this.chart.append('g').attr('class', 'legend-continuous-wrapper').attr('transform', "translate(".concat(insertPadding, ", ").concat(chartHeight - legendRectHeight - legendTextHeightSpace, ")"));
681
+ continuousLegendWrapper.append('rect').attr('width', legendRectWidth).attr('height', legendRectHeight).attr('fill', type === _constants.CHART_TYPE.MAP_BUBBLE ? bubbleColor : "url(#gradient-".concat((_this$chart$node2 = this.chart.node()) === null || _this$chart$node2 === void 0 ? void 0 : _this$chart$node2.id, "-").concat(previewType, ")")).call(g => {
682
+ if (type === _constants.CHART_TYPE.MAP_BUBBLE) {
683
+ continuousLegendWrapper.append('polygon').attr('points', "0,0 ".concat(legendRectWidth - 0.5, ",0 0,").concat(legendRectHeight - 0.5)).attr('fill', '#fff').attr('stroke', '#fff');
655
684
  }
656
685
  });
657
- _utils.BaseUtils.sortCharts(result, groupColumn, 'name');
658
- result.forEach(item => {
659
- item.name = item['oldName'];
686
+ continuousLegendWrapper.append('text').attr('class', 'range-start').attr('stroke', '#fff').attr('stroke-width', 1).attr('paint-order', 'stroke').attr('fill', theme.labelColor).text(legendTextRange[0]).call(g => {
687
+ const {
688
+ height
689
+ } = g.node().getBoundingClientRect();
690
+ g.attr('x', legendDirection === 'vertical' ? legendRectWidth + legendTextOffset : legendTextOffset);
691
+ g.attr('y', legendDirection === 'vertical' ? height : height + legendRectHeight);
692
+ });
693
+ continuousLegendWrapper.append('text').attr('class', 'range-end').attr('stroke', '#fff').attr('stroke-width', 1).attr('paint-order', 'stroke').attr('fill', theme.labelColor).text(legendTextRange[1]).call(g => {
694
+ const {
695
+ width,
696
+ height
697
+ } = g.node().getBoundingClientRect();
698
+ g.attr('x', legendDirection === 'vertical' ? legendRectWidth + legendTextOffset : legendRectWidth - width);
699
+ g.attr('y', legendDirection === 'vertical' ? legendRectHeight - legendTextOffset : height + legendRectHeight);
660
700
  });
661
701
  };
662
702
  // set legend
663
- this.setLegend = _ref => {
703
+ this.setLegend = _ref2 => {
664
704
  var _chart$config, _chart$config2, _chart$config3;
665
705
  let {
666
706
  legendName,
@@ -670,7 +710,7 @@ class ChartComponent extends _react.Component {
670
710
  colorScale,
671
711
  groupColumn,
672
712
  chart
673
- } = _ref;
713
+ } = _ref2;
674
714
  if (!this.chart) return;
675
715
  this.legendConfig = {
676
716
  legendRectWidth: (chart === null || chart === void 0 ? void 0 : (_chart$config = chart.config) === null || _chart$config === void 0 ? void 0 : _chart$config.type) === _constants.CHART_TYPE.SCATTER ? 8 : 20,
@@ -698,6 +738,7 @@ class ChartComponent extends _react.Component {
698
738
  bottomLegendSpace
699
739
  } = this.chartBoundingClientRect;
700
740
  const groupsData = this.getLegendDataGroups(legendData);
741
+ if (groupsData.length === 0) return;
701
742
  const legendWrapper = this.chart.append('g').attr('class', 'legend-wrapper');
702
743
 
703
744
  // legend offset bottom and When there is only one line of legend, it is displayed in the center (for scatter chart)
@@ -788,14 +829,14 @@ class ChartComponent extends _react.Component {
788
829
  });
789
830
  }
790
831
  };
791
- this.renderLegend = _ref2 => {
832
+ this.renderLegend = _ref3 => {
792
833
  let {
793
834
  legendWrapper,
794
835
  groupData,
795
836
  colorScale,
796
837
  theme,
797
838
  text
798
- } = _ref2;
839
+ } = _ref3;
799
840
  const {
800
841
  legendItemPaddingTop,
801
842
  legendItemTextPaddingTop,
@@ -821,15 +862,15 @@ class ChartComponent extends _react.Component {
821
862
  d3.select(item).remove();
822
863
  });
823
864
  }
824
- legendWrapper.selectAll().data(groupData).join('g').attr('data-groupName', _ref3 => {
825
- let [groupName] = _ref3;
826
- return groupName;
827
- }).append('rect').attr('width', legendRectWidth).attr('height', legendRectHeight).attr('y', legendItemPaddingTop).attr('rx', r).attr('fill', _ref4 => {
865
+ legendWrapper.selectAll().data(groupData).join('g').attr('data-groupName', _ref4 => {
828
866
  let [groupName] = _ref4;
867
+ return groupName;
868
+ }).append('rect').attr('width', legendRectWidth).attr('height', legendRectHeight).attr('y', legendItemPaddingTop).attr('rx', r).attr('fill', _ref5 => {
869
+ let [groupName] = _ref5;
829
870
  if (colorScale) return colorScale(groupName);
830
871
  return this.colorMap[groupName] || _constants.CHART_STYLE_COLORS[0];
831
- }).attr('data-text', _ref5 => {
832
- let [groupName] = _ref5;
872
+ }).attr('data-text', _ref6 => {
873
+ let [groupName] = _ref6;
833
874
  return groupName;
834
875
  }).call(g => {
835
876
  // Add text
@@ -1021,6 +1062,20 @@ class ChartComponent extends _react.Component {
1021
1062
  d3.select(legendItem).attr('opacity', 1);
1022
1063
  });
1023
1064
  };
1065
+ this.sortLegend = (result, groupColumn, legendName) => {
1066
+ result.forEach(item => {
1067
+ const option = groupColumn.data.options.find(option => option.name === item[legendName]);
1068
+ if (option !== null && option !== void 0 && option.id) {
1069
+ item['group_name_id'] = option.id;
1070
+ item['oldName'] = item.name;
1071
+ item.name = item['group_name_id'];
1072
+ }
1073
+ });
1074
+ _utils.BaseUtils.sortCharts(result, groupColumn, 'name');
1075
+ result.forEach(item => {
1076
+ item.name = item['oldName'];
1077
+ });
1078
+ };
1024
1079
  // theta is pie or ring chart
1025
1080
  this.setLegendForTheta = function (legendName) {
1026
1081
  let theme = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _constants.CHART_THEME_COLOR['light'];
@@ -1080,6 +1135,30 @@ class ChartComponent extends _react.Component {
1080
1135
  });
1081
1136
  this.formatedDataByName = formattedItems;
1082
1137
  };
1138
+ this.formatMapStatisticData = (statisticData, mapData, type) => {
1139
+ if (!statisticData) return [];
1140
+ if (!mapData.features) return [];
1141
+ let statisticNewData = [];
1142
+ let sum = 0;
1143
+ statisticData.forEach((item, index) => {
1144
+ if (item && item.name) {
1145
+ let matchFeature = mapData.features.find(feature => feature.properties.name.indexOf(item.name) > -1);
1146
+ if (matchFeature) {
1147
+ statisticNewData.push({
1148
+ name: matchFeature.properties.name,
1149
+ value: item.value || 0
1150
+ });
1151
+ if (type === 'map_bubble') {
1152
+ sum += item.value;
1153
+ }
1154
+ }
1155
+ }
1156
+ });
1157
+ if (type === 'map_bubble') {
1158
+ statisticNewData.sum = sum;
1159
+ }
1160
+ return statisticNewData;
1161
+ };
1083
1162
  this.getToolTipSettings = (isGroup, summaryColumn, y_axis_summary_method, useSingleSelectColumnColor) => {
1084
1163
  const obj = {
1085
1164
  showMarkers: false,
@@ -1235,7 +1314,7 @@ class ChartComponent extends _react.Component {
1235
1314
  annotationWrapper.append('text').attr('x', chartWidth - insertPadding - 30).attr('y', yScale(goal_value) - 10).attr('fill', '#666').text(goal_label);
1236
1315
  });
1237
1316
  };
1238
- this.addLabelToRectTop = _ref6 => {
1317
+ this.addLabelToRectTop = _ref7 => {
1239
1318
  let {
1240
1319
  container,
1241
1320
  x,
@@ -1244,7 +1323,7 @@ class ChartComponent extends _react.Component {
1244
1323
  theme,
1245
1324
  label_font_size,
1246
1325
  text
1247
- } = _ref6;
1326
+ } = _ref7;
1248
1327
  d3.select(container).append('text').attr('stroke', '#fff').attr('stroke-width', 1).attr('paint-order', 'stroke').attr('y', Number(y) - 10).attr('fill', theme.labelColor).attr('font-size', _utils.BaseUtils.getLabelFontSize(label_font_size)).text(text).call(g => {
1249
1328
  const {
1250
1329
  width
@@ -1252,7 +1331,7 @@ class ChartComponent extends _react.Component {
1252
1331
  g.attr('x', Number(x) + Number(xWidth) / 2 - width / 2);
1253
1332
  });
1254
1333
  };
1255
- this.addLabelToRectRight = _ref7 => {
1334
+ this.addLabelToRectRight = _ref8 => {
1256
1335
  let {
1257
1336
  container,
1258
1337
  x,
@@ -1262,7 +1341,7 @@ class ChartComponent extends _react.Component {
1262
1341
  theme,
1263
1342
  label_font_size,
1264
1343
  text
1265
- } = _ref7;
1344
+ } = _ref8;
1266
1345
  d3.select(container).append('text').attr('stroke', '#fff').attr('stroke-width', 1).attr('paint-order', 'stroke').attr('x', Number(x) + Number(xWidth) + 10).attr('y', Number(y)).attr('fill', theme.labelColor).attr('dominant-baseline', 'hanging').attr('font-size', _utils.BaseUtils.getLabelFontSize(label_font_size)).text(text).call(g => {
1267
1346
  if (g.node()) {
1268
1347
  var _g$node;
@@ -1273,7 +1352,7 @@ class ChartComponent extends _react.Component {
1273
1352
  }
1274
1353
  });
1275
1354
  };
1276
- this.addLabelToRectCenter = _ref8 => {
1355
+ this.addLabelToRectCenter = _ref9 => {
1277
1356
  let {
1278
1357
  chartType,
1279
1358
  container,
@@ -1284,7 +1363,7 @@ class ChartComponent extends _react.Component {
1284
1363
  theme,
1285
1364
  label_font_size,
1286
1365
  text
1287
- } = _ref8;
1366
+ } = _ref9;
1288
1367
  d3.select(container).append('text').attr('stroke', '#fff').attr('stroke-width', 1).attr('paint-order', 'stroke').attr('fill', theme.labelColor).attr('font-size', _utils.BaseUtils.getLabelFontSize(label_font_size)).text(text).call(g => {
1289
1368
  const {
1290
1369
  width,
@@ -1326,13 +1405,13 @@ class ChartComponent extends _react.Component {
1326
1405
  }
1327
1406
  };
1328
1407
  // Use clipPath to make rectangle rounded corners
1329
- this.addClipPath = _ref9 => {
1408
+ this.addClipPath = _ref10 => {
1330
1409
  let {
1331
1410
  rect,
1332
1411
  parentNode,
1333
1412
  attr,
1334
1413
  rectId
1335
- } = _ref9;
1414
+ } = _ref10;
1336
1415
  const {
1337
1416
  borderRadius
1338
1417
  } = this.chartBoundingClientRect;
@@ -30,6 +30,8 @@ var _ring = _interopRequireDefault(require("./ring"));
30
30
  var _scatter = _interopRequireDefault(require("./scatter"));
31
31
  var _basicNumberCard = _interopRequireDefault(require("./basic-number-card"));
32
32
  var _combination = _interopRequireDefault(require("./combination"));
33
+ var _map = _interopRequireDefault(require("./map"));
34
+ var _mapBubble = _interopRequireDefault(require("./map-bubble"));
33
35
  var _trend = _interopRequireDefault(require("./trend"));
34
36
  var _tableElement = _interopRequireDefault(require("./table-element"));
35
37
  const Wrapper = _ref => {
@@ -251,6 +253,18 @@ const Wrapper = _ref => {
251
253
  canvasStyle: canvasStyle
252
254
  }));
253
255
  }
256
+ case _constants.CHART_TYPE.MAP:
257
+ {
258
+ return /*#__PURE__*/_react.default.createElement(_map.default, Object.assign({}, baseProps, {
259
+ canvasStyle: canvasStyle
260
+ }));
261
+ }
262
+ case _constants.CHART_TYPE.MAP_BUBBLE:
263
+ {
264
+ return /*#__PURE__*/_react.default.createElement(_mapBubble.default, Object.assign({}, baseProps, {
265
+ canvasStyle: canvasStyle
266
+ }));
267
+ }
254
268
  case _constants.CHART_TYPE.BASIC_NUMBER_CARD:
255
269
  {
256
270
  return /*#__PURE__*/_react.default.createElement(_basicNumberCard.default, Object.assign({}, baseProps, {
@@ -0,0 +1,268 @@
1
+ "use strict";
2
+
3
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
4
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = void 0;
9
+ var _react = _interopRequireDefault(require("react"));
10
+ var _propTypes = _interopRequireDefault(require("prop-types"));
11
+ var _lodashEs = require("lodash-es");
12
+ var d3 = _interopRequireWildcard(require("d3"));
13
+ var _topojson = require("topojson");
14
+ var _dtableUtils = require("dtable-utils");
15
+ var _constants = require("../../constants");
16
+ var _utils = require("../../utils");
17
+ var _context = _interopRequireDefault(require("../../context"));
18
+ var _mapJson = _interopRequireDefault(require("../../services/map-json"));
19
+ var _tooltip = _interopRequireDefault(require("../../components/tooltip"));
20
+ var _chartComponent = _interopRequireDefault(require("./chart-component"));
21
+ class MapBubble extends _chartComponent.default {
22
+ constructor(props) {
23
+ super(props);
24
+ this.handleResize = () => {
25
+ this.chart.node() && this.chart.node().remove();
26
+ this.createChart();
27
+ this.drawChart();
28
+ };
29
+ this.createChart = () => {
30
+ const {
31
+ chart
32
+ } = this.props;
33
+ const initConfig = {
34
+ insertPadding: 30
35
+ };
36
+ this.initChart(this.container, chart === null || chart === void 0 ? void 0 : chart.id, initConfig);
37
+ };
38
+ this.drawChart = async () => {
39
+ let {
40
+ result: data,
41
+ chart
42
+ } = this.props;
43
+ if (!Array.isArray(data)) return;
44
+ const {
45
+ map_location,
46
+ map_level = _constants.MAP_LEVEL.COUNTRY,
47
+ type
48
+ } = chart.config;
49
+ const mediaUrl = _context.default.getSetting('mediaUrl');
50
+ const mapJson = await (0, _mapJson.default)(map_level, map_location, mediaUrl);
51
+ if (!mapJson) return;
52
+ const statisticNewData = this.formatMapStatisticData(data, mapJson, type);
53
+ this.draw(statisticNewData, mapJson);
54
+ };
55
+ this.showTooltip = event => {
56
+ const title = event.currentTarget.getAttribute('data-name');
57
+ const value = Number(event.currentTarget.getAttribute('data-value'));
58
+ const {
59
+ offsetX,
60
+ offsetY
61
+ } = event;
62
+ const newTooltipData = {
63
+ title,
64
+ items: [{
65
+ color: '',
66
+ name: '数量',
67
+ value
68
+ }]
69
+ };
70
+ this.setState({
71
+ tooltipData: newTooltipData
72
+ });
73
+ this.setState({
74
+ toolTipPosition: {
75
+ offsetX,
76
+ offsetY
77
+ }
78
+ });
79
+ };
80
+ this.moveTooltip = event => {
81
+ const {
82
+ offsetX,
83
+ offsetY
84
+ } = event;
85
+ this.setState({
86
+ toolTipPosition: {
87
+ offsetX,
88
+ offsetY
89
+ }
90
+ });
91
+ };
92
+ this.hiddenTooltip = event => {
93
+ this.setState({
94
+ toolTipPosition: null
95
+ });
96
+ };
97
+ this.draw = (data, mapJson) => {
98
+ const {
99
+ chart,
100
+ globalTheme,
101
+ canvasStyle
102
+ } = this.props;
103
+ const theme = _constants.CHART_THEME_COLOR[globalTheme];
104
+ const {
105
+ map_level = _constants.MAP_LEVEL.COUNTRY,
106
+ legend_size,
107
+ legend_direction,
108
+ summary_method,
109
+ type,
110
+ bubble_color = '#2a67d1'
111
+ } = chart.config;
112
+ const {
113
+ width: chartWidth,
114
+ height: chartHeight,
115
+ insertPadding
116
+ } = this.chartBoundingClientRect;
117
+ const newMapData = map_level === _constants.MAP_LEVEL.COUNTRY ? (0, _topojson.feature)(mapJson, mapJson.objects) : mapJson;
118
+
119
+ // 1. Setting up projection
120
+ const projection = d3.geoMercator().fitSize([chartWidth - insertPadding, chartHeight - insertPadding], newMapData);
121
+
122
+ // 2. Generate a path based on projection
123
+ const pathGenerator = d3.geoPath(projection);
124
+
125
+ // 3. Rendering map
126
+ this.chart.append('g').attr('class', 'map-wrapper').selectAll().data(newMapData.features).join('g').append('path').attr('d', d => {
127
+ return pathGenerator(d);
128
+ }).attr('stroke-width', 1).attr('stroke', '#bdbdbd').attr('stroke-opacity', 1).attr('fill', '#e2e2e2').attr('opacity', 1).attr('data-name', d => d.properties.name);
129
+
130
+ // draw bubble circle
131
+ this.drawCircle(data, newMapData, pathGenerator);
132
+
133
+ // draw legend
134
+ const columnData = this.getColumnData();
135
+ this.setContinuousLegend({
136
+ previewType: canvasStyle.previewType,
137
+ theme,
138
+ legendDirection: legend_direction,
139
+ legendSize: legend_size,
140
+ legendTextRange: [_utils.BaseUtils.getSummaryValueDisplayString(columnData, d3.min(data, d => d.value), summary_method), _utils.BaseUtils.getSummaryValueDisplayString(columnData, d3.max(data, d => d.value), summary_method)],
141
+ type,
142
+ bubbleColor: bubble_color
143
+ });
144
+ };
145
+ this.handleAcitveAndInActiveState = (state, event, highlightedBorderColor) => {
146
+ if (state === 'active') {
147
+ d3.select(event.currentTarget).transition().duration(this.transitionDuration).attr('fill-opacity', 0.9);
148
+ return;
149
+ }
150
+ d3.select(event.currentTarget).transition().duration(this.transitionDuration).attr('fill-opacity', 0.6);
151
+ };
152
+ this.getColumnData = () => {
153
+ const {
154
+ chart
155
+ } = this.props;
156
+ const {
157
+ summary_type,
158
+ summary_column_key,
159
+ table_id
160
+ } = chart.config;
161
+ let columnData = _constants.DEFAULT_NUMBER_FORMAT_OBJECT;
162
+ if (summary_type === _constants.CHART_SUMMARY_TYPE.ADVANCED) {
163
+ const table = (0, _dtableUtils.getTableById)(table_id);
164
+ const summaryColumn = (0, _dtableUtils.getTableColumnByKey)(table, summary_column_key) || {};
165
+ columnData = summaryColumn.data || _constants.DEFAULT_NUMBER_FORMAT_OBJECT;
166
+ }
167
+ return columnData;
168
+ };
169
+ this.drawCircle = (data, mapData, geoPath) => {
170
+ const {
171
+ chart
172
+ } = this.props;
173
+ const {
174
+ bubble_color = '#2a67d1'
175
+ } = chart.config;
176
+ const circleData = [];
177
+ mapData.features.forEach(item => {
178
+ const curName = item.properties.name;
179
+ const curData = data.find(item => item.name.includes(curName));
180
+ if (curData) {
181
+ circleData.push({
182
+ feature: item,
183
+ value: curData.value,
184
+ name: curName
185
+ });
186
+ }
187
+ });
188
+ const bubbleWrapper = this.chart.append('g').attr('class', 'bubble-wrapper');
189
+ circleData.forEach(_ref => {
190
+ let {
191
+ feature,
192
+ value,
193
+ name
194
+ } = _ref;
195
+ const centroid = geoPath.centroid(feature);
196
+ if (centroid && centroid[0] && centroid[1]) {
197
+ bubbleWrapper.append('circle').attr('cx', centroid[0]).attr('cy', centroid[1]).attr('r', () => {
198
+ const percent = value / data.sum;
199
+ let size = percent * 100;
200
+ return size;
201
+ }).attr('fill', bubble_color).attr('fill-opacity', 0.6).attr('stroke', bubble_color).attr('stroke-opacity', 0.9).attr('data-value', value).attr('data-name', name).on('click', event => {
202
+ const name = event.target.getAttribute('data-name');
203
+ const newData = data.find(item => item.name.includes(name));
204
+ newData && this.props.toggleRecords(newData);
205
+ }).on('mouseover', event => {
206
+ this.showTooltip(event);
207
+ this.handleAcitveAndInActiveState('active', event);
208
+ }).on('mousemove', event => {
209
+ this.moveTooltip(event);
210
+ }).on('mouseleave', event => {
211
+ this.hiddenTooltip(event);
212
+ this.handleAcitveAndInActiveState('inActive', event);
213
+ });
214
+ }
215
+ });
216
+ };
217
+ this.chart = null;
218
+ this.state = {
219
+ tooltipData: null,
220
+ toolTipPosition: null
221
+ };
222
+ }
223
+ componentDidMount() {
224
+ this.createChart();
225
+ this.drawChart();
226
+ this.debouncedHandleResize = (0, _lodashEs.debounce)(this.handleResize, 300);
227
+ window.addEventListener('resize', this.debouncedHandleResize);
228
+ }
229
+ componentDidUpdate(prevProps) {
230
+ super.componentDidUpdate(prevProps);
231
+ if (_utils.BaseUtils.shouldChartComponentUpdate(prevProps, this.props)) {
232
+ this.createChart();
233
+ this.drawChart();
234
+ }
235
+ }
236
+ componentWillUnmount() {
237
+ this.chart.node() && this.chart.node().remove();
238
+ window.removeEventListener('resize', this.debouncedHandleResize);
239
+ }
240
+ render() {
241
+ const {
242
+ tooltipData,
243
+ toolTipPosition
244
+ } = this.state;
245
+ return /*#__PURE__*/_react.default.createElement("div", {
246
+ ref: ref => this.container = ref,
247
+ className: "sea-chart-container"
248
+ }, /*#__PURE__*/_react.default.createElement(_tooltip.default, {
249
+ tooltipData: tooltipData,
250
+ toolTipPosition: toolTipPosition,
251
+ chart: this.chart
252
+ }));
253
+ }
254
+ }
255
+ MapBubble.propTypes = {
256
+ canvasStyle: _propTypes.default.object,
257
+ chart: _propTypes.default.object,
258
+ groupbyColumn: _propTypes.default.object,
259
+ columnGroupbyColumn: _propTypes.default.object,
260
+ summaryColumn: _propTypes.default.object,
261
+ result: _propTypes.default.array,
262
+ tables: _propTypes.default.array,
263
+ globalTheme: _propTypes.default.string,
264
+ chartColorTheme: _propTypes.default.string,
265
+ toggleRecords: _propTypes.default.func,
266
+ customRender: _propTypes.default.func
267
+ };
268
+ var _default = exports.default = MapBubble;
@@ -0,0 +1,268 @@
1
+ "use strict";
2
+
3
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
4
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = void 0;
9
+ var _react = _interopRequireDefault(require("react"));
10
+ var _propTypes = _interopRequireDefault(require("prop-types"));
11
+ var _lodashEs = require("lodash-es");
12
+ var d3 = _interopRequireWildcard(require("d3"));
13
+ var _topojson = require("topojson");
14
+ var _dtableUtils = require("dtable-utils");
15
+ var _constants = require("../../constants");
16
+ var _utils = require("../../utils");
17
+ var _colorRules = require("../../constants/color-rules");
18
+ var _context = _interopRequireDefault(require("../../context"));
19
+ var _mapJson = _interopRequireDefault(require("../../services/map-json"));
20
+ var _tooltip = _interopRequireDefault(require("../../components/tooltip"));
21
+ var _chartComponent = _interopRequireDefault(require("./chart-component"));
22
+ class Map extends _chartComponent.default {
23
+ constructor(props) {
24
+ super(props);
25
+ this.handleResize = () => {
26
+ this.chart.node() && this.chart.node().remove();
27
+ this.createChart();
28
+ this.drawChart();
29
+ };
30
+ this.createChart = () => {
31
+ const {
32
+ chart
33
+ } = this.props;
34
+ const initConfig = {
35
+ insertPadding: 30
36
+ };
37
+ this.initChart(this.container, chart === null || chart === void 0 ? void 0 : chart.id, initConfig);
38
+ };
39
+ this.drawChart = async () => {
40
+ let {
41
+ result: data,
42
+ chart
43
+ } = this.props;
44
+ if (!Array.isArray(data)) return;
45
+ const {
46
+ map_location,
47
+ map_level = _constants.MAP_LEVEL.COUNTRY,
48
+ type
49
+ } = chart.config;
50
+ const mediaUrl = _context.default.getSetting('mediaUrl');
51
+ const mapJson = await (0, _mapJson.default)(map_level, map_location, mediaUrl);
52
+ if (!mapJson) return;
53
+ const statisticNewData = this.formatMapStatisticData(data, mapJson, type);
54
+ this.draw(statisticNewData, mapJson);
55
+ };
56
+ this.showTooltip = event => {
57
+ const title = event.target.getAttribute('data-name');
58
+ const value = Number(event.target.getAttribute('data-value'));
59
+ const {
60
+ offsetX,
61
+ offsetY
62
+ } = event;
63
+ const newTooltipData = {
64
+ title,
65
+ items: [{
66
+ color: '',
67
+ name: '数量',
68
+ value
69
+ }]
70
+ };
71
+ this.setState({
72
+ tooltipData: newTooltipData
73
+ });
74
+ this.setState({
75
+ toolTipPosition: {
76
+ offsetX,
77
+ offsetY
78
+ }
79
+ });
80
+ };
81
+ this.moveTooltip = event => {
82
+ const {
83
+ offsetX,
84
+ offsetY
85
+ } = event;
86
+ this.setState({
87
+ toolTipPosition: {
88
+ offsetX,
89
+ offsetY
90
+ }
91
+ });
92
+ };
93
+ this.hiddenTooltip = event => {
94
+ this.setState({
95
+ toolTipPosition: null
96
+ });
97
+ };
98
+ this.draw = (data, mapJson) => {
99
+ const {
100
+ chart,
101
+ globalTheme,
102
+ canvasStyle
103
+ } = this.props;
104
+ const theme = _constants.CHART_THEME_COLOR[globalTheme];
105
+ const {
106
+ map_level = _constants.MAP_LEVEL.COUNTRY,
107
+ data_color,
108
+ legend_size,
109
+ legend_direction,
110
+ summary_method
111
+ } = chart.config;
112
+ const {
113
+ width: chartWidth,
114
+ height: chartHeight,
115
+ insertPadding
116
+ } = this.chartBoundingClientRect;
117
+ const newMapData = map_level === _constants.MAP_LEVEL.COUNTRY ? (0, _topojson.feature)(mapJson, mapJson.objects) : mapJson;
118
+ const currentColorOption = _colorRules.COLOR_OPTIONS.filter(item => item.name === data_color)[0] || _colorRules.COLOR_OPTIONS[0];
119
+ const {
120
+ exampleColors,
121
+ highlightedBorderColor
122
+ } = currentColorOption;
123
+
124
+ // Color scale
125
+ const minVal = d3.min(data, d => d.value);
126
+ const maxVal = d3.max(data, d => d.value);
127
+ const color = d3.scaleSequential([minVal, maxVal], d3.interpolateRgbBasis(exampleColors)).unknown('#e2e2e2');
128
+
129
+ // 1. Setting up projection
130
+ const projection = d3.geoMercator().fitSize([chartWidth - insertPadding, chartHeight - insertPadding], newMapData);
131
+
132
+ // 2. Generate a path based on projection
133
+ const pathGenerator = d3.geoPath(projection);
134
+
135
+ // 3. Rendering map
136
+ this.chart.append('g').attr('class', 'map-wrapper').on('click', event => {
137
+ const value = Number(event.target.getAttribute('data-value'));
138
+ if (value) {
139
+ const name = event.target.getAttribute('data-name');
140
+ const newData = data.find(item => item.name.includes(name));
141
+ newData && this.props.toggleRecords(newData);
142
+ }
143
+ }).on('mousemove', event => {
144
+ const value = Number(event.target.getAttribute('data-value'));
145
+ if (value) {
146
+ this.curElement = event.target.parentNode;
147
+ this.showTooltip(event);
148
+ this.handleAcitveAndInActiveState('active', event, highlightedBorderColor);
149
+ } else {
150
+ if (this.curElement) {
151
+ this.hiddenTooltip(event);
152
+ this.handleAcitveAndInActiveState('inActive', event, highlightedBorderColor);
153
+ this.curElement = null;
154
+ }
155
+ }
156
+ }).on('mouseleave', event => {
157
+ if (this.curElement) {
158
+ this.hiddenTooltip(event);
159
+ this.handleAcitveAndInActiveState('inActive', event, highlightedBorderColor);
160
+ this.curElement = null;
161
+ }
162
+ }).selectAll().data(newMapData.features).join('g').append('path').attr('d', d => {
163
+ return pathGenerator(d);
164
+ }).attr('stroke-width', 1).attr('stroke', '#bdbdbd').attr('stroke-opacity', 1).attr('opacity', 1).attr('data-name', d => d.properties.name).call(g => {
165
+ g.nodes().forEach(item => {
166
+ const curName = item.getAttribute('data-name');
167
+ const curItemData = data.find(item => item.name.includes(curName));
168
+ if (curItemData) {
169
+ d3.select(item).attr('fill', color(curItemData.value));
170
+ d3.select(item).attr('data-value', curItemData.value);
171
+ } else {
172
+ d3.select(item).attr('fill', color());
173
+ }
174
+ });
175
+ });
176
+ const columnData = this.getColumnData();
177
+ this.setContinuousLegend({
178
+ previewType: canvasStyle.previewType,
179
+ theme,
180
+ colorRange: exampleColors,
181
+ legendDirection: legend_direction,
182
+ legendSize: legend_size,
183
+ legendTextRange: [_utils.BaseUtils.getSummaryValueDisplayString(columnData, minVal, summary_method), _utils.BaseUtils.getSummaryValueDisplayString(columnData, maxVal, summary_method)]
184
+ });
185
+ };
186
+ this.handleAcitveAndInActiveState = (state, event, highlightedBorderColor) => {
187
+ if (state === 'active') {
188
+ const lastElement = Array.from(event.target.parentNode.parentNode.children).at(-1);
189
+
190
+ // Add element to the end
191
+ d3.select(this.curElement).select('path').transition().duration(this.transitionDuration).attr('stroke-opacity', 0.7).attr('stroke-width', 0.5).attr('stroke', highlightedBorderColor);
192
+ lastElement.after(this.curElement);
193
+ return;
194
+ }
195
+ if (this.curElement) {
196
+ d3.select(this.curElement).select('path').transition().duration(this.transitionDuration).attr('stroke-opacity', 1).attr('stroke-width', 1).attr('stroke', '#bdbdbd');
197
+ }
198
+ };
199
+ this.getColumnData = () => {
200
+ const {
201
+ chart
202
+ } = this.props;
203
+ const {
204
+ summary_type,
205
+ summary_column_key,
206
+ table_id
207
+ } = chart.config;
208
+ let columnData = _constants.DEFAULT_NUMBER_FORMAT_OBJECT;
209
+ if (summary_type === _constants.CHART_SUMMARY_TYPE.ADVANCED) {
210
+ const table = (0, _dtableUtils.getTableById)(table_id);
211
+ const summaryColumn = (0, _dtableUtils.getTableColumnByKey)(table, summary_column_key) || {};
212
+ columnData = summaryColumn.data || _constants.DEFAULT_NUMBER_FORMAT_OBJECT;
213
+ }
214
+ return columnData;
215
+ };
216
+ this.chart = null;
217
+ this.state = {
218
+ tooltipData: null,
219
+ toolTipPosition: null
220
+ };
221
+ this.curElement = null; // Regions that currently contain data
222
+ }
223
+ componentDidMount() {
224
+ this.createChart();
225
+ this.drawChart();
226
+ this.debouncedHandleResize = (0, _lodashEs.debounce)(this.handleResize, 300);
227
+ window.addEventListener('resize', this.debouncedHandleResize);
228
+ }
229
+ componentDidUpdate(prevProps) {
230
+ super.componentDidUpdate(prevProps);
231
+ if (_utils.BaseUtils.shouldChartComponentUpdate(prevProps, this.props)) {
232
+ this.createChart();
233
+ this.drawChart();
234
+ }
235
+ }
236
+ componentWillUnmount() {
237
+ this.chart.node() && this.chart.node().remove();
238
+ window.removeEventListener('resize', this.debouncedHandleResize);
239
+ }
240
+ render() {
241
+ const {
242
+ tooltipData,
243
+ toolTipPosition
244
+ } = this.state;
245
+ return /*#__PURE__*/_react.default.createElement("div", {
246
+ ref: ref => this.container = ref,
247
+ className: "sea-chart-container"
248
+ }, /*#__PURE__*/_react.default.createElement(_tooltip.default, {
249
+ tooltipData: tooltipData,
250
+ toolTipPosition: toolTipPosition,
251
+ chart: this.chart
252
+ }));
253
+ }
254
+ }
255
+ Map.propTypes = {
256
+ canvasStyle: _propTypes.default.object,
257
+ chart: _propTypes.default.object,
258
+ groupbyColumn: _propTypes.default.object,
259
+ columnGroupbyColumn: _propTypes.default.object,
260
+ summaryColumn: _propTypes.default.object,
261
+ result: _propTypes.default.array,
262
+ tables: _propTypes.default.array,
263
+ globalTheme: _propTypes.default.string,
264
+ chartColorTheme: _propTypes.default.string,
265
+ toggleRecords: _propTypes.default.func,
266
+ customRender: _propTypes.default.func
267
+ };
268
+ var _default = exports.default = Map;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sea-chart",
3
- "version": "2.0.25",
3
+ "version": "2.0.26",
4
4
  "main": "./dist/index.js",
5
5
  "dependencies": {
6
6
  "@dnd-kit/core": "^6.1.0",
@@ -17,7 +17,8 @@
17
17
  "rc-slider": "^10.5.0",
18
18
  "reactstrap": "~9.2.3",
19
19
  "shallowequal": "^1.1.0",
20
- "slugid": "~5.0.1"
20
+ "slugid": "~5.0.1",
21
+ "topojson": "^3.0.2"
21
22
  },
22
23
  "peerDependencies": {
23
24
  "dtable-ui-component": "~6.0.15",