diff options
Diffstat (limited to 'src/client/views/nodes/ImageBox.tsx')
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 127 |
1 files changed, 61 insertions, 66 deletions
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 00057055f..815a3f7b2 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -14,7 +14,7 @@ import { ComputedField } from '../../../new_fields/ScriptField'; import { Cast, NumCast, StrCast } from '../../../new_fields/Types'; import { AudioField, ImageField } from '../../../new_fields/URLField'; import { TraceMobx } from '../../../new_fields/util'; -import { emptyFunction, returnOne, Utils } from '../../../Utils'; +import { emptyFunction, returnOne, Utils, returnZero } from '../../../Utils'; import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices'; import { Docs } from '../../documents/Documents'; import { Networking } from '../../Network'; @@ -24,7 +24,7 @@ import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from "../../views/ContextMenu"; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { ContextMenuProps } from '../ContextMenuItem'; -import { DocAnnotatableComponent } from '../DocComponent'; +import { ViewBoxAnnotatableComponent } from '../DocComponent'; import FaceRectangles from './FaceRectangles'; import { FieldView, FieldViewProps } from './FieldView'; import "./ImageBox.scss"; @@ -65,7 +65,7 @@ const uploadIcons = { }; @observer -export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocument>(ImageDocument) { +export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageDocument>(ImageDocument) { protected multiTouchDisposer?: import("../../util/InteractionUtils").InteractionUtils.MultiTouchEventDisposer | undefined; public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); } private _imgRef: React.RefObject<HTMLImageElement> = React.createRef(); @@ -79,10 +79,6 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this))); } - get fieldKey() { - return this.props.fieldKey.startsWith("@") ? StrCast(this.props.Document[this.props.fieldKey]) : this.props.fieldKey; - } - @undoBatch @action drop = (e: Event, de: DragManager.DropEvent) => { @@ -146,19 +142,19 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum @undoBatch rotate = action(() => { - const nw = NumCast(this.Document[this.fieldKey + "-nativeWidth"]); - const nh = NumCast(this.Document[this.fieldKey + "-nativeHeight"]); - const w = this.Document._width; - const h = this.Document._height; + const nw = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]); + const nh = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]); + const w = this.layoutDoc._width; + const h = this.layoutDoc._height; this.dataDoc[this.fieldKey + "-rotation"] = (NumCast(this.dataDoc[this.fieldKey + "-rotation"]) + 90) % 360; this.dataDoc[this.fieldKey + "-nativeWidth"] = nh; this.dataDoc[this.fieldKey + "-nativeHeight"] = nw; - this.Document._width = h; - this.Document._height = w; + this.layoutDoc._width = h; + this.layoutDoc._height = w; }); specificContextMenu = (e: React.MouseEvent): void => { - const field = Cast(this.Document[this.fieldKey], ImageField); + const field = Cast(this.dataDoc[this.fieldKey], ImageField); if (field) { const funcs: ContextMenuProps[] = []; funcs.push({ description: "Copy path", event: () => Utils.CopyText(field.url.href), icon: "expand-arrows-alt" }); @@ -190,9 +186,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum extractFaces = () => { 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; + return results.map((face: CognitiveServices.Image.Face) => Docs.Get.FromJson({ data: face, title: `Face: ${face.faceId}` })!); }; this.url && CognitiveServices.Image.Appliers.ProcessImage(this.dataDoc, [this.fieldKey + "-faces"], this.url, Service.Face, converter); } @@ -243,12 +237,13 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum } @action onError = (error: any) => { const timeout = this._curSuffix === "_s" ? this._smallRetryCount : this._curSuffix === "_m" ? this._mediumRetryCount : this._largeRetryCount; - if (timeout < 10) { - // setTimeout(this.retryPath, 500); - } - const original = StrCast(this.dataDoc.originalUrl); - if (error.type === "error" && original) { - this.dataDoc[this.fieldKey] = new ImageField(original); + if (timeout < 5) { + setTimeout(this.retryPath, 500); + } else { + const original = StrCast(this.dataDoc[this.fieldKey + "-originalUrl"]); + if (error.type === "error" && original) { + this.dataDoc[this.fieldKey] = new ImageField(original); + } } } _curSuffix = "_m"; @@ -258,31 +253,29 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum width: NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]), height: NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]) }; - const docAspect = this.Document[HeightSym]() / this.Document[WidthSym](); + const docAspect = this.layoutDoc[HeightSym]() / this.layoutDoc[WidthSym](); const cachedAspect = cachedNativeSize.height / cachedNativeSize.width; if (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(NumCast(this.layoutDoc._width) / NumCast(this.layoutDoc._height) - cachedNativeSize.width / cachedNativeSize.height) > 0.05) { if (!this.layoutDoc.isTemplateDoc || this.dataDoc !== this.layoutDoc) { - requestImageSize(imgPath).then((inquiredSize: any) => { + requestImageSize(imgPath).then(action((inquiredSize: any) => { const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]) % 180; const rotatedNativeSize = rotation === 90 || rotation === 270 ? { height: inquiredSize.width, width: inquiredSize.height } : inquiredSize; const rotatedAspect = rotatedNativeSize.height / rotatedNativeSize.width; - 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.fieldKey + "-nativeWidth"] = this.Document._nativeWidth = rotatedNativeSize.width; - this.dataDoc[this.fieldKey + "-nativeHeight"] = this.Document._nativeHeight = rotatedNativeSize.height; - } - }), 0); - }).catch((err: any) => console.log(err)); + if (this.layoutDoc[WidthSym]() && (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(1 - docAspect / rotatedAspect) > 0.1)) { + this.layoutDoc._height = this.layoutDoc[WidthSym]() * rotatedAspect; + this.dataDoc[this.fieldKey + "-nativeWidth"] = this.layoutDoc._nativeWidth = this.layoutDoc._width; + this.dataDoc[this.fieldKey + "-nativeHeight"] = this.layoutDoc._nativeHeight = this.layoutDoc._height; + } + })).catch(console.log); } else if (Math.abs(1 - docAspect / cachedAspect) > 0.1) { - this.Document._width = this.Document[WidthSym]() || cachedNativeSize.width; - this.Document._height = this.Document[WidthSym]() * cachedAspect; + this.layoutDoc._width = this.layoutDoc[WidthSym]() || cachedNativeSize.width; + this.layoutDoc._height = this.layoutDoc[WidthSym]() * cachedAspect; } - } else if (this.Document._nativeWidth !== cachedNativeSize.width || this.Document._nativeHeight !== cachedNativeSize.height) { - !(this.Document[StrCast(this.props.Document.layoutKey)] instanceof Doc) && setTimeout(() => { - if (!(this.Document[StrCast(this.props.Document.layoutKey)] instanceof Doc)) { - this.Document._nativeWidth = cachedNativeSize.width; - this.Document._nativeHeight = cachedNativeSize.height; + } else if (this.layoutDoc._nativeWidth !== cachedNativeSize.width || this.layoutDoc._nativeHeight !== cachedNativeSize.height) { + !(this.layoutDoc[StrCast(this.layoutDoc.layoutKey)] instanceof Doc) && setTimeout(() => { + if (!(this.layoutDoc[StrCast(this.layoutDoc.layoutKey)] instanceof Doc)) { + this.layoutDoc._nativeWidth = cachedNativeSize.width; + this.layoutDoc._nativeHeight = cachedNativeSize.height; } }, 0); } @@ -311,8 +304,9 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum audioDown = () => this.recordAudioAnnotation(); considerGooglePhotosLink = () => { - const remoteUrl = this.Document.googlePhotosUrl; + const remoteUrl = this.dataDoc.googlePhotosUrl; return !remoteUrl ? (null) : (<img + style={{ transform: `scale(${this.props.ContentScaling()})`, transformOrigin: "bottom right" }} id={"google-photos"} src={"/assets/google_photos.png"} onClick={() => window.open(remoteUrl)} @@ -320,7 +314,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum } considerGooglePhotosTags = () => { - const tags = this.Document.googlePhotosTags; + const tags = this.dataDoc.googlePhotosTags; return !tags ? (null) : (<img id={"google-tags"} src={"/assets/google_tags.png"} />); } @@ -337,13 +331,14 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum return ( <img id={"upload-icon"} + style={{ transform: `scale(${1 / this.props.ContentScaling()})`, transformOrigin: "bottom right" }} src={`/assets/${this.uploadIcon}`} onClick={async () => { const { dataDoc } = this; const { success, failure, idle, loading } = uploadIcons; runInAction(() => this.uploadIcon = loading); const [{ accessPaths }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [primary] }); - dataDoc.originalUrl = primary; + dataDoc[this.props.fieldKey + "-originalUrl"] = primary; let succeeded = true; let data: ImageField | undefined; try { @@ -370,38 +365,35 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum return { nativeWidth, nativeHeight }; } + // this._curSuffix = ""; + // if (w > 20) { + // 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"; @computed get paths() { - let paths = [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")]; - // this._curSuffix = ""; - // if (w > 20) { - const alts = DocListCast(this.dataDoc[this.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.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); - return paths; + const field = Cast(this.dataDoc[this.fieldKey], ImageField, null); // retrieve the primary image URL that is being rendered from the data doc + const alts = DocListCast(this.dataDoc[this.fieldKey + "-alternates"]); // retrieve alternate documents that may be rendered as alternate images + const altpaths = alts.map(doc => Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url.href).filter(url => url); // access the primary layout data of the alternate documents + const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths; + return paths.length ? paths : [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")]; } @computed get content() { TraceMobx(); - const srcpath = this.paths[NumCast(this.props.Document.curPage, 0)]; + const srcpath = this.paths[0]; const fadepath = this.paths[Math.min(1, this.paths.length - 1)]; const { nativeWidth, nativeHeight } = this.nativeSize; const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]); - const aspect = (rotation % 180) ? this.Document[HeightSym]() / this.Document[WidthSym]() : 1; - const shift = (rotation % 180) ? (nativeHeight - nativeWidth / aspect) / 2 : 0; - + const aspect = (rotation % 180) ? nativeHeight / nativeWidth : 1; + const shift = (rotation % 180) ? (nativeHeight - nativeWidth) * (1 - 1 / aspect) : 0; this.resize(srcpath); - return <div className="imageBox-cont" key={this.props.Document[Id]} ref={this.createDropTarget}> + return <div className="imageBox-cont" key={this.layoutDoc[Id]} ref={this.createDropTarget}> <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})` }} + style={{ transform: `scale(${aspect}) translate(0px, ${shift}px) rotate(${rotation}deg)` }} width={nativeWidth} ref={this._imgRef} onError={this.onError} /> @@ -414,7 +406,7 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum ref={this._imgRef} onError={this.onError} /></div>} </div> - {!this.props.Document._showAudio ? (null) : + {!this.layoutDoc._showAudio ? (null) : <div className="imageBox-audioBackground" onPointerDown={this.audioDown} onPointerEnter={this.onPointerEnter} @@ -436,15 +428,18 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum 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()}%`, - pointerEvents: this.props.Document.isBackground ? "none" : undefined, + transform: this.props.PanelWidth() ? undefined : `scale(${this.props.ContentScaling()})`, + width: this.props.PanelWidth() ? undefined : `${100 / this.props.ContentScaling()}%`, + height: this.props.PanelWidth() ? undefined : `${100 / this.props.ContentScaling()}%`, + pointerEvents: this.layoutDoc.isBackground ? "none" : undefined, borderRadius: `${Number(StrCast(this.layoutDoc.borderRounding).replace("px", "")) / this.props.ContentScaling()}px` }} > <CollectionFreeFormView {...this.props} + forceScaling={true} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth} + NativeHeight={returnZero} + NativeWidth={returnZero} annotationsKey={this.annotationKey} isAnnotationOverlay={true} focus={this.props.focus} |