feat: now each chart can be opened in full screen

This commit is contained in:
Kacper Kula 2025-08-13 21:12:02 +01:00
parent e45ef49ed6
commit 22dbb66fcd
4 changed files with 177 additions and 8 deletions

View file

@ -0,0 +1,5 @@
---
"sqlseal-charts": patch
---
now every chart can be opened in full screen

View file

@ -1,4 +1,4 @@
import { App } from "obsidian";
import { App, setIcon } from "obsidian";
import { parseCode } from "./utils/configParser";
import { prepareDataVariables } from "./utils/prepareDataVariables";
import * as echarts from 'echarts';
@ -6,6 +6,7 @@ import * as ecStat from 'echarts-stat';
import type { RendererConfig } from "@hypersphere/sqlseal";
import { ViewDefinition } from "@hypersphere/sqlseal/dist/src/grammar/parser";
import { parseCodeAdvanced } from "./utils/advancedParser";
import { FullScreenChartModal } from "./fullscreenModal";
interface Config {
config: string
@ -36,6 +37,20 @@ export class ChartRenderer implements RendererConfig {
return { config: config.trim() }
}
private createFullscreenButton(container: HTMLElement, chartConfig: Record<string, any>) {
const fullscreenButton = container.createEl('button', {
cls: 'sqlseal-fullscreen-button',
attr: { 'aria-label': 'Open chart in fullscreen' }
})
setIcon(fullscreenButton, 'maximize-2')
fullscreenButton.addEventListener('click', (e) => {
e.stopPropagation();
const modal = new FullScreenChartModal(this.app, chartConfig);
modal.open();
})
}
render(config: Config, el: HTMLElement) {
let isRendered: boolean = false
let chart: echarts.ECharts | null = null
@ -78,12 +93,16 @@ export class ChartRenderer implements RendererConfig {
el.empty()
const container = el.createDiv({ cls: 'sqlseal-charts-container' })
const chartDiv = container.createDiv()
const chartHeader = container.createDiv({ cls: 'sqlseal-chart-header' })
const chartDiv = container.createDiv({ cls: 'sqlseal-chart-content' })
this.createFullscreenButton(chartHeader, configRecord)
requestAnimationFrame(() => {
const box = container.getBoundingClientRect()
const width = box.width
const height = box.height
const containerBox = container.getBoundingClientRect()
const width = containerBox.width
const height = containerBox.height
chart = echarts.init(chartDiv, null, { height: height, width: width })
chart.setOption(configRecord)
isRendered = true

87
src/fullscreenModal.ts Normal file
View file

@ -0,0 +1,87 @@
import { App, Modal } from "obsidian";
import * as echarts from 'echarts';
export class FullScreenChartModal extends Modal {
private chart: echarts.ECharts | null = null;
private chartConfig: Record<string, any>;
private resizeHandler: (() => void) | null = null;
constructor(app: App, chartConfig: Record<string, any>) {
super(app);
this.chartConfig = chartConfig;
this.scope.register([], "Escape", () => {
this.close();
});
}
onOpen() {
const { contentEl, modalEl } = this;
contentEl.empty();
// Apply fullscreen classes
modalEl.addClass('sqlseal-fullscreen-modal');
contentEl.addClass('sqlseal-fullscreen-modal');
// Force modal to fullscreen dimensions
modalEl.style.width = '100vw';
modalEl.style.height = '100vh';
modalEl.style.maxWidth = 'none';
modalEl.style.maxHeight = 'none';
modalEl.style.left = '0';
modalEl.style.top = '0';
modalEl.style.transform = 'none';
modalEl.style.margin = '0';
// Set content area dimensions
contentEl.style.width = '95vw';
contentEl.style.height = '90vh';
contentEl.style.maxWidth = 'none';
contentEl.style.maxHeight = 'none';
contentEl.style.margin = '2.5vh 2.5vw';
contentEl.style.position = 'absolute';
contentEl.style.left = '2.5vw';
contentEl.style.top = '5vh';
const chartContainer = contentEl.createDiv({ cls: 'sqlseal-fullscreen-chart-container' });
// Initialize chart after modal is rendered
requestAnimationFrame(() => {
requestAnimationFrame(() => {
const containerRect = chartContainer.getBoundingClientRect();
const width = containerRect.width || window.innerWidth * 0.9;
const height = containerRect.height || window.innerHeight * 0.8;
this.chart = echarts.init(chartContainer, null, { width, height });
this.chart.setOption(this.chartConfig);
this.resizeHandler = () => {
if (this.chart) {
this.chart.resize();
}
};
window.addEventListener('resize', this.resizeHandler);
// Ensure proper sizing after initialization
setTimeout(() => {
if (this.chart) {
this.chart.resize();
}
}, 100);
});
});
}
onClose() {
if (this.resizeHandler) {
window.removeEventListener('resize', this.resizeHandler);
this.resizeHandler = null;
}
if (this.chart) {
this.chart.dispose();
this.chart = null;
}
}
}

View file

@ -1,11 +1,69 @@
.sqlseal-charts-container {
display: grid;
justify-content: center;
display: flex;
flex-direction: column;
width: 100%;
aspect-ratio: 16 / 9;
position: relative;
}
.sqlseal-charts-container > div {
.sqlseal-chart-header {
display: flex;
justify-content: flex-end;
position: absolute;
bottom: 8px;
right: 8px;
z-index: 10;
}
.sqlseal-fullscreen-button {
background: var(--background-modifier-hover);
border: none;
border-radius: var(--radius-s);
padding: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.7;
transition: opacity 0.2s ease;
}
.sqlseal-fullscreen-button:hover {
background: var(--background-modifier-border-hover);
opacity: 1;
}
.sqlseal-chart-content {
width: 100%;
height: 100%;
flex: 1;
}
.sqlseal-fullscreen-modal {
z-index: 9999;
}
.sqlseal-fullscreen-modal .modal {
width: 100vw !important;
height: 100vh !important;
max-width: none !important;
max-height: none !important;
margin: 0 !important;
padding: 0 !important;
}
.sqlseal-fullscreen-modal .modal-content {
width: 95vw !important;
height: 90vh !important;
max-width: none !important;
max-height: none !important;
padding: 20px !important;
margin: 2.5vh 2.5vw !important;
border-radius: 8px !important;
}
.sqlseal-fullscreen-chart-container {
width: 100%;
height: calc(90vh - 40px);
min-height: 400px;
}