UNPKG

10.8 kBJavaScriptView Raw
1import { fromPoints } from '../core/bbox.js';
2import BoundingRect from '../core/BoundingRect.js';
3import Point from '../core/Point.js';
4import { map } from '../core/util.js';
5import Polygon from '../graphic/shape/Polygon.js';
6import Rect from '../graphic/shape/Rect.js';
7import Sector from '../graphic/shape/Sector.js';
8import { pathToPolygons } from './convertPath.js';
9import { clonePath } from './path.js';
10function getDividingGrids(dimSize, rowDim, count) {
11 var rowSize = dimSize[rowDim];
12 var columnSize = dimSize[1 - rowDim];
13 var ratio = Math.abs(rowSize / columnSize);
14 var rowCount = Math.ceil(Math.sqrt(ratio * count));
15 var columnCount = Math.floor(count / rowCount);
16 if (columnCount === 0) {
17 columnCount = 1;
18 rowCount = count;
19 }
20 var grids = [];
21 for (var i = 0; i < rowCount; i++) {
22 grids.push(columnCount);
23 }
24 var currentCount = rowCount * columnCount;
25 var remained = count - currentCount;
26 if (remained > 0) {
27 for (var i = 0; i < remained; i++) {
28 grids[i % rowCount] += 1;
29 }
30 }
31 return grids;
32}
33function divideSector(sectorShape, count, outShapes) {
34 var r0 = sectorShape.r0;
35 var r = sectorShape.r;
36 var startAngle = sectorShape.startAngle;
37 var endAngle = sectorShape.endAngle;
38 var angle = Math.abs(endAngle - startAngle);
39 var arcLen = angle * r;
40 var deltaR = r - r0;
41 var isAngleRow = arcLen > Math.abs(deltaR);
42 var grids = getDividingGrids([arcLen, deltaR], isAngleRow ? 0 : 1, count);
43 var rowSize = (isAngleRow ? angle : deltaR) / grids.length;
44 for (var row = 0; row < grids.length; row++) {
45 var columnSize = (isAngleRow ? deltaR : angle) / grids[row];
46 for (var column = 0; column < grids[row]; column++) {
47 var newShape = {};
48 if (isAngleRow) {
49 newShape.startAngle = startAngle + rowSize * row;
50 newShape.endAngle = startAngle + rowSize * (row + 1);
51 newShape.r0 = r0 + columnSize * column;
52 newShape.r = r0 + columnSize * (column + 1);
53 }
54 else {
55 newShape.startAngle = startAngle + columnSize * column;
56 newShape.endAngle = startAngle + columnSize * (column + 1);
57 newShape.r0 = r0 + rowSize * row;
58 newShape.r = r0 + rowSize * (row + 1);
59 }
60 newShape.clockwise = sectorShape.clockwise;
61 newShape.cx = sectorShape.cx;
62 newShape.cy = sectorShape.cy;
63 outShapes.push(newShape);
64 }
65 }
66}
67function divideRect(rectShape, count, outShapes) {
68 var width = rectShape.width;
69 var height = rectShape.height;
70 var isHorizontalRow = width > height;
71 var grids = getDividingGrids([width, height], isHorizontalRow ? 0 : 1, count);
72 var rowSizeDim = isHorizontalRow ? 'width' : 'height';
73 var columnSizeDim = isHorizontalRow ? 'height' : 'width';
74 var rowDim = isHorizontalRow ? 'x' : 'y';
75 var columnDim = isHorizontalRow ? 'y' : 'x';
76 var rowSize = rectShape[rowSizeDim] / grids.length;
77 for (var row = 0; row < grids.length; row++) {
78 var columnSize = rectShape[columnSizeDim] / grids[row];
79 for (var column = 0; column < grids[row]; column++) {
80 var newShape = {};
81 newShape[rowDim] = row * rowSize;
82 newShape[columnDim] = column * columnSize;
83 newShape[rowSizeDim] = rowSize;
84 newShape[columnSizeDim] = columnSize;
85 newShape.x += rectShape.x;
86 newShape.y += rectShape.y;
87 outShapes.push(newShape);
88 }
89 }
90}
91function crossProduct2d(x1, y1, x2, y2) {
92 return x1 * y2 - x2 * y1;
93}
94function lineLineIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y) {
95 var mx = a2x - a1x;
96 var my = a2y - a1y;
97 var nx = b2x - b1x;
98 var ny = b2y - b1y;
99 var nmCrossProduct = crossProduct2d(nx, ny, mx, my);
100 if (Math.abs(nmCrossProduct) < 1e-6) {
101 return null;
102 }
103 var b1a1x = a1x - b1x;
104 var b1a1y = a1y - b1y;
105 var p = crossProduct2d(b1a1x, b1a1y, nx, ny) / nmCrossProduct;
106 if (p < 0 || p > 1) {
107 return null;
108 }
109 return new Point(p * mx + a1x, p * my + a1y);
110}
111function projPtOnLine(pt, lineA, lineB) {
112 var dir = new Point();
113 Point.sub(dir, lineB, lineA);
114 dir.normalize();
115 var dir2 = new Point();
116 Point.sub(dir2, pt, lineA);
117 var len = dir2.dot(dir);
118 return len;
119}
120function addToPoly(poly, pt) {
121 var last = poly[poly.length - 1];
122 if (last && last[0] === pt[0] && last[1] === pt[1]) {
123 return;
124 }
125 poly.push(pt);
126}
127function splitPolygonByLine(points, lineA, lineB) {
128 var len = points.length;
129 var intersections = [];
130 for (var i = 0; i < len; i++) {
131 var p0 = points[i];
132 var p1 = points[(i + 1) % len];
133 var intersectionPt = lineLineIntersect(p0[0], p0[1], p1[0], p1[1], lineA.x, lineA.y, lineB.x, lineB.y);
134 if (intersectionPt) {
135 intersections.push({
136 projPt: projPtOnLine(intersectionPt, lineA, lineB),
137 pt: intersectionPt,
138 idx: i
139 });
140 }
141 }
142 if (intersections.length < 2) {
143 return [{ points: points }, { points: points }];
144 }
145 intersections.sort(function (a, b) {
146 return a.projPt - b.projPt;
147 });
148 var splitPt0 = intersections[0];
149 var splitPt1 = intersections[intersections.length - 1];
150 if (splitPt1.idx < splitPt0.idx) {
151 var tmp = splitPt0;
152 splitPt0 = splitPt1;
153 splitPt1 = tmp;
154 }
155 var splitPt0Arr = [splitPt0.pt.x, splitPt0.pt.y];
156 var splitPt1Arr = [splitPt1.pt.x, splitPt1.pt.y];
157 var newPolyA = [splitPt0Arr];
158 var newPolyB = [splitPt1Arr];
159 for (var i = splitPt0.idx + 1; i <= splitPt1.idx; i++) {
160 addToPoly(newPolyA, points[i].slice());
161 }
162 addToPoly(newPolyA, splitPt1Arr);
163 addToPoly(newPolyA, splitPt0Arr);
164 for (var i = splitPt1.idx + 1; i <= splitPt0.idx + len; i++) {
165 addToPoly(newPolyB, points[i % len].slice());
166 }
167 addToPoly(newPolyB, splitPt0Arr);
168 addToPoly(newPolyB, splitPt1Arr);
169 return [{
170 points: newPolyA
171 }, {
172 points: newPolyB
173 }];
174}
175function binaryDividePolygon(polygonShape) {
176 var points = polygonShape.points;
177 var min = [];
178 var max = [];
179 fromPoints(points, min, max);
180 var boundingRect = new BoundingRect(min[0], min[1], max[0] - min[0], max[1] - min[1]);
181 var width = boundingRect.width;
182 var height = boundingRect.height;
183 var x = boundingRect.x;
184 var y = boundingRect.y;
185 var pt0 = new Point();
186 var pt1 = new Point();
187 if (width > height) {
188 pt0.x = pt1.x = x + width / 2;
189 pt0.y = y;
190 pt1.y = y + height;
191 }
192 else {
193 pt0.y = pt1.y = y + height / 2;
194 pt0.x = x;
195 pt1.x = x + width;
196 }
197 return splitPolygonByLine(points, pt0, pt1);
198}
199function binaryDivideRecursive(divider, shape, count, out) {
200 if (count === 1) {
201 out.push(shape);
202 }
203 else {
204 var mid = Math.floor(count / 2);
205 var sub = divider(shape);
206 binaryDivideRecursive(divider, sub[0], mid, out);
207 binaryDivideRecursive(divider, sub[1], count - mid, out);
208 }
209 return out;
210}
211export function clone(path, count) {
212 var paths = [];
213 for (var i = 0; i < count; i++) {
214 paths.push(clonePath(path));
215 }
216 return paths;
217}
218function copyPathProps(source, target) {
219 target.setStyle(source.style);
220 target.z = source.z;
221 target.z2 = source.z2;
222 target.zlevel = source.zlevel;
223}
224function polygonConvert(points) {
225 var out = [];
226 for (var i = 0; i < points.length;) {
227 out.push([points[i++], points[i++]]);
228 }
229 return out;
230}
231export function split(path, count) {
232 var outShapes = [];
233 var shape = path.shape;
234 var OutShapeCtor;
235 switch (path.type) {
236 case 'rect':
237 divideRect(shape, count, outShapes);
238 OutShapeCtor = Rect;
239 break;
240 case 'sector':
241 divideSector(shape, count, outShapes);
242 OutShapeCtor = Sector;
243 break;
244 case 'circle':
245 divideSector({
246 r0: 0, r: shape.r, startAngle: 0, endAngle: Math.PI * 2,
247 cx: shape.cx, cy: shape.cy
248 }, count, outShapes);
249 OutShapeCtor = Sector;
250 break;
251 default:
252 var m = path.getComputedTransform();
253 var scale = m ? Math.sqrt(Math.max(m[0] * m[0] + m[1] * m[1], m[2] * m[2] + m[3] * m[3])) : 1;
254 var polygons = map(pathToPolygons(path.getUpdatedPathProxy(), scale), function (poly) { return polygonConvert(poly); });
255 var polygonCount = polygons.length;
256 if (polygonCount === 0) {
257 binaryDivideRecursive(binaryDividePolygon, {
258 points: polygons[0]
259 }, count, outShapes);
260 }
261 else if (polygonCount === count) {
262 for (var i = 0; i < polygonCount; i++) {
263 outShapes.push({
264 points: polygons[i]
265 });
266 }
267 }
268 else {
269 var totalArea_1 = 0;
270 var items = map(polygons, function (poly) {
271 var min = [];
272 var max = [];
273 fromPoints(poly, min, max);
274 var area = (max[1] - min[1]) * (max[0] - min[0]);
275 totalArea_1 += area;
276 return { poly: poly, area: area };
277 });
278 items.sort(function (a, b) { return b.area - a.area; });
279 var left = count;
280 for (var i = 0; i < polygonCount; i++) {
281 var item = items[i];
282 if (left <= 0) {
283 break;
284 }
285 var selfCount = i === polygonCount - 1
286 ? left
287 : Math.ceil(item.area / totalArea_1 * count);
288 if (selfCount < 0) {
289 continue;
290 }
291 binaryDivideRecursive(binaryDividePolygon, {
292 points: item.poly
293 }, selfCount, outShapes);
294 left -= selfCount;
295 }
296 ;
297 }
298 OutShapeCtor = Polygon;
299 break;
300 }
301 if (!OutShapeCtor) {
302 return clone(path, count);
303 }
304 var out = [];
305 for (var i = 0; i < outShapes.length; i++) {
306 var subPath = new OutShapeCtor();
307 subPath.setShape(outShapes[i]);
308 copyPathProps(path, subPath);
309 out.push(subPath);
310 }
311 return out;
312}