Skip to content

Commit

Permalink
fix(potentiometer): broken in Firefox
Browse files Browse the repository at this point in the history
see #133
  • Loading branch information
urish committed Jul 25, 2022
1 parent 46cf4df commit 1847655
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 4 deletions.
8 changes: 4 additions & 4 deletions src/potentiometer-element.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export default {
component: 'wokwi-potentiometer',
};

const Template = ({ degrees = 0, zoom = 1 }) => html`
<span style="transform: rotate(${degrees}deg); zoom: ${zoom}; display: inline-block;">
const Template = ({ transform = '' }) => html`
<span style="transform: ${transform}; display: inline-block;">
<wokwi-potentiometer @input=${action('input')} />
</span>
`;
Expand All @@ -17,7 +17,7 @@ export const Default = Template.bind({});
Default.args = {};

export const Rotated = Template.bind({});
Rotated.args = { ...Default.args, degrees: 90 };
Rotated.args = { ...Default.args, transform: 'rotate(90deg)' };

export const Zoomed = Template.bind({});
Zoomed.args = { ...Default.args, zoom: 1.5 };
Zoomed.args = { ...Default.args, transform: 'translate(25px, 25px) scale(1.5)' };
35 changes: 35 additions & 0 deletions src/potentiometer-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { customElement, property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { analog, ElementPin } from './pin';
import { clamp } from './utils/clamp';
import { calculateBoundingRect } from './utils/geometry';

const knobCenter = {
x: 9.91,
Expand Down Expand Up @@ -152,6 +153,7 @@ export class PotentiometerElement extends LitElement {
</g>
<ellipse cx="9.95" cy="8.06" rx="6.60" ry="6.58" fill="#c3c2c3" stroke-width=".15" />
<rect id="rotating" x="10" y="2" width=".42" height="3.1" stroke-width=".15" />
<rect x="0" y="9.5" width="1" height="1" fill="none" id="firefox-workaround" />
</svg>
`;
}
Expand Down Expand Up @@ -192,6 +194,39 @@ export class PotentiometerElement extends LitElement {
private updateKnobMatrix() {
const knob = this.shadowRoot?.querySelector<SVGRectElement>('#knob');
this.pageToKnobMatrix = knob?.getScreenCTM()?.inverse() ?? null;

if (navigator.userAgent.indexOf('Firefox') >= 0) {
// Firefox's getScreenCTM() is broken: https://bugzilla.mozilla.org/show_bug.cgi?id=1610093
const firefoxWorkaround =
this.shadowRoot?.querySelector<SVGRectElement>('#firefox-workaround');
const boundingRect = firefoxWorkaround?.getBoundingClientRect();
const svgRect = firefoxWorkaround?.ownerSVGElement?.getBoundingClientRect();
if (!boundingRect || !svgRect) {
return;
}

const cx = svgRect.x + svgRect.width / 2;
const cy = svgRect.y + svgRect.height / 2;
const deltaX = cx - (boundingRect.x + boundingRect.width / 2);
const deltaY = cy - (boundingRect.y + boundingRect.height / 2);
const angle = (Math.atan2(deltaY, deltaX) / Math.PI) * 180;
const rotation = new DOMMatrix().rotate(angle);
const rotatedRect = calculateBoundingRect(new DOMRect(0, 9.5, 1, 1), rotation);
const sx = rotatedRect.width / boundingRect.width;
const sy = rotatedRect.height / boundingRect.height;
this.pageToKnobMatrix = rotation
.inverse()
.multiply(
new DOMMatrix([
sx,
0,
0,
sy,
rotatedRect.left - boundingRect.left * sx,
rotatedRect.top - boundingRect.top * sy,
])
);
}
}

private rotateHandler(event: MouseEvent | TouchEvent) {
Expand Down
11 changes: 11 additions & 0 deletions src/utils/geometry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export function calculateBoundingRect(rect: DOMRect, transform: DOMMatrix) {
const topLeft = transform.transformPoint({ x: rect.left, y: rect.top });
const topRight = transform.transformPoint({ x: rect.right, y: rect.top });
const bottomLeft = transform.transformPoint({ x: rect.left, y: rect.bottom });
const bottomRight = transform.transformPoint({ x: rect.right, y: rect.bottom });
const minX = Math.min(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x);
const minY = Math.min(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y);
const maxX = Math.max(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x);
const maxY = Math.max(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y);
return new DOMRect(minX, minY, maxX - minX, maxY - minY);
}

0 comments on commit 1847655

Please sign in to comment.