mirror of
https://github.com/h-sphere/sql-seal-charts.git
synced 2026-07-22 12:00:28 +00:00
Merge pull request #9 from h-sphere/feat/chart-full-screen
feat: now each chart can be opened in full screen
This commit is contained in:
commit
f359f0e587
4 changed files with 171 additions and 8 deletions
5
.changeset/hungry-jokes-say.md
Normal file
5
.changeset/hungry-jokes-say.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"sqlseal-charts": patch
|
||||
---
|
||||
|
||||
now every chart can be opened in full screen
|
||||
|
|
@ -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
|
||||
|
|
|
|||
69
src/fullscreenModal.ts
Normal file
69
src/fullscreenModal.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
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");
|
||||
|
||||
const chartContainer = contentEl.createDiv({
|
||||
cls: "sqlseal-fullscreen-chart-container",
|
||||
});
|
||||
|
||||
// Initialize chart after modal is rendered
|
||||
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);
|
||||
|
||||
// Show modal after chart is loaded
|
||||
modalEl.addClass("loaded");
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
76
styles.css
76
styles.css
|
|
@ -1,11 +1,81 @@
|
|||
.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-charts-container:hover .sqlseal-chart-header {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.sqlseal-chart-header {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
z-index: 10;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.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;
|
||||
width: 100vw !important;
|
||||
height: 100vh !important;
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
left: 0 !important;
|
||||
top: 0 !important;
|
||||
transform: none !important;
|
||||
margin: 0 !important;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.sqlseal-fullscreen-modal.loaded {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.sqlseal-fullscreen-modal .modal-content {
|
||||
width: 95vw !important;
|
||||
height: 90vh !important;
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
margin: 2.5vh 2.5vw !important;
|
||||
position: absolute !important;
|
||||
left: 2.5vw !important;
|
||||
top: 5vh !important;
|
||||
}
|
||||
|
||||
.sqlseal-fullscreen-chart-container {
|
||||
width: 100%;
|
||||
height: calc(90vh - 40px);
|
||||
min-height: 400px;
|
||||
}
|
||||
Loading…
Reference in a new issue