@things-factory/weather 9.0.0-beta.50 → 9.0.0-beta.55
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/assets/images/wind.png +0 -0
- package/assets/images/wind2.png +0 -0
- package/client/ol-components/webgl-image-static.ts +75 -5
- package/client/pages/weather-page.ts +39 -9
- package/config/config.development.js +3 -0
- package/config/config.production.js +3 -0
- package/dist-client/ol-components/webgl-image-static.d.ts +12 -0
- package/dist-client/ol-components/webgl-image-static.js +66 -5
- package/dist-client/ol-components/webgl-image-static.js.map +1 -1
- package/dist-client/pages/weather-page.js +37 -9
- package/dist-client/pages/weather-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/controllers/open-meteo-adapter.js +6 -2
- package/dist-server/controllers/open-meteo-adapter.js.map +1 -1
- package/dist-server/controllers/weather-controller.js +26 -11
- package/dist-server/controllers/weather-controller.js.map +1 -1
- package/dist-server/services/chrome-renderer.js +51 -26
- package/dist-server/services/chrome-renderer.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -6
- package/server/controllers/open-meteo-adapter.ts +7 -2
- package/server/controllers/weather-controller.ts +23 -7
- package/server/services/chrome-renderer.ts +58 -27
|
@@ -78,17 +78,16 @@ export async function getGlobalWeatherImage(type: WeatherType, forceRefresh: boo
|
|
|
78
78
|
// 객체인 경우 처리 (JSON.stringify된 버퍼일 수 있음)
|
|
79
79
|
try {
|
|
80
80
|
// JSON 문자열로 변환했다가 다시 파싱하면 배열로 변환될 수 있음
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
.map(key => cachedDataJson[key])
|
|
81
|
+
if ((cachedDataJson.type = 'Buffer')) {
|
|
82
|
+
cachedData = cachedDataJson.data
|
|
83
|
+
}
|
|
85
84
|
} catch (conversionError) {
|
|
86
85
|
console.error('캐시 데이터 변환 실패:', conversionError)
|
|
87
86
|
}
|
|
88
87
|
}
|
|
89
88
|
}
|
|
90
89
|
|
|
91
|
-
if (cachedData) {
|
|
90
|
+
if (cachedData && cachedData.length > 0) {
|
|
92
91
|
console.log(`전체 날씨 이미지 캐시 사용 (타입: ${type})`)
|
|
93
92
|
return cachedData
|
|
94
93
|
}
|
|
@@ -98,7 +97,7 @@ export async function getGlobalWeatherImage(type: WeatherType, forceRefresh: boo
|
|
|
98
97
|
|
|
99
98
|
var { value: weatherPoints } = (await cacheService.getFromCache(`weather-points`, {})) || {}
|
|
100
99
|
|
|
101
|
-
if (!weatherPoints) {
|
|
100
|
+
if (!weatherPoints || weatherPoints.length === 0) {
|
|
102
101
|
const weatherData = await getGlobalWeatherData(10)
|
|
103
102
|
|
|
104
103
|
const flattenedWeatherPoints = weatherData.reduce((acc, area) => {
|
|
@@ -106,10 +105,27 @@ export async function getGlobalWeatherImage(type: WeatherType, forceRefresh: boo
|
|
|
106
105
|
}, [])
|
|
107
106
|
|
|
108
107
|
weatherPoints = flattenedWeatherPoints.map(point => {
|
|
108
|
+
let value
|
|
109
|
+
switch (type) {
|
|
110
|
+
case 'temperature':
|
|
111
|
+
value = point.temperature?.current
|
|
112
|
+
break
|
|
113
|
+
case 'humidity':
|
|
114
|
+
value = point.humidity
|
|
115
|
+
break
|
|
116
|
+
case 'wind':
|
|
117
|
+
value = point.wind?.speed
|
|
118
|
+
break
|
|
119
|
+
case 'precipitation':
|
|
120
|
+
value = 0
|
|
121
|
+
break // 현재 데이터 없음
|
|
122
|
+
}
|
|
123
|
+
|
|
109
124
|
return {
|
|
110
125
|
lat: point.location.latitude,
|
|
111
126
|
lng: point.location.longitude,
|
|
112
|
-
value
|
|
127
|
+
value,
|
|
128
|
+
// value: point.temperature?.current,
|
|
113
129
|
description: point.weatherDescription,
|
|
114
130
|
temperature: point.temperature?.current,
|
|
115
131
|
humidity: point.humidity,
|
|
@@ -100,39 +100,70 @@ export async function renderWeatherMap(
|
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
imageData.data[index + 2] = color.b
|
|
116
|
-
imageData.data[index + 3] = color.a
|
|
117
|
-
} else {
|
|
118
|
-
console.warn('잘못된 인덱스:', index)
|
|
103
|
+
function calculateColor(type, value) {
|
|
104
|
+
switch (type) {
|
|
105
|
+
case 'temperature':
|
|
106
|
+
return { r: Math.min(255, Math.max(0, (value + 50) * 2.55)), g: 0, b: 0, a: 255 }
|
|
107
|
+
case 'humidity':
|
|
108
|
+
return { r: 0, g: Math.min(255, Math.max(0, value * 2.55)), b: 0, a: 255 }
|
|
109
|
+
case 'wind':
|
|
110
|
+
return { r: Math.min(255, Math.max(0, value * 5)), g: 0, b: 255, a: 255 }
|
|
111
|
+
case 'precipitation':
|
|
112
|
+
return { r: 0, g: 0, b: Math.min(255, Math.max(0, value * 2.55)), a: 255 }
|
|
113
|
+
default:
|
|
114
|
+
return { r: 255, g: 255, b: 255, a: 255 }
|
|
119
115
|
}
|
|
116
|
+
}
|
|
120
117
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
118
|
+
function renderInterpolated(ctx, data, type, width, height) {
|
|
119
|
+
const imageData = ctx.createImageData(width, height)
|
|
120
|
+
const maxDistance = width * 0.05 // 최대 영향 거리 (이미지 너비의 5%)
|
|
121
|
+
|
|
122
|
+
// 모든 픽셀에 대해 계산
|
|
123
|
+
for (let y = 0; y < height; y++) {
|
|
124
|
+
for (let x = 0; x < width; x++) {
|
|
125
|
+
// 픽셀의 위/경도 계산
|
|
126
|
+
const lng = (x / width) * 360 - 180
|
|
127
|
+
const lat = 90 - (y / height) * 180
|
|
128
|
+
|
|
129
|
+
// 역거리 가중치 보간법
|
|
130
|
+
let weightedSum = 0
|
|
131
|
+
let totalWeight = 0
|
|
132
|
+
|
|
133
|
+
data.forEach(point => {
|
|
134
|
+
const pixelX = ((point.lng + 180) / 360) * width
|
|
135
|
+
const pixelY = ((90 - point.lat) / 180) * height
|
|
136
|
+
const distance = Math.sqrt(Math.pow(x - pixelX, 2) + Math.pow(y - pixelY, 2))
|
|
137
|
+
|
|
138
|
+
if (distance <= maxDistance && typeof point.value === 'number') {
|
|
139
|
+
const weight = 1 / (Math.pow(distance, 2) + 0.1)
|
|
140
|
+
weightedSum += point.value * weight
|
|
141
|
+
totalWeight += weight
|
|
142
|
+
}
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
const index = (y * width + x) * 4
|
|
146
|
+
if (totalWeight > 0) {
|
|
147
|
+
const value = weightedSum / totalWeight
|
|
148
|
+
const color = calculateColor(type, value)
|
|
149
|
+
|
|
150
|
+
imageData.data[index] = color.r
|
|
151
|
+
imageData.data[index + 1] = color.g
|
|
152
|
+
imageData.data[index + 2] = color.b
|
|
153
|
+
imageData.data[index + 3] = color.a
|
|
154
|
+
} else {
|
|
155
|
+
// 영향 범위 내 데이터 없음
|
|
156
|
+
imageData.data[index + 3] = 0 // 투명하게
|
|
130
157
|
}
|
|
131
158
|
}
|
|
132
159
|
}
|
|
133
|
-
})
|
|
134
160
|
|
|
135
|
-
|
|
161
|
+
ctx.putImageData(imageData, 0, 0)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// 보간 렌더링 호출
|
|
165
|
+
renderInterpolated(ctx, data, type, width, height)
|
|
166
|
+
|
|
136
167
|
console.log('Canvas 렌더링 완료')
|
|
137
168
|
;(window as any).renderComplete = true
|
|
138
169
|
} catch (err) {
|