sea-chart 2.0.26 → 2.0.27
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.
- package/dist/components/types-dialog/index.js +0 -2
- package/dist/view/wrapper/chart-component.js +59 -3
- package/dist/view/wrapper/index.js +14 -0
- package/dist/view/wrapper/map-bubble.js +6 -7
- package/dist/view/wrapper/map-world-bubble.js +266 -0
- package/dist/view/wrapper/map-world.js +279 -0
- package/dist/view/wrapper/map.js +5 -6
- package/package.json +1 -1
|
@@ -70,8 +70,6 @@ const TypesDialog = _ref => {
|
|
|
70
70
|
const handleFilterTypes = (0, _react.useCallback)(() => {
|
|
71
71
|
if (hideTypeToggle) {
|
|
72
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;
|
|
75
73
|
return newChartTypes;
|
|
76
74
|
}
|
|
77
75
|
return _constants.CHART_TYPES;
|
|
@@ -667,7 +667,7 @@ class ChartComponent extends _react.Component {
|
|
|
667
667
|
const legendRectHeight = legendDirection === 'vertical' ? Math.min(legendSize * 100, chartHeight - insertPadding * 2) : 12;
|
|
668
668
|
const legendTextOffset = 2;
|
|
669
669
|
const legendTextHeightSpace = legendDirection === 'vertical' ? 0 : 14 + legendTextOffset;
|
|
670
|
-
if (
|
|
670
|
+
if (![_constants.CHART_TYPE.MAP_BUBBLE, _constants.CHART_TYPE.WORLD_MAP_BUBBLE].includes(type)) {
|
|
671
671
|
var _this$chart$node;
|
|
672
672
|
// add linearGradient
|
|
673
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%');
|
|
@@ -678,8 +678,8 @@ class ChartComponent extends _react.Component {
|
|
|
678
678
|
|
|
679
679
|
// add legend
|
|
680
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',
|
|
682
|
-
if (
|
|
681
|
+
continuousLegendWrapper.append('rect').attr('width', legendRectWidth).attr('height', legendRectHeight).attr('fill', [_constants.CHART_TYPE.MAP_BUBBLE, _constants.CHART_TYPE.WORLD_MAP_BUBBLE].includes(type) ? 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 ([_constants.CHART_TYPE.MAP_BUBBLE, _constants.CHART_TYPE.WORLD_MAP_BUBBLE].includes(type)) {
|
|
683
683
|
continuousLegendWrapper.append('polygon').attr('points', "0,0 ".concat(legendRectWidth - 0.5, ",0 0,").concat(legendRectHeight - 0.5)).attr('fill', '#fff').attr('stroke', '#fff');
|
|
684
684
|
}
|
|
685
685
|
});
|
|
@@ -1140,6 +1140,13 @@ class ChartComponent extends _react.Component {
|
|
|
1140
1140
|
if (!mapData.features) return [];
|
|
1141
1141
|
let statisticNewData = [];
|
|
1142
1142
|
let sum = 0;
|
|
1143
|
+
|
|
1144
|
+
// Modify the map json data of type Topology
|
|
1145
|
+
mapData.features.forEach(feature => {
|
|
1146
|
+
if (feature.properties.fullname) {
|
|
1147
|
+
feature.properties.name = feature.properties.fullname;
|
|
1148
|
+
}
|
|
1149
|
+
});
|
|
1143
1150
|
statisticData.forEach((item, index) => {
|
|
1144
1151
|
if (item && item.name) {
|
|
1145
1152
|
let matchFeature = mapData.features.find(feature => feature.properties.name.indexOf(item.name) > -1);
|
|
@@ -1159,6 +1166,55 @@ class ChartComponent extends _react.Component {
|
|
|
1159
1166
|
}
|
|
1160
1167
|
return statisticNewData;
|
|
1161
1168
|
};
|
|
1169
|
+
this.formatWorldMapStatisticData = (statisticData, mapData, type) => {
|
|
1170
|
+
if (!statisticData) return [];
|
|
1171
|
+
if (!mapData.features) return [];
|
|
1172
|
+
const reg = /^([A-Za-z])/;
|
|
1173
|
+
const countryMap = new Map();
|
|
1174
|
+
mapData.features.forEach(item => {
|
|
1175
|
+
countryMap.set(item.properties.name, item.properties.name_cn);
|
|
1176
|
+
countryMap.set(item.properties.name_cn, item.properties.name);
|
|
1177
|
+
});
|
|
1178
|
+
let sum = 0;
|
|
1179
|
+
let statisticNewData = [];
|
|
1180
|
+
statisticData.forEach(item => {
|
|
1181
|
+
if (item && item.name) {
|
|
1182
|
+
let nameType, name, name_cn;
|
|
1183
|
+
if (reg.test(item.name)) {
|
|
1184
|
+
nameType = 'en';
|
|
1185
|
+
name = item.name;
|
|
1186
|
+
name_cn = countryMap.get(name);
|
|
1187
|
+
} else {
|
|
1188
|
+
nameType = 'zh-cn';
|
|
1189
|
+
name = countryMap.get(item.name);
|
|
1190
|
+
name_cn = item.name;
|
|
1191
|
+
}
|
|
1192
|
+
const value = item.value;
|
|
1193
|
+
if (name_cn && name) {
|
|
1194
|
+
const existedData = statisticNewData.find(i => i.name === name);
|
|
1195
|
+
if (existedData) {
|
|
1196
|
+
existedData.value += value;
|
|
1197
|
+
existedData.formatted_value = parseInt(existedData.formatted_value) + parseInt(item.formatted_value) + '';
|
|
1198
|
+
} else {
|
|
1199
|
+
statisticNewData.push({
|
|
1200
|
+
name_cn,
|
|
1201
|
+
name,
|
|
1202
|
+
nameType,
|
|
1203
|
+
value: value || 0,
|
|
1204
|
+
formatted_value: item.formatted_value + ''
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
if (type === _constants.CHART_TYPE.WORLD_MAP_BUBBLE) {
|
|
1208
|
+
sum += item.value;
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
});
|
|
1213
|
+
if (type === _constants.CHART_TYPE.WORLD_MAP_BUBBLE) {
|
|
1214
|
+
statisticNewData.sum = sum;
|
|
1215
|
+
}
|
|
1216
|
+
return statisticNewData;
|
|
1217
|
+
};
|
|
1162
1218
|
this.getToolTipSettings = (isGroup, summaryColumn, y_axis_summary_method, useSingleSelectColumnColor) => {
|
|
1163
1219
|
const obj = {
|
|
1164
1220
|
showMarkers: false,
|
|
@@ -32,6 +32,8 @@ var _basicNumberCard = _interopRequireDefault(require("./basic-number-card"));
|
|
|
32
32
|
var _combination = _interopRequireDefault(require("./combination"));
|
|
33
33
|
var _map = _interopRequireDefault(require("./map"));
|
|
34
34
|
var _mapBubble = _interopRequireDefault(require("./map-bubble"));
|
|
35
|
+
var _mapWorld = _interopRequireDefault(require("./map-world"));
|
|
36
|
+
var _mapWorldBubble = _interopRequireDefault(require("./map-world-bubble"));
|
|
35
37
|
var _trend = _interopRequireDefault(require("./trend"));
|
|
36
38
|
var _tableElement = _interopRequireDefault(require("./table-element"));
|
|
37
39
|
const Wrapper = _ref => {
|
|
@@ -265,6 +267,18 @@ const Wrapper = _ref => {
|
|
|
265
267
|
canvasStyle: canvasStyle
|
|
266
268
|
}));
|
|
267
269
|
}
|
|
270
|
+
case _constants.CHART_TYPE.WORLD_MAP:
|
|
271
|
+
{
|
|
272
|
+
return /*#__PURE__*/_react.default.createElement(_mapWorld.default, Object.assign({}, baseProps, {
|
|
273
|
+
canvasStyle: canvasStyle
|
|
274
|
+
}));
|
|
275
|
+
}
|
|
276
|
+
case _constants.CHART_TYPE.WORLD_MAP_BUBBLE:
|
|
277
|
+
{
|
|
278
|
+
return /*#__PURE__*/_react.default.createElement(_mapWorldBubble.default, Object.assign({}, baseProps, {
|
|
279
|
+
canvasStyle: canvasStyle
|
|
280
|
+
}));
|
|
281
|
+
}
|
|
268
282
|
case _constants.CHART_TYPE.BASIC_NUMBER_CARD:
|
|
269
283
|
{
|
|
270
284
|
return /*#__PURE__*/_react.default.createElement(_basicNumberCard.default, Object.assign({}, baseProps, {
|
|
@@ -49,8 +49,9 @@ class MapBubble extends _chartComponent.default {
|
|
|
49
49
|
const mediaUrl = _context.default.getSetting('mediaUrl');
|
|
50
50
|
const mapJson = await (0, _mapJson.default)(map_level, map_location, mediaUrl);
|
|
51
51
|
if (!mapJson) return;
|
|
52
|
-
const
|
|
53
|
-
this.
|
|
52
|
+
const newMapJson = map_level === _constants.MAP_LEVEL.COUNTRY ? (0, _topojson.feature)(mapJson, mapJson.objects) : mapJson;
|
|
53
|
+
const statisticNewData = this.formatMapStatisticData(data, newMapJson, type);
|
|
54
|
+
this.draw(statisticNewData, newMapJson);
|
|
54
55
|
};
|
|
55
56
|
this.showTooltip = event => {
|
|
56
57
|
const title = event.currentTarget.getAttribute('data-name');
|
|
@@ -102,7 +103,6 @@ class MapBubble extends _chartComponent.default {
|
|
|
102
103
|
} = this.props;
|
|
103
104
|
const theme = _constants.CHART_THEME_COLOR[globalTheme];
|
|
104
105
|
const {
|
|
105
|
-
map_level = _constants.MAP_LEVEL.COUNTRY,
|
|
106
106
|
legend_size,
|
|
107
107
|
legend_direction,
|
|
108
108
|
summary_method,
|
|
@@ -114,21 +114,20 @@ class MapBubble extends _chartComponent.default {
|
|
|
114
114
|
height: chartHeight,
|
|
115
115
|
insertPadding
|
|
116
116
|
} = this.chartBoundingClientRect;
|
|
117
|
-
const newMapData = map_level === _constants.MAP_LEVEL.COUNTRY ? (0, _topojson.feature)(mapJson, mapJson.objects) : mapJson;
|
|
118
117
|
|
|
119
118
|
// 1. Setting up projection
|
|
120
|
-
const projection = d3.geoMercator().fitSize([chartWidth - insertPadding, chartHeight - insertPadding],
|
|
119
|
+
const projection = d3.geoMercator().fitSize([chartWidth - insertPadding, chartHeight - insertPadding], mapJson);
|
|
121
120
|
|
|
122
121
|
// 2. Generate a path based on projection
|
|
123
122
|
const pathGenerator = d3.geoPath(projection);
|
|
124
123
|
|
|
125
124
|
// 3. Rendering map
|
|
126
|
-
this.chart.append('g').attr('class', 'map-wrapper').selectAll().data(
|
|
125
|
+
this.chart.append('g').attr('class', 'map-wrapper').selectAll().data(mapJson.features).join('g').append('path').attr('d', d => {
|
|
127
126
|
return pathGenerator(d);
|
|
128
127
|
}).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
128
|
|
|
130
129
|
// draw bubble circle
|
|
131
|
-
this.drawCircle(data,
|
|
130
|
+
this.drawCircle(data, mapJson, pathGenerator);
|
|
132
131
|
|
|
133
132
|
// draw legend
|
|
134
133
|
const columnData = this.getColumnData();
|
|
@@ -0,0 +1,266 @@
|
|
|
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
|
+
type
|
|
46
|
+
} = chart.config;
|
|
47
|
+
const mediaUrl = _context.default.getSetting('mediaUrl');
|
|
48
|
+
const mapJson = await (0, _mapJson.default)(_constants.MAP_LEVEL.WORLD, '', mediaUrl);
|
|
49
|
+
if (!mapJson) return;
|
|
50
|
+
const newMapJson = (0, _topojson.feature)(mapJson, mapJson.objects);
|
|
51
|
+
const statisticNewData = this.formatWorldMapStatisticData(data, newMapJson, type);
|
|
52
|
+
this.draw(statisticNewData, newMapJson);
|
|
53
|
+
};
|
|
54
|
+
this.showTooltip = (event, data) => {
|
|
55
|
+
const curData = data.find(item => item.name.includes(event.currentTarget.getAttribute('data-name')));
|
|
56
|
+
const title = curData.nameType === 'en' ? curData.name : curData.name_cn;
|
|
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
|
+
legend_size,
|
|
106
|
+
legend_direction,
|
|
107
|
+
summary_method,
|
|
108
|
+
type,
|
|
109
|
+
bubble_color
|
|
110
|
+
} = chart.config;
|
|
111
|
+
const {
|
|
112
|
+
width: chartWidth,
|
|
113
|
+
height: chartHeight,
|
|
114
|
+
insertPadding
|
|
115
|
+
} = this.chartBoundingClientRect;
|
|
116
|
+
|
|
117
|
+
// 1. Setting up projection
|
|
118
|
+
const projection = d3.geoMercator().fitSize([chartWidth - insertPadding, chartHeight - insertPadding], mapJson);
|
|
119
|
+
|
|
120
|
+
// 2. Generate a path based on projection
|
|
121
|
+
const pathGenerator = d3.geoPath(projection);
|
|
122
|
+
|
|
123
|
+
// 3. Rendering map
|
|
124
|
+
this.chart.append('g').attr('class', 'map-wrapper').selectAll().data(mapJson.features).join('g').append('path').attr('d', d => {
|
|
125
|
+
return pathGenerator(d);
|
|
126
|
+
}).attr('stroke-width', 1).attr('stroke', '#bdbdbd').attr('stroke-opacity', 1).attr('fill', '#e2e2e2').attr('opacity', 1).attr('data-name', d => d.properties.name);
|
|
127
|
+
|
|
128
|
+
// draw bubble circle
|
|
129
|
+
this.drawCircle(data, mapJson, pathGenerator);
|
|
130
|
+
|
|
131
|
+
// draw legend
|
|
132
|
+
const columnData = this.getColumnData();
|
|
133
|
+
this.setContinuousLegend({
|
|
134
|
+
previewType: canvasStyle.previewType,
|
|
135
|
+
theme,
|
|
136
|
+
legendDirection: legend_direction,
|
|
137
|
+
legendSize: legend_size,
|
|
138
|
+
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)],
|
|
139
|
+
type,
|
|
140
|
+
bubbleColor: bubble_color || '#2a67d1'
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
this.handleAcitveAndInActiveState = (state, event, highlightedBorderColor) => {
|
|
144
|
+
if (state === 'active') {
|
|
145
|
+
d3.select(event.currentTarget).transition().duration(this.transitionDuration).attr('fill-opacity', 0.9);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
d3.select(event.currentTarget).transition().duration(this.transitionDuration).attr('fill-opacity', 0.6);
|
|
149
|
+
};
|
|
150
|
+
this.getColumnData = () => {
|
|
151
|
+
const {
|
|
152
|
+
chart
|
|
153
|
+
} = this.props;
|
|
154
|
+
const {
|
|
155
|
+
summary_type,
|
|
156
|
+
summary_column_key,
|
|
157
|
+
table_id
|
|
158
|
+
} = chart.config;
|
|
159
|
+
let columnData = _constants.DEFAULT_NUMBER_FORMAT_OBJECT;
|
|
160
|
+
if (summary_type === _constants.CHART_SUMMARY_TYPE.ADVANCED) {
|
|
161
|
+
const table = (0, _dtableUtils.getTableById)(table_id);
|
|
162
|
+
const summaryColumn = (0, _dtableUtils.getTableColumnByKey)(table, summary_column_key) || {};
|
|
163
|
+
columnData = summaryColumn.data || _constants.DEFAULT_NUMBER_FORMAT_OBJECT;
|
|
164
|
+
}
|
|
165
|
+
return columnData;
|
|
166
|
+
};
|
|
167
|
+
this.drawCircle = (data, mapData, geoPath) => {
|
|
168
|
+
const {
|
|
169
|
+
chart
|
|
170
|
+
} = this.props;
|
|
171
|
+
const {
|
|
172
|
+
bubble_color
|
|
173
|
+
} = chart.config;
|
|
174
|
+
const circleData = [];
|
|
175
|
+
mapData.features.forEach(item => {
|
|
176
|
+
const curName = item.properties.name;
|
|
177
|
+
const curData = data.find(item => item.name.includes(curName));
|
|
178
|
+
if (curData) {
|
|
179
|
+
circleData.push({
|
|
180
|
+
feature: item,
|
|
181
|
+
value: curData.value,
|
|
182
|
+
name: curName
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
const bubbleWrapper = this.chart.append('g').attr('class', 'bubble-wrapper');
|
|
187
|
+
circleData.forEach(_ref => {
|
|
188
|
+
let {
|
|
189
|
+
feature,
|
|
190
|
+
value,
|
|
191
|
+
name
|
|
192
|
+
} = _ref;
|
|
193
|
+
const centroid = geoPath.centroid(feature);
|
|
194
|
+
if (centroid && centroid[0] && centroid[1]) {
|
|
195
|
+
bubbleWrapper.append('circle').attr('cx', centroid[0]).attr('cy', centroid[1]).attr('r', () => {
|
|
196
|
+
const percent = value / data.sum;
|
|
197
|
+
let size = percent * 100;
|
|
198
|
+
return size;
|
|
199
|
+
}).attr('fill', bubble_color || '#2a67d1').attr('fill-opacity', 0.6).attr('stroke', bubble_color || '#2a67d1').attr('stroke-opacity', 0.9).attr('data-value', value).attr('data-name', name).on('click', event => {
|
|
200
|
+
const name = event.target.getAttribute('data-name');
|
|
201
|
+
const newData = data.find(item => item.name.includes(name));
|
|
202
|
+
newData && this.props.toggleRecords(newData);
|
|
203
|
+
}).on('mouseover', event => {
|
|
204
|
+
this.showTooltip(event, data);
|
|
205
|
+
this.handleAcitveAndInActiveState('active', event);
|
|
206
|
+
}).on('mousemove', event => {
|
|
207
|
+
this.moveTooltip(event);
|
|
208
|
+
}).on('mouseleave', event => {
|
|
209
|
+
this.hiddenTooltip(event);
|
|
210
|
+
this.handleAcitveAndInActiveState('inActive', event);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
};
|
|
215
|
+
this.chart = null;
|
|
216
|
+
this.state = {
|
|
217
|
+
tooltipData: null,
|
|
218
|
+
toolTipPosition: null
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
componentDidMount() {
|
|
222
|
+
this.createChart();
|
|
223
|
+
this.drawChart();
|
|
224
|
+
this.debouncedHandleResize = (0, _lodashEs.debounce)(this.handleResize, 300);
|
|
225
|
+
window.addEventListener('resize', this.debouncedHandleResize);
|
|
226
|
+
}
|
|
227
|
+
componentDidUpdate(prevProps) {
|
|
228
|
+
super.componentDidUpdate(prevProps);
|
|
229
|
+
if (_utils.BaseUtils.shouldChartComponentUpdate(prevProps, this.props)) {
|
|
230
|
+
this.createChart();
|
|
231
|
+
this.drawChart();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
componentWillUnmount() {
|
|
235
|
+
this.chart.node() && this.chart.node().remove();
|
|
236
|
+
window.removeEventListener('resize', this.debouncedHandleResize);
|
|
237
|
+
}
|
|
238
|
+
render() {
|
|
239
|
+
const {
|
|
240
|
+
tooltipData,
|
|
241
|
+
toolTipPosition
|
|
242
|
+
} = this.state;
|
|
243
|
+
return /*#__PURE__*/_react.default.createElement("div", {
|
|
244
|
+
ref: ref => this.container = ref,
|
|
245
|
+
className: "sea-chart-container"
|
|
246
|
+
}, /*#__PURE__*/_react.default.createElement(_tooltip.default, {
|
|
247
|
+
tooltipData: tooltipData,
|
|
248
|
+
toolTipPosition: toolTipPosition,
|
|
249
|
+
chart: this.chart
|
|
250
|
+
}));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
MapBubble.propTypes = {
|
|
254
|
+
canvasStyle: _propTypes.default.object,
|
|
255
|
+
chart: _propTypes.default.object,
|
|
256
|
+
groupbyColumn: _propTypes.default.object,
|
|
257
|
+
columnGroupbyColumn: _propTypes.default.object,
|
|
258
|
+
summaryColumn: _propTypes.default.object,
|
|
259
|
+
result: _propTypes.default.array,
|
|
260
|
+
tables: _propTypes.default.array,
|
|
261
|
+
globalTheme: _propTypes.default.string,
|
|
262
|
+
chartColorTheme: _propTypes.default.string,
|
|
263
|
+
toggleRecords: _propTypes.default.func,
|
|
264
|
+
customRender: _propTypes.default.func
|
|
265
|
+
};
|
|
266
|
+
var _default = exports.default = MapBubble;
|
|
@@ -0,0 +1,279 @@
|
|
|
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
|
+
type
|
|
47
|
+
} = chart.config;
|
|
48
|
+
const mediaUrl = _context.default.getSetting('mediaUrl');
|
|
49
|
+
const mapJson = await (0, _mapJson.default)(_constants.MAP_LEVEL.WORLD, '', mediaUrl);
|
|
50
|
+
if (!mapJson) return;
|
|
51
|
+
const newMapJson = (0, _topojson.feature)(mapJson, mapJson.objects);
|
|
52
|
+
const statisticNewData = this.formatWorldMapStatisticData(data, newMapJson, type);
|
|
53
|
+
this.draw(statisticNewData, newMapJson);
|
|
54
|
+
};
|
|
55
|
+
this.showTooltip = (event, data) => {
|
|
56
|
+
const curData = data.find(item => item.name.includes(event.target.parentNode.getAttribute('data-name')));
|
|
57
|
+
const title = curData.nameType === 'en' ? curData.name : curData.name_cn;
|
|
58
|
+
const value = Number(event.target.parentNode.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
|
+
isCalculateByView
|
|
104
|
+
} = this.props;
|
|
105
|
+
const theme = _constants.CHART_THEME_COLOR[globalTheme];
|
|
106
|
+
const {
|
|
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 currentColorOption = _colorRules.COLOR_OPTIONS.filter(item => item.name === data_color)[0] || _colorRules.COLOR_OPTIONS[0];
|
|
118
|
+
const {
|
|
119
|
+
exampleColors,
|
|
120
|
+
highlightedBorderColor
|
|
121
|
+
} = currentColorOption;
|
|
122
|
+
|
|
123
|
+
// Color scale
|
|
124
|
+
const minVal = d3.min(data, d => d.value);
|
|
125
|
+
const maxVal = d3.max(data, d => d.value);
|
|
126
|
+
const color = d3.scaleSequential([minVal, maxVal], d3.interpolateRgbBasis(exampleColors)).unknown('#e2e2e2');
|
|
127
|
+
|
|
128
|
+
// 1. Setting up projection
|
|
129
|
+
const projection = d3.geoMercator().fitSize([chartWidth - insertPadding, chartHeight - insertPadding], mapJson);
|
|
130
|
+
|
|
131
|
+
// 2. Generate a path based on projection
|
|
132
|
+
const pathGenerator = d3.geoPath(projection);
|
|
133
|
+
|
|
134
|
+
// 3. Rendering map
|
|
135
|
+
this.chart.append('g').attr('class', 'map-wrapper').on('click', event => {
|
|
136
|
+
if (isCalculateByView) {
|
|
137
|
+
const value = Number(event.target.parentNode.getAttribute('data-value'));
|
|
138
|
+
if (value) {
|
|
139
|
+
const name = event.target.parentNode.getAttribute('data-name');
|
|
140
|
+
const newData = data.find(item => item.name.includes(name));
|
|
141
|
+
newData && this.props.toggleRecords([newData]);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}).on('mousemove', event => {
|
|
145
|
+
console.log(data);
|
|
146
|
+
const value = Number(event.target.parentNode.getAttribute('data-value'));
|
|
147
|
+
if (this.curElement) {
|
|
148
|
+
this.handleAcitveAndInActiveState('inActive', event, highlightedBorderColor);
|
|
149
|
+
this.curElement = null;
|
|
150
|
+
}
|
|
151
|
+
if (value) {
|
|
152
|
+
this.curElement = event.target.parentNode;
|
|
153
|
+
this.showTooltip(event, data);
|
|
154
|
+
this.handleAcitveAndInActiveState('active', event, highlightedBorderColor);
|
|
155
|
+
} else {
|
|
156
|
+
this.hiddenTooltip(event);
|
|
157
|
+
}
|
|
158
|
+
}).on('mouseleave', event => {
|
|
159
|
+
if (this.curElement) {
|
|
160
|
+
this.hiddenTooltip(event);
|
|
161
|
+
this.handleAcitveAndInActiveState('inActive', event, highlightedBorderColor);
|
|
162
|
+
this.curElement = null;
|
|
163
|
+
}
|
|
164
|
+
}).selectAll().data(mapJson.features).join('g').attr('data-name', d => d.properties.name).attr('stroke-width', 1).attr('stroke', '#bdbdbd').attr('stroke-opacity', 1).attr('opacity', 1).append('path').attr('d', d => {
|
|
165
|
+
return pathGenerator(d);
|
|
166
|
+
}).attr('data-name', d => d.properties.name).call(g => {
|
|
167
|
+
var _g$nodes$find;
|
|
168
|
+
const chinaGroup = (_g$nodes$find = g.nodes().find(item => item.getAttribute('data-name').includes('China'))) === null || _g$nodes$find === void 0 ? void 0 : _g$nodes$find.parentNode;
|
|
169
|
+
const chinaTaiwan = g.nodes().find(item => item.getAttribute('data-name').includes('Taiwan'));
|
|
170
|
+
if (chinaGroup) {
|
|
171
|
+
(chinaTaiwan === null || chinaTaiwan === void 0 ? void 0 : chinaTaiwan.parentNode) && chinaTaiwan.parentNode.remove();
|
|
172
|
+
chinaGroup.append(chinaTaiwan);
|
|
173
|
+
}
|
|
174
|
+
}).call(g => {
|
|
175
|
+
g.nodes().forEach(item => {
|
|
176
|
+
const curGroup = item.parentNode;
|
|
177
|
+
const curName = curGroup.getAttribute('data-name');
|
|
178
|
+
const curItemData = data.find(d => d.name.includes(curName));
|
|
179
|
+
if (curItemData) {
|
|
180
|
+
d3.select(curGroup).attr('fill', color(curItemData.value));
|
|
181
|
+
d3.select(curGroup).attr('data-value', curItemData.value);
|
|
182
|
+
} else {
|
|
183
|
+
d3.select(curGroup).attr('fill', color());
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
const columnData = this.getColumnData();
|
|
188
|
+
this.setContinuousLegend({
|
|
189
|
+
previewType: canvasStyle.previewType,
|
|
190
|
+
theme,
|
|
191
|
+
colorRange: exampleColors,
|
|
192
|
+
legendDirection: legend_direction,
|
|
193
|
+
legendSize: legend_size,
|
|
194
|
+
legendTextRange: [_utils.BaseUtils.getSummaryValueDisplayString(columnData, minVal, summary_method), _utils.BaseUtils.getSummaryValueDisplayString(columnData, maxVal, summary_method)]
|
|
195
|
+
});
|
|
196
|
+
};
|
|
197
|
+
this.handleAcitveAndInActiveState = (state, event, highlightedBorderColor) => {
|
|
198
|
+
if (state === 'active') {
|
|
199
|
+
const lastElement = Array.from(event.target.parentNode.parentNode.children).at(-1);
|
|
200
|
+
|
|
201
|
+
// Add element to the end
|
|
202
|
+
d3.select(this.curElement).transition().duration(this.transitionDuration).attr('stroke-opacity', 0.7).attr('stroke-width', 0.5).attr('stroke', highlightedBorderColor);
|
|
203
|
+
lastElement.after(this.curElement);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (this.curElement) {
|
|
207
|
+
d3.select(this.curElement).transition().duration(this.transitionDuration).attr('stroke-opacity', 1).attr('stroke-width', 1).attr('stroke', '#bdbdbd');
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
this.getColumnData = () => {
|
|
211
|
+
const {
|
|
212
|
+
chart
|
|
213
|
+
} = this.props;
|
|
214
|
+
const {
|
|
215
|
+
summary_type,
|
|
216
|
+
summary_column_key,
|
|
217
|
+
table_id
|
|
218
|
+
} = chart.config;
|
|
219
|
+
let columnData = _constants.DEFAULT_NUMBER_FORMAT_OBJECT;
|
|
220
|
+
if (summary_type === _constants.CHART_SUMMARY_TYPE.ADVANCED) {
|
|
221
|
+
const table = (0, _dtableUtils.getTableById)(table_id);
|
|
222
|
+
const summaryColumn = (0, _dtableUtils.getTableColumnByKey)(table, summary_column_key) || {};
|
|
223
|
+
columnData = summaryColumn.data || _constants.DEFAULT_NUMBER_FORMAT_OBJECT;
|
|
224
|
+
}
|
|
225
|
+
return columnData;
|
|
226
|
+
};
|
|
227
|
+
this.chart = null;
|
|
228
|
+
this.state = {
|
|
229
|
+
tooltipData: null,
|
|
230
|
+
toolTipPosition: null
|
|
231
|
+
};
|
|
232
|
+
this.curElement = null; // Regions that currently contain data
|
|
233
|
+
}
|
|
234
|
+
componentDidMount() {
|
|
235
|
+
this.createChart();
|
|
236
|
+
this.drawChart();
|
|
237
|
+
this.debouncedHandleResize = (0, _lodashEs.debounce)(this.handleResize, 300);
|
|
238
|
+
window.addEventListener('resize', this.debouncedHandleResize);
|
|
239
|
+
}
|
|
240
|
+
componentDidUpdate(prevProps) {
|
|
241
|
+
super.componentDidUpdate(prevProps);
|
|
242
|
+
if (_utils.BaseUtils.shouldChartComponentUpdate(prevProps, this.props)) {
|
|
243
|
+
this.createChart();
|
|
244
|
+
this.drawChart();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
componentWillUnmount() {
|
|
248
|
+
this.chart.node() && this.chart.node().remove();
|
|
249
|
+
window.removeEventListener('resize', this.debouncedHandleResize);
|
|
250
|
+
}
|
|
251
|
+
render() {
|
|
252
|
+
const {
|
|
253
|
+
tooltipData,
|
|
254
|
+
toolTipPosition
|
|
255
|
+
} = this.state;
|
|
256
|
+
return /*#__PURE__*/_react.default.createElement("div", {
|
|
257
|
+
ref: ref => this.container = ref,
|
|
258
|
+
className: "sea-chart-container"
|
|
259
|
+
}, /*#__PURE__*/_react.default.createElement(_tooltip.default, {
|
|
260
|
+
tooltipData: tooltipData,
|
|
261
|
+
toolTipPosition: toolTipPosition,
|
|
262
|
+
chart: this.chart
|
|
263
|
+
}));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
Map.propTypes = {
|
|
267
|
+
canvasStyle: _propTypes.default.object,
|
|
268
|
+
chart: _propTypes.default.object,
|
|
269
|
+
groupbyColumn: _propTypes.default.object,
|
|
270
|
+
columnGroupbyColumn: _propTypes.default.object,
|
|
271
|
+
summaryColumn: _propTypes.default.object,
|
|
272
|
+
result: _propTypes.default.array,
|
|
273
|
+
tables: _propTypes.default.array,
|
|
274
|
+
globalTheme: _propTypes.default.string,
|
|
275
|
+
chartColorTheme: _propTypes.default.string,
|
|
276
|
+
toggleRecords: _propTypes.default.func,
|
|
277
|
+
customRender: _propTypes.default.func
|
|
278
|
+
};
|
|
279
|
+
var _default = exports.default = Map;
|
package/dist/view/wrapper/map.js
CHANGED
|
@@ -50,8 +50,9 @@ class Map extends _chartComponent.default {
|
|
|
50
50
|
const mediaUrl = _context.default.getSetting('mediaUrl');
|
|
51
51
|
const mapJson = await (0, _mapJson.default)(map_level, map_location, mediaUrl);
|
|
52
52
|
if (!mapJson) return;
|
|
53
|
-
const
|
|
54
|
-
this.
|
|
53
|
+
const newMapJson = map_level === _constants.MAP_LEVEL.COUNTRY ? (0, _topojson.feature)(mapJson, mapJson.objects) : mapJson;
|
|
54
|
+
const statisticNewData = this.formatMapStatisticData(data, newMapJson, type);
|
|
55
|
+
this.draw(statisticNewData, newMapJson);
|
|
55
56
|
};
|
|
56
57
|
this.showTooltip = event => {
|
|
57
58
|
const title = event.target.getAttribute('data-name');
|
|
@@ -103,7 +104,6 @@ class Map extends _chartComponent.default {
|
|
|
103
104
|
} = this.props;
|
|
104
105
|
const theme = _constants.CHART_THEME_COLOR[globalTheme];
|
|
105
106
|
const {
|
|
106
|
-
map_level = _constants.MAP_LEVEL.COUNTRY,
|
|
107
107
|
data_color,
|
|
108
108
|
legend_size,
|
|
109
109
|
legend_direction,
|
|
@@ -114,7 +114,6 @@ class Map extends _chartComponent.default {
|
|
|
114
114
|
height: chartHeight,
|
|
115
115
|
insertPadding
|
|
116
116
|
} = this.chartBoundingClientRect;
|
|
117
|
-
const newMapData = map_level === _constants.MAP_LEVEL.COUNTRY ? (0, _topojson.feature)(mapJson, mapJson.objects) : mapJson;
|
|
118
117
|
const currentColorOption = _colorRules.COLOR_OPTIONS.filter(item => item.name === data_color)[0] || _colorRules.COLOR_OPTIONS[0];
|
|
119
118
|
const {
|
|
120
119
|
exampleColors,
|
|
@@ -127,7 +126,7 @@ class Map extends _chartComponent.default {
|
|
|
127
126
|
const color = d3.scaleSequential([minVal, maxVal], d3.interpolateRgbBasis(exampleColors)).unknown('#e2e2e2');
|
|
128
127
|
|
|
129
128
|
// 1. Setting up projection
|
|
130
|
-
const projection = d3.geoMercator().fitSize([chartWidth - insertPadding, chartHeight - insertPadding],
|
|
129
|
+
const projection = d3.geoMercator().fitSize([chartWidth - insertPadding, chartHeight - insertPadding], mapJson);
|
|
131
130
|
|
|
132
131
|
// 2. Generate a path based on projection
|
|
133
132
|
const pathGenerator = d3.geoPath(projection);
|
|
@@ -159,7 +158,7 @@ class Map extends _chartComponent.default {
|
|
|
159
158
|
this.handleAcitveAndInActiveState('inActive', event, highlightedBorderColor);
|
|
160
159
|
this.curElement = null;
|
|
161
160
|
}
|
|
162
|
-
}).selectAll().data(
|
|
161
|
+
}).selectAll().data(mapJson.features).join('g').append('path').attr('d', d => {
|
|
163
162
|
return pathGenerator(d);
|
|
164
163
|
}).attr('stroke-width', 1).attr('stroke', '#bdbdbd').attr('stroke-opacity', 1).attr('opacity', 1).attr('data-name', d => d.properties.name).call(g => {
|
|
165
164
|
g.nodes().forEach(item => {
|