Markup Viewer
Getting Started
Installation
npm i -S @procore/markup-viewer
Importing
import MarkupViewer, {
tools,
EVENT_CONSTANTS,
TRIGGER_CONSTANTS,
} from '@procore/markup-viewer';
Usage
const options = { tools, htmlText: '<div></div>' };
const markupViewer = new MarkupViewer(options);
Creating a new instance of MarkupViewer adds all of the DOM elements needed to display the viewer on the page.
Options[Object
]:
Keys:
- tools[
object
] - pass in the tools that should be available to in the markupViewer
- initialHtmlTextt[
string
] - A valid HTML string, representing the page to be shown
Events
An instance of MarkupViewer exposes the following methods, which ar responsible for all interactions with the markupViewer
.
-
on(eventKey, callback)
-
off(eventKey, callback)
-
trigger(eventKey, callbackArg)
By default, a set of events keys are exported as constants from MarkupViewer
.
TRIGGER_CONSTANTS
- Use these when to tell
markupViewer
what to do.
EVENT_CONSTANTS
- Use these for listening for information from
markupViewer
Every constant in TRIGGER_CONSTANTS
has a pair in EVENT_CONSTANTS
to be used as an acknowledgement or to respond to updated data.
Example
import MarkupViewer, {
tools,
EVENT_CONSTANTS,
TRIGGER_CONSTANTS,
} from '@procore/markup-viewer';
const options = {
tools: {
rect: tools.rect,
},
};
const markupViewer = new MarkupViewer(options);
const rectCB = payload => console.log(payload);
markupViewer.on(EVENT_CONSTANTS.DRAW_COMPLETE, rectCB);
markupViewer.trigger(TRIGGER_CONSTANTS.SET_ACTIVE_TOOL, { toolKey: 'rect' });
Later:
markupViewer.off(EVENT_CONSTANTS.DRAW_COMPLETE, rectCB);
Working with Redux
For convenience, EVENT_CONSTANTS
contains a super-listener for subscribing to all markupViewer
events. When markupViewer is triggered, two events will be broadcast. EVENT_CONSTANTS.MARKUP_VIEWER_EVENTS
will pass an object formatted like a Redux action to the provided callback. The type
will be the specific event, and the payload will be the same payload that would be received for the individual event.
Subscriptions/listeners need to be set up before an event is triggered. When using Redux, it is typically easier to set up a single listener to EVENT_CONSTANTS.MARKUP_VIEWER_EVENT
right when an app starts.
The following is an example of two different options for listening to events:
markupViewer.on(EVENT_CONSTANTS.SELECT_TOOL, payload => console.log(payload));
markupViewer.on(EVENT_CONSTANTS.MARKUP_VIEWER_EVENT, ({ type, payload }) =>
console.log({ type, payload })
);
markupViewer.trigger(TRIGGER_CONSTANTS.SELECT_TOOL, { toolKey: 'rect' });
Tools
The following tools are included to be used out of the box:
- rect
- freehand
- selection
- stamp
You can also create your own tools, either by extending ClickDrag, or by using ClickDrag as a template for your own use case.
When activated, a new instance of a tool is constructed with the following arguments:
- viewer
- events
- options (user-defined)
Attributes
When activated, rect and freehand will respond to the TRIGGER_CONSTANTS.UPDATE_ATTRIBUTES
event:
markupViewer.trigger(TRIGGER_CONSTANTS.UPDATE_ATTRIBUTES, {
fill: '#00FF00',
stroke: '#00FF00',
'fill-opacity': 0.5,
'stroke-width': 4,
});
Example: setting color of shape
import MarkupViewer, { tools, EVENT_CONSTANTS, TRIGGER_CONSTANTS } from '@procore/markup-viewer';
const options = {
tools: {
rect: tools.rect,
},
};
const markupViewer = new MarkupViewer(options);
markupViewer.trigger(TRIGGER_CONSTANTS.SET_ACTIVE_TOOL, {
toolKey: 'rect',
options: {
fill: '#00FF00',
stroke: '#00FF00',
'fill-opacity': 0.5,
'stroke-width': 4,
}
);
markupViewer.trigger(TRIGGER_CONSTANTS.SET_ACTIVE_TOOL, { toolKey: 'rect' });
markupViewer.trigger(TRIGGER_CONSTANTS.UPDATE_ATTRIBUTES, {
fill: '#FF0000',
stroke: '#FF0000',
});
Constants for events
TRIGGER_CONSTANTS
SET_PAGE
import { TRIGGER_CONSTANTS } from '@procore/markup-viewer';
const options = { htmlText: '<div></div>' };
markupViewer.trigger(TRIGGER_CONSTANTS.SET_PAGE, options);
ZOOM_IN
import { TRIGGER_CONSTANTS } from '@procore/markup-viewer';
const zoomAmount = 0.05;
markupViewer.trigger(TRIGGER_CONSTANTS.ZOOM_IN, zoomAmount);
ZOOM_OUT
import { TRIGGER_CONSTANTS } from '@procore/markup-viewer';
const zoomAmount = 0.05;
markupViewer.trigger(TRIGGER_CONSTANTS.ZOOM_OUT, zoomAmount);
RESET_ZOOM
import { TRIGGER_CONSTANTS } from '@procore/markup-viewer';
markupViewer.trigger(TRIGGER_CONSTANTS.RESET_ZOOM);
SET_ACTIVE_TOOL
Rect
import { TRIGGER_CONSTANTS } from '@procore/markup-viewer';
const toolKey = 'rect';
const options = {
fill: '#ff0000',
'fill-opacity': 0.5,
stroke: '#0000ff',
'stroke-opacity': 1,
'stroke-width': 4,
};
markupViewer.trigger(TRIGGER_CONSTANTS.SET_ACTIVE_TOOL, { toolKey, options });
Freehand
import { TRIGGER_CONSTANTS } from '@procore/markup-viewer';
const toolKey = 'freehand';
const options = {
stroke: '#0000ff',
'stroke-opacity': 1,
'stroke-width': 4,
};
markupViewer.trigger(TRIGGER_CONSTANTS.SET_ACTIVE_TOOL, { toolKey, options });
Selection
import { TRIGGER_CONSTANTS } from '@procore/markup-viewer';
const toolKey = 'selection';
markupViewer.trigger(TRIGGER_CONSTANTS.SET_ACTIVE_TOOL, { toolKey });
Stamp
import { TRIGGER_CONSTANTS } from '@procore/markup-viewer';
const stamp = {
url: 'someImage.svg',
width: 100,
height: 100,
};
const options = {
stamp,
};
const toolKey = 'stamp';
markupViewer.trigger(TRIGGER_CONSTANTS.SET_ACTIVE_TOOL, { toolKey, options });
CANCEL_ACTIVE_TOOL
import { TRIGGER_CONSTANTS } from '@procore/markup-viewer';
markupViewer.trigger(TRIGGER_CONSTANTS.CANCEL_ACTIVE_TOOL);
UPDATE_ATTRIBUTES
Will only trigger successfully if there is an active tool that supports updating attributes (rect/freehand)
import { TRIGGER_CONSTANTS } from '@procore/markup-viewer';
const options = {
fill: '#ff0000',
'fill-opacity': 0.5,
stroke: '#0000ff',
'stroke-opacity': 1,
'stroke-width': 4,
};
markupViewer.trigger(TRIGGER_CONSTANTS.UPDATE_ATTRIBUTES, options);
CREATE_MARKUP_ELEMENTS
Typically used for rendering a markupElement from a server-event
import { TRIGGER_CONSTANTS } from '@procore/markup-viewer';
const markupElements = [
{
id: 123,
type: 'rect',
svg: '<rect width="10" height="10" x="0" y="0"></rect>',
},
];
markupViewer.trigger(TRIGGER_CONSTANTS.CREATE_MARKUP_ELEMENTS, markupElement);
REMOVE_MARKUP_ELEMENTS
import { TRIGGER_CONSTANTS } from '@procore/markup-viewer';
const markupElements = ['abc-123'];
markupViewer.trigger(TRIGGER_CONSTANTS.REMOVE_MARKUP_ELEMENTS, markupElements);
UPDATE_MARKUP_ELEMENTS
import { TRIGGER_CONSTANTS } from '@procore/markup-viewer';
const uuid = 'abc-123';
const svg = '<rect></rect>';
const id = 321;
markupViewer.trigger(TRIGGER_CONSTANTS.UPDATE_MARKUP_ELEMENT, [
{
uuid,
svg,
id,
},
]);
UPDATE_SHAPE_ATTRIBUTES
import { TRIGGER_CONSTANTS } from '@procore/markup-viewer';
const markupElements = ['abc-123', 'def-456', 'ghi-789'];
const attributes = {
fill: '#ff0000',
'fill-opacity': 0.5,
stroke: '#0000ff',
'stroke-opacity': 1,
'stroke-width': 4,
};
markupViewer.trigger(TRIGGER_CONSTANTS.UPDATE_SHAPE_ATTRIBUTES, {
markupElements,
attributes,
});
UPDATE_MARKUP_ELEMENT_SELECTION
import { TRIGGER_CONSTANTS } from '@procore/markup-viewer';
const markupElements = ['abc-123', 'def-456', 'ghi-789'];
markupViewer.trigger(TRIGGER_CONSTANTS, markupElements);
EVENT_CONSTANTS
SET_PAGE
import { EVENT_CONSTANTS } from '@procore/markup-viewer';
const callback = payload => console.log(payload);
markupViewer.on(EVENT_CONSTANTS.SET_PAGE, callback);
payload:
ZOOM_IN
import { EVENT_CONSTANTS } from '@procore/markup-viewer';
const callback = payload => console.log(payload);
markupViewer.on(EVENT_CONSTANTS.ZOOM_IN, callback);
payload:
{
zoomLevel: 1.05
}
ZOOM_OUT
import { EVENT_CONSTANTS } from '@procore/markup-viewer';
const callback = payload => console.log(payload);
markupViewer.on(EVENT_CONSTANTS.ZOOM_OUT, callback);
payload:
{
zoomLevel: 0.95
}
RESET_ZOOM
import { EVENT_CONSTANTS } from '@procore/markup-viewer';
const callback = payload => console.log(payload);
markupViewer.on(EVENT_CONSTANTS.RESET_ZOOM, callback);
payload:
{
zoomLevel: 0.95
}
SET_ACTIVE_TOOL
import { EVENT_CONSTANTS } from '@procore/markup-viewer';
const callback = payload => console.log(payload);
markupViewer.on(EVENT_CONSTANTS.SET_ACTIVE_TOOL, callback);
payload:
{
toolKey: 'rect',
options
}
CANCEL_ACTIVE_TOOL
import { EVENT_CONSTANTS } from '@procore/markup-viewer';
const callback = payload => console.log(payload);
markupViewer.on(EVENT_CONSTANTS.CANCEL_ACTIVE_TOOL, callback);
payload:
UPDATE_ATTRIBUTES
import { EVENT_CONSTANTS } from '@procore/markup-viewer';
const callback = payload => console.log(payload);
markupViewer.on(EVENT_CONSTANTS.UPDATE_ATTRIBUTES, callback);
payload:
{
fill: '#ff0000',
'fill-opacity': 0.5,
stroke: '#0000ff',
'stroke-opacity': 1,
'stroke-width': 4,
}
CREATE_MARKUP_ELEMENTS
import { EVENT_CONSTANTS } from '@procore/markup-viewer';
const callback = payload => console.log(payload);
markupViewer.on(EVENT_CONSTANTS.CREATE_MARKUP_ELEMENTS, callback);
payload:
[
{
uuid: 'abc-123',
id: 123,
svg: '<rect></rect>',
type: 'rect',
attributes: {}
}
]
REMOVE_MARKUP_ELEMENTS
import { EVENT_CONSTANTS } from '@procore/markup-viewer';
const callback = payload => console.log(payload);
markupViewer.on(EVENT_CONSTANTS.REMOVE_MARKUP_ELEMENTS, callback);
payload:
[
'abc-123'
]
UPDATE_MARKUP_ELEMENTS
import { EVENT_CONSTANTS } from '@procore/markup-viewer';
const callback = payload => console.log(payload);
markupViewer.on(EVENT_CONSTANTS.UPDATE_MARKUP_ELEMENTS, callback);
payload:
[
{
uuid: 'abc-123',
id: 123,
svg: '<rect></rect>',
type: 'rect',
attributes: {}
}
]
UPDATE_SHAPE_ATTRIBUTES
import { EVENT_CONSTANTS } from '@procore/markup-viewer';
const callback = payload => console.log(payload);
markupViewer.on(EVENT_CONSTANTS.UPDATE_SHAPE_ATTRIBUTES, callback);
payload:
[
{
uuid: 'abc-123',
id: 123,
svg: '<rect></rect>',
type: 'rect',
attributes: {}
}
]
UPDATE_MARKUP_ELEMENT_SELECTION
import { EVENT_CONSTANTS } from '@procore/markup-viewer';
const callback = payload => console.log(payload);
markupViewer.on(EVENT_CONSTANTS.UPDATE_MARKUP_ELEMENT_SELECTION, callback);
payload:
[
'abc-123',
'def-456',
'ghi-789'
]
DRAW_COMPLETE
import { EVENT_CONSTANTS } from '@procore/markup-viewer';
const callback = payload => console.log(payload);
markupViewer.on(EVENT_CONSTANTS.DRAW_COMPLETE, callback);
payload:
{
uuid: 'abc-123',
svg: '<rect></rect>',
type: 'rect',
attributes: {}
}
MARKUP_VIEWER_EVENT
This event is a 'super event'. This event is fired for every event in EVENT_CONSTANTS. Its payload is an object formatted for easy use in Redux-like environments, with type
and payload
keys. type
will be a constant from EVENT_CONSTANTS
; payload
will be the associated payload listed above.
import { EVENT_CONSTANTS } from '@procore/markup-viewer';
const callback = payload => console.log(payload);
markupViewer.on(EVENT_CONSTANTS.MARKUP_VIEWER_EVENT, callback);
payload:
{
type: EVENT_CONSTANTS.*,
payload
}