Skip to content
Merged
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
25 changes: 20 additions & 5 deletions bundle/latex2html5.bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -3302,6 +3302,23 @@ var LaTeX2HTML5 = (() => {
}
};
var psgraph = {
/**
* Maps a pointer's client position into the picture's own pixel space. A
* page may draw the svg smaller than its natural size (CSS `zoom` or a
* transform to fit a phone screen), and neither `offsetX` nor a raw
* `clientX - rect.left` accounts for that, so divide out the drawn scale.
* Measuring the svg itself, not the event target, also keeps a pointer over
* a child path from reading coordinates relative to that path.
*/
pointerCoords(svg, clientX, clientY) {
if (!svg) return [0, 0];
const rect = svg.getBoundingClientRect();
const width = parseFloat(svg.getAttribute("width") || "") || rect.width;
const height = parseFloat(svg.getAttribute("height") || "") || rect.height;
const scaleX = rect.width && width ? rect.width / width : 1;
const scaleY = rect.height && height ? rect.height / height : 1;
return [(clientX - rect.left) / scaleX, (clientY - rect.top) / scaleY];
},
env: null,
getSize() {
const padding = 20;
Expand Down Expand Up @@ -3832,16 +3849,14 @@ var LaTeX2HTML5 = (() => {
function(event) {
event.preventDefault();
var touch = event.touches ? event.touches[0] : null;
var rect = event.target.getBoundingClientRect();
var touchcoords = touch ? [touch.clientX - rect.left, touch.clientY - rect.top] : [0, 0];
drawLayer(touchcoords, { pointer: true });
if (!touch) return;
drawLayer(psgraph.pointerCoords(svg.node(), touch.clientX, touch.clientY), { pointer: true });
}
);
svg.on(
"mousemove",
function(event) {
var coords = [event.offsetX || 0, event.offsetY || 0];
drawLayer(coords, { pointer: true });
drawLayer(psgraph.pointerCoords(svg.node(), event.clientX, event.clientY), { pointer: true });
}
);
psgraph.processRputElements.call(this, el);
Expand Down
25 changes: 25 additions & 0 deletions packages/html5/test/pspicture.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,31 @@ describe('pspicture component (SVG rendering)', () => {
expect(shapeOrder(svg)).toEqual(before);
});

it('maps the pointer into picture space when the svg is drawn scaled down', () => {
// A page fitting a 200px picture onto a phone draws it at 100px (CSS zoom
// or a transform). The pointer's screen offset must be divided back out,
// or a dragged vector lands at half the distance from the finger.
const env = parsePspicture(`
\\begin{pspicture}(0,0)(4,4)
\\userline[linewidth=2pt]{->}(0,0)(2,2)
\\end{pspicture}
`);

const div = pspicture(env);
document.body.appendChild(div);
const svg = div.querySelector('svg')!;
const natural = parseFloat(svg.getAttribute('width')!);
svg.getBoundingClientRect = () =>
({ left: 10, top: 20, width: natural / 2, height: natural / 2, right: 0, bottom: 0, x: 10, y: 20 }) as DOMRect;

svg.dispatchEvent(new MouseEvent('mousemove', { bubbles: true, clientX: 10 + natural / 4, clientY: 20 + natural / 8 }));

const d = svg.querySelector('path')!.getAttribute('d')!;
const [x2, y2] = d.trim().split(/[\s,LM]+/).filter(Boolean).slice(-2).map(Number);
expect(x2).toBeCloseTo(natural / 2);
expect(y2).toBeCloseTo(natural / 4);
});

it('renders psdots as small circles', () => {
const env = parsePspicture(`
\\begin{pspicture}(0,0)(4,4)
Expand Down
26 changes: 21 additions & 5 deletions packages/pstricks/src/lib/psgraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,24 @@ class PatchSelection {
}

const psgraph: any = {
/**
* Maps a pointer's client position into the picture's own pixel space. A
* page may draw the svg smaller than its natural size (CSS `zoom` or a
* transform to fit a phone screen), and neither `offsetX` nor a raw
* `clientX - rect.left` accounts for that, so divide out the drawn scale.
* Measuring the svg itself, not the event target, also keeps a pointer over
* a child path from reading coordinates relative to that path.
*/
pointerCoords(svg: Element | null, clientX: number, clientY: number): number[] {
if (!svg) return [0, 0];
const rect = svg.getBoundingClientRect();
const width = parseFloat(svg.getAttribute('width') || '') || rect.width;
const height = parseFloat(svg.getAttribute('height') || '') || rect.height;
const scaleX = rect.width && width ? rect.width / width : 1;
const scaleY = rect.height && height ? rect.height / height : 1;
return [(clientX - rect.left) / scaleX, (clientY - rect.top) / scaleY];
},

env: null as any,
getSize(): { width: number; height: number } {
const padding = 20;
Expand Down Expand Up @@ -1596,17 +1614,15 @@ const psgraph: any = {
function (this: any, event: any) {
event.preventDefault();
var touch = event.touches ? event.touches[0] : null;
var rect = event.target.getBoundingClientRect();
var touchcoords = touch ? [touch.clientX - rect.left, touch.clientY - rect.top] : [0, 0];
drawLayer(touchcoords, { pointer: true });
if (!touch) return;
drawLayer(psgraph.pointerCoords(svg.node(), touch.clientX, touch.clientY), { pointer: true });
}
);

svg.on(
'mousemove',
function (this: any, event: any) {
var coords = [event.offsetX || 0, event.offsetY || 0];
drawLayer(coords, { pointer: true });
drawLayer(psgraph.pointerCoords(svg.node(), event.clientX, event.clientY), { pointer: true });
}
);

Expand Down
7 changes: 2 additions & 5 deletions packages/react/src/components/pspicture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,14 @@ export default (props: PspictureProps) => {
}, [props]);

const handleMouseMove = (event: React.MouseEvent<SVGSVGElement>) => {
const coords = [event.nativeEvent.offsetX || 0, event.nativeEvent.offsetY || 0];
userEventHandler(coords);
userEventHandler(psgraph.pointerCoords(svgRef.current, event.clientX, event.clientY));
};

const handleTouchMove = (event: React.TouchEvent<SVGSVGElement>) => {
event.preventDefault();
const touch = event.touches[0];
if (touch && svgRef.current) {
const rect = svgRef.current.getBoundingClientRect();
const coords = [touch.clientX - rect.left, touch.clientY - rect.top];
userEventHandler(coords);
userEventHandler(psgraph.pointerCoords(svgRef.current, touch.clientX, touch.clientY));
}
};

Expand Down
Loading