Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: align cover svg to viewer #167

Merged
merged 5 commits into from
Jan 5, 2020
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
3 changes: 2 additions & 1 deletion docs/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ import {
ALIGN_RIGHT,
ALIGN_TOP,
ALIGN_BOTTOM,

ALIGN_COVER,

INITIAL_VALUE
} from 'react-svg-pan-zoom'
```
Expand Down
1 change: 1 addition & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ export const ALIGN_LEFT = 'left';
export const ALIGN_RIGHT = 'right';
export const ALIGN_TOP = 'top';
export const ALIGN_BOTTOM = 'bottom';
export const ALIGN_COVER = 'cover';

export const INITIAL_VALUE = {}
29 changes: 23 additions & 6 deletions src/features/zoom.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {fromObject, scale, transform, translate} from 'transformation-matrix';

import {
ACTION_ZOOM, MODE_IDLE, MODE_ZOOMING,
ALIGN_CENTER, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_TOP, ALIGN_BOTTOM
ALIGN_CENTER, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_TOP, ALIGN_BOTTOM, ALIGN_COVER
} from '../constants';
import {decompose, getSVGPoint, set} from './common';
import calculateBox from '../utils/calculateBox';
Expand Down Expand Up @@ -101,15 +101,16 @@ export function fitToViewer(value, SVGAlignX=ALIGN_LEFT, SVGAlignY=ALIGN_TOP) {
let scaleY = viewerHeight / SVGHeight;
let scaleLevel = Math.min(scaleX, scaleY);

const scaleMatrix = scale(scaleLevel, scaleLevel);
let scaleMatrix = scale(scaleLevel, scaleLevel);

let translateX = -SVGMinX * scaleX;
let translateY = -SVGMinY * scaleY;

// after fitting, SVG and the viewer will match in width (1) or in height (2)
if (scaleX < scaleY) {
//(1) match in width, meaning scaled SVGHeight <= viewerHeight
// after fitting, SVG and the viewer will match in width (1) or in height (2) or SVG will cover the container with preserving aspect ratio (0)
if (scaleX < scaleY) {
let remainderY = viewerHeight - scaleX * SVGHeight;

//(1) match in width, meaning scaled SVGHeight <= viewerHeight
switch(SVGAlignY) {
case ALIGN_TOP:
translateY = -SVGMinY * scaleLevel;
Expand All @@ -123,12 +124,20 @@ export function fitToViewer(value, SVGAlignX=ALIGN_LEFT, SVGAlignY=ALIGN_TOP) {
translateY = remainderY - SVGMinY * scaleLevel;
break;

case ALIGN_COVER:
scaleMatrix = scale(scaleY, scaleY); // (0) we must now match to short edge, in this case - height
let remainderX = viewerWidth - scaleY * SVGWidth; // calculate remainder in the other scale

translateX = SVGMinX + Math.round(remainderX / 2); // center by the long edge
break;

default:
//no op
}
} else {
//(2) match in height, meaning scaled SVGWidth <= viewerWidth
let remainderX = viewerWidth - scaleY * SVGWidth;

//(2) match in height, meaning scaled SVGWidth <= viewerWidth
switch(SVGAlignX) {
case ALIGN_LEFT:
translateX = -SVGMinX * scaleLevel;
Expand All @@ -142,12 +151,20 @@ export function fitToViewer(value, SVGAlignX=ALIGN_LEFT, SVGAlignY=ALIGN_TOP) {
translateX = remainderX - SVGMinX * scaleLevel;
break;

case ALIGN_COVER:
scaleMatrix = scale(scaleX, scaleX); // (0) we must now match to short edge, in this case - width
let remainderY = viewerHeight - scaleX * SVGHeight; // calculate remainder in the other scale

translateY = SVGMinY + Math.round(remainderY / 2); // center by the long edge
break;

default:
//no op
}
}

const translationMatrix = translate(translateX, translateY);

const matrix = transform(
translationMatrix, //2
scaleMatrix //1
Expand Down
7 changes: 5 additions & 2 deletions storybook/stories/DifferentSizesStory.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ALIGN_LEFT,
ALIGN_RIGHT,
ALIGN_TOP,
ALIGN_COVER,
UncontrolledReactSVGPanZoom
} from '../../src/index';

Expand Down Expand Up @@ -34,12 +35,14 @@ export default class DifferentSizesStory extends Component {
SVGAlignX: select('toolbarProps.SVGAlignX', {
[ALIGN_LEFT]: ALIGN_LEFT,
[ALIGN_CENTER]: ALIGN_CENTER,
[ALIGN_RIGHT]: ALIGN_RIGHT
[ALIGN_RIGHT]: ALIGN_RIGHT,
[ALIGN_COVER]: ALIGN_COVER,
}, ALIGN_LEFT),
SVGAlignY: select('toolbarProps.SVGAlignY', {
[ALIGN_TOP]: ALIGN_TOP,
[ALIGN_CENTER]: ALIGN_CENTER,
[ALIGN_BOTTOM]: ALIGN_BOTTOM
[ALIGN_BOTTOM]: ALIGN_BOTTOM,
[ALIGN_COVER]: ALIGN_COVER,
}, ALIGN_TOP),
}

Expand Down
31 changes: 30 additions & 1 deletion test/features/zoom.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ALIGN_LEFT,
ALIGN_RIGHT,
ALIGN_TOP,
ALIGN_COVER,
fitSelection,
fitToViewer,
MODE_IDLE,
Expand Down Expand Up @@ -105,7 +106,29 @@ describe("fitSelection", () => {
test.todo('h<w')
})

describe("fitToViewer", () => {
describe("fitToViewer rect > viewer", () => {
test("rect with w>h", () => {
const value = getDefaultValue(
200, 100, //viewer 200x100
0, 0, 400, 400, //svg 400x400
)

const value1 = fitToViewer(value, ALIGN_COVER, ALIGN_COVER)
expect(testSVGBBox(value1)).toEqual([0, -50, 200, 150])
})

test("rect with w<h", () => {
const value = getDefaultValue(
100, 200, //viewer 200x100
0, 0, 400, 400, //svg 400x400
)

const value1 = fitToViewer(value, ALIGN_COVER, ALIGN_COVER)
expect(testSVGBBox(value1)).toEqual([-50, 0, 150, 200])
})
})

describe("fitToViewer rect < viewer", () => {
test("rect with w>h", () => {
const value = getDefaultValue(
200, 100, //viewer 200x100
Expand All @@ -120,6 +143,9 @@ describe("fitToViewer", () => {

const value3 = fitToViewer(value, ALIGN_RIGHT, ALIGN_TOP)
expect(testSVGBBox(value3)).toEqual([100, 0, 200, 100])

const value4 = fitToViewer(value, ALIGN_COVER, ALIGN_COVER)
expect(testSVGBBox(value4)).toEqual([0, -50, 200, 150])
})

test("rect with w<h", () => {
Expand All @@ -136,6 +162,9 @@ describe("fitToViewer", () => {

const value3 = fitToViewer(value, ALIGN_LEFT, ALIGN_BOTTOM)
expect(testSVGBBox(value3)).toEqual([0, 100, 100, 200])

const value4 = fitToViewer(value, ALIGN_COVER, ALIGN_COVER)
expect(testSVGBBox(value4)).toEqual([-50, 0, 150, 200])
})
})

Expand Down