Skip to content
Snippets Groups Projects
Commit 478505e9 authored by Jacob Benz's avatar Jacob Benz
Browse files

inital work second window image viewer

parent 32ba8617
Branches
No related tags found
1 merge request!9Allow users with multiple screens to open image viewer in a second window
.imageViewer {
display: table;
height: 100%;
width: 100%;
}
.imageViewer .toolbar {
display: flex;
justify-content: space-between;
align-items: center;
height: 32px;
padding: 8px;
margin-top: 4px;
}
.imageViewer .image {
display: table-row;
height: 100%;
}
.imageViewer .toolbar .navigation {
display: flex;
align-items: center;
gap: 8px;
}
.imageViewer .toolbar .zoom {
display: flex;
align-items: center;
gap: 8px;
}
.imageViewer .lw-button {
display: flex !important;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
border-radius: 3px;
}
.imageViewer .lw-button:hover {
cursor: pointer;
background-color: rgba(0, 0, 0, .1);
/* border: 1px solid #aaa; */
}
.imageViewer .pageInfo {
/* display: block;
position: relative;
float: right;
margin: 5px 3px; */
}
.imageViewer input.currPage {
height: 20px;
width: 20px;
text-align: right;
}
.imageViewer .openseadragon-message {
white-space: pre;
}
\ No newline at end of file
import { Box, Link, Stack, Typography } from '@mui/material';
import { Logo } from '@src/components';
import { Page } from '@src/layouts';
import { Trans, useTranslation } from 'react-i18next';
import { Link as RouterLink } from 'react-router';
import { BroadcastChannel } from 'broadcast-channel';
import { useEffect, useState } from 'react';
import OpenSeaDragon from 'openseadragon';
import './imageViewer.css'
export const ImageViewerPage = () => {
const { t } = useTranslation();
const channel = new BroadcastChannel('imageViewer-channel');
const [images, setImages] = useState("")
const id: string = "LEAF-Wwriter-SepImageViewer"
//var viewer: any;
useEffect(() => {
const handleMessage = (event) => {
console.log(event)
if (event.tileSources) {
setImages(event.tileSources);
}
};
channel.onmessage = handleMessage;
// Clean up the channel when the component unmounts
return () => {
channel.close();
};
}, [channel]);
useEffect(() => {
channel.postMessage({imageViewerWindowReady: true})
console.log("HIU")
}, [])
useEffect(() => {
console.log(images)
}, [images])
useEffect(() => {
let viewer = OpenSeaDragon({
id: 'seadragon-viewer',
sequenceMode: true,
autoHideControls: false,
showFullPageControl: false,
previousButton: `${id}_prev`,
nextButton: `${id}_next`,
zoomInButton: `${id}_zoomIn`,
zoomOutButton: `${id}_zoomOut`,
homeButton: `${id}_home`,
});
console.log(images)
viewer.open(images)
// Cleanup (equal to componentWillUnmount)
return () => {
viewer.destroy();
viewer = null;
};
}, [images]);
return (
<div id={id} className="imageViewer">
<div className="toolbar">
<div className="navigation">
<span id={id + "_prev"} className="lw-button">
<i className="fas fa-arrow-left"></i>
</span>
<span id={id + "_next"} className="lw-button">
<i className="fas fa-arrow-right"></i>
</span>
<span className="pageInfo">
<input type="text" className="currPage" /> / <span className="totalPages"/>
</span>
</div>
<div className="zoom">
<span id={id + "_zoomIn"} className="lw-button">
<i className="fas fa-search-plus"></i>
</span>
<span id={id + "_zoomOut"} className="lw-button">
<i className="fas fa-search-minus"></i>
</span>
<span id={id + "_home"} className="lw-button">
<i className="fas fa-compress"></i>
</span>
</div>
</div>
<div id="seadragon-viewer" className="seadragon-viewer" />
</div>
);
};
......@@ -2,3 +2,4 @@ export * from './LinkAccounts';
export * from './edit';
export * from './error/NotFoundView';
export * from './home';
export * from './imageviewer';
import { BasicLayout } from './layouts';
import { EditPage, HomePage, LinkAccountsPage, NotFoundPage } from './pages';
import { EditPage, HomePage, LinkAccountsPage, NotFoundPage, ImageViewerPage } from './pages';
export const routes = [
{
......@@ -10,6 +10,7 @@ export const routes = [
{ path: '/link-accounts', element: <LinkAccountsPage /> },
{ path: '/edit', element: <EditPage /> },
{ path: '/view', element: <EditPage /> },
{ path: '/imageviewer', element: <ImageViewerPage /> },
{ index: true, element: <HomePage /> },
],
},
......
......@@ -8,6 +8,9 @@ import { Button } from './Button';
import { IconButton } from './IconButton';
import { Toggle } from './Toggle';
import { Trans, useTranslation } from 'react-i18next';
//import PortalComponent from './PortalComponent';
import { BroadcastChannel } from 'broadcast-channel';
import { useEffect, useState } from 'react';
type ItemType = 'button' | 'divider' | 'iconButton' | 'toggle';
type ItemGroup = 'action' | 'ui' | 'panel' | 'general';
......@@ -42,6 +45,28 @@ export const EditorToolbar = () => {
const container = useRef<HTMLDivElement>(null);
/*
const [showPortal, setShowPortal] = useState(false);
const channel = new BroadcastChannel('imageViewer-channel');
const [message, setMessage] = useState("")
useEffect(() => {
const handleMessage = (event) => {
console.log(event)
if (event.imageViewerWindowReady && event.imageViewerWindowReady == true) {
channel.postMessage({dataIn: "Hi, I am Broadcast!"})
}
};
channel.onmessage = handleMessage;
// Clean up the channel when the component unmounts
return () => {
channel.close();
};
}, [channel]);*/
const isSupported = useCallback(
(name: EntityType) => window.writer.schemaManager.mapper.getEntitiesMapping().has(name),
[schemaId],
......@@ -227,6 +252,15 @@ export const EditorToolbar = () => {
title: t('Validate').toString(),
type: 'iconButton',
},
{
group: 'ui',
icon: 'validate',
onClick: () => {
const externalWindow = window.open(window.location.origin + '/imageviewer', '', 'width=600,height=400,left=200,top=200');
},
title: t('Second Window Image Viewer').toString(),
type: 'iconButton',
},
{ group: 'ui', type: 'divider', hide: isReadonly },
{
group: 'ui',
......
......@@ -6,6 +6,7 @@ import { Octokit } from '@octokit/rest';
import { Buffer } from 'buffer/';
import axios, { AxiosInstance, AxiosResponse } from 'axios';
import i18next from '../../../../i18n';
import { BroadcastChannel } from 'broadcast-channel';
const { t } = i18next;
......@@ -25,17 +26,23 @@ class ImageViewer {
readonly osd: ReturnType<typeof OpenSeaDragon>;
readonly channel: any;
$pageBreaks: any;
$oldPageBreaks: any;
currentIndex = -1;
ignoreScroll = false;
inhibitScroll = false // Marker to inhibit scrolling when user has zoomed in on a particular image
globalTileSources: any;
constructor({ attribute, parentId, tag, writer }: ImageViewerProps) {
this.writer = writer;
this.id = `${parentId}_imageViewer`;
this.tagName = tag ?? 'pb'; // page break element name
this.attrName = attribute ?? 'facs'; // attribute that stores the image URL
this.channel = new BroadcastChannel('imageViewer-channel');
this.channel.onmessage = this.handleMessage;
const _this = this;
......@@ -149,6 +156,14 @@ class ImageViewer {
});
}
private handleMessage = (event) => {
console.log(event)
if (event.imageViewerWindowReady && event.imageViewerWindowReady == true) {
this.channel.postMessage({tileSources: this.globalTileSources})
}
};
// ensure page break tags are display block
private cssHack() {
if (!this.writer.editor) return;
......@@ -451,6 +466,8 @@ class ImageViewer {
}
}
this.globalTileSources = tileSources
this.osd.open(tileSources);
// tileSources.length === 0
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment