UNPKG

molstar

Version:

A comprehensive macromolecular library.

260 lines 14.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ScreenshotPreview = void 0; var tslib_1 = require("tslib"); var jsx_runtime_1 = require("react/jsx-runtime"); /** * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> */ var React = (0, tslib_1.__importStar)(require("react")); var react_1 = require("react"); var object_1 = require("../../mol-util/object"); var use_behavior_1 = require("../hooks/use-behavior"); var _ScreenshotPreview = function (props) { var plugin = props.plugin, cropFrameColor = props.cropFrameColor; var helper = plugin.helpers.viewportScreenshot; var _a = (0, react_1.useState)(null), currentCanvas = _a[0], setCurrentCanvas = _a[1]; var canvasRef = (0, react_1.useRef)(null); var propsRef = (0, react_1.useRef)(props); (0, react_1.useEffect)(function () { propsRef.current = props; }, Object.values(props)); (0, react_1.useEffect)(function () { if (currentCanvas !== canvasRef.current) { setCurrentCanvas(canvasRef.current); } }); (0, react_1.useEffect)(function () { var _a; var isDirty = false; var subs = []; function subscribe(xs, f) { if (!xs) return; subs.push(xs.subscribe(f)); } function preview() { var p = propsRef.current; if (!p.suspend && canvasRef.current) { drawPreview(helper, canvasRef.current, p.customBackground, p.borderColor, p.borderWidth); } if (!canvasRef.current) isDirty = true; } var interval = setInterval(function () { if (isDirty) { isDirty = false; preview(); } }, 1000 / 8); subscribe(plugin.events.canvas3d.settingsUpdated, function () { return isDirty = true; }); subscribe((_a = plugin.canvas3d) === null || _a === void 0 ? void 0 : _a.didDraw, function () { return isDirty = true; }); subscribe(plugin.state.data.behaviors.isUpdating, function (v) { if (!v) isDirty = true; }); subscribe(helper.behaviors.values, function () { return isDirty = true; }); subscribe(helper.behaviors.cropParams, function () { return isDirty = true; }); var resizeObserver = void 0; if (typeof ResizeObserver !== 'undefined') { resizeObserver = new ResizeObserver(function () { return isDirty = true; }); } var canvas = canvasRef.current; resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.observe(canvas); preview(); return function () { clearInterval(interval); subs.forEach(function (s) { return s.unsubscribe(); }); resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.unobserve(canvas); }; }, [helper]); (0, react_1.useLayoutEffect)(function () { if (canvasRef.current) { drawPreview(helper, canvasRef.current, props.customBackground, props.borderColor, props.borderWidth); } }, (0, tslib_1.__spreadArray)([], Object.values(props), true)); return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsxs)("div", (0, tslib_1.__assign)({ style: { position: 'relative', width: '100%', height: '100%' } }, { children: [(0, jsx_runtime_1.jsx)("canvas", { ref: canvasRef, onContextMenu: function (e) { e.preventDefault(); e.stopPropagation(); }, style: { display: 'block', width: '100%', height: '100%' } }, void 0), (0, jsx_runtime_1.jsx)(ViewportFrame, { plugin: plugin, canvas: currentCanvas, color: cropFrameColor }, void 0)] }), void 0) }, void 0); }; exports.ScreenshotPreview = React.memo(_ScreenshotPreview, function (prev, next) { return (0, object_1.shallowEqual)(prev, next); }); function drawPreview(helper, target, customBackground, borderColor, borderWidth) { var _a = helper.getPreview(), canvas = _a.canvas, width = _a.width, height = _a.height; var ctx = target.getContext('2d'); if (!ctx) return; var w = target.clientWidth; var h = target.clientHeight; target.width = w; target.height = h; ctx.clearRect(0, 0, w, h); var frame = getViewportFrame(width, height, w, h); if (customBackground) { ctx.fillStyle = customBackground; ctx.fillRect(frame.x, frame.y, frame.width, frame.height); } else if (helper.values.transparent) { // must be an odd number var s = 13; for (var i = 0; i < frame.width; i += s) { for (var j = 0; j < frame.height; j += s) { ctx.fillStyle = (i + j) % 2 ? '#ffffff' : '#bfbfbf'; var x = frame.x + i, y = frame.y + j; var w_1 = i + s > frame.width ? frame.width - i : s; var h_1 = j + s > frame.height ? frame.height - j : s; ctx.fillRect(x, y, w_1, h_1); } } } ctx.drawImage(canvas, frame.x, frame.y, frame.width, frame.height); if (borderColor && borderWidth) { var w_2 = borderWidth; ctx.rect(frame.x, frame.y, frame.width, frame.height); ctx.rect(frame.x + w_2, frame.y + w_2, frame.width - 2 * w_2, frame.height - 2 * w_2); ctx.fillStyle = borderColor; ctx.fill('evenodd'); } } function ViewportFrame(_a) { var _b; var plugin = _a.plugin, canvas = _a.canvas, _c = _a.color, color = _c === void 0 ? 'rgba(255, 87, 45, 0.75)' : _c; var helper = plugin.helpers.viewportScreenshot; var params = (0, use_behavior_1.useBehavior)(helper === null || helper === void 0 ? void 0 : helper.behaviors.values); var cropParams = (0, use_behavior_1.useBehavior)(helper === null || helper === void 0 ? void 0 : helper.behaviors.cropParams); var crop = (0, use_behavior_1.useBehavior)(helper === null || helper === void 0 ? void 0 : helper.behaviors.relativeCrop); var cropFrameRef = (0, react_1.useRef)({ x: 0, y: 0, width: 0, height: 0 }); (0, use_behavior_1.useBehavior)((params === null || params === void 0 ? void 0 : params.resolution.name) === 'viewport' ? (_b = plugin.canvas3d) === null || _b === void 0 ? void 0 : _b.resized : void 0); var _d = React.useState(''), drag = _d[0], setDrag = _d[1]; var _e = (0, react_1.useState)([0, 0]), start = _e[0], setStart = _e[1]; var _f = (0, react_1.useState)([0, 0]), current = _f[0], setCurrent = _f[1]; if (!helper || !canvas) return null; var _g = helper.getSizeAndViewport(), width = _g.width, height = _g.height; var frame = getViewportFrame(width, height, canvas.clientWidth, canvas.clientHeight); var cropFrame = { x: frame.x + Math.floor(frame.width * crop.x), y: frame.y + Math.floor(frame.height * crop.y), width: Math.ceil(frame.width * crop.width), height: Math.ceil(frame.height * crop.height) }; var rectCrop = toRect(cropFrame); var rectFrame = toRect(frame); if (drag === 'move') { rectCrop.l += current[0] - start[0]; rectCrop.r += current[0] - start[0]; rectCrop.t += current[1] - start[1]; rectCrop.b += current[1] - start[1]; } else if (drag) { if (drag.indexOf('left') >= 0) { rectCrop.l += current[0] - start[0]; } else if (drag.indexOf('right') >= 0) { rectCrop.r += current[0] - start[0]; } if (drag.indexOf('top') >= 0) { rectCrop.t += current[1] - start[1]; } else if (drag.indexOf('bottom') >= 0) { rectCrop.b += current[1] - start[1]; } } if (rectCrop.l > rectCrop.r) { var t = rectCrop.l; rectCrop.l = rectCrop.r; rectCrop.r = t; } if (rectCrop.t > rectCrop.b) { var t = rectCrop.t; rectCrop.t = rectCrop.b; rectCrop.b = t; } var pad = 40; rectCrop.l = Math.min(rectFrame.r - pad, Math.max(rectFrame.l, rectCrop.l)); rectCrop.r = Math.max(rectFrame.l + pad, Math.min(rectFrame.r, rectCrop.r)); rectCrop.t = Math.min(rectFrame.b - pad, Math.max(rectFrame.t, rectCrop.t)); rectCrop.b = Math.max(rectFrame.t + pad, Math.min(rectFrame.b, rectCrop.b)); cropFrame.x = rectCrop.l; cropFrame.y = rectCrop.t; cropFrame.width = rectCrop.r - rectCrop.l + 1; cropFrame.height = rectCrop.b - rectCrop.t + 1; cropFrameRef.current = cropFrame; var onMove = function (e) { e.preventDefault(); setCurrent([e.pageX, e.pageY]); }; var onTouchMove = function (e) { e.preventDefault(); var t = e.touches[0]; setCurrent([t.pageX, t.pageY]); }; var onTouchStart = function (e) { e.preventDefault(); setDrag(e.currentTarget.getAttribute('data-drag')); var t = e.touches[0]; var p = [t.pageX, t.pageY]; setStart(p); setCurrent(p); window.addEventListener('touchend', onTouchEnd); window.addEventListener('touchmove', onTouchMove); }; var onStart = function (e) { e.preventDefault(); setDrag(e.currentTarget.getAttribute('data-drag')); var p = [e.pageX, e.pageY]; setStart(p); setCurrent(p); window.addEventListener('mouseup', onEnd); window.addEventListener('mousemove', onMove); }; var onEnd = function () { window.removeEventListener('mouseup', onEnd); window.removeEventListener('mousemove', onMove); finish(); }; var onTouchEnd = function () { window.removeEventListener('touchend', onTouchEnd); window.removeEventListener('touchmove', onTouchMove); finish(); }; function finish() { var cropFrame = cropFrameRef.current; if (cropParams.auto) { helper === null || helper === void 0 ? void 0 : helper.behaviors.cropParams.next((0, tslib_1.__assign)((0, tslib_1.__assign)({}, cropParams), { auto: false })); } helper === null || helper === void 0 ? void 0 : helper.behaviors.relativeCrop.next({ x: (cropFrame.x - frame.x) / frame.width, y: (cropFrame.y - frame.y) / frame.height, width: cropFrame.width / frame.width, height: cropFrame.height / frame.height }); setDrag(''); var p = [0, 0]; setStart(p); setCurrent(p); } var contextMenu = function (e) { e.preventDefault(); e.stopPropagation(); }; var d = 4; var border = "3px solid " + color; var transparent = 'transparent'; return (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { "data-drag": 'move', style: { position: 'absolute', left: cropFrame.x, top: cropFrame.y, width: cropFrame.width, height: cropFrame.height, border: border, cursor: 'move' }, onMouseDown: onStart, onTouchStart: onTouchStart, draggable: false, onContextMenu: contextMenu }, void 0), (0, jsx_runtime_1.jsx)("div", { "data-drag": 'left', style: { position: 'absolute', left: cropFrame.x - d, top: cropFrame.y + d, width: 4 * d, height: cropFrame.height - d, background: transparent, cursor: 'w-resize' }, onMouseDown: onStart, onTouchStart: onTouchStart, draggable: false, onContextMenu: contextMenu }, void 0), (0, jsx_runtime_1.jsx)("div", { "data-drag": 'right', style: { position: 'absolute', left: rectCrop.r - 2 * d, top: cropFrame.y, width: 4 * d, height: cropFrame.height - d, background: transparent, cursor: 'w-resize' }, onMouseDown: onStart, onTouchStart: onTouchStart, draggable: false, onContextMenu: contextMenu }, void 0), (0, jsx_runtime_1.jsx)("div", { "data-drag": 'top', style: { position: 'absolute', left: cropFrame.x - d, top: cropFrame.y - d, width: cropFrame.width + 2 * d, height: 4 * d, background: transparent, cursor: 'n-resize' }, onMouseDown: onStart, onTouchStart: onTouchStart, draggable: false, onContextMenu: contextMenu }, void 0), (0, jsx_runtime_1.jsx)("div", { "data-drag": 'bottom', style: { position: 'absolute', left: cropFrame.x - d, top: rectCrop.b - 2 * d, width: cropFrame.width + 2 * d, height: 4 * d, background: transparent, cursor: 'n-resize' }, onMouseDown: onStart, onTouchStart: onTouchStart, draggable: false, onContextMenu: contextMenu }, void 0), (0, jsx_runtime_1.jsx)("div", { "data-drag": 'top, left', style: { position: 'absolute', left: rectCrop.l - d, top: rectCrop.t - d, width: 4 * d, height: 4 * d, background: transparent, cursor: 'nw-resize' }, onMouseDown: onStart, onTouchStart: onTouchStart, draggable: false, onContextMenu: contextMenu }, void 0), (0, jsx_runtime_1.jsx)("div", { "data-drag": 'bottom, right', style: { position: 'absolute', left: rectCrop.r - 2 * d, top: rectCrop.b - 2 * d, width: 4 * d, height: 4 * d, background: transparent, cursor: 'nw-resize' }, onMouseDown: onStart, onTouchStart: onTouchStart, draggable: false, onContextMenu: contextMenu }, void 0), (0, jsx_runtime_1.jsx)("div", { "data-drag": 'top, right', style: { position: 'absolute', left: rectCrop.r - 2 * d, top: rectCrop.t - d, width: 4 * d, height: 4 * d, background: transparent, cursor: 'ne-resize' }, onMouseDown: onStart, onTouchStart: onTouchStart, draggable: false, onContextMenu: contextMenu }, void 0), (0, jsx_runtime_1.jsx)("div", { "data-drag": 'bottom, left', style: { position: 'absolute', left: rectCrop.l - d, top: rectCrop.b - 2 * d, width: 4 * d, height: 4 * d, background: transparent, cursor: 'ne-resize' }, onMouseDown: onStart, onTouchStart: onTouchStart, draggable: false, onContextMenu: contextMenu }, void 0)] }, void 0); } function toRect(viewport) { return { l: viewport.x, t: viewport.y, r: viewport.x + viewport.width - 1, b: viewport.y + viewport.height - 1 }; } function getViewportFrame(srcWidth, srcHeight, w, h) { var a0 = srcWidth / srcHeight; var a1 = w / h; if (a0 <= a1) { var t = h * a0; return { x: Math.round((w - t) / 2), y: 0, width: Math.round(t), height: h }; } else { var t = w / a0; return { x: 0, y: Math.round((h - t) / 2), width: w, height: Math.round(t) }; } } //# sourceMappingURL=screenshot.js.map