mirror of
https://github.com/finos/SymphonyElectron.git
synced 2025-02-25 18:55:29 -06:00
feat: SDA-2705 Add possibility for panning
This commit is contained in:
parent
94eb41719b
commit
e18b431c98
@ -1,29 +1,50 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`<AnnotateArea/> should render correctly 1`] = `
|
exports[`<AnnotateArea/> should render correctly 1`] = `
|
||||||
<svg
|
<AnnotateArea
|
||||||
data-testid="annotate-area"
|
annotateAreaDimensions={
|
||||||
height={800}
|
|
||||||
id="annotate-area"
|
|
||||||
onMouseDown={[Function]}
|
|
||||||
onMouseLeave={[Function]}
|
|
||||||
onMouseMove={[Function]}
|
|
||||||
onMouseUp={[Function]}
|
|
||||||
style={
|
|
||||||
Object {
|
Object {
|
||||||
"cursor": "crosshair",
|
"height": 800,
|
||||||
|
"width": 800,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width={800}
|
chosenTool="PEN"
|
||||||
|
highlightColor="rgba(233, 0, 0, 0.64)"
|
||||||
|
imageDimensions={
|
||||||
|
Object {
|
||||||
|
"height": 800,
|
||||||
|
"width": 800,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onChange={[MockFunction]}
|
||||||
|
paths={Array []}
|
||||||
|
penColor="rgba(38, 196, 58, 1)"
|
||||||
|
screenSnippetPath="very-nice-path"
|
||||||
>
|
>
|
||||||
<image
|
<div
|
||||||
className="SnippetImage"
|
id="annotate-wrapper"
|
||||||
height={800}
|
style={
|
||||||
id="screenSnippet"
|
Object {
|
||||||
width={800}
|
"height": 800,
|
||||||
x={0}
|
"width": 800,
|
||||||
xlinkHref="very-nice-path"
|
}
|
||||||
y={0}
|
}
|
||||||
/>
|
>
|
||||||
</svg>
|
<svg
|
||||||
|
data-testid="annotate-area"
|
||||||
|
height={800}
|
||||||
|
id="annotate-area"
|
||||||
|
onMouseDown={[Function]}
|
||||||
|
onMouseLeave={[Function]}
|
||||||
|
onMouseMove={[Function]}
|
||||||
|
onMouseUp={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"cursor": "crosshair",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
width={800}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</AnnotateArea>
|
||||||
`;
|
`;
|
||||||
|
@ -62,20 +62,27 @@ exports[`Snipping Tool should render correctly 1`] = `
|
|||||||
className="imageContainer"
|
className="imageContainer"
|
||||||
>
|
>
|
||||||
<AnnotateArea
|
<AnnotateArea
|
||||||
|
annotateAreaDimensions={
|
||||||
|
Object {
|
||||||
|
"height": 600,
|
||||||
|
"width": 800,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backgroundImagePath=""
|
||||||
chosenTool="PEN"
|
chosenTool="PEN"
|
||||||
data-testid="annotate-component"
|
data-testid="annotate-component"
|
||||||
highlightColor="rgba(0, 142, 255, 0.64)"
|
highlightColor="rgba(0, 142, 255, 0.64)"
|
||||||
imageDimensions={
|
imageDimensions={
|
||||||
Object {
|
Object {
|
||||||
"height": 600,
|
"height": 600,
|
||||||
"width": 800,
|
"width": 800,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
onChange={[Function]}
|
||||||
onChange={[Function]}
|
paths={Array []}
|
||||||
paths={Array []}
|
penColor="rgba(0, 142, 255, 1)"
|
||||||
penColor="rgba(0, 142, 255, 1)"
|
/>
|
||||||
screenSnippetPath="Screen-Snippet"
|
</div>
|
||||||
/></div>
|
|
||||||
</main>
|
</main>
|
||||||
<footer>
|
<footer>
|
||||||
<button
|
<button
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { shallow } from 'enzyme';
|
import { mount } from 'enzyme';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import AnnotateArea from '../src/renderer/components/annotate-area';
|
import AnnotateArea from '../src/renderer/components/annotate-area';
|
||||||
import { Tool } from '../src/renderer/components/snipping-tool';
|
import { Tool } from '../src/renderer/components/snipping-tool';
|
||||||
@ -9,6 +9,7 @@ const defaultProps = {
|
|||||||
penColor: 'rgba(38, 196, 58, 1)',
|
penColor: 'rgba(38, 196, 58, 1)',
|
||||||
onChange: jest.fn(),
|
onChange: jest.fn(),
|
||||||
imageDimensions: { width: 800, height: 800 },
|
imageDimensions: { width: 800, height: 800 },
|
||||||
|
annotateAreaDimensions: { width: 800, height: 800 },
|
||||||
chosenTool: Tool.pen,
|
chosenTool: Tool.pen,
|
||||||
screenSnippetPath: 'very-nice-path',
|
screenSnippetPath: 'very-nice-path',
|
||||||
};
|
};
|
||||||
@ -19,25 +20,27 @@ afterEach(() => {
|
|||||||
|
|
||||||
describe('<AnnotateArea/>', () => {
|
describe('<AnnotateArea/>', () => {
|
||||||
it('should render correctly', () => {
|
it('should render correctly', () => {
|
||||||
const wrapper = shallow(<AnnotateArea {...defaultProps} />);
|
const wrapper = mount(<AnnotateArea {...defaultProps} />);
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call onChange when drawn on annotate area', () => {
|
it('should call onChange when drawn on annotate area', () => {
|
||||||
const wrapper = shallow(<AnnotateArea {...defaultProps} />);
|
const wrapper = mount(<AnnotateArea {...defaultProps} />);
|
||||||
wrapper.simulate('mousedown', { pageX: 2, pageY: 49 });
|
const area = wrapper.find('[data-testid="annotate-area"]');
|
||||||
wrapper.simulate('mouseup');
|
area.simulate('mousedown', { pageX: 2, pageY: 49 });
|
||||||
|
area.simulate('mouseup');
|
||||||
expect(defaultProps.onChange).toHaveBeenCalledTimes(1);
|
expect(defaultProps.onChange).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call onChange with correct pen props if drawn drawn on annotate area with pen', () => {
|
it('should call onChange with correct pen props if drawn drawn on annotate area with pen', () => {
|
||||||
const wrapper = shallow(<AnnotateArea {...defaultProps} />);
|
const wrapper = mount(<AnnotateArea {...defaultProps} />);
|
||||||
wrapper.simulate('mousedown', { pageX: 2, pageY: 49 });
|
const area = wrapper.find('[data-testid="annotate-area"]');
|
||||||
wrapper.simulate('mouseup');
|
area.simulate('mousedown', { pageX: 2, pageY: 49 });
|
||||||
|
area.simulate('mouseup');
|
||||||
expect(defaultProps.onChange).toHaveBeenCalledWith([{
|
expect(defaultProps.onChange).toHaveBeenCalledWith([{
|
||||||
color: 'rgba(38, 196, 58, 1)',
|
color: 'rgba(38, 196, 58, 1)',
|
||||||
key: 'path0',
|
key: 'path0',
|
||||||
points: [{ x: 2, y: 1 }],
|
points: [{ x: 0, y: 0 }],
|
||||||
shouldShow: true,
|
shouldShow: true,
|
||||||
strokeWidth: 5,
|
strokeWidth: 5,
|
||||||
}]);
|
}]);
|
||||||
@ -50,12 +53,14 @@ describe('<AnnotateArea/>', () => {
|
|||||||
penColor: 'rgba(38, 196, 58, 1)',
|
penColor: 'rgba(38, 196, 58, 1)',
|
||||||
onChange: jest.fn(),
|
onChange: jest.fn(),
|
||||||
imageDimensions: { width: 800, height: 800 },
|
imageDimensions: { width: 800, height: 800 },
|
||||||
|
annotateAreaDimensions: { width: 800, height: 800 },
|
||||||
chosenTool: Tool.highlight,
|
chosenTool: Tool.highlight,
|
||||||
screenSnippetPath: 'very-nice-path',
|
screenSnippetPath: 'very-nice-path',
|
||||||
};
|
};
|
||||||
const wrapper = shallow(<AnnotateArea {...highlightProps} />);
|
const wrapper = mount(<AnnotateArea {...highlightProps} />);
|
||||||
wrapper.simulate('mousedown', { pageX: 2, pageY: 49 });
|
const area = wrapper.find('[data-testid="annotate-area"]');
|
||||||
wrapper.simulate('mouseup');
|
area.simulate('mousedown', { pageX: 2, pageY: 49 });
|
||||||
|
area.simulate('mouseup');
|
||||||
expect(highlightProps.onChange).toHaveBeenCalledWith([{
|
expect(highlightProps.onChange).toHaveBeenCalledWith([{
|
||||||
color: 'rgba(233, 0, 0, 0.64)',
|
color: 'rgba(233, 0, 0, 0.64)',
|
||||||
key: 'path0',
|
key: 'path0',
|
||||||
@ -78,15 +83,16 @@ describe('<AnnotateArea/>', () => {
|
|||||||
penColor: 'rgba(38, 196, 58, 1)',
|
penColor: 'rgba(38, 196, 58, 1)',
|
||||||
onChange: jest.fn(),
|
onChange: jest.fn(),
|
||||||
imageDimensions: { width: 800, height: 800 },
|
imageDimensions: { width: 800, height: 800 },
|
||||||
|
annotateAreaDimensions: { width: 800, height: 800 },
|
||||||
chosenTool: Tool.highlight,
|
chosenTool: Tool.highlight,
|
||||||
screenSnippetPath: 'very-nice-path',
|
screenSnippetPath: 'very-nice-path',
|
||||||
};
|
};
|
||||||
const wrapper = shallow(<AnnotateArea {...pathProps} />);
|
const wrapper = mount(<AnnotateArea {...pathProps} />);
|
||||||
expect(wrapper.find('[data-testid="path0"]').exists()).toEqual(true);
|
expect(wrapper.find('[data-testid="path0"]').exists()).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not render any path if no path is provided in props', () => {
|
it('should not render any path if no path is provided in props', () => {
|
||||||
const wrapper = shallow(<AnnotateArea {...defaultProps} />);
|
const wrapper = mount(<AnnotateArea {...defaultProps} />);
|
||||||
expect(wrapper.find('[data-testid="path0"]').exists()).toEqual(false);
|
expect(wrapper.find('[data-testid="path0"]').exists()).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -103,10 +109,11 @@ describe('<AnnotateArea/>', () => {
|
|||||||
penColor: 'rgba(38, 196, 58, 1)',
|
penColor: 'rgba(38, 196, 58, 1)',
|
||||||
onChange: jest.fn(),
|
onChange: jest.fn(),
|
||||||
imageDimensions: { width: 800, height: 800 },
|
imageDimensions: { width: 800, height: 800 },
|
||||||
|
annotateAreaDimensions: { width: 800, height: 800 },
|
||||||
chosenTool: Tool.eraser,
|
chosenTool: Tool.eraser,
|
||||||
screenSnippetPath: 'very-nice-path',
|
screenSnippetPath: 'very-nice-path',
|
||||||
};
|
};
|
||||||
const wrapper = shallow(<AnnotateArea {...pathProps} />);
|
const wrapper = mount(<AnnotateArea {...pathProps} />);
|
||||||
const path = wrapper.find('[data-testid="path0"]');
|
const path = wrapper.find('[data-testid="path0"]');
|
||||||
path.simulate('click');
|
path.simulate('click');
|
||||||
expect(pathProps.onChange).toHaveBeenCalledWith([{
|
expect(pathProps.onChange).toHaveBeenCalledWith([{
|
||||||
|
@ -13,7 +13,7 @@ describe('Snipping Tool', () => {
|
|||||||
|
|
||||||
it('should set up a "once" listener for snipping-tool-data event on mounting', () => {
|
it('should set up a "once" listener for snipping-tool-data event on mounting', () => {
|
||||||
const spy = jest.spyOn(ipcRenderer, 'once');
|
const spy = jest.spyOn(ipcRenderer, 'once');
|
||||||
shallow(React.createElement(SnippingTool));
|
mount(React.createElement(SnippingTool));
|
||||||
expect(spy).toBeCalledWith('snipping-tool-data', expect.any(Function));
|
expect(spy).toBeCalledWith('snipping-tool-data', expect.any(Function));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ describe('Snipping Tool', () => {
|
|||||||
await waitForPromisesToResolve();
|
await waitForPromisesToResolve();
|
||||||
expect(spy).toBeCalledWith('upload-snippet', {
|
expect(spy).toBeCalledWith('upload-snippet', {
|
||||||
base64PngData: 'NO CANVAS',
|
base64PngData: 'NO CANVAS',
|
||||||
screenSnippetPath: 'Screen-Snippet',
|
screenSnippetPath: '',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -963,8 +963,10 @@ export class WindowHandler {
|
|||||||
const MIN_WIDTH = 320;
|
const MIN_WIDTH = 320;
|
||||||
const CONTAINER_HEIGHT = 175;
|
const CONTAINER_HEIGHT = 175;
|
||||||
const OS_PADDING = 25;
|
const OS_PADDING = 25;
|
||||||
let height: number = dimensions?.height || 0;
|
const snippetImageHeight = dimensions?.height || 0;
|
||||||
let width: number = dimensions?.width || 0;
|
const snippetImageWidth = dimensions?.width || 0;
|
||||||
|
let annotateAreaHeight = snippetImageHeight;
|
||||||
|
let annotateAreaWidth = snippetImageWidth;
|
||||||
|
|
||||||
if (parentWindow) {
|
if (parentWindow) {
|
||||||
const { bounds: { height: sHeight, width: sWidth } } = electron.screen.getDisplayMatching(parentWindow.getBounds());
|
const { bounds: { height: sHeight, width: sWidth } } = electron.screen.getDisplayMatching(parentWindow.getBounds());
|
||||||
@ -972,24 +974,24 @@ export class WindowHandler {
|
|||||||
// This calculation is to make sure the
|
// This calculation is to make sure the
|
||||||
// snippet window does not cover the entire screen
|
// snippet window does not cover the entire screen
|
||||||
const maxScreenHeight: number = calculatePercentage(sHeight, 90);
|
const maxScreenHeight: number = calculatePercentage(sHeight, 90);
|
||||||
if (height > maxScreenHeight) {
|
if (annotateAreaHeight > maxScreenHeight) {
|
||||||
height = maxScreenHeight;
|
annotateAreaHeight = maxScreenHeight;
|
||||||
}
|
}
|
||||||
const maxScreenWidth: number = calculatePercentage(sWidth, 90);
|
const maxScreenWidth: number = calculatePercentage(sWidth, 90);
|
||||||
if (width > maxScreenWidth) {
|
if (annotateAreaWidth > maxScreenWidth) {
|
||||||
width = maxScreenWidth;
|
annotateAreaWidth = maxScreenWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
// decrease image height when there is no space for the container window
|
// decrease image height when there is no space for the container window
|
||||||
if ((sHeight - height) < CONTAINER_HEIGHT) {
|
if ((sHeight - annotateAreaHeight) < CONTAINER_HEIGHT) {
|
||||||
height -= CONTAINER_HEIGHT;
|
annotateAreaHeight -= CONTAINER_HEIGHT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const windowHeight = height + CONTAINER_HEIGHT - OS_PADDING;
|
const windowHeight = annotateAreaHeight + CONTAINER_HEIGHT - OS_PADDING;
|
||||||
|
|
||||||
const opts: ICustomBrowserWindowConstructorOpts = this.getWindowOpts(
|
const opts: ICustomBrowserWindowConstructorOpts = this.getWindowOpts(
|
||||||
{
|
{
|
||||||
width,
|
width: annotateAreaWidth,
|
||||||
height: windowHeight,
|
height: windowHeight,
|
||||||
minHeight: MIN_HEIGHT,
|
minHeight: MIN_HEIGHT,
|
||||||
minWidth: MIN_WIDTH,
|
minWidth: MIN_WIDTH,
|
||||||
@ -1022,8 +1024,10 @@ export class WindowHandler {
|
|||||||
this.snippingToolWindow.webContents.once('did-finish-load', async () => {
|
this.snippingToolWindow.webContents.once('did-finish-load', async () => {
|
||||||
const snippingToolInfo = {
|
const snippingToolInfo = {
|
||||||
snipImage,
|
snipImage,
|
||||||
height,
|
annotateAreaHeight,
|
||||||
width,
|
annotateAreaWidth,
|
||||||
|
snippetImageHeight,
|
||||||
|
snippetImageWidth,
|
||||||
};
|
};
|
||||||
if (this.snippingToolWindow && windowExists(this.snippingToolWindow)) {
|
if (this.snippingToolWindow && windowExists(this.snippingToolWindow)) {
|
||||||
this.snippingToolWindow.webContents.send(
|
this.snippingToolWindow.webContents.send(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { LazyBrush } from 'lazy-brush';
|
import { LazyBrush } from 'lazy-brush';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { IImageDimensions, IPath, IPoint, Tool } from './snipping-tool';
|
import { IDimensions, IPath, IPoint, Tool } from './snipping-tool';
|
||||||
|
|
||||||
const { useState } = React;
|
const { useState } = React;
|
||||||
|
|
||||||
@ -17,9 +17,10 @@ export interface IAnnotateAreaProps {
|
|||||||
highlightColor: string;
|
highlightColor: string;
|
||||||
penColor: string;
|
penColor: string;
|
||||||
onChange: (paths: IPath[]) => void;
|
onChange: (paths: IPath[]) => void;
|
||||||
imageDimensions: IImageDimensions;
|
imageDimensions: IDimensions;
|
||||||
|
annotateAreaDimensions: IDimensions;
|
||||||
chosenTool: Tool;
|
chosenTool: Tool;
|
||||||
screenSnippetPath: string;
|
backgroundImagePath?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lazy = new LazyBrush({
|
const lazy = new LazyBrush({
|
||||||
@ -27,9 +28,6 @@ const lazy = new LazyBrush({
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
initialPoint: { x: 0, y: 0 },
|
initialPoint: { x: 0, y: 0 },
|
||||||
});
|
});
|
||||||
const TOP_MENU_HEIGHT = 48;
|
|
||||||
const MIN_ANNOTATE_AREA_HEIGHT = 200;
|
|
||||||
const MIN_ANNOTATE_AREA_WIDTH = 312;
|
|
||||||
const PEN_WIDTH = 5;
|
const PEN_WIDTH = 5;
|
||||||
const HIGHLIGHT_WIDTH = 28;
|
const HIGHLIGHT_WIDTH = 28;
|
||||||
|
|
||||||
@ -40,7 +38,8 @@ const AnnotateArea: React.FunctionComponent<IAnnotateAreaProps> = ({
|
|||||||
onChange,
|
onChange,
|
||||||
imageDimensions,
|
imageDimensions,
|
||||||
chosenTool,
|
chosenTool,
|
||||||
screenSnippetPath,
|
backgroundImagePath,
|
||||||
|
annotateAreaDimensions,
|
||||||
}) => {
|
}) => {
|
||||||
const [isDrawing, setIsDrawing] = useState(false);
|
const [isDrawing, setIsDrawing] = useState(false);
|
||||||
|
|
||||||
@ -66,10 +65,19 @@ const AnnotateArea: React.FunctionComponent<IAnnotateAreaProps> = ({
|
|||||||
// Utility functions
|
// Utility functions
|
||||||
|
|
||||||
const getMousePosition = (e: React.MouseEvent) => {
|
const getMousePosition = (e: React.MouseEvent) => {
|
||||||
// We need to offset for elements in the window that is not the annotate area
|
const target = document.getElementById('annotate-area');
|
||||||
const x = imageDimensions.width >= MIN_ANNOTATE_AREA_WIDTH ? e.pageX : e.pageX - (MIN_ANNOTATE_AREA_WIDTH - imageDimensions.width) / 2;
|
if (target) {
|
||||||
const y = imageDimensions.height >= MIN_ANNOTATE_AREA_HEIGHT ? (e.pageY - TOP_MENU_HEIGHT) : (e.pageY - ((MIN_ANNOTATE_AREA_HEIGHT - imageDimensions.height) / 2) - TOP_MENU_HEIGHT);
|
const rect = target.getBoundingClientRect();
|
||||||
return { x, y };
|
// Offseting the scrolled X and Y inside the annotate area
|
||||||
|
return {
|
||||||
|
x: e.clientX - rect.left,
|
||||||
|
y: e.clientY - rect.top,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
x: e.clientX,
|
||||||
|
y: e.clientY,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Render and preparing render functions
|
// Render and preparing render functions
|
||||||
@ -113,12 +121,12 @@ const AnnotateArea: React.FunctionComponent<IAnnotateAreaProps> = ({
|
|||||||
const addPathPoint = (e: React.MouseEvent) => {
|
const addPathPoint = (e: React.MouseEvent) => {
|
||||||
const p = [...paths];
|
const p = [...paths];
|
||||||
const mousePos: IPoint = getMousePosition(e);
|
const mousePos: IPoint = getMousePosition(e);
|
||||||
|
lazy.update({ x: mousePos.x, y: mousePos.y });
|
||||||
|
const point: IPoint = lazy.getBrushCoordinates();
|
||||||
if (chosenTool === Tool.highlight) {
|
if (chosenTool === Tool.highlight) {
|
||||||
lazy.update({ x: mousePos.x, y: mousePos.y });
|
|
||||||
const point: IPoint = lazy.getBrushCoordinates();
|
|
||||||
onChange(addHighlightPoint(p, point));
|
onChange(addHighlightPoint(p, point));
|
||||||
} else {
|
} else {
|
||||||
onChange(addPenPoint(p, mousePos));
|
onChange(addPenPoint(p, point));
|
||||||
}
|
}
|
||||||
if (!isDrawing) {
|
if (!isDrawing) {
|
||||||
setIsDrawing(true);
|
setIsDrawing(true);
|
||||||
@ -216,29 +224,46 @@ const AnnotateArea: React.FunctionComponent<IAnnotateAreaProps> = ({
|
|||||||
addPathPoint(e);
|
addPathPoint(e);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getAnnotateWrapperStyle = () => {
|
||||||
|
const shouldShowScrollBars =
|
||||||
|
imageDimensions.height > annotateAreaDimensions.height ||
|
||||||
|
imageDimensions.width > annotateAreaDimensions.width;
|
||||||
|
return {
|
||||||
|
width: annotateAreaDimensions.width,
|
||||||
|
height: annotateAreaDimensions.height,
|
||||||
|
...(shouldShowScrollBars && { overflow: 'scroll' }),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<svg
|
<div
|
||||||
data-testid='annotate-area'
|
id='annotate-wrapper'
|
||||||
style={{ cursor: 'crosshair' }}
|
style={getAnnotateWrapperStyle()}>
|
||||||
id='annotate-area'
|
<svg
|
||||||
width={imageDimensions.width}
|
data-testid='annotate-area'
|
||||||
height={imageDimensions.height}
|
style={{ cursor: 'crosshair' }}
|
||||||
onMouseDown={handleMouseDown}
|
id='annotate-area'
|
||||||
onMouseUp={stopDrawing}
|
|
||||||
onMouseMove={handleMouseMove}
|
|
||||||
onMouseLeave={stopDrawing}
|
|
||||||
>
|
|
||||||
<image
|
|
||||||
x={0}
|
|
||||||
y={0}
|
|
||||||
id='screenSnippet'
|
|
||||||
xlinkHref={screenSnippetPath}
|
|
||||||
width={imageDimensions.width}
|
width={imageDimensions.width}
|
||||||
height={imageDimensions.height}
|
height={imageDimensions.height}
|
||||||
className='SnippetImage'
|
onMouseDown={handleMouseDown}
|
||||||
/>
|
onMouseUp={stopDrawing}
|
||||||
{renderPaths(getSvgPathsData(paths))}
|
onMouseMove={handleMouseMove}
|
||||||
</svg>
|
onMouseLeave={stopDrawing}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
backgroundImagePath &&
|
||||||
|
<image
|
||||||
|
x={0}
|
||||||
|
y={0}
|
||||||
|
id='backgroundImage'
|
||||||
|
xlinkHref={backgroundImagePath}
|
||||||
|
width={imageDimensions.width}
|
||||||
|
height={imageDimensions.height}
|
||||||
|
/>}
|
||||||
|
{renderPaths(getSvgPathsData(paths))}
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { i18n } from '../../common/i18n-preload';
|
|||||||
import AnnotateArea from './annotate-area';
|
import AnnotateArea from './annotate-area';
|
||||||
import ColorPickerPill, { IColor } from './color-picker-pill';
|
import ColorPickerPill, { IColor } from './color-picker-pill';
|
||||||
|
|
||||||
const { useState, useRef, useEffect } = React;
|
const { useState, useRef, useEffect, useLayoutEffect } = React;
|
||||||
|
|
||||||
export enum Tool {
|
export enum Tool {
|
||||||
pen = 'PEN',
|
pen = 'PEN',
|
||||||
@ -25,15 +25,7 @@ export interface IPoint {
|
|||||||
y: number;
|
y: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISvgPath {
|
export interface IDimensions {
|
||||||
svgPath: string;
|
|
||||||
key: string;
|
|
||||||
strokeWidth: number;
|
|
||||||
color: string;
|
|
||||||
shouldShow: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IImageDimensions {
|
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
}
|
}
|
||||||
@ -60,11 +52,15 @@ const SNIPPING_TOOL_NAMESPACE = 'ScreenSnippet';
|
|||||||
const SnippingTool: React.FunctionComponent<ISnippingToolProps> = ({ existingPaths }) => {
|
const SnippingTool: React.FunctionComponent<ISnippingToolProps> = ({ existingPaths }) => {
|
||||||
// State preparation functions
|
// State preparation functions
|
||||||
|
|
||||||
const [screenSnippetPath, setScreenSnippetPath] = useState('Screen-Snippet');
|
const [screenSnippetPath, setScreenSnippetPath] = useState('');
|
||||||
const [imageDimensions, setImageDimensions] = useState({
|
const [imageDimensions, setImageDimensions] = useState({
|
||||||
height: 600,
|
height: 600,
|
||||||
width: 800,
|
width: 800,
|
||||||
});
|
});
|
||||||
|
const [annotateAreaDimensions, setAnnotateAreaDimensions] = useState({
|
||||||
|
height: 600,
|
||||||
|
width: 800,
|
||||||
|
});
|
||||||
const [paths, setPaths] = useState<IPath[]>(existingPaths || []);
|
const [paths, setPaths] = useState<IPath[]>(existingPaths || []);
|
||||||
const [chosenTool, setChosenTool] = useState(Tool.pen);
|
const [chosenTool, setChosenTool] = useState(Tool.pen);
|
||||||
const [penColor, setPenColor] = useState<IColor>({ rgbaColor: 'rgba(0, 142, 255, 1)' });
|
const [penColor, setPenColor] = useState<IColor>({ rgbaColor: 'rgba(0, 142, 255, 1)' });
|
||||||
@ -79,12 +75,24 @@ const SnippingTool: React.FunctionComponent<ISnippingToolProps> = ({ existingPat
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
const getSnipImageData = ({ }, { snipImage, height, width }) => {
|
const getSnipImageData = ({ }, {
|
||||||
|
snipImage,
|
||||||
|
annotateAreaHeight,
|
||||||
|
annotateAreaWidth,
|
||||||
|
snippetImageHeight,
|
||||||
|
snippetImageWidth,
|
||||||
|
}) => {
|
||||||
setScreenSnippetPath(snipImage);
|
setScreenSnippetPath(snipImage);
|
||||||
setImageDimensions({ height, width });
|
setImageDimensions({ height: snippetImageHeight, width: snippetImageWidth });
|
||||||
|
setAnnotateAreaDimensions({ height: annotateAreaHeight, width: annotateAreaWidth });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
ipcRenderer.once('snipping-tool-data', getSnipImageData);
|
ipcRenderer.once('snipping-tool-data', getSnipImageData);
|
||||||
|
return () => {
|
||||||
|
ipcRenderer.removeListener('snipping-tool-data', getSnipImageData);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Hook that alerts clicks outside of the passed refs
|
// Hook that alerts clicks outside of the passed refs
|
||||||
const useClickOutsideExaminer = (
|
const useClickOutsideExaminer = (
|
||||||
@ -179,12 +187,12 @@ const SnippingTool: React.FunctionComponent<ISnippingToolProps> = ({ existingPat
|
|||||||
'src',
|
'src',
|
||||||
'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svgData))),
|
'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svgData))),
|
||||||
);
|
);
|
||||||
const screenSnippet = document.getElementById('screenSnippet') as HTMLImageElement;
|
const backgroundImage = document.getElementById('backgroundImage') as HTMLImageElement;
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// Listens to when the img is loaded in memory and adds the data from the SVG paths + screenSnippet to the canvas
|
// Listens to when the img is loaded in memory and adds the data from the SVG paths + screenSnippet to the canvas
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
ctx.drawImage(screenSnippet, 0, 0);
|
ctx.drawImage(backgroundImage, 0, 0);
|
||||||
ctx.drawImage(img, 0, 0);
|
ctx.drawImage(img, 0, 0);
|
||||||
try {
|
try {
|
||||||
// Extracts base 64 png img data from the canvas
|
// Extracts base 64 png img data from the canvas
|
||||||
@ -310,8 +318,9 @@ const SnippingTool: React.FunctionComponent<ISnippingToolProps> = ({ existingPat
|
|||||||
penColor={penColor.rgbaColor}
|
penColor={penColor.rgbaColor}
|
||||||
onChange={setPaths}
|
onChange={setPaths}
|
||||||
imageDimensions={imageDimensions}
|
imageDimensions={imageDimensions}
|
||||||
screenSnippetPath={screenSnippetPath}
|
backgroundImagePath={screenSnippetPath}
|
||||||
chosenTool={chosenTool}
|
chosenTool={chosenTool}
|
||||||
|
annotateAreaDimensions={annotateAreaDimensions}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
@ -4,10 +4,6 @@
|
|||||||
@version-text-color: rgb(47, 47, 47, 1);
|
@version-text-color: rgb(47, 47, 47, 1);
|
||||||
@text-padding: 10px;
|
@text-padding: 10px;
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user