Plot outputs incorrectly sized inside scaled outputs (#4139)

* Fix #4135: Plot outputs incorrectly sized inside scaled outputs

CSS zoom property affects el.getBoundingClientRect() but not
el.offsetWidth/Height. When reporting sizes of outputs from
client to server, we need to back out the CSS zoom because
those sizes are used as CSS width/height, which will be
affected by zoom.

(Note that something similar happens with CSS transforms but
we don't have a good way to deal with them)

* Squelch TS error

* `yarn build` (GitHub Actions)

* Add TODO

Co-authored-by: Garrick Aden-Buie <garrick@adenbuie.com>

* Rebuild JS

---------

Co-authored-by: jcheng5 <jcheng5@users.noreply.github.com>
Co-authored-by: Garrick Aden-Buie <garrick@adenbuie.com>
This commit is contained in:
Joe Cheng
2024-12-08 01:25:32 -08:00
committed by GitHub
parent e5083f4938
commit 5bf0701939
7 changed files with 39 additions and 11 deletions

View File

@@ -6873,6 +6873,14 @@
return 1;
}
}
function getBoundingClientSizeBeforeZoom(el) {
var rect = el.getBoundingClientRect();
var zoom = el.currentCSSZoom || 1;
return {
width: rect.width / zoom,
height: rect.height / zoom
};
}
function scopeExprToFunc(expr) {
var exprEscaped = expr.replace(/[\\"']/g, "\\$&").replace(/\u0000/g, "\\0").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/[\b]/g, "\\b");
var func;
@@ -25282,7 +25290,7 @@
};
doSendImageSize = function _doSendImageSize() {
(0, import_jquery39.default)(".shiny-image-output, .shiny-plot-output, .shiny-report-size").each(function() {
var id = getIdFromEl(this), rect = this.getBoundingClientRect();
var id = getIdFromEl(this), rect = getBoundingClientSizeBeforeZoom(this);
if (rect.width !== 0 || rect.height !== 0) {
inputs.setInput(".clientdata_output_" + id + "_width", rect.width);
inputs.setInput(".clientdata_output_" + id + "_height", rect.height);
@@ -25464,7 +25472,7 @@
};
initialValues = (0, _context3.t0)(_context3.t1, _context3.t2);
(0, import_jquery39.default)(".shiny-image-output, .shiny-plot-output, .shiny-report-size").each(function() {
var id = getIdFromEl(this), rect = this.getBoundingClientRect();
var id = getIdFromEl(this), rect = getBoundingClientSizeBeforeZoom(this);
if (rect.width !== 0 || rect.height !== 0) {
initialValues[".clientdata_output_" + id + "_width"] = rect.width;
initialValues[".clientdata_output_" + id + "_height"] = rect.height;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -21,6 +21,7 @@ import { debounce, Debouncer } from "../time";
import {
$escape,
compareVersion,
getBoundingClientSizeBeforeZoom,
getComputedLinkColor,
getStyle,
hasDefinedProperty,
@@ -289,7 +290,7 @@ class ShinyClass {
$(".shiny-image-output, .shiny-plot-output, .shiny-report-size").each(
function () {
const id = getIdFromEl(this),
rect = this.getBoundingClientRect();
rect = getBoundingClientSizeBeforeZoom(this);
if (rect.width !== 0 || rect.height !== 0) {
initialValues[".clientdata_output_" + id + "_width"] = rect.width;
@@ -425,7 +426,7 @@ class ShinyClass {
$(".shiny-image-output, .shiny-plot-output, .shiny-report-size").each(
function () {
const id = getIdFromEl(this),
rect = this.getBoundingClientRect();
rect = getBoundingClientSizeBeforeZoom(this);
if (rect.width !== 0 || rect.height !== 0) {
inputs.setInput(".clientdata_output_" + id + "_width", rect.width);

View File

@@ -144,6 +144,20 @@ function pixelRatio(): number {
}
}
function getBoundingClientSizeBeforeZoom(el: HTMLElement): {
width: number;
height: number;
} {
const rect = el.getBoundingClientRect();
// Cast to any because currentCSSZoom isn't in the type def of HTMLElement
// TODO: typescript >= 5.5.2 added this property to the type definition
const zoom = (el as any).currentCSSZoom || 1;
return {
width: rect.width / zoom,
height: rect.height / zoom,
};
}
// Takes a string expression and returns a function that takes an argument.
//
// When the function is executed, it will evaluate that expression using
@@ -398,6 +412,7 @@ export {
formatDateUTC,
makeResizeFilter,
pixelRatio,
getBoundingClientSizeBeforeZoom,
scopeExprToFunc,
asArray,
mergeSort,

View File

@@ -10,6 +10,10 @@ declare function parseDate(dateString: string): Date;
declare function formatDateUTC(x: Date): string;
declare function makeResizeFilter(el: HTMLElement, func: (width: HTMLElement["offsetWidth"], height: HTMLElement["offsetHeight"]) => void): () => void;
declare function pixelRatio(): number;
declare function getBoundingClientSizeBeforeZoom(el: HTMLElement): {
width: number;
height: number;
};
declare function scopeExprToFunc(expr: string): (scope: unknown) => unknown;
declare function asArray<T>(value: T | T[] | null | undefined): T[];
declare function mergeSort<Item>(list: Item[], sortfunc: (a: Item, b: Item) => boolean | number): Item[];
@@ -26,4 +30,4 @@ declare function updateLabel(labelTxt: string | undefined, labelNode: JQuery<HTM
declare function getComputedLinkColor(el: HTMLElement): string;
declare function isBS3(): boolean;
declare function toLowerCase<T extends string>(str: T): Lowercase<T>;
export { escapeHTML, randomId, strToBool, getStyle, padZeros, roundSignif, parseDate, formatDateUTC, makeResizeFilter, pixelRatio, scopeExprToFunc, asArray, mergeSort, $escape, mapValues, isnan, _equal, equal, compareVersion, updateLabel, getComputedLinkColor, hasOwnProperty, hasDefinedProperty, isBS3, toLowerCase, };
export { escapeHTML, randomId, strToBool, getStyle, padZeros, roundSignif, parseDate, formatDateUTC, makeResizeFilter, pixelRatio, getBoundingClientSizeBeforeZoom, scopeExprToFunc, asArray, mergeSort, $escape, mapValues, isnan, _equal, equal, compareVersion, updateLabel, getComputedLinkColor, hasOwnProperty, hasDefinedProperty, isBS3, toLowerCase, };