Skip to content

Commit

Permalink
Rotate image inside a graph (#1923)
Browse files Browse the repository at this point in the history
  • Loading branch information
dqnykamp authored Feb 27, 2023
1 parent 568adae commit 1cb7601
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 1 deletion.
54 changes: 54 additions & 0 deletions cypress/e2e/DoenetML/tagSpecific/image.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,60 @@ describe('Image Tag Tests', function () {

});

it('rotate image in graph', () => {
cy.window().then(async (win) => {
win.postMessage({
doenetML: `
<text>a</text>
<graph >
<image source="http://mathinsight.org/media/image/image/giant_anteater.jpg" rotate="$rotate1" name="image1" />
</graph>
<p name="pRotate1">Rotate 1: $image1.rotate</p>
<p>Change rotate 1 <mathinput name="rotate1" prefill="pi/4" /></p>
<p>Change rotate 1a <mathinput name="rotate1a" bindValueTo="$image1.rotate" /></p>
<image copySource="image1" name="image1a" />
`}, "*");
});

cy.get('#\\/_text1').should('have.text', 'a') //wait for page to load

// Is there a way to test the rotation of the image in the graph?

cy.get("#\\/pRotate1").should('contain.text', 'Rotate 1: 0.785')


cy.window().then(async (win) => {
let stateVariables = await win.returnAllStateVariables1();
expect(stateVariables["/image1"].stateValues.rotate).eq(Math.PI / 4)
});

cy.log("change rotate")

cy.get('#\\/rotate1 textarea').type("{end}{shift+home}{backspace}3pi/4{enter}", { force: true })

cy.get("#\\/pRotate1").should('contain.text', 'Rotate 1: 2.356')

cy.window().then(async (win) => {
let stateVariables = await win.returnAllStateVariables1();
expect(stateVariables["/image1"].stateValues.rotate).eq(3 * Math.PI / 4)
});

cy.get('#\\/rotate1a textarea').type("{end}{shift+home}{backspace}-pi{enter}", { force: true })

cy.get("#\\/pRotate1").should('contain.text', 'Rotate 1: -3.14159')

cy.window().then(async (win) => {
let stateVariables = await win.returnAllStateVariables1();
expect(stateVariables["/image1"].stateValues.rotate).eq(-Math.PI)
});


});

})


Expand Down
8 changes: 8 additions & 0 deletions src/Core/components/Image.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,14 @@ export default class Image extends BlockComponent {
validValues: ["upperright", "upperleft", "lowerright", "lowerleft", "top", "bottom", "left", "right", "center"]
}

attributes.rotate = {
createComponentOfType: "number",
createStateVariable: "rotate",
defaultValue: 0,
public: true,
forRenderer: true,
}

attributes.styleNumber.defaultValue = 0;

return attributes;
Expand Down
41 changes: 40 additions & 1 deletion src/Viewer/renderers/image.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export default React.memo(function Image(props) {

let currentOffset = useRef(null);

let rotationTransform = useRef(null);
let lastRotate = useRef(SVs.rotate);

const urlOrSource = (SVs.cid ? url : SVs.source) || "";

let onChangeVisibility = isVisible => {
Expand Down Expand Up @@ -70,7 +73,7 @@ export default React.memo(function Image(props) {
visible: !SVs.hidden,
fixed,
layer: 10 * SVs.layer + 0,
highlight: !fixed
highlight: !fixed,
};


Expand Down Expand Up @@ -137,6 +140,33 @@ export default React.memo(function Image(props) {

let newImageJXG = board.create('image', [urlOrSource, offset, [width, height]], jsxImageAttributes);

// tranformation code copied from jsxgraph documentation:
// https://jsxgraph.uni-bayreuth.de/wiki/index.php?title=Images#The_JavaScript_code_5
var tOff = board.create('transform', [
function () {
return -newImageJXG.X() - newImageJXG.W() * 0.5;
}, function () {
return -newImageJXG.Y() - newImageJXG.H() * 0.5;
}
], { type: 'translate' });
var tOffInverse = board.create('transform', [
function () {
return newImageJXG.X() + newImageJXG.W() * 0.5;
}, function () {
return newImageJXG.Y() + newImageJXG.H() * 0.5;
}
], { type: 'translate' });
var tRot = board.create('transform', [
SVs.rotate
], { type: 'rotate' });


tOff.bindTo(newImageJXG); // Shift image to origin
tRot.bindTo(newImageJXG); // Rotate
tOffInverse.bindTo(newImageJXG); // Shift image back

rotationTransform.current = tRot;
lastRotate.current = SVs.rotate;

newImageJXG.on('down', function (e) {
pointerAtDown.current = [e.x, e.y];
Expand Down Expand Up @@ -214,6 +244,9 @@ export default React.memo(function Image(props) {
previousPositionFromAnchor.current = SVs.positionFromAnchor;
currentSize.current = [width, height];

// need fullUpdate to get initial rotation in case image was from a blob
imageJXG.current.fullUpdate();

}

if (board) {
Expand Down Expand Up @@ -289,6 +322,12 @@ export default React.memo(function Image(props) {
currentSize.current = [width, height];
}

if (SVs.rotate != lastRotate.current) {
rotationTransform.current.setMatrix(board, "rotate", [SVs.rotate]);
lastRotate.current = SVs.rotate;
}


if (SVs.positionFromAnchor !== previousPositionFromAnchor.current || sizeChanged) {
let offset;
if (SVs.positionFromAnchor === "center") {
Expand Down

0 comments on commit 1cb7601

Please sign in to comment.