From b78e8c20b6d0be9133863d154113178541f14ba9 Mon Sep 17 00:00:00 2001 From: Guntis Smaukstelis Date: Sun, 16 Feb 2025 20:20:06 +0200 Subject: [PATCH] Add checkbox for latvia contour --- web/src/assets/latvia_contour.webp | Bin 0 -> 20666 bytes web/src/harmonie/GribFile.tsx | 7 +++++-- web/src/harmonie/Harmonie.tsx | 7 +++++++ web/src/harmonie/draw/drawGrib.ts | 30 ++++++++++++++++++++++++++++- 4 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 web/src/assets/latvia_contour.webp diff --git a/web/src/assets/latvia_contour.webp b/web/src/assets/latvia_contour.webp new file mode 100644 index 0000000000000000000000000000000000000000..d44ac642f9b60069f9beb690e136822e8bfc99b5 GIT binary patch literal 20666 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%0AmP(Cck}Q0 zkIltO(c0nytKo7emrHClH8uB82BBr5SB^|(k7LrKX8*|hCneKkHO^ubcaHc>JhijV z9uv1!3#{lJ8t=Fdcq) zV57C5j)uk66xLAF+%k~jB*Rg?h^Q!!YTm?nZ#4%&LR31f1@(salCLNrX7BR(ocwq+ z=AtKeh@}52hGjZO4p0{rA)Wwa|CGOVo(w%Toyo)DxqM}oBlMpHU)4^$!{6+ojyG6a zmL`E3qR9ksWO9O^>3kze%<5s=8CA+Y_9^~FQr>?1;O;%4pm+y4#4`PJqCwJhiij`) z9r;S&3_Yf1;qjSF(n;qq6ZgHh4YilzZcPYCpi3ykqr5hS6D8d~V;RL8{H0GDXLS4p z7=|i+{pQ^Mq-ADLzh==By_96Vb_+paeJut;)hD+}h+%=GJw>RkD0T0+aHBc@5kq=~ zaECQVep{3#dEn#B*o7XmURGAFHsJ2`DLv$GK=!m4`P2UB3$hf$(w9T(Y&nuet5g7a zGjq2$NMD9~&$jMF_Y5?ETpmRBt6iEvd1K*r8Sf5C3?DTD`L4S5QNgnC$=#Oty%av6 zI8kmBDbK)ZZpOfT4zWp9O@jmY-8v?qQW^EUB0@trPQUel=9!rpxaEr*O#0)4)E-HU z6gK1Do0Os2D{U~L8lB{40Eu?xi3o^ZE=C@BKbHJ^0?MQ<=VAKCSv^b0{?AQ0faUKR zK*8)2A6Vd*gM0fe;hrnxbIbBr~M!Nhi=3*yXnDpa>jDqTt}y zOqi<$3SVxJQZ8#B3_z9Kf1`=?(0BBuSGTG@AfFiPib2t2h8$mVD?L zo~;%c@UZdavgcz>gB8^OyQfdoI!|M?$gGXNN{EXsln+O%A%$j3%jzJGzkx5g5)8C9 z?vf`zEsCkpjNfIHh&~*8a^N69>-OHK5$P-NV1Ex}3ULWvad-^r;u@!4Wota*R<1@p zYeI1@>`Pz5WRYfhwGuQm@KJ*Sx44o-cMgRkgV`yjvh3&pI3;{=91mFohnL)Iy&iRJ|4wjBz&&XY{yQD?JeBi0q7!xxZxK$X6Sh z6GO$&IS(g1U|?^?Kz0xV#l1E$g+JpYUETU&2Q9`>FL{9PAYn>1tLZFI3RJoGm{m)C z;zHtN6={+@&dfTPH_k}I!tc7~Yp4kOxD3#>tJIDHi3SE=u>;Ac!OMmWj1%l60QV@< z86+d78gR8)N~3fo{=Lxy>?tP8pRy}NFo#F?0x+aj4N7_`pSCKGALAV zgI2ws!?-$b)V?+LC8DmzhUSwPI^e7~s>Ew%w|sIUT5Drs;{J6-DL8qht$0P=gT!f> zXkSP}Wtoa_-SUQA>BJkrN?H0;P*-FqTQGkuaZ`)x%6>%iUDl@4rq3zvuNLyOht>G((Cm*TdyaUJ#oVLBy*(xuqA%Avd=wO)NTXcoPP z9244Oji^s$*(p-DfO+kx(nF4kSD%(~Hqg2;$yV5nm{6lSweJ_cKybi>7~|vFr(HRQLZEF1{8#{#yjTdflqG33EHk%0fV(9+y_0H{-jv-S&PLL zdWD})RY<+rW*xi93imk6cpl0k^qjI2lc#W#ww@ontR1}!zHB}(zQ<962fr7eLjE3S zCwbiXq(1%rII=oEvg(6AsPoSe!&f$q6$20bo>*J}+38Y5XmEv;kRsDxLKpObo$d<> zNHRdbJS;0b2HZMmm`l=P4~%U8pluAeH-_Md2T%tuHk#}X?B`H2!_dgL3UPU5@_8I$ zCu#hCHBrT*`d0Rnx%G7G&V6w#lX{HzUl)=fWGc$AKfL3???sJ2yyc!g{){$KMl6@K z$ZNBUz@iS9C;GVvk%}caWt#)qNsKX=y8HB?hJ;%Xb2S&5yNH;0#uc74H+0pe?ZOzz z^gAKyII3k{J40*%S#!voKu2-$I&4PC=8(0w@*jF&cOG>{G@Qg^-xsJ)W&0`0C^QMbi3)DrG-?&0CN#v~0N=v; z)Fs6p!gYVmIU>-<2DhkG36m=rifsUV7QIQzmwVj)xf`QJpM4=f=%!#pXP`WzC8bjt zWx*y~Z(d_EeG59cmP=@3pX1gzHFO&`H^QYRH=gQ!1yZwEYUvmiAgH1K=~v~n9!MrP zT&*T09^6<9MFw(QskLqzE~bc+)(%LEf65{XqOKW;h=H`a)=+x$r5Z~#$*Om2u#?P| zp55>@e;6*08XcmJte!P0JCAJ9hRo$TZ^2Zkz^3BvNdLBPWN?^bL+f&^uio9R_59!_LjQ*O46$s zU_hEUzljd~dJsk@G^96yNm@H+3WsHAvk-z8&&+vcb|w~zd##@nhA-0AAVwIA18oIo z(D!N*==VCbPNN(V{DEQ-WGdL+bzAoxD#0Ld<$Uxc$ZK4GfOm9;1#foI5Ba{W7s1#PWs+__K?~Yrf=#CF_-u3qj8BLIjL?l4Dty-KHc7 z2+k^FDu$flcct2mw|JEJ7cJd#L7x$TJ#TC;a)4p{YuFYd+gu+RGVn6hE54{k$(0O0 z{`KnE^>cDUi@`@bbB64~gps#gOIS%C-(o1;u2tGN@t>jQBicW7N9?G7!FDNF`)~xi zXu5U>-Z&{M42JH}xeUbjq2%5OV^FAY)ar2?T?OcuwlbQf{T7_AMY$JFUITzdg=h<{ zwq@Q9%6>kDYch}U#_@_tO@Tc!6i7~~HOMKyAstLRqQ7b6_t<*RZ=ju#4@lCV-13lq zOE(xo82!?4%%~*Q10`5JLwWqb(U2ENi`Z?=Xg#QJ9`dc(Ukn0upN)}7v?XY z6l0#EfEknOdo!yJC5c1gzN*m>RRBx=(gU@_Va~Q&p)dO{Qx=S5q#Oan+?QS+OU6@; zz>nbRo1sDjq?X=rIWaep=$cWaa?ryR5tBnrcub+DmiNy@^H}TEPw+#`9{(6iGYl{T;*S|3Dxq#<26w=C8BrHCyb-_s4>%p zsol|`^@xY;kDy+Yp&J)WVyB*-yIfkj%%*GCfLDT`A1lGioNA4S}Kj$EEjZbr^2T;ScEn!bI&UKC` zq!fJUiLoO>uf&~I3{YiXXY_T?bMo}QPAWgBv;<<+UC5WLwPhsV zH%Fr6rABUxM^B~LY#`1m9Y6#Woh5};Uj^7a5)ns7+*aNcWHK($6Zc0EPrJ?#1E>m# zM@JW(>#qOw@!LbH-1=@au8GQeRy>j+_$z#evxz3Nbf&mgeRbuuVz!LuD2+56j~bt? z?d)r%R>eck4PED~_+u;?mGt*5HA)aSEIHj&Ajk!FIM&ly4$S8t$ z%niAe$DDIH#im|1Hqx~#w?Wzqn&#xL9p~C+(0#F_ezsMBS4|^8U&dyZu60J^nRLj! zeZ?ubyx_z=6x=vv5=|$lT|V;&Wk7Zp^j+0EqJR{)1UgU$+HHTG&acOuD-toLRZ?Yz zLppL$j_DK*>e)mXtnPwQ#577ZNg?Q8fl-p)Plegi+-@3vCWF+LuVpGyKJcwEvzOIJ zHHO;P=z*6je>td@oxR0MxkL`-85`T?b`QEAou+H+KXmDa%ekuGX=MYSCMYo5Ly)=RrL#0t^-Ma!9bCF*X<^9%F{USNk-CJ+jwoT~A5|L-*C-TuTalk#_x~A

%&d5!B0k^Fhbg9yF!A)-Ny<{h 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 // specific reference and forecast time (in one file) getAllGribLists: Accessor getIsCrop: Accessor, + getIsContour: Accessor, onClick: (name: string) => void, }> = ({ name, @@ -25,6 +26,7 @@ export const GribFile: Component<{ getFileGribList, getAllGribLists, getIsCrop, + getIsContour, onClick, }) => { let cachedMessages: GribMessage[] = [] @@ -36,10 +38,11 @@ export const GribFile: Component<{ createEffect(async () => { setIsLoading(true) const cropBounds = getIsCrop() ? CROP_BOUNDS : undefined + const contour = getIsContour() // hack to show loading spinner await new Promise(resolve => setTimeout(resolve, 100)) if (cachedMessages.length === 0) return; - drawGrib(getCanvas()!, cachedMessages, cachedBuffers, cachedBitmasks, cropBounds) + drawGrib(getCanvas()!, cachedMessages, cachedBuffers, cachedBitmasks, cropBounds, contour) setIsLoading(false) }) @@ -72,7 +75,7 @@ export const GribFile: Component<{ cachedBuffers = binaryBuffers.map(b => new Uint8Array(b)) cachedBitmasks = bitmasks.map(b => new Uint8Array(b)) const cropBounds = getIsCrop() ? CROP_BOUNDS : undefined - drawGrib(getCanvas()!, cachedMessages, cachedBuffers, cachedBitmasks, cropBounds) + drawGrib(getCanvas()!, cachedMessages, cachedBuffers, cachedBitmasks, cropBounds, getIsContour()) }) .catch(err => console.warn(err.message)) .finally(() => setIsLoading(false)) diff --git a/web/src/harmonie/Harmonie.tsx b/web/src/harmonie/Harmonie.tsx index 64e0318..8e08e47 100644 --- a/web/src/harmonie/Harmonie.tsx +++ b/web/src/harmonie/Harmonie.tsx @@ -14,6 +14,7 @@ export const Harmonie: Component<{}> = () => { const [getCanvas, setCanvas] = createSignal() const [getIsLoading, setIsLoading] = createSignal(true) const [getIsCrop, setIsCrop] = createSignal(true) + const [getIsContour, setIsContour] = createSignal(false) const [getGribList, setGribList] = createSignal([]) fetchJson(`${apiHost}/api/show/grib-list`) @@ -56,6 +57,11 @@ export const Harmonie: Component<{}> = () => { Crop Latvia setIsCrop(!getIsCrop())} /> +   +

    {getFileList().map(fileName => = () => { getFileGribList={() => getCurrentGribList(fileName)} getAllGribLists={getGribList} getIsCrop={getIsCrop} + getIsContour={getIsContour} onClick={() => onGribMessageClick(fileName)} /> )} diff --git a/web/src/harmonie/draw/drawGrib.ts b/web/src/harmonie/draw/drawGrib.ts index bba07fc..e5ee46c 100644 --- a/web/src/harmonie/draw/drawGrib.ts +++ b/web/src/harmonie/draw/drawGrib.ts @@ -3,10 +3,15 @@ import { GribMessage, MeteoParam } from '../interfaces' import { applyBitmask } from './bitmask' import { extractFromBounds } from './bounds' import { categoricalRainColors } from './categoricalRain' -import { hourPrecipitationColors, isCalculatedHourPrecipitation, precipitationColors } from './precipitation' +import { hourPrecipitationColors, precipitationColors } from './precipitation' import { temperatureColors } from './temperature' import { isCalculatedWindDirection, windDirectionArrows, windDirectionColors, windSpeedColors } from './windDirection' +import latvia_border from '../../assets/latvia_contour.webp' +const latviaBoderImg = new Image() +latviaBoderImg.onload = () => console.log('latvia_contour loaded') +latviaBoderImg.src = latvia_border + export type CropBounds = { x: number, y: number, width: number, height: number } export function drawGrib( @@ -15,6 +20,7 @@ export function drawGrib( buffers: Uint8Array[], bitmasks: Uint8Array[], cropBounds: CropBounds | undefined, + isContour: boolean, ): void { // normally we have one message/buffer/bitmask?. special cases have multiple like wind direction const [grib] = messages @@ -56,6 +62,10 @@ export function drawGrib( ctx.drawImage(tempCanvas, 0, -canvas.height) // ctx.drawImage(tempCanvas, 0, 0) ctx.restore() + + if (isContour && !!cropBounds) { + drawContour(canvas, ctx) // draw latvia contour only on cropped image + } } const CATEGORICAL_RAIN = [0, 1, 192] @@ -137,6 +147,24 @@ function fillImageData( } } +function drawContour( + canvas: HTMLCanvasElement, + ctx: CanvasRenderingContext2D, +): void { + ctx.save() + ctx.translate(canvas.width/2 + 8, canvas.height/2 - 5) + const angle = -26 + ctx.rotate(angle * Math.PI / 180) + const scale = 5.3 + const scaledWidth = latviaBoderImg.width/scale + const scaledHeight = latviaBoderImg.height/scale + ctx.drawImage(latviaBoderImg, + -scaledWidth/2, -scaledHeight/2, + scaledWidth, scaledHeight + ) + ctx.restore() +} + function rgbHexToU8(hex: string): RGBu8 { return [