aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/ImageBox.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/ImageBox.tsx')
-rw-r--r--src/client/views/nodes/ImageBox.tsx318
1 files changed, 200 insertions, 118 deletions
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index fa8eb7736..207546936 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -4,14 +4,13 @@ import { faAsterisk, faFileAudio, faImage, faPaintBrush, faBrain } from '@fortaw
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, observable, runInAction, trace } from 'mobx';
import { observer } from "mobx-react";
-import { Doc, DocListCast, HeightSym, WidthSym } from '../../../new_fields/Doc';
+import { Doc, DocListCast, HeightSym, WidthSym, DataSym } from '../../../new_fields/Doc';
import { List } from '../../../new_fields/List';
import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema';
import { ComputedField } from '../../../new_fields/ScriptField';
-import { BoolCast, Cast, FieldValue, NumCast, StrCast } from '../../../new_fields/Types';
+import { Cast, NumCast, StrCast } from '../../../new_fields/Types';
import { AudioField, ImageField } from '../../../new_fields/URLField';
-import { RouteStore } from '../../../server/RouteStore';
-import { Utils, returnOne, emptyFunction, OmitKeys } from '../../../Utils';
+import { Utils, returnOne, emptyFunction } from '../../../Utils';
import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices';
import { Docs } from '../../documents/Documents';
import { DragManager } from '../../util/DragManager';
@@ -19,7 +18,6 @@ import { undoBatch } from '../../util/UndoManager';
import { ContextMenu } from "../../views/ContextMenu";
import { ContextMenuProps } from '../ContextMenuItem';
import { DocAnnotatableComponent } from '../DocComponent';
-import { InkingControl } from '../InkingControl';
import FaceRectangles from './FaceRectangles';
import { FieldView, FieldViewProps } from './FieldView';
import "./ImageBox.scss";
@@ -28,9 +26,14 @@ import { SearchUtil } from '../../util/SearchUtil';
import { ClientRecommender } from '../../ClientRecommender';
import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
import { documentSchema } from '../../../new_fields/documentSchemas';
-import { Id } from '../../../new_fields/FieldSymbols';
-var requestImageSize = require('../../util/request-image-size');
-var path = require('path');
+import { Id, Copy } from '../../../new_fields/FieldSymbols';
+import { TraceMobx } from '../../../new_fields/util';
+import { SelectionManager } from '../../util/SelectionManager';
+import { cache } from 'sharp';
+import { ObjectField } from '../../../new_fields/ObjectField';
+import { Networking } from '../../Network';
+const requestImageSize = require('../../util/request-image-size');
+const path = require('path');
const { Howl } = require('howler');
@@ -41,7 +44,6 @@ library.add(faFileAudio, faAsterisk);
export const pageSchema = createSchema({
curPage: "number",
fitWidth: "boolean",
- rotation: "number",
googlePhotosUrl: "string",
googlePhotosTags: "string"
});
@@ -58,6 +60,13 @@ declare class MediaRecorder {
type ImageDocument = makeInterface<[typeof pageSchema, typeof documentSchema]>;
const ImageDocument = makeInterface(pageSchema, documentSchema);
+const uploadIcons = {
+ idle: "downarrow.png",
+ loading: "loading.gif",
+ success: "greencheck.png",
+ failure: "redx.png"
+};
+
@observer
export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocument>(ImageDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); }
@@ -65,33 +74,40 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
private _dropDisposer?: DragManager.DragDropDisposer;
@observable private _audioState = 0;
@observable static _showControls: boolean;
+ @observable uploadIcon = uploadIcons.idle;
protected createDropTarget = (ele: HTMLDivElement) => {
this._dropDisposer && this._dropDisposer();
- ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } }));
+ ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)));
}
@undoBatch
@action
drop = (e: Event, de: DragManager.DropEvent) => {
- if (de.data instanceof DragManager.DocumentDragData) {
- if (de.mods === "AltKey" && de.data.draggedDocuments.length && de.data.draggedDocuments[0].data instanceof ImageField) {
- Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new ImageField(de.data.draggedDocuments[0].data.url);
- e.stopPropagation();
+ if (de.complete.docDragData) {
+ if (de.metaKey) {
+ de.complete.docDragData.droppedDocuments.forEach(action((drop: Doc) => {
+ Doc.AddDocToList(this.dataDoc, this.props.fieldKey + "-alternates", drop);
+ e.stopPropagation();
+ }));
+ } else if (de.altKey || !this.dataDoc[this.props.fieldKey]) {
+ const layoutDoc = de.complete.docDragData?.draggedDocuments[0];
+ const targetField = Doc.LayoutFieldKey(layoutDoc);
+ if (layoutDoc?.[DataSym][targetField] instanceof ImageField) {
+ this.dataDoc[this.props.fieldKey] = ObjectField.MakeCopy(layoutDoc[DataSym][targetField] as ImageField);
+ this.dataDoc[this.props.fieldKey + "-nativeWidth"] = NumCast(layoutDoc[DataSym][targetField + "-nativeWidth"]);
+ this.dataDoc[this.props.fieldKey + "-nativeHeight"] = NumCast(layoutDoc[DataSym][targetField + "-nativeHeight"]);
+ e.stopPropagation();
+ }
}
- de.mods === "MetaKey" && de.data.droppedDocuments.forEach(action((drop: Doc) => {
- this.extensionDoc && Doc.AddDocToList(Doc.GetProto(this.extensionDoc), "Alternates", drop);
- e.stopPropagation();
- }));
}
}
recordAudioAnnotation = () => {
let gumStream: any;
let recorder: any;
- let self = this;
- const extensionDoc = this.extensionDoc;
- extensionDoc && navigator.mediaDevices.getUserMedia({
+ const self = this;
+ navigator.mediaDevices.getUserMedia({
audio: true
}).then(function (stream) {
gumStream = stream;
@@ -99,18 +115,18 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
recorder.ondataavailable = async function (e: any) {
const formData = new FormData();
formData.append("file", e.data);
- const res = await fetch(Utils.prepend(RouteStore.upload), {
+ const res = await fetch(Utils.prepend("/uploadFormData"), {
method: 'POST',
body: formData
});
const files = await res.json();
const url = Utils.prepend(files[0].path);
// upload to server with known URL
- let audioDoc = Docs.Create.AudioDocument(url, { title: "audio test", width: 200, height: 32 });
+ const audioDoc = Docs.Create.AudioDocument(url, { title: "audio test", _width: 200, _height: 32 });
audioDoc.treeViewExpandedView = "layout";
- let audioAnnos = Cast(extensionDoc.audioAnnotations, listSpec(Doc));
+ const audioAnnos = Cast(this.dataDoc[this.props.fieldKey + "-audioAnnotations"], listSpec(Doc));
if (audioAnnos === undefined) {
- extensionDoc.audioAnnotations = new List([audioDoc]);
+ this.dataDoc[this.props.fieldKey + "-audioAnnotations"] = new List([audioDoc]);
} else {
audioAnnos.push(audioDoc);
}
@@ -127,26 +143,26 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
@undoBatch
rotate = action(() => {
- let nw = this.Document.nativeWidth;
- let nh = this.Document.nativeHeight;
- let w = this.Document.width;
- let h = this.Document.height;
- this.Document.rotation = ((this.Document.rotation || 0) + 90) % 360;
- this.Document.nativeWidth = nh;
- this.Document.nativeHeight = nw;
- this.Document.width = h;
- this.Document.height = w;
+ const nw = NumCast(this.Document[this.props.fieldKey + "-nativeWidth"]);
+ const nh = NumCast(this.Document[this.props.fieldKey + "-nativeHeight"]);
+ const w = this.Document._width;
+ const h = this.Document._height;
+ this.dataDoc[this.props.fieldKey + "-rotation"] = (NumCast(this.dataDoc[this.props.fieldKey + "-rotation"]) + 90) % 360;
+ this.dataDoc[this.props.fieldKey + "-nativeWidth"] = nh;
+ this.dataDoc[this.props.fieldKey + "-nativeHeight"] = nw;
+ this.Document._width = h;
+ this.Document._height = w;
});
specificContextMenu = (e: React.MouseEvent): void => {
const field = Cast(this.Document[this.props.fieldKey], ImageField);
if (field) {
- let funcs: ContextMenuProps[] = [];
+ const funcs: ContextMenuProps[] = [];
funcs.push({ description: "Copy path", event: () => Utils.CopyText(field.url.href), icon: "expand-arrows-alt" });
funcs.push({ description: "Rotate", event: this.rotate, icon: "expand-arrows-alt" });
- let existingAnalyze = ContextMenu.Instance.findByDescription("Analyzers...");
- let modes: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : [];
+ const existingAnalyze = ContextMenu.Instance.findByDescription("Analyzers...");
+ const modes: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : [];
modes.push({ description: "Generate Tags", event: this.generateMetadata, icon: "tag" });
modes.push({ description: "Find Faces", event: this.extractFaces, icon: "camera" });
//modes.push({ description: "Recommend", event: this.extractText, icon: "brain" });
@@ -157,33 +173,33 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
}
extractFaces = () => {
- let converter = (results: any) => {
- let faceDocs = new List<Doc>();
+ const converter = (results: any) => {
+ const faceDocs = new List<Doc>();
results.reduce((face: CognitiveServices.Image.Face, faceDocs: List<Doc>) => faceDocs.push(Docs.Get.DocumentHierarchyFromJson(face, `Face: ${face.faceId}`)!), new List<Doc>());
return faceDocs;
};
- this.url && this.extensionDoc && CognitiveServices.Image.Appliers.ProcessImage(this.extensionDoc, ["faces"], this.url, Service.Face, converter);
+ this.url && CognitiveServices.Image.Appliers.ProcessImage(this.dataDoc, [this.props.fieldKey + "-faces"], this.url, Service.Face, converter);
}
generateMetadata = (threshold: Confidence = Confidence.Excellent) => {
- let converter = (results: any) => {
- let tagDoc = new Doc;
- let tagsList = new List();
+ const converter = (results: any) => {
+ const tagDoc = new Doc;
+ const tagsList = new List();
results.tags.map((tag: Tag) => {
tagsList.push(tag.name);
- let sanitized = tag.name.replace(" ", "_");
+ const sanitized = tag.name.replace(" ", "_");
tagDoc[sanitized] = ComputedField.MakeFunction(`(${tag.confidence} >= this.confidence) ? ${tag.confidence} : "${ComputedField.undefined}"`);
});
- this.extensionDoc && (this.extensionDoc.generatedTags = tagsList);
+ this.dataDoc[this.props.fieldKey + "-generatedTags"] = tagsList;
tagDoc.title = "Generated Tags Doc";
tagDoc.confidence = threshold;
return tagDoc;
};
- this.url && this.extensionDoc && CognitiveServices.Image.Appliers.ProcessImage(this.extensionDoc, ["generatedTagsDoc"], this.url, Service.ComputerVision, converter);
+ this.url && CognitiveServices.Image.Appliers.ProcessImage(this.dataDoc, [this.props.fieldKey + "-generatedTagsDoc"], this.url, Service.ComputerVision, converter);
}
@computed private get url() {
- let data = Cast(this.dataDoc[this.props.fieldKey], ImageField);
+ const data = Cast(this.dataDoc[this.props.fieldKey], ImageField);
return data ? data.url.href : undefined;
}
@@ -196,7 +212,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
} else if (!(lower.endsWith(".png") || lower.endsWith(".jpg") || lower.endsWith(".jpeg"))) {
return url.href;//Why is this here
}
- let ext = path.extname(url.href);
+ const ext = path.extname(url.href);
const suffix = this.props.renderDepth < 1 ? "_o" : this._curSuffix;
return url.href.replace(ext, suffix + ext);
}
@@ -209,37 +225,54 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
if (this._curSuffix === "_m") this._mediumRetryCount++;
if (this._curSuffix === "_l") this._largeRetryCount++;
}
- @action onError = () => {
- let timeout = this._curSuffix === "_s" ? this._smallRetryCount : this._curSuffix === "_m" ? this._mediumRetryCount : this._largeRetryCount;
+ @action onError = (error: any) => {
+ const timeout = this._curSuffix === "_s" ? this._smallRetryCount : this._curSuffix === "_m" ? this._mediumRetryCount : this._largeRetryCount;
if (timeout < 10) {
- setTimeout(this.retryPath, Math.min(10000, timeout * 5));
+ // setTimeout(this.retryPath, 500);
+ }
+ const original = StrCast(this.dataDoc.originalUrl);
+ if (error.type === "error" && original) {
+ this.dataDoc[this.props.fieldKey] = new ImageField(original);
}
}
_curSuffix = "_m";
- resize = (srcpath: string) => {
- requestImageSize(srcpath)
- .then((size: any) => {
- let rotation = NumCast(this.dataDoc.rotation) % 180;
- let realsize = rotation === 90 || rotation === 270 ? { height: size.width, width: size.height } : size;
- let aspect = realsize.height / realsize.width;
- if (this.Document.width && (Math.abs(1 - NumCast(this.Document.height) / NumCast(this.Document.width) / (realsize.height / realsize.width)) > 0.1)) {
- setTimeout(action(() => {
- this.Document.height = this.Document[WidthSym]() * aspect;
- this.Document.nativeHeight = realsize.height;
- this.Document.nativeWidth = realsize.width;
- }), 0);
- }
+ resize = (imgPath: string) => {
+ const cachedNativeSize = {
+ width: NumCast(this.dataDoc[this.props.fieldKey + "-nativeWidth"]),
+ height: NumCast(this.dataDoc[this.props.fieldKey + "-nativeHeight"])
+ };
+ const cachedImgPath = this.dataDoc[this.props.fieldKey + "-imgPath"];
+ if (!cachedNativeSize.width || !cachedNativeSize.height || imgPath !== cachedImgPath) {
+ (!this.layoutDoc.isTemplateDoc || this.dataDoc !== this.layoutDoc) && requestImageSize(imgPath).then((inquiredSize: any) => {
+ const rotation = NumCast(this.dataDoc[this.props.fieldKey + "-rotation"]) % 180;
+ const rotatedNativeSize = rotation === 90 || rotation === 270 ? { height: inquiredSize.width, width: inquiredSize.height } : inquiredSize;
+ const rotatedAspect = rotatedNativeSize.height / rotatedNativeSize.width;
+ const docAspect = this.Document[HeightSym]() / this.Document[WidthSym]();
+ setTimeout(action(() => {
+ if (this.Document[WidthSym]() && (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(1 - docAspect / rotatedAspect) > 0.1)) {
+ this.Document._height = this.Document[WidthSym]() * rotatedAspect;
+ this.dataDoc[this.props.fieldKey + "-nativeWidth"] = this.Document._nativeWidth = rotatedNativeSize.width;
+ this.dataDoc[this.props.fieldKey + "-nativeHeight"] = this.Document._nativeHeight = rotatedNativeSize.height;
+ }
+ this.dataDoc[this.props.fieldKey + "-imgPath"] = imgPath;
+ }), 0);
})
- .catch((err: any) => console.log(err));
+ .catch((err: any) => console.log(err));
+ } else if (this.Document._nativeHeight !== cachedNativeSize.width || this.Document._nativeWidth !== cachedNativeSize.height) {
+ !(this.Document[StrCast(this.props.Document.layoutKey)] instanceof Doc) && setTimeout(() => {
+ this.Document._nativeWidth = cachedNativeSize.width;
+ this.Document._nativeHeight = cachedNativeSize.height;
+ }, 0);
+ }
}
@action
onPointerEnter = () => {
- let self = this;
- let audioAnnos = this.extensionDoc && DocListCast(this.extensionDoc.audioAnnotations);
+ const self = this;
+ const audioAnnos = DocListCast(this.dataDoc[this.props.fieldKey + "-audioAnnotations"]);
if (audioAnnos && audioAnnos.length && this._audioState === 0) {
- let anno = audioAnnos[Math.floor(Math.random() * audioAnnos.length)];
+ const anno = audioAnnos[Math.floor(Math.random() * audioAnnos.length)];
anno.data instanceof AudioField && new Howl({
src: [anno.data.url.href],
format: ["mp3"],
@@ -270,80 +303,130 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
return !tags ? (null) : (<img id={"google-tags"} src={"/assets/google_tags.png"} />);
}
- @computed get content() {
- const extensionDoc = this.extensionDoc;
- if (!extensionDoc) return (null);
- // let transform = this.props.ScreenToLocalTransform().inverse();
- let pw = typeof this.props.PanelWidth === "function" ? this.props.PanelWidth() : typeof this.props.PanelWidth === "number" ? (this.props.PanelWidth as any) as number : 50;
- // var [sptX, sptY] = transform.transformPoint(0, 0);
- // let [bptX, bptY] = transform.transformPoint(pw, this.props.PanelHeight());
- // let w = bptX - sptX;
-
- let nativeWidth = (this.Document.nativeWidth || pw);
- let nativeHeight = (this.Document.nativeHeight || 0);
+ @computed
+ private get considerDownloadIcon() {
+ const data = this.dataDoc[this.props.fieldKey];
+ if (!(data instanceof ImageField)) {
+ return (null);
+ }
+ const primary = data.url.href;
+ if (primary.includes(window.location.origin)) {
+ return (null);
+ }
+ return (
+ <img
+ id={"upload-icon"}
+ src={`/assets/${this.uploadIcon}`}
+ onClick={async () => {
+ const { dataDoc } = this;
+ const { success, failure, idle, loading } = uploadIcons;
+ runInAction(() => this.uploadIcon = loading);
+ const [{ clientAccessPath }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [primary] });
+ dataDoc.originalUrl = primary;
+ let succeeded = true;
+ let data: ImageField | undefined;
+ try {
+ data = new ImageField(Utils.prepend(clientAccessPath));
+ } catch {
+ succeeded = false;
+ }
+ runInAction(() => this.uploadIcon = succeeded ? success : failure);
+ setTimeout(action(() => {
+ this.uploadIcon = idle;
+ if (data) {
+ dataDoc[this.props.fieldKey] = data;
+ }
+ }), 2000);
+ }}
+ />
+ );
+ }
+
+ @computed get nativeSize() {
+ const pw = typeof this.props.PanelWidth === "function" ? this.props.PanelWidth() : typeof this.props.PanelWidth === "number" ? (this.props.PanelWidth as any) as number : 50;
+ const nativeWidth = NumCast(this.dataDoc[this.props.fieldKey + "-nativeWidth"], pw);
+ const nativeHeight = NumCast(this.dataDoc[this.props.fieldKey + "-nativeHeight"], 1);
+ return { nativeWidth, nativeHeight };
+ }
+
+ @computed get paths() {
let paths = [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")];
// this._curSuffix = "";
// if (w > 20) {
- let alts = DocListCast(extensionDoc.Alternates);
- let altpaths = alts.filter(doc => doc.data instanceof ImageField).map(doc => this.choosePath((doc.data as ImageField).url));
- let field = this.dataDoc[this.props.fieldKey];
+ const alts = DocListCast(this.dataDoc[this.props.fieldKey + "-alternates"]);
+ const altpaths = alts.filter(doc => doc.data instanceof ImageField).map(doc => this.choosePath((doc.data as ImageField).url));
+ const field = this.dataDoc[this.props.fieldKey];
// if (w < 100 && this._smallRetryCount < 10) this._curSuffix = "_s";
// else if (w < 600 && this._mediumRetryCount < 10) this._curSuffix = "_m";
// else if (this._largeRetryCount < 10) this._curSuffix = "_l";
if (field instanceof ImageField) paths = [this.choosePath(field.url)];
paths.push(...altpaths);
- // }
- let interactive = InkingControl.Instance.selectedTool || this.Document.isBackground ? "" : "-interactive";
- let rotation = NumCast(this.Document.rotation, 0);
- let aspect = (rotation % 180) ? this.Document[HeightSym]() / this.Document[WidthSym]() : 1;
- let shift = (rotation % 180) ? (nativeHeight - nativeWidth / aspect) / 2 : 0;
- let srcpath = paths[Math.min(paths.length - 1, (this.Document.curPage || 0))];
- let fadepath = paths[Math.min(paths.length - 1, 1)];
+ return paths;
+ }
+
+ @computed get content() {
+ TraceMobx();
+
+ const srcpath = this.paths[NumCast(this.props.Document.curPage, 0)];
+ const fadepath = this.paths[Math.min(1, this.paths.length - 1)];
+ const { nativeWidth, nativeHeight } = this.nativeSize;
+ const rotation = NumCast(this.dataDoc[this.props.fieldKey + "-rotation"]);
+ const aspect = (rotation % 180) ? this.Document[HeightSym]() / this.Document[WidthSym]() : 1;
+ const shift = (rotation % 180) ? (nativeHeight - nativeWidth / aspect) / 2 : 0;
!this.Document.ignoreAspect && this.resize(srcpath);
- return (
- <div className={`imageBox-cont${interactive}`} key={this.props.Document[Id]} ref={this.createDropTarget} onContextMenu={this.specificContextMenu}>
- <div id="cf">
- <img
- key={this._smallRetryCount + (this._mediumRetryCount << 4) + (this._largeRetryCount << 8)} // force cache to update on retrys
- src={srcpath}
- style={{ transform: `translate(0px, ${shift}px) rotate(${rotation}deg) scale(${aspect})` }}
- width={nativeWidth}
- ref={this._imgRef}
- onError={this.onError} />
- {fadepath === srcpath ? (null) : <div className="imageBox-fadeBlocker"> <img className="imageBox-fadeaway"
+ return <div className="imageBox-cont" key={this.props.Document[Id]} ref={this.createDropTarget} onContextMenu={this.specificContextMenu}>
+ <div className="imageBox-fader" >
+ <img key={this._smallRetryCount + (this._mediumRetryCount << 4) + (this._largeRetryCount << 8)} // force cache to update on retrys
+ src={srcpath}
+ style={{ transform: `translate(0px, ${shift}px) rotate(${rotation}deg) scale(${aspect})` }}
+ width={nativeWidth}
+ ref={this._imgRef}
+ onError={this.onError} />
+ {fadepath === srcpath ? (null) : <div className="imageBox-fadeBlocker">
+ <img className="imageBox-fadeaway"
key={"fadeaway" + this._smallRetryCount + (this._mediumRetryCount << 4) + (this._largeRetryCount << 8)} // force cache to update on retrys
src={fadepath}
- style={{ transform: `translate(0px, ${shift}px) rotate(${rotation}deg) scale(${aspect})` }}
+ style={{ transform: `translate(0px, ${shift}px) rotate(${rotation}deg) scale(${aspect})`, }}
width={nativeWidth}
ref={this._imgRef}
onError={this.onError} /></div>}
- </div>
- <div className="imageBox-audioBackground"
- onPointerDown={this.audioDown}
- onPointerEnter={this.onPointerEnter}
- style={{ height: `calc(${.1 * nativeHeight / nativeWidth * 100}%)` }}
- >
- <FontAwesomeIcon className="imageBox-audioFont"
- style={{ color: [DocListCast(extensionDoc.audioAnnotations).length ? "blue" : "gray", "green", "red"][this._audioState] }} icon={!DocListCast(extensionDoc.audioAnnotations).length ? "microphone" : faFileAudio} size="sm" />
- </div>
- {this.considerGooglePhotosLink()}
- <FaceRectangles document={extensionDoc} color={"#0000FF"} backgroundColor={"#0000FF"} />
- </div>);
+ </div>
+ <div className="imageBox-audioBackground"
+ onPointerDown={this.audioDown}
+ onPointerEnter={this.onPointerEnter}
+ style={{ height: `calc(${.1 * nativeHeight / nativeWidth * 100}%)` }}
+ >
+ <FontAwesomeIcon className="imageBox-audioFont"
+ style={{ color: [DocListCast(this.dataDoc[this.props.fieldKey + "-audioAnnotations"]).length ? "blue" : "gray", "green", "red"][this._audioState] }}
+ icon={!DocListCast(this.dataDoc[this.props.fieldKey + "-audioAnnotations"]).length ? "microphone" : faFileAudio} size="sm" />
+ </div>
+ {this.considerDownloadIcon}
+ {this.considerGooglePhotosLink()}
+ <FaceRectangles document={this.dataDoc} color={"#0000FF"} backgroundColor={"#0000FF"} />
+ </div>;
}
+ contentFunc = () => [this.content];
render() {
- return (<div className={"imageBox-container"} onContextMenu={this.specificContextMenu}>
+ TraceMobx();
+ const dragging = !SelectionManager.GetIsDragging() ? "" : "-dragging";
+ return (<div className={`imageBox${dragging}`} onContextMenu={this.specificContextMenu}
+ style={{
+ transform: `scale(${this.props.ContentScaling()})`,
+ width: `${100 / this.props.ContentScaling()}%`,
+ height: `${100 / this.props.ContentScaling()}%`
+ }} >
<CollectionFreeFormView {...this.props}
PanelHeight={this.props.PanelHeight}
PanelWidth={this.props.PanelWidth}
- annotationsKey={this.annotationsKey}
+ annotationsKey={this.annotationKey}
isAnnotationOverlay={true}
focus={this.props.focus}
isSelected={this.props.isSelected}
select={emptyFunction}
- active={this.active}
+ active={this.annotationsActive}
ContentScaling={returnOne}
whenActiveChanged={this.whenActiveChanged}
removeDocument={this.removeDocument}
@@ -351,11 +434,10 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
addDocument={this.addDocument}
CollectionView={undefined}
ScreenToLocalTransform={this.props.ScreenToLocalTransform}
- ruleProvider={undefined}
renderDepth={this.props.renderDepth + 1}
ContainingCollectionDoc={this.props.ContainingCollectionDoc}
chromeCollapsed={true}>
- {() => [this.content]}
+ {this.contentFunc}
</CollectionFreeFormView>
</div >);
}