koishi-plugin-ets2-tools-tmp 3.1.1 → 3.1.3

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.
@@ -8,135 +8,265 @@
8
8
  <script src="./package/leaflet/heatmap.min.js"></script>
9
9
  <script src="./package/leaflet/leaflet-heatmap.js"></script>
10
10
  <style>
11
- body, html {
12
- margin: 0;
13
- padding: 0;
14
- }
15
- * {
16
- font-family: "微软雅黑", serif;
17
- }
11
+ body, html { margin: 0; padding: 0; }
12
+ * { font-family: "微软雅黑", serif; }
13
+
18
14
  #container {
19
15
  width: 1000px;
20
16
  position: relative;
21
17
  }
18
+
22
19
  .map {
23
20
  width: 100%;
24
21
  height: 900px;
25
- background-color: #4b4b4b;
22
+ background-color: #1a1a2e;
23
+ }
24
+
25
+ /* Map overlay frame - cyber corners */
26
+ .map-frame {
27
+ position: absolute;
28
+ inset: 0;
29
+ pointer-events: none;
30
+ z-index: 999;
31
+ }
32
+
33
+ .corner {
34
+ position: absolute;
35
+ width: 24px;
36
+ height: 24px;
37
+ border-color: rgba(0, 200, 255, 0.4);
38
+ border-style: solid;
26
39
  }
