@things-factory/weather 9.0.0-beta.49 → 9.0.0-beta.52

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.
@@ -100,39 +100,70 @@ export async function renderWeatherMap(
100
100
  }
101
101
  }
102
102
 
103
- const imageData = ctx.createImageData(width, height)
104
-
105
- data.forEach(point => {
106
- const pixel = latLngToPixel(point.lat, point.lng)
107
- if (!pixel) return
108
-
109
- const color = valueToRGB(type, point)
110
- const index = (pixel.y * width + pixel.x) * 4
111
-
112
- if (index >= 0 && index < imageData.data.length) {
113
- imageData.data[index] = color.r
114
- imageData.data[index + 1] = color.g
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
- /* only for test */
122
- for (let dy = -18; dy <= 18; dy++) {
123
- for (let dx = -18; dx <= 18; dx++) {
124
- const fillIndex = ((pixel.y + dy) * width + (pixel.x + dx)) * 4
125
- if (fillIndex >= 0 && fillIndex < imageData.data.length) {
126
- imageData.data[fillIndex] = color.r
127
- imageData.data[fillIndex + 1] = color.g
128
- imageData.data[fillIndex + 2] = color.b
129
- imageData.data[fillIndex + 3] = color.a
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
- ctx.putImageData(imageData, 0, 0)
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) {