@parliamentarch/core 4.0.0 → 5.0.0
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/README.md +37 -5
- package/dist/geometry.d.ts +31 -6
- package/dist/geometry.js +36 -19
- package/dist/geometry.js.map +1 -1
- package/dist/majority-line.d.ts +46 -0
- package/dist/majority-line.js +144 -0
- package/dist/majority-line.js.map +1 -0
- package/dist/utils.d.ts +7 -2
- package/dist/utils.js +12 -7
- package/dist/utils.js.map +1 -1
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
Tools to generate arch-styled parliamentary diagrams.
|
|
4
4
|
|
|
5
|
-

|
|
6
|
+
<!-- absolute link for NPM support -->
|
|
6
7
|
|
|
7
|
-
This package handles two things: majorly (in the `geometry` submodule), the geometry of how the seats are arranged in space, and as an aside (in the `utils` submodule), some util functions shared by the other modules taking over from there.
|
|
8
|
+
This package handles two things: majorly (in the `geometry` submodule), the geometry of how the seats are arranged in space, some additional functions to generate majority lines serpenting between the seats (in the `majority-line` submodule), and as an aside (in the `utils` submodule), some util functions shared by the other modules taking over from there and regrouping the other submodules.
|
|
8
9
|
|
|
9
10
|
Those won't be enough to generate SVG files or nodes by themselves. In fact, there is nothing specific to SVG in this package, and a wholly different display system could be used to generate a diagram from what this package provides.
|
|
10
11
|
|
|
@@ -53,6 +54,10 @@ Returns a list of each row's maximum seat capacity, starting from inner to outer
|
|
|
53
54
|
|
|
54
55
|
Returns the row thickness, i.e the difference between the radii of two consecutive rows, for a given number of rows.
|
|
55
56
|
|
|
57
|
+
`getMaxSeatRadius(nRows: number): number`
|
|
58
|
+
|
|
59
|
+
Returns the maximum radius seats can have before risking to touch their neighbors. Equal to half of the row thickness.
|
|
60
|
+
|
|
56
61
|
`FillingStrategy`
|
|
57
62
|
|
|
58
63
|
A string enum of the implemented strategies to fill the seats among the rows:
|
|
@@ -61,7 +66,7 @@ A string enum of the implemented strategies to fill the seats among the rows:
|
|
|
61
66
|
- `EMPTY_INNER`: This selects as few outermost rows as necessary to hold the given seats, then distributes the seats proportionally among them. Depending on the number of seats and rows, this either leaves empty inner rows, or is equivalent to the `DEFAULT` strategy. This is equivalent to the legacy "dense rows" option, in that in non-empty rows, the distance between consecutive seats is the smallest possible, and is close among all rows.
|
|
62
67
|
- `OUTER_PRIORITY`: This fills the rows to their maximal capacity, starting with the outermost rows going in. The result is that given a number of rows, adding one seat makes a change in only one row.
|
|
63
68
|
|
|
64
|
-
`getSeatCenters(nSeats: number, options?): Map<[number, number],
|
|
69
|
+
`getSeatCenters(nSeats: number, options?): Map<[number, number], SeatInfo>`
|
|
65
70
|
|
|
66
71
|
This is the main function of the submodule. The options are as follows:
|
|
67
72
|
|
|
@@ -71,7 +76,28 @@ This is the main function of the submodule. The options are as follows:
|
|
|
71
76
|
|
|
72
77
|
The function returns a map representing the ensemble of seats. The keys are `[x, y]` pairs, the cartesian coordinates of the center of the seat. The coordinates start from the bottom-left corner of the rectangle, with the x axis pointing to the right and the y axis pointing up. The outer radius of the annulus, equal to the height and to half of the width of the rectangle, is 1, so `x` goes from 0 to 2 and `y` goes from 0 to 1.
|
|
73
78
|
|
|
74
|
-
The values are
|
|
79
|
+
The values are objects (type aliased as `SeatInfo`). They contain:
|
|
80
|
+
- `angle: number`: the angle, in radians, calculated from the right-outermost point of the annulus arc, through the center of the annulus, to the center of the seat
|
|
81
|
+
- `rowIdx: number`: the index of the row, starting from 0 for the innermost row, and counting rows that contain no seats (for instance due to the filling strategy)
|
|
82
|
+
|
|
83
|
+
Sorting the keys by decreasing angle value returns the seats arranged from left to right. The order of the entries in the Map is undocumented, however the function may be considered pure in that for a given version of the library, and a given set of parameters, the seats will be returned in the same order.
|
|
84
|
+
|
|
85
|
+
## Majority-line module contents
|
|
86
|
+
|
|
87
|
+
`getMajorityLineCheckpoints(seatCenters, options): MajorityLineCheckpoints`
|
|
88
|
+
|
|
89
|
+
The function generates information needed to draw a curve (intended as a cubic bezier curve) zigzagging between the seats to represent a majority. It returns the base points of the bezier curve, as well as some metadata useful to generate the control points. All points are provided as `[x, y]` number coordinates.
|
|
90
|
+
The parameters are as follows:
|
|
91
|
+
|
|
92
|
+
- `seatCenters: SeatCenters`: the format returned by `geometry.getSeatCenters`.
|
|
93
|
+
- `options.ratio: number`: a value between 0 and 1, representing the share of seats that will be on the left of the majority line. Defaults to 0.5.
|
|
94
|
+
- `options.round: (number) => number`: a function that will round the number of seats on either side of the majority line. Rounding up means more seats to the left of the line. Defaults to Math.ceil, which rounds to the higher closest integer.
|
|
95
|
+
|
|
96
|
+
The fields of the returned value are as follows:
|
|
97
|
+
- `startPoint: [number, number]`: the starting point of the curve, inside all the rows.
|
|
98
|
+
- `checkpoints: [number, number][]`: the intermediary points of the curve, roughly one per row.
|
|
99
|
+
- `endPoint: [number, number]`: the end point of the curve, outside all the rows.
|
|
100
|
+
- `rowThickness: number`: the row thickness, can be useful to scale the control points relative to the provided points.
|
|
75
101
|
|
|
76
102
|
## Utils module contents
|
|
77
103
|
|
|
@@ -92,8 +118,14 @@ This generic function turns one representation of how each seat is displayed, in
|
|
|
92
118
|
|
|
93
119
|
`precomputeFromAttribution<SeatDisplay>(attribution, options?): PrecomputeReturn<SeatDisplay>`
|
|
94
120
|
|
|
95
|
-
This function pre-calculates some information from an attribution of seats, making it almost enough to be displayed.
|
|
121
|
+
This function pre-calculates some information from an attribution of seats, making it almost enough to be displayed.
|
|
96
122
|
|
|
97
123
|
- `attribution: ReadonlyMap<SeatDisplay, number> | readonly WithNumber<SeatDisplay>[]`
|
|
98
124
|
- `options.seatRadiusFactor`: the factor between 0 and 1 described earlier. At 1, neighboring seats will touch one another.
|
|
125
|
+
- `options.majorityLines`: a list of option objects as taken by `majority-line.getMajorityLineCheckpoints`. Each object, even if empty, will generate a line.
|
|
99
126
|
- `options`: the rest of the options are the same as taken by the `getSeatCenters` function.
|
|
127
|
+
|
|
128
|
+
The return value is an object containing the following keys:
|
|
129
|
+
- `groupedSeatCenters`: grouped seat centers as returned by the previous function.
|
|
130
|
+
- `seatActualRadius: number`: the radius of the seats in the same unit as the coordinates.
|
|
131
|
+
- `majorityLineCheckpoints`: an array containing as many results of the `getMajorityLineCheckpoints` function (and in the same order) as related options were passed.
|
package/dist/geometry.d.ts
CHANGED
|
@@ -4,12 +4,23 @@
|
|
|
4
4
|
*
|
|
5
5
|
* If you divide the half-disk of the hemicycle into one half-disk of half the radius and one half-annulus outside of it,
|
|
6
6
|
* the innermost row lies on the border between the two, and the outermost row lies entirely inside the half-annulus.
|
|
7
|
-
* So, looking at
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* So, looking at a vertical line cutting the diagram in half,
|
|
8
|
+
* that line's length is 1,
|
|
9
|
+
* the innermost row crosses the line in its middle,
|
|
10
|
+
* and all the rows minus half of the innermost are higher than this middle point.
|
|
11
|
+
* So, 1 = (nRows - .5) *2 *rowThickness
|
|
12
|
+
* 1 = (2*nRows - 1) *rowThickness
|
|
13
|
+
* rowThickness = 1 / (2*nRows -1)
|
|
11
14
|
*/
|
|
12
15
|
export declare function getRowThickness(nRows: number): number;
|
|
16
|
+
export declare function getMaxSeatRadius(nRows: number): number;
|
|
17
|
+
/**
|
|
18
|
+
* @param rowIdx the index of the row, starting from 0 from the inner out,
|
|
19
|
+
* and counting the rows that may be empty due to the filling strategy
|
|
20
|
+
* @param rowThickness as returned by getRowThickness
|
|
21
|
+
* @returns the radius of the circle crossing the center of each seat in the row
|
|
22
|
+
*/
|
|
23
|
+
export declare function getRowArcRadius(rowIdx: number, rowThickness: number): number;
|
|
13
24
|
/**
|
|
14
25
|
* This indicates the maximal number of seats for each row for a given number of rows.
|
|
15
26
|
* @param spanAngle if provided, it is the angle in degrees that the hemicycle, as an annulus arc, covers.
|
|
@@ -42,6 +53,18 @@ export interface GetSeatCentersOptions {
|
|
|
42
53
|
fillingStrategy: FillingStrategy;
|
|
43
54
|
spanAngle: number;
|
|
44
55
|
}
|
|
56
|
+
export interface SeatInfo {
|
|
57
|
+
/**
|
|
58
|
+
* The angle in radian, from 0 to 2π,
|
|
59
|
+
* trigonometrically positive (the rightmost seats have the smallest angle).
|
|
60
|
+
*/
|
|
61
|
+
angle: number;
|
|
62
|
+
/**
|
|
63
|
+
* This is 0-indexed, starting from the innermost row,
|
|
64
|
+
* even if that row is completely empty due to the filling strategy or any other option.
|
|
65
|
+
*/
|
|
66
|
+
rowIdx: number;
|
|
67
|
+
}
|
|
45
68
|
/**
|
|
46
69
|
* Computes the coordinates of the centers of the seats, with (as a bonus) the angle of each seat in the hemicycle.
|
|
47
70
|
* The canvas is assumed to be 2 in width and 1 in height, with the x axis pointing right and the y axis pointing up.
|
|
@@ -56,6 +79,8 @@ export interface GetSeatCentersOptions {
|
|
|
56
79
|
* through the center, to the side of the leftmost seats.
|
|
57
80
|
* It takes a value in degrees and defaults to 180 to make a true hemicycle.
|
|
58
81
|
* Values above 180 are not supported.
|
|
59
|
-
* @returns a map whose keys are the seat centers as [x, y] coordinates
|
|
82
|
+
* @returns a map whose keys are the seat centers as [x, y] coordinates.
|
|
83
|
+
* The values of the map contain pre-computed metadata about the seats, useful to sort or categorize them.
|
|
84
|
+
* The returned order of the seats is unspecified.
|
|
60
85
|
*/
|
|
61
|
-
export declare function getSeatCenters(nSeats: number, { minNRows, fillingStrategy, spanAngle, }?: Partial<GetSeatCentersOptions
|
|
86
|
+
export declare function getSeatCenters(nSeats: number, { minNRows, fillingStrategy, spanAngle, }?: Partial<Readonly<GetSeatCentersOptions>>): Map<[number, number], SeatInfo>;
|
package/dist/geometry.js
CHANGED
|
@@ -6,13 +6,28 @@ const DEFAULT_SPAN_ANGLE = 180;
|
|
|
6
6
|
*
|
|
7
7
|
* If you divide the half-disk of the hemicycle into one half-disk of half the radius and one half-annulus outside of it,
|
|
8
8
|
* the innermost row lies on the border between the two, and the outermost row lies entirely inside the half-annulus.
|
|
9
|
-
* So, looking at
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* So, looking at a vertical line cutting the diagram in half,
|
|
10
|
+
* that line's length is 1,
|
|
11
|
+
* the innermost row crosses the line in its middle,
|
|
12
|
+
* and all the rows minus half of the innermost are higher than this middle point.
|
|
13
|
+
* So, 1 = (nRows - .5) *2 *rowThickness
|
|
14
|
+
* 1 = (2*nRows - 1) *rowThickness
|
|
15
|
+
* rowThickness = 1 / (2*nRows -1)
|
|
13
16
|
*/
|
|
14
17
|
export function getRowThickness(nRows) {
|
|
15
|
-
return 1 / (
|
|
18
|
+
return 1 / (2 * nRows - 1);
|
|
19
|
+
}
|
|
20
|
+
export function getMaxSeatRadius(nRows) {
|
|
21
|
+
return getRowThickness(nRows) / 2;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* @param rowIdx the index of the row, starting from 0 from the inner out,
|
|
25
|
+
* and counting the rows that may be empty due to the filling strategy
|
|
26
|
+
* @param rowThickness as returned by getRowThickness
|
|
27
|
+
* @returns the radius of the circle crossing the center of each seat in the row
|
|
28
|
+
*/
|
|
29
|
+
export function getRowArcRadius(rowIdx, rowThickness) {
|
|
30
|
+
return .5 + rowIdx * rowThickness;
|
|
16
31
|
}
|
|
17
32
|
/**
|
|
18
33
|
* This indicates the maximal number of seats for each row for a given number of rows.
|
|
@@ -21,11 +36,11 @@ export function getRowThickness(nRows) {
|
|
|
21
36
|
* The length of the array is nRows.
|
|
22
37
|
*/
|
|
23
38
|
export function getRowsFromNRows(nRows, spanAngle = DEFAULT_SPAN_ANGLE) {
|
|
24
|
-
const
|
|
39
|
+
const thic = getRowThickness(nRows);
|
|
25
40
|
const radianSpanAngle = Math.PI * spanAngle / 180;
|
|
26
41
|
return Array.from({ length: nRows }, (_, r) => {
|
|
27
|
-
const rowArcRadius =
|
|
28
|
-
return Math.floor(radianSpanAngle * rowArcRadius /
|
|
42
|
+
const rowArcRadius = getRowArcRadius(r, thic);
|
|
43
|
+
return Math.floor(radianSpanAngle * rowArcRadius / thic);
|
|
29
44
|
});
|
|
30
45
|
}
|
|
31
46
|
/**
|
|
@@ -69,11 +84,14 @@ export var FillingStrategy;
|
|
|
69
84
|
* through the center, to the side of the leftmost seats.
|
|
70
85
|
* It takes a value in degrees and defaults to 180 to make a true hemicycle.
|
|
71
86
|
* Values above 180 are not supported.
|
|
72
|
-
* @returns a map whose keys are the seat centers as [x, y] coordinates
|
|
87
|
+
* @returns a map whose keys are the seat centers as [x, y] coordinates.
|
|
88
|
+
* The values of the map contain pre-computed metadata about the seats, useful to sort or categorize them.
|
|
89
|
+
* The returned order of the seats is unspecified.
|
|
73
90
|
*/
|
|
74
91
|
export function getSeatCenters(nSeats, { minNRows = 0, fillingStrategy = FillingStrategy.DEFAULT, spanAngle = DEFAULT_SPAN_ANGLE, } = {}) {
|
|
75
92
|
const nRows = Math.max(minNRows, getNRowsFromNSeats(nSeats, spanAngle));
|
|
76
93
|
const rowThicc = getRowThickness(nRows);
|
|
94
|
+
const maxSeatRadius = rowThicc / 2;
|
|
77
95
|
const spanAngleMargin = (1 - spanAngle / 180) * Math.PI / 2;
|
|
78
96
|
const maxedRows = getRowsFromNRows(nRows, spanAngle);
|
|
79
97
|
let startingRow, fillingRatio, seatsOnStartingRow;
|
|
@@ -114,34 +132,33 @@ export function getSeatCenters(nSeats, { minNRows = 0, fillingStrategy = Filling
|
|
|
114
132
|
throw new Error(`Invalid filling strategy: ${fillingStrategy}`);
|
|
115
133
|
}
|
|
116
134
|
const positions = new Map();
|
|
117
|
-
for (let
|
|
135
|
+
for (let rowIdx = startingRow; rowIdx < nRows; rowIdx++) {
|
|
118
136
|
let nSeatsThisRow;
|
|
119
|
-
if (
|
|
137
|
+
if (rowIdx === nRows - 1) { // if it's the last, outermost row
|
|
120
138
|
// fit all the remaining seats
|
|
121
139
|
nSeatsThisRow = nSeats - positions.size;
|
|
122
140
|
}
|
|
123
141
|
else if (fillingStrategy === FillingStrategy.OUTER_PRIORITY) {
|
|
124
|
-
if (
|
|
142
|
+
if (rowIdx === startingRow) {
|
|
125
143
|
nSeatsThisRow = seatsOnStartingRow;
|
|
126
144
|
}
|
|
127
145
|
else {
|
|
128
|
-
nSeatsThisRow = maxedRows[
|
|
146
|
+
nSeatsThisRow = maxedRows[rowIdx];
|
|
129
147
|
}
|
|
130
148
|
}
|
|
131
149
|
else {
|
|
132
150
|
// fullness of the diagram times the maximal number of seats in this row
|
|
133
|
-
nSeatsThisRow = Math.round(fillingRatio * maxedRows[
|
|
151
|
+
nSeatsThisRow = Math.round(fillingRatio * maxedRows[rowIdx]);
|
|
134
152
|
// actually more precise rounding : avoid rounding errors to accumulate too much
|
|
135
153
|
// nSeatsThisRow = Math.round((nSeats-positions.size) * maxedRows[r] / maxedRows.reduce((a, b) => a + b, 0));
|
|
136
154
|
}
|
|
137
|
-
|
|
138
|
-
const rowArcRadius = .5 + 2 * r * rowThicc;
|
|
155
|
+
const rowArcRadius = getRowArcRadius(rowIdx, rowThicc);
|
|
139
156
|
if (nSeatsThisRow === 1) {
|
|
140
|
-
positions.set([1, rowArcRadius], Math.PI / 2);
|
|
157
|
+
positions.set([1, rowArcRadius], { rowIdx, angle: Math.PI / 2 });
|
|
141
158
|
}
|
|
142
159
|
else {
|
|
143
160
|
// the angle necessary in this row to put the first (and last) seats fully on the canvas
|
|
144
|
-
const angleMargin = Math.asin(
|
|
161
|
+
const angleMargin = Math.asin(maxSeatRadius / rowArcRadius)
|
|
145
162
|
// add the margin to make up the side angle
|
|
146
163
|
+ spanAngleMargin;
|
|
147
164
|
// alternatively, allow the centers of the seats by the side to reach the angle's limits
|
|
@@ -153,7 +170,7 @@ export function getSeatCenters(nSeats, { minNRows = 0, fillingStrategy = Filling
|
|
|
153
170
|
for (let s = 0; s < nSeatsThisRow; s++) {
|
|
154
171
|
const angle = angleMargin + s * angleStep;
|
|
155
172
|
// an oriented angle, so it goes trig positive (counterclockwise)
|
|
156
|
-
positions.set([1 + rowArcRadius * Math.cos(angle), rowArcRadius * Math.sin(angle)], angle);
|
|
173
|
+
positions.set([1 + rowArcRadius * Math.cos(angle), rowArcRadius * Math.sin(angle)], { rowIdx, angle });
|
|
157
174
|
}
|
|
158
175
|
}
|
|
159
176
|
}
|
package/dist/geometry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geometry.js","sourceRoot":"","sources":["../src/geometry.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAE/B
|
|
1
|
+
{"version":3,"file":"geometry.js","sourceRoot":"","sources":["../src/geometry.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAE/B;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa;IACzC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAC,KAAK,GAAG,CAAC,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC1C,OAAO,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACtC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,YAAoB;IAChE,OAAO,EAAE,GAAG,MAAM,GAAG,YAAY,CAAC;AACtC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa,EAAE,SAAS,GAAG,kBAAkB;IAC1E,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACpC,MAAM,eAAe,GAAG,IAAI,CAAC,EAAE,GAAG,SAAS,GAAG,GAAG,CAAC;IAClD,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC1C,MAAM,YAAY,GAAG,eAAe,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,YAAY,GAAG,IAAI,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;AACP,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc,EAAE,SAAS,GAAG,kBAAkB;IAC7E,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,OAAO,gBAAgB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,EAAE,CAAC;QAC5E,KAAK,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,MAAM,CAAN,IAAY,eAiBX;AAjBD,WAAY,eAAe;IACvB;;;OAGG;IACH,sCAAmB,CAAA;IAEnB;;;OAGG;IACH,8CAA2B,CAAA;IAE3B;;OAEG;IACH,oDAAiC,CAAA;AACrC,CAAC,EAjBW,eAAe,KAAf,eAAe,QAiB1B;AAqBD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,cAAc,CAC1B,MAAc,EACd,EACI,QAAQ,GAAG,CAAC,EACZ,eAAe,GAAG,eAAe,CAAC,OAAO,EACzC,SAAS,GAAG,kBAAkB,MACY,EAAE;IAEhD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,kBAAkB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IACxE,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,aAAa,GAAG,QAAQ,GAAC,CAAC,CAAC;IACjC,MAAM,eAAe,GAAG,CAAC,CAAC,GAAG,SAAS,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IAE5D,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAErD,IAAI,WAAW,EAAE,YAAY,EAAE,kBAAkB,CAAC;IAClD,QAAQ,eAAe,EAAE,CAAC;QACtB,KAAK,eAAe,CAAC,OAAO;YACxB,WAAW,GAAG,CAAC,CAAC;YAChB,YAAY,GAAG,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YAC7D,MAAM;QAEV,KAAK,eAAe,CAAC,WAAW;YAC5B,CAAC;gBACG,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC;gBAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC;oBACxD,IAAI,CAAC,KAAK,EAAE,CAAC;gBACjB,CAAC;gBACD,qEAAqE;gBACrE,6BAA6B;gBAE7B,kDAAkD;gBAClD,+BAA+B;gBAC/B,WAAW,GAAG,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;gBAClC,YAAY,GAAG,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YAC5D,CAAC;YACD,MAAM;QAEV,KAAK,eAAe,CAAC,cAAc;YAC/B,CAAC;gBACG,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC;gBAC/B,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,EAAE,CAAC;oBAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;gBACjB,CAAC;gBACD,6DAA6D;gBAC7D,6BAA6B;gBAE7B,mDAAmD;gBACnD,oEAAoE;gBACpE,WAAW,GAAG,KAAK,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;gBACtC,kBAAkB,GAAG,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YAClE,CAAC;YACD,MAAM;QAEV;YACI,MAAM,IAAI,KAAK,CAAC,6BAA6B,eAAe,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,GAAG,EAA8B,CAAC;IACxD,KAAK,IAAI,MAAM,GAAG,WAAW,EAAE,MAAM,GAAG,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;QACtD,IAAI,aAAqB,CAAC;QAC1B,IAAI,MAAM,KAAK,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,kCAAkC;YAC1D,8BAA8B;YAC9B,aAAa,GAAG,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC;QAC5C,CAAC;aAAM,IAAI,eAAe,KAAK,eAAe,CAAC,cAAc,EAAE,CAAC;YAC5D,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;gBACzB,aAAa,GAAG,kBAAmB,CAAC;YACxC,CAAC;iBAAM,CAAC;gBACJ,aAAa,GAAG,SAAS,CAAC,MAAM,CAAE,CAAC;YACvC,CAAC;QACL,CAAC;aAAM,CAAC;YACJ,wEAAwE;YACxE,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,YAAa,GAAG,SAAS,CAAC,MAAM,CAAE,CAAC,CAAC;YAC/D,gFAAgF;YAChF,6GAA6G;QACjH,CAAC;QAED,MAAM,YAAY,GAAG,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAEvD,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;YACtB,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QACrE,CAAC;aAAM,CAAC;YACJ,wFAAwF;YACxF,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;gBACvD,2CAA2C;kBACzC,eAAe,CAAC;YACtB,wFAAwF;YACxF,8DAA8D;YAE9D,6CAA6C;YAC7C,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC;YACpE,6EAA6E;YAC7E,gEAAgE;YAEhE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,EAAE,CAAC,EAAE,EAAE,CAAC;gBACrC,MAAM,KAAK,GAAG,WAAW,GAAG,CAAC,GAAG,SAAS,CAAC;gBAC1C,iEAAiE;gBACjE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YAC3G,CAAC;QACL,CAAC;IACL,CAAC;IACD,OAAO,SAAS,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { SeatInfo } from "./geometry.js";
|
|
2
|
+
type Point = [number, number];
|
|
3
|
+
type SeatCenters = ReadonlyMap<Point, SeatInfo>;
|
|
4
|
+
type Rounder = (n: number) => number;
|
|
5
|
+
export interface GetMajorityLineCheckpointsOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Used to round the sharing of the assembly.
|
|
8
|
+
* Rounding up means more seats to the left.
|
|
9
|
+
* Defaults to Math.ceil,
|
|
10
|
+
* which rounds to the higher closest integer.
|
|
11
|
+
*/
|
|
12
|
+
round: Rounder;
|
|
13
|
+
/**
|
|
14
|
+
* A value between 0 and 1
|
|
15
|
+
* representing the share of the seats that will be on the left.
|
|
16
|
+
* Defaults to .5.
|
|
17
|
+
*/
|
|
18
|
+
ratio: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Represents all the base points necessary to draw a line (ideally a bezier curve)
|
|
22
|
+
* zigzagging between the seats to represent a majority.
|
|
23
|
+
* The base points are provided, as well as values to help create control points.
|
|
24
|
+
*/
|
|
25
|
+
export interface MajorityLineCheckpoints {
|
|
26
|
+
/** The starting point, on the inner side of the arch. */
|
|
27
|
+
startPoint: Point;
|
|
28
|
+
/**
|
|
29
|
+
* A list of points, one for each row
|
|
30
|
+
* (though not necessarily placed exactly on the row's half-circle),
|
|
31
|
+
* from inner to outer.
|
|
32
|
+
*/
|
|
33
|
+
checkpoints: Point[];
|
|
34
|
+
/** The end point, on the outer side of the arch. */
|
|
35
|
+
endPoint: Point;
|
|
36
|
+
/**
|
|
37
|
+
* The row thickness.
|
|
38
|
+
* Can help place the control points from each base point,
|
|
39
|
+
* offset by some factor times that value,
|
|
40
|
+
* for instance towards the center of the diagram,
|
|
41
|
+
* or parallel to the direction set by the ratio.
|
|
42
|
+
*/
|
|
43
|
+
rowThickness: number;
|
|
44
|
+
}
|
|
45
|
+
export declare function getMajorityLineCheckpoints(seatCenters: SeatCenters, { round, ratio, }?: Partial<Readonly<GetMajorityLineCheckpointsOptions>>): MajorityLineCheckpoints;
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { getRowArcRadius, getRowThickness } from "./geometry.js";
|
|
2
|
+
const sign = Math.sign;
|
|
3
|
+
export function getMajorityLineCheckpoints(seatCenters, { round = Math.ceil, ratio = .5, } = {}) {
|
|
4
|
+
const isInRightPart = getIsInRightPart(seatCenters, round, ratio);
|
|
5
|
+
const seatsPerRow = getSeatsPerRow(seatCenters);
|
|
6
|
+
const rowThickness = getRowThickness(seatsPerRow.length);
|
|
7
|
+
const maxSeatRadius = rowThickness / 2;
|
|
8
|
+
if (ratio === .5) {
|
|
9
|
+
return {
|
|
10
|
+
startPoint: [1, .5 - maxSeatRadius],
|
|
11
|
+
checkpoints: getCheckpointsForHalf(seatsPerRow, rowThickness, maxSeatRadius, isInRightPart),
|
|
12
|
+
endPoint: [1, 1],
|
|
13
|
+
rowThickness,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
const ratioAngle = (1 - ratio) * Math.PI;
|
|
18
|
+
return {
|
|
19
|
+
startPoint: polarToCartesian(.5 - maxSeatRadius, ratioAngle),
|
|
20
|
+
checkpoints: getCheckpoints(seatCenters, seatsPerRow, rowThickness, maxSeatRadius, isInRightPart, ratioAngle),
|
|
21
|
+
endPoint: polarToCartesian(1, ratioAngle),
|
|
22
|
+
rowThickness,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function getIsInRightPart(seatCenters, round, ratio) {
|
|
27
|
+
const rightPart = new Set([...seatCenters.keys()]
|
|
28
|
+
.sort((k1, k2) => seatCenters.get(k1).angle - seatCenters.get(k2).angle)
|
|
29
|
+
.slice(0, seatCenters.size - round(seatCenters.size * ratio)));
|
|
30
|
+
return rightPart.has.bind(rightPart);
|
|
31
|
+
}
|
|
32
|
+
function getSeatsPerRow(seatCenters) {
|
|
33
|
+
var _a;
|
|
34
|
+
var _b;
|
|
35
|
+
const rv = [];
|
|
36
|
+
for (const [seatCenter, seatInfo] of seatCenters) {
|
|
37
|
+
((_a = rv[_b = seatInfo.rowIdx]) !== null && _a !== void 0 ? _a : (rv[_b] = [])).push(seatCenter);
|
|
38
|
+
}
|
|
39
|
+
return rv;
|
|
40
|
+
}
|
|
41
|
+
function getCheckpointsForHalf(seatsPerRow, rowThicc, maxSeatRadius, isInRightPart) {
|
|
42
|
+
const checkpoints = [];
|
|
43
|
+
for (let rowIdx = 0; rowIdx < seatsPerRow.length; rowIdx++) {
|
|
44
|
+
const row = seatsPerRow[rowIdx];
|
|
45
|
+
const rowArcRadius = getRowArcRadius(rowIdx, rowThicc);
|
|
46
|
+
const rowSide = getRowSideForHalf(row, isInRightPart);
|
|
47
|
+
checkpoints.push([1 + rowSide * maxSeatRadius, rowArcRadius]);
|
|
48
|
+
}
|
|
49
|
+
return checkpoints;
|
|
50
|
+
}
|
|
51
|
+
function getRowSideForHalf(row, isInRightPart) {
|
|
52
|
+
if ((row.length % 2) === 0) {
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
const nSeatsRightPartInRow = row.reduce((a, p) => isInRightPart(p) ? a + 1 : a, 0);
|
|
56
|
+
return sign((row.length / 2) - nSeatsRightPartInRow);
|
|
57
|
+
}
|
|
58
|
+
/*
|
|
59
|
+
multi-point placement with non-half ratio
|
|
60
|
+
|
|
61
|
+
for each row
|
|
62
|
+
Find the two boundary seats
|
|
63
|
+
If there is none, use the straight point line (on the row semi-circle and whose angle is the ratio) and move on to the next row.
|
|
64
|
+
If there is two, comparing by angle, keep the seat nearest to the ratio angle.
|
|
65
|
+
Test whether the straight line would be within maxSeatRadius (=rowThickness/2) of the seat.
|
|
66
|
+
If not, take the straight point.
|
|
67
|
+
If so, then put the line on the side of the seat depending on which part it's in,
|
|
68
|
+
and either (1) the point at a maxSeatRadius distance of the seat and on a perpendicular to the straight line passing through the seat,
|
|
69
|
+
or (2) the point at a maxSeatRadius distance of the seat and on the row's base semicircle.
|
|
70
|
+
|
|
71
|
+
in case (1) the control point is offset by a vector colinear to the straight line and whose norm is the offset value
|
|
72
|
+
in case (2) the control point is a polar point from the center of the diagram,
|
|
73
|
+
whose angle is the same as the point and whose distance is the point's minus (or plus) the offset value
|
|
74
|
+
*/
|
|
75
|
+
function getCheckpoints(seatCenters, seatsPerRow, rowThicc, maxSeatRadius, isInRightPart, ratioAngle) {
|
|
76
|
+
const checkpoints = [];
|
|
77
|
+
for (let rowIdx = 0; rowIdx < seatsPerRow.length; rowIdx++) {
|
|
78
|
+
const row = seatsPerRow[rowIdx];
|
|
79
|
+
const rowArcRadius = getRowArcRadius(rowIdx, rowThicc);
|
|
80
|
+
const straightLinePoint = polarToCartesian(rowArcRadius, ratioAngle);
|
|
81
|
+
const [leftSeat, rightSeat] = getBoundarySeats(row, isInRightPart);
|
|
82
|
+
let seat;
|
|
83
|
+
if (leftSeat === null) {
|
|
84
|
+
if (rightSeat === null) {
|
|
85
|
+
checkpoints.push(straightLinePoint);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
seat = rightSeat;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
if (rightSeat === null) {
|
|
94
|
+
seat = leftSeat;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
// between two seats
|
|
98
|
+
if (Math.abs(seatCenters.get(leftSeat).angle - ratioAngle) < Math.abs(seatCenters.get(rightSeat).angle - ratioAngle)) {
|
|
99
|
+
seat = leftSeat;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
seat = rightSeat;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (squareDistanceCartesian(straightLinePoint, seat) >= maxSeatRadius ** 2) {
|
|
107
|
+
checkpoints.push(straightLinePoint);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const sidgn = isInRightPart(seat) ? 1 : -1;
|
|
111
|
+
// (2)
|
|
112
|
+
const seatAngle = getPolarAngle(seat);
|
|
113
|
+
const angleIncrement = 2 * Math.atan(maxSeatRadius / 2 / rowArcRadius);
|
|
114
|
+
const point = polarToCartesian(rowArcRadius, seatAngle + sidgn * angleIncrement);
|
|
115
|
+
checkpoints.push(point);
|
|
116
|
+
}
|
|
117
|
+
return checkpoints;
|
|
118
|
+
}
|
|
119
|
+
function getBoundarySeats(row, isInRightPart) {
|
|
120
|
+
let lastSeatRightSide = null, firstSeatLeftSide = null;
|
|
121
|
+
// relies on getSeatCenters returning them by increasing angle, and getSeatsPerRow being stable
|
|
122
|
+
// could also just do a sort before the for loop
|
|
123
|
+
for (const seat of row) {
|
|
124
|
+
if (isInRightPart(seat)) {
|
|
125
|
+
lastSeatRightSide = seat;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
firstSeatLeftSide = seat;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return [firstSeatLeftSide, lastSeatRightSide];
|
|
133
|
+
}
|
|
134
|
+
function polarToCartesian(norm, angle) {
|
|
135
|
+
return [1 + norm * Math.cos(angle), norm * Math.sin(angle)];
|
|
136
|
+
}
|
|
137
|
+
/** From the diagram's center. */
|
|
138
|
+
function getPolarAngle([x, y]) {
|
|
139
|
+
return Math.atan2(y, x - 1);
|
|
140
|
+
}
|
|
141
|
+
function squareDistanceCartesian(pointA, pointB) {
|
|
142
|
+
return (pointB[0] - pointA[0]) ** 2 + (pointB[1] - pointA[1]) ** 2;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=majority-line.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"majority-line.js","sourceRoot":"","sources":["../src/majority-line.ts"],"names":[],"mappings":"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"}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { GetSeatCentersOptions } from "./geometry.js";
|
|
2
|
+
import { GetMajorityLineCheckpointsOptions, MajorityLineCheckpoints } from "./majority-line.js";
|
|
2
3
|
type WithNumber<T> = T & {
|
|
3
4
|
readonly nSeats?: number | undefined;
|
|
4
5
|
};
|
|
@@ -22,19 +23,23 @@ type GroupedSeatCenters<SeatDisplay, SeatLocation> = Iterable<readonly [SeatDisp
|
|
|
22
23
|
export declare function regroupSeatCenters<SeatDisplay, SeatLocation = SeatCenter>(seatCenters: MappedSeatCenters<SeatDisplay, SeatLocation>): GroupedSeatCenters<SeatDisplay, SeatLocation>;
|
|
23
24
|
export interface PrecomputeOptions extends GetSeatCentersOptions {
|
|
24
25
|
seatRadiusFactor: number;
|
|
26
|
+
majorityLines: readonly Partial<Readonly<GetMajorityLineCheckpointsOptions>>[];
|
|
25
27
|
}
|
|
26
28
|
export interface PrecomputeReturn<SeatDisplay> {
|
|
27
29
|
groupedSeatCenters: Map<SeatDisplay, SeatCenter[]>;
|
|
28
30
|
seatActualRadius: number;
|
|
31
|
+
majorityLineCheckpoints: MajorityLineCheckpoints[];
|
|
29
32
|
}
|
|
30
33
|
/**
|
|
31
34
|
* Pre-computes some values that are useful in the extensions that generate actual diagrams.
|
|
32
35
|
* The SeatDisplay type will depend on the extension.
|
|
33
36
|
* @param options.seatRadiusFactor the ratio (between 0 and 1) of the seat radius over the row thickness. Defaults to .8.
|
|
37
|
+
* @param options.majorityLine if included, a list of options for the majority line generator, each object will generate one line.
|
|
34
38
|
* @param options the rest of the options are those passed through to the options parameter of the getSeatCenters function.
|
|
35
|
-
* @returns an object with
|
|
39
|
+
* @returns an object with the following properties:
|
|
36
40
|
* the groupedSeatCenters key, a mapping of SeatDisplay objects to the list of the corresponding seats' coordinates,
|
|
37
|
-
*
|
|
41
|
+
* the seatActualRadius key, the actual radius of the seats (in the same unit as the coordinates),
|
|
42
|
+
* and the majorityLineCheckpoints key containing an array of as many results of the majority line calculations as related options were passed.
|
|
38
43
|
*/
|
|
39
44
|
export declare function precomputeFromAttribution<SeatDisplay>(attribution: ReadonlyMap<SeatDisplay, number> | readonly WithNumber<SeatDisplay>[], options?: Partial<Readonly<PrecomputeOptions>>): PrecomputeReturn<SeatDisplay>;
|
|
40
45
|
export {};
|
package/dist/utils.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { getNRowsFromNSeats,
|
|
1
|
+
import { getNRowsFromNSeats, getMaxSeatRadius, getSeatCenters } from "./geometry.js";
|
|
2
|
+
import { getMajorityLineCheckpoints } from "./majority-line.js";
|
|
2
3
|
const isReadonlyMap = v => v instanceof Map;
|
|
3
4
|
/**
|
|
4
5
|
* Typically SeatLocation is a tuple of x/y coordinates, and SeatDisplay gives infos on what seats should look like.
|
|
@@ -47,24 +48,28 @@ export function regroupSeatCenters(seatCenters) {
|
|
|
47
48
|
* Pre-computes some values that are useful in the extensions that generate actual diagrams.
|
|
48
49
|
* The SeatDisplay type will depend on the extension.
|
|
49
50
|
* @param options.seatRadiusFactor the ratio (between 0 and 1) of the seat radius over the row thickness. Defaults to .8.
|
|
51
|
+
* @param options.majorityLine if included, a list of options for the majority line generator, each object will generate one line.
|
|
50
52
|
* @param options the rest of the options are those passed through to the options parameter of the getSeatCenters function.
|
|
51
|
-
* @returns an object with
|
|
53
|
+
* @returns an object with the following properties:
|
|
52
54
|
* the groupedSeatCenters key, a mapping of SeatDisplay objects to the list of the corresponding seats' coordinates,
|
|
53
|
-
*
|
|
55
|
+
* the seatActualRadius key, the actual radius of the seats (in the same unit as the coordinates),
|
|
56
|
+
* and the majorityLineCheckpoints key containing an array of as many results of the majority line calculations as related options were passed.
|
|
54
57
|
*/
|
|
55
58
|
export function precomputeFromAttribution(attribution, options = {}) {
|
|
56
|
-
var _a;
|
|
59
|
+
var _a, _b, _c;
|
|
57
60
|
if (!isReadonlyMap(attribution)) {
|
|
58
61
|
attribution = new Map(attribution.map(seatData => { var _a; return [seatData, (_a = seatData.nSeats) !== null && _a !== void 0 ? _a : 1]; }));
|
|
59
62
|
}
|
|
60
63
|
const seatRadiusFactor = (_a = options.seatRadiusFactor) !== null && _a !== void 0 ? _a : .8;
|
|
61
64
|
const nSeats = [...attribution.values()].reduce((a, b) => a + b, 0);
|
|
62
|
-
const
|
|
63
|
-
const groupedSeatCenters = dispatchSeats(attribution, [...
|
|
64
|
-
const seatActualRadius = seatRadiusFactor *
|
|
65
|
+
const seatCenters = getSeatCenters(nSeats, options);
|
|
66
|
+
const groupedSeatCenters = dispatchSeats(attribution, [...seatCenters.keys()].sort((a, b) => seatCenters.get(b).angle - seatCenters.get(a).angle));
|
|
67
|
+
const seatActualRadius = seatRadiusFactor * getMaxSeatRadius(getNRowsFromNSeats(nSeats, options.spanAngle));
|
|
68
|
+
const majorityLineCheckpoints = (_c = (_b = options.majorityLines) === null || _b === void 0 ? void 0 : _b.map(o => getMajorityLineCheckpoints(seatCenters, o))) !== null && _c !== void 0 ? _c : [];
|
|
65
69
|
return {
|
|
66
70
|
groupedSeatCenters,
|
|
67
71
|
seatActualRadius,
|
|
72
|
+
majorityLineCheckpoints,
|
|
68
73
|
};
|
|
69
74
|
}
|
|
70
75
|
//# sourceMappingURL=utils.js.map
|
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parliamentarch/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Tools to generate arch-styled parliamentary diagrams",
|
|
5
5
|
"type": "module",
|
|
6
6
|
|
|
@@ -13,6 +13,12 @@
|
|
|
13
13
|
"default": "./dist/geometry.js"
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
|
+
"./majority-line": {
|
|
17
|
+
"import": {
|
|
18
|
+
"types": "./dist/majority-line.d.ts",
|
|
19
|
+
"default": "./dist/majority-line.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
16
22
|
"./utils": {
|
|
17
23
|
"import": {
|
|
18
24
|
"types": "./dist/utils.d.ts",
|
|
@@ -38,7 +44,7 @@
|
|
|
38
44
|
},
|
|
39
45
|
|
|
40
46
|
"author": "Gouvernathor",
|
|
41
|
-
"license": "BSD-3-Clause",
|
|
47
|
+
"license": "(BSD-3-Clause OR CC-BY-4.0)",
|
|
42
48
|
"repository": {
|
|
43
49
|
"type": "git",
|
|
44
50
|
"url": "https://codeberg.org/Gouvernathor/ParliamentArch-TS.git",
|