40
+
41
+ .corner.tl { top: 0; left: 0; border-width: 2px 0 0 2px; }
42
+ .corner.tr { top: 0; right: 0; border-width: 2px 2px 0 0; }
43
+ .corner.bl { bottom: 0; left: 0; border-width: 0 0 2px 2px; }
44
+ .corner.br { bottom: 0; right: 0; border-width: 0 2px 2px 0; }
45
+
46
+ /* Map title overlay */
47
+ .map-title {
48
+ position: absolute;
49
+ top: 12px;
50
+ left: 16px;
51
+ z-index: 1000;
52
+ pointer-events: none;
53
+ }
54
+
55
+ .map-title-icon {
56
+ font-size: 16px;
57
+ filter: drop-shadow(0 0 6px rgba(0, 200, 255, 0.5));
58
+ }
59
+
60
+ .map-title-text {
61
+ font-size: 12px;
62
+ font-weight: 800;
63
+ color: rgba(0, 200, 255, 0.6);
64
+ letter-spacing: 2px;
65
+ text-transform: uppercase;
66
+ margin-top: 2px;
67
+ }
68
+
69
+ /* Player count badge */
70
+ .player-badge {
71
+ position: absolute;
72
+ top: 12px;
73
+ right: 16px;
74
+ z-index: 1000;
75
+ pointer-events: none;
76
+ display: flex;
77
+ align-items: center;
78
+ gap: 6px;
79
+ padding: 4px 10px;
80
+ background: rgba(0, 0, 0, 0.6);
81
+ border: 1px solid rgba(0, 200, 255, 0.2);
82
+ border-radius: 6px;
83
+ backdrop-filter: blur(8px);
84
+ }
85
+
86
+ .player-badge-dot {
87
+ width: 6px;
88
+ height: 6px;
89
+ border-radius: 50%;
90
+ background: #00ff88;
91
+ box-shadow: 0 0 4px rgba(0, 255, 136, 0.6);
92
+ }
93
+
94
+ .player-badge-text {
95
+ font-size: 11px;
96
+ font-weight: 700;
97
+ color: #00c8ff;
98
+ text-shadow: 0 0 4px rgba(0, 200, 255, 0.3);
99
+ }
100
+
101
+ /* ===== TRAFFIC BOX ===== */
27
102
  .traffic-box {
28
- //position: absolute;
29
- //bottom: 0;
30
- //left: 0;
31
- //z-index: 9999999;
32
103
  width: 100%;
33
- backdrop-filter: blur(3px);
34
- background-color: #4b4b4b;
35
- padding: 12px 16px;
104
+ background: linear-gradient(180deg, #0d0d1a 0%, #0a0a14 100%);
105
+ padding: 0;
36
106
  box-sizing: border-box;
37
- overflow-y: hidden;
107
+ overflow: hidden;
108
+ position: relative;
38
109
  }
39
- .traffic-item {
40
- color: #ffffff;
41
- width: 33.3333%;
42
- float: left;
43
- margin-top: 8px;
110
+
111
+ .traffic-header {
112
+ display: flex;
113
+ align-items: center;
114
+ gap: 8px;
115
+ padding: 10px 16px 6px;
116
+ border-bottom: 1px solid rgba(0, 200, 255, 0.08);
117
+ }
118
+
119
+ .traffic-header-icon {
44
120
  font-size: 14px;
45
- border-right: 1px solid rgba(255, 255, 255, 0.3);
121
+ filter: drop-shadow(0 0 4px rgba(0, 200, 255, 0.4));
122
+ }
123
+
124
+ .traffic-header-text {
125
+ font-size: 11px;
126
+ font-weight: 800;
127
+ color: #556;
128
+ letter-spacing: 1.5px;
129
+ text-transform: uppercase;
130
+ }
131
+
132
+ .traffic-grid {
133
+ display: grid;
134
+ grid-template-columns: repeat(3, 1fr);
135
+ gap: 0;
136
+ padding: 0 12px 10px;
137
+ }
138
+
139
+ .traffic-item {
140
+ color: #c0c8d0;
141
+ padding: 8px 10px;
142
+ border-right: 1px solid rgba(0, 200, 255, 0.06);
143
+ border-bottom: 1px solid rgba(0, 200, 255, 0.04);
144
+ font-size: 12px;
46
145
  box-sizing: border-box;
47
- padding: 0 10px;
48
146
  display: flex;
49
147
  flex-direction: row;
50
148
  align-items: center;
51
- justify-content: center;
149
+ gap: 6px;
52
150
  }
53
- .traffic-item:nth-child(-n+3) {
54
- margin-top: 0;
151
+
152
+ .traffic-item:nth-child(3n) {
153
+ border-right: none;
55
154
  }
56
- .traffic-item:last-child, .traffic-item:nth-child(3n) {
57
- border-right: 0;
155
+
156
+ .traffic-item:nth-last-child(-n+3) {
157
+ border-bottom: none;
58
158
  }
159
+
59
160
  .traffic-item .region-info {
60
- display: inline-block;
61
- width: 72%;
161
+ flex: 1;
162
+ min-width: 0;
62
163
  white-space: nowrap;
63
164
  overflow: hidden;
64
165
  text-overflow: ellipsis;
65
166
  }
167
+
168
+ .traffic-item .region-info strong {
169
+ color: #d0e0ff;
170
+ font-weight: 700;
171
+ }
172
+
66
173
  .traffic-item .player-count {
67
- display: inline-block;
68
- width: 16%;
69
- text-align: center;
174
+ font-size: 12px;
175
+ font-weight: 800;
176
+ color: #00c8ff;
177
+ text-shadow: 0 0 4px rgba(0, 200, 255, 0.2);
178
+ flex-shrink: 0;
70
179
  }
180
+
71
181
  .traffic-item .traffic-status {
72
- display: inline-block;
73
- width: 12%;
74
- text-align: right;
182
+ font-size: 10px;
183
+ font-weight: 700;
184
+ padding: 1px 6px;
185
+ border-radius: 4px;
186
+ flex-shrink: 0;
187
+ text-transform: uppercase;
188
+ letter-spacing: 0.5px;
189
+ }
190
+
191
+ .status-fluid {
192
+ color: #00d26a;
193
+ background: rgba(0, 210, 106, 0.1);
194
+ border: 1px solid rgba(0, 210, 106, 0.2);
195
+ }
196
+
197
+ .status-moderate {
198
+ color: #ff6723;
199
+ background: rgba(255, 103, 35, 0.1);
200
+ border: 1px solid rgba(255, 103, 35, 0.2);
201
+ }
202
+
203
+ .status-congested {
204
+ color: #f8312f;
205
+ background: rgba(248, 49, 47, 0.1);
206
+ border: 1px solid rgba(248, 49, 47, 0.2);
207
+ }
208
+
209
+ .status-heavy {
210
+ color: #8d67c5;
211
+ background: rgba(141, 103, 197, 0.1);
212
+ border: 1px solid rgba(141, 103, 197, 0.2);
75
213
  }
76
214
  </style>
77
215
  </head>
78
216
  <body>
79
217
  <div id="container">
80
218
  <div id="map" class="map"></div>
81
- <div class="traffic-box"></div>
219
+
220
+ <div class="map-frame">
221
+ <div class="corner tl"></div>
222
+ <div class="corner tr"></div>
223
+ <div class="corner bl"></div>
224
+ <div class="corner br"></div>
225
+ </div>
226
+
227
+ <div class="map-title">
228
+ <div class="map-title-icon">🗺️</div>
229
+ <div class="map-title-text">LIVE HEATMAP</div>
230
+ </div>
231
+
232
+ <div class="player-badge">
233
+ <div class="player-badge-dot"></div>
234
+ <div class="player-badge-text" id="player-count">0 在线</div>
235
+ </div>
236
+
237
+ <div class="traffic-box">
238
+ <div class="traffic-header">
239
+ <span class="traffic-header-icon">📊</span>
240
+ <span class="traffic-header-text">热门区域路况</span>
241
+ </div>
242
+ <div class="traffic-grid" id="traffic-grid"></div>
243
+ </div>
82
244
  </div>
245
+
83
246
  <script>
84
247
  let mapConfig = {
85
248
  ets: {
86
249
  tileUrl: 'https://ets-map.oss-cn-beijing.aliyuncs.com/ets2/05102019/{z}/{x}/{y}.png',
87
- multipliers: {
88
- x: 70272,
89
- y: 76157
90
- },
91
- breakpoints: {
92
- uk: {
93
- x: -31056.8,
94
- y: -5832.867
95
- }
96
- },
97
- bounds: {
98
- y: 131072,
99
- x: 131072
100
- },
101
- maxZoom: 8,
102
- minZoom: 2,
103
- // 游戏地转地图坐标
104
- calculateMapCoordinate (x, y) {
105
- return [
106
- x / 1.609055 + mapConfig.ets.multipliers.x,
107
- y / 1.609055 + mapConfig.ets.multipliers.y
108
- ];
250
+ multipliers: { x: 70272, y: 76157 },
251
+ breakpoints: { uk: { x: -31056.8, y: -5832.867 } },
252
+ bounds: { y: 131072, x: 131072 },
253
+ maxZoom: 8, minZoom: 2,
254
+ calculateMapCoordinate(x, y) {
255
+ return [x / 1.609055 + mapConfig.ets.multipliers.x, y / 1.609055 + mapConfig.ets.multipliers.y];
109
256
  }
110
257
  },
111
258
  promods: {
112
- tileUrl: 'https://ets-map.oss-cn-beijing.aliyuncs.com/promods/05102019/{z}/{x}/{y}.png',
113
- multipliers: {
114
- x: 51953,
115
- y: 76024
116
- },
117
- breakpoints: {
118
- uk: {
119
- x: -31056.8,
120
- y: -5832.867
121
- }
122
- },
123
- bounds: {
124
- y: 131072,
125
- x: 131072
126
- },
127
- maxZoom: 8,
128
- minZoom: 2,
129
- // 游戏地转地图坐标
130
- calculateMapCoordinate (x, y) {
131
- return [
132
- x / 2.598541 + mapConfig.promods.multipliers.x,
133
- y / 2.598541 + mapConfig.promods.multipliers.y
134
- ]
259
+ tileUrl: 'https://ets6-map.oss-cn-beijing.aliyuncs.com/promods/05102019/{z}/{x}/{y}.png',
260
+ multipliers: { x: 51953, y: 76024 },
261
+ breakpoints: { uk: { x: -31056.8, y: -5832.867 } },
262
+ bounds: { y: 131072, x: 131072 },
263
+ maxZoom: 8, minZoom: 2,
264
+ calculateMapCoordinate(x, y) {
265
+ return [x / 2.598541 + mapConfig.promods.multipliers.x, y / 2.598541 + mapConfig.promods.multipliers.y];
135
266
  }
136
267
  }
137
- }
268
+ };
138
269
 
139
- // 定义地图
140
270
  let map = L.map('map', {
141
271
  attributionControl: false,
142
272
  crs: L.CRS.Simple,
@@ -144,62 +274,62 @@
144
274
  zoomSnap: 0.1
145
275
  });
146
276
 
277
+ const statusClassMap = {
278
+ '畅通': 'status-fluid',
279
+ '正常': 'status-moderate',
280
+ '缓慢': 'status-congested',
281
+ '拥堵': 'status-heavy'
282
+ };
283
+
147
284
  function setData(data) {
148
- // 边界
149
285
  let bounds = L.latLngBounds(
150
286
  map.unproject([0, mapConfig[data.mapType].bounds.y], mapConfig[data.mapType].maxZoom),
151
287
  map.unproject([mapConfig[data.mapType].bounds.x, 0], mapConfig[data.mapType].maxZoom)
152
288
  );
153
289
 
154
- // 瓦片地图
155
290
  L.tileLayer(mapConfig[data.mapType].tileUrl, {
156
- minZoom: 0,
157
- maxZoom: 8,
158
- minNativeZoom: 1,
159
- maxNativeZoom: 8,
160
- tileSize: 512,
161
- bounds: bounds,
162
- reuseTiles: true
291
+ minZoom: 0, maxZoom: 8,
292
+ minNativeZoom: 1, maxNativeZoom: 8,
293
+ tileSize: 512, bounds: bounds, reuseTiles: true
163
294
  }).addTo(map);
164
- map.setMaxBounds(
165
- new L.LatLngBounds(
166
- map.unproject([0, mapConfig[data.mapType].bounds.y], mapConfig[data.mapType].maxZoom),
167
- map.unproject([mapConfig[data.mapType].bounds.x, 0], mapConfig[data.mapType].maxZoom)
168
- )
169
- );
170
295
 
171
- // 展示地图全貌
172
- map.fitBounds(bounds)
296
+ map.setMaxBounds(new L.LatLngBounds(
297
+ map.unproject([0, mapConfig[data.mapType].bounds.y], mapConfig[data.mapType].maxZoom),
298
+ map.unproject([mapConfig[data.mapType].bounds.x, 0], mapConfig[data.mapType].maxZoom)
299
+ ));
300
+
301
+ map.fitBounds(bounds);
173
302
 
174
- // 热力图
303
+ // Heatmap
175
304
  let heatmapLayer = new HeatmapOverlay({
176
305
  radius: 3,
177
306
  maxOpacity: 0.8,
178
307
  scaleRadius: true,
179
308
  useLocalExtrema: true,
180
- latField: "lat",
181
- lngField: "lng",
182
- valueField: "count"
309
+ latField: "lat", lngField: "lng", valueField: "count"
183
310
  });
184
311
  map.addLayer(heatmapLayer);
185
- let heatmapData = []
312
+
313
+ let heatmapData = [];
186
314
  for (const arrayElement of data.playerCoordinateList) {
187
315
  let unprojected = map.unproject(mapConfig[data.mapType].calculateMapCoordinate(arrayElement[0], arrayElement[1]), 8);
188
316
  heatmapData.push({ lat: unprojected.lat, lng: unprojected.lng, count: 1 });
189
317
  }
190
- heatmapLayer.setData({
191
- min: 1,
192
- max: 5000,
193
- data: heatmapData
194
- })
318
+ heatmapLayer.setData({ min: 1, max: 5000, data: heatmapData });
319
+
320
+ // Player count badge
321
+ document.getElementById('player-count').textContent = data.playerCoordinateList.length.toLocaleString() + ' 在线';
195
322
 
196
- // 展示热门地区路况状态
323
+ // Traffic grid
324
+ const grid = document.getElementById('traffic-grid');
197
325
  for (const traffic of data.trafficList) {
198
- document.getElementsByClassName('traffic-box')[0].insertAdjacentHTML('beforeend', `
326
+ const cls = statusClassMap[traffic.severity.text] || '';
327
+ grid.insertAdjacentHTML('beforeend', `
199
328
  <div class="traffic-item">
200
- <span class="region-info"><strong>${traffic.country}</strong> ${traffic.province}</span><span class="player-count">${traffic.playerCount}人</span><span class="traffic-status" style="color: ${traffic.severity.color}">${traffic.severity.text}</span>
201
- </div>
202
- `);
329
+ <span class="region-info"><strong>${traffic.country}</strong> ${traffic.province}</span>
330
+ <span class="player-count">${traffic.playerCount}</span>
331
+ <span class="traffic-status ${cls}">${traffic.severity.text}</span>
332
+ </div>`);
203
333
  }
204
334
  }
205
335
  </script>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-ets2-tools-tmp",
3
3
  "description": "欧卡2 TruckersMP信息查询、车队平台查询及活动提醒",
4
- "version": "3.1.1",
4
+ "version": "3.1.3",
5
5
  "contributors": [
6
6
  "opwop <slhp1013@qq.com>",
7
7
  "bot_actions <168329908@qq.com>"