React and OpenSeadragon draw polygons on image - javascript

I'm writing my web-app with create-react-app and I want to create a viewer to render an image and create multiple editable polygons on it.
OpenSeadragon is perfect for this job, in particular there is a useful plugin OpenseadragonFabricjsOverlay that use fabric.js.
So after I installed the following libraries:
"#types/fabric": "^4.5.12",
"#types/openseadragon": "^3.0.4",
"fabric": "^5.2.4",
"openseadragon": "^3.1.0",
"openseadragon-fabricjs-overlay": "github:altert/OpenseadragonFabricjsOverlay"
and created Viewer component
import React, { useEffect } from 'react';
import OpenSeadragon from 'openseadragon';
// eslint-disable-next-line #typescript-eslint/ban-ts-comment
// #ts-ignore
import 'openseadragon-fabricjs-overlay/openseadragon-fabricjs-overlay';
import { fabric } from 'fabric';
const Viewer = () => {
useEffect(() => {
const viewer = OpenSeadragon({
id: 'seadragon-viewer',
tileSources: {
type: 'image',
url: 'path/to/image/jpg'
}
});
// Initialize overlay
const options = {
scale: 1000
}
const overlay = viewer.fabricjsOverlay(options);
return () => {
viewer.destroy();
};
});
return (
<div id="seadragon-viewer" style={{ height: '100%', width: '100%' }}></div>
);
};
export default Viewer;
I get that error:
[openseadragon-canvas-overlay] requires OpenSeadragon
This occurs because OpenSeaDragon has not yet loaded.
How can I include the openseadragon-fabricjs-overlay.js file after OpenSeadragon?
Do you have advices?
UPDATE:
Follow this issue to fix it

The fabric overlay is assuming that OpenSeadragon will be found on the global window object. You might be able to fix it by adding this between the OSD and plugin imports:
window.OpenSeadragon = OpenSeadragon;

Related

Bpmn io vue 3 integration problems

Im currently trying to embed bpmn io in a vue 3 application. Im able to load the diagram using the raw loader in webpack. Unfortunately there are some other issues.
1. The side bar on the left is not appearing
2. The canvas.zoom is not working. Diagram occupies only a small portion of the screen width and height.
MainPage.vue (file where bpmn magic resides)
<template>
<div ref="container" id="canvas" style="height: 100%"/>
</template>
<script>
import pizzaDiagram from '../assets/pizza-diagram.bpmn';
export default {
name: 'main-page',
mounted() {
this.$nextTick(() => {
const container = this.$refs.container;
let modeler = this.$bpmnModeler;
modeler.attachTo(container)
modeler.options = {
container,
height: "100%",
width: "100%"
}
modeler.importXML(pizzaDiagram).then((result) => {
const {warnings} = result;
console.log('success !', warnings);
const canvas = modeler.get('canvas');
canvas.zoom('fit-viewport')
}).catch((err) => {
const {warnings, message} = err;
console.trace('something went wrong. what went wrong :', warnings, message)
})
})
},
data() {
return {}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
#canvas{
height: 100%;
width: 100%;
}
</style>
main.js (file where i register my bpmn components for general use app-wide)
import { createApp } from 'vue'
import App from './App.vue'
import BpmnJS from 'bpmn-js/dist/bpmn-navigated-viewer.production.min.js'
import BpmnModeler from "bpmn-js";
import BpmnViewer from "bpmn-js";
const app = createApp(App);
app.config.globalProperties.$bpmnViewer = new BpmnViewer();
app.config.globalProperties.$bpmnModeler = new BpmnModeler();
app.config.globalProperties.$bpmnInstance = new BpmnJS();
app.mount('#app')
I was able to solve this. The problem was that i was using the ref=container on the template and then passing it to the canvas options. When i used `document.getElementById("container") to refer to the element i was able to get it to work.

How to import Mozilla PDF.js in Vue project?

The question is simple. How do I correctly import the PDF.js library into a Vuejs project?
The library is undefined when I log it.
See my problem in a codesandbox live here.
This is how I am trying it now:
<script>
import pdfjsLib from "pdfjs-dist/build/pdf";
// import { PDFViewer } from "pdfjs-dist/web/pdf_viewer";
import "pdfjs-dist/web/pdf_viewer.css";
pdfjsLib.GlobalWorkerOptions.workerSrc =
"https://cdn.jsdelivr.net/npm/pdfjs-dist#2.0.943/build/pdf.worker.min.js";
export default {
name: "PdfViewer",
mounted() {
pdfjsLib.getDocument("./sample.pdf").then((doc) => {
console.log("doc: ", doc);
});
},
methods: {},
};
</script>
But that gives me the following error: Cannot read property 'GlobalWorkerOptions' of undefined
I think the error occurs if pdfjsLib does not fall into the global scope
, see also codesandbox :
<template>
<div id="pageContainer">
<div id="viewer" class="pdfViewer"></div>
</div>
</template>
<script>
import pdfjsLib from "pdfjs-dist/build/pdf";
import { PDFViewer } from "pdfjs-dist/web/pdf_viewer";
import "pdfjs-dist/web/pdf_viewer.css";
pdfjsLib.GlobalWorkerOptions.workerSrc =
"https://cdn.jsdelivr.net/npm/pdfjs-dist#2.0.943/build/pdf.worker.min.js";
export default {
name: "PdfViewer",
props: { docPath: String },
mounted() {
this.getPdf();
},
methods: {
async getPdf() {
let container = document.getElementById("pageContainer");
let pdfViewer = new PDFViewer({
container: container,
});
let pdf = await pdfjsLib.getDocument(this.docPath);
pdfViewer.setDocument(pdf);
},
},
};
</script>
<style>
#pageContainer {
margin: auto;
width: 80%;
}
div.page {
display: inline-block;
}
</style>
use it:
<PdfViewer docPath="./sample.pdf" />
In case anyone else needs it, the soution is really simple. You just have to import it like this:
import * as pdfjsLib from "pdfjs-dist/build/pdf";
Pdf.js provide a solution for us. Webpack.js included in the project.
const pdfjsLib = require("pdfjs-dist/webpack");
If you get an error like below:
./node_modules/pdfjs-dist/build/pdf.min.js 22:36927
Module parse failed: Unexpected token (22:36927)
Then we have to use es5/build/pdf.js, so we can create src/pdfjs-webpack.js :
"use strict";
var pdfjs = require("pdfjs-dist/es5/build/pdf.min.js");
var PdfjsWorker = require("worker-loader?esModule=false&filename=[name].js!pdfjs-dist/es5/build/pdf.worker.min.js");
if (typeof window !== "undefined" && "Worker" in window) {
pdfjs.GlobalWorkerOptions.workerPort = new PdfjsWorker();
}
module.exports = pdfjs;
then:
const pdfjsLib = require("../pdfjs-webpack");
vue-cli5 already use webpack5, and webpack5 has a built-in web worker and is very easy to use.
Create a file: pdfjs-webpack5.js
import * as pdfjsLib from 'pdfjs-dist'
pdfjsLib.GlobalWorkerOptions.workerPort = new Worker(new URL('pdfjs-dist/build/pdf.worker.js', import.meta.url))
export default pdfjsLib
According to the example getinfo.js given in Setup PDF.js in a website, you can easily read the contents of PDF files.
I use the version of the package.
pdfjs-dist: 2.15.349
webpack: 5.74.0
#vue/cli*: 5.0.8

Writing documentation for plain JS class in storybook

I have just started using Storybook for a UI component lib I am working on. I wanted to extract JSDoc written for JS class methods and properties into Storybook and create a Doc.
Storybook does support creating doc for React components by reading its propTypes. Is there addon or someway to do the same for a JS class.
I am using the latest storybook 6.
Thanks in advance
You can do it like a normal component:
form-validators.stories.ts
import { FormValidators } from './path';
export default {
title: 'Components/Form Validators',
component: FormValidators,
parameters: {
previewTabs: { canvas: { hidden: true } },
docsOnly: true,
},
} as Meta;
export const Default: Story = () => ({
template: '<div>Test</div>',
});
Or I prefer an MDX file.
form-validators.stories.mdx
import { ArgsTable } from '#storybook/addon-docs/blocks';
import { Meta } from '#storybook/addon-docs/blocks';
import { FormValidators } from './path';
<Meta
title="Components/Form Validators"
parameters={{ previewTabs: { canvas: { hidden: true } } }}
/>
<ArgsTable of={FormValidators} />

No upload button using FilePond ReactJs

Good day,
I am wanting to Use FilePond with Reactjs to facilitate image uploads to a server.What I want is to have the file populate in the Pond like the description shows then for the upload button to appear for the user to upload the file.
Initially from using their demo code I noticed that it would auto-upload files and from reading the documentation I see that I disable that auto upload feature using "instantUpload={false}" in my server. However I have done this and I still don't have an upload button for the user to use. I read the documentation some more and they say I need to specify the server which I have . Is there something that I am missing to show the upload button in my code.
Code below:
import React, { Component } from "react";
/*import agent from "superagent";*/
import classNames from "classnames";
import cookie from 'react-cookies';
// Import React FilePond
import { FilePond, registerPlugin } from "react-filepond";
// Import FilePond styles
import "filepond/dist/filepond.min.css";
// Import the Image EXIF Orientation and Image Preview plugins
// Note: These need to be installed separately
import FilePondPluginImageExifOrientation from "filepond-plugin-image-exif-orientation";
import FilePondPluginImagePreview from "filepond-plugin-image-preview";
import "filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css";
// Register the plugins
registerPlugin(FilePondPluginImageExifOrientation, FilePondPluginImagePreview);
export default class FotoUpload extends Component {
constructor(props) {
super(props);
this.state = {
// Set initial files, type 'local' means this is a file
// that has already been uploaded to the server (see docs)
files: [
{
source: "index.html",
options: {
type: "local"
}
}
]
};
}
handleInit() {
console.log("FilePond instance has initialised", this.pond);
}
render() {
return (
<div className="App">
{/* Pass FilePond properties as attributes */}
<FilePond
ref={ref => (this.pond = ref)}
allowFilePoster={true}
instantUpload={false}
server=
{
{
url: 'http://mybackend.com:5000/upload/images',
process: {
headers: {
'cookie-token': cookie.load('cookie')
},
}
}
}
name="image"
acceptedFileTypes={['image/*']}
oninit={() => this.handleInit()}
onupdatefiles={fileItems => {
// Set currently active file objects to this.state
this.setState({
files: fileItems.map(fileItem => fileItem.file)
});
}}
/>
</div>
);
}
}
If I allow the instaupload feature the file will upload and success will return , but I will still not receive an Upload button.
Myimage
As you can see there isn't an upload button like shown in the offical documentation.
Similar problem
https://github.com/pqina/vue-filepond/issues/5
FilePond Documentation
https://pqina.nl/filepond/docs/patterns/api/server/
Official repo
https://github.com/pqina/react-filepond

Take screenshot of React app and generate it as PDF

I'd like to generate a PDF from my React App, the easiest way would probably be to take a screenshot of the current state of my app / ideally a div and save it as PDF...I just don't seem to be able to find the best way how to do it.
Any ideas?
For anyone reading this pdfkit can also generate pdfs in the browser...nice!
You'll need to check out pdfkit website and specifically I only got it to work using the browser releases for pdfkit and blob-stream
https://github.com/devongovett/pdfkit/releases
https://github.com/devongovett/blob-stream/releases
My code looked like
import PDFDocument from 'pdfkit'
import BlobStream from 'blob-stream'
import FileSaver from 'file-saver'
let doc = new PDFDocument()
let stream = doc.pipe(BlobStream())
addHeader(doc, 'My Report.....')
doc.moveDown(0.5).fontSize(8)
// render you doc
// then add a stream eventListener to allow download
stream.on('finish', ()=>{
let blob = stream.toBlob('application/pdf')
FileSaver.saveAs(blob, 'myPDF.pdf')
})
doc.end()
How about a combination of:
html2canvas: https://html2canvas.hertzen.com/
and
jsPDF: https://parall.ax/products/jspdf
From the canvas provided by html2canvas, you can convert it to an image with .toDataUrl() and then feed that into jsPDF with the .addImage() method which wants a base64 image.
Using html2canvas and jsPDF created a react components that export the div and its children components as pdf and Image
The react component is defined as following
import React from 'react'
import html2canvas from 'html2canvas'
import { jsPDF } from "jspdf";
class Exporter extends React.Component {
constructor(props) {
super(props)
}
export =(type, name)=>{
html2canvas(document.querySelector(`#capture`)).then(canvas => {
let dataURL = canvas.toDataURL('image/png');
if (type === 'pdf') {
const pdf = new jsPDF({
orientation: "landscape",
unit: "in",
format: [14, 10]
});
pdf.addImage(dataURL, 'PNG', .6, .6);
pdf.save(`${name}.pdf`);
} else if (type === 'png') {
var link = document.createElement('a');
link.download = `${name}.png`;
link.href = dataURL;
link.click();
}
});
}
render() {
return (
<div>
<button onClick={()=>this.export("pdf", "my-content")}></button>
<div id={`capture`} >
Content to export as pdf/png
{this.props.children} //any child Component render here will be exported as pdf/png
</div>
</div>
)
}
}
export default Exporter

Categories