UNPKG

label-studio

Version:

Data Labeling Tool that is backend agnostic and can be embedded into your applications

409 lines (342 loc) 11.1 kB
import React, { Component } from "react"; import { Stage, Layer, Group, Line } from "react-konva"; import { observer } from "mobx-react"; import ImageGrid from "../ImageGrid/ImageGrid"; import ImageTransformer from "../ImageTransformer/ImageTransformer"; import ObjectTag from "../../components/Tags/Object"; import Tree from "../../core/Tree"; import styles from "./ImageView.module.scss"; export default observer( class ImageView extends Component { constructor(props) { super(props); this.onResize = this.onResize.bind(this); } /** * Handler of click on Image */ handleOnClick = ev => { const { item } = this.props; return item.onImageClick(ev); }; /** * Handler for mouse down */ handleStageMouseDown = e => { const { item } = this.props; // item.freezeHistory(); const p = e.target.getParent(); if (p && p.className === "Transformer") { return; } if (e.target === e.target.getStage() || (e.target.parent && e.target.parent.attrs.name === "ruler")) { return item.onMouseDown(e); } return true; // /** // * Disable polygon event handler // */ // if (item.controlButtonType === "PolygonLabelsModel") { // return; // } // /** // * Brush event handler // */ // if (item.controlButtonType === "BrushLabelsModel") { // const { x, y } = e.target.getStage().getPointerPosition(); // item.startDraw({ x: Math.floor(x), y: Math.floor(y) }); // return; // } // if (e.target === e.target.getStage() || (e.target.parent && e.target.parent.attrs.name === "ruler")) { // // draw rect // const x = (e.evt.offsetX - item.zoomingPositionX) / item.zoomScale; // const y = (e.evt.offsetY - item.zoomingPositionY) / item.zoomScale; // item.startDraw({ x: x, y: y }); // return; // } // const clickedOnTransformer = e.target.getParent().className === "Transformer"; // if (clickedOnTransformer) { // return; // } // return true; }; /** * Handler of mouse up */ handleMouseUp = e => { const { item } = this.props; item.freezeHistory(); return item.onMouseUp(e); // if (item.mode === "drawing") { // /** // * Set mode of Image for "view" // */ // item.setMode("viewing"); // /** // * Constants of min size of bounding box // */ // const minSize = { width: 3, height: 3 }; // /** // * Current shape // */ // const currentShape = item.detachActiveShape(); // /** // * Check for minimal size of boundng box // */ // if (currentShape.width > minSize.width && currentShape.height > minSize.height) item.addShape(currentShape); // } else if (item.mode === "brush") { // item.setMode("viewing"); // const currentShape = item.detachActiveShape(); // item.addShape(currentShape); // } else if (item.mode === "eraser") { // item.setMode("viewing"); // } }; /** * Handler for mouse move */ handleMouseMove = e => { const { item } = this.props; /** * Freeze this event */ item.freezeHistory(); return item.onMouseMove(e); // /** // * // */ // if (item.mode === "drawing") { // const x = (e.evt.offsetX - item.zoomingPositionX) / item.zoomScale; // const y = (e.evt.offsetY - item.zoomingPositionY) / item.zoomScale; // item.updateDraw({ x: x, y: y }); // } else if (item.mode === "brush") { // const { x, y } = e.target.getStage().getPointerPosition(); // item.addPoints({ x: Math.floor(x), y: Math.floor(y) }); // } else if (item.mode === "eraser") { // const { x, y } = e.target.getStage().getPointerPosition(); // item.addEraserPoints({ x: Math.floor(x), y: Math.floor(y) }); // } // item.setPointerPosition({ x: e.evt.offsetX, y: e.evt.offsetY }); }; /** * Update brightness of Image */ updateBrightness = range => { const { item } = this.props; item.freezeHistory(); item.setBrightnessGrade(range); }; updateBrushControl = arg => this.props.item.updateBrushControl(arg); updateBrushStrokeWidth = arg => this.props.item.updateBrushStrokeWidth(arg); updateGridSize = range => { const { item } = this.props; item.freezeHistory(); item.setGridSize(range); }; /** * Handle to zoom */ handleZoom = e => { /** * Disable if user doesn't use ctrl */ if (e.evt && !e.evt.ctrlKey) { return; } else if (e.evt && e.evt.ctrlKey) { /** * Disable scrolling page */ e.evt.preventDefault(); } const { item } = this.props; item.freezeHistory(); const stage = item.stageRef; const scaleBy = parseFloat(item.zoomby); const oldScale = stage.scaleX(); let mousePointTo; let newScale; let pos; let newPos; if (e.evt) { mousePointTo = { x: stage.getPointerPosition().x / oldScale - stage.x() / oldScale, y: stage.getPointerPosition().y / oldScale - stage.y() / oldScale, }; newScale = e.evt.deltaY > 0 ? oldScale * scaleBy : oldScale / scaleBy; newPos = { x: -(mousePointTo.x - stage.getPointerPosition().x / newScale) * newScale, y: -(mousePointTo.y - stage.getPointerPosition().y / newScale) * newScale, }; } else { pos = { x: stage.width() / 2, y: stage.height() / 2, }; mousePointTo = { x: pos.x / oldScale - stage.x() / oldScale, y: pos.y / oldScale - stage.y() / oldScale, }; newScale = Math.max(0.05, oldScale * e); newPos = { x: -(mousePointTo.x - pos.x / newScale) * newScale, y: -(mousePointTo.y - pos.y / newScale) * newScale, }; } if (item.negativezoom !== true && newScale <= 1) { item.setZoom(1, 0, 0); stage.scale({ x: 1, y: 1 }); stage.position({ x: 0, y: 0 }); stage.batchDraw(); return; } stage.scale({ x: newScale, y: newScale }); item.setZoom(newScale, newPos.x, newPos.y); stage.position(newPos); stage.batchDraw(); }; renderRulers() { const { item } = this.props; const width = 1; const color = "white"; return ( <Group name="ruler" onClick={ev => { ev.cancelBubble = false; }} > <Line x={0} y={item.cursorPositionY} points={[0, 0, item.stageWidth, 0]} strokeWidth={width} stroke={color} tension={0} dash={[4, 4]} closed /> <Line x={item.cursorPositionX} y={0} points={[0, 0, 0, item.stageHeight]} strokeWidth={width} stroke={color} tension={0} dash={[1.5]} closed /> </Group> ); } onResize() { this.props.item.onResize(this.container.offsetWidth, this.container.offsetHeight, true); } componentDidMount() { window.addEventListener("resize", this.onResize); } componentWillUnmount() { window.removeEventListener("resize", this.onResize); } render() { const { item, store } = this.props; // TODO fix me if (!store.task || !item._value) return null; const cb = item.controlButton(); const c = store.completionStore.selected; const divStyle = { overflow: "hidden", // width: item.stageWidth + "px", }; const imgStyle = { width: item.width, maxWidth: item.maxwidth, transformOrigin: "left top", filter: `brightness(${item.brightnessGrade}%)`, }; if (item.zoomScale !== 1) { let { zoomingPositionX, zoomingPositionY } = item; const translate = "translate(" + zoomingPositionX + "px," + zoomingPositionY + "px) "; imgStyle["transform"] = translate + "scale(" + item.resize + ", " + item.resize + ")"; } return ( <ObjectTag item={item} style={{ position: "relative", display: "flex", alignItems: "flex-start", justifyContent: "space-between", }} > <div ref={node => { this.container = node; }} style={divStyle} > <img ref={ref => { item.setImageRef(ref); }} style={imgStyle} src={item._value} onLoad={item.updateImageSize} onClick={this.handleOnClick} alt="LS" /> </div> <Stage ref={ref => { item.setStageRef(ref); }} style={{ position: "absolute", top: 0, left: 0, brightness: "150%" }} width={item.stageWidth} height={item.stageHeight} scaleX={item.scale} scaleY={item.scale} onDblClick={this.handleDblClick} onClick={this.handleOnClick} onMouseDown={this.handleStageMouseDown} onMouseMove={this.handleMouseMove} onMouseUp={this.handleMouseUp} onWheel={item.zoom ? this.handleZoom : () => {}} > {item.grid && item.sizeUpdated && <ImageGrid item={item} />} {item.shapes.map(shape => { let brushShape; if (shape.type === "brushregion") { brushShape = ( <Layer name="brushLayer" id={shape.id}> {Tree.renderItem(shape)} </Layer> ); } return brushShape; })} <Layer> {item.shapes.filter(s => s.type !== "brushregion").map(s => Tree.renderItem(s))} {item.activeShape && Tree.renderItem(item.activeShape)} {c.edittable === true && ( <ImageTransformer rotateEnabled={cb && cb.canrotate} selectedShape={item.selectedShape} /> )} </Layer> </Stage> <div className={styles.block}> {item .getToolsManager() .allTools() .map(tool => tool.viewClass)} </div> </ObjectTag> ); } }, ); // <ImageControls // item={item} // handleZoom={this.handleZoom} // updateBrightness={this.updateBrightness} // updateGridSize={this.updateGridSize} // updateBrushControl={this.updateBrushControl} // updateBrushStrokeWidth={this.updateBrushStrokeWidth} // />