Commit 791e653c authored by dechen lin's avatar dechen lin
Browse files

feat: add web project

parent 9d689790
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 1.25H15V2.75H3V1.25ZM15 5.25H3V6.75H15V5.25ZM15 13.25H3V14.75H15V13.25ZM15 9.25H6V10.75H15V9.25ZM0 5.25H1.5V6.75H0V5.25ZM1.5 13.25H0V14.75H1.5V13.25ZM0 1.25H1.5V2.75H0V1.25ZM4.5 9.25H3V10.75H4.5V9.25Z" fill="black"/>
</svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.5 2C3.5 1.72421 3.72421 1.5 4 1.5H5.25C5.52579 1.5 5.75 1.72421 5.75 2V5.25C5.75 5.52579 5.52579 5.75 5.25 5.75H4C3.72421 5.75 3.5 5.52579 3.5 5.25V2ZM4 0C2.89579 0 2 0.895786 2 2V5.25C2 6.35421 2.89579 7.25 4 7.25H5.25C6.35421 7.25 7.25 6.35421 7.25 5.25V2C7.25 0.895786 6.35421 0 5.25 0H4ZM3.5 10.75C3.5 10.4742 3.72421 10.25 4 10.25H5.25C5.52579 10.25 5.75 10.4742 5.75 10.75V14C5.75 14.2758 5.52579 14.5 5.25 14.5H4C3.72421 14.5 3.5 14.2758 3.5 14V10.75ZM4 8.75C2.89579 8.75 2 9.64579 2 10.75V14C2 15.1042 2.89579 16 4 16H5.25C6.35421 16 7.25 15.1042 7.25 14V10.75C7.25 9.64579 6.35421 8.75 5.25 8.75H4ZM10.75 1.5C10.4742 1.5 10.25 1.72421 10.25 2V5.25C10.25 5.52579 10.4742 5.75 10.75 5.75H12C12.2758 5.75 12.5 5.52579 12.5 5.25V2C12.5 1.72421 12.2758 1.5 12 1.5H10.75ZM8.75 2C8.75 0.895786 9.64579 0 10.75 0H12C13.1042 0 14 0.895786 14 2V5.25C14 6.35421 13.1042 7.25 12 7.25H10.75C9.64579 7.25 8.75 6.35421 8.75 5.25V2ZM10.25 10.75C10.25 10.4742 10.4742 10.25 10.75 10.25H12C12.2758 10.25 12.5 10.4742 12.5 10.75V14C12.5 14.2758 12.2758 14.5 12 14.5H10.75C10.4742 14.5 10.25 14.2758 10.25 14V10.75ZM10.75 8.75C9.64579 8.75 8.75 9.64579 8.75 10.75V14C8.75 15.1042 9.64579 16 10.75 16H12C13.1042 16 14 15.1042 14 14V10.75C14 9.64579 13.1042 8.75 12 8.75H10.75Z" fill="black"/>
</svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.00488 9.75V14C7.00488 14.1658 7.07073 14.3247 7.18794 14.4419C7.30515 14.5592 7.46412 14.625 7.62988 14.625C7.79564 14.625 7.95461 14.5592 8.07183 14.4419C8.18904 14.3247 8.25488 14.1658 8.25488 14V9.75L8.75488 9.25H13.0049C13.1706 9.25 13.3296 9.18415 13.4468 9.06694C13.564 8.94973 13.6299 8.79076 13.6299 8.625C13.6299 8.45924 13.564 8.30027 13.4468 8.18306C13.3296 8.06585 13.1706 8 13.0049 8H8.75488L8.25488 7.5V3.25C8.25488 3.08424 8.18904 2.92527 8.07183 2.80806C7.95461 2.69085 7.79564 2.625 7.62988 2.625C7.46412 2.625 7.30515 2.69085 7.18794 2.80806C7.07073 2.92527 7.00488 3.08424 7.00488 3.25V7.5L6.50488 8H2.25488C2.08912 8 1.93015 8.06585 1.81294 8.18306C1.69573 8.30027 1.62988 8.45924 1.62988 8.625C1.62988 8.79076 1.69573 8.94973 1.81294 9.06694C1.93015 9.18415 2.08912 9.25 2.25488 9.25H6.39188L7.00488 9.75Z" fill="black"/>
</svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.375 9.25C13.5408 9.25 13.6997 9.18415 13.8169 9.06694C13.9342 8.94973 14 8.79076 14 8.625C14 8.45924 13.9342 8.30027 13.8169 8.18306C13.6997 8.06585 13.5408 8 13.375 8H2.625C2.45924 8 2.30027 8.06585 2.18306 8.18306C2.06585 8.30027 2 8.45924 2 8.625C2 8.79076 2.06585 8.94973 2.18306 9.06694C2.30027 9.18415 2.45924 9.25 2.625 9.25H13.375Z" fill="black"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M13 9L6 5v8z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M10 13l4-7H6z"/></svg>
\ No newline at end of file
var LAYER_CHANGE_ACTIVE_CLASS = 'layerChange-active'
// 获取 button 元素
var layerChangeButton = document.getElementById('layerChange');
var isLayerChangeButtonActive = () => {
return layerChangeButton.classList.contains(LAYER_CHANGE_ACTIVE_CLASS)
}
var getLocale = () => {
console.log('test-iframe-locale', localStorage.getItem('umi-locale') ,localStorage.getItem('locale') , '')
return localStorage.getItem('umi_locale') || localStorage.getItem('locale') || 'zh-CN';
}
// 添加tooltip
function createHoverTooltip(element, tooltipText, id, options = {}) {
const tooltip = document.createElement('div');
tooltip.className = `tooltip-${id} tooltip`;
tooltip.style.display = 'none';
tooltip.style.zIndex = '999';
document.body.appendChild(tooltip);
const defaultOptions = {
offset: { y: 10 },
delay: 200,
duration: 200,
};
const mergedOptions = { ...defaultOptions, ...options };
let tooltipTimer;
function positionTooltip() {
const rect = element.getBoundingClientRect();
const tooltipRect = tooltip.getBoundingClientRect();
const left = rect.left + (rect.width - tooltipRect.width) / 2;
const top = rect.bottom + mergedOptions.offset.y;
tooltip.style.left = `${left}px`;
tooltip.style.top = `${top}px`;
}
function showTooltip() {
tooltip.textContent = tooltipText;
tooltip.style.display = 'block';
tooltip.style.opacity = '0';
tooltip.style.transition = `opacity ${mergedOptions.duration}ms`;
positionTooltip();
setTimeout(() => {
tooltip.style.opacity = '1';
}, 10);
}
function hideTooltip() {
tooltip.style.opacity = '0';
setTimeout(() => {
tooltip.style.display = 'none';
}, mergedOptions.duration);
}
element.addEventListener('mouseenter', () => {
tooltipTimer = setTimeout(showTooltip, mergedOptions.delay);
});
element.addEventListener('mouseleave', () => {
clearTimeout(tooltipTimer);
hideTooltip();
});
window.addEventListener('resize', positionTooltip);
window.addEventListener('scroll', positionTooltip);
// 返回对象,包含 updateTooltipText 函数
return {
updateTooltipText: (newText) => {
tooltipText = newText;
positionTooltip()
if (tooltip.style.display !== 'none') {
showTooltip();
tooltipText = newText;
}
}
};
}
const tooltipLayer = createHoverTooltip(layerChangeButton, getLocale() === 'zh-CN' ? '隐藏识别结果': 'Hide recognition results', 'layerChange', { offset: { y: 22 } });
window.addEventListener('storage', function(event) {
// 检查事件是否与监听的键相关
if (event.key === 'umi_locale'|| event.key === 'locale') {
const text = isLayerChangeButtonActive() ? event?.newValue === 'zh-CN' ? '隐藏识别结果': 'Hide recognition results': getLocale() === 'zh-CN' ? '显示识别结果': 'Display recognition results'
tooltipLayer?.updateTooltipText(text)
}
});
// 添加点击事件监听器
layerChangeButton.addEventListener('click', function() {
// 检查当前 button 的选中状态
if (isLayerChangeButtonActive()) {
// 如果已经处于选中状态,则移除选中状态的 class
const annotationLayerList = document.getElementsByClassName('annotationLayer')
Array?.from(annotationLayerList)?.forEach(element => {
var extractLayer = element.querySelector('#extractLayer');
if(extractLayer) {
extractLayer.style.opacity = 0
}
});
console.log('test-dd', annotationLayerList, typeof annotationLayerList)
tooltipLayer?.updateTooltipText( getLocale() === 'zh-CN' ? '显示识别结果': 'Display recognition results')
this.classList.remove(LAYER_CHANGE_ACTIVE_CLASS);
} else {
// 如果未处于选中状态,则添加选中状态的 class
this.classList.add(LAYER_CHANGE_ACTIVE_CLASS);
tooltipLayer?.updateTooltipText(getLocale() === 'zh-CN' ? '隐藏识别结果': 'Hide recognition results')
const scale = 0.943 / 0.7071 * window?.PDFViewerApplication?.pdfViewer?._currentScale || 1
window.renderExtractLayer(window.pdfExtractData, Number(0), scale)
const annotationLayerList = document.getElementsByClassName('annotationLayer')
Array?.from(annotationLayerList)?.forEach(element => {
var extractLayer = element.querySelector('#extractLayer');
if(extractLayer) {
extractLayer.style.opacity = 1
}
})
}
});
// 获取显示消息的元素
const messageDisplay = document.getElementById('messageDisplay');
function removeDuplicates(arr) {
return [...new Set(arr)];
}
window.addEventListener('error', function(event) {
if (event.target && event.target.tagName === 'SCRIPT') {
console.error("Script error detected: ", event);
}
}, true);
// 添加消息监听器
window.addEventListener('message', function(event) {
const receivedMessage = event.data;
const data = receivedMessage?.data
const type = receivedMessage?.type
function setHasRenderAnimatedPage (num) {
if(!window.hasRenderAnimatedPage ) {
window.hasRenderAnimatedPage = []
}
if( typeof window.hasRenderAnimatedPage === 'object'){
window.hasRenderAnimatedPage = removeDuplicates([...window.hasRenderAnimatedPage, num])
}
}
let animatingBox = new Map()
function renderExtractLayer(data, pageNum, scale) {
// 判断按钮是开的还是关的
if(!isLayerChangeButtonActive()) return;
const bboxes = data?.[pageNum]?.bboxes || []
function drawBoxes(boxes, scale) {
if(animatingBox.get(pageNum)) return
// const annotationLayer = document.querySelector('.canvasWrapper');
const pageLayer = document.getElementsByClassName('page')?.[pageNum]
const annotationLayer = pageLayer.querySelectorAll('.annotationLayer')?.[0];
// annotationLayer.removeAttribute('hidden');
if(!annotationLayer) {
// console.error('error: annotationLayer has not been rendered')
return
}
const extractLayer = annotationLayer.querySelector('#extractLayer');
// 因为pdfjs只会缓存8页的内容,所以采用每次切换移除重建canvas的方式
if (extractLayer) {
extractLayer?.remove();
}
annotationLayer.style.width = '100%';
annotationLayer.style.height = '100%'
annotationLayer.style.position = 'absolute';
annotationLayer.style.top = 0;
annotationLayer.style.left = 0;
const computedLayer = document.querySelector('.canvasWrapper');
const canvas = document.createElement('canvas');
canvas.id = 'extractLayer'
const w = pageLayer?.offsetWidth - 18;
const h = pageLayer?.offsetHeight - 18;
canvas.width = true ? `${w}` : '100%';
canvas.height = true ? `${h}`: '100%';
canvas.style.width = true ? `${w}px` : '100%';
canvas.style.height = true ? `${h}px`: '100%';
canvas.style.position = 'absolute';
canvas.style.top = 0;
canvas.style.left = 0;
annotationLayer.append(canvas)
const ctx = canvas.getContext('2d');
// 移除之前的画布内容
// ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
// console.log('renderExtractLayer: draw boxes')
function drawPartialRect(ctx, box, progress, scale) {
const [x, y, x2, y2]= box.bbox.map((i) => (i * scale));
const width = x2 - x;
const height = y2 - y;
const color = box?.color?.line
const fillColor = box?.color?.fill
ctx.beginPath();
ctx.strokeStyle = color;
// 左边竖线
ctx.moveTo(x, y);
ctx.lineTo(x, y2);
// 上边横线
ctx.moveTo(x, y);
ctx.lineTo(x + width * (progress < 0 ? 0: progress), y);
// 右边竖线 (只在进度完成时绘制)
if (progress === 1) {
ctx.moveTo(x2, y);
ctx.lineTo(x2, y2);
ctx.fillStyle = fillColor;
ctx.fillRect(x, y, width, height);
}
// 下边横线
ctx.moveTo(x, y2);
ctx.lineTo(x + width * (progress < 0 ? 0: progress), y2);
ctx.stroke();
}
function fillRect(ctx, box, scale) {
const [x, y, x2, y2]= box.bbox.map((i) => (i * scale));
const width = x2 - x;
const height = y2 - y;
const color = box?.color?.fill
ctx.fillStyle = color;
ctx.fillRect(x, y, width, height);
}
function animateBox(ctx, box, duration = 1000) {
const startTime = performance.now();
function animate(currentTime) {
const elapsedTime = currentTime - startTime;
const progress = Math.min(elapsedTime / duration, 1);
// ctx.clearRect(...box.bbox); // 清除之前的绘制
drawPartialRect(ctx, box, progress, scale);
if (progress < 1) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
}
async function animateAllBoxes() {
// const [index, value] of array.entries()
for (const [index, box] of boxes?.entries()) {
await animateBox(ctx, box, 600); // 动画时间改为500ms
await new Promise(resolve => setTimeout(resolve, 200)); // 每个框之间的延迟也减少到100ms
}
// 所有线框动画完成后,一次性填充所有矩形
// ctx.clearRect(...box.bbox); // 清除之前的绘制
// boxes.forEach(box => fillRect(ctx, box, scale));
console.log("test-animate All animations completed and boxes filled");
animatingBox.set(pageNum, false)
}
boxes.forEach((box, index) => {
drawPartialRect(ctx, box, 1, scale);
});
canvas.style.width = false ? `${w}px` : '100%';
canvas.style.height = false ? `${h}px`: '100%';
ctx.restore();
}
!!bboxes?.length&&drawBoxes(bboxes, scale);
}
// init extractLayer data
if(type === 'initExtractLayerData') {
const scale = 0.943 / 0.7071 * window?.PDFViewerApplication?.pdfViewer?._currentScale || 1
const currentPageNumber = window?.PDFViewerApplication?.pdfViewer?._currentPageNumber || 1
window.pdfExtractData = data;
window.renderExtractLayer = renderExtractLayer
// window.renderExtractLayer(window.pdfExtractData, currentPageNumber - 1, scale)
// use the picture view rather than outlined view
window.renderExtractLayer(window.pdfExtractData, Number(0), scale)
window?.PDFViewerApplication?.pdfSidebar?.switchView(1, false)
}
if(type === 'pageChange') {
if(window.renderExtractLayer
&& window.pdfExtractData
) {
const scale = 0.943 / 0.7071 * window?.PDFViewerApplication?.pdfViewer?._currentScale || 1
const currentPageNumber = data || 0
window.renderExtractLayer(window.pdfExtractData, Number(0), scale)
window.renderExtractLayer(window.pdfExtractData, Number(data), scale)
} else if(!window.pdfExtractData) {
// console.error('extract pdf render data has not been initialized')
}
}
if( type === 'title') {
const odlPdfTitle = document.getElementById("odl-pdf-title");
odlPdfTitle.innerText = data;
}
if( type === 'setPage') {
window?.PDFViewerApplication?.eventBus?.dispatch("pagenumberchanged", {
value: data
})
}
if( type === '') {
}
});
// Copyright 2014 PDFium Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Digitized data copyright (c) 2010 Google Corporation
with Reserved Font Arimo, Tinos and Cousine.
Copyright (c) 2012 Red Hat, Inc.
with Reserved Font Name Liberation.
This Font Software is licensed under the SIL Open Font License,
Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
PREAMBLE The goals of the Open Font License (OFL) are to stimulate
worldwide development of collaborative font projects, to support the font
creation efforts of academic and linguistic communities, and to provide
a free and open framework in which fonts may be shared and improved in
partnership with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves.
The fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply to
any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such.
This may include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components
as distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting ? in part or in whole ?
any of the components of the Original Version, by changing formats or
by porting the Font Software to a new environment.
"Author" refers to any designer, engineer, programmer, technical writer
or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining a
copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,in
Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the
corresponding Copyright Holder. This restriction only applies to the
primary font name as presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole, must
be distributed entirely under this license, and must not be distributed
under any other license. The requirement for fonts to remain under
this license does not apply to any document created using the Font
Software.
TERMINATION
This license becomes null and void if any of the above conditions are not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
DEALINGS IN THE FONT SOFTWARE.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment