Skip to content
Merged

Sri #131

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added anemui-core/assets/images/banner_logos_imp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions anemui-core/css/graphcontainer.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,21 @@ div.GraphContainer {
padding: 0.3em 0.5em;
}

.pop-graph {
width: clamp(300px, 50vw, 900px);
height: clamp(250px, 44vh, 500px);

@include md-desktop {
width: clamp(500px, 55vw, 1100px);
height: clamp(350px, 48vh, 600px);
}

@include xl-desktop {
width: clamp(600px, 55vw, 1200px);
height: clamp(400px, 50vh, 650px);
}
}

a.popup-close-button {
position: absolute;
top: 10px;
Expand Down
38 changes: 32 additions & 6 deletions anemui-core/css/topbar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -680,11 +680,11 @@
}

.inputDiv .title {
font-size: 0.8em;
font-size: 0.7em;
}

.inputDiv .sub-title {
font-size: 0.8em;
font-size: 0.7em;
}


Expand Down Expand Up @@ -722,18 +722,36 @@
}
}

@include md-desktop {
.inputDiv .title {
font-size: 0.8em;
}

.inputDiv .sub-title {
font-size: 0.8em;
}
}

@include xl-desktop {
// width: 97%;
padding-top: 0em;

.longLogo, .shortLogo, .allScrLogo {
padding-left: 0;
}

#logo img {
width: 120px;
margin-left: 7%;
}

.inputDiv .title {
font-size: 0.9em;
}

.inputDiv .sub-title {
font-size: 0.9em;
}
}
}

Expand Down Expand Up @@ -788,7 +806,7 @@ li {

.inputDiv .title{
white-space: normal;
font-size: 0.7em;
font-size: 0.6em;
font-style: italic;
line-height: 1.2;
text-align: left;
Expand All @@ -799,7 +817,7 @@ li {

.inputDiv .sub-title {
display: block;
font-size: 1em;
font-size: 0.9em;
font-style: normal;
font-weight: 500;
width: fit-content;
Expand Down Expand Up @@ -983,9 +1001,17 @@ input.selection-param-input {
.dropdown-item {
box-sizing: border-box;
white-space: normal;
font-size: 0.7em !important;
font-size: 0.6em !important;
font-style: italic;
line-height: 1.2;

@include md-desktop {
font-size: 0.65em !important;
}

@include xl-desktop {
font-size: 0.7em !important;
}
}

#marker {
Expand Down
8 changes: 4 additions & 4 deletions anemui-core/src/language/language.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ export default class Language {
'index units': 'Index units',
'Terciles': 'Terciles',
'Anomalías': 'Anomalies',
'kJ/m2': 'kJ/m²',
'MJ/m2': 'MJ/m²'
'kJ/m2': 'kJ/m²·day',
'MJ/m2': 'MJ/m²·day'
}
},
es: {
Expand Down Expand Up @@ -184,8 +184,8 @@ export default class Language {
'index units': 'Unidades del índice',
'Terciles': 'Terciles',
'Anomalías': 'Anomalías',
'kJ/m2': 'kJ/m²',
'MJ/m2': 'MJ/m²'
'kJ/m2': 'kJ/m²·día',
'MJ/m2': 'MJ/m²·día'
}
}
}
Expand Down
116 changes: 65 additions & 51 deletions anemui-core/src/ui/Graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { dateText } from "../data/CsPConstans";
import { CsTimeSpan } from "../data/CsDataTypes";
import { CsLatLong } from '../CsMapTypes';


require("dygraphs/dist/dygraph.css")

export type GraphType = "Serial" | "Area" | "Linear" | "Cummulative" | "MgFr" | "WindRose" | "PercentileClock" | "ECDF" | "DailyEvolution"
Expand Down Expand Up @@ -110,21 +111,16 @@ export class CsGraph extends BaseFrame {

public render(): JSX.Element {
let self = this;
// Calcular tamaño responsivo del gráfico
const maxWidth = Math.min(screen.width * 0.85, 900);
const maxHeight = Math.min(screen.height * 0.65, 500);
let graphWidth = screen.width > 1200 ? Math.min(screen.width * 0.4, maxWidth) : Math.min(screen.width * 0.55, maxWidth);
let graphHeight = screen.height > 900 ? Math.min(screen.height * 0.4, maxHeight) : Math.min(screen.height * 0.50, maxHeight);
let element =
(<div className="container">
<div id="GraphContainer" className='GraphContainer row' hidden >
<div className="popup-content-wrapper col">
<div className="popup-content" style={{ width: "auto", position: "relative" }}>
<div id="popGraph" style={{ height: graphHeight + "px", width: graphWidth + "px" }}></div>
<div id="popGraph" className="pop-graph"></div>
<div id="graphTooltip"></div>
</div>
<div className="labels-content" style={{ width: "auto" }}>
<div id="labels" style={{ width: "100%", maxWidth: graphWidth + "px" }}></div>
<div id="labels" style={{ width: "100%" }}></div>
</div>
<div id="colorLegend" style={{ display: "none", padding: "8px 5px", justifyContent: "center", alignItems: "center", gap: "3px", flexWrap: "wrap", fontSize: "11px" }}></div>
<div id="graphControls" className="graph-controls" hidden style={{ display: "flex", justifyContent: "center", alignItems: "center", padding: "10px", gap: "15px", flexWrap: "wrap" }}>
Expand Down Expand Up @@ -315,10 +311,12 @@ export class CsGraph extends BaseFrame {
const totalH = headerHeight + graphH + labelsH + colorLegendH + copyrightHeight;
const totalW = graphW;

const dpr = Math.max(window.devicePixelRatio || 1, 2);
const exportCanvas = document.createElement('canvas');
exportCanvas.width = totalW;
exportCanvas.height = totalH;
exportCanvas.width = Math.round(totalW * dpr);
exportCanvas.height = Math.round(totalH * dpr);
const ctx = exportCanvas.getContext('2d');
ctx.scale(dpr, dpr);

// Fondo blanco
ctx.fillStyle = '#ffffff';
Expand Down Expand Up @@ -492,7 +490,7 @@ export class CsGraph extends BaseFrame {
}

// --- Barra de logos (pie) ---
this.drawLogosAndDownload(exportCanvas, ctx, 'grafico.png');
this.drawLogosAndDownload(exportCanvas, ctx, 'grafico.png', dpr);
}

/**
Expand Down Expand Up @@ -535,67 +533,83 @@ export class CsGraph extends BaseFrame {
ctx.drawImage(chartCanvas, 0, headerHeight);

// Barra de logos + descarga
this.drawLogosAndDownload(exportCanvas, ctx, filename);
this.drawLogosAndDownload(exportCanvas, ctx, filename, window.devicePixelRatio || 1);
}

protected drawLogosAndDownload(exportCanvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D, filename: string): void {
const logoImg = document.querySelector('#logo-container img') as HTMLImageElement;
if (logoImg && logoImg.complete && logoImg.naturalWidth > 0) {
this.appendLogosBarAndDownload(exportCanvas, logoImg, filename);
} else if (logoImg) {
const clone = new Image();
clone.crossOrigin = 'anonymous';
clone.onload = () => this.appendLogosBarAndDownload(exportCanvas, clone, filename);
clone.onerror = () => this.downloadExportCanvas(exportCanvas, filename);
clone.src = logoImg.src;
} else {
this.downloadExportCanvas(exportCanvas, filename);
}
protected drawLogosAndDownload(exportCanvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D, filename: string, exportScale?: number): void {
const banner = new Image();
banner.crossOrigin = 'anonymous';
banner.onload = () => this.appendLogosBarAndDownload(exportCanvas, banner, filename, exportScale);
banner.onerror = () => this.downloadExportCanvas(exportCanvas, filename);
banner.src = './images/banner_logos_imp.png';
}

protected appendLogosBarAndDownload(srcCanvas: HTMLCanvasElement, logoImg: HTMLImageElement, filename: string): void {
const logoBarHeight = 60;
const pad = 10;
protected appendLogosBarAndDownload(srcCanvas: HTMLCanvasElement, logoImg: HTMLImageElement, filename: string, exportScale?: number): void {
const pad = 6;
const copyrightLineH = 18;
const dpr = exportScale ?? (window.devicePixelRatio || 1);

const cssW = srcCanvas.width / dpr;

// Logos a ancho completo, altura proporcional
const logoH = cssW * (logoImg.naturalHeight / logoImg.naturalWidth);
const totalBarH = logoH + copyrightLineH;
const totalBarHPx = Math.round(totalBarH * dpr);

const finalCanvas = document.createElement('canvas');
finalCanvas.width = srcCanvas.width;
finalCanvas.height = srcCanvas.height + logoBarHeight;
finalCanvas.height = srcCanvas.height + totalBarHPx;
const fCtx = finalCanvas.getContext('2d');

// Copiar el contenido del gráfico (ya está en resolución dpr)
fCtx.drawImage(srcCanvas, 0, 0);

const barY = srcCanvas.height;
fCtx.fillStyle = '#ffffff';
fCtx.fillRect(0, barY, finalCanvas.width, logoBarHeight);
fCtx.save();
fCtx.translate(0, srcCanvas.height);
fCtx.scale(dpr, dpr);

// Fondo blanco + línea separadora
fCtx.fillStyle = '#ffffff';
fCtx.fillRect(0, 0, cssW, totalBarH);
fCtx.strokeStyle = '#cccccc';
fCtx.lineWidth = 1;
fCtx.beginPath();
fCtx.moveTo(0, barY);
fCtx.lineTo(finalCanvas.width, barY);
fCtx.moveTo(0, 0);
fCtx.lineTo(cssW, 0);
fCtx.stroke();

// Copyright primero (para medir su ancho y reservar espacio)
const copyrightText = '\u00A9 AEMET - CSIC PTI-Clima';
// Logo a ancho completo — downscaling progresivo (mipmap) para evitar
// artefactos al reducir 6060px→~800px en un solo paso.
const targetW = Math.round(cssW * dpr);
const targetH = Math.round(logoH * dpr);
let logoSrc: HTMLImageElement | HTMLCanvasElement = logoImg;
let sw = logoImg.naturalWidth;
let sh = logoImg.naturalHeight;
while (sw / targetW > 2 || sh / targetH > 2) {
sw = Math.max(Math.ceil(sw / 2), targetW);
sh = Math.max(Math.ceil(sh / 2), targetH);
const tmp = document.createElement('canvas');
tmp.width = sw;
tmp.height = sh;
const tCtx = tmp.getContext('2d');
tCtx.imageSmoothingEnabled = true;
tCtx.imageSmoothingQuality = 'high';
tCtx.drawImage(logoSrc, 0, 0, sw, sh);
logoSrc = tmp;
}
fCtx.imageSmoothingEnabled = true;
fCtx.imageSmoothingQuality = 'high';
fCtx.drawImage(logoSrc, 0, 0, cssW, logoH);

// Copyright en línea separada debajo
const copyrightText = '© AEMET - CSIC PTI-Clima';
fCtx.font = '10px sans-serif';
fCtx.fillStyle = '#666666';
fCtx.textBaseline = 'bottom';
fCtx.textBaseline = 'middle';
fCtx.textAlign = 'right';
fCtx.fillText(copyrightText, finalCanvas.width - pad, barY + logoBarHeight - 4);
fCtx.textAlign = 'left';
const copyrightW = fCtx.measureText(copyrightText).width + pad * 2;

// Logo: ajustar para no solapar el copyright
const maxLogoH = logoBarHeight - pad * 2;
const maxLogoW = finalCanvas.width - copyrightW - pad;
const scaleH = maxLogoH / logoImg.naturalHeight;
const scaleW = maxLogoW / logoImg.naturalWidth;
const scale = Math.min(scaleH, scaleW);
const logoW = logoImg.naturalWidth * scale;
const logoH = logoImg.naturalHeight * scale;
const logoX = pad;
const logoY = barY + (logoBarHeight - logoH) / 2;
fCtx.drawImage(logoImg, logoX, logoY, logoW, logoH);
fCtx.fillText(copyrightText, cssW - pad, logoH + copyrightLineH / 2);

fCtx.restore();

this.downloadExportCanvas(finalCanvas, filename);
}
Expand Down