Skip to content

Instantly share code, notes, and snippets.

@Deraen
Last active May 29, 2019 07:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Deraen/0dd99e0157fd8119ac6b3557ff11fa2c to your computer and use it in GitHub Desktop.
Save Deraen/0dd99e0157fd8119ac6b3557ff11fa2c to your computer and use it in GitHub Desktop.
React Konva example with Reagent
(ns example.react-konva-image
(:require [reagent.core :as r]
;; This presumes Shadow-cljs (or cljsjs packages with correct definitions)
[react-konva :refer [Stage Layer Image]]
[use-image :as use-image]))
(defn lion-image []
(let [[image] (use-image "https://konvajs.org/assets/lion.png")]
(r/as-element [:> Image {:image image}])))
;; or, without Reagent hiccup -> React elements step, directly creating React element:
(r/create-element Image #js {:image image})
(defn url-image [_]
(let [image (r/atom nil)
loaded (r/atom false)
handle-load (fn []
(reset! loaded true))
load-image (fn [src]
(let [i (new js/window.Image)]
(reset! image i)
(set! (.-src i) src)
(.addEventListener i "load" handle-load)))
;; Unused
image-node (atom nil)
ref-fn #(reset! image-node %)]
(r/create-class
{:component-did-mount (fn [this] (load-image (:src (r/props this))))
:component-did-update (fn [this [_ old-props]]
(if (not= (:src old-props) (:src (r/props this)))
(load-image (:src (r/props this)))))
:component-will-unmount (fn [this]
(.removeEventListener @image "load" handle-load))
:reagent-render (fn [{:keys [x y]}]
(if @loaded
[:> Image
{:x x
:y y
:image @image
:ref ref-fn}]))})))
(defn app []
[:> Stage
{:width (.-innerWidth js/window)
:height (.-innerHeight js/window)}
[:> Layer
[url-image {:src "https://konvajs.org/assets/yoda.jpg" x: 150}]
;; Use as React component!
[:> lion-image]]])
import React, { Component } from 'react';
import { render } from 'react-dom';
import { Stage, Layer, Image } from 'react-konva';
import useImage from 'use-image';
// the first very simple and recommended way:
const LionImage = () => {
const [image] = useImage('https://konvajs.org/assets/lion.png');
return <Image image={image} />;
};
// custom component that will handle loading image from url
// you may add more logic here to handle "loading" state
// or if loading is failed
// VERY IMPORTANT NOTES:
// at first we will set image state to null
// and then we will set it to native image instance when it is loaded
class URLImage extends React.Component {
state = {
image: null
};
componentDidMount() {
this.loadImage();
}
componentDidUpdate(oldProps) {
if (oldProps.src !== this.props.src) {
this.loadImage();
}
}
componentWillUnmount() {
this.image.removeEventListener('load', this.handleLoad);
}
loadImage() {
// save to "this" to remove "load" handler on unmount
this.image = new window.Image();
this.image.src = this.props.src;
this.image.addEventListener('load', this.handleLoad);
}
handleLoad = () => {
// after setState react-konva will update canvas and redraw the layer
// because "image" property is changed
this.setState({
image: this.image
});
// if you keep same image object during source updates
// you will have to update layer manually:
// this.imageNode.getLayer().batchDraw();
};
render() {
return (
<Image
x={this.props.x}
y={this.props.y}
image={this.state.image}
ref={node => {
this.imageNode = node;
}}
/>
);
}
}
class App extends Component {
render() {
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
<URLImage src="https://konvajs.org/assets/yoda.jpg" x={150} />
<LionImage />
</Layer>
</Stage>
);
}
}
render(<App />, document.getElementById('root'));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment