Base64Png Editor with Patternfly and Invert Tweaker
import * as React from "react"; | |
import { useCallback, useEffect, useImperativeHandle, useRef, useState } from "react"; | |
import { EditorApi, KogitoEditorEnvelopeContextType } from "@kogito-tooling/editor/dist/api"; | |
import { Nav, NavItem, NavList, Page, Switch, Title } from "@patternfly/react-core"; | |
import { DEFAULT_RECT } from "@kogito-tooling/guided-tour/dist/api"; | |
import { Base64PngEdit, Base64PngStateControl } from "./Base64PngStateControl"; | |
import "./styles.scss"; | |
interface Props { | |
envelopeContext: KogitoEditorEnvelopeContextType; | |
} | |
export const Base64PngEditor = React.forwardRef<EditorApi, Props>((props, forwardedRef) => { | |
const [originalContent, setOriginalContent] = useState(""); | |
const [editorContent, setEditorContent] = useState(""); | |
const imageRef = useRef<HTMLImageElement>(null); | |
const canvasRef = useRef<HTMLCanvasElement>(null); | |
useEffect(() => { | |
props.envelopeContext.channelApi.notifications.receive_ready(); | |
}, []); | |
const getContent = useCallback(() => { | |
return editorContent; | |
}, [editorContent]); | |
const getPreview = useCallback(() => { | |
const width = imageRef.current!.width; | |
const height = imageRef.current!.height; | |
return ` | |
<svg version="1.1" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" | |
xmlns="http://www.w3.org/2000/svg" | |
xmlns:xlink="http://www.w3.org/1999/xlink"> | |
<image width="${width}" height="${height}" xlink:href="data:image/png;base64,${editorContent}" /> | |
</svg>`; | |
}, [editorContent]); | |
const setContent = useCallback((path: string, content: string) => { | |
setOriginalContent(content); | |
}, []); | |
useImperativeHandle(forwardedRef, () => { | |
return { | |
getContent: () => Promise.resolve(getContent()), | |
getPreview: () => Promise.resolve(getPreview()), | |
setContent: (path: string, content: string) => Promise.resolve(setContent(path, content)), | |
undo: () => Promise.resolve(), | |
redo: () => Promise.resolve(), | |
getElementPosition: (selector: string) => Promise.resolve(DEFAULT_RECT), | |
}; | |
}); | |
const [disabled, setDisabled] = useState(true); | |
const [invert, setInvert] = useState("0"); | |
const tweakInvert = useCallback((value: string) => { | |
setInvert(value); | |
props.envelopeContext.channelApi.notifications.receive_newEdit({ id: new Date().getTime().toString() }); | |
}, [invert]); | |
useEffect(() => { | |
const ctx = canvasRef.current?.getContext("2d")!; | |
ctx.filter = `invert(${invert}%)`; | |
ctx.drawImage(imageRef.current!, 0, 0); | |
setEditorContent(canvasRef.current!.toDataURL().split(",")[1]); | |
}, [invert]); | |
useEffect(() => { | |
const ctx = canvasRef.current?.getContext("2d")!; | |
canvasRef.current!.width = 0; | |
canvasRef.current!.height = 0; | |
imageRef.current!.onload = () => { | |
canvasRef.current!.width = imageRef.current!.width; | |
canvasRef.current!.height = imageRef.current!.height; | |
ctx.drawImage(imageRef.current!, 0, 0); | |
setEditorContent(canvasRef.current!.toDataURL().split(",")[1]); | |
setDisabled(false); | |
}; | |
return () => { | |
imageRef.current!.onload = null; | |
}; | |
}, []); | |
return ( | |
<Page className={"base64png-editor--page"}> | |
<div className={"base64png-editor--main"}> | |
<div className={"base64png-editor--viewport"}> | |
<img | |
ref={imageRef} | |
className={"base64png-editor--image"} | |
src={`data:image/png;base64,${originalContent}`} | |
alt={"Original"} | |
/> | |
{disabled && ( | |
<EmptyState> | |
<EmptyStateIcon icon={CubesIcon} /> | |
<Title headingLevel="h5" size="4xl"> | |
Empty image | |
</Title> | |
</EmptyState> | |
)} | |
<canvas ref={canvasRef} className={"base64png-editor--canvas"} /> | |
</div> | |
<div className={"base64png-editor--tweaks"}> | |
<Nav aria-label="Image tweaker"> | |
<NavList> | |
<NavItem itemId={0}> | |
<div className={"base64png-editor--tweaks-nav-item"}> | |
<p>Invert</p> | |
<Switch | |
id="invert-switch" | |
isDisabled={disabled} | |
isChecked={invert === "100"} | |
onChange={(value) => tweakInvert(value ? "100" : "0")} | |
/> | |
</div> | |
</NavItem> | |
</NavList> | |
</Nav> | |
</div> | |
</div> | |
</Page> | |
); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment