ts-maps 0.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 +284 -0
- package/dist/apply-transform.d.ts +47 -0
- package/dist/base-element.d.ts +5 -0
- package/dist/base.d.ts +19 -0
- package/dist/brasil.d.ts +1 -0
- package/dist/canada.d.ts +1 -0
- package/dist/canvas-element.d.ts +8 -0
- package/dist/coords-to-point.d.ts +26 -0
- package/dist/create-lines.d.ts +39 -0
- package/dist/create-markers.d.ts +51 -0
- package/dist/create-regions.d.ts +19 -0
- package/dist/create-series.d.ts +20 -0
- package/dist/data-visualization.d.ts +99 -0
- package/dist/deep-merge.d.ts +44 -0
- package/dist/event-handler.d.ts +12 -0
- package/dist/events.d.ts +14 -0
- package/dist/get-inset-for-point.d.ts +24 -0
- package/dist/get-marker-position.d.ts +15 -0
- package/dist/image-element.d.ts +7 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +2027 -0
- package/dist/interactable.d.ts +7 -0
- package/dist/italy.d.ts +1 -0
- package/dist/legend.d.ts +6 -0
- package/dist/line.d.ts +29 -0
- package/dist/map.d.ts +422 -0
- package/dist/marker.d.ts +31 -0
- package/dist/options.d.ts +5 -0
- package/dist/ordinal-scale.d.ts +32 -0
- package/dist/projection.d.ts +18 -0
- package/dist/region.d.ts +21 -0
- package/dist/reposition-labels.d.ts +27 -0
- package/dist/reposition-lines.d.ts +32 -0
- package/dist/reposition-markers.d.ts +26 -0
- package/dist/resize.d.ts +5 -0
- package/dist/series.d.ts +4 -0
- package/dist/set-focus.d.ts +58 -0
- package/dist/set-scale.d.ts +80 -0
- package/dist/setup-container-events.d.ts +48 -0
- package/dist/setup-container-touch-events.d.ts +68 -0
- package/dist/setup-element-events.d.ts +125 -0
- package/dist/setup-zoom-buttons.d.ts +21 -0
- package/dist/shape-element.d.ts +10 -0
- package/dist/spain.d.ts +1 -0
- package/dist/text-element.d.ts +1 -0
- package/dist/tooltip.d.ts +80 -0
- package/dist/types.d.ts +398 -0
- package/dist/update-size.d.ts +6 -0
- package/dist/us-aea-en.d.ts +266 -0
- package/dist/us-lcc-en.d.ts +266 -0
- package/dist/us-merc-en.d.ts +266 -0
- package/dist/us-mill-en.d.ts +266 -0
- package/dist/utils.d.ts +21 -0
- package/dist/vector-map.d.ts +15 -0
- package/dist/world-merc.d.ts +1 -0
- package/dist/world.d.ts +1 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
<p align="center"><img src="https://github.com/stacksjs/mail-server/blob/main/.github/art/cover.jpg?raw=true" alt="Social Card of this repo"></p>
|
|
2
|
+
|
|
3
|
+
[![npm version][npm-version-src]][npm-version-href]
|
|
4
|
+
[![GitHub Actions][github-actions-src]][github-actions-href]
|
|
5
|
+
[](http://commitizen.github.io/cz-cli/)
|
|
6
|
+
<!-- [![npm downloads][npm-downloads-src]][npm-downloads-href] -->
|
|
7
|
+
<!-- [![Codecov][codecov-src]][codecov-href] -->
|
|
8
|
+
|
|
9
|
+
# The Post
|
|
10
|
+
|
|
11
|
+
> Finally a mail server that can be managed.
|
|
12
|
+
|
|
13
|
+
Perfect for local development and testing environments. _Production-ready release coming soon!_
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- 📨 **Mail Server** _lightweight, configurable, and extensible_
|
|
18
|
+
- 🛠️ **Mail Utilities** _send, receive, and manage emails_
|
|
19
|
+
- 📦 **Mail UI** _web interfaces for managing emails, including a component library_
|
|
20
|
+
- 🤖 **CLI** _command-line interface for managing emails_
|
|
21
|
+
- 🔒 **Security** _TLS support, authentication, and spam protection_
|
|
22
|
+
- 🚀 **Performance** _optimized for high-throughput environments_
|
|
23
|
+
- 🎯 **Modern** _built with TypeScript, zero dependencies_
|
|
24
|
+
- 📝 **Logging** _detailed logging and monitoring capabilities_
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
bun install -d @stacksjs/post
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
<!-- _Alternatively, you can install:_
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
brew install post # wip
|
|
36
|
+
pkgx install post # wip
|
|
37
|
+
``` -->
|
|
38
|
+
|
|
39
|
+
## Get Started
|
|
40
|
+
|
|
41
|
+
There are two ways of using the mail server: _as a library or as a CLI._
|
|
42
|
+
|
|
43
|
+
### Library Usage
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { SMTPServer } from '@stacksjs/post'
|
|
47
|
+
|
|
48
|
+
// Basic SMTP Server
|
|
49
|
+
const server = new SMTPServer({
|
|
50
|
+
secure: true,
|
|
51
|
+
name: 'mail.example.com',
|
|
52
|
+
banner: 'Welcome to My Mail Server',
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
server.listen(25)
|
|
56
|
+
|
|
57
|
+
// Advanced Configuration
|
|
58
|
+
const secureServer = new SMTPServer({
|
|
59
|
+
// TLS Configuration
|
|
60
|
+
secure: true,
|
|
61
|
+
needsUpgrade: false,
|
|
62
|
+
sniOptions: new Map([
|
|
63
|
+
['example.com', {
|
|
64
|
+
key: fs.readFileSync('certs/example.com.key'),
|
|
65
|
+
cert: fs.readFileSync('certs/example.com.cert')
|
|
66
|
+
}]
|
|
67
|
+
]),
|
|
68
|
+
|
|
69
|
+
// Authentication
|
|
70
|
+
authMethods: ['PLAIN', 'LOGIN'],
|
|
71
|
+
onAuth: (auth, session, callback) => {
|
|
72
|
+
if (auth.username === 'user' && auth.password === 'pass')
|
|
73
|
+
callback(null, { user: 'user' })
|
|
74
|
+
else
|
|
75
|
+
callback(new Error('Invalid credentials'))
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
// Message Handling
|
|
79
|
+
size: 1024 * 1024, // 1MB limit
|
|
80
|
+
onData: (stream, session, callback) => {
|
|
81
|
+
stream.pipe(process.stdout) // Echo message to console
|
|
82
|
+
stream.on('end', callback)
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
// Logging
|
|
86
|
+
logger: {
|
|
87
|
+
info: console.log,
|
|
88
|
+
debug: console.debug,
|
|
89
|
+
error: console.error
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
secureServer.listen(465) // SMTPS port
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Event Handling
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
server.on('connect', (session) => {
|
|
100
|
+
console.log('New connection from', session.remoteAddress)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
server.on('error', (err) => {
|
|
104
|
+
console.error('Server error:', err)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
server.on('close', () => {
|
|
108
|
+
console.log('Server shutting down')
|
|
109
|
+
})
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### CLI Usage
|
|
113
|
+
|
|
114
|
+
The Post CLI provides a comprehensive set of commands for managing your mail server:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Start the server
|
|
118
|
+
post start # Start with default config
|
|
119
|
+
post start --config custom # Use custom config file
|
|
120
|
+
post start --port 25 # Specify port
|
|
121
|
+
post start --secure # Start in TLS mode
|
|
122
|
+
|
|
123
|
+
# Configuration
|
|
124
|
+
post init # Create default config file
|
|
125
|
+
post config show # Display current configuration
|
|
126
|
+
post config set key=value # Update configuration
|
|
127
|
+
|
|
128
|
+
# Monitoring
|
|
129
|
+
post status # Show server status
|
|
130
|
+
post logs # View server logs
|
|
131
|
+
post logs --live # Live log streaming
|
|
132
|
+
post stats # Show server statistics
|
|
133
|
+
|
|
134
|
+
# User Management
|
|
135
|
+
post users list # List all users
|
|
136
|
+
post users add <email> # Add new user
|
|
137
|
+
post users remove <email> # Remove user
|
|
138
|
+
post users quota <email> # Show/set user quota
|
|
139
|
+
|
|
140
|
+
# Queue Management
|
|
141
|
+
post queue list # List queued messages
|
|
142
|
+
post queue flush # Process all queued messages
|
|
143
|
+
post queue remove <id> # Remove message from queue
|
|
144
|
+
|
|
145
|
+
# Security
|
|
146
|
+
post tls setup # Configure TLS certificates
|
|
147
|
+
post tls renew # Renew certificates
|
|
148
|
+
post blacklist add <ip> # Add IP to blacklist
|
|
149
|
+
post whitelist add <ip> # Add IP to whitelist
|
|
150
|
+
|
|
151
|
+
# Maintenance
|
|
152
|
+
post backup # Create server backup
|
|
153
|
+
post restore <file> # Restore from backup
|
|
154
|
+
post cleanup # Clean old logs/messages
|
|
155
|
+
|
|
156
|
+
# Advanced
|
|
157
|
+
post test # Run server tests
|
|
158
|
+
post benchmark # Run performance tests
|
|
159
|
+
post debug # Start in debug mode
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Configuration
|
|
163
|
+
|
|
164
|
+
The Mail Server can be configured using a `post.config.ts` _(or `post.config.js`)_ file:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
// post.config.ts
|
|
168
|
+
export default {
|
|
169
|
+
// Server Configuration
|
|
170
|
+
server: {
|
|
171
|
+
name: 'mail.example.com',
|
|
172
|
+
secure: true,
|
|
173
|
+
ports: {
|
|
174
|
+
smtp: 25,
|
|
175
|
+
smtps: 465,
|
|
176
|
+
submission: 587
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
// TLS Configuration
|
|
181
|
+
tls: {
|
|
182
|
+
cert: '/path/to/cert.pem',
|
|
183
|
+
key: '/path/to/key.pem',
|
|
184
|
+
domains: ['example.com', 'mail.example.com']
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
// Authentication
|
|
188
|
+
auth: {
|
|
189
|
+
methods: ['PLAIN', 'LOGIN'],
|
|
190
|
+
database: 'sqlite://users.db'
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
// Storage
|
|
194
|
+
storage: {
|
|
195
|
+
type: 'disk',
|
|
196
|
+
path: '/var/mail',
|
|
197
|
+
quota: '1GB'
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
// Security
|
|
201
|
+
security: {
|
|
202
|
+
rateLimit: {
|
|
203
|
+
window: '1h',
|
|
204
|
+
max: 1000
|
|
205
|
+
},
|
|
206
|
+
spamProtection: true,
|
|
207
|
+
dnsbl: ['zen.spamhaus.org']
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
// Logging
|
|
211
|
+
logging: {
|
|
212
|
+
level: 'info',
|
|
213
|
+
file: '/var/log/post.log',
|
|
214
|
+
format: 'json'
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
_Then run:_
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
post start
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
To learn more, head over to the [documentation](https://the-post.sh/).
|
|
226
|
+
|
|
227
|
+
## Testing
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
bun test
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Changelog
|
|
234
|
+
|
|
235
|
+
Please see our [releases](https://github.com/stacksjs/stacks/releases) page for more information on what has changed recently.
|
|
236
|
+
|
|
237
|
+
## Contributing
|
|
238
|
+
|
|
239
|
+
Please review the [Contributing Guide](https://github.com/stacksjs/contributing) for details.
|
|
240
|
+
|
|
241
|
+
## Community
|
|
242
|
+
|
|
243
|
+
For help, discussion about best practices, or any other conversation that would benefit from being searchable:
|
|
244
|
+
|
|
245
|
+
[Discussions on GitHub](https://github.com/stacksjs/stacks/discussions)
|
|
246
|
+
|
|
247
|
+
For casual chit-chat with others using this package:
|
|
248
|
+
|
|
249
|
+
[Join the Stacks Discord Server](https://discord.gg/stacksjs)
|
|
250
|
+
|
|
251
|
+
## Postcardware
|
|
252
|
+
|
|
253
|
+
Two things are true: Stacks OSS will always stay open-source, and we do love to receive postcards from wherever Stacks is used! _We also publish them on our website. And thank you, Spatie_
|
|
254
|
+
|
|
255
|
+
Our address: Stacks.js, 12665 Village Ln #2306, Playa Vista, CA 90094 🌎
|
|
256
|
+
|
|
257
|
+
## Sponsors
|
|
258
|
+
|
|
259
|
+
We would like to extend our thanks to the following sponsors for funding Stacks development. If you are interested in becoming a sponsor, please reach out to us.
|
|
260
|
+
|
|
261
|
+
- [JetBrains](https://www.jetbrains.com/)
|
|
262
|
+
- [The Solana Foundation](https://solana.com/)
|
|
263
|
+
|
|
264
|
+
## Credits
|
|
265
|
+
|
|
266
|
+
- [Andris Reinman](https://github.com/andris9) _(Author of `nodemailer` & `smtp-server`)_
|
|
267
|
+
- [Ralph Slooten](https://avatars.githubusercontent.com/u/1463435?s=64&v=4) _(Author of `mailtrap`)_
|
|
268
|
+
- [Chris Breuer](https://github.com/chrisbbreuer)
|
|
269
|
+
- [All Contributors](../../contributors)
|
|
270
|
+
|
|
271
|
+
## License
|
|
272
|
+
|
|
273
|
+
The MIT License (MIT). Please see [LICENSE](https://github.com/stacksjs/stacks/tree/main/LICENSE.md) for more information.
|
|
274
|
+
|
|
275
|
+
Made with 💙
|
|
276
|
+
|
|
277
|
+
<!-- Badges -->
|
|
278
|
+
[npm-version-src]: https://img.shields.io/npm/v/@stacksjs/mail-server?style=flat-square
|
|
279
|
+
[npm-version-href]: https://npmjs.com/package/@stacksjs/mail-server
|
|
280
|
+
[github-actions-src]: https://img.shields.io/github/actions/workflow/status/stacksjs/mail-server/ci.yml?style=flat-square&branch=main
|
|
281
|
+
[github-actions-href]: https://github.com/stacksjs/mail-server/actions?query=workflow%3Aci
|
|
282
|
+
|
|
283
|
+
<!-- [codecov-src]: https://img.shields.io/codecov/c/gh/stacksjs/mail-server/main?style=flat-square
|
|
284
|
+
[codecov-href]: https://codecov.io/gh/stacksjs/mail-server -->
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export default function applyTransform(this: MapInterface): void {
|
|
2
|
+
let maxTransX: number, maxTransY: number, minTransX: number, minTransY: number
|
|
3
|
+
|
|
4
|
+
if (this._defaultWidth * this.scale <= this._width) {
|
|
5
|
+
maxTransX = (this._width - this._defaultWidth * this.scale) / (2 * this.scale)
|
|
6
|
+
minTransX = (this._width - this._defaultWidth * this.scale) / (2 * this.scale)
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
maxTransX = 0
|
|
10
|
+
minTransX = (this._width - this._defaultWidth * this.scale) / this.scale
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (this._defaultHeight * this.scale <= this._height) {
|
|
14
|
+
maxTransY = (this._height - this._defaultHeight * this.scale) / (2 * this.scale)
|
|
15
|
+
minTransY = (this._height - this._defaultHeight * this.scale) / (2 * this.scale)
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
maxTransY = 0
|
|
19
|
+
minTransY = (this._height - this._defaultHeight * this.scale) / this.scale
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (this.transY > maxTransY) {
|
|
23
|
+
this.transY = maxTransY
|
|
24
|
+
}
|
|
25
|
+
else if (this.transY < minTransY) {
|
|
26
|
+
this.transY = minTransY
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (this.transX > maxTransX) {
|
|
30
|
+
this.transX = maxTransX
|
|
31
|
+
}
|
|
32
|
+
else if (this.transX < minTransX) {
|
|
33
|
+
this.transX = minTransX
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
this.canvas.applyTransformParams(this.scale, this.transX, this.transY)
|
|
37
|
+
|
|
38
|
+
if (this._markers) {
|
|
39
|
+
this._repositionMarkers()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (this._lines) {
|
|
43
|
+
this._repositionLines()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
this._repositionLabels()
|
|
47
|
+
};
|
package/dist/base.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
declare interface BBox {
|
|
2
|
+
x: number
|
|
3
|
+
y: number
|
|
4
|
+
width: number
|
|
5
|
+
height: number
|
|
6
|
+
}
|
|
7
|
+
declare interface BaseComponentShape {
|
|
8
|
+
remove: () => void
|
|
9
|
+
setStyle: (property: string | Record<string, any>, value?: string | number) => void
|
|
10
|
+
addClass: (className: string) => void
|
|
11
|
+
getBBox: () => BBox
|
|
12
|
+
width?: number
|
|
13
|
+
node?: SVGElement
|
|
14
|
+
isHovered?: boolean
|
|
15
|
+
isSelected?: boolean
|
|
16
|
+
updateStyle?: () => void
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default BaseComponent;
|
package/dist/brasil.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default brasil;
|
package/dist/canada.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default canada;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
declare interface Point {
|
|
2
|
+
x: number
|
|
3
|
+
y: number
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export default function coordsToPoint(this: MapInterface, lat: number, lng: number): Point | false {
|
|
7
|
+
const projection = this.params.map?.projection || 'mercator'
|
|
8
|
+
const coords = projection === 'mercator' ? this.mercator.convert(lat, lng) : this.miller.convert(lat, lng)
|
|
9
|
+
|
|
10
|
+
if (coords === false) {
|
|
11
|
+
return false
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const inset = this.getInsetForPoint(coords.x, coords.y)
|
|
15
|
+
if (!inset) {
|
|
16
|
+
return false
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const x = inset.leftLng + ((coords.x - inset.leftLng) / (inset.rightLng - inset.leftLng)) * inset.width
|
|
20
|
+
const y = inset.topLat + ((coords.y - inset.topLat) / (inset.bottomLat - inset.topLat)) * inset.height
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
x,
|
|
24
|
+
y,
|
|
25
|
+
}
|
|
26
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export default function createLines(this: MapInterface, lines: LineConfig[]): void {
|
|
2
|
+
const markers = this._markers || {}
|
|
3
|
+
const { style, elements: _, ...rest } = this.params.lines || {}
|
|
4
|
+
|
|
5
|
+
let point1: { x: number, y: number } | false = false
|
|
6
|
+
let point2: { x: number, y: number } | false = false
|
|
7
|
+
|
|
8
|
+
for (const index in lines) {
|
|
9
|
+
const lineConfig = lines[index]
|
|
10
|
+
|
|
11
|
+
for (const { config: markerConfig } of Object.values(markers)) {
|
|
12
|
+
if (markerConfig.name === lineConfig.from) {
|
|
13
|
+
point1 = this.getMarkerPosition(markerConfig)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (markerConfig.name === lineConfig.to) {
|
|
17
|
+
point2 = this.getMarkerPosition(markerConfig)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (point1 !== false && point2 !== false) {
|
|
22
|
+
this._lines = this._lines || {}
|
|
23
|
+
this._lines[getLineUid(lineConfig.from, lineConfig.to)] = new Line(
|
|
24
|
+
{
|
|
25
|
+
index,
|
|
26
|
+
map: this,
|
|
27
|
+
group: this._linesGroup,
|
|
28
|
+
config: lineConfig,
|
|
29
|
+
x1: point1.x,
|
|
30
|
+
y1: point1.y,
|
|
31
|
+
x2: point2.x,
|
|
32
|
+
y2: point2.y,
|
|
33
|
+
...rest,
|
|
34
|
+
},
|
|
35
|
+
merge({ initial: style }, { initial: lineConfig.style || {} }, true),
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export default function createMarkers(
|
|
2
|
+
this: MapInterface,
|
|
3
|
+
markers: Record<string, MarkerConfig> = {},
|
|
4
|
+
isRecentlyCreated = false,
|
|
5
|
+
): void {
|
|
6
|
+
for (let index in markers) {
|
|
7
|
+
const config = markers[index]
|
|
8
|
+
const point = this.getMarkerPosition(config)
|
|
9
|
+
const uid = config.coords.join(':')
|
|
10
|
+
|
|
11
|
+
if (!point) {
|
|
12
|
+
continue
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (isRecentlyCreated) {
|
|
16
|
+
if (
|
|
17
|
+
Object.keys(this._markers || {}).filter(i => this._markers?.[i]._uid === uid).length
|
|
18
|
+
) {
|
|
19
|
+
continue
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
index = String(Object.keys(this._markers || {}).length)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const marker = new Marker(
|
|
26
|
+
{
|
|
27
|
+
index,
|
|
28
|
+
map: this,
|
|
29
|
+
label: this.params.labels?.markers ? {} : undefined,
|
|
30
|
+
labelsGroup: this._markerLabelsGroup,
|
|
31
|
+
cx: point.x,
|
|
32
|
+
cy: point.y,
|
|
33
|
+
group: this._markersGroup,
|
|
34
|
+
config,
|
|
35
|
+
isRecentlyCreated,
|
|
36
|
+
},
|
|
37
|
+
merge(this.params.markerStyle || {}, { ...(config.style || {}) }, true),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
if (this._markers?.[index]) {
|
|
41
|
+
this.removeMarkers([index])
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
this._markers = this._markers || {}
|
|
45
|
+
this._markers[index] = {
|
|
46
|
+
_uid: uid,
|
|
47
|
+
config,
|
|
48
|
+
element: marker as unknown as MarkerInstance,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export default function createRegions(this: MapInterface): void {
|
|
2
|
+
this._regionLabelsGroup = this._regionLabelsGroup || this.canvas.createGroup('jvm-regions-labels-group')
|
|
3
|
+
|
|
4
|
+
for (const code in this._mapData.paths) {
|
|
5
|
+
const region = new Region({
|
|
6
|
+
map: this,
|
|
7
|
+
code,
|
|
8
|
+
path: this._mapData.paths[code].path,
|
|
9
|
+
style: merge({}, this.params.regionStyle || {}),
|
|
10
|
+
labelStyle: this.params.regionLabelStyle,
|
|
11
|
+
labelsGroup: this._regionLabelsGroup,
|
|
12
|
+
label: this.params.labels?.regions ? {} : undefined,
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
this.regions[code] = {
|
|
16
|
+
element: region,
|
|
17
|
+
} as RegionType
|
|
18
|
+
}
|
|
19
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { MapInterface } from '../types';
|
|
2
|
+
|
|
3
|
+
declare type SeriesKey = 'markers' | 'regions'
|
|
4
|
+
|
|
5
|
+
export default function createSeries(this: MapInterface): void {
|
|
6
|
+
this.series = { markers: [], regions: [] }
|
|
7
|
+
|
|
8
|
+
for (const key in this.params.series) {
|
|
9
|
+
const seriesKey = key as SeriesKey
|
|
10
|
+
if (this.params.series[seriesKey]) {
|
|
11
|
+
for (let i = 0; i < this.params.series[seriesKey].length; i++) {
|
|
12
|
+
this.series[seriesKey][i] = new Series(
|
|
13
|
+
this.params.series[seriesKey][i],
|
|
14
|
+
seriesKey === 'markers' ? (this._markers || {}) : this.regions,
|
|
15
|
+
this,
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { DataVisualizationOptions, MapInterface } from './types';
|
|
2
|
+
|
|
3
|
+
export declare class DataVisualization {
|
|
4
|
+
private _scale: [string, string]
|
|
5
|
+
private _values: Record<string, number | string>
|
|
6
|
+
private _fromColor: number[]
|
|
7
|
+
private _toColor: number[]
|
|
8
|
+
private _map: MapInterface
|
|
9
|
+
private min: number = Number.MAX_VALUE
|
|
10
|
+
private max: number = 0
|
|
11
|
+
|
|
12
|
+
constructor({ scale, values }: DataVisualizationOptions, map: MapInterface) {
|
|
13
|
+
this._scale = scale
|
|
14
|
+
this._values = values
|
|
15
|
+
this._fromColor = this.hexToRgb(scale[0])
|
|
16
|
+
this._toColor = this.hexToRgb(scale[1])
|
|
17
|
+
this._map = map
|
|
18
|
+
|
|
19
|
+
this.setMinMaxValues(values)
|
|
20
|
+
this.visualize()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
setMinMaxValues(values: Record<string, number | string>): void {
|
|
24
|
+
for (const key in values) {
|
|
25
|
+
const value = Number.parseFloat(String(values[key]))
|
|
26
|
+
|
|
27
|
+
if (value > this.max) {
|
|
28
|
+
this.max = value
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (value < this.min) {
|
|
32
|
+
this.min = value
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
visualize(): void {
|
|
38
|
+
const attrs: Record<string, string> = {}
|
|
39
|
+
let value: number
|
|
40
|
+
|
|
41
|
+
for (const regionCode in this._values) {
|
|
42
|
+
value = Number.parseFloat(String(this._values[regionCode]))
|
|
43
|
+
|
|
44
|
+
if (!Number.isNaN(value)) {
|
|
45
|
+
attrs[regionCode] = this.getValue(value)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
this.setAttributes(attrs)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
setAttributes(attrs: Record<string, string>): void {
|
|
53
|
+
for (const code in attrs) {
|
|
54
|
+
if (this._map.regions[code]) {
|
|
55
|
+
this._map.regions[code].element.setStyle('fill', attrs[code])
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getValue(value: number): string {
|
|
61
|
+
if (this.min === this.max) {
|
|
62
|
+
return `#${this._toColor.join('')}`
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let hex: string
|
|
66
|
+
let color = '#'
|
|
67
|
+
|
|
68
|
+
for (let i = 0; i < 3; i++) {
|
|
69
|
+
hex = Math.round(
|
|
70
|
+
this._fromColor[i] + (this._toColor[i] - this._fromColor[i]) * ((value - this.min) / (this.max - this.min)),
|
|
71
|
+
).toString(16)
|
|
72
|
+
|
|
73
|
+
color += (hex.length === 1 ? '0' : '') + hex
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return color
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
hexToRgb(h: string): number[] {
|
|
80
|
+
let r: string = '0'
|
|
81
|
+
let g: string = '0'
|
|
82
|
+
let b: string = '0'
|
|
83
|
+
|
|
84
|
+
if (h.length === 4) {
|
|
85
|
+
r = `0x${h[1]}${h[1]}`
|
|
86
|
+
g = `0x${h[2]}${h[2]}`
|
|
87
|
+
b = `0x${h[3]}${h[3]}`
|
|
88
|
+
}
|
|
89
|
+
else if (h.length === 7) {
|
|
90
|
+
r = `0x${h[1]}${h[2]}`
|
|
91
|
+
g = `0x${h[3]}${h[4]}`
|
|
92
|
+
b = `0x${h[5]}${h[6]}`
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return [Number.parseInt(r, 16), Number.parseInt(g, 16), Number.parseInt(b, 16)]
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export default DataVisualization
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
declare interface Options {
|
|
2
|
+
arrayMerge?: (target: any[], source: any[], options: Options) => any[]
|
|
3
|
+
clone?: boolean
|
|
4
|
+
customMerge?: (key: string) => ((x: any, y: any) => any) | undefined
|
|
5
|
+
isMergeableObject?: (value: any) => boolean
|
|
6
|
+
cloneUnlessOtherwiseSpecified?: (value: any, options: Options) => any
|
|
7
|
+
}
|
|
8
|
+
declare type DeepMergeResult = Record<string | symbol, any>
|
|
9
|
+
|
|
10
|
+
const deepmerge: {
|
|
11
|
+
<T>(target: T, source: T, options?: Options): T
|
|
12
|
+
} = function deepmerge<T>(target: T, source: T, options: Options = {}): T {
|
|
13
|
+
options.arrayMerge = options.arrayMerge || defaultArrayMerge
|
|
14
|
+
options.isMergeableObject = options.isMergeableObject || isMergeableObject
|
|
15
|
+
options.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified
|
|
16
|
+
|
|
17
|
+
const sourceIsArray = Array.isArray(source)
|
|
18
|
+
const targetIsArray = Array.isArray(target)
|
|
19
|
+
const sourceAndTargetTypesMatch = sourceIsArray === targetIsArray
|
|
20
|
+
|
|
21
|
+
if (!sourceAndTargetTypesMatch) {
|
|
22
|
+
return cloneUnlessOtherwiseSpecified(source, options) as T
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (sourceIsArray) {
|
|
26
|
+
return options.arrayMerge(target as any[], source as any[], options) as T
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return mergeObject(target as Record<string | symbol, any>, source as Record<string | symbol, any>, options) as T
|
|
30
|
+
}
|
|
31
|
+
declare function isMergeableObject(value: any): boolean;
|
|
32
|
+
declare function isNonNullObject(value: any): boolean;
|
|
33
|
+
declare function isSpecial(value: any): boolean;
|
|
34
|
+
declare function isReactElement(value: any): boolean;
|
|
35
|
+
declare function isNode(value: any): boolean;
|
|
36
|
+
declare function emptyTarget(val: any): any[] | Record<string | symbol, any>;
|
|
37
|
+
declare function cloneUnlessOtherwiseSpecified(value: any, options: Options): any;
|
|
38
|
+
declare function defaultArrayMerge(target: any[], source: any[], options: Options): any[];
|
|
39
|
+
declare function getMergeFunction(key: string, options: Options): (x: any, y: any, options: Options) => any;
|
|
40
|
+
declare function getEnumerableOwnPropertySymbols(target: Record<string | symbol, any>): symbol[];
|
|
41
|
+
declare function getKeys(target: Record<string | symbol, any>): (string | symbol)[];
|
|
42
|
+
declare function propertyIsOnObject(object: Record<string | symbol, any>, property: string | symbol): boolean;
|
|
43
|
+
declare function propertyIsUnsafe(target: Record<string | symbol, any>, key: string | symbol): boolean;
|
|
44
|
+
declare function mergeObject(target: Record<string | symbol, any>, source: Record<string | symbol, any>, options: Options): DeepMergeResult;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { EventRegistry } from './types';
|
|
2
|
+
|
|
3
|
+
declare let eventRegistry: EventRegistry;
|
|
4
|
+
declare const EventHandler: {
|
|
5
|
+
on: (element: HTMLElement, event: string, handler: EventListenerOrEventListenerObject, options: AddEventListenerOptions) => void;
|
|
6
|
+
delegate: (element: HTMLElement, event: string, selector: string, handler: (e: Event) => void;
|
|
7
|
+
off: (element: HTMLElement, event: string, handler: EventListenerOrEventListenerObject) => void;
|
|
8
|
+
flush: () => void;
|
|
9
|
+
getEventRegistry: () => void
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default EventHandler;
|