Skip to content

Commit 717f158

Browse files
committed
Rework the extra space allocation for axes that are on the edges.
This still allocates space initially as it did before, but that is merely to let the JavaScript know where to make adjustments and so that there is space for the axes and tick labels to render. Then the JavaScript adjusts the space after the initial render. This ensures that there is enough space for the labels as well as make the spacing nicer when the board is resized in the imageview dialog.
1 parent 5794396 commit 717f158

File tree

3 files changed

+107
-40
lines changed

3 files changed

+107
-40
lines changed

htdocs/js/ImageView/imageview.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@
219219
if (graphDiv) {
220220
graphDiv.style.width = width + 'px';
221221
graphDiv.style.height = height + 'px';
222-
this.dispatchEvent(new Event('resized.imageview'));
222+
graphDiv.dispatchEvent(new Event('resized.imageview'));
223223
}
224224

225225
// Re-position the modal.
@@ -312,7 +312,7 @@
312312
backdrop.style.opacity = '0.2';
313313
});
314314
modal.addEventListener('hidden.bs.modal', () => {
315-
if (imgType == 'div') this.dispatchEvent(new Event('hidden.imageview'));
315+
if (graphDiv) graphDiv.dispatchEvent(new Event('hidden.imageview'));
316316
bsModal.dispose();
317317
modal.remove();
318318
window.removeEventListener('resize', onWinResize);

htdocs/js/Plots/plots.js

Lines changed: 99 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ const PGplots = {
182182

183183
// This axis provides the vertical grid lines.
184184
if (options.grid?.x) {
185-
board.create(
185+
plot.xGrid = board.create(
186186
'axis',
187187
[
188188
[options.xAxis?.min ?? -5, options.xAxis?.position ?? 0],
@@ -246,7 +246,7 @@ const PGplots = {
246246

247247
// This axis provides the horizontal grid lines.
248248
if (options.grid?.y) {
249-
board.create(
249+
plot.yGrid = board.create(
250250
'axis',
251251
[
252252
[options.yAxis?.position ?? 0, options.yAxis?.min ?? -5],
@@ -305,7 +305,7 @@ const PGplots = {
305305
}
306306

307307
if (options.xAxis?.visible) {
308-
const xAxis = board.create(
308+
const xAxis = (plot.xAxis = board.create(
309309
'axis',
310310
[
311311
[options.xAxis.min ?? -5, options.xAxis.position ?? 0],
@@ -374,16 +374,19 @@ const PGplots = {
374374
},
375375
options.xAxis.overrideOptions ?? {}
376376
)
377-
);
377+
));
378378
xAxis.defaultTicks.generateLabelText = plot.generateLabelText;
379379
xAxis.defaultTicks.formatLabelText = plot.formatLabelText;
380380

381-
if (options.xAxis.location !== 'middle') {
382-
board.create(
381+
if (options.xAxis.location !== 'middle' && options.xAxis.name !== '') {
382+
plot.xLabel = board.create(
383383
'text',
384384
[
385-
(xAxis.point1.X() + xAxis.point2.X()) / 2,
386-
options.xAxis.location === 'top' ? board.getBoundingBox()[1] : board.getBoundingBox()[3],
385+
() => (xAxis.point1.X() + xAxis.point2.X()) / 2,
386+
() =>
387+
options.xAxis.location === 'top'
388+
? board.getBoundingBox()[1] - 2 / board.unitY
389+
: board.getBoundingBox()[3] + 2 / board.unitY,
387390
options.xAxis.name ?? '\\(x\\)'
388391
],
389392
{
@@ -392,14 +395,15 @@ const PGplots = {
392395
highlight: false,
393396
color: 'black',
394397
fixed: true,
395-
useMathJax: true
398+
useMathJax: true,
399+
cssStyle: 'line-height: 1;'
396400
}
397401
);
398402
}
399403
}
400404

401405
if (options.yAxis?.visible) {
402-
const yAxis = board.create(
406+
const yAxis = (plot.yAxis = board.create(
403407
'axis',
404408
[
405409
[options.yAxis.position ?? 0, options.yAxis.min ?? -5],
@@ -469,35 +473,103 @@ const PGplots = {
469473
},
470474
options.yAxis.overrideOptions ?? {}
471475
)
472-
);
476+
));
473477
yAxis.defaultTicks.generateLabelText = plot.generateLabelText;
474478
yAxis.defaultTicks.formatLabelText = plot.formatLabelText;
475479

476-
if (options.yAxis.location !== 'center') {
477-
board.create(
478-
'text',
480+
if (options.yAxis.location !== 'center' && options.yAxis.name !== '') {
481+
plot.yLabel = board.create('text', [0, 0, options.yAxis.name ?? '\\(y\\)'], {
482+
anchorX: 'middle',
483+
anchorY: options.yAxis.location === 'right' ? 'bottom' : 'top',
484+
rotate: 90,
485+
highlight: 0,
486+
color: 'black',
487+
fixed: 1,
488+
useMathJax: 1,
489+
cssStyle: 'line-height: 1;'
490+
});
491+
const transform = board.create(
492+
'transform',
479493
[
480-
options.yAxis.location === 'right' ? boundingBox[2] : boundingBox[0],
481-
(yAxis.point1.Y() + yAxis.point2.Y()) / 2,
482-
options.yAxis.name ?? '\\(y\\)'
494+
() =>
495+
options.yAxis.location === 'right'
496+
? board.getBoundingBox()[2] - 2 / board.unitX
497+
: board.getBoundingBox()[0] + 2 / board.unitX,
498+
() => (yAxis.point1.Y() + yAxis.point2.Y()) / 2
483499
],
484-
{
485-
anchorX: 'middle',
486-
anchorY: options.yAxis.location === 'right' ? 'bottom' : 'top',
487-
rotate: 90,
488-
highlight: 0,
489-
color: 'black',
490-
fixed: 1,
491-
useMathJax: 1
492-
}
500+
{ type: 'translate' }
493501
);
502+
transform.bindTo(plot.yLabel);
494503
}
495504
}
496505

497506
plotContents(board, plot);
498507

499508
board.unsuspendUpdate();
500509

510+
plot.updateBoundingBox = () => {
511+
if (options.board?.showNavigation || (!plot.xAxis && !plot.yAxis)) return;
512+
513+
const adjustLeft = options.yAxis?.visible && boundingBox[0] < (options.xAxis?.min ?? -5);
514+
const adjustRight = options.yAxis?.visible && boundingBox[2] > (options.xAxis?.max ?? 5);
515+
const adjustBottom = options.xAxis?.visible && boundingBox[3] < (options.yAxis?.min ?? 5);
516+
const adjustTop = options.xAxis?.visible && boundingBox[1] > (options.yAxis?.max ?? -5);
517+
if (!adjustLeft && !adjustRight && !adjustTop && !adjustBottom) return;
518+
519+
let width = 0;
520+
if (plot.yAxis) {
521+
for (const label of plot.yAxis.defaultTicks.labels) {
522+
const rect = label.rendNode.getBoundingClientRect();
523+
if (rect.width > width) width = rect.width;
524+
}
525+
if (plot.yLabel) width += plot.yLabel.rendNode.getBoundingClientRect().width + 4;
526+
width += 12;
527+
}
528+
529+
let height = 0;
530+
if (plot.xAxis) {
531+
for (const label of plot.xAxis.defaultTicks.labels) {
532+
const rect = label.rendNode.getBoundingClientRect();
533+
if (rect.height > height) height = rect.height;
534+
}
535+
if (plot.xLabel) height += plot.xLabel.rendNode.getBoundingClientRect().height + 4;
536+
height += 8;
537+
}
538+
539+
const currentBoundingBox = board.getBoundingBox();
540+
board.setBoundingBox([
541+
adjustLeft ? options.xAxis.min - width / board.unitX : currentBoundingBox[0],
542+
adjustTop ? options.yAxis.max + height / board.unitY : currentBoundingBox[1],
543+
adjustRight ? options.xAxis.max + width / board.unitX : currentBoundingBox[2],
544+
adjustBottom ? options.yAxis.min - height / board.unitY : currentBoundingBox[3]
545+
]);
546+
547+
if (options.yAxis.location !== 'center' && (adjustLeft || adjustRight)) {
548+
const anchorDist = adjustLeft
549+
? (options.xAxis?.min ?? -5) - board.getBoundingBox()[0]
550+
: board.getBoundingBox()[2] - (options.xAxis?.max ?? -5);
551+
plot.yAxis?.setAttribute({ anchorDist });
552+
plot.yGrid?.setAttribute({ anchorDist });
553+
}
554+
if (options.xAxis.location !== 'center' && (adjustBottom || adjustTop)) {
555+
const anchorDist = adjustBottom
556+
? (options.yAxis?.min ?? -5) - board.getBoundingBox()[3]
557+
: board.getBoundingBox()[1] - (options.yAxis?.max ?? -5);
558+
plot.xAxis?.setAttribute({ anchorDist });
559+
plot.xGrid?.setAttribute({ anchorDist });
560+
}
561+
};
562+
563+
if (id.startsWith('magnified-')) {
564+
board.containerObj.addEventListener('resized.imageview', () => {
565+
board.resizeContainer(board.containerObj.clientWidth, board.containerObj.clientHeight, true);
566+
setTimeout(plot.updateBoundingBox);
567+
});
568+
board.containerObj.addEventListener('hidden.imageview', () => JXG.JSXGraph.freeBoard(board));
569+
} else {
570+
setTimeout(plot.updateBoundingBox);
571+
}
572+
501573
return board;
502574
};
503575

@@ -515,19 +587,11 @@ const PGplots = {
515587

516588
await drawPromise(boardContainerId);
517589

518-
let jsxBoard = null;
519590
container.addEventListener('shown.imageview', async () => {
520591
document
521592
.getElementById(`magnified-${boardContainerId}`)
522593
?.classList.add(...Array.from(container.classList).filter((c) => c !== 'image-view-elt'));
523-
jsxBoard = await drawPromise(`magnified-${boardContainerId}`);
524-
});
525-
container.addEventListener('resized.imageview', () => {
526-
jsxBoard?.resizeContainer(jsxBoard.containerObj.clientWidth, jsxBoard.containerObj.clientHeight, true);
527-
});
528-
container.addEventListener('hidden.imageview', () => {
529-
if (jsxBoard) JXG.JSXGraph.freeBoard(jsxBoard);
530-
jsxBoard = null;
594+
await drawPromise(`magnified-${boardContainerId}`);
531595
});
532596
}
533597
};

lib/Plots/JSXGraph.pm

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,10 @@ sub HTML {
6565
$options->{board}{showNavigation} = $axes->style('jsx_navigation') ? 1 : 0;
6666
$options->{board}{overrideOptions} = $axes->style('jsx_options') if $axes->style('jsx_options');
6767

68-
# Set the bounding box. Add padding for the axes at the edge of graph if needed.
68+
# Set the bounding box. Add padding for the axes at the edge of graph if needed. Note that the padding set here is
69+
# not the final padding used in the end result. The plots.js JavaScript adjusts the padding to fit the axis label
70+
# content. This just needs to add enough padding so that the label content has enough room to render, and so that
71+
# the JavaScript knows where the adjustments are needed.
6972
$options->{board}{boundingBox} = [
7073
$xmin - (
7174
$yvisible
@@ -80,8 +83,8 @@ sub HTML {
8083
];
8184

8285
$options->{xAxis}{visible} = $xvisible;
86+
($options->{xAxis}{min}, $options->{xAxis}{max}) = ($xmin, $xmax);
8387
if ($xvisible || ($show_grid && $grid->{xmajor})) {
84-
($options->{xAxis}{min}, $options->{xAxis}{max}) = ($xmin, $xmax);
8588
$options->{xAxis}{position} = $xaxis_pos;
8689
$options->{xAxis}{location} = $xaxis_loc;
8790
$options->{xAxis}{ticks}{scale} = $axes->xaxis('tick_scale');
@@ -90,8 +93,8 @@ sub HTML {
9093
}
9194

9295
$options->{yAxis}{visible} = $yvisible;
96+
($options->{yAxis}{min}, $options->{yAxis}{max}) = ($ymin, $ymax);
9397
if ($yvisible || ($show_grid && $grid->{ymajor})) {
94-
($options->{yAxis}{min}, $options->{yAxis}{max}) = ($ymin, $ymax);
9598
$options->{yAxis}{position} = $yaxis_pos;
9699
$options->{yAxis}{location} = $yaxis_loc;
97100
$options->{yAxis}{ticks}{scale} = $axes->yaxis('tick_scale');

0 commit comments

Comments
 (0)