From e4eac6e4256dc320f6c767ecbad54b83459c4331 Mon Sep 17 00:00:00 2001 From: zaultavangar Date: Mon, 11 Dec 2023 14:46:58 -0500 Subject: updates to map feature --- .../views/nodes/MapboxMapBox/MapboxContainer.tsx | 844 +++++++++++++++++++++ 1 file changed, 844 insertions(+) create mode 100644 src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx (limited to 'src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx') diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx new file mode 100644 index 000000000..a6182991d --- /dev/null +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -0,0 +1,844 @@ +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import BingMapsReact from 'bingmaps-react'; +import { Button, EditableText, IconButton, Type } from 'browndash-components'; +import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { Doc, DocListCast, Field, LinkedTo, Opt } from '../../../../fields/Doc'; +import { DocCss, Highlight } from '../../../../fields/DocSymbols'; +import { Id } from '../../../../fields/FieldSymbols'; +import { DocCast, NumCast, StrCast } from '../../../../fields/Types'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils'; +import { Docs, DocUtils } from '../../../documents/Documents'; +import { DocumentType } from '../../../documents/DocumentTypes'; +import { DocumentManager } from '../../../util/DocumentManager'; +import { DragManager } from '../../../util/DragManager'; +import { LinkManager } from '../../../util/LinkManager'; +import { SnappingManager } from '../../../util/SnappingManager'; +import { Transform } from '../../../util/Transform'; +import { undoable, UndoManager } from '../../../util/UndoManager'; +import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; +import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; +import { Colors } from '../../global/globalEnums'; +import { SidebarAnnos } from '../../SidebarAnnos'; +import { DocumentView } from '../DocumentView'; +import { FieldView, FieldViewProps } from '../FieldView'; +import { FormattedTextBox } from '../formattedText/FormattedTextBox'; +import { PinProps, PresBox } from '../trails'; +import './MapBox.scss'; +import { MapAnchorMenu } from '../MapBox/MapAnchorMenu'; +import { MapProvider, Map as MapboxMap } from 'react-map-gl'; + +// amongus +/** + * MapBox architecture: + * Main component: MapBox.tsx + * Supporting Components: SidebarAnnos, CollectionStackingView + * + * MapBox is a node that extends the ViewBoxAnnotatableComponent. Similar to PDFBox and WebBox, it supports interaction between sidebar content and document content. + * The main body of MapBox uses Google Maps API to allow location retrieval, adding map markers, pan and zoom, and open street view. + * Dash Document architecture is integrated with Maps API: When drag and dropping documents with ExifData (gps Latitude and Longitude information) available, + * sidebarAddDocument function checks if the document contains lat & lng information, if it does, then the document is added to both the sidebar and the infowindow (a pop up corresponding to a map marker--pin on map). + * The lat and lng field of the document is filled when importing (spec see ConvertDMSToDD method and processFileUpload method in Documents.ts). + * A map marker is considered a document that contains a collection with stacking view of documents, it has a lat, lng location, which is passed to Maps API's custom marker (red pin) to be rendered on the google maps + */ + +const mapboxApiKey = "pk.eyJ1IjoiemF1bHRhdmFuZ2FyIiwiYSI6ImNsbnc2eHJpbTA1ZTUyam85aGx4Z2FhbGwifQ.2Kqw9mk-9wAAg9kmHmKzcg"; +const bingApiKey = process.env.BING_MAPS; // if you're running local, get a Bing Maps api key here: https://www.bingmapsportal.com/ and then add it to the .env file in the Dash-Web root directory as: _CLIENT_BING_MAPS= + +/** + * Consider integrating later: allows for drawing, circling, making shapes on map + */ +// const drawingManager = new window.google.maps.drawing.DrawingManager({ +// drawingControl: true, +// drawingControlOptions: { +// position: google.maps.ControlPosition.TOP_RIGHT, +// drawingModes: [ +// google.maps.drawing.OverlayType.MARKER, +// // currently we are not supporting the following drawing mode on map, a thought for future development +// google.maps.drawing.OverlayType.CIRCLE, +// google.maps.drawing.OverlayType.POLYLINE, +// ], +// }, +// }); + +@observer +export class MapBoxContainer extends ViewBoxAnnotatableComponent() { + public static LayoutString(fieldKey: string) { + return FieldView.LayoutString(MapBoxContainer, fieldKey); + } + private _dragRef = React.createRef(); + private _sidebarRef = React.createRef(); + private _ref: React.RefObject = React.createRef(); + private _disposers: { [key: string]: IReactionDisposer } = {}; + private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt) => void); + + @observable private _savedAnnotations = new ObservableMap(); + @computed get allSidebarDocs() { + return DocListCast(this.dataDoc[this.SidebarKey]); + } + // this list contains pushpins and configs + @computed get allAnnotations() { + return DocListCast(this.dataDoc[this.annotationKey]); + } + @computed get allPushpins() { + return this.allAnnotations.filter(anno => anno.type === DocumentType.PUSHPIN); + } + @computed get SidebarShown() { + return this.layoutDoc._layout_showSidebar ? true : false; + } + @computed get sidebarWidthPercent() { + return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%'); + } + @computed get sidebarColor() { + return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4')); + } + @computed get SidebarKey() { + return this.fieldKey + '_sidebar'; + } + + componentDidMount() { + this._unmounting = false; + this.props.setContentView?.(this); + } + + _unmounting = false; + componentWillUnmount(): void { + this._unmounting = true; + this.deselectPin(); + this._rerenderTimeout && clearTimeout(this._rerenderTimeout); + Object.keys(this._disposers).forEach(key => this._disposers[key]?.()); + } + + /** + * Called when dragging documents into map sidebar or directly into infowindow; to create a map marker, ref to MapMarkerDocument in Documents.ts + * @param doc + * @param sidebarKey + * @returns + */ + sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => { + if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar(); + const docs = doc instanceof Doc ? [doc] : doc; + docs.forEach(doc => { + let existingPin = this.allPushpins.find(pin => pin.latitude === doc.latitude && pin.longitude === doc.longitude) ?? this.selectedPin; + if (doc.latitude !== undefined && doc.longitude !== undefined && !existingPin) { + existingPin = this.createPushpin(NumCast(doc.latitude), NumCast(doc.longitude), StrCast(doc.map)); + } + if (existingPin) { + setTimeout(() => { + // we use a timeout in case this is called from the sidebar which may have just added a link that hasn't made its way into th elink manager yet + if (!LinkManager.Instance.getAllRelatedLinks(doc).some(link => DocCast(link.link_anchor_1)?.mapPin === existingPin || DocCast(link.link_anchor_2)?.mapPin === existingPin)) { + const anchor = this.getAnchor(true, undefined, existingPin); + anchor && DocUtils.MakeLink(anchor, doc, { link_relationship: 'link to map location' }); + doc.latitude = existingPin?.latitude; + doc.longitude = existingPin?.longitude; + } + }); + } + }); //add to annotation list + + return this.addDocument(doc, sidebarKey); // add to sidebar list + }; + + removeMapDocument = (doc: Doc | Doc[], annotationKey?: string) => { + const docs = doc instanceof Doc ? [doc] : doc; + this.allAnnotations.filter(anno => docs.includes(DocCast(anno.mapPin))).forEach(anno => (anno.mapPin = undefined)); + return this.removeDocument(doc, annotationKey, undefined); + }; + + /** + * Removing documents from the sidebar + * @param doc + * @param sidebarKey + * @returns + */ + sidebarRemoveDocument = (doc: Doc | Doc[], sidebarKey?: string) => this.removeMapDocument(doc, sidebarKey); + + /** + * Toggle sidebar onclick the tiny comment button on the top right corner + * @param e + */ + sidebarBtnDown = (e: React.PointerEvent) => { + setupMoveUpEvents( + this, + e, + (e, down, delta) => + runInAction(() => { + const localDelta = this.props + .ScreenToLocalTransform() + .scale(this.props.NativeDimScaling?.() || 1) + .transformDirection(delta[0], delta[1]); + const fullWidth = NumCast(this.layoutDoc._width); + const mapWidth = fullWidth - this.sidebarWidth(); + if (this.sidebarWidth() + localDelta[0] > 0) { + this.layoutDoc._layout_showSidebar = true; + this.layoutDoc._width = fullWidth + localDelta[0]; + this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth + localDelta[0])).toString() + '%'; + } else { + this.layoutDoc._layout_showSidebar = false; + this.layoutDoc._width = mapWidth; + this.layoutDoc._layout_sidebarWidthPercent = '0%'; + } + return false; + }), + emptyFunction, + () => UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar map') + ); + }; + sidebarWidth = () => (Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth(); + + /** + * Handles toggle of sidebar on click the little comment button + */ + @computed get sidebarHandle() { + return ( +
+ +
+ ); + } + + // TODO: Adding highlight box layer to Maps + @action + toggleSidebar = () => { + const prevWidth = this.sidebarWidth(); + this.layoutDoc._layout_showSidebar = (this.layoutDoc._layout_sidebarWidthPercent = StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%') === '0%' ? `${(100 * 0.2) / 1.2}%` : '0%') !== '0%'; + this.layoutDoc._width = this.layoutDoc._layout_showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth); + }; + + startAnchorDrag = (e: PointerEvent, ele: HTMLElement) => { + e.preventDefault(); + e.stopPropagation(); + + const sourceAnchorCreator = action(() => { + const note = this.getAnchor(true); + if (note && this.selectedPin) { + note.latitude = this.selectedPin.latitude; + note.longitude = this.selectedPin.longitude; + note.map = this.selectedPin.map; + } + return note as Doc; + }); + + const targetCreator = (annotationOn: Doc | undefined) => { + const target = DocUtils.GetNewTextDoc('Note linked to ' + this.rootDoc.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow'); + FormattedTextBox.SelectOnLoad = target[Id]; + return target; + }; + const docView = this.props.DocumentView?.(); + docView && + DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(docView, sourceAnchorCreator, targetCreator), e.pageX, e.pageY, { + dragComplete: e => { + if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { + e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.Document; + e.annoDragData.linkSourceDoc.followLinkZoom = false; + } + }, + }); + }; + + createNoteAnnotation = () => { + const createFunc = undoable( + action(() => { + const note = this._sidebarRef.current?.anchorMenuClick(this.getAnchor(true), ['latitude', 'longitude', LinkedTo]); + if (note && this.selectedPin) { + note.latitude = this.selectedPin.latitude; + note.longitude = this.selectedPin.longitude; + note.map = this.selectedPin.map; + } + }), + 'create note annotation' + ); + if (!this.layoutDoc.layout_showSidebar) { + this.toggleSidebar(); + setTimeout(createFunc); + } else createFunc(); + }; + sidebarDown = (e: React.PointerEvent) => { + setupMoveUpEvents(this, e, this.sidebarMove, emptyFunction, () => setTimeout(this.toggleSidebar), true); + }; + sidebarMove = (e: PointerEvent, down: number[], delta: number[]) => { + const bounds = this._ref.current!.getBoundingClientRect(); + this.layoutDoc._layout_sidebarWidthPercent = '' + 100 * Math.max(0, 1 - (e.clientX - bounds.left) / bounds.width) + '%'; + this.layoutDoc._layout_showSidebar = this.layoutDoc._layout_sidebarWidthPercent !== '0%'; + e.preventDefault(); + return false; + }; + + setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean, doc: Opt) => void) => (this._setPreviewCursor = func); + + addDocumentWrapper = (doc: Doc | Doc[], annotationKey?: string) => this.addDocument(doc, annotationKey); + + pointerEvents = () => (this.props.isContentActive() && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : 'none'); + + panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth(); + panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); + scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); + transparentFilter = () => [...this.props.childFilters(), Utils.TransparentBackgroundFilter]; + opaqueFilter = () => [...this.props.childFilters(), Utils.OpaqueBackgroundFilter]; + infoWidth = () => this.props.PanelWidth() / 5; + infoHeight = () => this.props.PanelHeight() / 5; + anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; + savedAnnotations = () => this._savedAnnotations; + + _bingSearchManager: any; + _bingMap: any; + get MicrosoftMaps() { + return (window as any).Microsoft.Maps; + } + // uses Bing Search to retrieve lat/lng for a location. eg., + // const results = this.geocodeQuery(map.map, 'Philadelphia, PA'); + // to move the map to that location: + // const location = await this.geocodeQuery(this._bingMap, 'Philadelphia, PA'); + // this._bingMap.current.setView({ + // mapTypeId: this.MicrosoftMaps.MapTypeId.aerial, + // center: new this.MicrosoftMaps.Location(loc.latitude, loc.longitude), + // }); + // + bingGeocode = (map: any, query: string) => { + return new Promise<{ latitude: number; longitude: number }>((res, reject) => { + //If search manager is not defined, load the search module. + if (!this._bingSearchManager) { + //Create an instance of the search manager and call the geocodeQuery function again. + this.MicrosoftMaps.loadModule('Microsoft.Maps.Search', () => { + this._bingSearchManager = new this.MicrosoftMaps.Search.SearchManager(map.current); + res(this.bingGeocode(map, query)); + }); + } else { + this._bingSearchManager.geocode({ + where: query, + callback: action((r: any) => res(r.results[0].location)), + errorCallback: (e: any) => reject(), + }); + } + }); + }; + + @observable + bingSearchBarContents: any = this.rootDoc.map; // For Bing Maps: The contents of the Bing search bar (string) + + geoDataRequestOptions = { + entityType: 'PopulatedPlace', + }; + + // incrementer: number = 0; + /* + * Creates Pushpin doc and adds it to the list of annotations + */ + @action + createPushpin = undoable((latitude: number, longitude: number, map?: string) => { + // Stores the pushpin as a MapMarkerDocument + const pushpin = Docs.Create.PushpinDocument( + NumCast(latitude), + NumCast(longitude), + false, + [], + { title: map ?? `lat=${latitude},lng=${longitude}`, map: map } + // ,'pushpinIDamongus'+ this.incrementer++ + ); + this.addDocument(pushpin, this.annotationKey); + return pushpin; + // mapMarker.infoWindowOpen = true; + }, 'createpin'); + + // The pin that is selected + @observable selectedPin: Doc | undefined; + + @action + deselectPin = () => { + if (this.selectedPin) { + // Removes filter + Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'remove'); + Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'remove'); + Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove'); + + const temp = this.selectedPin; + if (!this._unmounting) { + this._bingMap.current.entities.remove(this.map_docToPinMap.get(temp)); + } + const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(temp.latitude, temp.longitude)); + this.MicrosoftMaps.Events.addHandler(newpin, 'click', (e: any) => this.pushpinClicked(temp as Doc)); + if (!this._unmounting) { + this._bingMap.current.entities.push(newpin); + } + this.map_docToPinMap.set(temp, newpin); + this.selectedPin = undefined; + this.bingSearchBarContents = this.rootDoc.map; + } + }; + + getView = async (doc: Doc) => { + if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(); + return new Promise>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); + }; + /* + * Pushpin onclick + */ + @action + pushpinClicked = (pinDoc: Doc) => { + this.deselectPin(); + this.selectedPin = pinDoc; + this.bingSearchBarContents = pinDoc.map; + + // Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'match'); + // Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'match'); + Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(this.selectedPin)}`, 'check'); + + this.recolorPin(this.selectedPin, 'green'); + + MapAnchorMenu.Instance.Delete = this.deleteSelectedPin; + MapAnchorMenu.Instance.Center = this.centerOnSelectedPin; + MapAnchorMenu.Instance.OnClick = this.createNoteAnnotation; + MapAnchorMenu.Instance.StartDrag = this.startAnchorDrag; + + const point = this._bingMap.current.tryLocationToPixel(new this.MicrosoftMaps.Location(this.selectedPin.latitude, this.selectedPin.longitude)); + const x = point.x + (this.props.PanelWidth() - this.sidebarWidth()) / 2; + const y = point.y + this.props.PanelHeight() / 2 + 32; + const cpt = this.props.ScreenToLocalTransform().inverse().transformPoint(x, y); + MapAnchorMenu.Instance.jumpTo(cpt[0], cpt[1], true); + + document.addEventListener('pointerdown', this.tryHideMapAnchorMenu, true); + }; + + /** + * Map OnClick + */ + @action + mapOnClick = (e: { location: { latitude: any; longitude: any } }) => { + this.props.select(false); + this.deselectPin(); + }; + /* + * Updates values of layout doc to match the current map + */ + @action + mapRecentered = () => { + if ( + Math.abs(NumCast(this.dataDoc.latitude) - this._bingMap.current.getCenter().latitude) > 1e-7 || // + Math.abs(NumCast(this.dataDoc.longitude) - this._bingMap.current.getCenter().longitude) > 1e-7 + ) { + this.dataDoc.latitude = this._bingMap.current.getCenter().latitude; + this.dataDoc.longitude = this._bingMap.current.getCenter().longitude; + this.dataDoc.map = ''; + this.bingSearchBarContents = ''; + } + this.dataDoc.map_zoom = this._bingMap.current.getZoom(); + }; + /* + * Updates maptype + */ + @action + updateMapType = () => (this.dataDoc.map_type = this._bingMap.current.getMapTypeId()); + + /* + * For Bing Maps + * Called by search button's onClick + * Finds the geocode of the searched contents and sets location to that location + **/ + @action + bingSearch = () => { + return this.bingGeocode(this._bingMap, this.bingSearchBarContents).then(location => { + this.dataDoc.latitude = location.latitude; + this.dataDoc.longitude = location.longitude; + this.dataDoc.map_zoom = this._bingMap.current.getZoom(); + this.dataDoc.map = this.bingSearchBarContents; + }); + }; + + /* + * Returns doc w/ relevant info + */ + getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps, existingPin?: Doc) => { + /// this should use SELECTED pushpin for lat/long if there is a selection, otherwise CENTER + const anchor = Docs.Create.ConfigDocument({ + title: 'MapAnchor:' + this.rootDoc.title, + text: StrCast(this.selectedPin?.map) || StrCast(this.rootDoc.map) || 'map location', + config_latitude: NumCast((existingPin ?? this.selectedPin)?.latitude ?? this.dataDoc.latitude), + config_longitude: NumCast((existingPin ?? this.selectedPin)?.longitude ?? this.dataDoc.longitude), + config_map_zoom: NumCast(this.dataDoc.map_zoom), + config_map_type: StrCast(this.dataDoc.map_type), + config_map: StrCast((existingPin ?? this.selectedPin)?.map) || StrCast(this.dataDoc.map), + layout_unrendered: true, + mapPin: existingPin ?? this.selectedPin, + annotationOn: this.rootDoc, + }); + if (anchor) { + if (!addAsAnnotation) anchor.backgroundColor = 'transparent'; + addAsAnnotation && this.addDocument(anchor); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), map: true } }, this.rootDoc); + return anchor; + } + return this.rootDoc; + }; + + map_docToPinMap = new Map(); + map_pinHighlighted = new Map(); + /* + * Input: pin doc + * Adds MicrosoftMaps Pushpin to the map (render) + */ + @action + addPushpin = (pin: Doc) => { + const pushPin = pin.infoWindowOpen + ? new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(pin.latitude, pin.longitude), {}) + : new this.MicrosoftMaps.Pushpin( + new this.MicrosoftMaps.Location(pin.latitude, pin.longitude) + // {icon: 'http://icons.iconarchive.com/icons/icons-land/vista-map-markers/24/Map-Marker-Marker-Outside-Chartreuse-icon.png'} + ); + + this._bingMap.current.entities.push(pushPin); + + this.MicrosoftMaps.Events.addHandler(pushPin, 'click', (e: any) => this.pushpinClicked(pin)); + // this.MicrosoftMaps.Events.addHandler(pushPin, 'dblclick', (e: any) => this.pushpinDblClicked(pushPin, pin)); + this.map_docToPinMap.set(pin, pushPin); + }; + + /* + * Input: pin doc + * Removes pin from annotations + */ + @action + removePushpin = (pinDoc: Doc) => this.removeMapDocument(pinDoc, this.annotationKey); + + /* + * Removes pushpin from map render + */ + deletePushpin = (pinDoc: Doc) => { + if (!this._unmounting) { + this._bingMap.current.entities.remove(this.map_docToPinMap.get(pinDoc)); + } + this.map_docToPinMap.delete(pinDoc); + this.selectedPin = undefined; + }; + + @action + deleteSelectedPin = undoable(() => { + if (this.selectedPin) { + // Removes filter + Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'remove'); + Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'remove'); + Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove'); + + this.removePushpin(this.selectedPin); + } + MapAnchorMenu.Instance.fadeOut(true); + document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu, true); + }, 'delete pin'); + + tryHideMapAnchorMenu = (e: PointerEvent) => { + let target = document.elementFromPoint(e.x, e.y); + while (target) { + if (target === MapAnchorMenu.top.current) return; + target = target.parentElement; + } + e.stopPropagation(); + e.preventDefault(); + MapAnchorMenu.Instance.fadeOut(true); + document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu, true); + }; + + @action + centerOnSelectedPin = () => { + if (this.selectedPin) { + this.dataDoc.latitude = this.selectedPin.latitude; + this.dataDoc.longitude = this.selectedPin.longitude; + this.dataDoc.map = this.selectedPin.map ?? ''; + this.bingSearchBarContents = this.selectedPin.map; + } + MapAnchorMenu.Instance.fadeOut(true); + document.removeEventListener('pointerdown', this.tryHideMapAnchorMenu); + }; + + /** + * View options for bing maps + */ + bingViewOptions = { + // center: { latitude: this.dataDoc.latitude ?? defaultCenter.lat, longitude: this.dataDoc.longitude ?? defaultCenter.lng }, + zoom: this.dataDoc.latitude ?? 10, + mapTypeId: 'grayscale', + }; + + /** + * Map options + */ + bingMapOptions = { + navigationBarMode: 'square', + backgroundColor: '#f1f3f4', + enableInertia: true, + supportedMapTypes: ['grayscale', 'canvasLight'], + disableMapTypeSelectorMouseOver: true, + // showScalebar:true + // disableRoadView:true, + // disableBirdseye:true + streetsideOptions: { + showProblemReporting: false, + showCurrentAddress: false, + }, + }; + + @action + searchbarOnEdit = (newText: string) => (this.bingSearchBarContents = newText); + + recolorPin = (pin: Doc, color?: string) => { + this._bingMap.current.entities.remove(this.map_docToPinMap.get(pin)); + this.map_docToPinMap.delete(pin); + const newpin = new this.MicrosoftMaps.Pushpin(new this.MicrosoftMaps.Location(pin.latitude, pin.longitude), color ? { color } : {}); + this.MicrosoftMaps.Events.addHandler(newpin, 'click', (e: any) => this.pushpinClicked(pin)); + this._bingMap.current.entities.push(newpin); + this.map_docToPinMap.set(pin, newpin); + }; + + /* + * Called when BingMap is first rendered + * Initializes starting values + */ + @observable _mapReady = false; + @action + bingMapReady = (map: any) => { + this._mapReady = true; + this._bingMap = map.map; + if (!this._bingMap.current) { + alert('NO Map!?'); + } + this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'click', this.mapOnClick); + this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'viewchangeend', undoable(this.mapRecentered, 'Map Layout Change')); + this.MicrosoftMaps.Events.addHandler(this._bingMap.current, 'maptypechanged', undoable(this.updateMapType, 'Map ViewType Change')); + + this._disposers.mapLocation = reaction( + () => this.rootDoc.map, + mapLoc => (this.bingSearchBarContents = mapLoc), + { fireImmediately: true } + ); + this._disposers.highlight = reaction( + () => this.allAnnotations.map(doc => doc[Highlight]), + () => { + const allConfigPins = this.allAnnotations.map(doc => ({ doc, pushpin: DocCast(doc.mapPin) })).filter(pair => pair.pushpin); + allConfigPins.forEach(({ doc, pushpin }) => { + if (!pushpin[Highlight] && this.map_pinHighlighted.get(pushpin)) { + this.recolorPin(pushpin); + this.map_pinHighlighted.delete(pushpin); + } + }); + allConfigPins.forEach(({ doc, pushpin }) => { + if (doc[Highlight] && !this.map_pinHighlighted.get(pushpin)) { + this.recolorPin(pushpin, 'orange'); + this.map_pinHighlighted.set(pushpin, true); + } + }); + }, + { fireImmediately: true } + ); + + this._disposers.location = reaction( + () => ({ lat: this.rootDoc.latitude, lng: this.rootDoc.longitude, zoom: this.rootDoc.map_zoom, mapType: this.rootDoc.map_type }), + locationObject => { + // if (this._bingMap.current) + try { + locationObject?.zoom && + this._bingMap.current?.setView({ + mapTypeId: locationObject.mapType, + zoom: locationObject.zoom, + center: new this.MicrosoftMaps.Location(locationObject.lat, locationObject.lng), + }); + } catch (e) { + console.log(e); + } + }, + { fireImmediately: true } + ); + }; + + dragToggle = (e: React.PointerEvent) => { + let dragClone: HTMLDivElement | undefined; + + setupMoveUpEvents( + e, + e, + e => { + if (!dragClone) { + dragClone = this._dragRef.current?.cloneNode(true) as HTMLDivElement; + dragClone.style.position = 'absolute'; + dragClone.style.zIndex = '10000'; + DragManager.Root().appendChild(dragClone); + } + dragClone.style.transform = `translate(${e.clientX - 15}px, ${e.clientY - 15}px)`; + return false; + }, + e => { + if (!dragClone) return; + DragManager.Root().removeChild(dragClone); + let target = document.elementFromPoint(e.x, e.y); + while (target) { + if (target === this._ref.current) { + const cpt = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY); + const x = cpt[0] - (this.props.PanelWidth() - this.sidebarWidth()) / 2; + const y = cpt[1] - 32 /* height of search bar */ - this.props.PanelHeight() / 2; + const location = this._bingMap.current.tryPixelToLocation(new this.MicrosoftMaps.Point(x, y)); + this.createPushpin(location.latitude, location.longitude); + break; + } + target = target.parentElement; + } + }, + e => { + const createPin = () => this.createPushpin(this.rootDoc.latitude, this.rootDoc.longitude, this.rootDoc.map); + if (this.bingSearchBarContents) { + this.bingSearch().then(createPin); + } else createPin(); + } + ); + }; + + searchbarKeyDown = (e: any) => e.key === 'Enter' && this.bingSearch(); + + static _firstRender = true; + static _rerenderDelay = 500; + _rerenderTimeout: any; + render() { + // bcz: no idea what's going on here, but bings maps have some kind of bug + // such that we need to delay rendering a second map on startup until the first map is rendered. + this.rootDoc[DocCss]; + if (MapBoxContainer._rerenderDelay) { + // prettier-ignore + this._rerenderTimeout = this._rerenderTimeout ?? + setTimeout(action(() => { + if ((window as any).Microsoft?.Maps?.Internal._WorkDispatcher) { + MapBoxContainer._rerenderDelay = 0; + } + this._rerenderTimeout = undefined; + this.rootDoc[DocCss] = this.rootDoc[DocCss] + 1; + }), MapBoxContainer._rerenderDelay); + return null; + } + + const renderAnnotations = (childFilters?: () => string[]) => null; + return ( +
+
e.stopPropagation()} + onPointerDown={async e => { + e.button === 0 && !e.ctrlKey && e.stopPropagation(); + }} + style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, pointerEvents: this.pointerEvents() }}> +
{renderAnnotations(this.transparentFilter)}
+ {renderAnnotations(this.opaqueFilter)} + {SnappingManager.GetIsDragging() ? null : renderAnnotations()} + +
+ typeof newText === 'string' && this.searchbarOnEdit(newText)} + onEnter={e => this.bingSearch()} + placeholder={this.bingSearchBarContents || 'enter city/zip/...'} + textAlign="center" + /> +
+ + + + + +{/* + */} +
+ {!this._mapReady + ? null + : this.allAnnotations + .filter(anno => !anno.layout_unrendered) + .map((pushpin, i) => ( + + ))} +
+ {/* */} +
+ {/* */} +
+ +
+ {this.sidebarHandle} +
+ ); + } +} -- cgit v1.2.3-70-g09d2 From adf56d455ab0e429b7eac3430890ba7677cce8d9 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 15 Dec 2023 11:16:37 -0500 Subject: more fixes for mapbox and dataviz --- package-lock.json | 2188 +++++++++++++++++++- package.json | 3 + src/client/views/nodes/DataVizBox/DataVizBox.tsx | 14 +- .../nodes/DataVizBox/components/Histogram.tsx | 102 +- .../nodes/DataVizBox/components/LineChart.tsx | 66 +- .../views/nodes/DataVizBox/components/PieChart.tsx | 88 +- .../views/nodes/DataVizBox/components/TableBox.tsx | 79 +- src/client/views/nodes/MapBox/AnimationUtility.ts | 482 ++--- .../views/nodes/MapBox/DirectionsAnchorMenu.tsx | 69 +- .../views/nodes/MapboxMapBox/MapboxContainer.tsx | 66 +- webpack.config.js | 2 +- 11 files changed, 2636 insertions(+), 523 deletions(-) (limited to 'src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx') diff --git a/package-lock.json b/package-lock.json index 18c4f3d05..6496b4184 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "@mui/material": "^5.14.19", "@octokit/core": "^5.0.2", "@react-google-maps/api": "^2.19.2", + "@turf/turf": "^6.5.0", "@types/bezier-js": "^4.1.3", "@types/cors": "^2.8.17", "@types/d3-axis": "^3.0.6", @@ -113,6 +114,7 @@ "jsonschema": "^1.4.1", "jszip": "^3.10.1", "lodash": "^4.17.21", + "mapbox-gl": "^3.0.1", "mathquill": "^0.10.1-a", "md5-file": "^5.0.0", "memorystream": "^0.3.1", @@ -163,6 +165,7 @@ "react-icons": "^4.12.0", "react-jsx-parser": "^1.29.0", "react-loading": "^2.0.3", + "react-map-gl": "^7.1.6", "react-markdown": "^9.0.1", "react-measure": "^2.5.2", "react-resizable": "^3.0.5", @@ -3126,6 +3129,42 @@ "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "dev": true }, + "node_modules/@mapbox/geojson-rewind": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", + "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", + "dependencies": { + "get-stream": "^6.0.1", + "minimist": "^1.2.6" + }, + "bin": { + "geojson-rewind": "geojson-rewind" + } + }, + "node_modules/@mapbox/geojson-rewind/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@mapbox/jsonlint-lines-primitives": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", + "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@mapbox/mapbox-gl-supported": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-2.0.1.tgz", + "integrity": "sha512-HP6XvfNIzfoMVfyGjBckjiAOQK9WfX0ywdLubuPMPv+Vqf5fj0uCbgBQYpiqcWZT6cbyyRnTSXDheT1ugvF6UQ==" + }, "node_modules/@mapbox/node-pre-gyp": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", @@ -3228,6 +3267,55 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/@mapbox/point-geometry": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", + "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==" + }, + "node_modules/@mapbox/tiny-sdf": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.6.tgz", + "integrity": "sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==" + }, + "node_modules/@mapbox/unitbezier": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==" + }, + "node_modules/@mapbox/vector-tile": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", + "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", + "dependencies": { + "@mapbox/point-geometry": "~0.1.0" + } + }, + "node_modules/@mapbox/whoots-js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", + "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@maplibre/maplibre-gl-style-spec": { + "version": "19.3.3", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-19.3.3.tgz", + "integrity": "sha512-cOZZOVhDSulgK0meTsTkmNXb1ahVvmTmWmfx9gRBwc6hq98wS9JP35ESIoNq3xqEan+UN+gn8187Z6E4NKhLsw==", + "dependencies": { + "@mapbox/jsonlint-lines-primitives": "~2.0.2", + "@mapbox/unitbezier": "^0.0.1", + "json-stringify-pretty-compact": "^3.0.0", + "minimist": "^1.2.8", + "rw": "^1.3.3", + "sort-object": "^3.0.3" + }, + "bin": { + "gl-style-format": "dist/gl-style-format.mjs", + "gl-style-migrate": "dist/gl-style-migrate.mjs", + "gl-style-validate": "dist/gl-style-validate.mjs" + } + }, "node_modules/@mongodb-js/saslprep": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.1.tgz", @@ -3775,11 +3863,1588 @@ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", "dev": true }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@turf/along": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/along/-/along-6.5.0.tgz", + "integrity": "sha512-LLyWQ0AARqJCmMcIEAXF4GEu8usmd4Kbz3qk1Oy5HoRNpZX47+i5exQtmIWKdqJ1MMhW26fCTXgpsEs5zgJ5gw==", + "dependencies": { + "@turf/bearing": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/angle": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/angle/-/angle-6.5.0.tgz", + "integrity": "sha512-4pXMbWhFofJJAOvTMCns6N4C8CMd5Ih4O2jSAG9b3dDHakj3O4yN1+Zbm+NUei+eVEZ9gFeVp9svE3aMDenIkw==", + "dependencies": { + "@turf/bearing": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/area": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/area/-/area-6.5.0.tgz", + "integrity": "sha512-xCZdiuojokLbQ+29qR6qoMD89hv+JAgWjLrwSEWL+3JV8IXKeNFl6XkEJz9HGkVpnXvQKJoRz4/liT+8ZZ5Jyg==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/bbox": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/bbox/-/bbox-6.5.0.tgz", + "integrity": "sha512-RBbLaao5hXTYyyg577iuMtDB8ehxMlUqHEJiMs8jT1GHkFhr6sYre3lmLsPeYEi/ZKj5TP5tt7fkzNdJ4GIVyw==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/bbox-clip": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/bbox-clip/-/bbox-clip-6.5.0.tgz", + "integrity": "sha512-F6PaIRF8WMp8EmgU/Ke5B1Y6/pia14UAYB5TiBC668w5rVVjy5L8rTm/m2lEkkDMHlzoP9vNY4pxpNthE7rLcQ==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/bbox-polygon": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/bbox-polygon/-/bbox-polygon-6.5.0.tgz", + "integrity": "sha512-+/r0NyL1lOG3zKZmmf6L8ommU07HliP4dgYToMoTxqzsWzyLjaj/OzgQ8rBmv703WJX+aS6yCmLuIhYqyufyuw==", + "dependencies": { + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/bearing": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/bearing/-/bearing-6.5.0.tgz", + "integrity": "sha512-dxINYhIEMzgDOztyMZc20I7ssYVNEpSv04VbMo5YPQsqa80KO3TFvbuCahMsCAW5z8Tncc8dwBlEFrmRjJG33A==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/bezier-spline": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/bezier-spline/-/bezier-spline-6.5.0.tgz", + "integrity": "sha512-vokPaurTd4PF96rRgGVm6zYYC5r1u98ZsG+wZEv9y3kJTuJRX/O3xIY2QnTGTdbVmAJN1ouOsD0RoZYaVoXORQ==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-clockwise": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-clockwise/-/boolean-clockwise-6.5.0.tgz", + "integrity": "sha512-45+C7LC5RMbRWrxh3Z0Eihsc8db1VGBO5d9BLTOAwU4jR6SgsunTfRWR16X7JUwIDYlCVEmnjcXJNi/kIU3VIw==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-contains": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-contains/-/boolean-contains-6.5.0.tgz", + "integrity": "sha512-4m8cJpbw+YQcKVGi8y0cHhBUnYT+QRfx6wzM4GI1IdtYH3p4oh/DOBJKrepQyiDzFDaNIjxuWXBh0ai1zVwOQQ==", + "dependencies": { + "@turf/bbox": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/boolean-point-on-line": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-crosses": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-crosses/-/boolean-crosses-6.5.0.tgz", + "integrity": "sha512-gvshbTPhAHporTlQwBJqyfW+2yV8q/mOTxG6PzRVl6ARsqNoqYQWkd4MLug7OmAqVyBzLK3201uAeBjxbGw0Ng==", + "dependencies": { + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-intersect": "^6.5.0", + "@turf/polygon-to-line": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-disjoint": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-disjoint/-/boolean-disjoint-6.5.0.tgz", + "integrity": "sha512-rZ2ozlrRLIAGo2bjQ/ZUu4oZ/+ZjGvLkN5CKXSKBcu6xFO6k2bgqeM8a1836tAW+Pqp/ZFsTA5fZHsJZvP2D5g==", + "dependencies": { + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/line-intersect": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/polygon-to-line": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-equal": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-equal/-/boolean-equal-6.5.0.tgz", + "integrity": "sha512-cY0M3yoLC26mhAnjv1gyYNQjn7wxIXmL2hBmI/qs8g5uKuC2hRWi13ydufE3k4x0aNRjFGlg41fjoYLwaVF+9Q==", + "dependencies": { + "@turf/clean-coords": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "geojson-equality": "0.1.6" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-intersects": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-intersects/-/boolean-intersects-6.5.0.tgz", + "integrity": "sha512-nIxkizjRdjKCYFQMnml6cjPsDOBCThrt+nkqtSEcxkKMhAQj5OO7o2CecioNTaX8EayqwMGVKcsz27oP4mKPTw==", + "dependencies": { + "@turf/boolean-disjoint": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-overlap": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-overlap/-/boolean-overlap-6.5.0.tgz", + "integrity": "sha512-8btMIdnbXVWUa1M7D4shyaSGxLRw6NjMcqKBcsTXcZdnaixl22k7ar7BvIzkaRYN3SFECk9VGXfLncNS3ckQUw==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-intersect": "^6.5.0", + "@turf/line-overlap": "^6.5.0", + "@turf/meta": "^6.5.0", + "geojson-equality": "0.1.6" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-parallel": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-parallel/-/boolean-parallel-6.5.0.tgz", + "integrity": "sha512-aSHJsr1nq9e5TthZGZ9CZYeXklJyRgR5kCLm5X4urz7+MotMOp/LsGOsvKvK9NeUl9+8OUmfMn8EFTT8LkcvIQ==", + "dependencies": { + "@turf/clean-coords": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/line-segment": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-point-in-polygon": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-6.5.0.tgz", + "integrity": "sha512-DtSuVFB26SI+hj0SjrvXowGTUCHlgevPAIsukssW6BG5MlNSBQAo70wpICBNJL6RjukXg8d2eXaAWuD/CqL00A==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-point-on-line": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-point-on-line/-/boolean-point-on-line-6.5.0.tgz", + "integrity": "sha512-A1BbuQ0LceLHvq7F/P7w3QvfpmZqbmViIUPHdNLvZimFNLo4e6IQunmzbe+8aSStH9QRZm3VOflyvNeXvvpZEQ==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/boolean-within": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-within/-/boolean-within-6.5.0.tgz", + "integrity": "sha512-YQB3oU18Inx35C/LU930D36RAVe7LDXk1kWsQ8mLmuqYn9YdPsDQTMTkLJMhoQ8EbN7QTdy333xRQ4MYgToteQ==", + "dependencies": { + "@turf/bbox": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/boolean-point-on-line": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/buffer": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/buffer/-/buffer-6.5.0.tgz", + "integrity": "sha512-qeX4N6+PPWbKqp1AVkBVWFerGjMYMUyencwfnkCesoznU6qvfugFHNAngNqIBVnJjZ5n8IFyOf+akcxnrt9sNg==", + "dependencies": { + "@turf/bbox": "^6.5.0", + "@turf/center": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/projection": "^6.5.0", + "d3-geo": "1.7.1", + "turf-jsts": "*" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/buffer/node_modules/d3-array": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" + }, + "node_modules/@turf/buffer/node_modules/d3-geo": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.7.1.tgz", + "integrity": "sha512-O4AempWAr+P5qbk2bC2FuN/sDW4z+dN2wDf9QV3bxQt4M5HfOEeXLgJ/UKQW0+o1Dj8BE+L5kiDbdWUMjsmQpw==", + "dependencies": { + "d3-array": "1" + } + }, + "node_modules/@turf/center": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/center/-/center-6.5.0.tgz", + "integrity": "sha512-T8KtMTfSATWcAX088rEDKjyvQCBkUsLnK/Txb6/8WUXIeOZyHu42G7MkdkHRoHtwieLdduDdmPLFyTdG5/e7ZQ==", + "dependencies": { + "@turf/bbox": "^6.5.0", + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/center-mean": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/center-mean/-/center-mean-6.5.0.tgz", + "integrity": "sha512-AAX6f4bVn12pTVrMUiB9KrnV94BgeBKpyg3YpfnEbBpkN/znfVhL8dG8IxMAxAoSZ61Zt9WLY34HfENveuOZ7Q==", + "dependencies": { + "@turf/bbox": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/center-median": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/center-median/-/center-median-6.5.0.tgz", + "integrity": "sha512-dT8Ndu5CiZkPrj15PBvslpuf01ky41DEYEPxS01LOxp5HOUHXp1oJxsPxvc+i/wK4BwccPNzU1vzJ0S4emd1KQ==", + "dependencies": { + "@turf/center-mean": "^6.5.0", + "@turf/centroid": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/center-of-mass": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/center-of-mass/-/center-of-mass-6.5.0.tgz", + "integrity": "sha512-EWrriU6LraOfPN7m1jZi+1NLTKNkuIsGLZc2+Y8zbGruvUW+QV7K0nhf7iZWutlxHXTBqEXHbKue/o79IumAsQ==", + "dependencies": { + "@turf/centroid": "^6.5.0", + "@turf/convex": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/centroid": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/centroid/-/centroid-6.5.0.tgz", + "integrity": "sha512-MwE1oq5E3isewPprEClbfU5pXljIK/GUOMbn22UM3IFPDJX0KeoyLNwghszkdmFp/qMGL/M13MMWvU+GNLXP/A==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/circle": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/circle/-/circle-6.5.0.tgz", + "integrity": "sha512-oU1+Kq9DgRnoSbWFHKnnUdTmtcRUMmHoV9DjTXu9vOLNV5OWtAAh1VZ+mzsioGGzoDNT/V5igbFOkMfBQc0B6A==", + "dependencies": { + "@turf/destination": "^6.5.0", + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/clean-coords": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/clean-coords/-/clean-coords-6.5.0.tgz", + "integrity": "sha512-EMX7gyZz0WTH/ET7xV8MyrExywfm9qUi0/MY89yNffzGIEHuFfqwhcCqZ8O00rZIPZHUTxpmsxQSTfzJJA1CPw==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/clone": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-6.5.0.tgz", + "integrity": "sha512-mzVtTFj/QycXOn6ig+annKrM6ZlimreKYz6f/GSERytOpgzodbQyOgkfwru100O1KQhhjSudKK4DsQ0oyi9cTw==", + "dependencies": { + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/clusters": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/clusters/-/clusters-6.5.0.tgz", + "integrity": "sha512-Y6gfnTJzQ1hdLfCsyd5zApNbfLIxYEpmDibHUqR5z03Lpe02pa78JtgrgUNt1seeO/aJ4TG1NLN8V5gOrHk04g==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/clusters-dbscan": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/clusters-dbscan/-/clusters-dbscan-6.5.0.tgz", + "integrity": "sha512-SxZEE4kADU9DqLRiT53QZBBhu8EP9skviSyl+FGj08Y01xfICM/RR9ACUdM0aEQimhpu+ZpRVcUK+2jtiCGrYQ==", + "dependencies": { + "@turf/clone": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0", + "density-clustering": "1.3.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/clusters-kmeans": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/clusters-kmeans/-/clusters-kmeans-6.5.0.tgz", + "integrity": "sha512-DwacD5+YO8kwDPKaXwT9DV46tMBVNsbi1IzdajZu1JDSWoN7yc7N9Qt88oi+p30583O0UPVkAK+A10WAQv4mUw==", + "dependencies": { + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "skmeans": "0.9.7" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/collect": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/collect/-/collect-6.5.0.tgz", + "integrity": "sha512-4dN/T6LNnRg099m97BJeOcTA5fSI8cu87Ydgfibewd2KQwBexO69AnjEFqfPX3Wj+Zvisj1uAVIZbPmSSrZkjg==", + "dependencies": { + "@turf/bbox": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/helpers": "^6.5.0", + "rbush": "2.x" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/combine": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/combine/-/combine-6.5.0.tgz", + "integrity": "sha512-Q8EIC4OtAcHiJB3C4R+FpB4LANiT90t17uOd851qkM2/o6m39bfN5Mv0PWqMZIHWrrosZqRqoY9dJnzz/rJxYQ==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/concave": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/concave/-/concave-6.5.0.tgz", + "integrity": "sha512-I/sUmUC8TC5h/E2vPwxVht+nRt+TnXIPRoztDFvS8/Y0+cBDple9inLSo9nnPXMXidrBlGXZ9vQx/BjZUJgsRQ==", + "dependencies": { + "@turf/clone": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/tin": "^6.5.0", + "topojson-client": "3.x", + "topojson-server": "3.x" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/convex": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/convex/-/convex-6.5.0.tgz", + "integrity": "sha512-x7ZwC5z7PJB0SBwNh7JCeCNx7Iu+QSrH7fYgK0RhhNop13TqUlvHMirMLRgf2db1DqUetrAO2qHJeIuasquUWg==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0", + "concaveman": "*" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/destination": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/destination/-/destination-6.5.0.tgz", + "integrity": "sha512-4cnWQlNC8d1tItOz9B4pmJdWpXqS0vEvv65bI/Pj/genJnsL7evI0/Xw42RvEGROS481MPiU80xzvwxEvhQiMQ==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/difference": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/difference/-/difference-6.5.0.tgz", + "integrity": "sha512-l8iR5uJqvI+5Fs6leNbhPY5t/a3vipUF/3AeVLpwPQcgmedNXyheYuy07PcMGH5Jdpi5gItOiTqwiU/bUH4b3A==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "polygon-clipping": "^0.15.3" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/dissolve": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/dissolve/-/dissolve-6.5.0.tgz", + "integrity": "sha512-WBVbpm9zLTp0Bl9CE35NomTaOL1c4TQCtEoO43YaAhNEWJOOIhZMFJyr8mbvYruKl817KinT3x7aYjjCMjTAsQ==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "polygon-clipping": "^0.15.3" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/distance": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/distance/-/distance-6.5.0.tgz", + "integrity": "sha512-xzykSLfoURec5qvQJcfifw/1mJa+5UwByZZ5TZ8iaqjGYN0vomhV9aiSLeYdUGtYRESZ+DYC/OzY+4RclZYgMg==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/distance-weight": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/distance-weight/-/distance-weight-6.5.0.tgz", + "integrity": "sha512-a8qBKkgVNvPKBfZfEJZnC3DV7dfIsC3UIdpRci/iap/wZLH41EmS90nM+BokAJflUHYy8PqE44wySGWHN1FXrQ==", + "dependencies": { + "@turf/centroid": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/ellipse": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/ellipse/-/ellipse-6.5.0.tgz", + "integrity": "sha512-kuXtwFviw/JqnyJXF1mrR/cb496zDTSbGKtSiolWMNImYzGGkbsAsFTjwJYgD7+4FixHjp0uQPzo70KDf3AIBw==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/rhumb-destination": "^6.5.0", + "@turf/transform-rotate": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/envelope": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/envelope/-/envelope-6.5.0.tgz", + "integrity": "sha512-9Z+FnBWvOGOU4X+fMZxYFs1HjFlkKqsddLuMknRaqcJd6t+NIv5DWvPtDL8ATD2GEExYDiFLwMdckfr1yqJgHA==", + "dependencies": { + "@turf/bbox": "^6.5.0", + "@turf/bbox-polygon": "^6.5.0", + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/explode": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/explode/-/explode-6.5.0.tgz", + "integrity": "sha512-6cSvMrnHm2qAsace6pw9cDmK2buAlw8+tjeJVXMfMyY+w7ZUi1rprWMsY92J7s2Dar63Bv09n56/1V7+tcj52Q==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/flatten": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/flatten/-/flatten-6.5.0.tgz", + "integrity": "sha512-IBZVwoNLVNT6U/bcUUllubgElzpMsNoCw8tLqBw6dfYg9ObGmpEjf9BIYLr7a2Yn5ZR4l7YIj2T7kD5uJjZADQ==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/flip": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/flip/-/flip-6.5.0.tgz", + "integrity": "sha512-oyikJFNjt2LmIXQqgOGLvt70RgE2lyzPMloYWM7OR5oIFGRiBvqVD2hA6MNw6JewIm30fWZ8DQJw1NHXJTJPbg==", + "dependencies": { + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/great-circle": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/great-circle/-/great-circle-6.5.0.tgz", + "integrity": "sha512-7ovyi3HaKOXdFyN7yy1yOMa8IyOvV46RC1QOQTT+RYUN8ke10eyqExwBpL9RFUPvlpoTzoYbM/+lWPogQlFncg==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/helpers": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.5.0.tgz", + "integrity": "sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==", + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/hex-grid": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/hex-grid/-/hex-grid-6.5.0.tgz", + "integrity": "sha512-Ln3tc2tgZT8etDOldgc6e741Smg1CsMKAz1/Mlel+MEL5Ynv2mhx3m0q4J9IB1F3a4MNjDeVvm8drAaf9SF33g==", + "dependencies": { + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/intersect": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/interpolate": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/interpolate/-/interpolate-6.5.0.tgz", + "integrity": "sha512-LSH5fMeiGyuDZ4WrDJNgh81d2DnNDUVJtuFryJFup8PV8jbs46lQGfI3r1DJ2p1IlEJIz3pmAZYeTfMMoeeohw==", + "dependencies": { + "@turf/bbox": "^6.5.0", + "@turf/centroid": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/hex-grid": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/point-grid": "^6.5.0", + "@turf/square-grid": "^6.5.0", + "@turf/triangle-grid": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/intersect": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/intersect/-/intersect-6.5.0.tgz", + "integrity": "sha512-2legGJeKrfFkzntcd4GouPugoqPUjexPZnOvfez+3SfIMrHvulw8qV8u7pfVyn2Yqs53yoVCEjS5sEpvQ5YRQg==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "polygon-clipping": "^0.15.3" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/invariant": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.5.0.tgz", + "integrity": "sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg==", + "dependencies": { + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/isobands": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/isobands/-/isobands-6.5.0.tgz", + "integrity": "sha512-4h6sjBPhRwMVuFaVBv70YB7eGz+iw0bhPRnp+8JBdX1UPJSXhoi/ZF2rACemRUr0HkdVB/a1r9gC32vn5IAEkw==", + "dependencies": { + "@turf/area": "^6.5.0", + "@turf/bbox": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/explode": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "object-assign": "*" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/isolines": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/isolines/-/isolines-6.5.0.tgz", + "integrity": "sha512-6ElhiLCopxWlv4tPoxiCzASWt/jMRvmp6mRYrpzOm3EUl75OhHKa/Pu6Y9nWtCMmVC/RcWtiiweUocbPLZLm0A==", + "dependencies": { + "@turf/bbox": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "object-assign": "*" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/kinks": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/kinks/-/kinks-6.5.0.tgz", + "integrity": "sha512-ViCngdPt1eEL7hYUHR2eHR662GvCgTc35ZJFaNR6kRtr6D8plLaDju0FILeFFWSc+o8e3fwxZEJKmFj9IzPiIQ==", + "dependencies": { + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/length": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/length/-/length-6.5.0.tgz", + "integrity": "sha512-5pL5/pnw52fck3oRsHDcSGrj9HibvtlrZ0QNy2OcW8qBFDNgZ4jtl6U7eATVoyWPKBHszW3dWETW+iLV7UARig==", + "dependencies": { + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-arc": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-arc/-/line-arc-6.5.0.tgz", + "integrity": "sha512-I6c+V6mIyEwbtg9P9zSFF89T7QPe1DPTG3MJJ6Cm1MrAY0MdejwQKOpsvNl8LDU2ekHOlz2kHpPVR7VJsoMllA==", + "dependencies": { + "@turf/circle": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-chunk": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-chunk/-/line-chunk-6.5.0.tgz", + "integrity": "sha512-i1FGE6YJaaYa+IJesTfyRRQZP31QouS+wh/pa6O3CC0q4T7LtHigyBSYjrbjSLfn2EVPYGlPCMFEqNWCOkC6zg==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/length": "^6.5.0", + "@turf/line-slice-along": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-intersect": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-intersect/-/line-intersect-6.5.0.tgz", + "integrity": "sha512-CS6R1tZvVQD390G9Ea4pmpM6mJGPWoL82jD46y0q1KSor9s6HupMIo1kY4Ny+AEYQl9jd21V3Scz20eldpbTVA==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-segment": "^6.5.0", + "@turf/meta": "^6.5.0", + "geojson-rbush": "3.x" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-offset": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-offset/-/line-offset-6.5.0.tgz", + "integrity": "sha512-CEXZbKgyz8r72qRvPchK0dxqsq8IQBdH275FE6o4MrBkzMcoZsfSjghtXzKaz9vvro+HfIXal0sTk2mqV1lQTw==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-overlap": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-overlap/-/line-overlap-6.5.0.tgz", + "integrity": "sha512-xHOaWLd0hkaC/1OLcStCpfq55lPHpPNadZySDXYiYjEz5HXr1oKmtMYpn0wGizsLwrOixRdEp+j7bL8dPt4ojQ==", + "dependencies": { + "@turf/boolean-point-on-line": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-segment": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/nearest-point-on-line": "^6.5.0", + "deep-equal": "1.x", + "geojson-rbush": "3.x" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-segment": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-segment/-/line-segment-6.5.0.tgz", + "integrity": "sha512-jI625Ho4jSuJESNq66Mmi290ZJ5pPZiQZruPVpmHkUw257Pew0alMmb6YrqYNnLUuiVVONxAAKXUVeeUGtycfw==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-slice": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-slice/-/line-slice-6.5.0.tgz", + "integrity": "sha512-vDqJxve9tBHhOaVVFXqVjF5qDzGtKWviyjbyi2QnSnxyFAmLlLnBfMX8TLQCAf2GxHibB95RO5FBE6I2KVPRuw==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/nearest-point-on-line": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-slice-along": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-slice-along/-/line-slice-along-6.5.0.tgz", + "integrity": "sha512-KHJRU6KpHrAj+BTgTNqby6VCTnDzG6a1sJx/I3hNvqMBLvWVA2IrkR9L9DtsQsVY63IBwVdQDqiwCuZLDQh4Ng==", + "dependencies": { + "@turf/bearing": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-split": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-split/-/line-split-6.5.0.tgz", + "integrity": "sha512-/rwUMVr9OI2ccJjw7/6eTN53URtGThNSD5I0GgxyFXMtxWiloRJ9MTff8jBbtPWrRka/Sh2GkwucVRAEakx9Sw==", + "dependencies": { + "@turf/bbox": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-intersect": "^6.5.0", + "@turf/line-segment": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/nearest-point-on-line": "^6.5.0", + "@turf/square": "^6.5.0", + "@turf/truncate": "^6.5.0", + "geojson-rbush": "3.x" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/line-to-polygon": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-to-polygon/-/line-to-polygon-6.5.0.tgz", + "integrity": "sha512-qYBuRCJJL8Gx27OwCD1TMijM/9XjRgXH/m/TyuND4OXedBpIWlK5VbTIO2gJ8OCfznBBddpjiObLBrkuxTpN4Q==", + "dependencies": { + "@turf/bbox": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/mask": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/mask/-/mask-6.5.0.tgz", + "integrity": "sha512-RQha4aU8LpBrmrkH8CPaaoAfk0Egj5OuXtv6HuCQnHeGNOQt3TQVibTA3Sh4iduq4EPxnZfDjgsOeKtrCA19lg==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "polygon-clipping": "^0.15.3" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/meta": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-6.5.0.tgz", + "integrity": "sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA==", + "dependencies": { + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/midpoint": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/midpoint/-/midpoint-6.5.0.tgz", + "integrity": "sha512-MyTzV44IwmVI6ec9fB2OgZ53JGNlgOpaYl9ArKoF49rXpL84F9rNATndbe0+MQIhdkw8IlzA6xVP4lZzfMNVCw==", + "dependencies": { + "@turf/bearing": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/moran-index": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/moran-index/-/moran-index-6.5.0.tgz", + "integrity": "sha512-ItsnhrU2XYtTtTudrM8so4afBCYWNaB0Mfy28NZwLjB5jWuAsvyV+YW+J88+neK/ougKMTawkmjQqodNJaBeLQ==", + "dependencies": { + "@turf/distance-weight": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/nearest-point": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/nearest-point/-/nearest-point-6.5.0.tgz", + "integrity": "sha512-fguV09QxilZv/p94s8SMsXILIAMiaXI5PATq9d7YWijLxWUj6Q/r43kxyoi78Zmwwh1Zfqz9w+bCYUAxZ5+euA==", + "dependencies": { + "@turf/clone": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/nearest-point-on-line": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/nearest-point-on-line/-/nearest-point-on-line-6.5.0.tgz", + "integrity": "sha512-WthrvddddvmymnC+Vf7BrkHGbDOUu6Z3/6bFYUGv1kxw8tiZ6n83/VG6kHz4poHOfS0RaNflzXSkmCi64fLBlg==", + "dependencies": { + "@turf/bearing": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-intersect": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/nearest-point-to-line": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/nearest-point-to-line/-/nearest-point-to-line-6.5.0.tgz", + "integrity": "sha512-PXV7cN0BVzUZdjj6oeb/ESnzXSfWmEMrsfZSDRgqyZ9ytdiIj/eRsnOXLR13LkTdXVOJYDBuf7xt1mLhM4p6+Q==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/point-to-line-distance": "^6.5.0", + "object-assign": "*" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/planepoint": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/planepoint/-/planepoint-6.5.0.tgz", + "integrity": "sha512-R3AahA6DUvtFbka1kcJHqZ7DMHmPXDEQpbU5WaglNn7NaCQg9HB0XM0ZfqWcd5u92YXV+Gg8QhC8x5XojfcM4Q==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/point-grid": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/point-grid/-/point-grid-6.5.0.tgz", + "integrity": "sha512-Iq38lFokNNtQJnOj/RBKmyt6dlof0yhaHEDELaWHuECm1lIZLY3ZbVMwbs+nXkwTAHjKfS/OtMheUBkw+ee49w==", + "dependencies": { + "@turf/boolean-within": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/point-on-feature": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/point-on-feature/-/point-on-feature-6.5.0.tgz", + "integrity": "sha512-bDpuIlvugJhfcF/0awAQ+QI6Om1Y1FFYE8Y/YdxGRongivix850dTeXCo0mDylFdWFPGDo7Mmh9Vo4VxNwW/TA==", + "dependencies": { + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/center": "^6.5.0", + "@turf/explode": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/nearest-point": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/point-to-line-distance": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/point-to-line-distance/-/point-to-line-distance-6.5.0.tgz", + "integrity": "sha512-opHVQ4vjUhNBly1bob6RWy+F+hsZDH9SA0UW36pIRzfpu27qipU18xup0XXEePfY6+wvhF6yL/WgCO2IbrLqEA==", + "dependencies": { + "@turf/bearing": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/projection": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0", + "@turf/rhumb-distance": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/points-within-polygon": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/points-within-polygon/-/points-within-polygon-6.5.0.tgz", + "integrity": "sha512-YyuheKqjliDsBDt3Ho73QVZk1VXX1+zIA2gwWvuz8bR1HXOkcuwk/1J76HuFMOQI3WK78wyAi+xbkx268PkQzQ==", + "dependencies": { + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/polygon-smooth": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/polygon-smooth/-/polygon-smooth-6.5.0.tgz", + "integrity": "sha512-LO/X/5hfh/Rk4EfkDBpLlVwt3i6IXdtQccDT9rMjXEP32tRgy0VMFmdkNaXoGlSSKf/1mGqLl4y4wHd86DqKbg==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/polygon-tangents": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/polygon-tangents/-/polygon-tangents-6.5.0.tgz", + "integrity": "sha512-sB4/IUqJMYRQH9jVBwqS/XDitkEfbyqRy+EH/cMRJURTg78eHunvJ708x5r6umXsbiUyQU4eqgPzEylWEQiunw==", + "dependencies": { + "@turf/bbox": "^6.5.0", + "@turf/boolean-within": "^6.5.0", + "@turf/explode": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/nearest-point": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/polygon-to-line": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/polygon-to-line/-/polygon-to-line-6.5.0.tgz", + "integrity": "sha512-5p4n/ij97EIttAq+ewSnKt0ruvuM+LIDzuczSzuHTpq4oS7Oq8yqg5TQ4nzMVuK41r/tALCk7nAoBuw3Su4Gcw==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/polygonize": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/polygonize/-/polygonize-6.5.0.tgz", + "integrity": "sha512-a/3GzHRaCyzg7tVYHo43QUChCspa99oK4yPqooVIwTC61npFzdrmnywMv0S+WZjHZwK37BrFJGFrZGf6ocmY5w==", + "dependencies": { + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/envelope": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/projection": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/projection/-/projection-6.5.0.tgz", + "integrity": "sha512-/Pgh9mDvQWWu8HRxqpM+tKz8OzgauV+DiOcr3FCjD6ubDnrrmMJlsf6fFJmggw93mtVPrZRL6yyi9aYCQBOIvg==", + "dependencies": { + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/random": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/random/-/random-6.5.0.tgz", + "integrity": "sha512-8Q25gQ/XbA7HJAe+eXp4UhcXM9aOOJFaxZ02+XSNwMvY8gtWSCBLVqRcW4OhqilgZ8PeuQDWgBxeo+BIqqFWFQ==", + "dependencies": { + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/rectangle-grid": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/rectangle-grid/-/rectangle-grid-6.5.0.tgz", + "integrity": "sha512-yQZ/1vbW68O2KsSB3OZYK+72aWz/Adnf7m2CMKcC+aq6TwjxZjAvlbCOsNUnMAuldRUVN1ph6RXMG4e9KEvKvg==", + "dependencies": { + "@turf/boolean-intersects": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/rewind": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/rewind/-/rewind-6.5.0.tgz", + "integrity": "sha512-IoUAMcHWotBWYwSYuYypw/LlqZmO+wcBpn8ysrBNbazkFNkLf3btSDZMkKJO/bvOzl55imr/Xj4fi3DdsLsbzQ==", + "dependencies": { + "@turf/boolean-clockwise": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/rhumb-bearing": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/rhumb-bearing/-/rhumb-bearing-6.5.0.tgz", + "integrity": "sha512-jMyqiMRK4hzREjQmnLXmkJ+VTNTx1ii8vuqRwJPcTlKbNWfjDz/5JqJlb5NaFDcdMpftWovkW5GevfnuzHnOYA==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/rhumb-destination": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/rhumb-destination/-/rhumb-destination-6.5.0.tgz", + "integrity": "sha512-RHNP1Oy+7xTTdRrTt375jOZeHceFbjwohPHlr9Hf68VdHHPMAWgAKqiX2YgSWDcvECVmiGaBKWus1Df+N7eE4Q==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/rhumb-distance": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/rhumb-distance/-/rhumb-distance-6.5.0.tgz", + "integrity": "sha512-oKp8KFE8E4huC2Z1a1KNcFwjVOqa99isxNOwfo4g3SUABQ6NezjKDDrnvC4yI5YZ3/huDjULLBvhed45xdCrzg==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/sample": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/sample/-/sample-6.5.0.tgz", + "integrity": "sha512-kSdCwY7el15xQjnXYW520heKUrHwRvnzx8ka4eYxX9NFeOxaFITLW2G7UtXb6LJK8mmPXI8Aexv23F2ERqzGFg==", + "dependencies": { + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/sector": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/sector/-/sector-6.5.0.tgz", + "integrity": "sha512-cYUOkgCTWqa23SOJBqxoFAc/yGCUsPRdn/ovbRTn1zNTm/Spmk6hVB84LCKOgHqvSF25i0d2kWqpZDzLDdAPbw==", + "dependencies": { + "@turf/circle": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-arc": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/shortest-path": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/shortest-path/-/shortest-path-6.5.0.tgz", + "integrity": "sha512-4de5+G7+P4hgSoPwn+SO9QSi9HY5NEV/xRJ+cmoFVRwv2CDsuOPDheHKeuIAhKyeKDvPvPt04XYWbac4insJMg==", + "dependencies": { + "@turf/bbox": "^6.5.0", + "@turf/bbox-polygon": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/clean-coords": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/transform-scale": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/simplify": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/simplify/-/simplify-6.5.0.tgz", + "integrity": "sha512-USas3QqffPHUY184dwQdP8qsvcVH/PWBYdXY5am7YTBACaQOMAlf6AKJs9FT8jiO6fQpxfgxuEtwmox+pBtlOg==", + "dependencies": { + "@turf/clean-coords": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/square": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/square/-/square-6.5.0.tgz", + "integrity": "sha512-BM2UyWDmiuHCadVhHXKIx5CQQbNCpOxB6S/aCNOCLbhCeypKX5Q0Aosc5YcmCJgkwO5BERCC6Ee7NMbNB2vHmQ==", + "dependencies": { + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/square-grid": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/square-grid/-/square-grid-6.5.0.tgz", + "integrity": "sha512-mlR0ayUdA+L4c9h7p4k3pX6gPWHNGuZkt2c5II1TJRmhLkW2557d6b/Vjfd1z9OVaajb1HinIs1FMSAPXuuUrA==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/rectangle-grid": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/standard-deviational-ellipse": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/standard-deviational-ellipse/-/standard-deviational-ellipse-6.5.0.tgz", + "integrity": "sha512-02CAlz8POvGPFK2BKK8uHGUk/LXb0MK459JVjKxLC2yJYieOBTqEbjP0qaWhiBhGzIxSMaqe8WxZ0KvqdnstHA==", + "dependencies": { + "@turf/center-mean": "^6.5.0", + "@turf/ellipse": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/points-within-polygon": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/tag": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/tag/-/tag-6.5.0.tgz", + "integrity": "sha512-XwlBvrOV38CQsrNfrxvBaAPBQgXMljeU0DV8ExOyGM7/hvuGHJw3y8kKnQ4lmEQcmcrycjDQhP7JqoRv8vFssg==", + "dependencies": { + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/tesselate": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/tesselate/-/tesselate-6.5.0.tgz", + "integrity": "sha512-M1HXuyZFCfEIIKkglh/r5L9H3c5QTEsnMBoZOFQiRnGPGmJWcaBissGb7mTFX2+DKE7FNWXh4TDnZlaLABB0dQ==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "earcut": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/tin": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/tin/-/tin-6.5.0.tgz", + "integrity": "sha512-YLYikRzKisfwj7+F+Tmyy/LE3d2H7D4kajajIfc9mlik2+esG7IolsX/+oUz1biguDYsG0DUA8kVYXDkobukfg==", + "dependencies": { + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/transform-rotate": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/transform-rotate/-/transform-rotate-6.5.0.tgz", + "integrity": "sha512-A2Ip1v4246ZmpssxpcL0hhiVBEf4L8lGnSPWTgSv5bWBEoya2fa/0SnFX9xJgP40rMP+ZzRaCN37vLHbv1Guag==", + "dependencies": { + "@turf/centroid": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0", + "@turf/rhumb-destination": "^6.5.0", + "@turf/rhumb-distance": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/transform-scale": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/transform-scale/-/transform-scale-6.5.0.tgz", + "integrity": "sha512-VsATGXC9rYM8qTjbQJ/P7BswKWXHdnSJ35JlV4OsZyHBMxJQHftvmZJsFbOqVtQnIQIzf2OAly6rfzVV9QLr7g==", + "dependencies": { + "@turf/bbox": "^6.5.0", + "@turf/center": "^6.5.0", + "@turf/centroid": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0", + "@turf/rhumb-destination": "^6.5.0", + "@turf/rhumb-distance": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/transform-translate": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/transform-translate/-/transform-translate-6.5.0.tgz", + "integrity": "sha512-NABLw5VdtJt/9vSstChp93pc6oel4qXEos56RBMsPlYB8hzNTEKYtC146XJvyF4twJeeYS8RVe1u7KhoFwEM5w==", + "dependencies": { + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/rhumb-destination": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/triangle-grid": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/triangle-grid/-/triangle-grid-6.5.0.tgz", + "integrity": "sha512-2jToUSAS1R1htq4TyLQYPTIsoy6wg3e3BQXjm2rANzw4wPQCXGOxrur1Fy9RtzwqwljlC7DF4tg0OnWr8RjmfA==", + "dependencies": { + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/intersect": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/truncate": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/truncate/-/truncate-6.5.0.tgz", + "integrity": "sha512-pFxg71pLk+eJj134Z9yUoRhIi8vqnnKvCYwdT4x/DQl/19RVdq1tV3yqOT3gcTQNfniteylL5qV1uTBDV5sgrg==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/turf": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/turf/-/turf-6.5.0.tgz", + "integrity": "sha512-ipMCPnhu59bh92MNt8+pr1VZQhHVuTMHklciQURo54heoxRzt1neNYZOBR6jdL+hNsbDGAECMuIpAutX+a3Y+w==", + "dependencies": { + "@turf/along": "^6.5.0", + "@turf/angle": "^6.5.0", + "@turf/area": "^6.5.0", + "@turf/bbox": "^6.5.0", + "@turf/bbox-clip": "^6.5.0", + "@turf/bbox-polygon": "^6.5.0", + "@turf/bearing": "^6.5.0", + "@turf/bezier-spline": "^6.5.0", + "@turf/boolean-clockwise": "^6.5.0", + "@turf/boolean-contains": "^6.5.0", + "@turf/boolean-crosses": "^6.5.0", + "@turf/boolean-disjoint": "^6.5.0", + "@turf/boolean-equal": "^6.5.0", + "@turf/boolean-intersects": "^6.5.0", + "@turf/boolean-overlap": "^6.5.0", + "@turf/boolean-parallel": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/boolean-point-on-line": "^6.5.0", + "@turf/boolean-within": "^6.5.0", + "@turf/buffer": "^6.5.0", + "@turf/center": "^6.5.0", + "@turf/center-mean": "^6.5.0", + "@turf/center-median": "^6.5.0", + "@turf/center-of-mass": "^6.5.0", + "@turf/centroid": "^6.5.0", + "@turf/circle": "^6.5.0", + "@turf/clean-coords": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/clusters": "^6.5.0", + "@turf/clusters-dbscan": "^6.5.0", + "@turf/clusters-kmeans": "^6.5.0", + "@turf/collect": "^6.5.0", + "@turf/combine": "^6.5.0", + "@turf/concave": "^6.5.0", + "@turf/convex": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/difference": "^6.5.0", + "@turf/dissolve": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/distance-weight": "^6.5.0", + "@turf/ellipse": "^6.5.0", + "@turf/envelope": "^6.5.0", + "@turf/explode": "^6.5.0", + "@turf/flatten": "^6.5.0", + "@turf/flip": "^6.5.0", + "@turf/great-circle": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/hex-grid": "^6.5.0", + "@turf/interpolate": "^6.5.0", + "@turf/intersect": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/isobands": "^6.5.0", + "@turf/isolines": "^6.5.0", + "@turf/kinks": "^6.5.0", + "@turf/length": "^6.5.0", + "@turf/line-arc": "^6.5.0", + "@turf/line-chunk": "^6.5.0", + "@turf/line-intersect": "^6.5.0", + "@turf/line-offset": "^6.5.0", + "@turf/line-overlap": "^6.5.0", + "@turf/line-segment": "^6.5.0", + "@turf/line-slice": "^6.5.0", + "@turf/line-slice-along": "^6.5.0", + "@turf/line-split": "^6.5.0", + "@turf/line-to-polygon": "^6.5.0", + "@turf/mask": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/midpoint": "^6.5.0", + "@turf/moran-index": "^6.5.0", + "@turf/nearest-point": "^6.5.0", + "@turf/nearest-point-on-line": "^6.5.0", + "@turf/nearest-point-to-line": "^6.5.0", + "@turf/planepoint": "^6.5.0", + "@turf/point-grid": "^6.5.0", + "@turf/point-on-feature": "^6.5.0", + "@turf/point-to-line-distance": "^6.5.0", + "@turf/points-within-polygon": "^6.5.0", + "@turf/polygon-smooth": "^6.5.0", + "@turf/polygon-tangents": "^6.5.0", + "@turf/polygon-to-line": "^6.5.0", + "@turf/polygonize": "^6.5.0", + "@turf/projection": "^6.5.0", + "@turf/random": "^6.5.0", + "@turf/rewind": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0", + "@turf/rhumb-destination": "^6.5.0", + "@turf/rhumb-distance": "^6.5.0", + "@turf/sample": "^6.5.0", + "@turf/sector": "^6.5.0", + "@turf/shortest-path": "^6.5.0", + "@turf/simplify": "^6.5.0", + "@turf/square": "^6.5.0", + "@turf/square-grid": "^6.5.0", + "@turf/standard-deviational-ellipse": "^6.5.0", + "@turf/tag": "^6.5.0", + "@turf/tesselate": "^6.5.0", + "@turf/tin": "^6.5.0", + "@turf/transform-rotate": "^6.5.0", + "@turf/transform-scale": "^6.5.0", + "@turf/transform-translate": "^6.5.0", + "@turf/triangle-grid": "^6.5.0", + "@turf/truncate": "^6.5.0", + "@turf/union": "^6.5.0", + "@turf/unkink-polygon": "^6.5.0", + "@turf/voronoi": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/union": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/union/-/union-6.5.0.tgz", + "integrity": "sha512-igYWCwP/f0RFHIlC2c0SKDuM/ObBaqSljI3IdV/x71805QbIvY/BYGcJdyNcgEA6cylIGl/0VSlIbpJHZ9ldhw==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "polygon-clipping": "^0.15.3" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/unkink-polygon": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/unkink-polygon/-/unkink-polygon-6.5.0.tgz", + "integrity": "sha512-8QswkzC0UqKmN1DT6HpA9upfa1HdAA5n6bbuzHy8NJOX8oVizVAqfEPY0wqqTgboDjmBR4yyImsdPGUl3gZ8JQ==", + "dependencies": { + "@turf/area": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0", + "rbush": "^2.0.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/voronoi": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/voronoi/-/voronoi-6.5.0.tgz", + "integrity": "sha512-C/xUsywYX+7h1UyNqnydHXiun4UPjK88VDghtoRypR9cLlb7qozkiLRphQxxsCM0KxyxpVPHBVQXdAL3+Yurow==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "d3-voronoi": "1.1.2" + }, + "funding": { + "url": "https://opencollective.com/turf" + } }, "node_modules/@types/adm-zip": { "version": "0.5.5", @@ -4415,6 +6080,14 @@ "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", "dev": true }, + "node_modules/@types/mapbox-gl": { + "version": "2.7.19", + "resolved": "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-2.7.19.tgz", + "integrity": "sha512-pkRdlhQJNbtwcKJSVC4uuOA6M3OlOObIMhNecqHB991oeaDF5XkjSIRaTE0lh5p4KClptSCxW6MBiREVRHrl2A==", + "dependencies": { + "@types/geojson": "*" + } + }, "node_modules/@types/mdast": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", @@ -5496,6 +7169,14 @@ "dequal": "^2.0.3" } }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/array-back": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", @@ -5703,6 +7384,14 @@ "node": "*" } }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ast-types-flow": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", @@ -9255,6 +10944,23 @@ "node": ">= 0.8" } }, + "node_modules/bytewise": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bytewise/-/bytewise-1.1.0.tgz", + "integrity": "sha512-rHuuseJ9iQ0na6UDhnrRVDh8YnWVlU6xM3VH6q/+yHDeUH2zIhUzP+2/h3LIrhLDBtTqzWpE3p3tP/boefskKQ==", + "dependencies": { + "bytewise-core": "^1.2.2", + "typewise": "^1.0.3" + } + }, + "node_modules/bytewise-core": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bytewise-core/-/bytewise-core-1.2.3.tgz", + "integrity": "sha512-nZD//kc78OOxeYtRlVk8/zXqTB4gf/nlguL1ggWA8FuchMyOxcyHR4QPQZMUmA7czC+YnaBrPUCubqAWe50DaA==", + "dependencies": { + "typewise-core": "^1.2" + } + }, "node_modules/cacheable-lookup": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", @@ -9503,6 +11209,11 @@ "pnpm": ">=7" } }, + "node_modules/cheap-ruler": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/cheap-ruler/-/cheap-ruler-3.0.2.tgz", + "integrity": "sha512-02T332h1/HTN6cDSufLP8x4JzDs2+VC+8qZ/N0kWIVPyc2xUkWwWh3B2fJxR7raXkL4Mq7k554mfuM9ofv/vGg==" + }, "node_modules/check-error": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", @@ -9920,6 +11631,35 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "node_modules/concaveman": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/concaveman/-/concaveman-1.2.1.tgz", + "integrity": "sha512-PwZYKaM/ckQSa8peP5JpVr7IMJ4Nn/MHIaWUjP4be+KoZ7Botgs8seAZGpmaOM+UZXawcdYRao/px9ycrCihHw==", + "dependencies": { + "point-in-polygon": "^1.1.0", + "rbush": "^3.0.1", + "robust-predicates": "^2.0.4", + "tinyqueue": "^2.0.3" + } + }, + "node_modules/concaveman/node_modules/quickselect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", + "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + }, + "node_modules/concaveman/node_modules/rbush": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz", + "integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==", + "dependencies": { + "quickselect": "^2.0.0" + } + }, + "node_modules/concaveman/node_modules/robust-predicates": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-2.0.4.tgz", + "integrity": "sha512-l4NwboJM74Ilm4VKfbAtFeGq7aEjWL+5kVFcmgFA2MrdnQWx9iE/tUGvxY5HyMI7o/WpSIUFLbC5fbeaHgSCYg==" + }, "node_modules/confusing-browser-globals": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", @@ -10344,6 +12084,11 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/csscolorparser": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz", + "integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==" + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -10768,6 +12513,11 @@ "d3-selection": "2 - 3" } }, + "node_modules/d3-voronoi": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.2.tgz", + "integrity": "sha512-RhGS1u2vavcO7ay7ZNAPo4xeDh/VYeGof3x5ZLJBQgYhLegxr3s5IykvWmJ94FTU6mcbtp4sloqZ54mP6R4Utw==" + }, "node_modules/d3-zoom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", @@ -10932,6 +12682,25 @@ "node": ">=6" } }, + "node_modules/deep-equal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", + "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", + "dependencies": { + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.5.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -11126,7 +12895,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -11160,6 +12928,11 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, + "node_modules/density-clustering": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/density-clustering/-/density-clustering-1.3.0.tgz", + "integrity": "sha512-icpmBubVTwLnsaor9qH/4tG5+7+f61VcqMN3V3pm9sxxSCt2Jcs0zWOgwZW9ARJYaKD3FumIgHiMOcIMRRAzFQ==" + }, "node_modules/depcheck": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/depcheck/-/depcheck-1.4.7.tgz", @@ -11465,6 +13238,11 @@ "xtend": "^4.0.0" } }, + "node_modules/earcut": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", + "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -13674,6 +15452,17 @@ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -14601,7 +16390,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -14701,6 +16489,49 @@ "node": ">=6.9.0" } }, + "node_modules/geojson-equality": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/geojson-equality/-/geojson-equality-0.1.6.tgz", + "integrity": "sha512-TqG8YbqizP3EfwP5Uw4aLu6pKkg6JQK9uq/XZ1lXQntvTHD1BBKJWhNpJ2M0ax6TuWMP3oyx6Oq7FCIfznrgpQ==", + "dependencies": { + "deep-equal": "^1.0.0" + } + }, + "node_modules/geojson-rbush": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/geojson-rbush/-/geojson-rbush-3.2.0.tgz", + "integrity": "sha512-oVltQTXolxvsz1sZnutlSuLDEcQAKYC/uXt9zDzJJ6bu0W+baTI8LZBaTup5afzibEH4N3jlq2p+a152wlBJ7w==", + "dependencies": { + "@turf/bbox": "*", + "@turf/helpers": "6.x", + "@turf/meta": "6.x", + "@types/geojson": "7946.0.8", + "rbush": "^3.0.1" + } + }, + "node_modules/geojson-rbush/node_modules/@types/geojson": { + "version": "7946.0.8", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz", + "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==" + }, + "node_modules/geojson-rbush/node_modules/quickselect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", + "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + }, + "node_modules/geojson-rbush/node_modules/rbush": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz", + "integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==", + "dependencies": { + "quickselect": "^2.0.0" + } + }, + "node_modules/geojson-vt": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz", + "integrity": "sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==" + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -14780,6 +16611,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -14797,6 +16636,11 @@ "omggif": "^1.0.10" } }, + "node_modules/gl-matrix": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", + "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" + }, "node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", @@ -15034,6 +16878,11 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "node_modules/grid-index": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/grid-index/-/grid-index-1.1.0.tgz", + "integrity": "sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==" + }, "node_modules/gtoken": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.0.1.tgz", @@ -16501,7 +18350,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -16556,6 +18404,14 @@ "node": ">=0.4.0" } }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -17235,6 +19091,11 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/json-stringify-pretty-compact": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz", + "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==" + }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -17916,6 +19777,41 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "node_modules/mapbox-gl": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-3.0.1.tgz", + "integrity": "sha512-o7C6sAlj6Hkdd4xQVEgQflgJYNYyZOAtYahhIOb9m8chI8umtWcCp8Ie0iGLYJvce1WHRMa3WGzs69ggwuWlDA==", + "dependencies": { + "@mapbox/geojson-rewind": "^0.5.2", + "@mapbox/jsonlint-lines-primitives": "^2.0.2", + "@mapbox/mapbox-gl-supported": "^2.0.1", + "@mapbox/point-geometry": "^0.1.0", + "@mapbox/tiny-sdf": "^2.0.6", + "@mapbox/unitbezier": "^0.0.1", + "@mapbox/vector-tile": "^1.3.1", + "@mapbox/whoots-js": "^3.1.0", + "cheap-ruler": "^3.0.1", + "csscolorparser": "~1.0.3", + "earcut": "^2.2.4", + "geojson-vt": "^3.2.1", + "gl-matrix": "^3.4.3", + "grid-index": "^1.1.0", + "kdbush": "^4.0.1", + "murmurhash-js": "^1.0.0", + "pbf": "^3.2.1", + "potpack": "^2.0.0", + "quickselect": "^2.0.0", + "rw": "^1.3.3", + "supercluster": "^8.0.0", + "tinyqueue": "^2.0.3", + "vt-pbf": "^3.1.3" + } + }, + "node_modules/mapbox-gl/node_modules/quickselect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", + "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + }, "node_modules/markdown-table": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", @@ -19479,6 +21375,11 @@ "node": "*" } }, + "node_modules/murmurhash-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz", + "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==" + }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -22598,11 +24499,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, "engines": { "node": ">= 0.4" } @@ -23300,6 +25215,18 @@ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, + "node_modules/pbf": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz", + "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==", + "dependencies": { + "ieee754": "^1.1.12", + "resolve-protobuf-schema": "^2.1.0" + }, + "bin": { + "pbf": "bin/pbf" + } + }, "node_modules/pdf-parse": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pdf-parse/-/pdf-parse-1.1.1.tgz", @@ -23531,6 +25458,19 @@ "node": ">=12.13.0" } }, + "node_modules/point-in-polygon": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/point-in-polygon/-/point-in-polygon-1.1.0.tgz", + "integrity": "sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw==" + }, + "node_modules/polygon-clipping": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/polygon-clipping/-/polygon-clipping-0.15.3.tgz", + "integrity": "sha512-ho0Xx5DLkgxRx/+n4O74XyJ67DcyN3Tu9bGYKsnTukGAW6ssnuak6Mwcyb1wHy9MZc9xsUWqIoiazkZB5weECg==", + "dependencies": { + "splaytree": "^3.1.0" + } + }, "node_modules/postcss": { "version": "8.4.32", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", @@ -23647,6 +25587,11 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/potpack": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz", + "integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==" + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -23856,6 +25801,11 @@ "prosemirror-transform": "^1.1.0" } }, + "node_modules/protocol-buffers-schema": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", + "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==" + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -24100,6 +26050,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/quickselect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-1.1.1.tgz", + "integrity": "sha512-qN0Gqdw4c4KGPsBOQafj6yj/PA6c/L63f6CaZ/DCF/xF4Esu3jVmKLUDYxghFx8Kb/O7y9tI7x2RjTSXwdK1iQ==" + }, "node_modules/random-bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", @@ -24174,6 +26129,14 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/rbush": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/rbush/-/rbush-2.0.2.tgz", + "integrity": "sha512-XBOuALcTm+O/H8G90b6pzu6nX6v2zCKiFG4BJho8a+bY6AER6t8uQUZdi5bomQc0AprCWhEGa7ncAbbRap0bRA==", + "dependencies": { + "quickselect": "^1.0.1" + } + }, "node_modules/rc-switch": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-4.1.0.tgz", @@ -24410,6 +26373,29 @@ "react": ">=0.14.0" } }, + "node_modules/react-map-gl": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/react-map-gl/-/react-map-gl-7.1.6.tgz", + "integrity": "sha512-9XbrvpFF67Fyi+e6vRLJFnGpo3UF6ZHifIa8cS/wUYSsnv9sVyzGsN++FJy57zkz3Jh3kmf0xKZemR8K0FZLVw==", + "dependencies": { + "@maplibre/maplibre-gl-style-spec": "^19.2.1", + "@types/mapbox-gl": ">=1.0.0" + }, + "peerDependencies": { + "mapbox-gl": ">=1.13.0", + "maplibre-gl": ">=1.13.0", + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + }, + "peerDependenciesMeta": { + "mapbox-gl": { + "optional": true + }, + "maplibre-gl": { + "optional": true + } + } + }, "node_modules/react-markdown": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.0.1.tgz", @@ -24775,7 +26761,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -25197,6 +27182,14 @@ "node": ">=8" } }, + "node_modules/resolve-protobuf-schema": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", + "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "dependencies": { + "protocol-buffers-schema": "^3.3.1" + } + }, "node_modules/responselike": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", @@ -25913,7 +27906,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", - "dev": true, "dependencies": { "define-data-property": "^1.0.1", "functions-have-names": "^1.2.3", @@ -25923,6 +27915,20 @@ "node": ">= 0.4" } }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -26165,6 +28171,11 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/skmeans": { + "version": "0.9.7", + "resolved": "https://registry.npmjs.org/skmeans/-/skmeans-0.9.7.tgz", + "integrity": "sha512-hNj1/oZ7ygsfmPZ7ZfN5MUBRoGg1gtpnImuJBgLO0ljQ67DtJuiQaiYdS4lUA6s0KCwnPhGivtC/WRwIZLkHyg==" + }, "node_modules/slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", @@ -26279,6 +28290,38 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/sort-asc": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/sort-asc/-/sort-asc-0.2.0.tgz", + "integrity": "sha512-umMGhjPeHAI6YjABoSTrFp2zaBtXBej1a0yKkuMUyjjqu6FJsTF+JYwCswWDg+zJfk/5npWUUbd33HH/WLzpaA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-desc": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/sort-desc/-/sort-desc-0.2.0.tgz", + "integrity": "sha512-NqZqyvL4VPW+RAxxXnB8gvE1kyikh8+pR+T+CXLksVRN9eiQqkQlPwqWYU0mF9Jm7UnctShlxLyAt1CaBOTL1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-object": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sort-object/-/sort-object-3.0.3.tgz", + "integrity": "sha512-nK7WOY8jik6zaG9CRwZTaD5O7ETWDLZYMM12pqY8htll+7dYeqGfEUPcUBHOpSJg2vJOrvFIY2Dl5cX2ih1hAQ==", + "dependencies": { + "bytewise": "^1.1.0", + "get-value": "^2.0.2", + "is-extendable": "^0.1.1", + "sort-asc": "^0.2.0", + "sort-desc": "^0.2.0", + "union-value": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -26359,6 +28402,11 @@ "wbuf": "^1.7.3" } }, + "node_modules/splaytree": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/splaytree/-/splaytree-3.1.2.tgz", + "integrity": "sha512-4OM2BJgC5UzrhVnnJA4BkHKGtjXNzzUfpQjCO8I05xYPsfS/VuQDwjCGGMi8rYQilHEV4j8NBqTFbls/PZEE7A==" + }, "node_modules/split-on-first": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", @@ -26372,6 +28420,40 @@ "resolved": "https://registry.npmjs.org/split-skip/-/split-skip-0.0.2.tgz", "integrity": "sha512-weHOi8BolsDnGIwhhWHbA+wKSuSpvWwjRrdj8SdbIIis2vSwOE37CQP8x3EleuzxanUr3AK8BdUy4MkiOULPZg==" }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -27034,7 +29116,8 @@ "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true }, "node_modules/textarea-caret": { "version": "3.1.0", @@ -27073,6 +29156,11 @@ "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==" }, + "node_modules/tinyqueue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", + "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==" + }, "node_modules/titleize": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", @@ -27145,6 +29233,40 @@ "url": "https://github.com/sponsors/Borewit" } }, + "node_modules/topojson-client": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz", + "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==", + "dependencies": { + "commander": "2" + }, + "bin": { + "topo2geo": "bin/topo2geo", + "topomerge": "bin/topomerge", + "topoquantize": "bin/topoquantize" + } + }, + "node_modules/topojson-client/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/topojson-server": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/topojson-server/-/topojson-server-3.0.1.tgz", + "integrity": "sha512-/VS9j/ffKr2XAOjlZ9CgyyeLmgJ9dMwq6Y0YEON8O7p/tGGk+dCWnrE03zEdu7i4L7YsFZLEPZPzCvcB7lEEXw==", + "dependencies": { + "commander": "2" + }, + "bin": { + "geo2topo": "bin/geo2topo" + } + }, + "node_modules/topojson-server/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, "node_modules/touch": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", @@ -27820,6 +29942,11 @@ "node": "*" } }, + "node_modules/turf-jsts": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/turf-jsts/-/turf-jsts-1.2.3.tgz", + "integrity": "sha512-Ja03QIJlPuHt4IQ2FfGex4F4JAr8m3jpaHbFbQrgwr7s7L6U8ocrHiF3J1+wf9jzhGKxvDeaCAnGDot8OjGFyA==" + }, "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", @@ -27963,6 +30090,19 @@ "node": ">=18" } }, + "node_modules/typewise": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typewise/-/typewise-1.0.3.tgz", + "integrity": "sha512-aXofE06xGhaQSPzt8hlTY+/YWQhm9P0jYUp1f2XtmW/3Bk0qzXcyFWAtPoo2uTGQj1ZwbDuSyuxicq+aDo8lCQ==", + "dependencies": { + "typewise-core": "^1.2.0" + } + }, + "node_modules/typewise-core": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/typewise-core/-/typewise-core-1.2.0.tgz", + "integrity": "sha512-2SCC/WLzj2SbUwzFOzqMCkz5amXLlxtJqDKTICqg30x+2DZxcfZN2MvQZmGfXWKNWaKK9pBPsvkcwv8bF/gxKg==" + }, "node_modules/typical": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz", @@ -28082,6 +30222,20 @@ "resolved": "https://registry.npmjs.org/uninstall/-/uninstall-0.0.0.tgz", "integrity": "sha512-pjP/0+A4gsbDVa8XH/S2GZdT9NPJW8NFMy3GI7HnsWG+NAmFSSj3QidNosXBI9cPtxxNExEDdhKFO6sli8K3mA==" }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/unist-util-is": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", @@ -28509,6 +30663,16 @@ "node": ">=0.10.0" } }, + "node_modules/vt-pbf": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz", + "integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==", + "dependencies": { + "@mapbox/point-geometry": "0.1.0", + "@mapbox/vector-tile": "^1.3.1", + "pbf": "^3.2.1" + } + }, "node_modules/w3c-keyname": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", diff --git a/package.json b/package.json index fa0dc3ff5..98453a651 100644 --- a/package.json +++ b/package.json @@ -109,6 +109,7 @@ "@mui/material": "^5.14.19", "@octokit/core": "^5.0.2", "@react-google-maps/api": "^2.19.2", + "@turf/turf": "^6.5.0", "@types/bezier-js": "^4.1.3", "@types/cors": "^2.8.17", "@types/d3-axis": "^3.0.6", @@ -197,6 +198,7 @@ "jsonschema": "^1.4.1", "jszip": "^3.10.1", "lodash": "^4.17.21", + "mapbox-gl": "^3.0.1", "mathquill": "^0.10.1-a", "md5-file": "^5.0.0", "memorystream": "^0.3.1", @@ -247,6 +249,7 @@ "react-icons": "^4.12.0", "react-jsx-parser": "^1.29.0", "react-loading": "^2.0.3", + "react-map-gl": "^7.1.6", "react-markdown": "^9.0.1", "react-measure": "^2.5.2", "react-resizable": "^3.0.5", diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index a626772e4..e31c04c40 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -98,7 +98,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { }; componentDidMount() { - this.props.setContentView?.(this); + this._props.setContentView?.(this); if (!DataVizBox.dataset.has(CsvCast(this.dataDoc[this.fieldKey]).url.href)) this.fetchData(); } @@ -110,19 +110,19 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { // toggles for user to decide which chart type to view the data in @computed get renderVizView() { - const scale = this.props.NativeDimScaling?.() || 1; + const scale = this._props.NativeDimScaling?.() || 1; const sharedProps = { Document: this.Document, layoutDoc: this.layoutDoc, records: this.records, axes: this.axes, - height: (this.props.PanelHeight() / scale - 32) /* height of 'change view' button */ * 0.9, - width: (this.props.PanelWidth() / scale) * 0.9, + height: (this._props.PanelHeight() / scale - 32) /* height of 'change view' button */ * 0.9, + width: (this._props.PanelWidth() / scale) * 0.9, margin: { top: 10, right: 25, bottom: 75, left: 45 }, }; if (!this.records.length) return 'no data/visualization'; switch (this.dataVizView) { - case DataVizView.TABLE: return ; + case DataVizView.TABLE: return ; case DataVizView.LINECHART: return (this._vizRenderer = r ?? undefined)} />; case DataVizView.HISTOGRAM: return (this._vizRenderer = r ?? undefined)} />; case DataVizView.PIECHART: return (this._vizRenderer = r ?? undefined)} @@ -131,7 +131,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { } render() { - const scale = this.props.NativeDimScaling?.() || 1; + const scale = this._props.NativeDimScaling?.() || 1; return !this.records.length ? ( // displays how to get data into the DataVizBox if its empty @@ -140,7 +140,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() {
{ +export class Histogram extends ObservableReactComponent { private _disposers: { [key: string]: IReactionDisposer } = {}; private _histogramRef: React.RefObject = React.createRef(); private _histogramSvg: d3.Selection | undefined; @@ -45,46 +46,51 @@ export class Histogram extends React.Component { private selectedData: any = undefined; // Selection of selected bar private hoverOverData: any = undefined; // Selection of bar being hovered over + constructor(props: any) { + super(props); + makeObservable(this); + } + @computed get _tableDataIds() { - return !this.parentViz ? this.props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows); + return !this.parentViz ? this._props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows); } // returns all the data records that will be rendered by only returning those records that have been selected by the parent visualization (or all records if there is no parent) @computed get _tableData() { - return !this.parentViz ? this.props.records : this._tableDataIds.map(rowId => this.props.records[rowId]); + return !this.parentViz ? this._props.records : this._tableDataIds.map(rowId => this._props.records[rowId]); } // filters all data to just display selected data if brushed (created from an incoming link) @computed get _histogramData() { - if (this.props.axes.length < 1) return []; - if (this.props.axes.length < 2) { - var ax0 = this.props.axes[0]; - if (/\d/.test(this.props.records[0][ax0])) { + if (this._props.axes.length < 1) return []; + if (this._props.axes.length < 2) { + var ax0 = this._props.axes[0]; + if (/\d/.test(this._props.records[0][ax0])) { this.numericalXData = true; } - return this._tableData.map(record => ({ [ax0]: record[this.props.axes[0]] })); + return this._tableData.map(record => ({ [ax0]: record[this._props.axes[0]] })); } - var ax0 = this.props.axes[0]; - var ax1 = this.props.axes[1]; - if (/\d/.test(this.props.records[0][ax0])) { + var ax0 = this._props.axes[0]; + var ax1 = this._props.axes[1]; + if (/\d/.test(this._props.records[0][ax0])) { this.numericalXData = true; } - if (/\d/.test(this.props.records[0][ax1])) { + if (/\d/.test(this._props.records[0][ax1])) { this.numericalYData = true; } - return this._tableData.map(record => ({ [ax0]: record[this.props.axes[0]], [ax1]: record[this.props.axes[1]] })); + return this._tableData.map(record => ({ [ax0]: record[this._props.axes[0]], [ax1]: record[this._props.axes[1]] })); } @computed get defaultGraphTitle() { - var ax0 = this.props.axes[0]; - var ax1 = this.props.axes.length > 1 ? this.props.axes[1] : undefined; - if (this.props.axes.length < 2 || !ax1 || !/\d/.test(this.props.records[0][ax1]) || !this.numericalYData) { + var ax0 = this._props.axes[0]; + var ax1 = this._props.axes.length > 1 ? this._props.axes[1] : undefined; + if (this._props.axes.length < 2 || !ax1 || !/\d/.test(this._props.records[0][ax1]) || !this.numericalYData) { return ax0 + ' Histogram'; } else return ax0 + ' by ' + ax1 + ' Histogram'; } @computed get parentViz() { - return DocCast(this.props.Document.dataViz_parentViz); - // return LinkManager.Instance.getAllRelatedLinks(this.props.Document) // out of all links - // .filter(link => link.link_anchor_1 == this.props.Document.dataViz_parentViz) // get links where this chart doc is the target of the link + return DocCast(this._props.Document.dataViz_parentViz); + // return LinkManager.Instance.getAllRelatedLinks(this._props.Document) // out of all links + // .filter(link => link.link_anchor_1 == this._props.Document.dataViz_parentViz) // get links where this chart doc is the target of the link // .map(link => DocCast(link.link_anchor_1)); // then return the source of the link } @@ -114,16 +120,16 @@ export class Histogram extends React.Component { const anchor = Docs.Create.ConfigDocument({ title: 'histogram doc selection' + this._currSelected, }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.Document); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this._props.Document); return anchor; }; @computed get height() { - return this.props.height - this.props.margin.top - this.props.margin.bottom; + return this._props.height - this._props.margin.top - this._props.margin.bottom; } @computed get width() { - return this.props.width - this.props.margin.left - this.props.margin.right; + return this._props.width - this._props.margin.left - this._props.margin.right; } // cleans data by converting numerical data to numbers and taking out empty cells @@ -211,10 +217,10 @@ export class Histogram extends React.Component { .select(this._histogramRef.current) .append('svg') .attr('class', 'graph') - .attr('width', width + this.props.margin.right + this.props.margin.left) - .attr('height', height + this.props.margin.top + this.props.margin.bottom) + .attr('width', width + this._props.margin.right + this._props.margin.left) + .attr('height', height + this._props.margin.top + this._props.margin.bottom) .append('g') - .attr('transform', 'translate(' + this.props.margin.left + ',' + this.props.margin.top + ')')); + .attr('transform', 'translate(' + this._props.margin.left + ',' + this._props.margin.top + ')')); var x = d3 .scaleLinear() .domain(this.numericalXData ? [startingPoint!, endingPoint!] : [0, numBins]) @@ -382,7 +388,7 @@ export class Histogram extends React.Component { ) .attr('fill', d => { var barColor; - const barColors = StrListCast(this.props.layoutDoc.dataViz_histogram_barColors).map(each => each.split('::')); + const barColors = StrListCast(this._props.layoutDoc.dataViz_histogram_barColors).map(each => each.split('::')); barColors.forEach(each => { if (d[0] && d[0].toString() && each[0] == d[0].toString()) barColor = each[1]; else { @@ -390,24 +396,24 @@ export class Histogram extends React.Component { if (Number(range[0]) <= d[0] && d[0] <= Number(range[1])) barColor = each[1]; } }); - return barColor ? StrCast(barColor) : StrCast(this.props.layoutDoc.dataViz_histogram_defaultColor); + return barColor ? StrCast(barColor) : StrCast(this._props.layoutDoc.dataViz_histogram_defaultColor); }); }; @action changeSelectedColor = (color: string) => { this.curBarSelected.attr('fill', color); - const barName = StrCast(this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ each.split('::')[0] === barName && barColors.splice(barColors.indexOf(each), 1)); barColors.push(StrCast(barName + '::' + color)); }; @action eraseSelectedColor = () => { - this.curBarSelected.attr('fill', this.props.layoutDoc.dataViz_histogram_defaultColor); - const barName = StrCast(this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ each.split('::')[0] === barName && barColors.splice(barColors.indexOf(each), 1)); }; @@ -416,7 +422,7 @@ export class Histogram extends React.Component { if (svg) svg.selectAll('rect').attr('fill', (d: any) => { var barColor; - const barColors = StrListCast(this.props.layoutDoc.dataViz_histogram_barColors).map(each => each.split('::')); + const barColors = StrListCast(this._props.layoutDoc.dataViz_histogram_barColors).map(each => each.split('::')); barColors.forEach(each => { if (d[0] && d[0].toString() && each[0] == d[0].toString()) barColor = each[1]; else { @@ -424,7 +430,7 @@ export class Histogram extends React.Component { if (Number(range[0]) <= d[0] && d[0] <= Number(range[1])) barColor = each[1]; } }); - return barColor ? StrCast(barColor) : StrCast(this.props.layoutDoc.dataViz_histogram_defaultColor); + return barColor ? StrCast(barColor) : StrCast(this._props.layoutDoc.dataViz_histogram_defaultColor); }); }; @@ -433,14 +439,14 @@ export class Histogram extends React.Component { this._histogramData; var curSelectedBarName = ''; var titleAccessor: any = ''; - if (this.props.axes.length == 2) titleAccessor = 'dataViz_histogram_title' + this.props.axes[0] + '-' + this.props.axes[1]; - else if (this.props.axes.length > 0) titleAccessor = 'dataViz_histogram_title' + this.props.axes[0]; - if (!this.props.layoutDoc[titleAccessor]) this.props.layoutDoc[titleAccessor] = this.defaultGraphTitle; - if (!this.props.layoutDoc.dataViz_histogram_defaultColor) this.props.layoutDoc.dataViz_histogram_defaultColor = '#69b3a2'; - if (!this.props.layoutDoc.dataViz_histogram_barColors) this.props.layoutDoc.dataViz_histogram_barColors = new List(); + if (this._props.axes.length == 2) titleAccessor = 'dataViz_histogram_title' + this._props.axes[0] + '-' + this._props.axes[1]; + else if (this._props.axes.length > 0) titleAccessor = 'dataViz_histogram_title' + this._props.axes[0]; + if (!this._props.layoutDoc[titleAccessor]) this._props.layoutDoc[titleAccessor] = this.defaultGraphTitle; + if (!this._props.layoutDoc.dataViz_histogram_defaultColor) this._props.layoutDoc.dataViz_histogram_defaultColor = '#69b3a2'; + if (!this._props.layoutDoc.dataViz_histogram_barColors) this._props.layoutDoc.dataViz_histogram_barColors = new List(); var selected = 'none'; if (this._currSelected) { - curSelectedBarName = StrCast(this._currSelected![this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\ key // @@ -450,17 +456,17 @@ export class Histogram extends React.Component { selected = selected.substring(0, selected.length - 2) + ' }'; } var selectedBarColor; - var barColors = StrListCast(this.props.layoutDoc.histogramBarColors).map(each => each.split('::')); + var barColors = StrListCast(this._props.layoutDoc.histogramBarColors).map(each => each.split('::')); barColors.forEach(each => each[0] === curSelectedBarName && (selectedBarColor = each[1])); if (this._histogramData.length > 0 || !this.parentViz) { - return this.props.axes.length >= 1 ? ( + return this._props.axes.length >= 1 ? (
(this.props.layoutDoc[titleAccessor] = val as string)), + action(val => (this._props.layoutDoc[titleAccessor] = val as string)), 'Change Graph Title' )} color={'black'} @@ -472,9 +478,9 @@ export class Histogram extends React.Component { tooltip={'Change Default Bar Color'} type={Type.SEC} icon={} - selectedColor={StrCast(this.props.layoutDoc.dataViz_histogram_defaultColor)} - setFinalColor={undoable(color => (this.props.layoutDoc.dataViz_histogram_defaultColor = color), 'Change Default Bar Color')} - setSelectedColor={undoable(color => (this.props.layoutDoc.dataViz_histogram_defaultColor = color), 'Change Default Bar Color')} + selectedColor={StrCast(this._props.layoutDoc.dataViz_histogram_defaultColor)} + setFinalColor={undoable(color => (this._props.layoutDoc.dataViz_histogram_defaultColor = color), 'Change Default Bar Color')} + setSelectedColor={undoable(color => (this._props.layoutDoc.dataViz_histogram_defaultColor = color), 'Change Default Bar Color')} size={Size.XSMALL} />
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index 7e0391879..abb95aa4c 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -1,6 +1,6 @@ import { EditableText, Size } from 'browndash-components'; import * as d3 from 'd3'; -import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast, NumListCast, StrListCast } from '../../../../../fields/Doc'; @@ -14,6 +14,7 @@ import { PinProps, PresBox } from '../../trails'; import { DataVizBox } from '../DataVizBox'; import { createLineGenerator, drawLine, minMaxRange, scaleCreatorNumerical, xAxisCreator, xGrid, yAxisCreator, yGrid } from '../utils/D3Utils'; import './Chart.scss'; +import { ObservableReactComponent } from '../../../ObservableReactComponent'; export interface DataPoint { x: number; @@ -40,33 +41,38 @@ export interface LineChartProps { } @observer -export class LineChart extends React.Component { +export class LineChart extends ObservableReactComponent { private _disposers: { [key: string]: IReactionDisposer } = {}; private _lineChartRef: React.RefObject = React.createRef(); private _lineChartSvg: d3.Selection | undefined; @observable _currSelected: SelectedDataPoint | undefined = undefined; // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates + constructor(props:any) { + super(props); + makeObservable(this); + } + @computed get _tableDataIds() { - return !this.parentViz ? this.props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows); + return !this.parentViz ? this._props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows); } // returns all the data records that will be rendered by only returning those records that have been selected by the parent visualization (or all records if there is no parent) @computed get _tableData() { - return !this.parentViz ? this.props.records : this._tableDataIds.map(rowId => this.props.records[rowId]); + return !this.parentViz ? this._props.records : this._tableDataIds.map(rowId => this._props.records[rowId]); } @computed get _lineChartData() { - var guids = StrListCast(this.props.layoutDoc.dataViz_rowIds); - if (this.props.axes.length <= 1) return []; - return this._tableData.map(record => ({ x: Number(record[this.props.axes[0]]), y: Number(record[this.props.axes[1]]) })).sort((a, b) => (a.x < b.x ? -1 : 1)); + var guids = StrListCast(this._props.layoutDoc.dataViz_rowIds); + if (this._props.axes.length <= 1) return []; + return this._tableData.map(record => ({ x: Number(record[this._props.axes[0]]), y: Number(record[this._props.axes[1]]) })).sort((a, b) => (a.x < b.x ? -1 : 1)); } @computed get graphTitle() { - return this.props.axes[1] + ' vs. ' + this.props.axes[0] + ' Line Chart'; + return this._props.axes[1] + ' vs. ' + this._props.axes[0] + ' Line Chart'; } @computed get parentViz() { - return DocCast(this.props.Document.dataViz_parentViz); - // return LinkManager.Instance.getAllRelatedLinks(this.props.Document) // out of all links + return DocCast(this._props.Document.dataViz_parentViz); + // return LinkManager.Instance.getAllRelatedLinks(this._props.Document) // out of all links // .filter(link => { - // return link.link_anchor_1 == this.props.Document.dataViz_parentViz; + // return link.link_anchor_1 == this._props.Document.dataViz_parentViz; // }) // get links where this chart doc is the target of the link // .map(link => DocCast(link.link_anchor_1)); // then return the source of the link } @@ -94,7 +100,7 @@ export class LineChart extends React.Component { { fireImmediately: true } ); this._disposers.annos = reaction( - () => DocListCast(this.props.dataDoc[this.props.fieldKey + '_annotations']), + () => DocListCast(this._props.dataDoc[this._props.fieldKey + '_annotations']), annotations => { // modify how d3 renders so that anything in this annotations list would be potentially highlighted in some way // could be blue colored to make it look like anchor @@ -114,7 +120,7 @@ export class LineChart extends React.Component { // redraw annotations when the chart data has changed, or the local or inherited selection has changed this.clearAnnotations(); selected && this.drawAnnotations(Number(selected.x), Number(selected.y), true); - incomingHighlited?.forEach((record: any) => this.drawAnnotations(Number(record[this.props.axes[0]]), Number(record[this.props.axes[1]]))); + incomingHighlited?.forEach((record: any) => this.drawAnnotations(Number(record[this._props.axes[0]]), Number(record[this._props.axes[1]]))); }, { fireImmediately: true } ); @@ -170,23 +176,23 @@ export class LineChart extends React.Component { // title: 'line doc selection' + this._currSelected?.x, }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.Document); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this._props.Document); anchor.config_dataVizSelection = this._currSelected ? new List([this._currSelected.x, this._currSelected.y]) : undefined; return anchor; }; @computed get height() { - return this.props.height - this.props.margin.top - this.props.margin.bottom; + return this._props.height - this._props.margin.top - this._props.margin.bottom; } @computed get width() { - return this.props.width - this.props.margin.left - this.props.margin.right; + return this._props.width - this._props.margin.left - this._props.margin.right; } @computed get defaultGraphTitle() { - var ax0 = this.props.axes[0]; - var ax1 = this.props.axes.length > 1 ? this.props.axes[1] : undefined; - if (this.props.axes.length < 2 || !/\d/.test(this.props.records[0][ax0]) || !ax1) { + var ax0 = this._props.axes[0]; + var ax1 = this._props.axes.length > 1 ? this._props.axes[1] : undefined; + if (this._props.axes.length < 2 || !/\d/.test(this._props.records[0][ax0]) || !ax1) { return ax0 + ' Line Chart'; } else return ax1 + ' by ' + ax0 + ' Line Chart'; } @@ -210,7 +216,7 @@ export class LineChart extends React.Component { // TODO: nda - get rid of svg element in the list? if (this._currSelected && this._currSelected.x == x && this._currSelected.y == y) this._currSelected = undefined; else this._currSelected = x !== undefined && y !== undefined ? { x, y } : undefined; - this.props.records.forEach(record => record[this.props.axes[0]] === x && record[this.props.axes[1]] === y && (record.selected = true)); + this._props.records.forEach(record => record[this._props.axes[0]] === x && record[this._props.axes[1]] === y && (record.selected = true)); } drawDataPoints(data: DataPoint[], idx: number, xScale: d3.ScaleLinear, yScale: d3.ScaleLinear) { @@ -245,7 +251,7 @@ export class LineChart extends React.Component { const yScale = scaleCreatorNumerical(0, yMax, height, 0); // adding svg - const margin = this.props.margin; + const margin = this._props.margin; const svg = (this._lineChartSvg = d3 .select(this._lineChartRef.current) .append('svg') @@ -317,7 +323,7 @@ export class LineChart extends React.Component { svg.append('text') .attr('transform', 'translate(' + width / 2 + ' ,' + (height + 40) + ')') .style('text-anchor', 'middle') - .text(this.props.axes[0]); + .text(this._props.axes[0]); svg.append('text') .attr('transform', 'rotate(-90)' + ' ' + 'translate( 0, ' + -10 + ')') .attr('x', -(height / 2)) @@ -325,7 +331,7 @@ export class LineChart extends React.Component { .attr('height', 20) .attr('width', 20) .style('text-anchor', 'middle') - .text(this.props.axes[1]); + .text(this._props.axes[1]); }; private updateTooltip( @@ -346,18 +352,18 @@ export class LineChart extends React.Component { render() { var titleAccessor: any = ''; - if (this.props.axes.length == 2) titleAccessor = 'dataViz_lineChart_title' + this.props.axes[0] + '-' + this.props.axes[1]; - else if (this.props.axes.length > 0) titleAccessor = 'dataViz_lineChart_title' + this.props.axes[0]; - if (!this.props.layoutDoc[titleAccessor]) this.props.layoutDoc[titleAccessor] = this.defaultGraphTitle; - const selectedPt = this._currSelected ? `{ ${this.props.axes[0]}: ${this._currSelected.x} ${this.props.axes[1]}: ${this._currSelected.y} }` : 'none'; + if (this._props.axes.length == 2) titleAccessor = 'dataViz_lineChart_title' + this._props.axes[0] + '-' + this._props.axes[1]; + else if (this._props.axes.length > 0) titleAccessor = 'dataViz_lineChart_title' + this._props.axes[0]; + if (!this._props.layoutDoc[titleAccessor]) this._props.layoutDoc[titleAccessor] = this.defaultGraphTitle; + const selectedPt = this._currSelected ? `{ ${this._props.axes[0]}: ${this._currSelected.x} ${this._props.axes[1]}: ${this._currSelected.y} }` : 'none'; if (this._lineChartData.length > 0 || !this.parentViz || this.parentViz.length == 0) { - return this.props.axes.length >= 2 && /\d/.test(this.props.records[0][this.props.axes[0]]) && /\d/.test(this.props.records[0][this.props.axes[1]]) ? ( + return this._props.axes.length >= 2 && /\d/.test(this._props.records[0][this._props.axes[0]]) && /\d/.test(this._props.records[0][this._props.axes[1]]) ? (
(this.props.layoutDoc[titleAccessor] = val as string)), + action(val => (this._props.layoutDoc[titleAccessor] = val as string)), 'Change Graph Title' )} color={'black'} diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index c2e03744e..9e7265b26 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -1,7 +1,7 @@ import { Checkbox } from '@mui/material'; import { ColorPicker, EditableText, Size, Type } from 'browndash-components'; import * as d3 from 'd3'; -import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { FaFillDrip } from 'react-icons/fa'; @@ -13,6 +13,7 @@ import { Docs } from '../../../../documents/Documents'; import { undoable } from '../../../../util/UndoManager'; import { PinProps, PresBox } from '../../trails'; import './Chart.scss'; +import { ObservableReactComponent } from '../../../ObservableReactComponent'; export interface PieChartProps { Document: Doc; @@ -32,7 +33,7 @@ export interface PieChartProps { } @observer -export class PieChart extends React.Component { +export class PieChart extends ObservableReactComponent { private _disposers: { [key: string]: IReactionDisposer } = {}; private _piechartRef: React.RefObject = React.createRef(); private _piechartSvg: d3.Selection | undefined; @@ -41,44 +42,49 @@ export class PieChart extends React.Component { private hoverOverData: any = undefined; // Selection of slice being hovered over @observable _currSelected: any | undefined = undefined; // Object of selected slice + constructor(props: any) { + super(props); + makeObservable(this); + } + @computed get _tableDataIds() { - return !this.parentViz ? this.props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows); + return !this.parentViz ? this._props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows); } // returns all the data records that will be rendered by only returning those records that have been selected by the parent visualization (or all records if there is no parent) @computed get _tableData() { - return !this.parentViz ? this.props.records : this._tableDataIds.map(rowId => this.props.records[rowId]); + return !this.parentViz ? this._props.records : this._tableDataIds.map(rowId => this._props.records[rowId]); } // organized by specified number percentages/ratios if one column is selected and it contains numbers // otherwise, assume data is organized by categories @computed get byCategory() { - return !/\d/.test(this.props.records[0][this.props.axes[0]]) || this.props.layoutDoc.dataViz_pie_asHistogram; + return !/\d/.test(this._props.records[0][this._props.axes[0]]) || this._props.layoutDoc.dataViz_pie_asHistogram; } // filters all data to just display selected data if brushed (created from an incoming link) @computed get _pieChartData() { - if (this.props.axes.length < 1) return []; + if (this._props.axes.length < 1) return []; - const ax0 = this.props.axes[0]; - if (this.props.axes.length < 2) { - return this._tableData.map(record => ({ [ax0]: record[this.props.axes[0]] })); + const ax0 = this._props.axes[0]; + if (this._props.axes.length < 2) { + return this._tableData.map(record => ({ [ax0]: record[this._props.axes[0]] })); } - const ax1 = this.props.axes[1]; - return this._tableData.map(record => ({ [ax0]: record[this.props.axes[0]], [ax1]: record[this.props.axes[1]] })); + const ax1 = this._props.axes[1]; + return this._tableData.map(record => ({ [ax0]: record[this._props.axes[0]], [ax1]: record[this._props.axes[1]] })); } @computed get defaultGraphTitle() { - var ax0 = this.props.axes[0]; - var ax1 = this.props.axes.length > 1 ? this.props.axes[1] : undefined; - if (this.props.axes.length < 2 || !/\d/.test(this.props.records[0][ax0]) || !ax1) { + var ax0 = this._props.axes[0]; + var ax1 = this._props.axes.length > 1 ? this._props.axes[1] : undefined; + if (this._props.axes.length < 2 || !/\d/.test(this._props.records[0][ax0]) || !ax1) { return ax0 + ' Pie Chart'; } return ax1 + ' by ' + ax0 + ' Pie Chart'; } @computed get parentViz() { - return DocCast(this.props.Document.dataViz_parentViz); - // return LinkManager.Instance.getAllRelatedLinks(this.props.Document) // out of all links - // .filter(link => link.link_anchor_1 == this.props.Document.dataViz_parentViz) // get links where this chart doc is the target of the link + return DocCast(this._props.Document.dataViz_parentViz); + // return LinkManager.Instance.getAllRelatedLinks(this._props.Document) // out of all links + // .filter(link => link.link_anchor_1 == this._props.Document.dataViz_parentViz) // get links where this chart doc is the target of the link // .map(link => DocCast(link.link_anchor_1)); // then return the source of the link } @@ -101,16 +107,16 @@ export class PieChart extends React.Component { // title: 'piechart doc selection' + this._currSelected, }); - PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.Document); + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this._props.Document); return anchor; }; @computed get height() { - return this.props.height - this.props.margin.top - this.props.margin.bottom; + return this._props.height - this._props.margin.top - this._props.margin.bottom; } @computed get width() { - return this.props.width - this.props.margin.left - this.props.margin.right; + return this._props.width - this._props.margin.left - this._props.margin.right; } // cleans data by converting numerical data to numbers and taking out empty cells @@ -181,7 +187,7 @@ export class PieChart extends React.Component { var percentField = Object.keys(dataSet[0])[0]; var descriptionField = Object.keys(dataSet[0])[1]!; - var radius = Math.min(width, height - this.props.margin.top - this.props.margin.bottom) / 2; + var radius = Math.min(width, height - this._props.margin.top - this._props.margin.bottom) / 2; // converts data into Objects var data = this.data(dataSet); @@ -209,10 +215,10 @@ export class PieChart extends React.Component { .select(this._piechartRef.current) .append('svg') .attr('class', 'graph') - .attr('width', width + this.props.margin.right + this.props.margin.left) - .attr('height', height + this.props.margin.top + this.props.margin.bottom) + .attr('width', width + this._props.margin.right + this._props.margin.left) + .attr('height', height + this._props.margin.top + this._props.margin.bottom) .append('g')); - let g = svg.append('g').attr('transform', 'translate(' + (width / 2 + this.props.margin.left) + ',' + height / 2 + ')'); + let g = svg.append('g').attr('transform', 'translate(' + (width / 2 + this._props.margin.left) + ',' + height / 2 + ')'); var pie = d3.pie(); var arc = d3.arc().innerRadius(0).outerRadius(radius); @@ -249,7 +255,7 @@ export class PieChart extends React.Component { } catch (error) {} possibleDataPointVals.push(dataPointVal); }); - const sliceColors = StrListCast(this.props.layoutDoc.dataViz_pie_sliceColors).map(each => each.split('::')); + const sliceColors = StrListCast(this._props.layoutDoc.dataViz_pie_sliceColors).map(each => each.split('::')); arcs.append('path') .attr('fill', (d, i) => { var dataPoint; @@ -261,7 +267,7 @@ export class PieChart extends React.Component { } var sliceColor; if (dataPoint) { - const sliceTitle = dataPoint[this.props.axes[0]]; + const sliceTitle = dataPoint[this._props.axes[0]]; const accessByName = StrCast(sliceTitle) ? StrCast(sliceTitle).replace(/\$/g, '').replace(/\%/g, '').replace(/\#/g, '').replace(/\ each[0] == accessByName && (sliceColor = each[1])); } @@ -309,10 +315,10 @@ export class PieChart extends React.Component { @action changeSelectedColor = (color: string) => { this.curSliceSelected.attr('fill', color); - const sliceTitle = this._currSelected[this.props.axes[0]]; + const sliceTitle = this._currSelected[this._props.axes[0]]; const sliceName = StrCast(sliceTitle) ? StrCast(sliceTitle).replace(/\$/g, '').replace(/\%/g, '').replace(/\#/g, '').replace(/\ { if (each.split('::')[0] == sliceName) sliceColors.splice(sliceColors.indexOf(each), 1); }); @@ -320,20 +326,20 @@ export class PieChart extends React.Component { }; @action changeHistogramCheckBox = () => { - this.props.layoutDoc.dataViz_pie_asHistogram = !this.props.layoutDoc.dataViz_pie_asHistogram; + this._props.layoutDoc.dataViz_pie_asHistogram = !this._props.layoutDoc.dataViz_pie_asHistogram; this.drawChart(this._pieChartData, this.width, this.height); }; render() { var titleAccessor: any = ''; - if (this.props.axes.length == 2) titleAccessor = 'dataViz_pie_title' + this.props.axes[0] + '-' + this.props.axes[1]; - else if (this.props.axes.length > 0) titleAccessor = 'dataViz_pie_title' + this.props.axes[0]; - if (!this.props.layoutDoc[titleAccessor]) this.props.layoutDoc[titleAccessor] = this.defaultGraphTitle; - if (!this.props.layoutDoc.dataViz_pie_sliceColors) this.props.layoutDoc.dataViz_pie_sliceColors = new List(); + if (this._props.axes.length == 2) titleAccessor = 'dataViz_pie_title' + this._props.axes[0] + '-' + this._props.axes[1]; + else if (this._props.axes.length > 0) titleAccessor = 'dataViz_pie_title' + this._props.axes[0]; + if (!this._props.layoutDoc[titleAccessor]) this._props.layoutDoc[titleAccessor] = this.defaultGraphTitle; + if (!this._props.layoutDoc.dataViz_pie_sliceColors) this._props.layoutDoc.dataViz_pie_sliceColors = new List(); var selected: string; var curSelectedSliceName = ''; if (this._currSelected) { - const sliceTitle = this._currSelected[this.props.axes[0]]; + const sliceTitle = this._currSelected[this._props.axes[0]]; curSelectedSliceName = StrCast(sliceTitle) ? StrCast(sliceTitle).replace(/\$/g, '').replace(/\%/g, '').replace(/\#/g, '').replace(/\ { @@ -343,19 +349,19 @@ export class PieChart extends React.Component { selected += ' }'; } else selected = 'none'; var selectedSliceColor; - var sliceColors = StrListCast(this.props.layoutDoc.dataViz_pie_sliceColors).map(each => each.split('::')); + var sliceColors = StrListCast(this._props.layoutDoc.dataViz_pie_sliceColors).map(each => each.split('::')); sliceColors.forEach(each => { if (each[0] == curSelectedSliceName!) selectedSliceColor = each[1]; }); if (this._pieChartData.length > 0 || !this.parentViz) { - return this.props.axes.length >= 1 ? ( + return this._props.axes.length >= 1 ? (
(this.props.layoutDoc[titleAccessor] = val as string)), + action(val => (this._props.layoutDoc[titleAccessor] = val as string)), 'Change Graph Title' )} color={'black'} @@ -363,9 +369,9 @@ export class PieChart extends React.Component { fillWidth />
- {this.props.axes.length === 1 && /\d/.test(this.props.records[0][this.props.axes[0]]) ? ( -
- + {this._props.axes.length === 1 && /\d/.test(this._props.records[0][this._props.axes[0]]) ? ( +
+ Organize data as histogram
) : null} diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 3e7d3af8c..f77c138df 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -1,5 +1,5 @@ import { Button, Type } from 'browndash-components'; -import { action, computed, IReactionDisposer, observable, reaction, trace } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, reaction, trace } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, Field, NumListCast } from '../../../../../fields/Doc'; @@ -11,6 +11,7 @@ import { DragManager } from '../../../../util/DragManager'; import { DocumentView } from '../../DocumentView'; import { DataVizView } from '../DataVizBox'; import './Chart.scss'; +import { ObservableReactComponent } from '../../../ObservableReactComponent'; const { default: { DATA_VIZ_TABLE_ROW_HEIGHT } } = require('../../../global/globalCssVariables.module.scss'); // prettier-ignore interface TableBoxProps { Document: Doc; @@ -30,13 +31,17 @@ interface TableBoxProps { } @observer -export class TableBox extends React.Component { +export class TableBox extends ObservableReactComponent { _inputChangedDisposer?: IReactionDisposer; _containerRef: HTMLDivElement | null = null; @observable _scrollTop = -1; @observable _tableHeight = 0; @observable _tableContainerHeight = 0; + constructor(props: any) { + super(props); + makeObservable(this); + } componentDidMount() { // if the tableData changes (ie., when records are selected by the parent (input) visulization), @@ -48,17 +53,17 @@ export class TableBox extends React.Component { this._inputChangedDisposer?.(); } @computed get _tableDataIds() { - return !this.parentViz ? this.props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows); + return !this.parentViz ? this._props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows); } // returns all the data records that will be rendered by only returning those records that have been selected by the parent visualization (or all records if there is no parent) @computed get _tableData() { - return !this.parentViz ? this.props.records : this._tableDataIds.map(rowId => this.props.records[rowId]); + return !this.parentViz ? this._props.records : this._tableDataIds.map(rowId => this._props.records[rowId]); } @computed get parentViz() { - return DocCast(this.props.Document.dataViz_parentViz); - // return LinkManager.Instance.getAllRelatedLinks(this.props.Document) // out of all links - // .filter(link => link.link_anchor_1 == this.props.Document.dataViz_parentViz) // get links where this chart doc is the target of the link + return DocCast(this._props.Document.dataViz_parentViz); + // return LinkManager.Instance.getAllRelatedLinks(this._props.Document) // out of all links + // .filter(link => link.link_anchor_1 == this._props.Document.dataViz_parentViz) // get links where this chart doc is the target of the link // .map(link => DocCast(link.link_anchor_1)); // then return the source of the link } @@ -68,14 +73,14 @@ export class TableBox extends React.Component { // updates the 'dataViz_selectedRows' and 'dataViz_highlightedRows' fields to no longer include rows that aren't in the table filterSelectedRowsDown = () => { - const selected = NumListCast(this.props.layoutDoc.dataViz_selectedRows); - this.props.layoutDoc.dataViz_selectedRows = new List(selected.filter(rowId => this._tableDataIds.includes(rowId))); // filters through selected to remove guids that were removed in the incoming data - const highlighted = NumListCast(this.props.layoutDoc.dataViz_highlitedRows); - this.props.layoutDoc.dataViz_highlitedRows = new List(highlighted.filter(rowId => this._tableDataIds.includes(rowId))); // filters through highlighted to remove guids that were removed in the incoming data + const selected = NumListCast(this._props.layoutDoc.dataViz_selectedRows); + this._props.layoutDoc.dataViz_selectedRows = new List(selected.filter(rowId => this._tableDataIds.includes(rowId))); // filters through selected to remove guids that were removed in the incoming data + const highlighted = NumListCast(this._props.layoutDoc.dataViz_highlitedRows); + this._props.layoutDoc.dataViz_highlitedRows = new List(highlighted.filter(rowId => this._tableDataIds.includes(rowId))); // filters through highlighted to remove guids that were removed in the incoming data }; @computed get viewScale() { - return this.props.docView?.()?._props.ScreenToLocalTransform().Scale || 1; + return this._props.docView?.()?._props.ScreenToLocalTransform().Scale || 1; } @computed get rowHeight() { console.log('scale = ' + this.viewScale + ' table = ' + this._tableHeight + ' ids = ' + this._tableDataIds.length); @@ -89,14 +94,14 @@ export class TableBox extends React.Component { return Math.ceil(this.startID + (this._tableContainerHeight * this.viewScale) / (this.rowHeight || 1)); } @action handleScroll = () => { - if (!this.props.docView?.()?.ContentDiv?.hidden) { + if (!this._props.docView?.()?.ContentDiv?.hidden) { this._scrollTop = this._containerRef?.scrollTop ?? 0; } }; @action tableRowClick = (e: React.MouseEvent, rowId: number) => { - const highlited = Cast(this.props.layoutDoc.dataViz_highlitedRows, listSpec('number'), null); - const selected = Cast(this.props.layoutDoc.dataViz_selectedRows, listSpec('number'), null); + const highlited = Cast(this._props.layoutDoc.dataViz_highlitedRows, listSpec('number'), null); + const selected = Cast(this._props.layoutDoc.dataViz_selectedRows, listSpec('number'), null); if (e.metaKey) { // highlighting a row if (highlited?.includes(rowId)) highlited.splice(highlited.indexOf(rowId), 1); @@ -120,26 +125,26 @@ export class TableBox extends React.Component { e, e => { // dragging off a column to create a brushed DataVizBox - const sourceAnchorCreator = () => this.props.docView?.()!.Document!; + const sourceAnchorCreator = () => this._props.docView?.()!.Document!; const targetCreator = (annotationOn: Doc | undefined) => { - const embedding = Doc.MakeEmbedding(this.props.docView?.()!.Document!); + const embedding = Doc.MakeEmbedding(this._props.docView?.()!.Document!); embedding._dataViz = DataVizView.TABLE; embedding._dataViz_axes = new List([col, col]); - embedding._dataViz_parentViz = this.props.Document; + embedding._dataViz_parentViz = this._props.Document; embedding.annotationOn = annotationOn; - embedding.histogramBarColors = Field.Copy(this.props.layoutDoc.histogramBarColors); - embedding.defaultHistogramColor = this.props.layoutDoc.defaultHistogramColor; - embedding.pieSliceColors = Field.Copy(this.props.layoutDoc.pieSliceColors); + embedding.histogramBarColors = Field.Copy(this._props.layoutDoc.histogramBarColors); + embedding.defaultHistogramColor = this._props.layoutDoc.defaultHistogramColor; + embedding.pieSliceColors = Field.Copy(this._props.layoutDoc.pieSliceColors); return embedding; }; - if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) { - DragManager.StartAnchorAnnoDrag(e.target instanceof HTMLElement ? [e.target] : [], new DragManager.AnchorAnnoDragData(this.props.docView()!, sourceAnchorCreator, targetCreator), downX, downY, { + if (this._props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) { + DragManager.StartAnchorAnnoDrag(e.target instanceof HTMLElement ? [e.target] : [], new DragManager.AnchorAnnoDragData(this._props.docView()!, sourceAnchorCreator, targetCreator), downX, downY, { dragComplete: e => { if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { e.linkDocument.link_displayLine = true; e.linkDocument.link_matchEmbeddings = true; e.linkDocument.link_displayArrow = true; - // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.Document; + // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this._props.Document; // e.annoDragData.linkSourceDoc.followLinkZoom = false; } }, @@ -150,11 +155,11 @@ export class TableBox extends React.Component { }, emptyFunction, action(e => { - const newAxes = this.props.axes; + const newAxes = this._props.axes; if (newAxes.includes(col)) newAxes.splice(newAxes.indexOf(col), 1); else if (newAxes.length > 1) newAxes[1] = col; else newAxes.push(col); - this.props.selectAxes(newAxes); + this._props.selectAxes(newAxes); }) ); }; @@ -166,14 +171,14 @@ export class TableBox extends React.Component { className="tableBox" tabIndex={0} onKeyDown={e => { - if (this.props.layoutDoc && e.key === 'a' && (e.ctrlKey || e.metaKey)) { + if (this._props.layoutDoc && e.key === 'a' && (e.ctrlKey || e.metaKey)) { e.stopPropagation(); - this.props.layoutDoc.dataViz_selectedRows = new List(this._tableDataIds); + this._props.layoutDoc.dataViz_selectedRows = new List(this._tableDataIds); } }}>
-
{ onScroll={this.handleScroll} ref={action((r: HTMLDivElement | null) => { this._containerRef = r; - if (!this.props.docView?.()?.ContentDiv?.hidden && r) { + if (!this._props.docView?.()?.ContentDiv?.hidden && r) { this._tableContainerHeight = r.getBoundingClientRect().height ?? 0; r.addEventListener( 'wheel', // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this) @@ -196,7 +201,7 @@ export class TableBox extends React.Component { { - if (!this.props.docView?.()?.ContentDiv?.hidden && r) { + if (!this._props.docView?.()?.ContentDiv?.hidden && r) { this._tableHeight = r?.getBoundingClientRect().height ?? 0; } })}> @@ -207,8 +212,8 @@ export class TableBox extends React.Component { ); })} diff --git a/src/client/views/nodes/MapBox/AnimationUtility.ts b/src/client/views/nodes/MapBox/AnimationUtility.ts index 256acbf13..13ce5b7e2 100644 --- a/src/client/views/nodes/MapBox/AnimationUtility.ts +++ b/src/client/views/nodes/MapBox/AnimationUtility.ts @@ -1,13 +1,13 @@ -import mapboxgl from "mapbox-gl"; -import { MercatorCoordinate } from "mapbox-gl"; -import { MapRef } from "react-map-gl"; +import mapboxgl from 'mapbox-gl'; +import { MercatorCoordinate } from 'mapbox-gl'; +import { MapRef } from 'react-map-gl'; import * as React from 'react'; -import * as d3 from "d3"; +import * as d3 from 'd3'; import * as turf from '@turf/turf'; -import { Position } from "@turf/turf"; -import { Feature, FeatureCollection, GeoJsonProperties, Geometry } from "geojson"; -import { observer } from "mobx-react"; -import { action, computed, observable } from "mobx"; +import { Position } from '@turf/turf'; +import { Feature, FeatureCollection, GeoJsonProperties, Geometry } from 'geojson'; +import { observer } from 'mobx-react'; +import { action, computed, observable } from 'mobx'; export enum AnimationStatus { START = 'start', @@ -21,37 +21,35 @@ export enum AnimationSpeed { FAST = '3x', } -@observer export class AnimationUtility { - private SMOOTH_FACTOR = 0.95 - private ROUTE_COORDINATES: Position[] = []; + private SMOOTH_FACTOR = 0.95; + private ROUTE_COORDINATES: Position[] = []; private PATH: turf.helpers.Feature; private FLY_IN_START_PITCH = 40; - private FIRST_LNG_LAT: {lng: number, lat: number}; + private FIRST_LNG_LAT: { lng: number; lat: number }; private START_ALTITUDE = 3_000_000; @observable private isStreetViewAnimation: boolean; @observable private animationSpeed: AnimationSpeed; - - private previousLngLat: {lng: number, lat: number}; + private previousLngLat: { lng: number; lat: number }; private currentStreetViewBearing: number = 0; @computed get flyInEndBearing() { - return this.isStreetViewAnimation ? - this.calculateBearing( - { - lng: this.ROUTE_COORDINATES[0][0], - lat: this.ROUTE_COORDINATES[0][1] - }, - { - lng: this.ROUTE_COORDINATES[1][0], - lat: this.ROUTE_COORDINATES[1][1] - } - ) + return this.isStreetViewAnimation + ? this.calculateBearing( + { + lng: this.ROUTE_COORDINATES[0][0], + lat: this.ROUTE_COORDINATES[0][1], + }, + { + lng: this.ROUTE_COORDINATES[1][0], + lat: this.ROUTE_COORDINATES[1][1], + } + ) : -20; - } + } @computed get flyInStartBearing() { return Math.max(0, Math.min(this.flyInEndBearing + 20, 360)); // between 0 and 360 @@ -80,8 +78,8 @@ export class AnimationUtility { @computed get animationDuration(): number { return 20_000; - // compute path distance for a standard speed - // get animation speed + // compute path distance for a standard speed + // get animation speed // get isStreetViewAnimation (should be slower if so) } @@ -90,19 +88,13 @@ export class AnimationUtility { // calculate new flyToDuration and animationDuration this.animationSpeed = speed; } - + @action public updateIsStreetViewAnimation(isStreetViewAnimation: boolean) { this.isStreetViewAnimation = isStreetViewAnimation; } - - constructor( - firstLngLat: {lng: number, lat: number}, - routeCoordinates: Position[], - isStreetViewAnimation: boolean, - animationSpeed: AnimationSpeed - ) { + constructor(firstLngLat: { lng: number; lat: number }, routeCoordinates: Position[], isStreetViewAnimation: boolean, animationSpeed: AnimationSpeed) { this.FIRST_LNG_LAT = firstLngLat; this.previousLngLat = firstLngLat; this.ROUTE_COORDINATES = routeCoordinates; @@ -111,11 +103,11 @@ export class AnimationUtility { const bearing = this.calculateBearing( { lng: routeCoordinates[0][0], - lat: routeCoordinates[0][1] + lat: routeCoordinates[0][1], }, { lng: routeCoordinates[1][0], - lat: routeCoordinates[1][1] + lat: routeCoordinates[1][1], } ); this.currentStreetViewBearing = bearing; @@ -137,293 +129,245 @@ export class AnimationUtility { currentAnimationPhase, updateAnimationPhase, updateFrameId, - }: { - map: MapRef, + }: { + map: MapRef; // path: turf.helpers.Feature, // startBearing: number, // startAltitude: number, // pitch: number, - currentAnimationPhase: number, - updateAnimationPhase: ( - newAnimationPhase: number, - ) => void, + currentAnimationPhase: number; + updateAnimationPhase: (newAnimationPhase: number) => void; updateFrameId: (newFrameId: number) => void; + }) => { + return new Promise(async resolve => { + const pathDistance = turf.lineDistance(this.PATH); + console.log('PATH DISTANCE: ', pathDistance); + let startTime: number | null = null; + + const frame = async (currentTime: number) => { + if (!startTime) startTime = currentTime; + const elapsedSinceLastFrame = currentTime - startTime; + const phaseIncrement = elapsedSinceLastFrame / this.animationDuration; + const animationPhase = currentAnimationPhase + phaseIncrement; + + // when the duration is complete, resolve the promise and stop iterating + if (animationPhase > 1) { + resolve(); + return; + } - }) => { - return new Promise(async (resolve) => { - const pathDistance = turf.lineDistance(this.PATH); - console.log("PATH DISTANCE: ", pathDistance); - let startTime: number | null = null; - - const frame = async (currentTime: number) => { - if (!startTime) startTime = currentTime; - const elapsedSinceLastFrame = currentTime - startTime; - const phaseIncrement = elapsedSinceLastFrame / this.animationDuration; - const animationPhase = currentAnimationPhase + phaseIncrement; - - // when the duration is complete, resolve the promise and stop iterating - if (animationPhase > 1) { - resolve(); - return; - } + // calculate the distance along the path based on the animationPhase + const alongPath = turf.along(this.PATH, pathDistance * animationPhase).geometry.coordinates; + + const lngLat = { + lng: alongPath[0], + lat: alongPath[1], + }; + + let bearing: number; + if (this.isStreetViewAnimation) { + bearing = this.lerp( + this.currentStreetViewBearing, + this.calculateBearing(this.previousLngLat, lngLat), + 0.028 // Adjust the transition speed as needed + ); + this.currentStreetViewBearing = bearing; + // bearing = this.calculateBearing(this.previousLngLat, lngLat); // TODO: Calculate actual bearing + } else { + // slowly rotate the map at a constant rate + bearing = this.flyInEndBearing - animationPhase * 200.0; + // bearing = startBearing - animationPhase * 200.0; + } + + this.previousLngLat = lngLat; + + updateAnimationPhase(animationPhase); + + // compute corrected camera ground position, so that he leading edge of the path is in view + var correctedPosition = this.computeCameraPosition( + this.isStreetViewAnimation, + this.flyInEndPitch, + bearing, + lngLat, + this.flyInEndAltitude, + true // smooth + ); + + // set the pitch and bearing of the camera + const camera = map.getFreeCameraOptions(); + camera.setPitchBearing(this.flyInEndPitch, bearing); + + console.log('Corrected pos: ', correctedPosition); + console.log('Start altitude: ', this.flyInEndAltitude); + // set the position and altitude of the camera + camera.position = MercatorCoordinate.fromLngLat(correctedPosition, this.flyInEndAltitude); + + // apply the new camera options + map.setFreeCameraOptions(camera); - - // calculate the distance along the path based on the animationPhase - const alongPath = turf.along(this.PATH, pathDistance * animationPhase).geometry - .coordinates; - - const lngLat = { - lng: alongPath[0], - lat: alongPath[1], + // repeat! + const innerFrameId = await window.requestAnimationFrame(frame); + updateFrameId(innerFrameId); }; - - let bearing: number; - if (this.isStreetViewAnimation){ - bearing = this.lerp( - this.currentStreetViewBearing, - this.calculateBearing(this.previousLngLat, lngLat), - 0.028 // Adjust the transition speed as needed - ); - this.currentStreetViewBearing = bearing; - // bearing = this.calculateBearing(this.previousLngLat, lngLat); // TODO: Calculate actual bearing - } else { - // slowly rotate the map at a constant rate - bearing = this.flyInEndBearing - animationPhase * 200.0; - // bearing = startBearing - animationPhase * 200.0; - } - this.previousLngLat = lngLat; - - updateAnimationPhase(animationPhase); - - // compute corrected camera ground position, so that he leading edge of the path is in view - var correctedPosition = this.computeCameraPosition( - this.isStreetViewAnimation, - this.flyInEndPitch, - bearing, - lngLat, - this.flyInEndAltitude, - true // smooth - ); - - // set the pitch and bearing of the camera - const camera = map.getFreeCameraOptions(); - camera.setPitchBearing(this.flyInEndPitch, bearing); - - console.log("Corrected pos: ", correctedPosition); - console.log("Start altitude: ", this.flyInEndAltitude); - // set the position and altitude of the camera - camera.position = MercatorCoordinate.fromLngLat( - correctedPosition, - this.flyInEndAltitude - ); - - - // apply the new camera options - map.setFreeCameraOptions(camera); - - // repeat! - const innerFrameId = await window.requestAnimationFrame(frame); - updateFrameId(innerFrameId); - }; - - const outerFrameId = await window.requestAnimationFrame(frame); - updateFrameId(outerFrameId); + const outerFrameId = await window.requestAnimationFrame(frame); + updateFrameId(outerFrameId); }); - }; + }; - public flyInAndRotate = async ({ - map, - updateFrameId - }: - { - map: MapRef, - updateFrameId: (newFrameId: number) => void - } - ) => { - return new Promise<{bearing: number, altitude: number}>(async (resolve) => { - let start: number | null; - - var currentAltitude; - var currentBearing; - var currentPitch; - - // the animation frame will run as many times as necessary until the duration has been reached - const frame = async (time: number) => { - if (!start) { - start = time; - } - - // otherwise, use the current time to determine how far along in the duration we are - let animationPhase = (time - start) / this.flyToDuration; - - // because the phase calculation is imprecise, the final zoom can vary - // if it ended up greater than 1, set it to 1 so that we get the exact endAltitude that was requested - if (animationPhase > 1) { - animationPhase = 1; - } - - currentAltitude = this.START_ALTITUDE + (this.flyInEndAltitude - this.START_ALTITUDE) * d3.easeCubicOut(animationPhase) - // rotate the camera between startBearing and endBearing - currentBearing = this.flyInStartBearing + (this.flyInEndBearing - this.flyInStartBearing) * d3.easeCubicOut(animationPhase) - - currentPitch = this.FLY_IN_START_PITCH + (this.flyInEndPitch - this.FLY_IN_START_PITCH) * d3.easeCubicOut(animationPhase) - - // compute corrected camera ground position, so the start of the path is always in view - var correctedPosition = this.computeCameraPosition( - false, - currentPitch, - currentBearing, - this.FIRST_LNG_LAT, - currentAltitude - ); - - // set the pitch and bearing of the camera - const camera = map.getFreeCameraOptions(); - camera.setPitchBearing(currentPitch, currentBearing); - - // set the position and altitude of the camera - camera.position = MercatorCoordinate.fromLngLat( - correctedPosition, - currentAltitude - ); - - // apply the new camera options - map.setFreeCameraOptions(camera); - - // when the animationPhase is done, resolve the promise so the parent function can move on to the next step in the sequence - if (animationPhase === 1) { - resolve({ - bearing: currentBearing, - altitude: currentAltitude, - }); - - // return so there are no further iterations of this frame - return; - } - - const innerFrameId = await window.requestAnimationFrame(frame); - updateFrameId(innerFrameId); - - }; - - const outerFrameId = await window.requestAnimationFrame(frame); - updateFrameId(outerFrameId); + public flyInAndRotate = async ({ map, updateFrameId }: { map: MapRef; updateFrameId: (newFrameId: number) => void }) => { + return new Promise<{ bearing: number; altitude: number }>(async resolve => { + let start: number | null; + + var currentAltitude; + var currentBearing; + var currentPitch; + + // the animation frame will run as many times as necessary until the duration has been reached + const frame = async (time: number) => { + if (!start) { + start = time; + } + + // otherwise, use the current time to determine how far along in the duration we are + let animationPhase = (time - start) / this.flyToDuration; + + // because the phase calculation is imprecise, the final zoom can vary + // if it ended up greater than 1, set it to 1 so that we get the exact endAltitude that was requested + if (animationPhase > 1) { + animationPhase = 1; + } + + currentAltitude = this.START_ALTITUDE + (this.flyInEndAltitude - this.START_ALTITUDE) * d3.easeCubicOut(animationPhase); + // rotate the camera between startBearing and endBearing + currentBearing = this.flyInStartBearing + (this.flyInEndBearing - this.flyInStartBearing) * d3.easeCubicOut(animationPhase); + + currentPitch = this.FLY_IN_START_PITCH + (this.flyInEndPitch - this.FLY_IN_START_PITCH) * d3.easeCubicOut(animationPhase); + + // compute corrected camera ground position, so the start of the path is always in view + var correctedPosition = this.computeCameraPosition(false, currentPitch, currentBearing, this.FIRST_LNG_LAT, currentAltitude); + + // set the pitch and bearing of the camera + const camera = map.getFreeCameraOptions(); + camera.setPitchBearing(currentPitch, currentBearing); + + // set the position and altitude of the camera + camera.position = MercatorCoordinate.fromLngLat(correctedPosition, currentAltitude); + + // apply the new camera options + map.setFreeCameraOptions(camera); + + // when the animationPhase is done, resolve the promise so the parent function can move on to the next step in the sequence + if (animationPhase === 1) { + resolve({ + bearing: currentBearing, + altitude: currentAltitude, + }); + + // return so there are no further iterations of this frame + return; + } + + const innerFrameId = await window.requestAnimationFrame(frame); + updateFrameId(innerFrameId); + }; + + const outerFrameId = await window.requestAnimationFrame(frame); + updateFrameId(outerFrameId); }); - }; + }; - previousCameraPosition: {lng: number, lat: number} | null = null; + previousCameraPosition: { lng: number; lat: number } | null = null; - lerp = (start: number, end: number, amt: number) => { + lerp = (start: number, end: number, amt: number) => { return (1 - amt) * start + amt * end; - } - - computeCameraPosition = ( - isStreetViewAnimation: boolean, - pitch: number, - bearing: number, - targetPosition: {lng: number, lat: number}, - altitude: number, - smooth = false - ) => { + }; + + computeCameraPosition = (isStreetViewAnimation: boolean, pitch: number, bearing: number, targetPosition: { lng: number; lat: number }, altitude: number, smooth = false) => { const bearingInRadian = (bearing * Math.PI) / 180; - const pitchInRadian = ((90 - pitch)* Math.PI) / 180; + const pitchInRadian = ((90 - pitch) * Math.PI) / 180; let correctedLng = targetPosition.lng; let correctedLat = targetPosition.lat; if (!isStreetViewAnimation) { - const lngDiff = - ((altitude / Math.tan(pitchInRadian)) * - Math.sin(-bearingInRadian)) / - 70000; // ~70km/degree longitude - const latDiff = - ((altitude / Math.tan(pitchInRadian)) * - Math.cos(-bearingInRadian)) / - 110000 // 110km/degree latitude + const lngDiff = ((altitude / Math.tan(pitchInRadian)) * Math.sin(-bearingInRadian)) / 70000; // ~70km/degree longitude + const latDiff = ((altitude / Math.tan(pitchInRadian)) * Math.cos(-bearingInRadian)) / 110000; // 110km/degree latitude correctedLng = targetPosition.lng + lngDiff; correctedLat = targetPosition.lat - latDiff; - } - + const newCameraPosition = { - lng: correctedLng, - lat: correctedLat + lng: correctedLng, + lat: correctedLat, }; - + if (smooth) { - if (this.previousCameraPosition) { - newCameraPosition.lng = this.lerp(newCameraPosition.lng, this.previousCameraPosition.lng, this.SMOOTH_FACTOR); - newCameraPosition.lat = this.lerp(newCameraPosition.lat, this.previousCameraPosition.lat, this.SMOOTH_FACTOR); - } + if (this.previousCameraPosition) { + newCameraPosition.lng = this.lerp(newCameraPosition.lng, this.previousCameraPosition.lng, this.SMOOTH_FACTOR); + newCameraPosition.lat = this.lerp(newCameraPosition.lat, this.previousCameraPosition.lat, this.SMOOTH_FACTOR); + } } - - this.previousCameraPosition = newCameraPosition - + + this.previousCameraPosition = newCameraPosition; + return newCameraPosition; - }; - - public static createGeoJSONCircle = (center: number[], radiusInKm: number, points = 64): Feature=> { + }; + + public static createGeoJSONCircle = (center: number[], radiusInKm: number, points = 64): Feature => { const coords = { - latitude: center[1], - longitude: center[0], + latitude: center[1], + longitude: center[0], }; const km = radiusInKm; const ret = []; - const distanceX = km / (111.320 * Math.cos((coords.latitude * Math.PI) / 180)); + const distanceX = km / (111.32 * Math.cos((coords.latitude * Math.PI) / 180)); const distanceY = km / 110.574; let theta; let x; let y; for (let i = 0; i < points; i += 1) { - theta = (i / points) * (2 * Math.PI); - x = distanceX * Math.cos(theta); - y = distanceY * Math.sin(theta); - ret.push([coords.longitude + x, coords.latitude + y]); + theta = (i / points) * (2 * Math.PI); + x = distanceX * Math.cos(theta); + y = distanceY * Math.sin(theta); + ret.push([coords.longitude + x, coords.latitude + y]); } ret.push(ret[0]); return { - type: 'Feature', - geometry: { - type: 'Polygon', - coordinates: [ret], - }, - properties: {} + type: 'Feature', + geometry: { + type: 'Polygon', + coordinates: [ret], + }, + properties: {}, }; - } + }; - private calculateBearing( - from: { lng: number; lat: number }, - to: { lng: number; lat: number } - ): number { + private calculateBearing(from: { lng: number; lat: number }, to: { lng: number; lat: number }): number { const lon1 = from.lng; const lat1 = from.lat; const lon2 = to.lng; const lat2 = to.lat; - + const lon1Rad = (lon1 * Math.PI) / 180; const lon2Rad = (lon2 * Math.PI) / 180; const lat1Rad = (lat1 * Math.PI) / 180; const lat2Rad = (lat2 * Math.PI) / 180; - + const y = Math.sin(lon2Rad - lon1Rad) * Math.cos(lat2Rad); - const x = - Math.cos(lat1Rad) * Math.sin(lat2Rad) - - Math.sin(lat1Rad) * Math.cos(lat2Rad) * Math.cos(lon2Rad - lon1Rad); - - let bearing = Math.atan2(y,x); - + const x = Math.cos(lat1Rad) * Math.sin(lat2Rad) - Math.sin(lat1Rad) * Math.cos(lat2Rad) * Math.cos(lon2Rad - lon1Rad); + + let bearing = Math.atan2(y, x); + // Convert bearing from radians to degrees bearing = (bearing * 180) / Math.PI; - + // Ensure the bearing is within [0, 360) if (bearing < 0) { - bearing += 360; + bearing += 360; } - - return bearing; - } - -} \ No newline at end of file + return bearing; + } +} diff --git a/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx b/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx index bf4028f01..f9607becf 100644 --- a/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx +++ b/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx @@ -1,15 +1,15 @@ -import React = require('react'); -import { observer } from "mobx-react"; -import { AntimodeMenu, AntimodeMenuProps } from "../../AntimodeMenu"; -import { IReactionDisposer, ObservableMap, reaction } from "mobx"; -import { Doc, Opt } from "../../../../fields/Doc"; -import { returnFalse, unimplementedFunction } from "../../../../Utils"; -import { NumCast, StrCast } from "../../../../fields/Types"; -import { SelectionManager } from "../../../util/SelectionManager"; -import { IconButton } from "browndash-components"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { SettingsManager } from "../../../util/SettingsManager"; -import { IconLookup, faAdd, faCalendarDays, faRoute } from "@fortawesome/free-solid-svg-icons"; +import * as React from 'react'; +import { observer } from 'mobx-react'; +import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; +import { IReactionDisposer, ObservableMap, reaction } from 'mobx'; +import { Doc, Opt } from '../../../../fields/Doc'; +import { returnFalse, unimplementedFunction } from '../../../../Utils'; +import { NumCast, StrCast } from '../../../../fields/Types'; +import { SelectionManager } from '../../../util/SelectionManager'; +import { IconButton } from 'browndash-components'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { SettingsManager } from '../../../util/SettingsManager'; +import { IconLookup, faAdd, faCalendarDays, faRoute } from '@fortawesome/free-solid-svg-icons'; @observer export class DirectionsAnchorMenu extends AntimodeMenu { @@ -32,9 +32,9 @@ export class DirectionsAnchorMenu extends AntimodeMenu { private title: string | undefined = undefined; - public setPinDoc(pinDoc: Doc){ - this.title = StrCast(pinDoc.title ? pinDoc.title : `${NumCast(pinDoc.longitude)}, ${NumCast(pinDoc.latitude)}`) ; - console.log("Title: ", this.title) + public setPinDoc(pinDoc: Doc) { + this.title = StrCast(pinDoc.title ? pinDoc.title : `${NumCast(pinDoc.longitude)}, ${NumCast(pinDoc.latitude)}`); + console.log('Title: ', this.title); } public get Active() { @@ -54,7 +54,7 @@ export class DirectionsAnchorMenu extends AntimodeMenu { componentDidMount() { this._disposer = reaction( - () => SelectionManager.Views().slice(), + () => SelectionManager.Views.slice(), sel => DirectionsAnchorMenu.Instance.fadeOut(true) ); } @@ -95,43 +95,28 @@ export class DirectionsAnchorMenu extends AntimodeMenu { render() { const buttons = ( -
+
} color={SettingsManager.userColor} /> - - - } - color={SettingsManager.userColor} - /> - } - color={SettingsManager.userColor} - /> + + } color={SettingsManager.userColor} /> + } color={SettingsManager.userColor} />
- ) + ); return this.getElement( -
+
{this.title}
-
- - +
+ +
{buttons}
- ) + ); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx index a6182991d..6a14427c0 100644 --- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -43,7 +43,7 @@ import { MapProvider, Map as MapboxMap } from 'react-map-gl'; * A map marker is considered a document that contains a collection with stacking view of documents, it has a lat, lng location, which is passed to Maps API's custom marker (red pin) to be rendered on the google maps */ -const mapboxApiKey = "pk.eyJ1IjoiemF1bHRhdmFuZ2FyIiwiYSI6ImNsbnc2eHJpbTA1ZTUyam85aGx4Z2FhbGwifQ.2Kqw9mk-9wAAg9kmHmKzcg"; +const mapboxApiKey = 'pk.eyJ1IjoiemF1bHRhdmFuZ2FyIiwiYSI6ImNsbnc2eHJpbTA1ZTUyam85aGx4Z2FhbGwifQ.2Kqw9mk-9wAAg9kmHmKzcg'; const bingApiKey = process.env.BING_MAPS; // if you're running local, get a Bing Maps api key here: https://www.bingmapsportal.com/ and then add it to the .env file in the Dash-Web root directory as: _CLIENT_BING_MAPS= /** @@ -198,7 +198,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent @@ -230,8 +230,8 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { - const target = DocUtils.GetNewTextDoc('Note linked to ' + this.rootDoc.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow'); - FormattedTextBox.SelectOnLoad = target[Id]; + const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, undefined, annotationOn, undefined, 'yellow'); + FormattedTextBox.SetSelectOnLoad(target); return target; }; const docView = this.props.DocumentView?.(); @@ -324,7 +324,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { if (this.selectedPin) { // Removes filter - Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'remove'); - Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'remove'); - Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove'); + Doc.setDocFilter(this.Document, 'latitude', this.selectedPin.latitude, 'remove'); + Doc.setDocFilter(this.Document, 'longitude', this.selectedPin.longitude, 'remove'); + Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove'); const temp = this.selectedPin; if (!this._unmounting) { @@ -372,7 +372,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { /// this should use SELECTED pushpin for lat/long if there is a selection, otherwise CENTER const anchor = Docs.Create.ConfigDocument({ - title: 'MapAnchor:' + this.rootDoc.title, - text: StrCast(this.selectedPin?.map) || StrCast(this.rootDoc.map) || 'map location', + title: 'MapAnchor:' + this.Document.title, + text: StrCast(this.selectedPin?.map) || StrCast(this.Document.map) || 'map location', config_latitude: NumCast((existingPin ?? this.selectedPin)?.latitude ?? this.dataDoc.latitude), config_longitude: NumCast((existingPin ?? this.selectedPin)?.longitude ?? this.dataDoc.longitude), config_map_zoom: NumCast(this.dataDoc.map_zoom), @@ -469,15 +469,15 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent(); @@ -524,9 +524,9 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { if (this.selectedPin) { // Removes filter - Doc.setDocFilter(this.rootDoc, 'latitude', this.selectedPin.latitude, 'remove'); - Doc.setDocFilter(this.rootDoc, 'longitude', this.selectedPin.longitude, 'remove'); - Doc.setDocFilter(this.rootDoc, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove'); + Doc.setDocFilter(this.Document, 'latitude', this.selectedPin.latitude, 'remove'); + Doc.setDocFilter(this.Document, 'longitude', this.selectedPin.longitude, 'remove'); + Doc.setDocFilter(this.Document, LinkedTo, `mapPin=${Field.toScriptString(DocCast(this.selectedPin))}`, 'remove'); this.removePushpin(this.selectedPin); } @@ -614,7 +614,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent this.rootDoc.map, + () => this.Document.map, mapLoc => (this.bingSearchBarContents = mapLoc), { fireImmediately: true } ); @@ -639,7 +639,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent ({ lat: this.rootDoc.latitude, lng: this.rootDoc.longitude, zoom: this.rootDoc.map_zoom, mapType: this.rootDoc.map_type }), + () => ({ lat: this.Document.latitude, lng: this.Document.longitude, zoom: this.Document.map_zoom, mapType: this.Document.map_type }), locationObject => { // if (this._bingMap.current) try { @@ -690,7 +690,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { - const createPin = () => this.createPushpin(this.rootDoc.latitude, this.rootDoc.longitude, this.rootDoc.map); + const createPin = () => this.createPushpin(this.Document.latitude, this.Document.longitude, this.Document.map); if (this.bingSearchBarContents) { this.bingSearch().then(createPin); } else createPin(); @@ -706,7 +706,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent
{renderAnnotations(this.transparentFilter)}
{renderAnnotations(this.opaqueFilter)} - {SnappingManager.GetIsDragging() ? null : renderAnnotations()} + {SnappingManager.IsDragging ? null : renderAnnotations()}
- + - - -{/* + + {/* Date: Fri, 29 Dec 2023 17:01:40 -0500 Subject: cleaned up imports, mobx observable initialization and some compile errors. --- src/Utils.ts | 27 ++--- src/client/util/CalendarManager.tsx | 34 +++--- src/client/util/CaptureManager.tsx | 2 +- src/client/util/CurrentUserUtils.ts | 14 +-- src/client/util/GroupManager.tsx | 2 +- src/client/util/HypothesisUtils.ts | 13 ++- src/client/views/DocumentButtonBar.tsx | 5 - src/client/views/DocumentDecorations.tsx | 11 +- src/client/views/FilterPanel.tsx | 11 +- src/client/views/GestureOverlay.tsx | 25 +++-- src/client/views/InkTranscription.tsx | 8 +- src/client/views/InkingStroke.tsx | 76 +++++--------- src/client/views/MainView.tsx | 2 +- src/client/views/MetadataEntryMenu.tsx | 12 +-- src/client/views/PreviewCursor.tsx | 2 +- src/client/views/PropertiesButtons.tsx | 17 +-- .../views/PropertiesDocBacklinksSelector.tsx | 4 +- src/client/views/PropertiesSection.tsx | 6 +- src/client/views/TemplateMenu.tsx | 2 +- src/client/views/UndoStack.tsx | 22 ++-- src/client/views/animationtimeline/Region.tsx | 2 +- src/client/views/animationtimeline/Timeline.tsx | 4 +- .../views/animationtimeline/TimelineOverview.tsx | 2 +- src/client/views/animationtimeline/Track.tsx | 8 +- .../views/collections/CollectionCalendarView.tsx | 19 ++-- .../views/collections/CollectionDockingView.tsx | 4 +- src/client/views/collections/CollectionMenu.tsx | 3 - .../CollectionNoteTakingViewDivider.tsx | 2 +- .../views/collections/CollectionPileView.tsx | 2 +- .../collections/CollectionStackedTimeline.tsx | 4 +- .../CollectionStackingViewFieldColumn.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 8 +- .../views/collections/CollectionTimeView.tsx | 14 +-- src/client/views/collections/CollectionView.tsx | 2 +- src/client/views/collections/KeyRestrictionRow.tsx | 37 +++---- src/client/views/collections/TreeView.tsx | 2 +- .../CollectionFreeFormBackgroundGrid.tsx | 2 +- .../CollectionFreeFormInfoState.tsx | 2 +- .../CollectionFreeFormInfoUI.tsx | 8 +- .../CollectionFreeFormLinksView.tsx | 4 +- .../CollectionFreeFormPannableContents.tsx | 5 +- .../CollectionFreeFormRemoteCursors.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../collections/collectionFreeForm/MarqueeView.tsx | 5 +- .../collectionGrid/CollectionGridView.tsx | 4 +- .../views/collections/collectionGrid/Grid.tsx | 2 +- .../CollectionMulticolumnView.tsx | 4 +- .../CollectionMultirowView.tsx | 3 +- .../collectionMulticolumn/MulticolumnResizer.tsx | 8 +- .../MulticolumnWidthLabel.tsx | 27 +++-- .../collectionMulticolumn/MultirowHeightLabel.tsx | 22 ++-- .../collectionMulticolumn/MultirowResizer.tsx | 6 +- .../collectionSchema/SchemaColumnHeader.tsx | 4 +- src/client/views/linking/LinkMenuItem.tsx | 6 +- src/client/views/linking/LinkPopup.tsx | 8 +- .../views/linking/LinkRelationshipSearch.tsx | 2 +- .../views/newlightbox/ButtonMenu/ButtonMenu.tsx | 4 +- src/client/views/newlightbox/NewLightboxView.tsx | 26 ++--- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 4 +- .../views/nodes/DataVizBox/SchemaCSVPopUp.tsx | 30 +++--- .../nodes/DataVizBox/components/Histogram.tsx | 6 +- .../nodes/DataVizBox/components/LineChart.tsx | 28 ++--- .../views/nodes/DataVizBox/components/PieChart.tsx | 6 +- .../views/nodes/DataVizBox/components/TableBox.tsx | 12 +-- src/client/views/nodes/DocumentContentsView.tsx | 6 +- src/client/views/nodes/DocumentView.tsx | 7 +- src/client/views/nodes/FaceRectangle.tsx | 4 +- src/client/views/nodes/FaceRectangles.tsx | 4 +- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/KeyValuePair.tsx | 6 +- src/client/views/nodes/LinkDescriptionPopup.tsx | 2 +- src/client/views/nodes/LinkDocPreview.tsx | 8 +- src/client/views/nodes/LoadingBox.tsx | 2 +- src/client/views/nodes/MapBox/AnimationUtility.ts | 13 +-- .../views/nodes/MapBox/DirectionsAnchorMenu.tsx | 14 +-- src/client/views/nodes/MapBox/MapAnchorMenu.tsx | 106 +++++++------------ src/client/views/nodes/MapBox/MapBox.tsx | 60 +++++------ src/client/views/nodes/MapBox/MapBox2.tsx | 2 +- .../views/nodes/MapboxMapBox/MapboxContainer.tsx | 20 ++-- src/client/views/nodes/PDFBox.tsx | 2 +- .../nodes/PhysicsBox/PhysicsSimulationBox.tsx | 4 +- .../nodes/PhysicsBox/PhysicsSimulationWeight.tsx | 2 +- src/client/views/nodes/RadialMenu.tsx | 2 +- src/client/views/nodes/RadialMenuItem.tsx | 2 +- .../views/nodes/RecordingBox/RecordingBox.tsx | 4 +- src/client/views/nodes/ScreenshotBox.tsx | 2 +- src/client/views/nodes/ScriptingBox.tsx | 8 +- src/client/views/nodes/TaskCompletedBox.tsx | 8 +- src/client/views/nodes/VideoBox.tsx | 6 +- src/client/views/nodes/audio/AudioWaveform.tsx | 2 +- src/client/views/nodes/calendarBox/CalendarBox.tsx | 114 +++++++++------------ .../views/nodes/formattedText/DashDocView.tsx | 6 +- .../views/nodes/formattedText/EquationView.tsx | 7 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 4 +- .../views/nodes/formattedText/RichTextMenu.tsx | 2 +- .../views/nodes/importBox/ImportElementBox.tsx | 8 +- src/client/views/nodes/trails/PresBox.tsx | 6 +- src/client/views/pdf/Annotation.tsx | 5 +- src/client/views/pdf/GPTPopup/GPTPopup.tsx | 16 +-- src/client/views/pdf/PDFViewer.tsx | 2 +- src/client/views/search/SearchBox.tsx | 15 ++- src/client/views/selectedDoc/SelectedDocView.tsx | 6 +- src/client/views/topbar/TopBar.tsx | 4 +- src/client/views/webcam/DashWebRTCVideo.tsx | 5 +- src/debug/Repl.tsx | 10 +- src/debug/Viewer.tsx | 18 ++-- src/fields/CursorField.ts | 7 +- src/fields/Doc.ts | 4 +- src/fields/List.ts | 8 +- src/fields/Proxy.ts | 12 +-- src/fields/util.ts | 4 +- src/mobile/ImageUpload.tsx | 6 +- src/mobile/MobileInkOverlay.tsx | 2 +- src/mobile/MobileInterface.tsx | 110 ++++++++++---------- src/typings/index.d.ts | 4 +- test/test.ts | 106 ++++++++++--------- 116 files changed, 650 insertions(+), 793 deletions(-) (limited to 'src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx') diff --git a/src/Utils.ts b/src/Utils.ts index a060e4a2c..b5c218e01 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -1,13 +1,12 @@ -import * as uuid from 'uuid'; import { ColorResult } from 'react-color'; +import * as uuid from 'uuid'; //import { Socket } from '../node_modules/socket.io-client'; -import { Socket } from '../node_modules/socket.io/dist/index'; +import * as Color from 'color'; import * as rp from 'request-promise'; +import { Socket } from '../node_modules/socket.io/dist/index'; import { DocumentType } from './client/documents/DocumentTypes'; import { Colors } from './client/views/global/globalEnums'; import { Message } from './server/Message'; -import * as Color from 'color'; -import { action } from 'mobx'; export namespace Utils { export let CLICK_TIME = 300; @@ -896,23 +895,19 @@ export function setupMoveUpEvents( document.addEventListener('click', _clickEvent, true); } -export function dateRangeStrToDates (dateStr: string) { +export function dateRangeStrToDates(dateStr: string) { // dateStr in yyyy-mm-dd format - const dateRangeParts = dateStr.split("|"); // splits into from and to date - const fromParts = dateRangeParts[0].split("-"); - const toParts = dateRangeParts[1].split("-"); + const dateRangeParts = dateStr.split('|'); // splits into from and to date + const fromParts = dateRangeParts[0].split('-'); + const toParts = dateRangeParts[1].split('-'); const fromYear = parseInt(fromParts[0]); - const fromMonth = parseInt(fromParts[1])-1; + const fromMonth = parseInt(fromParts[1]) - 1; const fromDay = parseInt(fromParts[2]); const toYear = parseInt(toParts[0]); - const toMonth = parseInt(toParts[1])-1; + const toMonth = parseInt(toParts[1]) - 1; const toDay = parseInt(toParts[2]); - - return [ - new Date(fromYear, fromMonth, fromDay), - new Date(toYear, toMonth, toDay) - ]; -} \ No newline at end of file + return [new Date(fromYear, fromMonth, fromDay), new Date(toYear, toMonth, toDay)]; +} diff --git a/src/client/util/CalendarManager.tsx b/src/client/util/CalendarManager.tsx index 6ef2d3429..6e9094b3a 100644 --- a/src/client/util/CalendarManager.tsx +++ b/src/client/util/CalendarManager.tsx @@ -1,26 +1,24 @@ -import * as React from 'react'; -import './CalendarManager.scss'; +import { TextField } from '@mui/material'; +import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; -import { action, computed, observable, runInAction, makeObservable } from 'mobx'; +import * as React from 'react'; +import Select from 'react-select'; import { Doc, DocListCast } from '../../fields/Doc'; -import { DocumentView } from '../views/nodes/DocumentView'; +import { DocData } from '../../fields/DocSymbols'; +import { StrCast } from '../../fields/Types'; import { DictationOverlay } from '../views/DictationOverlay'; -import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox'; import { MainViewModal } from '../views/MainViewModal'; -import { TextField } from '@mui/material'; -import Select from 'react-select'; -import { SettingsManager } from './SettingsManager'; -import { DateCast, DocCast, StrCast } from '../../fields/Types'; -import { SelectionManager } from './SelectionManager'; +import { DocumentView } from '../views/nodes/DocumentView'; +import { TaskCompletionBox } from '../views/nodes/TaskCompletedBox'; +import './CalendarManager.scss'; import { DocumentManager } from './DocumentManager'; -import { DocData } from '../../fields/DocSymbols'; +import { SelectionManager } from './SelectionManager'; +import { SettingsManager } from './SettingsManager'; // import { DateRange, Range, RangeKeyDict } from 'react-date-range'; -import { Button } from 'browndash-components'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Provider, defaultTheme } from '@adobe/react-spectrum'; -import { DateValue } from '@internationalized/date'; -import { DateRangePicker, SpectrumDateRangePickerProps } from '@adobe/react-spectrum'; +import { DateRangePicker, Provider, defaultTheme } from '@adobe/react-spectrum'; import { IconLookup, faPlus } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Button } from 'browndash-components'; import { Docs } from '../documents/Documents'; import { ObservableReactComponent } from '../views/ObservableReactComponent'; // import 'react-date-range/dist/styles.css'; @@ -51,8 +49,8 @@ const formatCalendarDateToString = (calendarDate: any) => { export class CalendarManager extends ObservableReactComponent<{}> { public static Instance: CalendarManager; @observable private isOpen = false; - @observable private targetDoc: Doc | undefined; // the target document - @observable private targetDocView: DocumentView | undefined; // the DocumentView of the target doc + @observable private targetDoc: Doc | undefined = undefined; // the target document + @observable private targetDocView: DocumentView | undefined = undefined; // the DocumentView of the target doc @observable private dialogueBoxOpacity = 1; // for the modal @observable private overlayOpacity = 0.4; // for the modal diff --git a/src/client/util/CaptureManager.tsx b/src/client/util/CaptureManager.tsx index 071fc1ee9..c1e0a5b2e 100644 --- a/src/client/util/CaptureManager.tsx +++ b/src/client/util/CaptureManager.tsx @@ -15,7 +15,7 @@ import { SelectionManager } from './SelectionManager'; export class CaptureManager extends React.Component<{}> { public static Instance: CaptureManager; static _settingsStyle = addStyleSheet(); - @observable _document: any; + @observable _document: any = undefined; @observable isOpen: boolean = false; // whether the CaptureManager is to be displayed or not. constructor(props: {}) { diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index c1d74c398..3f28f44fc 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -1,5 +1,6 @@ import { observable, reaction, runInAction } from "mobx"; import * as rp from 'request-promise'; +import { OmitKeys, Utils } from "../../Utils"; import { Doc, DocListCast, DocListCastAsync, Opt } from "../../fields/Doc"; import { InkTool } from "../../fields/InkField"; import { List } from "../../fields/List"; @@ -8,29 +9,28 @@ import { RichTextField } from "../../fields/RichTextField"; import { listSpec } from "../../fields/Schema"; import { ScriptField } from "../../fields/ScriptField"; import { Cast, DateCast, DocCast, StrCast } from "../../fields/Types"; -import { nullAudio, WebField } from "../../fields/URLField"; +import { WebField, nullAudio } from "../../fields/URLField"; import { SetCachedGroups, SharingPermissions } from "../../fields/util"; import { GestureUtils } from "../../pen-gestures/GestureUtils"; -import { OmitKeys, Utils } from "../../Utils"; import { DocServer } from "../DocServer"; -import { Docs, DocumentOptions, DocUtils, FInfo } from "../documents/Documents"; import { CollectionViewType, DocumentType } from "../documents/DocumentTypes"; -import { TreeViewType } from "../views/collections/CollectionTreeView"; +import { DocUtils, Docs, DocumentOptions, FInfo } from "../documents/Documents"; import { DashboardView } from "../views/DashboardView"; +import { OverlayView } from "../views/OverlayView"; +import { TreeViewType } from "../views/collections/CollectionTreeView"; import { Colors } from "../views/global/globalEnums"; import { media_state } from "../views/nodes/AudioBox"; -import { DocumentView, OpenWhere } from "../views/nodes/DocumentView"; +import { OpenWhere } from "../views/nodes/DocumentView"; import { ButtonType } from "../views/nodes/FontIconBox/FontIconBox"; import { ImportElementBox } from "../views/nodes/importBox/ImportElementBox"; -import { OverlayView } from "../views/OverlayView"; import { DragManager, dropActionType } from "./DragManager"; import { MakeTemplate } from "./DropConverter"; import { FollowLinkScript } from "./LinkFollower"; import { LinkManager } from "./LinkManager"; import { ScriptingGlobals } from "./ScriptingGlobals"; import { ColorScheme } from "./SettingsManager"; -import { UndoManager } from "./UndoManager"; import { SnappingManager } from "./SnappingManager"; +import { UndoManager } from "./UndoManager"; interface Button { // DocumentOptions fields a button can set diff --git a/src/client/util/GroupManager.tsx b/src/client/util/GroupManager.tsx index 90f65b648..f4f879208 100644 --- a/src/client/util/GroupManager.tsx +++ b/src/client/util/GroupManager.tsx @@ -33,7 +33,7 @@ export class GroupManager extends ObservableReactComponent<{}> { @observable isOpen: boolean = false; // whether the GroupManager is to be displayed or not. @observable private users: string[] = []; // list of users populated from the database. @observable private selectedUsers: UserOptions[] | null = null; // list of users selected in the "Select users" dropdown. - @observable currentGroup: Opt; // the currently selected group. + @observable currentGroup: Opt = undefined; // the currently selected group. @observable private createGroupModalOpen: boolean = false; private inputRef: React.RefObject = React.createRef(); // the ref for the input box. private createGroupButtonRef: React.RefObject = React.createRef(); // the ref for the group creation button diff --git a/src/client/util/HypothesisUtils.ts b/src/client/util/HypothesisUtils.ts index 990798ed3..0ae23d793 100644 --- a/src/client/util/HypothesisUtils.ts +++ b/src/client/util/HypothesisUtils.ts @@ -1,16 +1,15 @@ -import { StrCast, Cast } from '../../fields/Types'; -import { SearchUtil } from './SearchUtil'; import { action, runInAction } from 'mobx'; +import { simulateMouseClick } from '../../Utils'; import { Doc, Opt } from '../../fields/Doc'; +import { Cast, StrCast } from '../../fields/Types'; +import { WebField } from '../../fields/URLField'; import { DocumentType } from '../documents/DocumentTypes'; import { Docs } from '../documents/Documents'; -import { SelectionManager } from './SelectionManager'; -import { WebField } from '../../fields/URLField'; -import { DocumentManager } from './DocumentManager'; import { DocumentLinksButton } from '../views/nodes/DocumentLinksButton'; -import { simulateMouseClick, Utils } from '../../Utils'; import { DocumentView } from '../views/nodes/DocumentView'; -import { Id } from '../../fields/FieldSymbols'; +import { DocumentManager } from './DocumentManager'; +import { SearchUtil } from './SearchUtil'; +import { SelectionManager } from './SelectionManager'; export namespace Hypothesis { /** diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index f0887676f..3938b81cd 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -40,14 +40,9 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => ( private _pullAnimating = false; private _pushAnimating = false; private _pullColorAnimating = false; - @observable private pushIcon: IconProp = 'arrow-alt-circle-up'; - @observable private pullIcon: IconProp = 'arrow-alt-circle-down'; - @observable private pullColor: string = 'white'; @observable public isAnimatingFetch = false; @observable public isAnimatingPulse = false; - @observable private openHover: UtilityButtonState = UtilityButtonState.Default; - @observable public static Instance: DocumentButtonBar; public static hasPushedHack = false; public static hasPulledHack = false; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index d2f23c2f3..dab6e6193 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -12,7 +12,7 @@ import { RichTextField } from '../../fields/RichTextField'; import { ScriptField } from '../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; import { GetEffectiveAcl } from '../../fields/util'; -import { emptyFunction, numberValue, returnFalse, setupMoveUpEvents, Utils } from '../../Utils'; +import { emptyFunction, lightOrDark, numberValue, returnFalse, setupMoveUpEvents, Utils } from '../../Utils'; import { Docs } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; import { DocumentManager } from '../util/DocumentManager'; @@ -85,7 +85,7 @@ export class DocumentDecorations extends ObservableReactComponent; - @observable public SavedColor?: string; - @observable public SavedWidth?: number; + @observable public InkShape: Opt = undefined; + @observable public SavedColor?: string = undefined; + @observable public SavedWidth?: number = undefined; @observable public Tool: ToolglassTools = ToolglassTools.None; @observable public KeepPrimitiveMode = false; // for whether primitive selection enters a one-shot or persistent mode - @observable private _thumbX?: number; - @observable private _thumbY?: number; + @observable private _thumbX?: number = undefined; + @observable private _thumbY?: number = undefined; @observable private _selectedIndex: number = -1; @observable private _menuX: number = -300; @observable private _menuY: number = -300; - @observable private _pointerY?: number; + @observable private _pointerY?: number = undefined; @observable private _points: { X: number; Y: number }[] = []; @observable private _strokes: InkData[] = []; - @observable private _palette?: JSX.Element; - @observable private _clipboardDoc?: JSX.Element; + @observable private _palette?: JSX.Element = undefined; + @observable private _clipboardDoc?: JSX.Element = undefined; @observable private _possibilities: JSX.Element[] = []; public static DownDocView: DocumentView | undefined; diff --git a/src/client/views/InkTranscription.tsx b/src/client/views/InkTranscription.tsx index b2ac208ca..7e2b334af 100644 --- a/src/client/views/InkTranscription.tsx +++ b/src/client/views/InkTranscription.tsx @@ -17,10 +17,10 @@ // export class InkTranscription extends React.Component { // static Instance: InkTranscription; -// @observable _mathRegister: any; -// @observable _mathRef: any; -// @observable _textRegister: any; -// @observable _textRef: any; +// @observable _mathRegister: any= undefined; +// @observable _mathRef: any= undefined; +// @observable _textRegister: any= undefined; +// @observable _textRef: any= undefined; // private lastJiix: any; // private currGroup?: Doc; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 9c96b4563..95c677845 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -20,9 +20,9 @@ Most of the operations that can be performed on an InkStroke (eg delete a point, rotate, stretch) are implemented in the InkStrokeProperties helper class */ -import * as React from 'react'; import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc } from '../../fields/Doc'; import { InkData, InkField } from '../../fields/InkField'; import { BoolCast, Cast, NumCast, RTFCast, StrCast } from '../../fields/Types'; @@ -32,7 +32,6 @@ import { CognitiveServices } from '../cognitive_services/CognitiveServices'; import { Docs } from '../documents/Documents'; import { InteractionUtils } from '../util/InteractionUtils'; import { SnappingManager } from '../util/SnappingManager'; -import { Transform } from '../util/Transform'; import { UndoManager } from '../util/UndoManager'; import { ContextMenu } from './ContextMenu'; import { ViewBoxBaseComponent } from './DocComponent'; @@ -59,14 +58,14 @@ export class InkingStroke extends ViewBoxBaseComponent() { private _handledClick = false; // flag denoting whether ink stroke has handled a psuedo-click onPointerUp so that the real onClick event can be stopPropagated private _disposers: { [key: string]: IReactionDisposer } = {}; - @observable _nearestSeg?: number; // nearest Bezier segment along the ink stroke to the cursor (used for displaying the Add Point highlight) - @observable _nearestT?: number; // nearest t value within the nearest Bezier segment " + @observable _nearestSeg?: number = undefined; // nearest Bezier segment along the ink stroke to the cursor (used for displaying the Add Point highlight) + @observable _nearestT?: number = undefined; // nearest t value within the nearest Bezier segment " @observable _nearestScrPt?: { X: number; Y: number }; // nearst screen point on the ink stroke "" componentDidMount() { - this.props.setContentView?.(this); + this._props.setContentView?.(this); this._disposers.selfDisper = reaction( - () => this.props.isSelected(), // react to stroke being deselected by turning off ink handles + () => this._props.isSelected(), // react to stroke being deselected by turning off ink handles selected => !selected && (InkStrokeProperties.Instance._controlButton = false) ); } @@ -76,7 +75,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { // transform is the inherited screentolocal xf plus any scaling that was done to make the stroke // fit within its panel (e.g., for content fitting views like Lightbox or multicolumn, etc) - screenToLocal = () => this.props.ScreenToLocalTransform().scale(this.props.NativeDimScaling?.() || 1); + screenToLocal = () => this._props.ScreenToLocalTransform().scale(this._props.NativeDimScaling?.() || 1); getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { const subAnchor = this._subContentView?.getAnchor?.(addAsAnnotation); @@ -100,27 +99,6 @@ export class InkingStroke extends ViewBoxBaseComponent() { return this.Document; }; - /** - * @returns the center of the ink stroke in the ink document's coordinate space (not screen space, and not the ink data coordinate space); - * DocumentDecorations calls getBounds() on DocumentViews which call getCenter() if defined - in the case of ink it needs to be defined since - * the center of the ink stroke changes as the stroke is rotated. - */ - getCenter = (xf: Transform) => { - const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); - const angle = -NumCast(this.layoutDoc.rotation); - const newPoints = inkData.map(pt => { - const newX = Math.cos(angle) * pt.X - (Math.sin(angle) * pt.Y * inkScaleY) / inkScaleX; - const newY = (Math.sin(angle) * pt.X * inkScaleX) / inkScaleY + Math.cos(angle) * pt.Y; - return { X: newX, Y: newY }; - }); - const crx = (Math.max(...newPoints.map(np => np.X)) + Math.min(...newPoints.map(np => np.X))) / 2; - const cry = (Math.max(...newPoints.map(np => np.Y)) + Math.min(...newPoints.map(np => np.Y))) / 2; - const cx = Math.cos(-angle) * crx - (Math.sin(-angle) * cry * inkScaleY) / inkScaleX; - const cy = (Math.sin(-angle) * crx * inkScaleX) / inkScaleY + Math.cos(-angle) * cry; - const tc = xf.transformPoint((cx - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (cy - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2); - return { X: tc[0], Y: tc[1] }; - }; - /** * analyzes the ink stroke and saves the analysis of the stroke to the 'inkAnalysis' field, * and the recognized words to the 'handwriting' @@ -147,7 +125,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { @action onPointerDown = (e: React.PointerEvent) => { this._handledClick = false; - const inkView = this.props.docViewPath().lastElement(); + const inkView = this._props.docViewPath().lastElement(); const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); const screenPts = inkData .map(point => @@ -159,7 +137,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { const { nearestSeg } = InkStrokeProperties.nearestPtToStroke(screenPts, { X: e.clientX, Y: e.clientY }); const controlIndex = nearestSeg; const wasSelected = InkStrokeProperties.Instance._currentPoint === controlIndex; - const isEditing = InkStrokeProperties.Instance._controlButton && this.props.isSelected(); + const isEditing = InkStrokeProperties.Instance._controlButton && this._props.isSelected(); this.controlUndo = undefined; setupMoveUpEvents( this, @@ -187,7 +165,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { InkStrokeProperties.Instance._currentPoint = -1; this._handledClick = true; // mark the double-click pseudo pointerevent so we can block the real mouse event from propagating to DocumentView if (isEditing) { - this._nearestT && this._nearestSeg !== undefined && InkStrokeProperties.Instance.addPoints(this.props.docViewPath().lastElement(), this._nearestT, this._nearestSeg, this.inkScaledData().inkData.slice()); + this._nearestT && this._nearestSeg !== undefined && InkStrokeProperties.Instance.addPoints(this._props.docViewPath().lastElement(), this._nearestT, this._nearestSeg, this.inkScaledData().inkData.slice()); } } }), @@ -258,8 +236,8 @@ export class InkingStroke extends ViewBoxBaseComponent() { inkLeft, inkWidth, inkHeight, - inkScaleX: (this.props.PanelWidth() - inkStrokeWidth) / (inkWidth - inkStrokeWidth || 1) || 1, - inkScaleY: (this.props.PanelHeight() - inkStrokeWidth) / (inkHeight - inkStrokeWidth || 1) || 1, + inkScaleX: (this._props.PanelWidth() - inkStrokeWidth) / (inkWidth - inkStrokeWidth || 1) || 1, + inkScaleY: (this._props.PanelHeight() - inkStrokeWidth) / (inkHeight - inkStrokeWidth || 1) || 1, }; }; @@ -311,7 +289,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { * @returns the JSX controls for displaying an editing UI for the stroke (control point & tangent handles) */ componentUI = (boundsLeft: number, boundsTop: number) => { - const inkDoc = this.props.Document; + const inkDoc = this.Document; const { inkData, inkStrokeWidth } = this.inkScaledData(); const screenSpaceCenterlineStrokeWidth = Math.min(3, inkStrokeWidth * this.screenToLocal().inverse().Scale); // the width of the blue line widget that shows the centerline of the ink stroke @@ -321,7 +299,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { const endMarker = StrCast(this.layoutDoc.stroke_endMarker); const markerScale = NumCast(this.layoutDoc.stroke_markerScale); return SnappingManager.IsDragging ? null : !InkStrokeProperties.Instance._controlButton ? ( - !this.props.isSelected() || InkingStroke.IsClosed(inkData) ? null : ( + !this._props.isSelected() || InkingStroke.IsClosed(inkData) ? null : (
@@ -360,12 +338,12 @@ export class InkingStroke extends ViewBoxBaseComponent() { setSubContentView = (doc: DocComponentView) => (this._subContentView = doc); @computed get fillColor() { const isInkMask = BoolCast(this.layoutDoc.stroke_isInkMask); - return isInkMask ? DashColor(StrCast(this.layoutDoc.fillColor, 'transparent')).blacken(0).rgb().toString() : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.FillColor) ?? 'transparent'; + return isInkMask ? DashColor(StrCast(this.layoutDoc.fillColor, 'transparent')).blacken(0).rgb().toString() : this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.FillColor) ?? 'transparent'; } @computed get strokeColor() { const { inkData } = this.inkScaledData(); const fillColor = this.fillColor; - return !InkingStroke.IsClosed(inkData) && fillColor && fillColor !== 'transparent' ? fillColor : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color) ?? StrCast(this.layoutDoc.color); + return !InkingStroke.IsClosed(inkData) && fillColor && fillColor !== 'transparent' ? fillColor : this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) ?? StrCast(this.layoutDoc.color); } render() { TraceMobx(); @@ -385,9 +363,9 @@ export class InkingStroke extends ViewBoxBaseComponent() { this.layoutDoc._height = Math.round(NumCast(this.layoutDoc._height)); }); } - const highlight = !this.controlUndo && this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Highlighting); + const highlight = !this.controlUndo && this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Highlighting); const highlightIndex = highlight?.highlightIndex; - const highlightColor = !this.props.isSelected() && !isInkMask && highlight?.highlightIndex ? highlight?.highlightColor : undefined; + const highlightColor = !this._props.isSelected() && !isInkMask && highlight?.highlightIndex ? highlight?.highlightColor : undefined; const color = StrCast(this.layoutDoc.stroke_outlineColor, !closed && fillColor && fillColor !== 'transparent' ? StrCast(this.layoutDoc.color, 'transparent') : 'transparent'); // Visually renders the polygonal line made by the user. @@ -437,7 +415,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { inkScaleX, inkScaleY, '', - this.props.pointerEvents?.() ?? 'visiblepainted', + this._props.pointerEvents?.() ?? 'visiblepainted', 0.0, false, downHdlr, @@ -450,7 +428,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { const lineHeightGuess = +getComputedStyle(document.body).lineHeight.replace('px', '') / +getComputedStyle(document.body).fontSize.replace('px', ''); const interactions = { onPointerLeave: action(() => (this._nearestScrPt = undefined)), - onPointerMove: this.props.isSelected() ? this.onPointerMove : undefined, + onPointerMove: this._props.isSelected() ? this.onPointerMove : undefined, onClick: (e: React.MouseEvent) => this._handledClick && e.stopPropagation(), onContextMenu: () => { const cm = ContextMenu.Instance; @@ -464,27 +442,27 @@ export class InkingStroke extends ViewBoxBaseComponent() { {clickableLine(this.onPointerDown, isInkMask)} {isInkMask ? null : inkLine} - {!closed || (!RTFCast(this.dataDoc.text)?.Text && (!this.props.isSelected() || Doc.UserDoc().activeInkHideTextLabels)) ? null : ( + {!closed || (!RTFCast(this.dataDoc.text)?.Text && (!this._props.isSelected() || Doc.UserDoc().activeInkHideTextLabels)) ? null : (
() { dontRegisterView={true} noSidebar={true} dontScale={true} - isContentActive={this.props.isContentActive} + isContentActive={this._props.isContentActive} />
)} diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 094bd2adb..35ffab337 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -118,7 +118,7 @@ export class MainView extends ObservableReactComponent<{}> { @computed private get userDoc() { return Doc.UserDoc(); } - @observable mainDoc: Opt; + @observable mainDoc: Opt = undefined; @computed private get mainContainer() { if (window.location.pathname.startsWith('/doc/') && Doc.CurrentUserEmail === 'guest') { DocServer.GetRefField(window.location.pathname.substring('/doc/'.length)).then(main => runInAction(() => (this.mainDoc = main as Doc))); diff --git a/src/client/views/MetadataEntryMenu.tsx b/src/client/views/MetadataEntryMenu.tsx index 5c6912121..89c3c41f8 100644 --- a/src/client/views/MetadataEntryMenu.tsx +++ b/src/client/views/MetadataEntryMenu.tsx @@ -1,12 +1,12 @@ -import * as React from 'react'; -import './MetadataEntryMenu.scss'; +import { IReactionDisposer, action, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; -import { observable, action, runInAction, trace, computed, IReactionDisposer, reaction } from 'mobx'; -import { KeyValueBox } from './nodes/KeyValueBox'; -import { Doc, Field, DocListCastAsync, DocListCast } from '../../fields/Doc'; +import * as React from 'react'; import * as Autosuggest from 'react-autosuggest'; -import { undoBatch, UndoManager } from '../util/UndoManager'; import { emptyFunction, emptyPath } from '../../Utils'; +import { Doc, DocListCast, Field } from '../../fields/Doc'; +import { undoBatch } from '../util/UndoManager'; +import './MetadataEntryMenu.scss'; +import { KeyValueBox } from './nodes/KeyValueBox'; export type DocLike = Doc | Doc[] | Promise | Promise; export interface MetadataEntryProps { diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index 166afc0c2..a69a5f5e8 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -24,7 +24,7 @@ export class PreviewCursor extends ObservableReactComponent<{}> { _addLiveTextDoc?: (doc: Doc) => void; _nudge?: undefined | ((x: number, y: number) => boolean); _slowLoadDocuments?: (files: File[] | string, options: DocumentOptions, generatedDocuments: Doc[], text: string, completed: ((doc: Doc[]) => void) | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => Promise; - @observable _clickPoint: number[]; + @observable _clickPoint: number[] = []; @observable public Visible = false; public Doc: Opt; constructor(props: any) { diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx index 8540e81e1..f1dadcd5e 100644 --- a/src/client/views/PropertiesButtons.tsx +++ b/src/client/views/PropertiesButtons.tsx @@ -2,6 +2,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Dropdown, DropdownType, IListItemProps, Toggle, ToggleType, Type } from 'browndash-components'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { AiOutlineColumnWidth } from 'react-icons/ai'; import { BiHide, BiShow } from 'react-icons/bi'; import { BsGrid3X3GapFill } from 'react-icons/bs'; @@ -12,28 +13,20 @@ import { RxWidth } from 'react-icons/rx'; import { TbEditCircle, TbEditCircleOff, TbHandOff, TbHandStop, TbHighlight, TbHighlightOff } from 'react-icons/tb'; import { TfiBarChart } from 'react-icons/tfi'; import { Doc, DocListCast, Opt } from '../../fields/Doc'; -import { InkField } from '../../fields/InkField'; import { RichTextField } from '../../fields/RichTextField'; import { BoolCast, ScriptCast } from '../../fields/Types'; import { ImageField } from '../../fields/URLField'; -import { DocUtils } from '../documents/Documents'; import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; +import { DocUtils } from '../documents/Documents'; import { IsFollowLinkScript } from '../util/LinkFollower'; import { LinkManager } from '../util/LinkManager'; import { SelectionManager } from '../util/SelectionManager'; import { SettingsManager } from '../util/SettingsManager'; -import { undoable, undoBatch } from '../util/UndoManager'; -import { Colors } from './global/globalEnums'; +import { undoBatch, undoable } from '../util/UndoManager'; import { InkingStroke } from './InkingStroke'; -import { DocumentView, OpenWhere } from './nodes/DocumentView'; import './PropertiesButtons.scss'; -import * as React from 'react'; - -enum UtilityButtonState { - Default, - OpenRight, - OpenExternally, -} +import { Colors } from './global/globalEnums'; +import { DocumentView, OpenWhere } from './nodes/DocumentView'; @observer export class PropertiesButtons extends React.Component<{}, {}> { diff --git a/src/client/views/PropertiesDocBacklinksSelector.tsx b/src/client/views/PropertiesDocBacklinksSelector.tsx index 58d3b72e8..244cd4aa0 100644 --- a/src/client/views/PropertiesDocBacklinksSelector.tsx +++ b/src/client/views/PropertiesDocBacklinksSelector.tsx @@ -7,10 +7,10 @@ import { DocumentType } from '../documents/DocumentTypes'; import { LinkManager } from '../util/LinkManager'; import { SelectionManager } from '../util/SelectionManager'; import { SettingsManager } from '../util/SettingsManager'; +import './PropertiesDocBacklinksSelector.scss'; import { CollectionDockingView } from './collections/CollectionDockingView'; import { LinkMenu } from './linking/LinkMenu'; -import { OpenWhere, OpenWhereMod } from './nodes/DocumentView'; -import './PropertiesDocBacklinksSelector.scss'; +import { OpenWhere } from './nodes/DocumentView'; type PropertiesDocBacklinksSelectorProps = { Document: Doc; diff --git a/src/client/views/PropertiesSection.tsx b/src/client/views/PropertiesSection.tsx index 2b9bfb505..3c9fa1123 100644 --- a/src/client/views/PropertiesSection.tsx +++ b/src/client/views/PropertiesSection.tsx @@ -1,11 +1,9 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; -import './PropertiesSection.scss'; -import { Doc } from '../../fields/Doc'; -import { StrCast } from '../../fields/Types'; +import * as React from 'react'; import { SettingsManager } from '../util/SettingsManager'; +import './PropertiesSection.scss'; export interface PropertiesSectionProps { title: string; diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 48653f30a..791928b4a 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -1,5 +1,6 @@ import { action, computed, observable, ObservableSet, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, DocListCast } from '../../fields/Doc'; import { ScriptField } from '../../fields/ScriptField'; import { Cast, StrCast } from '../../fields/Types'; @@ -13,7 +14,6 @@ import { CollectionTreeView } from './collections/CollectionTreeView'; import { DocumentView } from './nodes/DocumentView'; import { DefaultStyleProvider } from './StyleProvider'; import './TemplateMenu.scss'; -import * as React from 'react'; @observer class TemplateToggle extends React.Component<{ template: string; checked: boolean; toggle: (event: React.ChangeEvent, template: string) => void }> { diff --git a/src/client/views/UndoStack.tsx b/src/client/views/UndoStack.tsx index f07e38af1..ea038250e 100644 --- a/src/client/views/UndoStack.tsx +++ b/src/client/views/UndoStack.tsx @@ -15,8 +15,8 @@ interface UndoStackProps { } @observer export class UndoStack extends React.Component { - @observable static HideInline: boolean; - @observable static Expand: boolean; + @observable static HideInline: boolean = false; + @observable static Expand: boolean = false; render() { const background = UndoManager.batchCounter.get() ? 'yellow' : SettingsManager.userVariantColor; const color = UndoManager.batchCounter.get() ? 'black' : SettingsManager.userColor; @@ -39,19 +39,25 @@ export class UndoStack extends React.Component { color, }}> {Array.from(UndoManager.undoStackNames).map((name, i) => ( -
{ +
{ const size = UndoManager.undoStackNames.length; - for (let n = 0; n < size-i; n++ ) UndoManager.Undo(); } } - > + for (let n = 0; n < size - i; n++) UndoManager.Undo(); + }}>
{StrCast(name).replace(/[^\.]*\./, '')}
))} {Array.from(UndoManager.redoStackNames) .reverse() .map((name, i) => ( -
- { for (let n = 0; n <= i; n++ ) UndoManager.Redo() }}> +
{ + for (let n = 0; n <= i; n++) UndoManager.Redo(); + }}>
{StrCast(name).replace(/[^\.]*\./, '')}
diff --git a/src/client/views/animationtimeline/Region.tsx b/src/client/views/animationtimeline/Region.tsx index 15cbbc16f..99163f6c6 100644 --- a/src/client/views/animationtimeline/Region.tsx +++ b/src/client/views/animationtimeline/Region.tsx @@ -6,11 +6,11 @@ import { List } from '../../../fields/List'; import { createSchema, defaultSpec, listSpec, makeInterface } from '../../../fields/Schema'; import { Cast, NumCast } from '../../../fields/Types'; import { Transform } from '../../util/Transform'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import '../global/globalCssVariables.module.scss'; import './Region.scss'; import './Timeline.scss'; import { TimelineMenu } from './TimelineMenu'; -import { ObservableReactComponent } from '../ObservableReactComponent'; /** * Useful static functions that you can use. Mostly for logic, but you can also add UI logic here also diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index f27a2d2fd..cc4da1694 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -4,17 +4,17 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { Utils, emptyFunction, setupMoveUpEvents } from '../../../Utils'; import { Doc, DocListCast } from '../../../fields/Doc'; import { BoolCast, NumCast, StrCast } from '../../../fields/Types'; -import { emptyFunction, setupMoveUpEvents, Utils } from '../../../Utils'; import { DocumentType } from '../../documents/DocumentTypes'; import clamp from '../../util/clamp'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { FieldViewProps } from '../nodes/FieldView'; import { RegionHelpers } from './Region'; import './Timeline.scss'; import { TimelineOverview } from './TimelineOverview'; import { Track } from './Track'; -import { ObservableReactComponent } from '../ObservableReactComponent'; /** * Timeline class controls most of timeline functions besides individual region and track mechanism. Main functions are diff --git a/src/client/views/animationtimeline/TimelineOverview.tsx b/src/client/views/animationtimeline/TimelineOverview.tsx index 82ac69a3b..928739b53 100644 --- a/src/client/views/animationtimeline/TimelineOverview.tsx +++ b/src/client/views/animationtimeline/TimelineOverview.tsx @@ -28,7 +28,7 @@ export class TimelineOverview extends React.Component { @observable private overviewBarWidth: number = 0; @observable private playbarWidth: number = 0; @observable private activeOverviewWidth: number = 0; - @observable private _authoringReaction?: IReactionDisposer; + @observable private _authoringReaction?: IReactionDisposer = undefined; @observable private visibleTime: number = 0; @observable private currentX: number = 0; @observable private visibleStart: number = 0; diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 00aa51cac..490a14be5 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -8,10 +8,10 @@ import { ObjectField } from '../../../fields/ObjectField'; import { listSpec } from '../../../fields/Schema'; import { Cast, NumCast } from '../../../fields/Types'; import { Transform } from '../../util/Transform'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { Region, RegionData, RegionHelpers } from './Region'; import { Timeline } from './Timeline'; import './Track.scss'; -import { ObservableReactComponent } from '../ObservableReactComponent'; interface IProps { timeline: Timeline; @@ -29,9 +29,9 @@ interface IProps { @observer export class Track extends ObservableReactComponent { @observable private _inner = React.createRef(); - @observable private _currentBarXReaction: any; - @observable private _timelineVisibleReaction: any; - @observable private _autoKfReaction: any; + @observable private _currentBarXReaction: any = undefined; + @observable private _timelineVisibleReaction: any = undefined; + @observable private _autoKfReaction: any = undefined; @observable private _newKeyframe: boolean = false; private readonly MAX_TITLE_HEIGHT = 75; @observable private _trackHeight = 0; diff --git a/src/client/views/collections/CollectionCalendarView.tsx b/src/client/views/collections/CollectionCalendarView.tsx index 2cec29669..4c0a917f5 100644 --- a/src/client/views/collections/CollectionCalendarView.tsx +++ b/src/client/views/collections/CollectionCalendarView.tsx @@ -1,18 +1,11 @@ -import * as React from 'react'; -import { CollectionSubView } from './CollectionSubView'; +import { computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; -import { computed, makeObservable, observable } from 'mobx'; -import { Doc, DocListCast, Opt } from '../../../fields/Doc'; +import * as React from 'react'; +import { dateRangeStrToDates, emptyFunction, returnTrue } from '../../../Utils'; +import { Doc, DocListCast } from '../../../fields/Doc'; +import { StrCast } from '../../../fields/Types'; import { CollectionStackingView } from './CollectionStackingView'; -import { CollectionViewType } from '../../documents/DocumentTypes'; -import { dateRangeStrToDates, emptyFunction, returnAll, returnEmptyDoclist, returnNone, returnOne, returnTrue } from '../../../Utils'; -import { DocumentView, DocumentViewProps } from '../nodes/DocumentView'; -import { TbRuler } from 'react-icons/tb'; -import { Transform } from '../../util/Transform'; -import { DocData } from '../../../fields/DocSymbols'; -import { Cast, NumCast, StrCast } from '../../../fields/Types'; -import { StyleProp } from '../StyleProvider'; -import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView'; +import { CollectionSubView } from './CollectionSubView'; @observer export class CollectionCalendarView extends CollectionSubView() { diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 75c178136..868df7a3b 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -1,4 +1,4 @@ -import { action, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; +import { action, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; @@ -30,7 +30,7 @@ import { ScriptingRepl } from '../ScriptingRepl'; import { UndoStack } from '../UndoStack'; import './CollectionDockingView.scss'; import { CollectionFreeFormView } from './collectionFreeForm'; -import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; +import { CollectionSubView } from './CollectionSubView'; import { TabDocView } from './TabDocView'; const _global = (window /* browser */ || global) /* node */ as any; diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 443aa3f17..2a6cb081f 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -32,16 +32,13 @@ interface CollectionMenuProps { @observer export class CollectionMenu extends AntimodeMenu { @observable static Instance: CollectionMenu; - @observable SelectedCollection: DocumentView | undefined = undefined; - @observable FieldKey: string; private _docBtnRef = React.createRef(); constructor(props: any) { super(props); makeObservable(this); - this.FieldKey = ''; CollectionMenu.Instance = this; this._canFade = false; // don't let the inking menu fade away this.Pinned = Cast(Doc.UserDoc()['menuCollections-pinned'], 'boolean', true); diff --git a/src/client/views/collections/CollectionNoteTakingViewDivider.tsx b/src/client/views/collections/CollectionNoteTakingViewDivider.tsx index af822d917..2aad48d4a 100644 --- a/src/client/views/collections/CollectionNoteTakingViewDivider.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewDivider.tsx @@ -1,4 +1,4 @@ -import { action, observable, trace } from 'mobx'; +import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { emptyFunction, setupMoveUpEvents } from '../../../Utils'; diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index 170b1f1ec..e5068645f 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -1,5 +1,6 @@ import { action, computed, IReactionDisposer, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, DocListCast } from '../../../fields/Doc'; import { ScriptField } from '../../../fields/ScriptField'; import { NumCast, StrCast } from '../../../fields/Types'; @@ -12,7 +13,6 @@ import { computePassLayout, computeStarburstLayout } from './collectionFreeForm' import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import './CollectionPileView.scss'; import { CollectionSubView } from './CollectionSubView'; -import * as React from 'react'; @observer export class CollectionPileView extends CollectionSubView() { diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index fb8bc4da2..fa3844aa4 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -20,7 +20,7 @@ import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { undoBatch, UndoManager } from '../../util/UndoManager'; -import { CollectionSubView, SubCollectionViewProps } from '../collections/CollectionSubView'; +import { CollectionSubView } from '../collections/CollectionSubView'; import { LightboxView } from '../LightboxView'; import { AudioWaveform } from '../nodes/audio/AudioWaveform'; import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere } from '../nodes/DocumentView'; @@ -56,7 +56,7 @@ export enum TrimScope { @observer export class CollectionStackedTimeline extends CollectionSubView() { @observable static SelectingRegion: CollectionStackedTimeline | undefined = undefined; - @observable public static CurrentlyPlaying: DocumentView[]; + @observable public static CurrentlyPlaying: DocumentView[] = []; constructor(props: any) { super(props); makeObservable(this); diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index f9d575da2..69f1c332d 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -20,8 +20,8 @@ import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from '../EditableView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; -import './CollectionStackingView.scss'; import { ObservableReactComponent } from '../ObservableReactComponent'; +import './CollectionStackingView.scss'; // So this is how we are storing a column interface CSVFieldColumnProps { diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 2ff435ce2..570330174 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -4,11 +4,11 @@ import * as rp from 'request-promise'; import { Utils, returnFalse } from '../../../Utils'; import CursorField from '../../../fields/CursorField'; import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc'; -import { AclPrivate, DocData } from '../../../fields/DocSymbols'; +import { AclPrivate } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; -import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; +import { BoolCast, Cast, ScriptCast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; import { GetEffectiveAcl, TraceMobx } from '../../../fields/util'; import { GestureUtils } from '../../../pen-gestures/GestureUtils'; @@ -41,8 +41,8 @@ export function CollectionSubView(moreProps?: X) { makeObservable(this); } - @observable _focusFilters: Opt; // childFilters that are overridden when previewing a link to an anchor which has childFilters set on it - @observable _focusRangeFilters: Opt; // childFiltersByRanges that are overridden when previewing a link to an anchor which has childFiltersByRanges set on it + @observable _focusFilters: Opt = undefined; // childFilters that are overridden when previewing a link to an anchor which has childFilters set on it + @observable _focusRangeFilters: Opt = undefined; // childFiltersByRanges that are overridden when previewing a link to an anchor which has childFiltersByRanges set on it protected createDashEventsTarget = (ele: HTMLDivElement | null) => { this.dropDisposer?.(); this.gestureDisposer?.(); diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 6033b897d..7bbdb7073 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -1,6 +1,8 @@ import { toUpper } from 'lodash'; import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { emptyFunction, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from '../../../Utils'; import { Doc, Opt, StrListCast } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; @@ -8,7 +10,6 @@ import { RichTextField } from '../../../fields/RichTextField'; import { listSpec } from '../../../fields/Schema'; import { ComputedField, ScriptField } from '../../../fields/ScriptField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; -import { emptyFunction, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; @@ -17,20 +18,19 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { EditableView } from '../EditableView'; import { DocFocusOptions, DocumentView } from '../nodes/DocumentView'; import { PresBox } from '../nodes/trails'; -import { computePivotLayout, computeTimelineLayout, ViewDefBounds } from './collectionFreeForm/CollectionFreeFormLayoutEngines'; -import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import { CollectionSubView } from './CollectionSubView'; import './CollectionTimeView.scss'; -import * as React from 'react'; +import { ViewDefBounds, computePivotLayout, computeTimelineLayout } from './collectionFreeForm/CollectionFreeFormLayoutEngines'; +import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; @observer export class CollectionTimeView extends CollectionSubView() { _changing = false; @observable _layoutEngine = computePivotLayout.name; @observable _collapsed: boolean = false; - @observable _childClickedScript: Opt; - @observable _viewDefDivClick: Opt; - @observable _focusPivotField: Opt; + @observable _childClickedScript: Opt = undefined; + @observable _viewDefDivClick: Opt = undefined; + @observable _focusPivotField: Opt = undefined; constructor(props: any) { super(props); diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 0656843cb..c2f5ab2c0 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -16,6 +16,7 @@ import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { OpenWhere } from '../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; +import { CollectionCalendarView } from './CollectionCalendarView'; import { CollectionCarousel3DView } from './CollectionCarousel3DView'; import { CollectionCarouselView } from './CollectionCarouselView'; import { CollectionDockingView } from './CollectionDockingView'; @@ -28,7 +29,6 @@ import { CollectionTreeView } from './CollectionTreeView'; import './CollectionView.scss'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; import { CollectionGridView } from './collectionGrid/CollectionGridView'; -import { CollectionCalendarView } from './CollectionCalendarView'; import { CollectionLinearView } from './collectionLinear'; import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView'; import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView'; diff --git a/src/client/views/collections/KeyRestrictionRow.tsx b/src/client/views/collections/KeyRestrictionRow.tsx index f3071b316..4523a4f1e 100644 --- a/src/client/views/collections/KeyRestrictionRow.tsx +++ b/src/client/views/collections/KeyRestrictionRow.tsx @@ -1,6 +1,6 @@ -import * as React from "react"; -import { observable, runInAction } from "mobx"; -import { observer } from "mobx-react"; +import { observable, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; interface IKeyRestrictionProps { contains: boolean; @@ -19,37 +19,28 @@ export default class KeyRestrictionRow extends React.Component - runInAction(() => this._key = e.target.value)} - placeholder="KEY" /> - - runInAction(() => this._value = e.target.value)} - placeholder="VALUE" /> + runInAction(() => (this._value = e.target.value))} placeholder="VALUE" />
); } -} \ No newline at end of file +} diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index a7705ea7e..72882ac17 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -93,7 +93,7 @@ export class TreeView extends ObservableReactComponent { static _openLevelScript: Opt; private _header: React.RefObject = React.createRef(); private _tref = React.createRef(); - @observable _docRef: Opt; + @observable _docRef: Opt = undefined; private _disposers: { [name: string]: IReactionDisposer } = {}; private _editTitleScript: (() => ScriptField) | undefined; private _openScript: (() => ScriptField) | undefined; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx index 99ee5ef4e..08dfb32ad 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormBackgroundGrid.tsx @@ -1,8 +1,8 @@ import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { NumCast } from '../../../../fields/Types'; import './CollectionFreeFormView.scss'; -import * as React from 'react'; export interface CollectionFreeFormViewBackgroundGridProps { panX: () => number; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx index 2606304d0..58f6b1593 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoState.tsx @@ -1,5 +1,5 @@ import { IconButton, Size, Type } from 'browndash-components'; -import { action, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { SettingsManager } from '../../../util/SettingsManager'; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx index 15e4d8360..8628ca3c3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormInfoUI.tsx @@ -1,16 +1,16 @@ -import { IReactionDisposer, makeObservable, observable, runInAction } from 'mobx'; +import { makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast, Field, FieldResult } from '../../../../fields/Doc'; import { InkTool } from '../../../../fields/InkField'; +import { StrCast } from '../../../../fields/Types'; import { DocumentManager } from '../../../util/DocumentManager'; import { LinkManager } from '../../../util/LinkManager'; -import { DocButtonState, DocumentLinksButton } from '../../nodes/DocumentLinksButton'; import { ObservableReactComponent } from '../../ObservableReactComponent'; -import { CollectionFreeFormInfoState, InfoState, infoState, StateEntryFunc } from './CollectionFreeFormInfoState'; +import { DocButtonState, DocumentLinksButton } from '../../nodes/DocumentLinksButton'; +import { CollectionFreeFormInfoState, InfoState, StateEntryFunc, infoState } from './CollectionFreeFormInfoState'; import { CollectionFreeFormView } from './CollectionFreeFormView'; import './CollectionFreeFormView.scss'; -import { StrCast } from '../../../../fields/Types'; export interface CollectionFreeFormInfoUIProps { Document: Doc; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 779a0bf96..95d521f65 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -1,11 +1,11 @@ import { computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Id } from '../../../../fields/FieldSymbols'; import { DocumentManager } from '../../../util/DocumentManager'; import { LightboxView } from '../../LightboxView'; -import './CollectionFreeFormLinksView.scss'; import { CollectionFreeFormLinkView } from './CollectionFreeFormLinkView'; -import * as React from 'react'; +import './CollectionFreeFormLinksView.scss'; @observer export class CollectionFreeFormLinksView extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx index f54726a00..ec8416303 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormPannableContents.tsx @@ -1,12 +1,11 @@ import { computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { ScriptField } from '../../../../fields/ScriptField'; import { PresBox } from '../../nodes/trails/PresBox'; -import './CollectionFreeFormView.scss'; -import * as React from 'react'; import { CollectionFreeFormView } from './CollectionFreeFormView'; - +import './CollectionFreeFormView.scss'; export interface CollectionFreeFormPannableContentsProps { Document: Doc; viewDefDivClick?: ScriptField; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 45e24bbb2..fa8218bdd 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -1,6 +1,8 @@ import { computed } from 'mobx'; import { observer } from 'mobx-react'; import * as mobxUtils from 'mobx-utils'; +import * as React from 'react'; +import * as uuid from 'uuid'; import CursorField from '../../../../fields/CursorField'; import { Doc, FieldResult } from '../../../../fields/Doc'; import { Id } from '../../../../fields/FieldSymbols'; @@ -9,8 +11,6 @@ import { listSpec } from '../../../../fields/Schema'; import { Cast } from '../../../../fields/Types'; import { CollectionViewProps } from '../CollectionView'; import './CollectionFreeFormView.scss'; -import * as React from 'react'; -import * as uuid from 'uuid'; @observer export class CollectionFreeFormRemoteCursors extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 645e9cff7..cc0833698 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -37,6 +37,7 @@ import { CtrlKey } from '../../GlobalKeyHandler'; import { ActiveInkWidth, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke'; import { LightboxView } from '../../LightboxView'; import { CollectionFreeFormDocumentView, CollectionFreeFormDocumentViewWrapper } from '../../nodes/CollectionFreeFormDocumentView'; +import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp'; import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; @@ -52,7 +53,6 @@ import { CollectionFreeFormPannableContents } from './CollectionFreeFormPannable import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCursors'; import './CollectionFreeFormView.scss'; import { MarqueeView } from './MarqueeView'; -import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp'; export type collectionFreeformViewProps = { NativeWidth?: () => number; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index b22fdfa19..39d828302 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -16,19 +16,18 @@ import { DocumentType } from '../../../documents/DocumentTypes'; import { DocUtils, Docs, DocumentOptions } from '../../../documents/Documents'; import { SelectionManager } from '../../../util/SelectionManager'; import { freeformScrollMode } from '../../../util/SettingsManager'; +import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { UndoManager, undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { PreviewCursor } from '../../PreviewCursor'; -import { DocumentView, OpenWhere } from '../../nodes/DocumentView'; +import { OpenWhere } from '../../nodes/DocumentView'; import { pasteImageBitmap } from '../../nodes/WebBoxRenderer'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { SubCollectionViewProps } from '../CollectionSubView'; import { MarqueeOptionsMenu } from './MarqueeOptionsMenu'; import './MarqueeView.scss'; -import { SnappingManager } from '../../../util/SnappingManager'; - interface MarqueeViewProps { getContainerTransform: () => Transform; getTransform: () => Transform; diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 1e19964d7..3e75257e5 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -7,7 +7,6 @@ import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types import { emptyFunction, returnFalse, returnZero, setupMoveUpEvents } from '../../../../Utils'; import { Docs } from '../../../documents/Documents'; import { DragManager } from '../../../util/DragManager'; -import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; @@ -17,13 +16,12 @@ import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { CollectionSubView } from '../CollectionSubView'; import './CollectionGridView.scss'; import Grid, { Layout } from './Grid'; - @observer export class CollectionGridView extends CollectionSubView() { private _containerRef: React.RefObject = React.createRef(); private _changeListenerDisposer: Opt; // listens for changes in this.childLayoutPairs private _resetListenerDisposer: Opt; // listens for when the reset button is clicked - @observable private _rowHeight: Opt; // temporary store of row height to make change undoable + @observable private _rowHeight: Opt = undefined; // temporary store of row height to make change undoable @observable private _scroll: number = 0; // required to make sure the decorations box container updates on scroll private dropLocation: object = {}; // sets the drop location for external drops diff --git a/src/client/views/collections/collectionGrid/Grid.tsx b/src/client/views/collections/collectionGrid/Grid.tsx index 3d1d87aa0..9145d7ef1 100644 --- a/src/client/views/collections/collectionGrid/Grid.tsx +++ b/src/client/views/collections/collectionGrid/Grid.tsx @@ -1,5 +1,5 @@ -import * as React from 'react'; import { observer } from 'mobx-react'; +import * as React from 'react'; import '../../../../../node_modules/react-grid-layout/css/styles.css'; import '../../../../../node_modules/react-resizable/css/styles.css'; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index e12bcd8b0..5bea59e7b 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -4,13 +4,13 @@ import { Button } from 'browndash-components'; import { action, computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { returnFalse } from '../../../../Utils'; import { Doc, DocListCast } from '../../../../fields/Doc'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; -import { returnFalse } from '../../../../Utils'; import { DragManager, dropActionType } from '../../../util/DragManager'; import { SettingsManager } from '../../../util/SettingsManager'; import { Transform } from '../../../util/Transform'; -import { undoable, undoBatch } from '../../../util/UndoManager'; +import { undoBatch, undoable } from '../../../util/UndoManager'; import { DocumentView } from '../../nodes/DocumentView'; import { CollectionSubView } from '../CollectionSubView'; import './CollectionMulticolumnView.scss'; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 7dbc18e60..3043eb0f8 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -1,9 +1,9 @@ import { action, computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { returnFalse } from '../../../../Utils'; import { Doc, DocListCast } from '../../../../fields/Doc'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; -import { returnFalse } from '../../../../Utils'; import { DragManager, dropActionType } from '../../../util/DragManager'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; @@ -12,7 +12,6 @@ import { CollectionSubView } from '../CollectionSubView'; import './CollectionMultirowView.scss'; import HeightLabel from './MultirowHeightLabel'; import ResizeBar from './MultirowResizer'; - interface HeightSpecifier { magnitude: number; unit: string; diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx index 868b1140d..ea99bff2e 100644 --- a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx @@ -1,12 +1,12 @@ -import * as React from 'react'; +import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; -import { observable, action } from 'mobx'; +import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; -import { DimUnit } from './CollectionMulticolumnView'; import { UndoManager } from '../../../util/UndoManager'; -import { StyleProviderFunc } from '../../nodes/DocumentView'; import { StyleProp } from '../../StyleProvider'; +import { StyleProviderFunc } from '../../nodes/DocumentView'; +import { DimUnit } from './CollectionMulticolumnView'; interface ResizerProps { width: number; diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx index 9985a9fba..a9579d931 100644 --- a/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx @@ -1,27 +1,25 @@ -import * as React from "react"; -import { observer } from "mobx-react"; -import { computed } from "mobx"; -import { Doc } from "../../../../fields/Doc"; -import { NumCast, StrCast, BoolCast } from "../../../../fields/Types"; -import { EditableView } from "../../EditableView"; -import { DimUnit } from "./CollectionMulticolumnView"; +import { computed } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { Doc } from '../../../../fields/Doc'; +import { BoolCast, NumCast, StrCast } from '../../../../fields/Types'; +import { EditableView } from '../../EditableView'; +import { DimUnit } from './CollectionMulticolumnView'; interface WidthLabelProps { layout: Doc; collectionDoc: Doc; - decimals?: number; } @observer export default class WidthLabel extends React.Component { - @computed private get contents() { - const { layout, decimals } = this.props; + const { layout } = this.props; const getUnit = () => StrCast(layout.dimUnit); - const getMagnitude = () => String(+NumCast(layout.dimMagnitude).toFixed(decimals ?? 3)); + const getMagnitude = () => String(+NumCast(layout.dimMagnitude).toFixed(3)); return ( -
+
{ @@ -50,7 +48,6 @@ export default class WidthLabel extends React.Component { } render() { - return BoolCast(this.props.collectionDoc.showWidthLabels) ? this.contents : (null); + return BoolCast(this.props.collectionDoc.showWidthLabels) ? this.contents : null; } - -} \ No newline at end of file +} diff --git a/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx b/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx index aa5439fa4..878c7ff3c 100644 --- a/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx +++ b/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx @@ -1,10 +1,10 @@ -import * as React from "react"; -import { observer } from "mobx-react"; -import { computed } from "mobx"; -import { Doc } from "../../../../fields/Doc"; -import { NumCast, StrCast, BoolCast } from "../../../../fields/Types"; -import { EditableView } from "../../EditableView"; -import { DimUnit } from "./CollectionMultirowView"; +import { computed } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { Doc } from '../../../../fields/Doc'; +import { BoolCast, NumCast, StrCast } from '../../../../fields/Types'; +import { EditableView } from '../../EditableView'; +import { DimUnit } from './CollectionMultirowView'; interface HeightLabelProps { layout: Doc; @@ -14,14 +14,13 @@ interface HeightLabelProps { @observer export default class HeightLabel extends React.Component { - @computed private get contents() { const { layout, decimals } = this.props; const getUnit = () => StrCast(layout.dimUnit); const getMagnitude = () => String(+NumCast(layout.dimMagnitude).toFixed(decimals ?? 3)); return ( -
+
{ @@ -50,7 +49,6 @@ export default class HeightLabel extends React.Component { } render() { - return BoolCast(this.props.collectionDoc.showHeightLabels) ? this.contents : (null); + return BoolCast(this.props.collectionDoc.showHeightLabels) ? this.contents : null; } - -} \ No newline at end of file +} diff --git a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx index 5a9d6a82c..7dee65e58 100644 --- a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx @@ -1,12 +1,12 @@ -import * as React from 'react'; +import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; -import { observable, action } from 'mobx'; +import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; -import { DimUnit } from './CollectionMultirowView'; import { UndoManager } from '../../../util/UndoManager'; import { StyleProp } from '../../StyleProvider'; import { StyleProviderFunc } from '../../nodes/DocumentView'; +import { DimUnit } from './CollectionMultirowView'; interface ResizerProps { height: number; diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx index 04443b4a7..5f8b412be 100644 --- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx +++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx @@ -1,7 +1,7 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, observable } from 'mobx'; +import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import { Colors } from '../../global/globalEnums'; import './CollectionSchemaView.scss'; diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index 06073b52c..85e97f95f 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -1,3 +1,4 @@ +import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { action, computed, makeObservable, observable } from 'mobx'; @@ -7,18 +8,17 @@ import { emptyFunction, returnFalse, setupMoveUpEvents } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { Cast, DocCast, StrCast } from '../../../fields/Types'; import { WebField } from '../../../fields/URLField'; +import { DocumentType } from '../../documents/DocumentTypes'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; import { LinkManager } from '../../util/LinkManager'; import { SelectionManager } from '../../util/SelectionManager'; import { SettingsManager } from '../../util/SettingsManager'; +import { undoBatch } from '../../util/UndoManager'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { DocumentView, DocumentViewInternal, OpenWhere } from '../nodes/DocumentView'; import { LinkInfo } from '../nodes/LinkDocPreview'; import './LinkMenuItem.scss'; -import { undoBatch } from '../../util/UndoManager'; -import { IconProp } from '@fortawesome/fontawesome-svg-core'; -import { DocumentType } from '../../documents/DocumentTypes'; interface LinkMenuItemProps { groupType: string; diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx index 5460a6daf..7e344dd7a 100644 --- a/src/client/views/linking/LinkPopup.tsx +++ b/src/client/views/linking/LinkPopup.tsx @@ -1,16 +1,16 @@ import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import { EditorView } from 'prosemirror-view'; -import { Doc } from '../../../fields/Doc'; +import * as React from 'react'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../Utils'; +import { Doc } from '../../../fields/Doc'; import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; +import { DefaultStyleProvider } from '../StyleProvider'; import { OpenWhere } from '../nodes/DocumentView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { SearchBox } from '../search/SearchBox'; -import { DefaultStyleProvider } from '../StyleProvider'; import './LinkPopup.scss'; -import * as React from 'react'; interface LinkPopupProps { linkFrom?: () => Doc | undefined; @@ -29,7 +29,7 @@ interface LinkPopupProps { @observer export class LinkPopup extends React.Component { @observable private linkURL: string = ''; - @observable public view?: EditorView; + @observable public view?: EditorView = undefined; // TODO: should check for valid URL @undoBatch diff --git a/src/client/views/linking/LinkRelationshipSearch.tsx b/src/client/views/linking/LinkRelationshipSearch.tsx index 3e7f5be74..0902d53b2 100644 --- a/src/client/views/linking/LinkRelationshipSearch.tsx +++ b/src/client/views/linking/LinkRelationshipSearch.tsx @@ -1,6 +1,6 @@ import { observer } from 'mobx-react'; -import './LinkEditor.scss'; import * as React from 'react'; +import './LinkEditor.scss'; interface link_relationshipSearchProps { results: string[] | undefined; diff --git a/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx b/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx index 72b63cf8f..bce2b296f 100644 --- a/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx +++ b/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx @@ -3,12 +3,12 @@ import * as React from 'react'; import { Doc } from '../../../../fields/Doc'; import { InkTool } from '../../../../fields/InkField'; import { SelectionManager } from '../../../util/SelectionManager'; +import { SnappingManager } from '../../../util/SnappingManager'; import { CollectionDockingView } from '../../collections/CollectionDockingView'; -import { DocumentView, OpenWhereMod } from '../../nodes/DocumentView'; +import { OpenWhereMod } from '../../nodes/DocumentView'; import { NewLightboxView } from '../NewLightboxView'; import './ButtonMenu.scss'; import { IButtonMenu } from './utils'; -import { SnappingManager } from '../../../util/SnappingManager'; export const ButtonMenu = (props: IButtonMenu) => { return ( diff --git a/src/client/views/newlightbox/NewLightboxView.tsx b/src/client/views/newlightbox/NewLightboxView.tsx index 6980e31c1..3d159c3e3 100644 --- a/src/client/views/newlightbox/NewLightboxView.tsx +++ b/src/client/views/newlightbox/NewLightboxView.tsx @@ -2,28 +2,28 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnTrue } from '../../../Utils'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../../Utils'; import { DocUtils } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { LinkManager } from '../../util/LinkManager'; import { SelectionManager } from '../../util/SelectionManager'; +import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; -import { CollectionStackedTimeline } from '../collections/CollectionStackedTimeline'; -import { TabDocView } from '../collections/TabDocView'; import { GestureOverlay } from '../GestureOverlay'; import { LightboxView } from '../LightboxView'; -import { DocumentView, OpenWhere } from '../nodes/DocumentView'; import { DefaultStyleProvider } from '../StyleProvider'; -import { IRecommendation } from './components'; +import { CollectionStackedTimeline } from '../collections/CollectionStackedTimeline'; +import { TabDocView } from '../collections/TabDocView'; +import { DocumentView, OpenWhere } from '../nodes/DocumentView'; import { ExploreView } from './ExploreView'; -import { emptyBounds, IBounds } from './ExploreView/utils'; +import { IBounds, emptyBounds } from './ExploreView/utils'; import { NewLightboxHeader } from './Header'; import './NewLightboxView.scss'; import { RecommendationList } from './RecommendationList'; -import { SnappingManager } from '../../util/SnappingManager'; +import { IRecommendation } from './components'; enum LightboxStatus { RECOMMENDATIONS = 'recommendations', @@ -50,15 +50,15 @@ export class NewLightboxView extends React.Component { return this._doc; } private static LightboxDocTemplate = () => NewLightboxView._layoutTemplate; - @observable private static _layoutTemplate: Opt; - @observable private static _layoutTemplateString: Opt; - @observable private static _doc: Opt; - @observable private static _docTarget: Opt; + @observable private static _layoutTemplate: Opt = undefined; + @observable private static _layoutTemplateString: Opt = undefined; + @observable private static _doc: Opt = undefined; + @observable private static _docTarget: Opt = undefined; @observable private static _docFilters: string[] = []; // filters - private static _savedState: Opt; + private static _savedState: Opt = undefined; private static _history: Opt<{ doc: Doc; target?: Doc }[]> = []; @observable private static _future: Opt = []; - @observable private static _docView: Opt; + @observable private static _docView: Opt = undefined; // keywords @observable private static _keywords: string[] = []; diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 4c36d2fcb..12e8e1a69 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -44,8 +44,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { private _annotationLayer: React.RefObject = React.createRef(); anchorMenuClick?: () => undefined | ((anchor: Doc) => void); crop: ((region: Doc | undefined, addCrop?: boolean) => Doc | undefined) | undefined; - @observable schemaDataVizChildren: any; - @observable _marqueeing: number[] | undefined; + @observable schemaDataVizChildren: any = undefined; + @observable _marqueeing: number[] | undefined = undefined; @observable _savedAnnotations = new ObservableMap(); @computed get annotationLayer() { TraceMobx(); diff --git a/src/client/views/nodes/DataVizBox/SchemaCSVPopUp.tsx b/src/client/views/nodes/DataVizBox/SchemaCSVPopUp.tsx index 3cb5125da..24023077f 100644 --- a/src/client/views/nodes/DataVizBox/SchemaCSVPopUp.tsx +++ b/src/client/views/nodes/DataVizBox/SchemaCSVPopUp.tsx @@ -1,15 +1,14 @@ -import * as React from 'react'; -import './SchemaCSVPopUp.scss'; +import { IconButton } from 'browndash-components'; import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { CgClose } from 'react-icons/cg'; +import { Utils, emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import { Doc } from '../../../../fields/Doc'; -import { Button, IconButton, Type } from 'browndash-components'; import { StrCast } from '../../../../fields/Types'; -import { MarqueeView } from '../../collections/collectionFreeForm/MarqueeView'; -import { Utils, emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import { DragManager } from '../../../util/DragManager'; import { DocumentView } from '../DocumentView'; -import { CgClose } from 'react-icons/cg'; +import './SchemaCSVPopUp.scss'; interface SchemaCSVPopUpProps {} @@ -56,13 +55,11 @@ export class SchemaCSVPopUp extends React.Component {
{this.heading('Schema Table as Data Visualization Doc')}
-
-
this.drag(e)}> - -
+
+
this.drag(e)}> +
+
); @@ -88,9 +85,10 @@ export class SchemaCSVPopUp extends React.Component { return embedding; }; if (this.view && sourceAnchorCreator && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) { - DragManager.StartAnchorAnnoDrag(e.target instanceof HTMLElement ? [e.target] : [], - new DragManager.AnchorAnnoDragData(this.view, sourceAnchorCreator, targetCreator), downX, downY, { - dragComplete: e => {this.setVisible(false);}, + DragManager.StartAnchorAnnoDrag(e.target instanceof HTMLElement ? [e.target] : [], new DragManager.AnchorAnnoDragData(this.view, sourceAnchorCreator, targetCreator), downX, downY, { + dragComplete: e => { + this.setVisible(false); + }, }); return true; } @@ -108,4 +106,4 @@ export class SchemaCSVPopUp extends React.Component {
); } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx index 227c993c7..9e9a43b34 100644 --- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx +++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx @@ -1,7 +1,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ColorPicker, EditableText, IconButton, Size, Type } from 'browndash-components'; import * as d3 from 'd3'; -import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { FaFillDrip } from 'react-icons/fa'; @@ -11,10 +11,10 @@ import { listSpec } from '../../../../../fields/Schema'; import { Cast, DocCast, StrCast } from '../../../../../fields/Types'; import { Docs } from '../../../../documents/Documents'; import { undoable } from '../../../../util/UndoManager'; +import { ObservableReactComponent } from '../../../ObservableReactComponent'; import { PinProps, PresBox } from '../../trails'; import { scaleCreatorNumerical, yAxisCreator } from '../utils/D3Utils'; import './Chart.scss'; -import { ObservableReactComponent } from '../../../ObservableReactComponent'; export interface HistogramProps { Document: Doc; @@ -461,7 +461,7 @@ export class Histogram extends ObservableReactComponent { if (this._histogramData.length > 0 || !this.parentViz) { return this._props.axes.length >= 1 ? ( -
+
{ private _lineChartSvg: d3.Selection | undefined; @observable _currSelected: SelectedDataPoint | undefined = undefined; // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates - constructor(props:any) { + constructor(props: any) { super(props); makeObservable(this); } - @computed get _tableDataIds() { return !this.parentViz ? this._props.records.map((rec, i) => i) : NumListCast(this.parentViz.dataViz_selectedRows); } @@ -359,7 +358,7 @@ export class LineChart extends ObservableReactComponent { const selectedPt = this._currSelected ? `{ ${this._props.axes[0]}: ${this._currSelected.x} ${this._props.axes[1]}: ${this._currSelected.y} }` : 'none'; if (this._lineChartData.length > 0 || !this.parentViz || this.parentViz.length == 0) { return this._props.axes.length >= 2 && /\d/.test(this._props.records[0][this._props.axes[0]]) && /\d/.test(this._props.records[0][this._props.axes[1]]) ? ( -
+
{ />
- {selectedPt != 'none' ? -
+ {selectedPt != 'none' ? ( +
{`Selected: ${selectedPt}`} - -
- : null} + +
+ ) : null}
) : ( {'first use table view to select two numerical axes to plot'} diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx index e644870da..e67556cd0 100644 --- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx @@ -1,7 +1,7 @@ import { Checkbox } from '@mui/material'; import { ColorPicker, EditableText, Size, Type } from 'browndash-components'; import * as d3 from 'd3'; -import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { FaFillDrip } from 'react-icons/fa'; @@ -11,9 +11,9 @@ import { listSpec } from '../../../../../fields/Schema'; import { Cast, DocCast, StrCast } from '../../../../../fields/Types'; import { Docs } from '../../../../documents/Documents'; import { undoable } from '../../../../util/UndoManager'; +import { ObservableReactComponent } from '../../../ObservableReactComponent'; import { PinProps, PresBox } from '../../trails'; import './Chart.scss'; -import { ObservableReactComponent } from '../../../ObservableReactComponent'; export interface PieChartProps { Document: Doc; @@ -356,7 +356,7 @@ export class PieChart extends ObservableReactComponent { if (this._pieChartData.length > 0 || !this.parentViz) { return this._props.axes.length >= 1 ? ( -
+
{ return (this.viewScale * this._tableHeight) / this._tableDataIds.length; } @computed get startID() { - return this.rowHeight ? Math.max(Math.floor(this._scrollTop / this.rowHeight)-1, 0) : 0; + return this.rowHeight ? Math.max(Math.floor(this._scrollTop / this.rowHeight) - 1, 0) : 0; } @computed get endID() { console.log('start = ' + this.startID + ' container = ' + this._tableContainerHeight + ' scale = ' + this.viewScale + ' row = ' + this.rowHeight); @@ -169,7 +169,7 @@ export class TableBox extends ObservableReactComponent { return (
{ if (this._props.layoutDoc && e.key === 'a' && (e.ctrlKey || e.metaKey)) { @@ -226,7 +226,7 @@ export class TableBox extends ObservableReactComponent {
{this._tableDataIds - .filter((rowId, i) => this.startID-2 <= i && i <= this.endID+2) + .filter((rowId, i) => this.startID - 2 <= i && i <= this.endID + 2) ?.map(rowId => ( ; export interface JsxBindings { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index cc7fca8d2..f8f4b94a2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,10 +1,11 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { Dropdown, DropdownType, Type } from 'browndash-components'; +import { Howl } from 'howler'; import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { computedFn } from 'mobx-utils'; -import { Bounce, Fade, Flip, JackInTheBox, Roll, Rotate, Zoom } from 'react-awesome-reveal'; import * as React from 'react'; +import { Bounce, Fade, Flip, JackInTheBox, Roll, Rotate, Zoom } from 'react-awesome-reveal'; import { Utils, emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick } from '../../../Utils'; import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc'; import { AclPrivate, Animation, AudioPlay, DocViews } from '../../../fields/DocSymbols'; @@ -53,7 +54,6 @@ import { LinkAnchorBox } from './LinkAnchorBox'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; import { PresEffect, PresEffectDirection } from './trails'; import { PinProps, PresBox } from './trails/PresBox'; -import { Howl } from 'howler'; interface Window { MediaRecorder: MediaRecorder; @@ -138,7 +138,6 @@ export interface DocComponentView { dragStarting?: (snapToDraggedDoc: boolean, showGroupDragTarget: boolean, visited: Set) => void; incrementalRendering?: () => void; infoUI?: () => JSX.Element | null; - getCenter?: (xf: Transform) => { X: number; Y: number }; screenBounds?: () => Opt<{ left: number; top: number; right: number; bottom: number; center?: { X: number; Y: number } }>; ptToScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number }; ptFromScreen?: (pt: { X: number; Y: number }) => { X: number; Y: number }; @@ -1516,7 +1515,7 @@ export class DocumentView extends ObservableReactComponent { const docuBox = this.docView.ContentDiv.getElementsByClassName('linkAnchorBox-cont'); if (docuBox.length) return { ...docuBox[0].getBoundingClientRect(), center: undefined }; } - return { left, top, right, bottom, center: this.ComponentView?.getCenter?.(xf) }; + return { left, top, right, bottom }; }; public iconify(finished?: () => void, animateTime?: number) { diff --git a/src/client/views/nodes/FaceRectangle.tsx b/src/client/views/nodes/FaceRectangle.tsx index 8d03bf57a..46bc6eb03 100644 --- a/src/client/views/nodes/FaceRectangle.tsx +++ b/src/client/views/nodes/FaceRectangle.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; -import { observer } from 'mobx-react'; import { observable, runInAction } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; import { RectangleTemplate } from './FaceRectangles'; @observer diff --git a/src/client/views/nodes/FaceRectangles.tsx b/src/client/views/nodes/FaceRectangles.tsx index 26e720c0d..ade4225d9 100644 --- a/src/client/views/nodes/FaceRectangles.tsx +++ b/src/client/views/nodes/FaceRectangles.tsx @@ -1,8 +1,8 @@ +import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast } from '../../../fields/Doc'; -import { Cast, NumCast } from '../../../fields/Types'; -import { observer } from 'mobx-react'; import { Id } from '../../../fields/FieldSymbols'; +import { Cast, NumCast } from '../../../fields/Types'; import FaceRectangle from './FaceRectangle'; interface FaceRectanglesProps { diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index f4c5167a5..008f10f26 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; import { computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { DateField } from '../../../fields/DateField'; import { Doc, Field, FieldResult, Opt } from '../../../fields/Doc'; import { List } from '../../../fields/List'; diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index fd8d8ef56..7bc9d3f85 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -1,7 +1,6 @@ import { Tooltip } from '@mui/material'; import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; -import { ObservableGroupMap } from 'mobx-utils'; import * as React from 'react'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnZero } from '../../../Utils'; import { Doc, Field } from '../../../fields/Doc'; @@ -11,13 +10,13 @@ import { Transform } from '../../util/Transform'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { EditableView } from '../EditableView'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { DefaultStyleProvider } from '../StyleProvider'; import { OpenWhere } from './DocumentView'; import { FieldViewProps } from './FieldView'; import { KeyValueBox } from './KeyValueBox'; import './KeyValueBox.scss'; import './KeyValuePair.scss'; -import { ObservableReactComponent } from '../ObservableReactComponent'; // Represents one row in a key value plane @@ -35,12 +34,11 @@ export class KeyValuePair extends ObservableReactComponent { @observable private isPointerOver = false; @observable public isChecked = false; private checkbox = React.createRef(); - constructor(props:any) { + constructor(props: any) { super(props); makeObservable(this); } - @action handleCheck = (e: React.ChangeEvent) => { this.isChecked = e.currentTarget.checked; diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx index 32300d60a..8ad0b7dde 100644 --- a/src/client/views/nodes/LinkDescriptionPopup.tsx +++ b/src/client/views/nodes/LinkDescriptionPopup.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc } from '../../../fields/Doc'; import { LinkManager } from '../../util/LinkManager'; import './LinkDescriptionPopup.scss'; diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index d0a9f10b4..ea23ecbea 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -2,13 +2,14 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import wiki from 'wikijs'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils'; import { Doc, Opt } from '../../../fields/Doc'; import { Cast, DocCast, NumCast, PromiseValue, StrCast } from '../../../fields/Types'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils'; import { DocServer } from '../../DocServer'; -import { Docs } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; +import { Docs } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; @@ -16,10 +17,9 @@ import { LinkManager } from '../../util/LinkManager'; import { SearchUtil } from '../../util/SearchUtil'; import { SettingsManager } from '../../util/SettingsManager'; import { Transform } from '../../util/Transform'; +import { ObservableReactComponent } from '../ObservableReactComponent'; import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView'; import './LinkDocPreview.scss'; -import * as React from 'react'; -import { ObservableReactComponent } from '../ObservableReactComponent'; export class LinkInfo { private static _instance: Opt; diff --git a/src/client/views/nodes/LoadingBox.tsx b/src/client/views/nodes/LoadingBox.tsx index 27d73a585..adccc9db6 100644 --- a/src/client/views/nodes/LoadingBox.tsx +++ b/src/client/views/nodes/LoadingBox.tsx @@ -1,4 +1,4 @@ -import { action, observable, runInAction } from 'mobx'; +import { observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import ReactLoading from 'react-loading'; diff --git a/src/client/views/nodes/MapBox/AnimationUtility.ts b/src/client/views/nodes/MapBox/AnimationUtility.ts index 42dfa59b7..35153f439 100644 --- a/src/client/views/nodes/MapBox/AnimationUtility.ts +++ b/src/client/views/nodes/MapBox/AnimationUtility.ts @@ -1,13 +1,10 @@ -import mapboxgl from 'mapbox-gl'; -import { MercatorCoordinate } from 'mapbox-gl'; -import { MapRef } from 'react-map-gl'; -import * as React from 'react'; -import * as d3 from 'd3'; import * as turf from '@turf/turf'; import { Position } from '@turf/turf'; -import { Feature, FeatureCollection, GeoJsonProperties, Geometry } from 'geojson'; -import { observer } from 'mobx-react'; -import { action, computed, observable, runInAction, makeObservable } from 'mobx'; +import * as d3 from 'd3'; +import { Feature, GeoJsonProperties, Geometry } from 'geojson'; +import mapboxgl, { MercatorCoordinate } from 'mapbox-gl'; +import { action, computed, makeObservable, observable, runInAction } from 'mobx'; +import { MapRef } from 'react-map-gl'; export enum AnimationStatus { START = 'start', diff --git a/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx b/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx index f9607becf..7e99795b5 100644 --- a/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx +++ b/src/client/views/nodes/MapBox/DirectionsAnchorMenu.tsx @@ -1,15 +1,15 @@ -import * as React from 'react'; -import { observer } from 'mobx-react'; -import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; +import { IconLookup, faAdd, faCalendarDays, faRoute } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { IconButton } from 'browndash-components'; import { IReactionDisposer, ObservableMap, reaction } from 'mobx'; -import { Doc, Opt } from '../../../../fields/Doc'; +import { observer } from 'mobx-react'; +import * as React from 'react'; import { returnFalse, unimplementedFunction } from '../../../../Utils'; +import { Doc, Opt } from '../../../../fields/Doc'; import { NumCast, StrCast } from '../../../../fields/Types'; import { SelectionManager } from '../../../util/SelectionManager'; -import { IconButton } from 'browndash-components'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { SettingsManager } from '../../../util/SettingsManager'; -import { IconLookup, faAdd, faCalendarDays, faRoute } from '@fortawesome/free-solid-svg-icons'; +import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; @observer export class DirectionsAnchorMenu extends AntimodeMenu { diff --git a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx index 1b1b74e7c..08bea5d9d 100644 --- a/src/client/views/nodes/MapBox/MapAnchorMenu.tsx +++ b/src/client/views/nodes/MapBox/MapAnchorMenu.tsx @@ -1,26 +1,23 @@ +import { IconLookup, faAdd, faArrowDown, faArrowLeft, faArrowsRotate, faBicycle, faCalendarDays, faCar, faDiamondTurnRight, faEdit, faPersonWalking, faRoute } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import * as React from 'react'; +import { Autocomplete, Checkbox, FormControlLabel, TextField } from '@mui/material'; +import { IconButton } from 'browndash-components'; +import { Position } from 'geojson'; import { IReactionDisposer, ObservableMap, action, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; -import { Doc, NumListCast, Opt } from '../../../../fields/Doc'; +import * as React from 'react'; +import { CirclePicker, ColorResult } from 'react-color'; import { returnFalse, setupMoveUpEvents, unimplementedFunction } from '../../../../Utils'; +import { Doc, Opt } from '../../../../fields/Doc'; +import { NumCast, StrCast } from '../../../../fields/Types'; +import { CalendarManager } from '../../../util/CalendarManager'; import { SelectionManager } from '../../../util/SelectionManager'; -import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; -// import { GPTPopup, GPTPopupMode } from './../../GPTPopup/GPTPopup'; -import { Button, IconButton } from 'browndash-components'; import { SettingsManager } from '../../../util/SettingsManager'; +import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; import './MapAnchorMenu.scss'; -import { NumCast, StrCast } from '../../../../fields/Types'; -import { IconLookup, faDiamondTurnRight, faCalendarDays, faEdit, faAdd, faRoute, faArrowLeft, faLocationDot, faArrowDown, faCar, faBicycle, faPersonWalking, faUpload, faArrowsRotate } from '@fortawesome/free-solid-svg-icons'; -import { DirectionsAnchorMenu } from './DirectionsAnchorMenu'; -import { Autocomplete, Checkbox, FormControlLabel, TextField } from '@mui/material'; import { MapboxApiUtility, TransportationType } from './MapboxApiUtility'; -import { MapBox } from './MapBox'; -import { List } from '../../../../fields/List'; import { MarkerIcons } from './MarkerIcons'; -import { CirclePicker, ColorResult } from 'react-color'; -import { Position } from 'geojson'; -import { CalendarManager } from '../../../util/CalendarManager'; +// import { GPTPopup, GPTPopupMode } from './../../GPTPopup/GPTPopup'; type MapAnchorMenuType = 'standard' | 'routeCreation' | 'calendar' | 'customize' | 'route'; @@ -52,7 +49,6 @@ export class MapAnchorMenu extends AntimodeMenu { public UpdateMarkerColor: (color: string) => void = unimplementedFunction; public UpdateMarkerIcon: (iconKey: string) => void = unimplementedFunction; - public Hide: () => void = unimplementedFunction; public OpenAnimationPanel: (routeDoc: Doc | undefined) => void = unimplementedFunction; @@ -74,22 +70,21 @@ export class MapAnchorMenu extends AntimodeMenu { private title: string | undefined = undefined; public setPinDoc(pinDoc: Doc | undefined) { - if (pinDoc){ + if (pinDoc) { this.pinDoc = pinDoc; this.title = StrCast(pinDoc.title ? pinDoc.title : `${NumCast(pinDoc.longitude)}, ${NumCast(pinDoc.latitude)}`); } - } public setRouteDoc(routeDoc: Doc | undefined) { - if (routeDoc){ + if (routeDoc) { this.routeDoc = routeDoc; this.title = StrCast(routeDoc.title ?? 'Map route'); } } @action - public Reset(){ + public Reset() { this.destinationSelected = false; this.currentRouteInfoMap = undefined; this.destinationFeatures = []; @@ -296,34 +291,23 @@ export class MapAnchorMenu extends AntimodeMenu { return undefined; }; - getDirectionsButton: JSX.Element = ( - } - color={SettingsManager.userColor} /> - ) + getDirectionsButton: JSX.Element = (} color={SettingsManager.userColor} />); getAddToCalendarButton = (docType: string): JSX.Element => { return ( - { - CalendarManager.Instance.open(undefined, docType === 'pin' ? this.pinDoc : this.routeDoc) - }} - icon={} - color={SettingsManager.userColor} + { + CalendarManager.Instance.open(undefined, docType === 'pin' ? this.pinDoc : this.routeDoc); + }} + icon={} + color={SettingsManager.userColor} /> - ) - - } + ); + }; addToCalendarButton: JSX.Element = ( - CalendarManager.Instance.open(undefined, this.pinDoc)} - icon={} - color={SettingsManager.userColor} /> - ) + CalendarManager.Instance.open(undefined, this.pinDoc)} icon={} color={SettingsManager.userColor} /> + ); getLinkNoteToDocButton = (docType: string): JSX.Element => { return ( @@ -335,8 +319,8 @@ export class MapAnchorMenu extends AntimodeMenu { color={SettingsManager.userColor} /> - ) - } + ); + }; linkNoteToPinOrRoutenButton: JSX.Element = (
@@ -347,16 +331,9 @@ export class MapAnchorMenu extends AntimodeMenu { color={SettingsManager.userColor} />
- ) - - customizePinButton: JSX.Element = ( - } - color={SettingsManager.userColor} - /> - ) + ); + + customizePinButton: JSX.Element = (} color={SettingsManager.userColor} />); centerOnPinButton: JSX.Element = ( { icon={} color={SettingsManager.userColor} /> - ) + ); backButton: JSX.Element = ( { icon={} color={SettingsManager.userColor} /> - ) + ); addRouteButton: JSX.Element = ( { icon={} color={SettingsManager.userColor} /> - ) + ); getDeleteButton = (type: string) => { return ( @@ -393,17 +370,10 @@ export class MapAnchorMenu extends AntimodeMenu { icon={} color={SettingsManager.userColor} /> - ) - } + ); + }; - animateRouteButton: JSX.Element = ( - this.OpenAnimationPanel(this.routeDoc)} - icon={} - color={SettingsManager.userColor} - /> - ) + animateRouteButton: JSX.Element = ( this.OpenAnimationPanel(this.routeDoc)} icon={} color={SettingsManager.userColor} />); revertToOriginalMarkerButton = ( { icon={} color={SettingsManager.userColor} /> - ) + ); render() { const buttons = ( diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 7db139d74..ffd52fb0e 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -1,8 +1,17 @@ +import { IconLookup, faCircleXmark, faGear, faPause, faPlay, faRotate } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Checkbox, FormControlLabel, TextField } from '@mui/material'; +import * as turf from '@turf/turf'; import { IconButton, Size, Type } from 'browndash-components'; +import * as d3 from 'd3'; +import { Feature, FeatureCollection, GeoJsonProperties, Geometry, LineString, Position } from 'geojson'; +import mapboxgl, { LngLat, LngLatBoundsLike, MapLayerMouseEvent } from 'mapbox-gl'; import { IReactionDisposer, ObservableMap, action, autorun, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { CirclePicker, ColorResult } from 'react-color'; +import { Layer, MapProvider, MapRef, Map as MapboxMap, Marker, Source, ViewState, ViewStateChangeEvent } from 'react-map-gl'; +import { MarkerEvent } from 'react-map-gl/dist/esm/types'; import { Utils, emptyFunction, setupMoveUpEvents } from '../../../../Utils'; import { Doc, DocListCast, Field, LinkedTo, Opt } from '../../../../fields/Doc'; import { DocCss, Highlight } from '../../../../fields/DocSymbols'; @@ -22,22 +31,13 @@ import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../trails'; -import { MapAnchorMenu } from './MapAnchorMenu'; -import { ControlPosition, Layer, MapProvider, MapRef, Map as MapboxMap, Marker, MarkerProps, Source, ViewState, ViewStateChangeEvent } from 'react-map-gl'; -import './MapBox.scss'; -// import { GeocoderControl } from './GeocoderControl'; -import { IconLookup, faCircleXmark, faGear, faPause, faPlay, faRotate } from '@fortawesome/free-solid-svg-icons'; -import { Checkbox, FormControlLabel, TextField } from '@mui/material'; -import * as turf from '@turf/turf'; -import * as d3 from 'd3'; -import { Feature, FeatureCollection, GeoJsonProperties, Geometry, LineString, Position } from 'geojson'; -import mapboxgl, { LngLat, LngLatBoundsLike, MapLayerMouseEvent } from 'mapbox-gl'; -import { CirclePicker, ColorResult } from 'react-color'; -import { MarkerEvent } from 'react-map-gl/dist/esm/types'; import { fastSpeedIcon, mediumSpeedIcon, slowSpeedIcon } from './AnimationSpeedIcons'; import { AnimationSpeed, AnimationStatus, AnimationUtility } from './AnimationUtility'; +import { MapAnchorMenu } from './MapAnchorMenu'; +import './MapBox.scss'; import { MapboxApiUtility, TransportationType } from './MapboxApiUtility'; import { MarkerIcons } from './MarkerIcons'; +// import { GeocoderControl } from './GeocoderControl'; // amongus /** @@ -480,7 +480,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { @@ -650,7 +650,7 @@ export class MapBox extends ViewBoxAnnotatableComponent { - console.log('deleting') + console.log('deleting'); if (this.selectedPinOrRoute) { // Removes filter Doc.setDocFilter(this.Document, 'latitude', this.selectedPinOrRoute.latitude, 'remove'); @@ -677,15 +677,12 @@ export class MapBox extends ViewBoxAnnotatableComponent { if (this.selectedPinOrRoute) { @@ -882,8 +879,8 @@ export class MapBox extends ViewBoxAnnotatableComponent { return ( <> @@ -1423,20 +1417,14 @@ export class MapBox extends ViewBoxAnnotatableComponent
|
- } - /> + } />
|
|
-
+
Select Line Color:
- this.setAnimationLineColor(color)} /> + this.setAnimationLineColor(color)} />
-
@@ -1478,7 +1466,7 @@ export class MapBox extends ViewBoxAnnotatableComponent) => { const bearing = parseInt(e.target.value); if (!isNaN(bearing) && this._mapRef.current) { - console.log('bearing change') + console.log('bearing change'); const fixedBearing = Math.max(0, Math.min(360, bearing)); this._mapRef.current.setBearing(fixedBearing); this.dataDoc.map_bearing = fixedBearing; @@ -1489,7 +1477,7 @@ export class MapBox extends ViewBoxAnnotatableComponent) => { const pitch = parseInt(e.target.value); if (!isNaN(pitch) && this._mapRef.current) { - console.log('pitch change') + console.log('pitch change'); const fixedPitch = Math.max(0, Math.min(85, pitch)); this._mapRef.current.setPitch(fixedPitch); this.dataDoc.map_pitch = fixedPitch; @@ -1648,7 +1636,7 @@ export class MapBox extends ViewBoxAnnotatableComponent = React.createRef(); -// @observable private _overlayAnnoInfo: Opt; +// @observable private _overlayAnnoInfo: Opt = undefined; // showInfo = action((anno: Opt) => (this._overlayAnnoInfo = anno)); // public static LayoutString(fieldKey: string) { // return FieldView.LayoutString(MapBox2, fieldKey); diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx index 6a14427c0..70037f29c 100644 --- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -1,33 +1,31 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import BingMapsReact from 'bingmaps-react'; import { Button, EditableText, IconButton, Type } from 'browndash-components'; -import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx'; +import { IReactionDisposer, ObservableMap, action, computed, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { MapProvider, Map as MapboxMap } from 'react-map-gl'; +import { Utils, emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, setupMoveUpEvents } from '../../../../Utils'; import { Doc, DocListCast, Field, LinkedTo, Opt } from '../../../../fields/Doc'; import { DocCss, Highlight } from '../../../../fields/DocSymbols'; -import { Id } from '../../../../fields/FieldSymbols'; import { DocCast, NumCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../../Utils'; -import { Docs, DocUtils } from '../../../documents/Documents'; import { DocumentType } from '../../../documents/DocumentTypes'; +import { DocUtils, Docs } from '../../../documents/Documents'; import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { LinkManager } from '../../../util/LinkManager'; import { SnappingManager } from '../../../util/SnappingManager'; import { Transform } from '../../../util/Transform'; -import { undoable, UndoManager } from '../../../util/UndoManager'; -import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; +import { UndoManager, undoable } from '../../../util/UndoManager'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocComponent'; -import { Colors } from '../../global/globalEnums'; import { SidebarAnnos } from '../../SidebarAnnos'; +import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; +import { Colors } from '../../global/globalEnums'; import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; +import { MapAnchorMenu } from '../MapBox/MapAnchorMenu'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../trails'; import './MapBox.scss'; -import { MapAnchorMenu } from '../MapBox/MapAnchorMenu'; -import { MapProvider, Map as MapboxMap } from 'react-map-gl'; // amongus /** @@ -351,7 +349,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 733febd2d..7f1d6b049 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -48,7 +48,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent(); @observable private _searching: boolean = false; - @observable private _pdf: Opt; + @observable private _pdf: Opt = undefined; @observable private _pageControls = false; @computed get pdfUrl() { diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx index e75b1ab6f..135db64e0 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx @@ -6,8 +6,9 @@ import QuestionMarkIcon from '@mui/icons-material/QuestionMark'; import ReplayIcon from '@mui/icons-material/Replay'; import { Box, Button, Checkbox, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, FormControl, FormControlLabel, FormGroup, IconButton, LinearProgress, Stack } from '@mui/material'; import Typography from '@mui/material/Typography'; -import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'; +import { IReactionDisposer, action, computed, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { NumListCast } from '../../../../fields/Doc'; import { List } from '../../../../fields/List'; import { BoolCast, NumCast, StrCast } from '../../../../fields/Types'; @@ -19,7 +20,6 @@ import questions from './PhysicsSimulationQuestions.json'; import tutorials from './PhysicsSimulationTutorial.json'; import Wall from './PhysicsSimulationWall'; import Weight from './PhysicsSimulationWeight'; -import * as React from 'react'; interface IWallProps { length: number; diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx index f5077a07e..3b232ddd0 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx @@ -1,7 +1,7 @@ import { computed, IReactionDisposer, makeObservable, reaction } from 'mobx'; import { observer } from 'mobx-react'; -import './PhysicsSimulationBox.scss'; import * as React from 'react'; +import './PhysicsSimulationBox.scss'; interface IWallProps { length: number; diff --git a/src/client/views/nodes/RadialMenu.tsx b/src/client/views/nodes/RadialMenu.tsx index 061a46f03..3b2fc033d 100644 --- a/src/client/views/nodes/RadialMenu.tsx +++ b/src/client/views/nodes/RadialMenu.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import './RadialMenu.scss'; import { RadialMenuItem, RadialMenuProps } from './RadialMenuItem'; diff --git a/src/client/views/nodes/RadialMenuItem.tsx b/src/client/views/nodes/RadialMenuItem.tsx index c931202f1..10a90befd 100644 --- a/src/client/views/nodes/RadialMenuItem.tsx +++ b/src/client/views/nodes/RadialMenuItem.tsx @@ -1,7 +1,7 @@ -import * as React from 'react'; import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { UndoManager } from '../../util/UndoManager'; export interface RadialMenuProps { diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx index f01642236..658cfb1ca 100644 --- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx +++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx @@ -8,15 +8,15 @@ import { List } from '../../../../fields/List'; import { BoolCast, DocCast } from '../../../../fields/Types'; import { VideoField } from '../../../../fields/URLField'; import { Upload } from '../../../../server/SharedMediaTypes'; -import { Docs } from '../../../documents/Documents'; import { DocumentType } from '../../../documents/DocumentTypes'; +import { Docs } from '../../../documents/Documents'; import { DocumentManager } from '../../../util/DocumentManager'; import { DragManager } from '../../../util/DragManager'; import { ScriptingGlobals } from '../../../util/ScriptingGlobals'; import { Presentation } from '../../../util/TrackMovements'; import { undoBatch } from '../../../util/UndoManager'; -import { CollectionFreeFormView } from '../../collections/collectionFreeForm/CollectionFreeFormView'; import { ViewBoxBaseComponent } from '../../DocComponent'; +import { CollectionFreeFormView } from '../../collections/collectionFreeForm/CollectionFreeFormView'; import { media_state } from '../AudioBox'; import { FieldView, FieldViewProps } from '../FieldView'; import { VideoBox } from '../VideoBox'; diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index d5d31b407..79ed69cdd 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -1,5 +1,5 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import * as React from 'react'; // import { Canvas } from '@react-three/fiber'; import { computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index 7e7eaee45..8e506ec64 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -2,25 +2,23 @@ let ReactTextareaAutocomplete = require('@webscopeio/react-textarea-autocomplete import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { returnAlways, returnEmptyString } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { ScriptField } from '../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { returnAlways, returnEmptyString, returnTrue } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; -import { InteractionUtils } from '../../util/InteractionUtils'; +import { ScriptManager } from '../../util/ScriptManager'; import { CompileScript, ScriptParam } from '../../util/Scripting'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; -import { ScriptManager } from '../../util/ScriptManager'; import { ContextMenu } from '../ContextMenu'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { EditableView } from '../EditableView'; -import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { OverlayView } from '../OverlayView'; +import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { DocumentIconContainer } from './DocumentIcon'; -import { DocFocusOptions, DocumentView } from './DocumentView'; import './ScriptingBox.scss'; const _global = (window /* browser */ || global) /* node */ as any; diff --git a/src/client/views/nodes/TaskCompletedBox.tsx b/src/client/views/nodes/TaskCompletedBox.tsx index 9aab8c5a9..c9e15d314 100644 --- a/src/client/views/nodes/TaskCompletedBox.tsx +++ b/src/client/views/nodes/TaskCompletedBox.tsx @@ -1,15 +1,15 @@ -import * as React from 'react'; +import { Fade } from '@mui/material'; +import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import './TaskCompletedBox.scss'; -import { observable, action } from 'mobx'; -import { Fade } from '@mui/material'; @observer export class TaskCompletionBox extends React.Component<{}> { @observable public static taskCompleted: boolean = false; @observable public static popupX: number = 500; @observable public static popupY: number = 150; - @observable public static textDisplayed: string; + @observable public static textDisplayed: string = ''; @action public static toggleTaskCompleted = () => { diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index f205dbd56..8e9cfe3d7 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -74,8 +74,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent(); @observable _screenCapture = false; @observable _clicking = false; // used for transition between showing/hiding timeline @@ -86,7 +86,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent(){ +export class CalendarBox extends ViewBoxBaseComponent() { public static LayoutString(fieldKey: string = 'calendar') { return FieldView.LayoutString(CalendarBox, fieldKey); } - componentDidMount(): void { - - } + componentDidMount(): void {} - componentWillUnmount(): void { - - } + componentWillUnmount(): void {} - _calendarRef = React.createRef() + _calendarRef = React.createRef(); - get dateRangeStr (){ + get dateRangeStr() { return StrCast(this.Document.date_range); } - // Choose a calendar view based on the date range - get calendarViewType (): CalendarView { + // Choose a calendar view based on the date range + get calendarViewType(): CalendarView { const [fromDate, toDate] = dateRangeStrToDates(this.dateRangeStr); if (fromDate.getFullYear() !== toDate.getFullYear() || fromDate.getMonth() !== toDate.getMonth()) return 'multi-month'; @@ -43,92 +38,83 @@ export class CalendarBox extends ViewBoxBaseComponent(){ return 'week'; } - get calendarStartDate () { - return this.dateRangeStr.split("|")[0]; + get calendarStartDate() { + return this.dateRangeStr.split('|')[0]; } - get calendarToDate () { - return this.dateRangeStr.split("|")[1]; + get calendarToDate() { + return this.dateRangeStr.split('|')[1]; } - get childDocs (): Doc[] { + get childDocs(): Doc[] { return this.childDocs; // get all sub docs for a calendar } - docBackgroundColor (type: string): string { + docBackgroundColor(type: string): string { // TODO: Return a different color based on the event type return 'blue'; } - get calendarEvents (): EventSourceInput | undefined { + get calendarEvents(): EventSourceInput | undefined { if (this.childDocs.length === 0) return undefined; return this.childDocs.map((doc, idx) => { const docTitle = StrCast(doc.title); const docDateRange = StrCast(doc.date_range); const [startDate, endDate] = dateRangeStrToDates(docDateRange); const docType = doc.type; - const docDescription = doc.description ? StrCast(doc.description): ""; + const docDescription = doc.description ? StrCast(doc.description) : ''; return { title: docTitle, start: startDate, end: endDate, allDay: false, - classNames:[StrCast(docType)], // will determine the style + classNames: [StrCast(docType)], // will determine the style editable: false, // subject to change in the future backgroundColor: this.docBackgroundColor(StrCast(doc.type)), color: 'white', extendedProps: { - description: docDescription + description: docDescription, }, - - } - - }) + }; + }); } handleEventClick = (arg: EventClickArg) => { // TODO: open popover with event description, option to open CalendarManager and change event date, delete event, etc. - } + }; calendarEl: HTMLElement = document.getElementById('calendar-box-v1')!; // https://fullcalendar.io get calendar() { - return new Calendar(this.calendarEl, - { - plugins: [this.calendarViewType === 'multi-month' ? multiMonthPlugin : dayGridPlugin], - headerToolbar: { - left: 'prev,next today', - center: 'title', - right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek' - }, - initialDate: this.calendarStartDate, - navLinks: true, - editable: false, - displayEventTime: false, - displayEventEnd: false, - events: this.calendarEvents, - eventClick: this.handleEventClick - } - ) - + return new Calendar(this.calendarEl, { + plugins: [this.calendarViewType === 'multi-month' ? multiMonthPlugin : dayGridPlugin], + headerToolbar: { + left: 'prev,next today', + center: 'title', + right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek', + }, + initialDate: this.calendarStartDate, + navLinks: true, + editable: false, + displayEventTime: false, + displayEventEnd: false, + events: this.calendarEvents, + eventClick: this.handleEventClick, + }); } - - constructor(props: any){ + constructor(props: any) { super(props); makeObservable(this); } - render(){ + render() { return ( -
-
- -
-
+
+
+
); - } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 6332b200d..1002ee403 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -1,17 +1,17 @@ import { action, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { NodeSelection } from 'prosemirror-state'; +import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import { Doc } from '../../../../fields/Doc'; import { Height, Width } from '../../../../fields/DocSymbols'; import { NumCast, StrCast } from '../../../../fields/Types'; -import { emptyFunction, returnFalse, returnTrue, Utils } from '../../../../Utils'; +import { emptyFunction, returnFalse, Utils } from '../../../../Utils'; import { DocServer } from '../../../DocServer'; import { Docs, DocUtils } from '../../../documents/Documents'; import { Transform } from '../../../util/Transform'; import { DocFocusOptions, DocumentView } from '../DocumentView'; import { FormattedTextBox } from './FormattedTextBox'; -import * as React from 'react'; export class DashDocView { dom: HTMLSpanElement; // container for label and value @@ -83,7 +83,7 @@ export class DashDocViewInternal extends React.Component { _disposers: { [name: string]: IReactionDisposer } = {}; _textBox: FormattedTextBox; @observable _dashDoc: Doc | undefined = undefined; - @observable _finalLayout: any; + @observable _finalLayout: any = undefined; @observable _width: number = 0; @observable _height: number = 0; diff --git a/src/client/views/nodes/formattedText/EquationView.tsx b/src/client/views/nodes/formattedText/EquationView.tsx index 331ed1980..7e655531e 100644 --- a/src/client/views/nodes/formattedText/EquationView.tsx +++ b/src/client/views/nodes/formattedText/EquationView.tsx @@ -1,14 +1,13 @@ -import EquationEditor from './EquationEditor'; -import { IReactionDisposer, trace } from 'mobx'; +import { IReactionDisposer } from 'mobx'; import { observer } from 'mobx-react'; import { TextSelection } from 'prosemirror-state'; +import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; import { Doc } from '../../../../fields/Doc'; import { StrCast } from '../../../../fields/Types'; import './DashFieldView.scss'; +import EquationEditor from './EquationEditor'; import { FormattedTextBox } from './FormattedTextBox'; -import * as React from 'react'; -import { AnyArray } from 'mongoose'; export class EquationView { dom: HTMLDivElement; // container for label and value diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index ad2fab8b0..8bf8abafa 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -11,6 +11,7 @@ import { keymap } from 'prosemirror-keymap'; import { Fragment, Mark, Node, Slice } from 'prosemirror-model'; import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from 'prosemirror-state'; import { EditorView } from 'prosemirror-view'; +import * as React from 'react'; import { BsMarkdownFill } from 'react-icons/bs'; import { DateField } from '../../../../fields/DateField'; import { Doc, DocListCast, Field, Opt } from '../../../../fields/Doc'; @@ -70,9 +71,8 @@ import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu'; import { RichTextRules } from './RichTextRules'; import { schema } from './schema_rts'; import { SummaryView } from './SummaryView'; -// import * as applyDevTools from 'prosemirror-dev-tools'; -import * as React from 'react'; export const GoogleRef = 'googleDocId'; +// import * as applyDevTools from 'prosemirror-dev-tools'; type PullHandler = (exportState: Opt, dataDoc: Doc) => void; export interface FormattedTextBoxProps {} diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 4881070fd..3b31f2d17 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -32,7 +32,7 @@ export class RichTextMenu extends AntimodeMenu { private _linkToRef = React.createRef(); layoutDoc: Doc | undefined; - @observable public view?: EditorView; + @observable public view?: EditorView = undefined; public editorProps: FieldViewProps | undefined; public _brushMap: Map> = new Map(); diff --git a/src/client/views/nodes/importBox/ImportElementBox.tsx b/src/client/views/nodes/importBox/ImportElementBox.tsx index 9dc0c5180..b573f7c48 100644 --- a/src/client/views/nodes/importBox/ImportElementBox.tsx +++ b/src/client/views/nodes/importBox/ImportElementBox.tsx @@ -1,13 +1,11 @@ import { computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { returnFalse } from '../../../../Utils'; import { Doc } from '../../../../fields/Doc'; -import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue } from '../../../../Utils'; -import { Transform } from '../../../util/Transform'; import { ViewBoxBaseComponent } from '../../DocComponent'; -import { DefaultStyleProvider } from '../../StyleProvider'; -import { DocumentView, DocumentViewInternal } from '../DocumentView'; +import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; -import * as React from 'react'; @observer export class ImportElementBox extends ViewBoxBaseComponent() { diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index e213b2fc5..0305689e7 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -1,8 +1,8 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; import { action, computed, IReactionDisposer, makeObservable, observable, ObservableSet, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, DocListCast, FieldResult, NumListCast, Opt, StrListCast } from '../../../../fields/Doc'; import { Animation } from '../../../../fields/DocSymbols'; import { Copy, Id } from '../../../../fields/FieldSymbols'; @@ -24,7 +24,7 @@ import { SerializationHelper } from '../../../util/SerializationHelper'; import { SettingsManager } from '../../../util/SettingsManager'; import { undoBatch, UndoManager } from '../../../util/UndoManager'; import { CollectionDockingView } from '../../collections/CollectionDockingView'; -import { CollectionFreeFormView, computeTimelineLayout, MarqueeViewBounds } from '../../collections/collectionFreeForm'; +import { CollectionFreeFormView, MarqueeViewBounds } from '../../collections/collectionFreeForm'; import { CollectionStackedTimeline } from '../../collections/CollectionStackedTimeline'; import { CollectionView } from '../../collections/CollectionView'; import { TreeView } from '../../collections/TreeView'; @@ -83,12 +83,12 @@ export class PresBox extends ViewBoxBaseComponent() { _batch: UndoManager.Batch | undefined = undefined; // undo batch for dragging sliders which generate multiple scene edit events as the cursor moves _keyTimer: NodeJS.Timeout | undefined; // timer for turning off transition flag when key frame change has completed. Need to clear this if you do a second navigation before first finishes, or else first timer can go off during second naviation. _unmounting = false; // flag that view is unmounting used to block RemFromMap from deleting things + _presTimer: NodeJS.Timeout | undefined; @observable public static Instance: PresBox; @observable _isChildActive = false; @observable _moveOnFromAudio: boolean = true; - @observable _presTimer!: NodeJS.Timeout; @observable _eleArray: HTMLElement[] = []; @observable _dragArray: HTMLElement[] = []; diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index cf19ff6bc..5ea9e9979 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -1,18 +1,17 @@ -import * as React from 'react'; import { action, computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { Id } from '../../../fields/FieldSymbols'; import { List } from '../../../fields/List'; import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types'; import { LinkFollower } from '../../util/LinkFollower'; +import { LinkManager } from '../../util/LinkManager'; import { undoBatch } from '../../util/UndoManager'; import { OpenWhere } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { AnchorMenu } from './AnchorMenu'; import './Annotation.scss'; -import { LinkManager } from '../../util/LinkManager'; -import { Rect } from 'react-measure'; interface IAnnotationProps extends FieldViewProps { anno: Doc; diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index db21d9a3d..da8a88803 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -1,20 +1,20 @@ -import * as React from 'react'; -import './GPTPopup.scss'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Button, IconButton, Type } from 'browndash-components'; import { action, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { CgClose } from 'react-icons/cg'; import ReactLoading from 'react-loading'; import { TypeAnimation } from 'react-type-animation'; +import { Utils } from '../../../../Utils'; import { Doc } from '../../../../fields/Doc'; -import { DocUtils, Docs } from '../../../documents/Documents'; -import { Button, IconButton, Type } from 'browndash-components'; import { NumCast, StrCast } from '../../../../fields/Types'; -import { CgClose } from 'react-icons/cg'; -import { AnchorMenu } from '../AnchorMenu'; -import { gptImageCall } from '../../../apis/gpt/GPT'; import { Networking } from '../../../Network'; -import { Utils } from '../../../../Utils'; +import { gptImageCall } from '../../../apis/gpt/GPT'; +import { DocUtils, Docs } from '../../../documents/Documents'; import { ObservableReactComponent } from '../../ObservableReactComponent'; +import { AnchorMenu } from '../AnchorMenu'; +import './GPTPopup.scss'; export enum GPTPopupMode { SUMMARY, diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index e342c25b3..b6d027d30 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -302,7 +302,7 @@ export class PDFViewer extends ObservableReactComponent { } }; - @observable private _scrollTimer: any; + @observable private _scrollTimer: any = undefined; onScroll = (e: React.UIEvent) => { if (this._mainCont.current && !this._forcedScroll) { diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index ccfccb771..14187833f 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -2,24 +2,23 @@ import { Tooltip } from '@mui/material'; import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, DocListCast, DocListCastAsync, Field, Opt } from '../../../fields/Doc'; +import { Doc, DocListCastAsync, Field } from '../../../fields/Doc'; import { DirectLinks } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { DocCast, StrCast } from '../../../fields/Types'; -import { DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; +import { DocUtils } from '../../documents/Documents'; import { DocumentManager } from '../../util/DocumentManager'; import { LinkManager } from '../../util/LinkManager'; +import { SearchUtil } from '../../util/SearchUtil'; +import { SettingsManager } from '../../util/SettingsManager'; import { undoBatch } from '../../util/UndoManager'; -import { CollectionDockingView } from '../collections/CollectionDockingView'; import { ViewBoxBaseComponent } from '../DocComponent'; +import { CollectionDockingView } from '../collections/CollectionDockingView'; +import { IRecommendation, Recommendation } from '../newlightbox/components'; +import { fetchRecommendations } from '../newlightbox/utils'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import './SearchBox.scss'; -import { fetchRecommendations } from '../newlightbox/utils'; -import { IRecommendation, Recommendation } from '../newlightbox/components'; -import { Colors } from '../global/globalEnums'; -import { SettingsManager } from '../../util/SettingsManager'; -import { SearchUtil } from '../../util/SearchUtil'; const DAMPENING_FACTOR = 0.9; const MAX_ITERATIONS = 25; diff --git a/src/client/views/selectedDoc/SelectedDocView.tsx b/src/client/views/selectedDoc/SelectedDocView.tsx index 39e778b76..daacb368b 100644 --- a/src/client/views/selectedDoc/SelectedDocView.tsx +++ b/src/client/views/selectedDoc/SelectedDocView.tsx @@ -1,14 +1,14 @@ -import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ListBox } from 'browndash-components'; import { computed } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; +import { emptyFunction } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { StrCast } from '../../../fields/Types'; import { DocumentManager } from '../../util/DocumentManager'; -import { DocFocusOptions } from '../nodes/DocumentView'; -import { emptyFunction } from '../../../Utils'; import { SettingsManager } from '../../util/SettingsManager'; +import { DocFocusOptions } from '../nodes/DocumentView'; export interface SelectedDocViewProps { selectedDocs: Doc[]; diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index 0f3487cd1..575d5849e 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -16,15 +16,15 @@ import { ReportManager } from '../../util/reportManager/ReportManager'; import { ServerStats } from '../../util/ServerStats'; import { SettingsManager } from '../../util/SettingsManager'; import { SharingManager } from '../../util/SharingManager'; +import { SnappingManager } from '../../util/SnappingManager'; import { Transform } from '../../util/Transform'; import { CollectionDockingView } from '../collections/CollectionDockingView'; import { CollectionLinearView } from '../collections/collectionLinear'; import { DashboardView } from '../DashboardView'; import { Colors } from '../global/globalEnums'; -import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView'; +import { DocumentViewInternal } from '../nodes/DocumentView'; import { DefaultStyleProvider } from '../StyleProvider'; import './TopBar.scss'; -import { SnappingManager } from '../../util/SnappingManager'; /** * ABOUT: This is the topbar in Dash, which included the current Dashboard as well as access to information on the user diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx index f1739a41a..94458563e 100644 --- a/src/client/views/webcam/DashWebRTCVideo.tsx +++ b/src/client/views/webcam/DashWebRTCVideo.tsx @@ -3,16 +3,15 @@ import { faPhoneSlash, faSync } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { Doc } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; +import { SnappingManager } from '../../util/SnappingManager'; import '../../views/nodes/WebBox.scss'; import { CollectionFreeFormDocumentViewProps } from '../nodes/CollectionFreeFormDocumentView'; -import { DocumentView } from '../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import './DashWebRTCVideo.scss'; import { hangup, initialize, refreshVideos } from './WebCamLogic'; -import * as React from 'react'; -import { SnappingManager } from '../../util/SnappingManager'; /** * This models the component that will be rendered, that can be used as a doc that will reflect the video cams. diff --git a/src/debug/Repl.tsx b/src/debug/Repl.tsx index b8081648f..a9f7c085f 100644 --- a/src/debug/Repl.tsx +++ b/src/debug/Repl.tsx @@ -1,13 +1,13 @@ +import { computed, observable } from 'mobx'; +import { observer } from 'mobx-react'; import * as React from 'react'; import * as ReactDOM from 'react-dom/client'; -import { observer } from 'mobx-react'; -import { observable, computed } from 'mobx'; +import { DocServer } from '../client/DocServer'; +import { resolvedPorts } from '../client/util/CurrentUserUtils'; import { CompileScript } from '../client/util/Scripting'; -import { makeInterface } from '../fields/Schema'; import { ObjectField } from '../fields/ObjectField'; import { RefField } from '../fields/RefField'; -import { DocServer } from '../client/DocServer'; -import { resolvedPorts } from '../client/util/CurrentUserUtils'; +import { makeInterface } from '../fields/Schema'; @observer class Repl extends React.Component { diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx index 02038c426..f46adef77 100644 --- a/src/debug/Viewer.tsx +++ b/src/debug/Viewer.tsx @@ -1,19 +1,19 @@ -import { action, configure, observable, ObservableMap, Lambda } from 'mobx'; +import { action, configure, observable } from 'mobx'; +import { observer } from 'mobx-react'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import { observer } from 'mobx-react'; -import { Doc, Field, FieldResult, Opt } from '../fields/Doc'; import { DocServer } from '../client/DocServer'; +import { resolvedPorts } from '../client/util/CurrentUserUtils'; +import { CompileScript } from '../client/util/Scripting'; +import { EditableView } from '../client/views/EditableView'; +import CursorField from '../fields/CursorField'; +import { DateField } from '../fields/DateField'; +import { Doc, Field, FieldResult } from '../fields/Doc'; import { Id } from '../fields/FieldSymbols'; import { List } from '../fields/List'; -import { URLField } from '../fields/URLField'; -import { EditableView } from '../client/views/EditableView'; -import { CompileScript } from '../client/util/Scripting'; import { RichTextField } from '../fields/RichTextField'; -import { DateField } from '../fields/DateField'; import { ScriptField } from '../fields/ScriptField'; -import CursorField from '../fields/CursorField'; -import { resolvedPorts } from '../client/util/CurrentUserUtils'; +import { URLField } from '../fields/URLField'; DateField; URLField; diff --git a/src/fields/CursorField.ts b/src/fields/CursorField.ts index 46f5a8e1c..84917ae53 100644 --- a/src/fields/CursorField.ts +++ b/src/fields/CursorField.ts @@ -1,8 +1,7 @@ -import { ObjectField } from './ObjectField'; -import { observable } from 'mobx'; +import { createSimpleSchema, object, serializable } from 'serializr'; import { Deserializable } from '../client/util/SerializationHelper'; -import { serializable, createSimpleSchema, object, date } from 'serializr'; -import { FieldChanged, ToScriptString, ToString, Copy } from './FieldSymbols'; +import { Copy, FieldChanged, ToScriptString, ToString } from './FieldSymbols'; +import { ObjectField } from './ObjectField'; export type CursorPosition = { x: number; diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 8903a9f97..9dc3c173d 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -265,8 +265,8 @@ export class Doc extends RefField { @observable public [DocAcl]: { [key: string]: symbol } = {}; @observable public [DocCss]: number = 0; // incrementer denoting a change to CSS layout @observable public [DirectLinks] = new ObservableSet(); - @observable public [AudioPlay]: any; // meant to store sound object from Howl - @observable public [Animation]: Opt; + @observable public [AudioPlay]: any = undefined; // meant to store sound object from Howl + @observable public [Animation]: Opt = undefined; @observable public [Highlight]: boolean = false; @observable public [Brushed]: boolean = false; @observable public [DocViews] = new ObservableSet(); diff --git a/src/fields/List.ts b/src/fields/List.ts index 8c8ff1ea3..b8ad552d2 100644 --- a/src/fields/List.ts +++ b/src/fields/List.ts @@ -2,7 +2,7 @@ import { action, computed, makeObservable, observable } from 'mobx'; import { alias, list, serializable } from 'serializr'; import { DocServer } from '../client/DocServer'; import { ScriptingGlobals } from '../client/util/ScriptingGlobals'; -import { afterDocDeserialize, autoObject, Deserializable } from '../client/util/SerializationHelper'; +import { Deserializable, afterDocDeserialize, autoObject } from '../client/util/SerializationHelper'; import { Field } from './Doc'; import { FieldTuples, Self, SelfProxy } from './DocSymbols'; import { Copy, FieldChanged, Parent, ToScriptString, ToString } from './FieldSymbols'; @@ -11,7 +11,7 @@ import { ProxyField } from './Proxy'; import { RefField } from './RefField'; import { listSpec } from './Schema'; import { Cast } from './Types'; -import { deleteProperty, getter, setter, containedFieldChangedHandler } from './util'; +import { containedFieldChangedHandler, deleteProperty, getter, setter } from './util'; function toObjectField(field: Field) { return field instanceof RefField ? new ProxyField(field) : field; @@ -102,8 +102,8 @@ class ListImpl extends ObjectField { items.length === 0 && deleteCount ? { op: '$remFromSet', items: removed, hint: { start, deleteCount }, length: list.__fieldTuples.length } : items.length && !deleteCount && start === list.__fieldTuples.length - ? { op: '$addToSet', items, length: list.__fieldTuples.length } - : undefined + ? { op: '$addToSet', items, length: list.__fieldTuples.length } + : undefined ); return res.map(toRealField); }), diff --git a/src/fields/Proxy.ts b/src/fields/Proxy.ts index c076f5fe1..3a46e3581 100644 --- a/src/fields/Proxy.ts +++ b/src/fields/Proxy.ts @@ -1,12 +1,12 @@ -import { Deserializable } from '../client/util/SerializationHelper'; -import { Field, FieldWaiting, Opt } from './Doc'; +import { action, computed, observable, runInAction } from 'mobx'; import { primitive, serializable } from 'serializr'; -import { observable, action, runInAction, computed } from 'mobx'; import { DocServer } from '../client/DocServer'; -import { RefField } from './RefField'; -import { ObjectField } from './ObjectField'; -import { Id, Copy, ToScriptString, ToString, ToValue } from './FieldSymbols'; import { scriptingGlobal } from '../client/util/ScriptingGlobals'; +import { Deserializable } from '../client/util/SerializationHelper'; +import { Field, FieldWaiting, Opt } from './Doc'; +import { Copy, Id, ToScriptString, ToString, ToValue } from './FieldSymbols'; +import { ObjectField } from './ObjectField'; +import { RefField } from './RefField'; function deserializeProxy(field: any) { if (!field.cache.field) { diff --git a/src/fields/util.ts b/src/fields/util.ts index 545fe4478..b73520999 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -1,11 +1,11 @@ import { $mobx, action, observable, runInAction, trace } from 'mobx'; import { computedFn } from 'mobx-utils'; +import { returnZero } from '../Utils'; import { DocServer } from '../client/DocServer'; import { LinkManager } from '../client/util/LinkManager'; import { SerializationHelper } from '../client/util/SerializationHelper'; import { UndoManager } from '../client/util/UndoManager'; -import { returnZero } from '../Utils'; -import { aclLevel, Doc, DocListCast, Field, FieldResult, HierarchyMapping, ReverseHierarchyMap, StrListCast, updateCachedAcls } from './Doc'; +import { Doc, DocListCast, Field, FieldResult, HierarchyMapping, ReverseHierarchyMap, StrListCast, aclLevel, updateCachedAcls } from './Doc'; import { AclAdmin, AclAugment, AclEdit, AclPrivate, DocAcl, DocData, DocLayout, FieldKeys, ForceServerWrite, Height, Initializing, SelfProxy, UpdatingFromServer, Width } from './DocSymbols'; import { FieldChanged, Id, Parent, ToValue } from './FieldSymbols'; import { List } from './List'; diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index d2598c2db..e333e6a2e 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -1,19 +1,19 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import * as rp from 'request-promise'; +import { Utils } from '../Utils'; import { DocServer } from '../client/DocServer'; -import { Docs } from '../client/documents/Documents'; import { Networking } from '../client/Network'; +import { Docs } from '../client/documents/Documents'; import { MainViewModal } from '../client/views/MainViewModal'; import { Doc, Opt } from '../fields/Doc'; import { List } from '../fields/List'; import { listSpec } from '../fields/Schema'; import { Cast } from '../fields/Types'; -import { Utils } from '../Utils'; import './ImageUpload.scss'; import { MobileInterface } from './MobileInterface'; -import * as React from 'react'; const { default: { DFLT_IMAGE_NATIVE_DIM } } = require('../client/views/global/globalCssVariables.module.scss'); // prettier-ignore export interface ImageUploadProps { Document: Doc; // Target document for upload (upload location) diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx index 2e595e4bc..23e19585a 100644 --- a/src/mobile/MobileInkOverlay.tsx +++ b/src/mobile/MobileInkOverlay.tsx @@ -1,6 +1,6 @@ -import * as React from 'react'; import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import { DocServer } from '../client/DocServer'; import { DragManager } from '../client/util/DragManager'; import { Doc } from '../fields/Doc'; diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index bdd657575..e3d8f9394 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -1,52 +1,33 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { - faTasks, - faReply, - faQuoteLeft, - faHandPointLeft, - faFolderOpen, + faAddressCard, + faAlignLeft, + faAlignRight, faAngleDoubleLeft, - faExternalLinkSquareAlt, - faMobile, - faThLarge, - faWindowClose, - faEdit, - faTrashAlt, - faPalette, faAngleRight, + faArrowDown, + faArrowLeft, + faArrowRight, + faArrowUp, + faArrowsAltH, + faAsterisk, + faBars, faBell, - faTrash, + faBolt, + faBook, + faBrain, + faBullseye, + faCalculator, faCamera, - faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, - faArrowsAltH, - faPlus, - faMinus, - faTerminal, - faToggleOn, - faFile as fileSolid, - faExternalLinkAlt, - faLocationArrow, - faSearch, - faFileDownload, - faStop, - faCalculator, - faWindowMaximize, - faAddressCard, - faQuestionCircle, - faArrowLeft, - faArrowRight, - faArrowDown, - faArrowUp, - faBolt, - faBullseye, faCaretUp, faCat, faCheck, + faChevronLeft, faChevronRight, faClipboard, faClone, @@ -54,76 +35,95 @@ import { faCommentAlt, faCompressArrowsAlt, faCut, + faEdit, faEllipsisV, faEraser, faExclamation, + faExpand, + faExternalLinkAlt, + faExternalLinkSquareAlt, + faEye, faFileAlt, faFileAudio, + faFileDownload, faFilePdf, faFilm, faFilter, + faFolderOpen, faFont, faGlobeAsia, + faHandPointLeft, faHighlighter, + faHome, + faImage, + faLocationArrow, + faLongArrowAltLeft, faLongArrowAltRight, faMicrophone, + faMinus, + faMobile, faMousePointer, faMusic, faObjectGroup, + faPaintBrush, + faPalette, faPause, faPen, faPenNib, faPhone, faPlay, + faPlus, faPortrait, + faQuestionCircle, + faQuoteLeft, faRedoAlt, + faReply, + faSearch, faStamp, faStickyNote, + faStop, + faTasks, + faTerminal, + faTh, + faThLarge, faThumbtack, + faTimes, + faToggleOn, + faTrash, + faTrashAlt, faTree, faTv, - faBook, faUndoAlt, faVideo, - faAsterisk, - faBrain, - faImage, - faPaintBrush, - faTimes, - faEye, - faHome, - faLongArrowAltLeft, - faBars, - faTh, - faChevronLeft, - faAlignRight, - faAlignLeft, + faWindowClose, + faWindowMaximize, + faFile as fileSolid, } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Docs, DocumentOptions, DocUtils } from '../client/documents/Documents'; +import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../Utils'; import { CollectionViewType, DocumentType } from '../client/documents/DocumentTypes'; +import { Docs, DocumentOptions } from '../client/documents/Documents'; import { CurrentUserUtils } from '../client/util/CurrentUserUtils'; import { ScriptingGlobals } from '../client/util/ScriptingGlobals'; -import { SettingsManager, ColorScheme } from '../client/util/SettingsManager'; +import { SettingsManager } from '../client/util/SettingsManager'; import { Transform } from '../client/util/Transform'; import { UndoManager } from '../client/util/UndoManager'; -import { TabDocView } from '../client/views/collections/TabDocView'; import { GestureOverlay } from '../client/views/GestureOverlay'; +import { TabDocView } from '../client/views/collections/TabDocView'; import { AudioBox } from '../client/views/nodes/AudioBox'; import { DocumentView } from '../client/views/nodes/DocumentView'; -import { RichTextMenu } from '../client/views/nodes/formattedText/RichTextMenu'; import { RadialMenu } from '../client/views/nodes/RadialMenu'; +import { RichTextMenu } from '../client/views/nodes/formattedText/RichTextMenu'; import { Doc, DocListCast } from '../fields/Doc'; import { InkTool } from '../fields/InkField'; import { List } from '../fields/List'; import { ScriptField } from '../fields/ScriptField'; import { Cast, FieldValue, StrCast } from '../fields/Types'; -import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero } from '../Utils'; -import { Uploader } from './ImageUpload'; import './AudioUpload.scss'; +import { Uploader } from './ImageUpload'; import './ImageUpload.scss'; import './MobileInterface.scss'; diff --git a/src/typings/index.d.ts b/src/typings/index.d.ts index 8f21966ae..d46977816 100644 --- a/src/typings/index.d.ts +++ b/src/typings/index.d.ts @@ -14,9 +14,7 @@ declare module 'pdfjs-dist/web/pdf_viewer'; declare module 'react-jsx-parser'; declare module 'express-flash'; -declare module 'connect-flash' { - interface flash {} -} +declare module 'connect-flash'; declare module 'connect-mongo'; declare module '@mui/material'; diff --git a/test/test.ts b/test/test.ts index 489aa3025..ee14a9340 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1,37 +1,41 @@ import { expect } from 'chai'; import 'mocha'; const { JSDOM } = require('jsdom'); -const dom = new JSDOM("", { - url: `http://localhost:${resolvedPorts.server}` +const dom = new JSDOM('', { + url: `http://localhost:${resolvedPorts.server}`, }); (global as any).window = dom.window; - -import { autorun, reaction } from "mobx"; +import { reaction } from 'mobx'; +import { resolvedPorts } from '../src/client/util/CurrentUserUtils'; import { Doc } from '../src/fields/Doc'; +import { createSchema, defaultSpec, makeInterface } from '../src/fields/Schema'; import { Cast } from '../src/fields/Types'; -import { createSchema, makeInterface, defaultSpec } from '../src/fields/Schema'; import { ImageField } from '../src/fields/URLField'; -import { resolvedPorts } from '../src/client/util/CurrentUserUtils'; -describe("Document", () => { +describe('Document', () => { it('should hold fields', () => { - const key = "Test"; - const key2 = "Test2"; + const key = 'Test'; + const key2 = 'Test2'; const field = 15; const doc = new Doc(); doc[key] = field; - const getField = Cast(doc[key], "number"); - const getField2 = Cast(doc[key2], "number"); + const getField = Cast(doc[key], 'number'); + const getField2 = Cast(doc[key2], 'number'); expect(getField).to.equal(field); expect(getField2).to.equal(undefined); }); it('should update', () => { const doc = new Doc(); - const key = "Test"; - const key2 = "Test2"; + const key = 'Test'; + const key2 = 'Test2'; let ran = false; - reaction(() => doc[key], (field) => { ran = true; }); + reaction( + () => doc[key], + field => { + ran = true; + } + ); expect(ran).to.equal(false); doc[key2] = 4; @@ -44,55 +48,55 @@ describe("Document", () => { }); const testSchema1 = createSchema({ - a: "number", - b: "string", - c: "boolean", + a: 'number', + b: 'string', + c: 'boolean', d: ImageField, - e: Doc + e: Doc, }); type TestDoc = makeInterface<[typeof testSchema1]>; const TestDoc = makeInterface(testSchema1); const testSchema2 = createSchema({ - a: defaultSpec("boolean", true), - b: defaultSpec("number", 5), - c: defaultSpec("string", "hello world") + a: defaultSpec('boolean', true), + b: defaultSpec('number', 5), + c: defaultSpec('string', 'hello world'), }); type TestDoc2 = makeInterface<[typeof testSchema2]>; const TestDoc2 = makeInterface(testSchema2); const testSchema3 = createSchema({ - a: TestDoc2 + a: TestDoc2, }); type TestDoc3 = makeInterface<[typeof testSchema3]>; const TestDoc3 = makeInterface(testSchema3); -describe("Schema", () => { - it("should do the right thing 1", () => { - const test1 = new Doc; - const test2 = new Doc; - const ifield = new ImageField(new URL("http://google.com")); +describe('Schema', () => { + it('should do the right thing 1', () => { + const test1 = new Doc(); + const test2 = new Doc(); + const ifield = new ImageField(new URL('http://google.com')); test1.a = 5; - test1.b = "hello"; + test1.b = 'hello'; test1.c = true; test1.d = ifield; test1.e = test2; const doc = TestDoc(test1); expect(doc.a).to.equal(5); - expect(doc.b).to.equal("hello"); + expect(doc.b).to.equal('hello'); expect(doc.c).to.equal(true); expect(doc.d).to.equal(ifield); expect(doc.e).to.equal(test2); }); - it("should do the right thing 2", () => { - const test1 = new Doc; - const test2 = new Doc; - const ifield = new ImageField(new URL("http://google.com")); - test1.a = "hello"; + it('should do the right thing 2', () => { + const test1 = new Doc(); + const test2 = new Doc(); + const ifield = new ImageField(new URL('http://google.com')); + test1.a = 'hello'; test1.b = 5; test1.c = test2; test1.d = true; @@ -105,11 +109,11 @@ describe("Schema", () => { expect(doc.e).to.equal(undefined); }); - it("should do the right thing 3", () => { - const test1 = new Doc; - const test2 = new Doc; - const ifield = new ImageField(new URL("http://google.com")); - test1.a = "hello"; + it('should do the right thing 3', () => { + const test1 = new Doc(); + const test2 = new Doc(); + const ifield = new ImageField(new URL('http://google.com')); + test1.a = 'hello'; test1.b = 5; test1.c = test2; test1.d = true; @@ -122,40 +126,40 @@ describe("Schema", () => { expect(doc.e).to.equal(undefined); }); - it("should do the right thing 4", () => { + it('should do the right thing 4', () => { const doc = TestDoc2(); expect(doc.a).to.equal(true); expect(doc.b).to.equal(5); - expect(doc.c).to.equal("hello world"); + expect(doc.c).to.equal('hello world'); - const d2 = new Doc; + const d2 = new Doc(); d2.a = false; d2.b = 4; - d2.c = "goodbye"; + d2.c = 'goodbye'; const doc2 = TestDoc2(d2); expect(doc2.a).to.equal(false); expect(doc2.b).to.equal(4); - expect(doc2.c).to.equal("goodbye"); + expect(doc2.c).to.equal('goodbye'); - const d3 = new Doc; - d3.a = "hello"; + const d3 = new Doc(); + d3.a = 'hello'; d3.b = false; d3.c = 5; const doc3 = TestDoc2(d3); expect(doc3.a).to.equal(true); expect(doc3.b).to.equal(5); - expect(doc3.c).to.equal("hello world"); + expect(doc3.c).to.equal('hello world'); }); - it("should do the right thing 5", async () => { - const test1 = new Doc; - const test2 = new Doc; + it('should do the right thing 5', async () => { + const test1 = new Doc(); + const test2 = new Doc(); const doc = TestDoc3(test1); expect(doc.a).to.equal(undefined); test1.a = test2; const doc2 = (await doc.a)!; expect(doc2.a).to.equal(true); expect(doc2.b).to.equal(5); - expect(doc2.c).to.equal("hello world"); + expect(doc2.c).to.equal('hello world'); }); }); -- cgit v1.2.3-70-g09d2 From fdc0bf7c54af252178f587709630d36726484b91 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 2 Jan 2024 13:26:53 -0500 Subject: fixing more .props => ._props refernces. --- src/client/util/BranchingTrailManager.tsx | 2 +- src/client/util/CaptureManager.tsx | 2 +- src/client/util/DictationManager.ts | 8 +-- src/client/util/DragManager.ts | 2 +- src/client/util/GroupMemberView.tsx | 29 +++++---- src/client/util/SelectionManager.ts | 10 +-- src/client/util/SharingManager.tsx | 2 +- src/client/util/TrackMovements.ts | 4 +- src/client/views/DocComponent.tsx | 3 +- src/client/views/DocumentButtonBar.tsx | 74 +++------------------- src/client/views/DocumentDecorations.tsx | 10 +-- src/client/views/FilterPanel.tsx | 18 ++++-- src/client/views/InkStrokeProperties.ts | 2 +- src/client/views/PropertiesButtons.tsx | 6 +- src/client/views/StyleProvider.tsx | 2 +- src/client/views/TemplateMenu.tsx | 6 +- .../views/collections/CollectionCarousel3DView.tsx | 4 +- .../views/collections/CollectionCarouselView.tsx | 2 +- .../views/collections/CollectionDockingView.tsx | 2 +- src/client/views/collections/CollectionMenu.tsx | 4 +- .../views/collections/CollectionNoteTakingView.tsx | 2 +- .../views/collections/CollectionPileView.tsx | 4 +- .../collections/CollectionStackedTimeline.tsx | 2 +- src/client/views/collections/TreeView.tsx | 6 +- .../CollectionFreeFormLinkView.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../collectionGrid/CollectionGridView.tsx | 72 ++++++++++----------- .../collectionMulticolumn/MulticolumnResizer.tsx | 11 +--- .../collectionMulticolumn/MultirowResizer.tsx | 11 +--- .../nodes/DataVizBox/components/LineChart.tsx | 6 +- .../views/nodes/DataVizBox/components/TableBox.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 16 ++--- src/client/views/nodes/MapBox/MapBox2.tsx | 34 +++++----- src/client/views/nodes/MapBox/MapPushpinBox.tsx | 4 +- .../views/nodes/MapboxMapBox/MapboxContainer.tsx | 54 ++++++++-------- .../nodes/PhysicsBox/PhysicsSimulationBox.tsx | 34 +++++----- .../views/nodes/RecordingBox/RecordingBox.tsx | 6 +- src/client/views/nodes/ScreenshotBox.tsx | 50 +++++++-------- src/client/views/nodes/ScriptingBox.tsx | 14 ++-- src/client/views/nodes/audio/AudioWaveform.tsx | 2 +- .../views/nodes/formattedText/DashDocView.tsx | 16 ++--- .../views/nodes/formattedText/EquationView.tsx | 4 +- .../views/nodes/formattedText/RichTextMenu.tsx | 16 ++--- .../views/nodes/importBox/ImportElementBox.tsx | 4 +- src/client/views/pdf/Annotation.tsx | 55 ++++++++-------- src/client/views/search/SearchBox.tsx | 10 +-- src/client/views/selectedDoc/SelectedDocView.tsx | 6 +- 47 files changed, 289 insertions(+), 350 deletions(-) (limited to 'src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx') diff --git a/src/client/util/BranchingTrailManager.tsx b/src/client/util/BranchingTrailManager.tsx index 11f16493f..02879e3c4 100644 --- a/src/client/util/BranchingTrailManager.tsx +++ b/src/client/util/BranchingTrailManager.tsx @@ -54,7 +54,7 @@ export class BranchingTrailManager extends React.Component { @observable private docIdToDocMap: Map = new Map(); observeDocumentChange = (targetDoc: Doc, pres: PresBox) => { - const presId = pres.props.Document[Id]; + const presId = pres.Document[Id]; if (this.prevPresId === presId) { return; } diff --git a/src/client/util/CaptureManager.tsx b/src/client/util/CaptureManager.tsx index c1e0a5b2e..2e13aff2f 100644 --- a/src/client/util/CaptureManager.tsx +++ b/src/client/util/CaptureManager.tsx @@ -84,7 +84,7 @@ export class CaptureManager extends React.Component<{}> { onClick={() => { const selected = SelectionManager.Views.slice(); SelectionManager.DeselectAll(); - selected.map(dv => dv.props.removeDocument?.(dv.props.Document)); + selected.map(dv => dv.props.removeDocument?.(dv.Document)); this.close(); }}> Cancel diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index 039bb360e..82c63695c 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -290,7 +290,7 @@ export namespace DictationManager { if (!ctor) { return false; } - return Cast(Doc.GetProto(view.props.Document).data, ctor) !== undefined; + return Cast(Doc.GetProto(view.Document).data, ctor) !== undefined; }; const validate = (target: DocumentView, types: DocumentType[]) => { @@ -318,7 +318,7 @@ export namespace DictationManager { [ 'clear', { - action: (target: DocumentView) => (Doc.GetProto(target.props.Document).data = new List()), + action: (target: DocumentView) => (Doc.GetProto(target.Document).data = new List()), restrictTo: [DocumentType.COL], }, ], @@ -347,7 +347,7 @@ export namespace DictationManager { action: (target: DocumentView, matches: RegExpExecArray) => { const count = interpretNumber(matches[1]); const what = matches[2]; - const dataDoc = Doc.GetProto(target.props.Document); + const dataDoc = Doc.GetProto(target.Document); const fieldKey = 'data'; if (isNaN(count)) { return; @@ -372,7 +372,7 @@ export namespace DictationManager { expression: /view as (freeform|stacking|masonry|schema|tree)/g, action: (target: DocumentView, matches: RegExpExecArray) => { const mode = matches[1]; - mode && (target.props.Document._type_collection = mode); + mode && (target.Document._type_collection = mode); }, restrictTo: [DocumentType.COL], } diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index fe3a52be7..9ede18ed5 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -142,7 +142,7 @@ export namespace DragManager { this.linkSourceGetAnchor = linkSourceGetAnchor; } get dragDocument() { - return this.linkDragView.props.Document; + return this.linkDragView.Document; } linkSourceGetAnchor: () => Doc; linkSourceDoc?: Doc; diff --git a/src/client/util/GroupMemberView.tsx b/src/client/util/GroupMemberView.tsx index 7de0f336f..894583711 100644 --- a/src/client/util/GroupMemberView.tsx +++ b/src/client/util/GroupMemberView.tsx @@ -19,35 +19,38 @@ interface GroupMemberViewProps { @observer export class GroupMemberView extends React.Component { @observable private memberSort: 'ascending' | 'descending' | 'none' = 'none'; + get group() { + return this.props.group; + } private get editingInterface() { - let members: string[] = this.props.group ? JSON.parse(StrCast(this.props.group.members)) : []; + let members: string[] = this.group ? JSON.parse(StrCast(this.group.members)) : []; members = this.memberSort === 'ascending' ? members.sort() : this.memberSort === 'descending' ? members.sort().reverse() : members; - const options: UserOptions[] = this.props.group ? GroupManager.Instance.options.filter(option => !(JSON.parse(StrCast(this.props.group.members)) as string[]).includes(option.value)) : []; + const options: UserOptions[] = this.group ? GroupManager.Instance.options.filter(option => !(JSON.parse(StrCast(this.group.members)) as string[]).includes(option.value)) : []; - const hasEditAccess = GroupManager.Instance.hasEditAccess(this.props.group); + const hasEditAccess = GroupManager.Instance.hasEditAccess(this.group); - return !this.props.group ? null : ( + return !this.group ? null : (
(this.props.group.title = e.currentTarget.value)} + value={StrCast(this.group.title || this.group.groupName)} + onChange={e => (this.group.title = e.currentTarget.value)} disabled={!hasEditAccess}>
- {GroupManager.Instance.hasEditAccess(this.props.group) ? ( + {GroupManager.Instance.hasEditAccess(this.group) ? (
diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx index ea99bff2e..c38c6dc4e 100644 --- a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx @@ -18,12 +18,8 @@ interface ResizerProps { select: (isCtrlPressed: boolean) => void; } -const resizerOpacity = 1; - @observer export default class ResizeBar extends React.Component { - @observable private isHoverActive = false; - @observable private isResizingActive = false; private _resizeUndo?: UndoManager.Batch; @action @@ -35,7 +31,6 @@ export default class ResizeBar extends React.Component { window.removeEventListener('pointerup', this.onPointerUp); window.addEventListener('pointermove', this.onPointerMove); window.addEventListener('pointerup', this.onPointerUp); - this.isResizingActive = true; this._resizeUndo = UndoManager.StartBatch('multcol resizing'); }; @@ -80,8 +75,6 @@ export default class ResizeBar extends React.Component { @action private onPointerUp = () => { - this.isResizingActive = false; - this.isHoverActive = false; window.removeEventListener('pointermove', this.onPointerMove); window.removeEventListener('pointerup', this.onPointerUp); this._resizeUndo?.end(); @@ -96,9 +89,7 @@ export default class ResizeBar extends React.Component { pointerEvents: this.props.isContentActive?.() ? 'all' : 'none', width: this.props.width, backgroundColor: !this.props.isContentActive?.() ? '' : this.props.styleProvider?.(undefined, undefined, StyleProp.WidgetColor), - }} - onPointerEnter={action(() => (this.isHoverActive = true))} - onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))}> + }}>
this.registerResizing(e)} />
); diff --git a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx index 7dee65e58..6f1b3b425 100644 --- a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx @@ -17,12 +17,8 @@ interface ResizerProps { toBottom?: Doc; } -const resizerOpacity = 1; - @observer export default class ResizeBar extends React.Component { - @observable private isHoverActive = false; - @observable private isResizingActive = false; private _resizeUndo?: UndoManager.Batch; @action @@ -33,7 +29,6 @@ export default class ResizeBar extends React.Component { window.removeEventListener('pointerup', this.onPointerUp); window.addEventListener('pointermove', this.onPointerMove); window.addEventListener('pointerup', this.onPointerUp); - this.isResizingActive = true; this._resizeUndo = UndoManager.StartBatch('multcol resizing'); }; @@ -78,8 +73,6 @@ export default class ResizeBar extends React.Component { @action private onPointerUp = () => { - this.isResizingActive = false; - this.isHoverActive = false; window.removeEventListener('pointermove', this.onPointerMove); window.removeEventListener('pointerup', this.onPointerUp); this._resizeUndo?.end(); @@ -94,9 +87,7 @@ export default class ResizeBar extends React.Component { pointerEvents: this.props.isContentActive?.() ? 'all' : 'none', height: this.props.height, backgroundColor: !this.props.isContentActive?.() ? '' : this.props.styleProvider?.(undefined, undefined, StyleProp.WidgetColor), - }} - onPointerEnter={action(() => (this.isHoverActive = true))} - onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))}> + }}>
this.registerResizing(e)} />
); diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx index a69f083d1..50a8bf83d 100644 --- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx +++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx @@ -358,7 +358,7 @@ export class LineChart extends ObservableReactComponent { const selectedPt = this._currSelected ? `{ ${this._props.axes[0]}: ${this._currSelected.x} ${this._props.axes[1]}: ${this._currSelected.y} }` : 'none'; if (this._lineChartData.length > 0 || !this.parentViz || this.parentViz.length == 0) { return this._props.axes.length >= 2 && /\d/.test(this._props.records[0][this._props.axes[0]]) && /\d/.test(this._props.records[0][this._props.axes[1]]) ? ( -
+
{
) : null} diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index f127fecf3..5365fe1b2 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -169,7 +169,7 @@ export class TableBox extends ObservableReactComponent { return (
{ if (this._props.layoutDoc && e.key === 'a' && (e.ctrlKey || e.metaKey)) { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index f8f4b94a2..d07824099 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -881,7 +881,7 @@ export class DocumentViewInternal extends DocComponent this._rootSelected; panelHeight = () => this._props.PanelHeight() - this.headerMargin; - screenToLocal = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin); + contentScreenToLocal = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin); onClickFunc: any = () => (this.disableClickScriptFunc ? undefined : this.onClickHandler); setHeight = (height: number) => !this._props.suppressSetHeight && (this.layoutDoc._height = height); setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view)); @@ -925,7 +925,7 @@ export class DocumentViewInternal extends DocComponent { } @observable _selected = false; - public get SELECTED() { + public get IsSelected() { return this._selected; } - public set SELECTED(val) { + public set IsSelected(val) { runInAction(() => (this._selected = val)); } @observable public static LongPress = false; @@ -1431,9 +1431,9 @@ export class DocumentView extends ObservableReactComponent { return this._props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.Document['link_anchor_2']) : this._props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.Document['link_anchor_1']) : undefined; } @computed get hideLinkButton() { - return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.HideLinkBtn + (this.SELECTED ? ':selected' : '')); + return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.HideLinkBtn + (this.IsSelected ? ':selected' : '')); } - hideLinkCount = () => this._props.renderDepth === -1 || (this.SELECTED && this._props.renderDepth) || !this._isHovering || this.hideLinkButton; + hideLinkCount = () => this._props.renderDepth === -1 || (this.IsSelected && this._props.renderDepth) || !this._isHovering || this.hideLinkButton; @computed get linkCountView() { return ; } @@ -1568,9 +1568,9 @@ export class DocumentView extends ObservableReactComponent { layout_fitWidthFunc = (doc: Doc) => BoolCast(this.layout_fitWidth); scaleToScreenSpace = () => (1 / (this._props.NativeDimScaling?.() || 1)) * this.screenToLocalTransform().Scale; docViewPathFunc = () => this.docViewPath; - isSelected = () => this.SELECTED; + isSelected = () => this.IsSelected; select = (extendSelection: boolean, focusSelection?: boolean) => { - if (this.SELECTED && SelectionManager.Views.length > 1) SelectionManager.DeselectView(this); + if (this.IsSelected && SelectionManager.Views.length > 1) SelectionManager.DeselectView(this); else { SelectionManager.SelectView(this, extendSelection); if (focusSelection) { diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx index 1dbbbb633..722a347f1 100644 --- a/src/client/views/nodes/MapBox/MapBox2.tsx +++ b/src/client/views/nodes/MapBox/MapBox2.tsx @@ -127,7 +127,7 @@ // private _ref: React.RefObject = React.createRef(); // componentDidMount() { -// this.props.setContentView?.(this); +// this._props.setContentView?.(this); // } // @action @@ -358,9 +358,9 @@ // e, // (e, down, delta) => // runInAction(() => { -// const localDelta = this.props +// const localDelta = this._props // .ScreenToLocalTransform() -// .scale(this.props.NativeDimScaling?.() || 1) +// .scale(this._props.NativeDimScaling?.() || 1) // .transformDirection(delta[0], delta[1]); // const fullWidth = NumCast(this.layoutDoc._width); // const mapWidth = fullWidth - this.sidebarWidth(); @@ -380,12 +380,12 @@ // ); // }; -// sidebarWidth = () => (Number(this.layout_sidebarWidthPercent.substring(0, this.layout_sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth(); +// sidebarWidth = () => (Number(this.layout_sidebarWidthPercent.substring(0, this.layout_sidebarWidthPercent.length - 1)) / 100) * this._props.PanelWidth(); // @computed get layout_sidebarWidthPercent() { // return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%'); // } // @computed get sidebarColor() { -// return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4')); +// return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this._props.fieldKey + '_backgroundColor'], '#e4e4e4')); // } // /** @@ -444,7 +444,7 @@ // key="sidebar" // title="Toggle Sidebar" // style={{ -// display: !this.props.isContentActive() ? 'none' : undefined, +// display: !this._props.isContentActive() ? 'none' : undefined, // top: StrCast(this.layoutDoc._layout_showTitle) === 'title' ? 20 : 5, // backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK, // }} @@ -481,7 +481,7 @@ // }; // pointerEvents = () => { -// return this.props.isContentActive() === false ? 'none' : this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.IsDragging ? undefined : 'none'; +// return this._props.isContentActive() === false ? 'none' : this._props.isContentActive() && this._props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.IsDragging ? undefined : 'none'; // }; // @computed get annotationLayer() { // return ( @@ -489,7 +489,7 @@ // {this.inlineTextAnnotations // .sort((a, b) => NumCast(a.y) - NumCast(b.y)) // .map(anno => ( -// +// // ))} //
// ); @@ -515,13 +515,13 @@ // // } // }; -// panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth(); -// panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); -// scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); -// transparentFilter = () => [...this.props.childFilters(), Utils.TransparentBackgroundFilter]; -// opaqueFilter = () => [...this.props.childFilters(), Utils.OpaqueBackgroundFilter]; -// infoWidth = () => this.props.PanelWidth() / 5; -// infoHeight = () => this.props.PanelHeight() / 5; +// panelWidth = () => this._props.PanelWidth() / (this._props.NativeDimScaling?.() || 1) - this.sidebarWidth(); +// panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); +// scrollXf = () => this._props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); +// transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; +// opaqueFilter = () => [...this._props.childFilters(), Utils.OpaqueBackgroundFilter]; +// infoWidth = () => this._props.PanelWidth() / 5; +// infoHeight = () => this._props.PanelHeight() / 5; // anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; // savedAnnotations = () => this._savedAnnotations; @@ -556,7 +556,7 @@ // .map(marker => ( // // () { } get mapBoxView() { - return this.props.DocumentView?.()?._props.docViewPath().lastElement()?.ComponentView as MapBox; + return this._props.DocumentView?.()?._props.docViewPath().lastElement()?.ComponentView as MapBox; } get mapBox() { - return this.props.DocumentView?.()._props.docViewPath().lastElement()?.Document; + return this._props.DocumentView?.()._props.docViewPath().lastElement()?.Document; } render() { diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx index 70037f29c..2c31bbab7 100644 --- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -89,7 +89,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent runInAction(() => { - const localDelta = this.props + const localDelta = this._props .ScreenToLocalTransform() - .scale(this.props.NativeDimScaling?.() || 1) + .scale(this._props.NativeDimScaling?.() || 1) .transformDirection(delta[0], delta[1]); const fullWidth = NumCast(this.layoutDoc._width); const mapWidth = fullWidth - this.sidebarWidth(); @@ -183,7 +183,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar map') ); }; - sidebarWidth = () => (Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth(); + sidebarWidth = () => (Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100) * this._props.PanelWidth(); /** * Handles toggle of sidebar on click the little comment button @@ -195,7 +195,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { - e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.Document; + e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this._props.Document; e.annoDragData.linkSourceDoc.followLinkZoom = false; } }, @@ -276,15 +276,15 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent this.addDocument(doc, annotationKey); - pointerEvents = () => (this.props.isContentActive() && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : 'none'); + pointerEvents = () => (this._props.isContentActive() && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : 'none'); - panelWidth = () => this.props.PanelWidth() / (this.props.NativeDimScaling?.() || 1) - this.sidebarWidth(); - panelHeight = () => this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); - scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); - transparentFilter = () => [...this.props.childFilters(), Utils.TransparentBackgroundFilter]; - opaqueFilter = () => [...this.props.childFilters(), Utils.OpaqueBackgroundFilter]; - infoWidth = () => this.props.PanelWidth() / 5; - infoHeight = () => this.props.PanelHeight() / 5; + panelWidth = () => this._props.PanelWidth() / (this._props.NativeDimScaling?.() || 1) - this.sidebarWidth(); + panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); + scrollXf = () => this._props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); + transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; + opaqueFilter = () => [...this._props.childFilters(), Utils.OpaqueBackgroundFilter]; + infoWidth = () => this._props.PanelWidth() / 5; + infoHeight = () => this._props.PanelHeight() / 5; anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; savedAnnotations = () => this._savedAnnotations; @@ -399,9 +399,9 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { - this.props.select(false); + this._props.select(false); this.deselectPin(); }; /* @@ -677,9 +677,9 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent ( {/* [this.props.PanelWidth(), this.props.PanelHeight()], this.setupSimulation, { fireImmediately: true }); + this._widthDisposer = reaction(() => [this._props.PanelWidth(), this._props.PanelHeight()], this.setupSimulation, { fireImmediately: true }); // Create walls this.wallPositions = [ { length: 100, xPos: 0, yPos: 0, angleInDegrees: 0 }, { length: 100, xPos: 0, yPos: 100, angleInDegrees: 0 }, { length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 }, - { length: 100, xPos: (this.xMax / this.props.PanelWidth()) * 100, yPos: 0, angleInDegrees: 90 }, + { length: 100, xPos: (this.xMax / this._props.PanelWidth()) * 100, yPos: 0, angleInDegrees: 90 }, ]; } - componentDidUpdate(prevProps: Readonly>) { + componentDidUpdate(prevProps: Readonly) { super.componentDidUpdate(prevProps); - if (this.xMax !== this.props.PanelWidth() * 0.6 || this.yMax != this.props.PanelHeight()) { - this.xMax = this.props.PanelWidth() * 0.6; - this.yMax = this.props.PanelHeight(); + if (this.xMax !== this._props.PanelWidth() * 0.6 || this.yMax != this._props.PanelHeight()) { + this.xMax = this._props.PanelWidth() * 0.6; + this.yMax = this._props.PanelHeight(); this.setupSimulation(); } } @@ -632,7 +632,7 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent { - const length = (300 * this.props.PanelWidth()) / 1000; + const length = (300 * this._props.PanelWidth()) / 1000; const angle = 30; const x = length * Math.cos(((90 - angle) * Math.PI) / 180); const y = length * Math.sin(((90 - angle) * Math.PI) / 180); @@ -808,8 +808,8 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
@@ -923,8 +923,8 @@ export class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
this.props.isContentActive() && e.stopPropagation()} - style={{ overflow: 'auto', height: `${Math.max(1, 800 / this.props.PanelWidth()) * 100}%`, transform: `scale(${Math.min(1, this.props.PanelWidth() / 850)})` }}> + onWheel={e => this._props.isContentActive() && e.stopPropagation()} + style={{ overflow: 'auto', height: `${Math.max(1, 800 / this._props.PanelWidth()) * 100}%`, transform: `scale(${Math.min(1, this._props.PanelWidth() / 850)})` }}>
{this.dataDoc.simulation_paused && this.simulationMode != 'Tutorial' && ( diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx index 658cfb1ca..c04a81f7d 100644 --- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx +++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx @@ -31,7 +31,7 @@ export class RecordingBox extends ViewBoxBaseComponent() { private _ref: React.RefObject = React.createRef(); componentDidMount() { - this.props.setContentView?.(this); + this._props.setContentView?.(this); Doc.SetNativeWidth(this.dataDoc, 1280); Doc.SetNativeHeight(this.dataDoc, 720); } @@ -49,7 +49,7 @@ export class RecordingBox extends ViewBoxBaseComponent() { this.dataDoc[this.fieldKey + '_duration'] = this.videoDuration; this.dataDoc.layout = VideoBox.LayoutString(this.fieldKey); - this.dataDoc[this.props.fieldKey] = new VideoField(this.result.accessPaths.client); + this.dataDoc[this._props.fieldKey] = new VideoField(this.result.accessPaths.client); this.dataDoc[this.fieldKey + '_recorded'] = true; // stringify the presentation and store it if (presentation?.movements) { @@ -135,7 +135,7 @@ export class RecordingBox extends ViewBoxBaseComponent() { @action public static addRecToWorkspace(value: RecordingBox) { let ffView = Array.from(DocumentManager.Instance.DocumentViews).find(view => view.ComponentView instanceof CollectionFreeFormView); - (ffView?.ComponentView as CollectionFreeFormView).props.addDocument?.(value.Document); + (ffView?.ComponentView as CollectionFreeFormView)._props.addDocument?.(value.Document); Doc.RemoveDocFromList(Doc.UserDoc(), 'workspaceRecordings', value.Document); Doc.RemFromMyOverlay(value.Document); Doc.UserDoc().currentRecording = undefined; diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 79ed69cdd..36527c311 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -47,8 +47,8 @@ declare class MediaRecorder { // _mesh: any = undefined; // render() { -// const topLeft = [this.props.x, this.props.y]; -// const raised = this.props.raised; +// const topLeft = [this._props.x, this._props.y]; +// const raised = this._props.raised; // const find = (raised: { coord: Vector2, off: Vector3 }[], what: Vector2) => raised.find(r => r.coord.x === what.x && r.coord.y === what.y); // const tl1 = find(raised, new Vector2(topLeft[0], topLeft[1] + 1)); // const tl2 = find(raised, new Vector2(topLeft[0] + 1, topLeft[1] + 1)); @@ -69,11 +69,11 @@ declare class MediaRecorder { // const normals = new Float32Array(quad_normals); // const uvs = new Float32Array(quad_uvs); // Each vertex has one uv coordinate for texture mapping // const indices = new Uint32Array(quad_indices); // Use the four vertices to draw the two triangles that make up the square. -// const popOut = () => NumCast(this.props.Document.popOut); -// const popOff = () => NumCast(this.props.Document.popOff); +// const popOut = () => NumCast(this.Document.popOut); +// const popOff = () => NumCast(this.Document.popOff); // return ( // { -// this.props.setRaised([ +// this._props.setRaised([ // { coord: new Vector2(topLeft[0], topLeft[1]), off: new Vector3(-popOff(), -popOff(), popOut()) }, // { coord: new Vector2(topLeft[0] + 1, topLeft[1]), off: new Vector3(popOff(), -popOff(), popOut()) }, // { coord: new Vector2(topLeft[0], topLeft[1] + 1), off: new Vector3(-popOff(), popOff(), popOut()) }, @@ -99,7 +99,7 @@ declare class MediaRecorder { // r?.setAttribute('uv', new BufferAttribute(uvs, 2)); // r?.setIndex(new BufferAttribute(indices, 1)); // }} /> -// {!this._videoRef ? : +// {!this._videoRef ? : // // // } @@ -118,7 +118,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent ({ width: this.props.PanelWidth(), height: this.props.PanelHeight() }), + this._props.setContentView?.(this); // this tells the DocumentView that this ScreenshotBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link. + // this.layoutDoc.videoWall && reaction(() => ({ width: this._props.PanelWidth(), height: this._props.PanelHeight() }), // ({ width, height }) => { // if (this._camera) { // const angle = -Math.abs(1 - width / height); @@ -201,7 +201,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent numberRange(this._numScreens).forEach(y => screens.push( // ))); - // return { + // return { // this._camera = props.camera; // props.camera.position.set(this._numScreens / 2, this._numScreens / 2, this._numScreens - 2); // props.camera.lookAt(this._numScreens / 2, this._numScreens / 2, 0); @@ -224,15 +224,15 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent { const [{ result }] = await Networking.UploadFilesToServer(aud_chunks.map((file: any) => ({ file }))); if (!(result instanceof Error)) { - this.dataDoc[this.props.fieldKey + '_audio'] = new AudioField(result.accessPaths.agnostic.client); + this.dataDoc[this._props.fieldKey + '_audio'] = new AudioField(result.accessPaths.agnostic.client); } }; this._videoRef!.srcObject = await (navigator.mediaDevices as any).getDisplayMedia({ video: true }); this._videoRec = new MediaRecorder(this._videoRef!.srcObject); const vid_chunks: any = []; this._videoRec.onstart = () => { - if (this.dataDoc[this.props.fieldKey + '_trackScreen']) TrackMovements.Instance.start(); - this.dataDoc[this.props.fieldKey + '_recordingStart'] = new DateField(new Date()); + if (this.dataDoc[this._props.fieldKey + '_trackScreen']) TrackMovements.Instance.start(); + this.dataDoc[this._props.fieldKey + '_recordingStart'] = new DateField(new Date()); }; this._videoRec.ondataavailable = (e: any) => vid_chunks.push(e.data); this._videoRec.onstop = async (e: any) => { @@ -252,7 +252,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent (NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], NumCast(this.layoutDoc._height)) / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], NumCast(this.layoutDoc._width))) * this.props.PanelWidth(); - formattedPanelHeight = () => Math.max(0, this.props.PanelHeight() - this.videoPanelHeight()); + videoPanelHeight = () => (NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], NumCast(this.layoutDoc._height)) / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], NumCast(this.layoutDoc._width))) * this._props.PanelWidth(); + formattedPanelHeight = () => Math.max(0, this._props.PanelHeight() - this.videoPanelHeight()); render() { TraceMobx(); return ( @@ -296,14 +296,14 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent
+ ScreenToLocalTransform={this._props.ScreenToLocalTransform} + renderDepth={this._props.renderDepth + 1}> <> {this.threed} {this.content} @@ -324,7 +324,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent {!(this.dataDoc[this.fieldKey + '_dictation'] instanceof Doc) ? null : ( )}
- {!this.props.isSelected() ? null : ( + {!this._props.isSelected() ? null : (
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index 8e506ec64..73ad3a004 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -60,7 +60,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent !p.startsWith('_')) @@ -116,7 +116,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent { @@ -294,7 +294,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent { const copy = Doc.MakeCopy(this.Document, true); copy.x = NumCast(this.Document.x) + NumCast(this.dataDoc._width); - this.props.addDocument?.(copy); + this._props.addDocument?.(copy); }; // adds option to create a copy to the context menu @@ -310,7 +310,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent (this.functionName = e.target.value)} placeholder="enter name here" value={this.functionName} />; return ( -
this.props.isSelected() && e.stopPropagation()}> +
this._props.isSelected() && e.stopPropagation()}>
@@ -687,7 +687,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent this.props.isSelected() && e.stopPropagation()}> +
this._props.isSelected() && e.stopPropagation()}>
{this.renderScriptingBox} {definedParameters} @@ -745,7 +745,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent this.props.isSelected() && e.stopPropagation()}> +
this._props.isSelected() && e.stopPropagation()}> {!this.compileParams.length || !this.paramsNames ? null : (
{this.paramsNames.map((parameter: string, i: number) => ( @@ -812,7 +812,7 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent -
this.props.isSelected() && e.stopPropagation()}> +
this._props.isSelected() && e.stopPropagation()}> {this._paramSuggestion ? (
{' '} diff --git a/src/client/views/nodes/audio/AudioWaveform.tsx b/src/client/views/nodes/audio/AudioWaveform.tsx index 3e46ff4e6..7fd799952 100644 --- a/src/client/views/nodes/audio/AudioWaveform.tsx +++ b/src/client/views/nodes/audio/AudioWaveform.tsx @@ -109,7 +109,7 @@ export class AudioWaveform extends ObservableReactComponent progressColor={Colors.MEDIUM_BLUE_ALT} progress={this._props.progress ?? 1} barWidth={200 / this.audioBuckets.length} - //gradientColors={this.props.gradientColors} + //gradientColors={this._props.gradientColors} peaks={this.audioBuckets} width={(this._props.PanelWidth ?? 0) * window.devicePixelRatio} height={this.waveHeight * window.devicePixelRatio} diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 1002ee403..5a13fa8b4 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -177,7 +177,7 @@ export class DashDocViewInternal extends React.Component { }; componentWillUnmount = () => Object.values(this._disposers).forEach(disposer => disposer?.()); - isContentActive = () => this.props.tbox.props.isSelected() || this.props.tbox.isAnyChildContentActive?.(); + isContentActive = () => this.props.tbox._props.isSelected() || this.props.tbox.isAnyChildContentActive?.(); render() { return !this._dashDoc || !this._finalLayout || this.props.hidden ? null : ( @@ -205,21 +205,21 @@ export class DashDocViewInternal extends React.Component { removeDocument={this.removeDoc} isDocumentActive={returnFalse} isContentActive={this.isContentActive} - styleProvider={this._textBox.props.styleProvider} - docViewPath={this._textBox.props.docViewPath} + styleProvider={this._textBox._props.styleProvider} + docViewPath={this._textBox._props.docViewPath} ScreenToLocalTransform={this.getDocTransform} - addDocTab={this._textBox.props.addDocTab} + addDocTab={this._textBox._props.addDocTab} pinToPres={returnFalse} - renderDepth={this._textBox.props.renderDepth + 1} + renderDepth={this._textBox._props.renderDepth + 1} PanelWidth={this._finalLayout[Width]} PanelHeight={this._finalLayout[Height]} focus={this.outerFocus} whenChildContentsActiveChanged={this.props.tbox.whenChildContentsActiveChanged} bringToFront={emptyFunction} dontRegisterView={false} - childFilters={this.props.tbox?.props.childFilters} - childFiltersByRanges={this.props.tbox?.props.childFiltersByRanges} - searchFilterDocs={this.props.tbox?.props.searchFilterDocs} + childFilters={this.props.tbox?._props.childFilters} + childFiltersByRanges={this.props.tbox?._props.childFiltersByRanges} + searchFilterDocs={this.props.tbox?._props.searchFilterDocs} />
); diff --git a/src/client/views/nodes/formattedText/EquationView.tsx b/src/client/views/nodes/formattedText/EquationView.tsx index 7e655531e..b786c5ffb 100644 --- a/src/client/views/nodes/formattedText/EquationView.tsx +++ b/src/client/views/nodes/formattedText/EquationView.tsx @@ -65,8 +65,8 @@ export class EquationViewInternal extends React.Component constructor(props: any) { super(props); - this._fieldKey = this.props.fieldKey; - this._textBoxDoc = this.props.tbox.props.Document; + this._fieldKey = props.fieldKey; + this._textBoxDoc = props.tbox.Document; } componentWillUnmount() { diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 3b31f2d17..5858c3b11 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -186,7 +186,7 @@ export class RichTextMenu extends AntimodeMenu { // finds font sizes and families in selection getActiveAlignment() { - if (this.view && this.TextView?.props.rootSelected?.()) { + if (this.view && this.TextView?._props.rootSelected?.()) { const path = (this.view.state.selection.$from as any).path; for (let i = path.length - 3; i < path.length && i >= 0; i -= 3) { if (path[i]?.type === this.view.state.schema.nodes.paragraph || path[i]?.type === this.view.state.schema.nodes.heading) { @@ -199,7 +199,7 @@ export class RichTextMenu extends AntimodeMenu { // finds font sizes and families in selection getActiveListStyle() { - if (this.view && this.TextView?.props.rootSelected?.()) { + if (this.view && this.TextView?._props.rootSelected?.()) { const path = (this.view.state.selection.$from as any).path; for (let i = 0; i < path.length; i += 3) { if (path[i].type === this.view.state.schema.nodes.ordered_list) { @@ -219,7 +219,7 @@ export class RichTextMenu extends AntimodeMenu { const activeSizes = new Set(); const activeColors = new Set(); const activeHighlights = new Set(); - if (this.view && this.TextView?.props.rootSelected?.()) { + if (this.view && this.TextView?._props.rootSelected?.()) { const state = this.view.state; const pos = this.view.state.selection.$from; const marks: Mark[] = [...(state.storedMarks ?? [])]; @@ -254,7 +254,7 @@ export class RichTextMenu extends AntimodeMenu { //finds all active marks on selection in given group getActiveMarksOnSelection() { let activeMarks: MarkType[] = []; - if (!this.view || !this.TextView?.props.rootSelected?.()) return activeMarks; + if (!this.view || !this.TextView?._props.rootSelected?.()) return activeMarks; const markGroup = [schema.marks.noAutoLinkAnchor, schema.marks.strong, schema.marks.em, schema.marks.underline, schema.marks.strikethrough, schema.marks.superscript, schema.marks.subscript]; if (this.view.state.storedMarks) return this.view.state.storedMarks.map(mark => mark.type); @@ -447,7 +447,7 @@ export class RichTextMenu extends AntimodeMenu { this.layoutDoc && (this.layoutDoc.layout_centered = !this.layoutDoc.layout_centered); }; align = (view: EditorView, dispatch: any, alignment: 'left' | 'right' | 'center') => { - if (this.TextView?.props.rootSelected?.()) { + if (this.TextView?._props.rootSelected?.()) { var tr = view.state.tr; view.state.doc.nodesBetween(view.state.selection.from, view.state.selection.to, (node, pos, parent, index) => { if ([schema.nodes.paragraph, schema.nodes.heading].includes(node.type)) { @@ -581,7 +581,7 @@ export class RichTextMenu extends AntimodeMenu { return (this.view as any)?.TextView as FormattedTextBox; } get TextViewFieldKey() { - return this.TextView?.props.fieldKey; + return this.TextView?._props.fieldKey; } @action setActiveHighlight(color: string) { @@ -774,11 +774,11 @@ export class RichTextMenu extends AntimodeMenu { //
// {[this.createMarksDropdown(this.activeFontSize, this.fontSizeOptions, "font size", action((val: string) => { // this.activeFontSize = val; - // SelectionManager.Views.map(dv => dv.props.Document._text_fontSize = val); + // SelectionManager.Views.map(dv => dv.Document._text_fontSize = val); // })), // this.createMarksDropdown(this.activeFontFamily, this.fontFamilyOptions, "font family", action((val: string) => { // this.activeFontFamily = val; - // SelectionManager.Views.map(dv => dv.props.Document._text_fontFamily = val); + // SelectionManager.Views.map(dv => dv.Document._text_fontFamily = val); // })), //
, // this.createNodesDropdown(this.activeListType, this.listTypeOptions, "list type", () => ({})), diff --git a/src/client/views/nodes/importBox/ImportElementBox.tsx b/src/client/views/nodes/importBox/ImportElementBox.tsx index b573f7c48..1a92acea1 100644 --- a/src/client/views/nodes/importBox/ImportElementBox.tsx +++ b/src/client/views/nodes/importBox/ImportElementBox.tsx @@ -13,12 +13,12 @@ export class ImportElementBox extends ViewBoxBaseComponent() { return FieldView.LayoutString(ImportElementBox, fieldKey); } - screenToLocalXf = () => this.props.ScreenToLocalTransform().scale(1 * (this.props.NativeDimScaling?.() || 1)); + screenToLocalXf = () => this._props.ScreenToLocalTransform().scale(1 * (this._props.NativeDimScaling?.() || 1)); @computed get mainItem() { return (
Opt; } @observer -export class Annotation extends React.Component { +export class Annotation extends ObservableReactComponent { + constructor(props: any) { + super(props); + makeObservable(this); + } render() { return ( -
- {DocListCast(this.props.anno.text_inlineAnnotations).map(a => ( - +
+ {DocListCast(this._props.anno.text_inlineAnnotations).map(a => ( + ))}
); @@ -38,23 +43,23 @@ interface IRegionAnnotationProps extends IAnnotationProps { pointerEvents?: () => Opt; } @observer -class RegionAnnotation extends React.Component { +class RegionAnnotation extends ObservableReactComponent { private _mainCont: React.RefObject = React.createRef(); @computed get annoTextRegion() { - return Cast(this.props.document.annoTextRegion, Doc, null) || this.props.document; + return Cast(this._props.document.annoTextRegion, Doc, null) || this._props.document; } @undoBatch deleteAnnotation = () => { - const docAnnotations = DocListCast(this.props.dataDoc[this.props.fieldKey]); - this.props.dataDoc[this.props.fieldKey] = new List(docAnnotations.filter(a => a !== this.annoTextRegion)); + const docAnnotations = DocListCast(this._props.dataDoc[this._props.fieldKey]); + this._props.dataDoc[this._props.fieldKey] = new List(docAnnotations.filter(a => a !== this.annoTextRegion)); AnchorMenu.Instance.fadeOut(true); - this.props.select(false); + this._props.select(false); }; @undoBatch - pinToPres = () => this.props.pinToPres(this.annoTextRegion, {}); + pinToPres = () => this._props.pinToPres(this.annoTextRegion, {}); @undoBatch makeTargretToggle = () => (this.annoTextRegion.followLinkToggle = !this.annoTextRegion.followLinkToggle); @@ -65,7 +70,7 @@ class RegionAnnotation extends React.Component { const trail = DocCast(anchor.presentationTrail); if (trail) { Doc.ActivePresentation = trail; - this.props.addDocTab(trail, OpenWhere.replaceRight); + this._props.addDocTab(trail, OpenWhere.replaceRight); } }; @@ -94,9 +99,9 @@ class RegionAnnotation extends React.Component { }; @computed get linkHighlighted() { - for (const link of LinkManager.Instance.getAllDirectLinks(this.props.document)) { - const a1 = LinkManager.getOppositeAnchor(link, this.props.document); - if (a1 && Doc.GetBrushStatus(DocCast(a1.annotationOn, this.props.document))) return true; + for (const link of LinkManager.Instance.getAllDirectLinks(this._props.document)) { + const a1 = LinkManager.getOppositeAnchor(link, this._props.document); + if (a1 && Doc.GetBrushStatus(DocCast(a1.annotationOn, this._props.document))) return true; } } @@ -107,24 +112,24 @@ class RegionAnnotation extends React.Component { className="htmlAnnotation" ref={this._mainCont} onPointerEnter={action(() => { - Doc.BrushDoc(this.props.anno); - this.props.showInfo?.(this.props.anno); + Doc.BrushDoc(this._props.anno); + this._props.showInfo?.(this._props.anno); })} onPointerLeave={action(() => { - Doc.UnBrushDoc(this.props.anno); - this.props.showInfo?.(undefined); + Doc.UnBrushDoc(this._props.anno); + this._props.showInfo?.(undefined); })} onPointerDown={this.onPointerDown} onContextMenu={this.onContextMenu} style={{ - left: NumCast(this.props.document.x), - top: NumCast(this.props.document.y), - width: NumCast(this.props.document._width), - height: NumCast(this.props.document._height), + left: NumCast(this._props.document.x), + top: NumCast(this._props.document.y), + width: NumCast(this._props.document._width), + height: NumCast(this._props.document._height), opacity: brushed === Doc.DocBrushStatus.highlighted ? 0.5 : undefined, - pointerEvents: this.props.pointerEvents?.() as any, + pointerEvents: this._props.pointerEvents?.() as any, outline: brushed === Doc.DocBrushStatus.unbrushed && this.linkHighlighted ? 'solid 1px lightBlue' : undefined, - backgroundColor: brushed === Doc.DocBrushStatus.highlighted ? 'orange' : StrCast(this.props.document.backgroundColor), + backgroundColor: brushed === Doc.DocBrushStatus.highlighted ? 'orange' : StrCast(this._props.document.backgroundColor), }} /> ); diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 14187833f..4d29573d4 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -122,10 +122,10 @@ export class SearchBox extends ViewBoxBaseComponent() { @undoBatch makeLink = action((linkTo: Doc) => { - const linkFrom = this.props.linkCreateAnchor?.(); + const linkFrom = this._props.linkCreateAnchor?.(); if (linkFrom) { const link = DocUtils.MakeLink(linkFrom, linkTo, {}); - link && this.props.linkCreated?.(link); + link && this._props.linkCreated?.(link); } }); @@ -292,7 +292,7 @@ export class SearchBox extends ViewBoxBaseComponent() { const query = StrCast(this._searchString); Doc.SetSearchQuery(query); - if (!this.props.linkSearch) Array.from(this._results.keys()).forEach(doc => DocumentManager.Instance.getFirstDocumentView(doc)?.ComponentView?.search?.(this._searchString, undefined, true)); + if (!this._props.linkSearch) Array.from(this._results.keys()).forEach(doc => DocumentManager.Instance.getFirstDocumentView(doc)?.ComponentView?.search?.(this._searchString, undefined, true)); this._results.clear(); if (query) { @@ -375,13 +375,13 @@ export class SearchBox extends ViewBoxBaseComponent() { render() { var validResults = 0; - const isLinkSearch: boolean = this.props.linkSearch; + const isLinkSearch: boolean = this._props.linkSearch; const sortedResults = Array.from(this._results.entries()).sort((a, b) => (this._pageRanks.get(b[0]) ?? 0) - (this._pageRanks.get(a[0]) ?? 0)); // sorted by page rank const resultsJSX = Array(); - const fromDoc = this.props.linkFrom?.(); + const fromDoc = this._props.linkFrom?.(); sortedResults.forEach(result => { var className = 'searchBox-results-scroll-view-result'; diff --git a/src/client/views/selectedDoc/SelectedDocView.tsx b/src/client/views/selectedDoc/SelectedDocView.tsx index daacb368b..39e778b76 100644 --- a/src/client/views/selectedDoc/SelectedDocView.tsx +++ b/src/client/views/selectedDoc/SelectedDocView.tsx @@ -1,14 +1,14 @@ +import * as React from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ListBox } from 'browndash-components'; import { computed } from 'mobx'; import { observer } from 'mobx-react'; -import * as React from 'react'; -import { emptyFunction } from '../../../Utils'; import { Doc } from '../../../fields/Doc'; import { StrCast } from '../../../fields/Types'; import { DocumentManager } from '../../util/DocumentManager'; -import { SettingsManager } from '../../util/SettingsManager'; import { DocFocusOptions } from '../nodes/DocumentView'; +import { emptyFunction } from '../../../Utils'; +import { SettingsManager } from '../../util/SettingsManager'; export interface SelectedDocViewProps { selectedDocs: Doc[]; -- cgit v1.2.3-70-g09d2 From 2ea594a4c1ff221200e0795fb07d30b603177a67 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 3 Jan 2024 23:44:28 -0500 Subject: cleaned up screenToLocalTransform in several places by making it additional methods. cleaned up styleProider api a bit to take DocumentViewInternalProps, not DocumentViewProps.. --- src/client/util/HypothesisUtils.ts | 2 +- src/client/views/DocComponent.tsx | 10 ++ src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/DocumentDecorations.tsx | 16 +-- src/client/views/GestureOverlay.tsx | 2 +- src/client/views/GlobalKeyHandler.ts | 4 +- src/client/views/InkingStroke.tsx | 23 ++--- src/client/views/MarqueeAnnotator.tsx | 2 +- src/client/views/StyleProvider.tsx | 13 +-- .../views/collections/CollectionCarouselView.tsx | 5 +- .../views/collections/CollectionNoteTakingView.tsx | 18 ++-- .../collections/CollectionStackedTimeline.tsx | 11 ++- .../views/collections/CollectionStackingView.tsx | 12 +-- .../views/collections/CollectionTimeView.tsx | 1 - .../views/collections/CollectionTreeView.tsx | 4 +- src/client/views/collections/CollectionView.tsx | 2 +- src/client/views/collections/TabDocView.tsx | 7 +- src/client/views/collections/TreeView.tsx | 18 ++-- .../CollectionFreeFormLinkView.tsx | 10 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 94 +++++++++--------- .../collectionGrid/CollectionGridView.tsx | 6 +- .../CollectionMulticolumnView.tsx | 2 +- .../CollectionMultirowView.tsx | 2 +- .../collectionSchema/CollectionSchemaView.tsx | 21 ++-- src/client/views/nodes/AudioBox.tsx | 4 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 9 +- src/client/views/nodes/ComparisonBox.tsx | 6 +- .../views/nodes/DataVizBox/components/TableBox.tsx | 2 +- src/client/views/nodes/DocumentLinksButton.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 48 +++++---- src/client/views/nodes/ImageBox.tsx | 6 +- src/client/views/nodes/LinkBox.tsx | 10 +- src/client/views/nodes/MapBox/MapBox.tsx | 8 +- src/client/views/nodes/MapBox/MapBox2.tsx | 2 +- .../views/nodes/MapboxMapBox/MapboxContainer.tsx | 6 +- src/client/views/nodes/PDFBox.tsx | 2 +- src/client/views/nodes/ScreenshotBox.tsx | 1 - src/client/views/nodes/VideoBox.tsx | 6 +- src/client/views/nodes/WebBox.tsx | 12 +-- .../views/nodes/formattedText/FormattedTextBox.tsx | 109 +-------------------- .../views/nodes/importBox/ImportElementBox.tsx | 2 +- src/client/views/nodes/trails/PresBox.tsx | 4 +- src/client/views/nodes/trails/PresElementBox.tsx | 4 +- src/client/views/pdf/PDFViewer.tsx | 15 +-- 44 files changed, 230 insertions(+), 315 deletions(-) (limited to 'src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx') diff --git a/src/client/util/HypothesisUtils.ts b/src/client/util/HypothesisUtils.ts index 0ae23d793..f46c2d431 100644 --- a/src/client/util/HypothesisUtils.ts +++ b/src/client/util/HypothesisUtils.ts @@ -180,7 +180,7 @@ export namespace Hypothesis { }) ); const targetView: Opt = DocumentManager.Instance.getFirstDocumentView(target); - const position = targetView?.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); + const position = targetView?.screenToViewTransform().inverse().transformPoint(0, 0); targetView && position && simulateMouseClick(targetView.ContentDiv!, position[0], position[1], position[0], position[1], false); }, 300); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index b5bd17572..dfc298840 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -12,12 +12,14 @@ import { DocumentManager } from '../util/DocumentManager'; import { ObservableReactComponent } from './ObservableReactComponent'; import { CollectionFreeFormView } from './collections/collectionFreeForm'; import { DocumentView } from './nodes/DocumentView'; +import { Transform } from '../util/Transform'; /// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView) export interface DocComponentProps { Document: Doc; LayoutTemplate?: () => Opt; LayoutTemplateString?: string; + ScreenToLocalTransform: () => Transform; } export function DocComponent

() { class Component extends ObservableReactComponent> { @@ -26,6 +28,8 @@ export function DocComponent

() { makeObservable(this); } + ScreenToLocalBoxXf = () => this._props.ScreenToLocalTransform(); + //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then get Document() { return this._props.Document; @@ -50,10 +54,13 @@ interface ViewBoxBaseProps { fieldKey: string; isSelected: () => boolean; isContentActive: () => boolean | undefined; + ScreenToLocalTransform: () => Transform; renderDepth: number; } export function ViewBoxBaseComponent

() { class Component extends ObservableReactComponent> { + ScreenToLocalBoxXf = () => this._props.ScreenToLocalTransform(); + //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then get Document() { return this._props.Document; @@ -83,6 +90,7 @@ export interface ViewBoxAnnotatableProps { isContentActive: () => boolean | undefined; select: (isCtrlPressed: boolean) => void; whenChildContentsActiveChanged: (isActive: boolean) => void; + ScreenToLocalTransform: () => Transform; isSelected: () => boolean; renderDepth: number; isAnnotationOverlay?: boolean; @@ -94,6 +102,8 @@ export function ViewBoxAnnotatableComponent

() makeObservable(this); } + ScreenToLocalBoxXf = () => this._props.ScreenToLocalTransform(); + @observable _annotationKeySuffix = () => 'annotations'; @observable _isAnyChildContentActive = false; //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index e6d53e727..bb28d9ec9 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -305,7 +305,7 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => ( if (this._dragRef.current) { const dragDocView = this.view0!; const dragData = new DragManager.DocumentDragData([dragDocView.Document]); - const [left, top] = dragDocView.screenToNativeLocalTransform().inverse().transformPoint(0, 0); + const [left, top] = dragDocView.screenToContentsTransform().inverse().transformPoint(0, 0); dragData.defaultDropAction = 'embed'; dragData.canEmbed = true; DragManager.StartDocumentDrag([dragDocView.ContentDiv!], dragData, left, top, { hideSource: false }); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 583a7c447..ced8799bf 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -77,7 +77,7 @@ export class DocumentDecorations extends ObservableReactComponent center.x+x || this.Bounds.r < center.x+x || this.Bounds.y > center.y+y || this.Bounds.b < center.y+y ))); @@ -208,7 +208,7 @@ export class DocumentDecorations extends ObservableReactComponent dv.Document), dragDocView._props.dropAction ); - dragData.offset = dragDocView.screenToNativeLocalTransform().transformDirection(e.x - left, e.y - top); + dragData.offset = dragDocView.screenToContentsTransform().transformDirection(e.x - left, e.y - top); dragData.moveDocument = dragDocView._props.moveDocument; dragData.removeDocument = dragDocView._props.removeDocument; dragData.isDocDecorationMove = true; @@ -353,7 +353,7 @@ export class DocumentDecorations extends ObservableReactComponent { - const newloccentern = seldocview.screenToNativeLocalTransform().transformPoint(rotCenter[0], rotCenter[1]); + const newloccentern = seldocview.screenToContentsTransform().transformPoint(rotCenter[0], rotCenter[1]); const newlocenter = [newloccentern[0] - NumCast(seldocview.layoutDoc._width) / 2, newloccentern[1] - NumCast(seldocview.layoutDoc._height) / 2]; const final = Utils.rotPt(newlocenter[0], newlocenter[1], -(NumCast(seldocview.Document._rotation) / 180) * Math.PI); seldocview.Document.rotation_centerX = final.x / NumCast(seldocview.layoutDoc._width); @@ -385,7 +385,7 @@ export class DocumentDecorations extends ObservableReactComponent { const accumRot = (NumCast(dv.Document._rotation) / 180) * Math.PI; - const localRotCtr = dv._props.ScreenToLocalTransform().transformPoint(rcScreen.X, rcScreen.Y); + const localRotCtr = dv.screenToViewTransform().transformPoint(rcScreen.X, rcScreen.Y); const localRotCtrOffset = [localRotCtr[0] - NumCast(dv.Document.width) / 2, localRotCtr[1] - NumCast(dv.Document.height) / 2]; const startRotCtr = Utils.rotPt(localRotCtrOffset[0], localRotCtrOffset[1], -accumRot); const unrotatedDocPos = { x: NumCast(dv.Document.x) + localRotCtrOffset[0] - startRotCtr.x, y: NumCast(dv.Document.y) + localRotCtrOffset[1] - startRotCtr.y }; @@ -462,7 +462,7 @@ export class DocumentDecorations extends ObservableReactComponent { @@ -530,7 +530,7 @@ export class DocumentDecorations extends ObservableReactComponent 135 && seldocview.CollectionFreeFormDocumentView; const useRotation = !hideResizers && seldocview.Document.type !== DocumentType.EQUATION && seldocview.CollectionFreeFormDocumentView; // when do we want an object to not rotate? - const rotation = SelectionManager.Views.length == 1 ? seldocview.screenToNativeLocalTransform().inverse().RotateDeg : 0; + const rotation = SelectionManager.Views.length == 1 ? seldocview.screenToContentsTransform().inverse().RotateDeg : 0; // Radius constants const useRounding = seldocview.ComponentView instanceof ImageBox || seldocview.ComponentView instanceof FormattedTextBox || seldocview.ComponentView instanceof CollectionFreeFormView; diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 65aadc148..b1b04237c 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -385,7 +385,7 @@ export class GestureOverlay extends ObservableReactComponent dv.Document[Id]).join(':'); SelectionManager.Views.length && navigator.clipboard.writeText(text); DocumentDecorations.Instance.onCloseClick(true); @@ -312,7 +312,7 @@ export class KeyManager { case 'c': if ((document.activeElement as any)?.type !== 'text' && !AnchorMenu.Instance.Active && DocumentDecorations.Instance.Bounds.r - DocumentDecorations.Instance.Bounds.x > 2) { const bds = DocumentDecorations.Instance.Bounds; - const pt = SelectionManager.Views[0].props.ScreenToLocalTransform().transformPoint(bds.x + (bds.r - bds.x) / 2, bds.y + (bds.b - bds.y) / 2); + const pt = SelectionManager.Views[0].screenToViewTransform().transformPoint(bds.x + (bds.r - bds.x) / 2, bds.y + (bds.b - bds.y) / 2); const text = `__DashCloneId(${pt?.[0] || 0},${pt?.[1] || 0}):` + SelectionManager.Views.map(dv => dv.Document[Id]).join(':'); SelectionManager.Views.length && navigator.clipboard.writeText(text); stopPropagation = false; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 95c677845..c652e8966 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -45,6 +45,7 @@ import { FieldView, FieldViewProps } from './nodes/FieldView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { PinProps, PresBox } from './nodes/trails'; import { StyleProp } from './StyleProvider'; +import { Transform } from '../util/Transform'; const { default: { INK_MASK_SIZE } } = require('./global/globalCssVariables.module.scss'); // prettier-ignore @observer export class InkingStroke extends ViewBoxBaseComponent() { @@ -73,10 +74,6 @@ export class InkingStroke extends ViewBoxBaseComponent() { Object.keys(this._disposers).forEach(key => this._disposers[key]()); } - // transform is the inherited screentolocal xf plus any scaling that was done to make the stroke - // fit within its panel (e.g., for content fitting views like Lightbox or multicolumn, etc) - screenToLocal = () => this._props.ScreenToLocalTransform().scale(this._props.NativeDimScaling?.() || 1); - getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { const subAnchor = this._subContentView?.getAnchor?.(addAsAnnotation); if (subAnchor !== this.Document && subAnchor) return subAnchor; @@ -129,7 +126,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); const screenPts = inkData .map(point => - this.screenToLocal() + this.ScreenToLocalBoxXf() .inverse() .transformPoint((point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2) ) @@ -181,7 +178,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { */ ptFromScreen = (scrPt: { X: number; Y: number }) => { const { inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); - const docPt = this.screenToLocal().transformPoint(scrPt.X, scrPt.Y); + const docPt = this.ScreenToLocalBoxXf().transformPoint(scrPt.X, scrPt.Y); const inkPt = { X: (docPt[0] - inkStrokeWidth / 2) / inkScaleX + inkStrokeWidth / 2 + inkLeft, Y: (docPt[1] - inkStrokeWidth / 2) / inkScaleY + inkStrokeWidth / 2 + inkTop, @@ -199,7 +196,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { X: (inkPt.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, Y: (inkPt.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2, }; - const scrPt = this.screenToLocal().inverse().transformPoint(docPt.X, docPt.Y); + const scrPt = this.ScreenToLocalBoxXf().inverse().transformPoint(docPt.X, docPt.Y); return { X: scrPt[0], Y: scrPt[1] }; }; @@ -213,7 +210,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { snapPt = (scrPt: { X: number; Y: number }, excludeSegs?: number[]) => { const { inkData } = this.inkScaledData(); const { nearestPt, distance } = InkStrokeProperties.nearestPtToStroke(inkData, this.ptFromScreen(scrPt), excludeSegs ?? []); - return { nearestPt, distance: distance * this.screenToLocal().inverse().Scale }; + return { nearestPt, distance: distance * this.ScreenToLocalBoxXf().inverse().Scale }; }; /** @@ -250,7 +247,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); const screenPts = inkData .map(point => - this.screenToLocal() + this.ScreenToLocalBoxXf() .inverse() .transformPoint((point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2) ) @@ -275,7 +272,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); return inkData .map(point => - this.screenToLocal() + this.ScreenToLocalBoxXf() .inverse() .transformPoint((point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2) ) @@ -291,9 +288,9 @@ export class InkingStroke extends ViewBoxBaseComponent() { componentUI = (boundsLeft: number, boundsTop: number) => { const inkDoc = this.Document; const { inkData, inkStrokeWidth } = this.inkScaledData(); - const screenSpaceCenterlineStrokeWidth = Math.min(3, inkStrokeWidth * this.screenToLocal().inverse().Scale); // the width of the blue line widget that shows the centerline of the ink stroke + const screenSpaceCenterlineStrokeWidth = Math.min(3, inkStrokeWidth * this.ScreenToLocalBoxXf().inverse().Scale); // the width of the blue line widget that shows the centerline of the ink stroke - const screenInkWidth = this.screenToLocal().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth); + const screenInkWidth = this.ScreenToLocalBoxXf().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth); const startMarker = StrCast(this.layoutDoc.stroke_startMarker); const endMarker = StrCast(this.layoutDoc.stroke_endMarker); @@ -329,7 +326,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { false )} - +

); }; diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index 9f3786d8e..ed09d3bf3 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -158,7 +158,7 @@ export class MarqueeAnnotator extends ObservableReactComponent { const marqueeContainer = this.props.marqueeContainer; - const containerXf = this.props.isNativeScaled ? this.props.docView().screenToNativeLocalTransform() : this.props.docView().props.ScreenToLocalTransform(); + const containerXf = this.props.isNativeScaled ? this.props.docView().screenToContentsTransform() : this.props.docView().screenToViewTransform(); const boundingRect = marqueeContainer.getBoundingClientRect(); const center = { x: boundingRect.x + boundingRect.width / 2, y: boundingRect.y + boundingRect.height / 2 }; const downVec = Utils.rotPt(down[0] - center.x, diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 835e61d55..ce69dcc41 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -20,7 +20,7 @@ import { SnappingManager } from '../util/SnappingManager'; import { undoBatch, UndoManager } from '../util/UndoManager'; import { TreeSort } from './collections/TreeSort'; import { Colors } from './global/globalEnums'; -import { DocumentViewProps } from './nodes/DocumentView'; +import { DocumentViewInternalProps, DocumentViewProps } from './nodes/DocumentView'; import { FieldViewProps } from './nodes/FieldView'; import { KeyValueBox } from './nodes/KeyValueBox'; import { PropertiesView } from './PropertiesView'; @@ -37,7 +37,6 @@ export enum StyleProp { BackgroundColor = 'backgroundColor', // background color of a document view FillColor = 'fillColor', // fill color of an ink stroke or shape WidgetColor = 'widgetColor', // color to display UI widgets on a document view -- used for the sidebar divider dragger on a text note - HideLinkBtn = 'hideLinkButton', // hides the blue-dot link button. used when a document acts like a button PointerEvents = 'pointerEvents', // pointer events for DocumentView -- inherits pointer events if not specified Decorations = 'decorations', // additional decoration to display above a DocumentView -- currently only used to display a Lock for making things background HeaderMargin = 'headerMargin', // margin at top of documentview, typically for displaying a title -- doc contents will start below that @@ -81,11 +80,10 @@ export function wavyBorderPath(pw: number, ph: number, inset: number = 0.05) { // a preliminary implementation of a dash style sheet for setting rendering properties of documents nested within a Tab // -export function DefaultStyleProvider(doc: Opt, props: Opt, property: string): any { +export function DefaultStyleProvider(doc: Opt, props: Opt, property: string): any { const remoteDocHeader = 'author;author_date;noMargin'; const docProps = testDocProps(props) ? props : undefined; const fieldProps = testFieldProps(props) ? props : undefined; - const selected = property.includes(':selected'); const isCaption = property.includes(':caption'); const isAnchor = property.includes(':anchor'); const isContent = property.includes(':content'); @@ -138,14 +136,13 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt = StrCast(doc?.[fieldKey + 'color'], StrCast(doc?._color)); if (docColor) return docColor; const docView = props?.DocumentView?.(); - const backColor = backgroundCol() || docView?._props.styleProvider?.(docView._props.treeViewDoc, docView._props, StyleProp.BackgroundColor); + const backColor = backgroundCol() || docView?._props.styleProvider?.(docView._props.treeViewDoc, docView.docView?._props, StyleProp.BackgroundColor); return backColor ? lightOrDark(backColor) : undefined; case StyleProp.BorderRounding: return StrCast(doc?.[fieldKey + 'borderRounding'], StrCast(doc?.layout_borderRounding, doc?._type_collection === CollectionViewType.Pile ? '50%' : '')); @@ -373,7 +370,7 @@ export function DashboardToggleButton(doc: Doc, field: string, onIcon: IconProp, /** * add hide button decorations for the "Dashboards" flyout TreeView */ -export function DashboardStyleProvider(doc: Opt, props: Opt, property: string) { +export function DashboardStyleProvider(doc: Opt, props: Opt, property: string) { if (doc && property.split(':')[0] === StyleProp.Decorations) { return doc._type_collection === CollectionViewType.Docking || Doc.IsSystem(doc) ? null diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index b6acf3153..fb57a668e 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -7,10 +7,11 @@ import { Doc, Opt } from '../../../fields/Doc'; import { DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { DragManager } from '../../util/DragManager'; import { StyleProp } from '../StyleProvider'; -import { DocumentView, DocumentViewProps } from '../nodes/DocumentView'; +import { DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import './CollectionCarouselView.scss'; import { CollectionSubView } from './CollectionSubView'; +import { FieldViewProps } from '../nodes/FieldView'; @observer export class CollectionCarouselView extends CollectionSubView() { @@ -40,7 +41,7 @@ export class CollectionCarouselView extends CollectionSubView() { e.stopPropagation(); this.layoutDoc._carousel_index = (NumCast(this.layoutDoc._carousel_index) - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length; }; - captionStyleProvider = (doc: Doc | undefined, captionProps: Opt, property: string): any => { + captionStyleProvider = (doc: Doc | undefined, captionProps: Opt, property: string): any => { // first look for properties on the document in the carousel, then fallback to properties on the container const childValue = doc?.['caption-' + property] ? this.props.styleProvider?.(doc, captionProps, property) : undefined; return childValue ?? this.props.styleProvider?.(this.layoutDoc, captionProps, property); diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx index 0744814dd..527b72213 100644 --- a/src/client/views/collections/CollectionNoteTakingView.tsx +++ b/src/client/views/collections/CollectionNoteTakingView.tsx @@ -18,7 +18,7 @@ import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { LightboxView } from '../LightboxView'; -import { DocFocusOptions, DocumentView, DocumentViewProps } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { StyleProp } from '../StyleProvider'; @@ -195,7 +195,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { const found = this._mainCont && Array.from(this._mainCont.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); if (found) { const top = found.getBoundingClientRect().top; - const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top); + const localTop = this.ScreenToLocalBoxXf().transformPoint(0, top); if (Math.floor(localTop[1]) !== 0 && Math.ceil(this.props.PanelHeight()) < (this._mainCont?.scrollHeight || 0)) { let focusSpeed = options.zoomTime ?? 500; smoothScroll(focusSpeed, this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc); @@ -204,7 +204,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { } }; - styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { + styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { switch (property) { case StyleProp.BoxShadow: if (doc && DragManager.docsBeingDragged.includes(doc)) { @@ -282,7 +282,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { const y = this._scroll; // required for document decorations to update when the text box container is scrolled const { translateX, translateY } = Utils.GetScreenTransform(dref?.ContentDiv || undefined); // the document view may center its contents and if so, will prepend that onto the screenToLocalTansform. so we have to subtract that off - return new Transform(-translateX + (dref?.centeringX || 0), -translateY + (dref?.centeringY || 0), 1).scale(this.props.ScreenToLocalTransform().Scale); + return new Transform(-translateX + (dref?.centeringX || 0), -translateY + (dref?.centeringY || 0), 1).scale(this.ScreenToLocalBoxXf().Scale); } // how to get the width of a document. Currently returns the width of the column (minus margins) @@ -341,10 +341,10 @@ export class CollectionNoteTakingView extends CollectionSubView() { onPointerMove = (force: boolean, ex: number, ey: number) => { if (this.childDocList?.includes(DragManager.DocDragData?.draggedDocuments?.lastElement() as any) || force || SnappingManager.CanEmbed) { // get the current docs for the column based on the mouse's x coordinate - const xCoord = this.props.ScreenToLocalTransform().transformPoint(ex, ey)[0] - 2 * this.gridGap; + const xCoord = this.ScreenToLocalBoxXf().transformPoint(ex, ey)[0] - 2 * this.gridGap; const colDocs = this.getDocsFromXCoord(xCoord); // get the index for where you need to insert the doc you are currently dragging - const clientY = this.props.ScreenToLocalTransform().transformPoint(ex, ey)[1]; + const clientY = this.ScreenToLocalBoxXf().transformPoint(ex, ey)[1]; let dropInd = -1; let pos0 = (this.refList.lastElement() as HTMLDivElement).children[0].getBoundingClientRect().height + this.yMargin * 2; colDocs.forEach((doc, i) => { @@ -437,7 +437,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { if (rowCol[0] <= 0) { docs.splice(0, 0, ...newDocs); } else { - const colDocs = this.getDocsFromXCoord(this.props.ScreenToLocalTransform().transformPoint(de.x, de.y)[0]); + const colDocs = this.getDocsFromXCoord(this.ScreenToLocalBoxXf().transformPoint(de.x, de.y)[0]); const previousDoc = colDocs[rowCol[0] - 1]; const previousDocIndex = docs.indexOf(previousDoc); docs.splice(previousDocIndex + 1, 0, ...newDocs); @@ -546,7 +546,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { yMargin={this.yMargin} type={type} createDropTarget={this.createDashEventsTarget} - screenToLocalTransform={this.props.ScreenToLocalTransform} + screenToLocalTransform={this.ScreenToLocalBoxXf} editableViewProps={this.editableViewProps} /> ); @@ -586,7 +586,7 @@ export class CollectionNoteTakingView extends CollectionSubView() { // setColumnStartXCoords is used to update column widths when using the drag handlers between columns @action setColumnStartXCoords = (movementXScreen: number, colIndex: number) => { - const movementX = this.props.ScreenToLocalTransform().transformDirection(movementXScreen, 0)[0]; + const movementX = this.ScreenToLocalBoxXf().transformDirection(movementXScreen, 0)[0]; const leftHeader = this.colHeaderData[colIndex]; const rightHeader = this.colHeaderData[colIndex + 1]; leftHeader.setWidth(leftHeader.width + movementX / this.availableWidth); diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index a63688354..d99b4f9de 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -23,11 +23,12 @@ import { undoBatch, UndoManager } from '../../util/UndoManager'; import { CollectionSubView } from '../collections/CollectionSubView'; import { LightboxView } from '../LightboxView'; import { AudioWaveform } from '../nodes/audio/AudioWaveform'; -import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere } from '../nodes/DocumentView'; +import { DocFocusFunc, DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView'; import { LabelBox } from '../nodes/LabelBox'; import { VideoBox } from '../nodes/VideoBox'; import { ObservableReactComponent } from '../ObservableReactComponent'; import './CollectionStackedTimeline.scss'; +import { FieldViewProps } from '../nodes/FieldView'; export type CollectionStackedTimelineProps = { Play: () => void; @@ -367,7 +368,7 @@ export class CollectionStackedTimeline extends CollectionSubView { @@ -502,7 +503,7 @@ export class CollectionStackedTimeline extends CollectionSubView this._props.ScreenToLocalTransform().translate(0, -this.timelineContentHeight); + dictationScreenToLocalTransform = () => this.ScreenToLocalBoxXf().translate(0, -this.timelineContentHeight); isContentActive = () => this._props.isSelected() || this._props.isContentActive(); @@ -672,7 +673,7 @@ interface StackedTimelineAnchorProps { width: number; height: number; toTimeline: (screen_delta: number, width: number) => number; - styleProvider?: (doc: Opt, props: Opt, property: string) => any; + styleProvider?: StyleProviderFunc; playLink: (linkDoc: Doc, options: DocFocusOptions) => void; setTime: (time: number) => void; startTag: string; @@ -695,7 +696,7 @@ class StackedTimelineAnchor extends ObservableReactComponent node.id === doc[Id]); if (found) { const top = found.getBoundingClientRect().top; - const localTop = this._props.ScreenToLocalTransform().transformPoint(0, top); + const localTop = this.ScreenToLocalBoxXf().transformPoint(0, top); if (Math.floor(localTop[1]) !== 0) { let focusSpeed = options.zoomTime ?? 500; smoothScroll(focusSpeed, this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc); @@ -265,7 +265,7 @@ export class CollectionStackingView extends CollectionSubView, property: string) => { + styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { if (property === StyleProp.Opacity && doc) { if (this._props.childOpacity) { return this._props.childOpacity(); @@ -370,7 +370,7 @@ export class CollectionStackingView extends CollectionSubView ); }; @@ -611,7 +611,7 @@ export class CollectionStackingView extends CollectionSubView ); diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 7bbdb7073..7036ec41c 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -211,7 +211,6 @@ export class CollectionTimeView extends CollectionSubView() { Array.from(keySet).map(fieldKey => docItems.push({ description: ':' + fieldKey, event: () => (this.layoutDoc._pivotField = fieldKey), icon: 'compress-arrows-alt' })); docItems.push({ description: ':default', event: () => (this.layoutDoc._pivotField = undefined), icon: 'compress-arrows-alt' }); ContextMenu.Instance.addItem({ description: 'Pivot Fields ...', subitems: docItems, icon: 'eye' }); - const pt = this._props.ScreenToLocalTransform().inverse().transformPoint(x, y); ContextMenu.Instance.displayMenu(x, y, ':'); }; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 7f8d42088..18e0b98ef 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -154,7 +154,7 @@ export class CollectionTreeView extends CollectionSubView this._props.ScreenToLocalTransform().translate(0, -this._headerHeight); + screenToLocalTransform = () => this.ScreenToLocalBoxXf().translate(0, -this._headerHeight); @action remove = (doc: Doc | Doc[]): boolean => { @@ -312,7 +312,7 @@ export class CollectionTreeView extends CollectionSubView (this._titleRef = r) && (this._titleHeight = r.getBoundingClientRect().height * this._props.ScreenToLocalTransform().Scale))} + ref={action((r: any) => (this._titleRef = r) && (this._titleHeight = r.getBoundingClientRect().height * this.ScreenToLocalBoxXf().Scale))} key={this.Document[Id]} style={!this.outlineMode ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}}> {this.outlineMode ? this.documentTitle : this.editableTitle} diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index c2f5ab2c0..4a239e4b1 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -112,7 +112,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent (this._props.renderDepth ? this._props.ScreenToLocalTransform() : this._props.ScreenToLocalTransform().scale(this._props.PanelWidth() / this.bodyPanelWidth())); + screenToLocalTransform = () => (this._props.renderDepth ? this.ScreenToLocalBoxXf() : this.ScreenToLocalBoxXf().scale(this._props.PanelWidth() / this.bodyPanelWidth())); // prettier-ignore private renderSubView = (type: CollectionViewType | undefined, props: SubCollectionViewProps) => { TraceMobx(); diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index ac0ce7a2a..80808be92 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -29,7 +29,7 @@ import { LightboxView } from '../LightboxView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { DefaultStyleProvider, StyleProp } from '../StyleProvider'; import { Colors } from '../global/globalEnums'; -import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere, OpenWhereMod } from '../nodes/DocumentView'; import { KeyValueBox } from '../nodes/KeyValueBox'; import { DashFieldView } from '../nodes/formattedText/DashFieldView'; import { PinProps, PresBox, PresMovement } from '../nodes/trails'; @@ -37,6 +37,7 @@ import { CollectionDockingView } from './CollectionDockingView'; import { CollectionView } from './CollectionView'; import './TabDocView.scss'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; +import { FieldViewProps } from '../nodes/FieldView'; const _global = (window /* browser */ || global) /* node */ as any; interface TabDocViewProps { @@ -426,7 +427,7 @@ export class TabDocView extends ObservableReactComponent { ScreenToLocalTransform = () => { this._forceInvalidateScreenToLocal; const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont?.children?.[0] as HTMLElement); - return CollectionDockingView.Instance?._props.ScreenToLocalTransform().translate(-translateX, -translateY) ?? Transform.Identity(); + return CollectionDockingView.Instance?.ScreenToLocalBoxXf().translate(-translateX, -translateY) ?? Transform.Identity(); }; PanelWidth = () => this._panelWidth; PanelHeight = () => this._panelHeight; @@ -527,7 +528,7 @@ class TabMiniThumb extends React.Component { } @observer export class TabMinimapView extends ObservableReactComponent { - static miniStyleProvider = (doc: Opt, props: Opt, property: string): any => { + static miniStyleProvider = (doc: Opt, props: Opt, property: string): any => { if (doc) { switch (property.split(':')[0]) { default: diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index f2ceaa681..01b80e209 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -27,7 +27,7 @@ import { UndoManager, undoBatch, undoable } from '../../util/UndoManager'; import { EditableView } from '../EditableView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { StyleProp } from '../StyleProvider'; -import { DocumentView, DocumentViewInternal, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView'; +import { DocumentView, DocumentViewInternal, DocumentViewInternalProps, DocumentViewProps, OpenWhere, StyleProviderFunc } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { KeyValueBox } from '../nodes/KeyValueBox'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; @@ -172,6 +172,8 @@ export class TreeView extends ObservableReactComponent { return this._docRef?.IsSelected; } + ScreenToLocalTransform = () => this._props.ScreenToLocalTransform(); + childDocList(field: string) { const layout = Cast(Doc.LayoutField(this.Document), Doc, null); return DocListCast(this._props.dataDoc?.[field], DocListCast(layout?.[field], DocListCast(this.Document[field]))); @@ -447,11 +449,11 @@ export class TreeView extends ObservableReactComponent { } refTransform = (ref: HTMLDivElement | undefined | null) => { - if (!ref) return this._props.ScreenToLocalTransform(); + if (!ref) return this.ScreenToLocalTransform(); const { scale, translateX, translateY } = Utils.GetScreenTransform(ref); const outerXf = Utils.GetScreenTransform(this.treeView.MainEle()); - const offset = this._props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); - return this._props.ScreenToLocalTransform().translate(offset[0], offset[1]); + const offset = this.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); + return this.ScreenToLocalTransform().translate(offset[0], offset[1]); }; docTransform = () => this.refTransform(this._dref?.ContentRef?.current); getTransform = () => this.refTransform(this._tref.current); @@ -511,7 +513,7 @@ export class TreeView extends ObservableReactComponent { this._props.dragAction, this._props.addDocTab, this.titleStyleProvider, - this._props.ScreenToLocalTransform, + this.ScreenToLocalTransform, this._props.isContentActive, expandedWidth, this._props.renderDepth, @@ -671,7 +673,7 @@ export class TreeView extends ObservableReactComponent { StrCast(this.Document.childDragAction, this._props.dragAction) as dropActionType, this._props.addDocTab, this.titleStyleProvider, - this._props.ScreenToLocalTransform, + this.ScreenToLocalTransform, this._props.isContentActive, this._props.panelWidth, this._props.renderDepth, @@ -865,7 +867,7 @@ export class TreeView extends ObservableReactComponent { e.preventDefault(); } }; - titleStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { + titleStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (!doc || doc !== this.Document) return this._props?.treeView?._props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView const treeView = this.treeView; @@ -897,7 +899,7 @@ export class TreeView extends ObservableReactComponent { } return treeView._props.styleProvider?.(doc, props, property); }; - embeddedStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { + embeddedStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (property.startsWith(StyleProp.Decorations)) return null; return this._props?.treeView?._props.styleProvider?.(doc, props, property); // properties are inherited from the CollectionTreeView, not the hierarchical parent in the treeView }; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 6131fe037..5204633ea 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -22,8 +22,6 @@ export interface CollectionFreeFormLinkViewProps { LinkDocs: Doc[]; } -// props.screentolocatransform - @observer export class CollectionFreeFormLinkView extends ObservableReactComponent { @observable _opacity: number = 0; @@ -42,10 +40,10 @@ export class CollectionFreeFormLinkView extends ObservableReactComponent [ - this._props.A._props.ScreenToLocalTransform(), + this._props.A.screenToViewTransform(), Cast(Cast(Cast(this._props.A.Document, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop, Cast(Cast(Cast(this._props.A.Document, Doc, null)?.link_anchor_1, Doc, null)?.annotationOn, Doc, null)?.[DocCss], - this._props.B._props.ScreenToLocalTransform(), + this._props.B.screenToViewTransform(), Cast(Cast(Cast(this._props.A.Document, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.layout_scrollTop, Cast(Cast(Cast(this._props.A.Document, Doc, null)?.link_anchor_2, Doc, null)?.annotationOn, Doc, null)?.[DocCss], ], @@ -91,7 +89,7 @@ export class CollectionFreeFormLinkView extends ObservableReactComponent= 0 && mpx <= 1) linkDoc.link_anchor_1_x = mpx * 100; @@ -106,7 +104,7 @@ export class CollectionFreeFormLinkView extends ObservableReactComponent= 0 && mpx <= 1) linkDoc.link_anchor_2_x = mpx * 100; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 44654c8fe..0128647a4 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -38,7 +38,7 @@ import { ActiveInkWidth, InkingStroke, SetActiveInkColor, SetActiveInkWidth } fr import { LightboxView } from '../../LightboxView'; import { CollectionFreeFormDocumentView, CollectionFreeFormDocumentViewWrapper } from '../../nodes/CollectionFreeFormDocumentView'; import { SchemaCSVPopUp } from '../../nodes/DataVizBox/SchemaCSVPopUp'; -import { DocFocusOptions, DocumentView, DocumentViewProps, OpenWhere } from '../../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere } from '../../nodes/DocumentView'; import { FieldViewProps } from '../../nodes/FieldView'; import { FormattedTextBox } from '../../nodes/formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../../nodes/trails/PresBox'; @@ -172,10 +172,9 @@ export class CollectionFreeFormView extends CollectionSubView this.freeformData()?.scale ?? NumCast(Doc.Layout(this.Document)[this.scaleFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.[this.scaleFieldKey], 1)); PanZoomCenterXf = () => this._props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`; - ScreenToLocalXf = () => this.screenToLocalXf.copy(); + ScreenToContentsXf = () => this.screenToFreeformContentsXf.copy(); getActiveDocuments = () => this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout); isAnyChildContentActive = () => this._props.isAnyChildContentActive(); addLiveTextBox = (newDoc: Doc) => { @@ -329,13 +328,13 @@ export class CollectionFreeFormView extends CollectionSubView res(dv)); }); - internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData, xp: number, yp: number) { + internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData) { if (!super.onInternalDrop(e, de)) return false; const refDoc = docDragData.droppedDocuments[0]; - const [xpo, ypo] = this._props.ScreenToLocalTransform().transformPoint(de.x, de.y); - const z = NumCast(refDoc.z); - const x = (z ? xpo : xp) - docDragData.offset[0]; - const y = (z ? ypo : yp) - docDragData.offset[1]; + const fromScreenXf = NumCast(refDoc.z) ? this.ScreenToLocalBoxXf() : this.screenToFreeformContentsXf; + const [xpo, ypo] = fromScreenXf.transformPoint(de.x, de.y); + const x = xpo - docDragData.offset[0]; + const y = ypo - docDragData.offset[1]; const zsorted = this.childLayoutPairs .map(pair => pair.layout) .slice() @@ -347,7 +346,7 @@ export class CollectionFreeFormView extends CollectionSubView { const dropDoc = dropCreator(annotationOn); if (dropDoc) { @@ -408,20 +408,21 @@ export class CollectionFreeFormView extends CollectionSubView { - const [xp, yp] = this.screenToLocalXf.transformPoint(de.x, de.y); - if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData, xp, yp); - else if (de.complete.linkDragData) return this.internalLinkDrop(e, de, de.complete.linkDragData, xp, yp); - else if (de.complete.docDragData?.droppedDocuments.length) return this.internalDocDrop(e, de, de.complete.docDragData, xp, yp); + if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de, de.complete.annoDragData); + else if (de.complete.linkDragData) return this.internalLinkDrop(e, de, de.complete.linkDragData); + else if (de.complete.docDragData?.droppedDocuments.length) return this.internalDocDrop(e, de, de.complete.docDragData); return false; }; - onExternalDrop = (e: React.DragEvent) => (([x, y]) => super.onExternalDrop(e, { x, y }))(this.screenToLocalXf.transformPoint(e.pageX, e.pageY)); + onExternalDrop = (e: React.DragEvent) => (([x, y]) => super.onExternalDrop(e, { x, y }))(this.screenToFreeformContentsXf.transformPoint(e.pageX, e.pageY)); static overlapping(doc1: Doc, doc2: Doc, clusterDistance: number) { const doc2Layout = Doc.Layout(doc2); @@ -489,7 +489,7 @@ export class CollectionFreeFormView extends CollectionSubView v.ContentDiv!), de, @@ -586,7 +586,7 @@ export class CollectionFreeFormView extends CollectionSubView, props: Opt, property: string) => { + clusterStyleProvider = (doc: Opt, props: Opt, property: string) => { let styleProp = this._props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1 if (doc && this.childDocList?.includes(doc)) switch (property) { @@ -643,7 +643,7 @@ export class CollectionFreeFormView extends CollectionSubView 0 ? 1 / 1.05 : 1.05; if (deltaScale < 0) deltaScale = -deltaScale; - const [x, y] = this.screenToLocalXf.transformPoint(pointX, pointY); + const [x, y] = this.screenToFreeformContentsXf.transformPoint(pointX, pointY); const invTransform = this.panZoomXf.inverse(); if (deltaScale * invTransform.Scale > 20) { deltaScale = 20 / invTransform.Scale; @@ -982,7 +982,7 @@ export class CollectionFreeFormView extends CollectionSubView { - const pt = this.screenToLocalXf.transformPoint(NumCast(doc.x), NumCast(doc.y)); + const pt = this.screenToFreeformContentsXf.transformPoint(NumCast(doc.x), NumCast(doc.y)); doc.x = pt[0]; doc.y = pt[1]; return doc; @@ -1437,7 +1437,7 @@ export class CollectionFreeFormView extends CollectionSubView (this._hideInfo = true); - infoUI = () => (this._hideInfo || this.Document.annotationOn ? null : ); + infoUI = () => (this._hideInfo || this.Document.annotationOn || this._props.renderDepth ? null : ); componentDidMount() { this._props.setContentView?.(this); @@ -1601,7 +1601,7 @@ export class CollectionFreeFormView extends CollectionSubView { const childDocs = this.childDocs.slice(); childDocs.forEach(doc => { - const scr = this.screenToLocalXf.inverse().transformPoint(NumCast(doc.x), NumCast(doc.y)); + const scr = this.screenToFreeformContentsXf.inverse().transformPoint(NumCast(doc.x), NumCast(doc.y)); doc.x = scr?.[0]; doc.y = scr?.[1]; }); @@ -1713,7 +1713,7 @@ export class CollectionFreeFormView extends CollectionSubView ({ left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) }); const isDocInView = (doc: Doc, rect: { left: number; top: number; width: number; height: number }) => intersectRect(docDims(doc), rect); @@ -1725,7 +1725,7 @@ export class CollectionFreeFormView extends CollectionSubView !doc.isGroup && (snapToDraggedDoc || (SnappingManager.IsResizing !== doc && !DragManager.docsBeingDragged.includes(doc)))) .forEach(doc => { @@ -1822,8 +1822,8 @@ export class CollectionFreeFormView extends CollectionSubView @@ -1859,7 +1859,7 @@ export class CollectionFreeFormView extends CollectionSubView Math.max(0, this._props.PanelWidth() - 30); lightboxPanelHeight = () => Math.max(0, this._props.PanelHeight() - 30); - lightboxScreenToLocal = () => this._props.ScreenToLocalTransform().translate(-15, -15); + lightboxScreenToLocal = () => this.ScreenToLocalBoxXf().translate(-15, -15); onPassiveWheel = (e: WheelEvent) => { const docHeight = NumCast(this.Document[Doc.LayoutFieldKey(this.Document) + '_nativeHeight'], this.nativeHeight); const scrollable = NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this._props.PanelHeight() / this.nativeDimScaling; @@ -1950,7 +1950,7 @@ export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY } while (parFfview?.Document.isGroup) parFfview = parFfview.props.DocumentView?.().CollectionFreeFormView; const ffview = selfFfview && selfFfview.layoutDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it. Otherwise, zoom out on the parent ffview - ffview?.zoomSmoothlyAboutPt(ffview.screenToLocalXf.transformPoint(clientX, clientY), ffview?.isAnnotationOverlay ? 1 : 0.5, browseTransitionTime); + ffview?.zoomSmoothlyAboutPt(ffview.screenToFreeformContentsXf.transformPoint(clientX, clientY), ffview?.isAnnotationOverlay ? 1 : 0.5, browseTransitionTime); Doc.linkFollowHighlight(dv?.props.Document, false); } }); diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx index 0f750c4f8..d078e1d4f 100644 --- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx +++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx @@ -130,7 +130,7 @@ export class CollectionGridView extends CollectionSubView() { * Maps the x- and y- coordinates of the event to a grid cell. */ screenToCell(sx: number, sy: number) { - const pt = this._props.ScreenToLocalTransform().transformPoint(sx, sy); + const pt = this.ScreenToLocalBoxXf().transformPoint(sx, sy); const x = Math.floor(pt[0] / this.colWidthPlusGap); const y = Math.floor((pt[1] + this._scroll) / this.rowHeight); return { x, y }; @@ -159,7 +159,7 @@ export class CollectionGridView extends CollectionSubView() { const xypos = this.flexGrid ? layout : this.unflexedPosition(this.renderedLayoutList.findIndex(l => l.i === layout.i)); const pos = { x: xypos.x * this.colWidthPlusGap + this.margin, y: xypos.y * this.rowHeightPlusGap + this.margin - this._scroll }; - return this._props.ScreenToLocalTransform().translate(-pos.x, -pos.y); + return this.ScreenToLocalBoxXf().translate(-pos.x, -pos.y); }; /** @@ -390,7 +390,7 @@ export class CollectionGridView extends CollectionSubView() { numCols={this.numCols} rowHeight={this.rowHeight} setLayout={this.setLayout} - transformScale={this._props.ScreenToLocalTransform().Scale} + transformScale={this.ScreenToLocalBoxXf().Scale} compactType={this.compaction} // determines whether nodes should remain in position, be bound to the top, or to the left preventCollision={BoolCast(this.Document.gridPreventCollision)} // determines whether nodes should move out of the way (i.e. collide) when other nodes are dragged over them margin={this.margin} diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 5bea59e7b..563084af8 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -189,7 +189,7 @@ export class CollectionMulticolumnView extends CollectionSubView() { let offset = 0; for (const { layout: candidate } of this.childLayoutPairs) { if (candidate === layout) { - return this._props.ScreenToLocalTransform().translate(-offset / (this._props.NativeDimScaling?.() || 1), 0); + return this.ScreenToLocalBoxXf().translate(-offset / (this._props.NativeDimScaling?.() || 1), 0); } offset += this.lookupPixels(candidate) + resizerWidth; } diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 3043eb0f8..bf0d39197 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -184,7 +184,7 @@ export class CollectionMultirowView extends CollectionSubView() { let offset = 0; for (const { layout: candidate } of this.childLayoutPairs) { if (candidate === layout) { - return this._props.ScreenToLocalTransform().translate(0, -offset / (this._props.NativeDimScaling?.() || 1)); + return this.ScreenToLocalBoxXf().translate(0, -offset / (this._props.NativeDimScaling?.() || 1)); } offset += this.lookupPixels(candidate) + resizerHeight; } diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx index 2546f5b02..492aed0ea 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx @@ -16,7 +16,7 @@ import { undoable, undoBatch } from '../../../util/UndoManager'; import { ContextMenu } from '../../ContextMenu'; import { EditableView } from '../../EditableView'; import { Colors } from '../../global/globalEnums'; -import { DocFocusOptions, DocumentView, DocumentViewProps } from '../../nodes/DocumentView'; +import { DocFocusOptions, DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../../nodes/DocumentView'; import { KeyValueBox } from '../../nodes/KeyValueBox'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { DefaultStyleProvider, StyleProp } from '../../StyleProvider'; @@ -24,6 +24,7 @@ import { CollectionSubView } from '../CollectionSubView'; import './CollectionSchemaView.scss'; import { SchemaColumnHeader } from './SchemaColumnHeader'; import { SchemaRowBox } from './SchemaRowBox'; +import { FieldViewProps } from '../../nodes/FieldView'; export enum ColumnType { Number, @@ -321,8 +322,8 @@ export class CollectionSchemaView extends CollectionSubView() { change = this._displayColumnWidths[shrinking] - CollectionSchemaView._minColWidth; } - this._displayColumnWidths[shrinking] -= change * this._props.ScreenToLocalTransform().Scale; - this._displayColumnWidths[growing] += change * this._props.ScreenToLocalTransform().Scale; + this._displayColumnWidths[shrinking] -= change * this.ScreenToLocalBoxXf().Scale; + this._displayColumnWidths[growing] += change * this.ScreenToLocalBoxXf().Scale; return false; } @@ -379,7 +380,7 @@ export class CollectionSchemaView extends CollectionSubView() { @action highlightDropColumn = (e: PointerEvent) => { e.stopPropagation(); - const mouseX = this._props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY)[0]; + const mouseX = this.ScreenToLocalBoxXf().transformPoint(e.clientX, e.clientY)[0]; const index = this.findDropIndex(mouseX); this._colEles.forEach((colRef, i) => { let leftStyle = ''; @@ -439,7 +440,7 @@ export class CollectionSchemaView extends CollectionSubView() { onInternalDrop = (e: Event, de: DragManager.DropEvent) => { if (de.complete.columnDragData) { - const mouseX = this._props.ScreenToLocalTransform().transformPoint(de.x, de.y)[0]; + const mouseX = this.ScreenToLocalBoxXf().transformPoint(de.x, de.y)[0]; const index = this.findDropIndex(mouseX); this.moveColumn(de.complete.columnDragData.colIndex, index ?? de.complete.columnDragData.colIndex); @@ -483,7 +484,7 @@ export class CollectionSchemaView extends CollectionSubView() { const nativeWidth = this._previewRef!.getBoundingClientRect(); const minWidth = 40; const maxWidth = 1000; - const movedWidth = this._props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0]; + const movedWidth = this.ScreenToLocalBoxXf().transformDirection(nativeWidth.right - e.clientX, 0)[0]; const width = movedWidth < minWidth ? minWidth : movedWidth > maxWidth ? maxWidth : movedWidth; this.layoutDoc.schema_previewWidth = width; return false; @@ -507,7 +508,7 @@ export class CollectionSchemaView extends CollectionSubView() { const found = this._tableContentRef && Array.from(this._tableContentRef.getElementsByClassName('documentView-node')).find((node: any) => node.id === doc[Id]); if (found) { const rect = found.getBoundingClientRect(); - const localRect = this._props.ScreenToLocalTransform().transformBounds(rect.left, rect.top, rect.width, rect.height); + const localRect = this.ScreenToLocalBoxXf().transformBounds(rect.left, rect.top, rect.width, rect.height); if (localRect.y < this.rowHeightFunc() || localRect.y + localRect.height > this._props.PanelHeight()) { let focusSpeed = options.zoomTime ?? 50; smoothScroll(focusSpeed, this._tableContentRef!, localRect.y + this._tableContentRef!.scrollTop - this.rowHeightFunc(), options.easeFunc); @@ -829,7 +830,7 @@ export class CollectionSchemaView extends CollectionSubView() { rowHeightFunc = () => (BoolCast(this.layoutDoc._schema_singleLine) ? CollectionSchemaView._rowSingleLineHeight : CollectionSchemaView._rowHeight); sortedDocsFunc = () => this.sortedDocs; isContentActive = () => this._props.isSelected() || this._props.isContentActive(); - screenToLocal = () => this._props.ScreenToLocalTransform().translate(-this.tableWidth, 0); + screenToLocal = () => this.ScreenToLocalBoxXf().translate(-this.tableWidth, 0); previewWidthFunc = () => this.previewWidth; render() { return ( @@ -960,8 +961,8 @@ class CollectionSchemaViewDoc extends ObservableReactComponent this._props.schema.tableWidth; - screenToLocalXf = () => this._props.schema._props.ScreenToLocalTransform().translate(0, -this._props.rowHeight() - this._props.index * this._props.rowHeight()); - noOpacityStyleProvider = (doc: Opt, props: Opt, property: string) => { + screenToLocalXf = () => this._props.schema.ScreenToLocalBoxXf().translate(0, -this._props.rowHeight() - this._props.index * this._props.rowHeight()); + noOpacityStyleProvider = (doc: Opt, props: Opt, property: string) => { if (property === StyleProp.Opacity) return 1; return DefaultStyleProvider(doc, props, property); }; diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 567cf193e..908cd5dc0 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -460,7 +460,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent() { @action timelineWhenChildContentsActiveChanged = (isActive: boolean) => this._props.whenChildContentsActiveChanged((this._isAnyChildContentActive = isActive)); - timelineScreenToLocal = () => this._props.ScreenToLocalTransform().translate(0, -AudioBox.topControlsHeight); + timelineScreenToLocal = () => this.ScreenToLocalBoxXf().translate(0, -AudioBox.topControlsHeight); setPlayheadTime = (time: number) => (this._ele!.currentTime /*= this.layoutDoc._layout_currentTimecode*/ = time); @@ -564,7 +564,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent() { this._dropDisposer = DragManager.MakeDropTarget( r, (e, de) => { - const [xp, yp] = this._props.ScreenToLocalTransform().transformPoint(de.x, de.y); + const [xp, yp] = this.ScreenToLocalBoxXf().transformPoint(de.x, de.y); de.complete.docDragData && this.timeline?.internalDocDrop(e, de, de.complete.docDragData, xp); }, this.layoutDoc, diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 324a4b8d1..ad5aabc21 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -15,7 +15,8 @@ import { DocComponent } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import './CollectionFreeFormDocumentView.scss'; -import { DocumentView, DocumentViewProps, OpenWhere } from './DocumentView'; +import { DocumentView, DocumentViewInternalProps, DocumentViewProps, OpenWhere } from './DocumentView'; +import { FieldViewProps } from './FieldView'; export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentViewProps { x: number; @@ -148,7 +149,7 @@ export class CollectionFreeFormDocumentView extends DocComponent, property: string) => { + styleProvider = (doc: Doc | undefined, props: Opt, property: string) => { if (doc === this.layoutDoc) { switch (property) { case StyleProp.Opacity: return this._props.w_Opacity(); // only change the opacity for this specific document, not its children @@ -229,7 +230,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { const topDoc = this.Document; const containerDocView = this._props.docViewPath().lastElement(); - const screenXf = containerDocView?.screenToNativeLocalTransform(); + const screenXf = containerDocView?.screenToContentsTransform(); if (screenXf) { SelectionManager.DeselectAll(); if (topDoc.z) { @@ -251,7 +252,7 @@ export class CollectionFreeFormDocumentView extends DocComponent { - const [locX, locY] = this._props.ScreenToLocalTransform().transformDirection(x, y); + const [locX, locY] = this.ScreenToLocalBoxXf().transformDirection(x, y); this._props.Document.x = this._props.w_X() + locX; this._props.Document.y = this._props.w_Y() + locY; }; diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index de382fca5..5e7e568b0 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -11,7 +11,7 @@ import { undoBatch } from '../../util/UndoManager'; import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import './ComparisonBox.scss'; -import { DocumentView, DocumentViewProps } from './DocumentView'; +import { DocumentView, DocumentViewInternalProps, DocumentViewProps } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { PinProps, PresBox } from './trails'; @@ -88,7 +88,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { - const width = movementX * this._props.ScreenToLocalTransform().Scale + (this.clipWidth / 100) * this._props.PanelWidth(); + const width = movementX * this.ScreenToLocalBoxXf().Scale + (this.clipWidth / 100) * this._props.PanelWidth(); if (width && width > 5 && width < this._props.PanelWidth()) { this.layoutDoc[this.clipWidthKey] = (width * 100) / this._props.PanelWidth(); } @@ -148,7 +148,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent this.clearDoc(which) ); }; - docStyleProvider = (doc: Opt, props: Opt, property: string): any => { + docStyleProvider = (doc: Opt, props: Opt, property: string): any => { if (property === StyleProp.PointerEvents) return 'none'; return this._props.styleProvider?.(doc, props, property); }; diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index 5365fe1b2..ed44d9269 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -80,7 +80,7 @@ export class TableBox extends ObservableReactComponent { }; @computed get viewScale() { - return this._props.docView?.()?._props.ScreenToLocalTransform().Scale || 1; + return this._props.docView?.()?.screenToViewTransform().Scale || 1; } @computed get rowHeight() { console.log('scale = ' + this.viewScale + ' table = ' + this._tableHeight + ' ids = ' + this._tableDataIds.length); diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index 165057d21..c549a146a 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -257,7 +257,7 @@ export class DocumentLinksButton extends ObservableReactComponent Opt; -export type StyleProviderFunc = (doc: Opt, props: Opt, property: string) => any; +export type StyleProviderFunc = (doc: Opt, props: Opt, property: string) => any; export interface DocComponentView { fieldKey?: string; annotationKey?: string; @@ -394,11 +394,9 @@ export class DocumentViewInternal extends DocComponent dv.docView?._mainCont.current); const selected = views.length > 1 && views.some(dv => dv.Document === this.Document) ? views : [this._props.DocumentView()]; const dragData = new DragManager.DocumentDragData(selected.map(dv => dv.Document)); - const [left, top] = this._props.ScreenToLocalTransform().scale(this.NativeDimScaling).inverse().transformPoint(0, 0); - dragData.offset = this._props - .ScreenToLocalTransform() - .scale(this.NativeDimScaling) - .transformDirection(x - left, y - top); + const screenXf = this.props.DocumentView().screenToViewTransform(); + const [left, top] = screenXf.inverse().transformPoint(0, 0); + dragData.offset = screenXf.transformDirection(x - left, y - top); dragData.dropAction = dropAction; dragData.treeViewDoc = this._props.treeViewDoc; dragData.removeDocument = this._props.removeDocument; @@ -881,7 +879,7 @@ export class DocumentViewInternal extends DocComponent this._rootSelected; panelHeight = () => this._props.PanelHeight() - this.headerMargin; - contentScreenToLocal = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin); + screenToLocalContent = () => this.ScreenToLocalBoxXf().translate(0, -this.headerMargin); onClickFunc: any = () => (this.disableClickScriptFunc ? undefined : this.onClickHandler); setHeight = (height: number) => !this._props.suppressSetHeight && (this.layoutDoc._height = height); setContentView = action((view: { getAnchor?: (addAsAnnotation: boolean) => Doc; forward?: () => boolean; back?: () => boolean }) => (this._componentView = view)); @@ -925,7 +923,7 @@ export class DocumentViewInternal extends DocComponent this._props.PanelWidth() || 1; anchorPanelHeight = () => this._props.PanelHeight() || 1; - anchorStyleProvider = (doc: Opt, props: Opt, property: string): any => { + anchorStyleProvider = (doc: Opt, props: Opt, property: string): any => { // prettier-ignore switch (property.split(':')[0]) { case StyleProp.ShowTitle: return ''; @@ -1073,7 +1071,7 @@ export class DocumentViewInternal extends DocComponent, props: Opt, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption'); + captionStyleProvider = (doc: Opt, props: Opt, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption'); @observable _changingTitleField = false; @observable _dropDownInnerWidth = 0; fieldsDropdown = (inputOptions: string[], dropdownWidth: number, placeholder: string, onChange: (val: string | number) => void, onClose: () => void) => { @@ -1431,11 +1429,20 @@ export class DocumentView extends ObservableReactComponent { return this._props.LayoutTemplateString?.includes('link_anchor_2') ? DocCast(this.Document['link_anchor_2']) : this._props.LayoutTemplateString?.includes('link_anchor_1') ? DocCast(this.Document['link_anchor_1']) : undefined; } @computed get hideLinkButton() { - return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.HideLinkBtn + (this.IsSelected ? ':selected' : '')); + return ( + this._props.hideLinkButton || + this._props.renderDepth === -1 || // + (this.IsSelected && this._props.renderDepth) || + !this._isHovering || + (!this.IsSelected && this.layoutDoc.layout_hideLinkButton) || + SnappingManager.IsDragging || + SnappingManager.IsResizing + ); } - hideLinkCount = () => false; // this._props.renderDepth === -1 || (this.IsSelected && this._props.renderDepth) || !this._isHovering || this.hideLinkButton; + hideLinkCount = () => (this.hideLinkButton ? true : false); + @computed get linkCountView() { - return ; + return ; } @computed get docViewPath(): DocumentView[] { return this._props.docViewPath ? [...this._props.docViewPath(), this] : [this]; @@ -1508,7 +1515,7 @@ export class DocumentView extends ObservableReactComponent { if (this.docView._componentView?.screenBounds?.()) { return this.docView._componentView.screenBounds(); } - const xf = this.docView._props.ScreenToLocalTransform().scale(this.nativeScaling).inverse(); + const xf = this.docView.ScreenToLocalBoxXf().scale(this.nativeScaling).inverse(); const [[left, top], [right, bottom]] = [xf.transformPoint(0, 0), xf.transformPoint(this.panelWidth, this.panelHeight)]; if (this.docView._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { @@ -1566,7 +1573,7 @@ export class DocumentView extends ObservableReactComponent { }; layout_fitWidthFunc = (doc: Doc) => BoolCast(this.layout_fitWidth); - scaleToScreenSpace = () => this._props.ScreenToLocalTransform().Scale; + screenToLocalScale = () => this._props.ScreenToLocalTransform().Scale; docViewPathFunc = () => this.docViewPath; isSelected = () => this.IsSelected; select = (extendSelection: boolean, focusSelection?: boolean) => { @@ -1589,7 +1596,14 @@ export class DocumentView extends ObservableReactComponent { PanelHeight = () => this.panelHeight; NativeDimScaling = () => this.nativeScaling; selfView = () => this; - screenToNativeLocalTransform = () => + /** + * @returns Transform to the document view (in the coordinate system of whatever contains the DocumentView) + */ + screenToViewTransform = () => this._props.ScreenToLocalTransform(); + /** + * @returns Transform to the coordinate system of the contents of the document view (includes native dimension scaling and centering) + */ + screenToContentsTransform = () => this._props .ScreenToLocalTransform() .translate(-this.centeringX, -this.centeringY) @@ -1676,7 +1690,7 @@ export class DocumentView extends ObservableReactComponent { isSelected={this.isSelected} select={this.select} layout_fitWidth={this.layout_fitWidthFunc} - ScreenToLocalTransform={this.screenToNativeLocalTransform} + ScreenToLocalTransform={this.screenToContentsTransform} focus={this._props.focus || emptyFunction} ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))} /> diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 28c614786..a5853499f 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -90,7 +90,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent ({ forceFull: this._props.renderDepth < 1 || this.layoutDoc._showFullRes, - scrSize: (this._props.ScreenToLocalTransform().inverse().transformDirection(this.nativeSize.nativeWidth, this.nativeSize.nativeHeight)[0] / this.nativeSize.nativeWidth) * NumCast(this.layoutDoc._freeform_scale, 1), + scrSize: (this.ScreenToLocalBoxXf().inverse().transformDirection(this.nativeSize.nativeWidth, this.nativeSize.nativeHeight)[0] / this.nativeSize.nativeWidth) * NumCast(this.layoutDoc._freeform_scale, 1), selected: this._props.isSelected(), }), ({ forceFull, scrSize, selected }) => (this._curSuffix = selected ? '_o' : this.fieldKey === 'icon' ? '_m' : forceFull ? '_o' : scrSize < 0.25 ? '_s' : scrSize < 0.5 ? '_m' : scrSize < 0.8 ? '_l' : '_o'), @@ -158,7 +158,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent { - const scaling = (this._props.DocumentView?.()._props.ScreenToLocalTransform().Scale || 1) / NumCast(this.layoutDoc._freeform_scale, 1); + const scaling = (this._props.DocumentView?.().screenToViewTransform().Scale || 1) / NumCast(this.layoutDoc._freeform_scale, 1); const nscale = NumCast(this._props.PanelWidth()) / scaling; const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']); this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nw; @@ -366,7 +366,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent; } - screenToLocalTransform = () => this._props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop) * this._props.ScreenToLocalTransform().Scale); + screenToLocalTransform = () => this.ScreenToLocalBoxXf().translate(0, NumCast(this.layoutDoc._layout_scrollTop) * this.ScreenToLocalBoxXf().Scale); marqueeDown = (e: React.PointerEvent) => { if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) <= NumCast(this.dataDoc.freeform_scaleMin, 1) && this._props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { setupMoveUpEvents( diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 134f2e14a..7f1d41547 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -38,8 +38,8 @@ export class LinkBox extends ViewBoxBaseComponent() { } screenBounds = () => { if (this.layoutDoc._layout_isSvg && this.anchor1 && this.anchor2 && this.anchor1.CollectionFreeFormView) { - const a_invXf = this.anchor1._props.ScreenToLocalTransform().inverse(); - const b_invXf = this.anchor2._props.ScreenToLocalTransform().inverse(); + const a_invXf = this.anchor1.screenToViewTransform().inverse(); + const b_invXf = this.anchor2.screenToViewTransform().inverse(); const a_scrBds = { tl: a_invXf.transformPoint(0, 0), br: a_invXf.transformPoint(NumCast(this.anchor1.Document._width), NumCast(this.anchor1.Document._height)) }; const b_scrBds = { tl: b_invXf.transformPoint(0, 0), br: b_invXf.transformPoint(NumCast(this.anchor2.Document._width), NumCast(this.anchor2.Document._height)) }; @@ -67,9 +67,9 @@ export class LinkBox extends ViewBoxBaseComponent() { const b = (this.anchor2 ?? this.anchor1)!; const parxf = this._props.docViewPath()[this._props.docViewPath().length - 2].ComponentView as CollectionFreeFormView; - const this_xf = parxf?.screenToLocalXf ?? Transform.Identity; //this._props.ScreenToLocalTransform(); - const a_invXf = a._props.ScreenToLocalTransform().inverse(); - const b_invXf = b._props.ScreenToLocalTransform().inverse(); + const this_xf = parxf?.screenToFreeformContentsXf ?? Transform.Identity; //this.ScreenToLocalTransform(); + const a_invXf = a.screenToViewTransform().inverse(); + const b_invXf = b.screenToViewTransform().inverse(); const a_scrBds = { tl: a_invXf.transformPoint(0, 0), br: a_invXf.transformPoint(NumCast(a.Document._width), NumCast(a.Document._height)) }; const b_scrBds = { tl: b_invXf.transformPoint(0, 0), br: b_invXf.transformPoint(NumCast(b.Document._width), NumCast(b.Document._height)) }; const a_bds = { tl: this_xf.transformPoint(a_scrBds.tl[0], a_scrBds.tl[1]), br: this_xf.transformPoint(a_scrBds.br[0], a_scrBds.br[1]) }; diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index ffd52fb0e..41befbbfe 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -431,7 +431,7 @@ export class MapBox extends ViewBoxAnnotatableComponent this._props.PanelWidth() / (this._props.NativeDimScaling?.() || 1) - this.sidebarWidth(); panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); - scrollXf = () => this._props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); + scrollXf = () => this.ScreenToLocalBoxXf().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; opaqueFilter = () => [...this._props.childFilters(), Utils.OpaqueBackgroundFilter]; infoWidth = () => this._props.PanelWidth() / 5; @@ -531,7 +531,7 @@ export class MapBox extends ViewBoxAnnotatableComponent string[]) => null; return ( diff --git a/src/client/views/nodes/MapBox/MapBox2.tsx b/src/client/views/nodes/MapBox/MapBox2.tsx index 722a347f1..9734d9db1 100644 --- a/src/client/views/nodes/MapBox/MapBox2.tsx +++ b/src/client/views/nodes/MapBox/MapBox2.tsx @@ -517,7 +517,7 @@ // panelWidth = () => this._props.PanelWidth() / (this._props.NativeDimScaling?.() || 1) - this.sidebarWidth(); // panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); -// scrollXf = () => this._props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); +// scrollXf = () => this.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); // transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; // opaqueFilter = () => [...this._props.childFilters(), Utils.OpaqueBackgroundFilter]; // infoWidth = () => this._props.PanelWidth() / 5; diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx index 2c31bbab7..8b22a1531 100644 --- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -280,7 +280,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent this._props.PanelWidth() / (this._props.NativeDimScaling?.() || 1) - this.sidebarWidth(); panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); - scrollXf = () => this._props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); + scrollXf = () => this.ScreenToLocalBoxXf().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; opaqueFilter = () => [...this._props.childFilters(), Utils.OpaqueBackgroundFilter]; infoWidth = () => this._props.PanelWidth() / 5; @@ -401,7 +401,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent this.sidebarNativeHeight; sidebarMoveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => this.moveDocument(doc, targetCollection, addDocument, this.SidebarKey); sidebarRemDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, this.SidebarKey); - sidebarScreenToLocal = () => this._props.ScreenToLocalTransform().translate((this.sidebarWidth() - this._props.PanelWidth()) / this.pdfScale, 0); + sidebarScreenToLocal = () => this.ScreenToLocalBoxXf().translate((this.sidebarWidth() - this._props.PanelWidth()) / this.pdfScale, 0); @computed get sidebarCollection() { const renderComponent = (tag: string) => { const ComponentTag = tag === CollectionViewType.Freeform ? CollectionFreeFormView : CollectionStackingView; diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index 36527c311..f74e6fb2b 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -313,7 +313,6 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent <> {this.threed} diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 7ab954b3f..ce73d9f37 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -682,7 +682,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { action(encodeURIComponent => { this._clicking = false; if (this._props.isContentActive()) { - // const local = this._props.ScreenToLocalTransform().scale(this._props.scaling?.() || 1).transformPoint(e.clientX, e.clientY); + // const local = this.ScreenToLocalTransform().scale(this._props.scaling?.() || 1).transformPoint(e.clientX, e.clientY); // this.layoutDoc._layout_timelineHeightPercent = Math.max(0, Math.min(100, local[1] / this._props.PanelHeight() * 100)); this.layoutDoc._layout_timelineHeightPercent = 80; @@ -922,7 +922,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() { // renders video controls componentUI = (boundsLeft: number, boundsTop: number) => { - const xf = this._props.ScreenToLocalTransform().inverse(); + const xf = this.ScreenToLocalBoxXf().inverse(); const height = this._props.PanelHeight(); const vidHeight = (height * this.heightPercent) / 100 / this.scaling(); const vidWidth = this._props.PanelWidth() / this.scaling(); @@ -940,7 +940,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent() {
{ if (this._mainCont.current && selRange) { - if (this.dataDoc[this._props.fieldKey] instanceof HtmlField) this._mainCont.current.style.transform = `rotate(${NumCast(this._props.DocumentView!().screenToNativeLocalTransform().RotateDeg)}deg)`; + if (this.dataDoc[this._props.fieldKey] instanceof HtmlField) this._mainCont.current.style.transform = `rotate(${NumCast(this._props.DocumentView!().screenToContentsTransform().RotateDeg)}deg)`; const clientRects = selRange.getClientRects(); for (let i = 0; i < clientRects.length; i++) { const rect = clientRects.item(i); @@ -258,7 +258,7 @@ export class WebBox extends ViewBoxAnnotatableComponent 25) return
; + if (this.ScreenToLocalBoxXf().Scale > 25) return
; setTimeout( action(() => { if (this._initialScroll === undefined && !this._webPageHasBeenRendered) { @@ -1061,11 +1061,11 @@ export class WebBox extends ViewBoxAnnotatableComponent) => void) => (this._setPreviewCursor = func); panelWidth = () => this._props.PanelWidth() / (this._props.NativeDimScaling?.() || 1) - this.sidebarWidth() + WebBox.sidebarResizerWidth; panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); - scrollXf = () => this._props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); + scrollXf = () => this.ScreenToLocalBoxXf().translate(0, NumCast(this.layoutDoc._layout_scrollTop)); anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick; transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; opaqueFilter = () => [...this._props.childFilters(), Utils.noDragDocsFilter, ...(SnappingManager.CanEmbed ? [] : [Utils.OpaqueBackgroundFilter])]; - childStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { + childStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (doc instanceof Doc && property === StyleProp.PointerEvents) { if (this.inlineTextAnnotations.includes(doc)) return 'none'; } diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 8bf8abafa..66802d198 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1,7 +1,6 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; -import { isEqual } from 'lodash'; import { action, computed, IReactionDisposer, makeObservable, observable, ObservableSet, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { baseKeymap, selectAll } from 'prosemirror-commands'; @@ -21,12 +20,10 @@ import { InkTool } from '../../../../fields/InkField'; import { List } from '../../../../fields/List'; import { PrefetchProxy } from '../../../../fields/Proxy'; import { RichTextField } from '../../../../fields/RichTextField'; -import { RichTextUtils } from '../../../../fields/RichTextUtils'; import { ComputedField } from '../../../../fields/ScriptField'; import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util'; import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils'; -import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils'; import { gptAPICall, GPTCallType } from '../../../apis/gpt/GPT'; import { DocServer } from '../../../DocServer'; import { Docs, DocUtils } from '../../../documents/Documents'; @@ -46,7 +43,6 @@ import { CollectionTreeView } from '../../collections/CollectionTreeView'; import { ContextMenu } from '../../ContextMenu'; import { ContextMenuProps } from '../../ContextMenuItem'; import { ViewBoxAnnotatableComponent } from '../../DocComponent'; -import { DocumentButtonBar } from '../../DocumentButtonBar'; import { Colors } from '../../global/globalEnums'; import { LightboxView } from '../../LightboxView'; import { AnchorMenu } from '../../pdf/AnchorMenu'; @@ -71,9 +67,7 @@ import { RichTextMenu, RichTextMenuPlugin } from './RichTextMenu'; import { RichTextRules } from './RichTextRules'; import { schema } from './schema_rts'; import { SummaryView } from './SummaryView'; -export const GoogleRef = 'googleDocId'; // import * as applyDevTools from 'prosemirror-dev-tools'; -type PullHandler = (exportState: Opt, dataDoc: Doc) => void; export interface FormattedTextBoxProps {} @observer @@ -1189,15 +1183,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent DocumentButtonBar.Instance, - instance => { - if (instance) { - this.pullFromGoogleDoc(this.checkState); - this.dataDoc[GoogleRef] && this.dataDoc.googleDocUnchanged && runInAction(() => (instance.isAnimatingFetch = true)); - } - } - ); this._disposers.editorState = reaction( () => { const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc?.proto), this.fieldKey) ? DocCast(this.layoutDoc?.proto) : this?.dataDoc; @@ -1218,24 +1203,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent this._props.Document[Pulls], - () => { - if (!DocumentButtonBar.hasPulledHack) { - DocumentButtonBar.hasPulledHack = true; - this.pullFromGoogleDoc(this.dataDoc.googleDocUnchanged ? this.checkState : this.updateState); - } - } - ); - this._disposers.pushDoc = reaction( - () => this._props.Document[Pushes], - () => { - if (!DocumentButtonBar.hasPushedHack) { - DocumentButtonBar.hasPushedHack = true; - this.pushToGoogleDoc(); - } - } - ); this._disposers.search = reaction( () => Doc.IsSearchMatch(this.Document), @@ -1295,80 +1262,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent { - this.pullFromGoogleDoc(async (exportState: Opt, dataDoc: Doc) => { - const modes = GoogleApiClientUtils.Docs.WriteMode; - let mode = modes.Replace; - let reference: Opt = Cast(this.dataDoc[GoogleRef], 'string'); - if (!reference) { - mode = modes.Insert; - reference = { title: StrCast(this.dataDoc.title) }; - } - const redo = async () => { - if (this._editorView && reference) { - const content = await RichTextUtils.GoogleDocs.Export(this._editorView.state); - const response = await GoogleApiClientUtils.Docs.write({ reference, content, mode }); - response?.documentId && (this.dataDoc[GoogleRef] = response.documentId); - const pushSuccess = response !== undefined && !('errors' in response); - dataDoc.googleDocUnchanged = pushSuccess; - DocumentButtonBar.Instance.startPushOutcome(pushSuccess); - } - }; - const undo = () => { - if (exportState && reference) { - const content: GoogleApiClientUtils.Docs.Content = { - text: exportState.text, - requests: [], - }; - GoogleApiClientUtils.Docs.write({ reference, content, mode }); - } - }; - UndoManager.AddEvent({ undo, redo, prop: '' }); - redo(); - }); - }; - - pullFromGoogleDoc = async (handler: PullHandler) => { - const dataDoc = this.dataDoc; - const documentId = StrCast(dataDoc[GoogleRef]); - let exportState: Opt; - if (documentId) { - exportState = await RichTextUtils.GoogleDocs.Import(documentId, dataDoc); - } - exportState && UndoManager.RunInBatch(() => handler(exportState, dataDoc), Pulls); - }; - - updateState = (exportState: Opt, dataDoc: Doc) => { - let pullSuccess = false; - if (exportState !== undefined) { - pullSuccess = true; - dataDoc[this.fieldKey] = new RichTextField(JSON.stringify(exportState.state.toJSON())); - setTimeout(() => { - if (this._editorView) { - const state = this._editorView.state; - const end = state.doc.content.size - 1; - this._editorView.dispatch(state.tr.setSelection(TextSelection.create(state.doc, end, end))); - } - }, 0); - dataDoc.title = exportState.title; - this.dataDoc.title_custom = true; - dataDoc.googleDocUnchanged = true; - } else { - delete dataDoc[GoogleRef]; - } - DocumentButtonBar.Instance.startPullOutcome(pullSuccess); - }; - - checkState = (exportState: Opt, dataDoc: Doc) => { - if (exportState && this._editorView) { - const equalContent = isEqual(this._editorView.state.doc, exportState.state.doc); - const equalTitles = dataDoc.title === exportState.title; - const unchanged = equalContent && equalTitles; - dataDoc.googleDocUnchanged = unchanged; - DocumentButtonBar.Instance.setPullState(unchanged); - } - }; - clipboardTextSerializer = (slice: Slice): string => { let text = '', separated = true; @@ -1462,7 +1355,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent viewRect.bottom ? docPos.bottom - viewRect.bottom : undefined; if (((topOff && Math.abs(Math.trunc(topOff)) > 0) || (botOff && Math.abs(Math.trunc(botOff)) > 0)) && scrollRef) { const shift = Math.min(topOff ?? Number.MAX_VALUE, botOff ?? Number.MAX_VALUE); - const scrollPos = scrollRef.scrollTop + shift * self._props.ScreenToLocalTransform().Scale; + const scrollPos = scrollRef.scrollTop + shift * self.ScreenToLocalBoxXf().Scale; if (this._focusSpeed !== undefined) { scrollPos && (this._scrollStopper = smoothScroll(this._focusSpeed, scrollRef, scrollPos, 'ease', this._scrollStopper)); } else { diff --git a/src/client/views/nodes/importBox/ImportElementBox.tsx b/src/client/views/nodes/importBox/ImportElementBox.tsx index 1a92acea1..7d0086c0c 100644 --- a/src/client/views/nodes/importBox/ImportElementBox.tsx +++ b/src/client/views/nodes/importBox/ImportElementBox.tsx @@ -13,7 +13,7 @@ export class ImportElementBox extends ViewBoxBaseComponent() { return FieldView.LayoutString(ImportElementBox, fieldKey); } - screenToLocalXf = () => this._props.ScreenToLocalTransform().scale(1 * (this._props.NativeDimScaling?.() || 1)); + screenToLocalXf = () => this.ScreenToLocalBoxXf().scale(1 * (this._props.NativeDimScaling?.() || 1)); @computed get mainItem() { return (
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index 0305689e7..6fa64a765 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -979,7 +979,7 @@ export class PresBox extends ViewBoxBaseComponent() { enterMinimize = () => { this.updateCurrentPresentation(this.Document); clearTimeout(this._presTimer); - const pt = this._props.ScreenToLocalTransform().inverse().transformPoint(0, 0); + const pt = this.ScreenToLocalBoxXf().inverse().transformPoint(0, 0); this._props.removeDocument?.(this.layoutDoc); return PresBox.OpenPresMinimized(this.Document, [pt[0] + (this._props.PanelWidth() - 250), pt[1] + 10]); }; @@ -1076,7 +1076,7 @@ export class PresBox extends ViewBoxBaseComponent() { childLayoutTemplate = () => Docs.Create.PresElementBoxDocument(); removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.Document, this.fieldKey, doc); - getTransform = () => this._props.ScreenToLocalTransform().translate(-5, -65); // listBox padding-left and pres-box-cont minHeight + getTransform = () => this.ScreenToLocalBoxXf().translate(-5, -65); // listBox padding-left and pres-box-cont minHeight panelHeight = () => this._props.PanelHeight() - 40; /** * For sorting the array so that the order is maintained when it is dropped. diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx index ec5d090dd..4945d66c8 100644 --- a/src/client/views/nodes/trails/PresElementBox.tsx +++ b/src/client/views/nodes/trails/PresElementBox.tsx @@ -19,7 +19,7 @@ import { TreeView } from '../../collections/TreeView'; import { ViewBoxBaseComponent } from '../../DocComponent'; import { EditableView } from '../../EditableView'; import { Colors } from '../../global/globalEnums'; -import { DocumentView, DocumentViewProps } from '../../nodes/DocumentView'; +import { DocumentView, DocumentViewInternalProps, DocumentViewProps } from '../../nodes/DocumentView'; import { FieldView, FieldViewProps } from '../../nodes/FieldView'; import { StyleProp } from '../../StyleProvider'; import { PresBox } from './PresBox'; @@ -97,7 +97,7 @@ export class PresElementBox extends ViewBoxBaseComponent() { presExpandDocumentClick = () => (this.slideDoc.presentation_expandInlineButton = !this.slideDoc.presentation_expandInlineButton); embedHeight = () => this.collapsedHeight + this.expandViewHeight; embedWidth = () => this._props.PanelWidth() / 2; - styleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { + styleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { return property === StyleProp.Opacity ? 1 : this._props.styleProvider?.(doc, props, property); }; /** diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index f41094010..4a7e35c16 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -17,11 +17,11 @@ import { SnappingManager } from '../../util/SnappingManager'; import { MarqueeOptionsMenu } from '../collections/collectionFreeForm'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; -import { DocFocusOptions, DocumentViewProps } from '../nodes/DocumentView'; +import { DocFocusOptions, DocumentViewInternalProps, DocumentViewProps } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { LinkInfo } from '../nodes/LinkDocPreview'; import { ObservableReactComponent } from '../ObservableReactComponent'; -import { StyleProp } from '../StyleProvider'; +import { StyleProp, testDocProps } from '../StyleProvider'; import { AnchorMenu } from './AnchorMenu'; import { Annotation } from './Annotation'; import { GPTPopup } from './GPTPopup/GPTPopup'; @@ -53,7 +53,7 @@ interface IViewerProps extends FieldViewProps { export class PDFViewer extends ObservableReactComponent { static _annotationStyle: any = addStyleSheet(); - constructor(props: any) { + constructor(props: IViewerProps) { super(props); makeObservable(this); } @@ -419,7 +419,7 @@ export class PDFViewer extends ObservableReactComponent { @action createTextAnnotation = (sel: Selection, selRange: Range) => { if (this._mainCont.current) { - this._mainCont.current.style.transform = `rotate(${NumCast(this._props.DocumentView!().screenToNativeLocalTransform().RotateDeg)}deg)`; + this._mainCont.current.style.transform = `rotate(${NumCast(this._props.DocumentView!().screenToContentsTransform().RotateDeg)}deg)`; const boundingRect = this._mainCont.current.getBoundingClientRect(); const clientRects = selRange.getClientRects(); for (let i = 0; i < clientRects.length; i++) { @@ -491,16 +491,17 @@ export class PDFViewer extends ObservableReactComponent { } getScrollHeight = () => this._scrollHeight; - scrollXf = () => (this._mainCont.current ? this._props.ScreenToLocalTransform().translate(0, NumCast(this._props.layoutDoc._layout_scrollTop)) : this._props.ScreenToLocalTransform()); + scrollXf = () => this._props.ScreenToLocalTransform().translate(0, this._mainCont.current ? NumCast(this._props.layoutDoc._layout_scrollTop) : 0); overlayTransform = () => this.scrollXf().scale(1 / NumCast(this._props.layoutDoc._freeform_scale, 1)); panelWidth = () => this._props.PanelWidth() / (this._props.NativeDimScaling?.() || 1); panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); transparentFilter = () => [...this._props.childFilters(), Utils.TransparentBackgroundFilter]; opaqueFilter = () => [...this._props.childFilters(), Utils.noDragDocsFilter, ...(SnappingManager.CanEmbed && this._props.isContentActive() ? [] : [Utils.OpaqueBackgroundFilter])]; - childStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { + childStyleProvider = (doc: Doc | undefined, props: Opt, property: string): any => { if (doc instanceof Doc && property === StyleProp.PointerEvents) { + const docProps = testDocProps(props) ? props : undefined; if (this.inlineTextAnnotations.includes(doc) || this._props.isContentActive() === false) return 'none'; - const isInk = doc.layout_isSvg && !props?.LayoutTemplateString; + const isInk = doc.layout_isSvg && !docProps?.LayoutTemplateString; return isInk ? 'visiblePainted' : 'all'; } return this._props.styleProvider?.(doc, props, property); -- cgit v1.2.3-70-g09d2 From ae27dd1689ae1716591aab094e6d41f3a0160fef Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 4 Jan 2024 13:11:22 -0500 Subject: fixed ffmpeg for uploading videos. fixed getView() to take focus options so that if a sidebar or timeline has to be opened, the didMove flag can be set properly. added video snapshot frame to top menu. fixed using '^' to stop and start a selection region on timelines. --- src/client/documents/Documents.ts | 2 +- src/client/util/CurrentUserUtils.ts | 12 +- src/client/util/DocumentManager.ts | 2 +- src/client/util/PingManager.ts | 20 +-- src/client/views/GlobalKeyHandler.ts | 8 +- src/client/views/UndoStack.tsx | 10 +- .../views/collections/CollectionDockingView.tsx | 2 +- .../collections/CollectionStackedTimeline.tsx | 40 ++++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- .../collectionLinear/CollectionLinearView.tsx | 2 +- src/client/views/global/globalScripts.ts | 11 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 9 +- src/client/views/nodes/DocumentView.tsx | 9 +- src/client/views/nodes/MapBox/MapBox.tsx | 9 +- .../views/nodes/MapboxMapBox/MapboxContainer.tsx | 9 +- src/client/views/nodes/PDFBox.tsx | 7 +- src/client/views/nodes/VideoBox.scss | 6 +- src/client/views/nodes/VideoBox.tsx | 158 +++------------------ src/client/views/nodes/WebBox.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 7 +- src/server/DashUploadUtils.ts | 15 +- 21 files changed, 129 insertions(+), 215 deletions(-) (limited to 'src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 79285deb5..92a9ddfe8 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -209,7 +209,7 @@ export class DocumentOptions { author?: string; // STRt = new StrInfo('creator of document'); // bcz: don't change this. Otherwise, the userDoc's field Infos will have a FieldInfo assigned to its author field which will render it unreadable author_date?: DATEt = new DateInfo('date the document was created', true); annotationOn?: DOCt = new DocInfo('document annotated by this document', false); - embedContainer?: DOCt = new DocInfo('document that displays (contains) this discument', false); + _embedContainer?: DOCt = new DocInfo('document that displays (contains) this discument', false); rootDocument?: DOCt = new DocInfo('document that supplies the information needed for a rendering template (eg, pres slide for PresElement)'); color?: STRt = new StrInfo('foreground color data doc', false); hidden?: BOOLt = new BoolInfo('whether the document is not rendered by its collection', false); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 3f28f44fc..4391e87d6 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -309,7 +309,7 @@ export class CurrentUserUtils { { toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon: "file", dragFactory: doc.emptySlide as Doc, clickFactory: DocCast(doc.emptySlide), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}}, { toolTip: "Tap or drag to create a data note", title: "DataNote", icon: "window-maximize",dragFactory: doc.emptyHeader as Doc,clickFactory: DocCast(doc.emptyHeader), openFactoryAsDelegate: true, funcs: { hidden: "IsNoviceMode()"} }, { toolTip: "Toggle a Calculator REPL", title: "replviewer", icon: "calculator", clickFactory: '' as any, openFactoryLocation: OpenWhere.overlay}, // hack: clickFactory is not a Doc but will get interpreted as a custom UI by the openDoc() onClick script - // { toolTip: "Toggle an UndoStack", title: "undostacker", icon: "calculator", clickFactory: "" as any, openFactoryLocation: OpenWhere.overlay}, + // { toolTip: "Toggle an UndoStack", title: "undostacker", icon: "calculator", clickFactory: "" as any, openFactoryLocation: OpenWhere.overlay}, ].map(tuple => ( { openFactoryLocation: OpenWhere.addRight, scripts: { onClick: 'openDoc(copyDragFactory(this.clickFactory,this.openFactoryAsDelegate), this.openFactoryLocation)', @@ -695,11 +695,16 @@ export class CurrentUserUtils { static webTools() { return [ - { title: "Back", toolTip: "Go back", btnType: ButtonType.ClickButton, icon: "arrow-left", scripts: { onClick: '{ return webBack(_readOnly_); }' }}, - { title: "Forward", toolTip: "Go forward", btnType: ButtonType.ClickButton, icon: "arrow-right", scripts: { onClick: '{ return webForward(_readOnly_); }'}}, + { title: "Back", toolTip: "Go back", btnType: ButtonType.ClickButton, icon: "arrow-left", scripts: { onClick: '{ return webBack(); }' }}, + { title: "Forward", toolTip: "Go forward", btnType: ButtonType.ClickButton, icon: "arrow-right", scripts: { onClick: '{ return webForward(); }'}}, { title: "URL", toolTip: "URL", width: 250, btnType: ButtonType.EditableText, icon: "lock", ignoreClick: true, scripts: { script: '{ return webSetURL(value, _readOnly_); }'} }, ]; } + static videoTools() { + return [ + { title: "Snapshot",toolTip: "Take snapshot of current frame", btnType: ButtonType.ClickButton, icon: "camera", scripts: { onClick: '{ return videoSnapshot(); }' }}, + ]; + } static contextMenuTools():Button[] { return [ { btnList: new List([CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Tree, @@ -721,6 +726,7 @@ export class CurrentUserUtils { { title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available { title: "Stack", icon: "View", toolTip: "Stacking tools", subMenu: CurrentUserUtils.stackTools(), expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected + { title: "Video", icon: "Video", toolTip: "Video functions", subMenu: CurrentUserUtils.videoTools(), expertMode: false, toolType:DocumentType.VID, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected { title: "Schema", icon: "Schema",linearBtnWidth:58,toolTip: "Schema functions",subMenu: CurrentUserUtils.schemaTools(),expertMode: false,toolType:CollectionViewType.Schema,funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Schema is selected ]; } diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 0fab42895..7fef5cc79 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -281,7 +281,7 @@ export class DocumentManager { docContextPath.shift(); const childViewIterator = async (docView: DocumentView) => { const innerDoc = docContextPath.shift(); - return { focused: false, viewSpec: innerDoc, childDocView: innerDoc && !innerDoc.layout_unrendered ? (await docView.ComponentView?.getView?.(innerDoc)) ?? this.getDocumentView(innerDoc) : undefined }; + return { focused: false, viewSpec: innerDoc, childDocView: innerDoc && !innerDoc.layout_unrendered ? (await docView.ComponentView?.getView?.(innerDoc, options)) ?? this.getDocumentView(innerDoc) : undefined }; }; if (rootContextView) { diff --git a/src/client/util/PingManager.ts b/src/client/util/PingManager.ts index 865f8bc02..7638e2ce0 100644 --- a/src/client/util/PingManager.ts +++ b/src/client/util/PingManager.ts @@ -4,11 +4,20 @@ import { CurrentUserUtils } from './CurrentUserUtils'; export class PingManager { // create static instance and getter for global use @observable static _instance: PingManager; + @observable IsBeating = true; static get Instance(): PingManager { return PingManager._instance; } - @observable IsBeating = true; + // not used now, but may need to clear interval + private _interval: NodeJS.Timeout | null = null; + INTERVAL_SECONDS = 1; + constructor() { + makeObservable(this); + PingManager._instance = this; + this._interval = setInterval(this.sendPing, this.INTERVAL_SECONDS * 1000); + } + private setIsBeating = action((status: boolean) => { this.IsBeating = status; setTimeout(this.showAlert, 100); @@ -28,13 +37,4 @@ export class PingManager { } } }; - - // not used now, but may need to clear interval - private _interval: NodeJS.Timeout | null = null; - INTERVAL_SECONDS = 1; - constructor() { - makeObservable(this); - PingManager._instance = this; - this._interval = setInterval(this.sendPing, this.INTERVAL_SECONDS * 1000); - } } diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 77b831e51..d134d9e7b 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -128,10 +128,12 @@ export class KeyManager { var doDeselect = true; if (SnappingManager.IsDragging) { DragManager.AbortDrag(); - } else if (CollectionDockingView.Instance?.HasFullScreen) { + } + if (CollectionDockingView.Instance?.HasFullScreen) { CollectionDockingView.Instance?.CloseFullScreen(); - } else if (CollectionStackedTimeline.SelectingRegion) { - CollectionStackedTimeline.SelectingRegion = undefined; + } + if (CollectionStackedTimeline.SelectingRegions.size) { + CollectionStackedTimeline.StopSelecting(); doDeselect = false; } else { doDeselect = !ContextMenu.Instance.closeMenu(); diff --git a/src/client/views/UndoStack.tsx b/src/client/views/UndoStack.tsx index ea038250e..068143225 100644 --- a/src/client/views/UndoStack.tsx +++ b/src/client/views/UndoStack.tsx @@ -8,19 +8,13 @@ import { SettingsManager } from '../util/SettingsManager'; import { UndoManager } from '../util/UndoManager'; import './UndoStack.scss'; -interface UndoStackProps { - width?: number; - height?: number; - inline?: boolean; -} +interface UndoStackProps {} @observer export class UndoStack extends React.Component { - @observable static HideInline: boolean = false; - @observable static Expand: boolean = false; render() { const background = UndoManager.batchCounter.get() ? 'yellow' : SettingsManager.userVariantColor; const color = UndoManager.batchCounter.get() ? 'black' : SettingsManager.userColor; - return this.props.inline && UndoStack.HideInline ? null : ( + return (
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index c46f54c70..874cdffd9 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -615,7 +615,7 @@ ScriptingGlobals.add( // prettier-ignore switch (doc) { case '': return OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: 'Scripting REPL' }); - case "": return OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: 'Scripting REPL' }); + case "": return OverlayView.Instance.addWindow(, { x: 300, y: 100, width: 200, height: 200, title: 'Undo stack' }); } Doc.AddToMyOverlay(doc); } diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx index d99b4f9de..22a67c501 100644 --- a/src/client/views/collections/CollectionStackedTimeline.tsx +++ b/src/client/views/collections/CollectionStackedTimeline.tsx @@ -56,8 +56,11 @@ export enum TrimScope { @observer export class CollectionStackedTimeline extends CollectionSubView() { - @observable static SelectingRegion: CollectionStackedTimeline | undefined = undefined; - @observable public static CurrentlyPlaying: DocumentView[] = []; + public static SelectingRegions: Set = new Set(); + public static StopSelecting() { + this.SelectingRegions.forEach(action(region => (region._selectingRegion = false))); + this.SelectingRegions.clear(); + } constructor(props: any) { super(props); makeObservable(this); @@ -69,6 +72,8 @@ export class CollectionStackedTimeline extends CollectionSubView (CollectionStackedTimeline.SelectingRegion = undefined)); + if (this._selectingRegion) { + runInAction(() => (this._selectingRegion = false)); + CollectionStackedTimeline.SelectingRegions.delete(this); } } @@ -154,6 +160,15 @@ export class CollectionStackedTimeline extends CollectionSubView this.childDocList?.some(item => item === doc); + + getView = async (doc: Doc, options: DocFocusOptions): Promise> => + new Promise>(res => { + if (doc.hidden) options.didMove = !(doc.hidden = false); + const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv)); + findDoc(dv => res(dv)); + }); + anchorStart = (anchor: Doc) => NumCast(anchor._timecodeToShow, NumCast(anchor[this._props.startTag])); anchorEnd = (anchor: Doc, val: any = null) => NumCast(anchor._timecodeToHide, NumCast(anchor[this._props.endTag], val) ?? null); @@ -191,14 +206,16 @@ export class CollectionStackedTimeline extends CollectionSubView ({ - level: this.getLevel(anchor, overlaps), - anchor, + const drawAnchors = this.childLayoutPairs.map(pair => ({ + level: this.getLevel(pair.layout, overlaps), + anchor: pair.layout, })); const maxLevel = overlaps.reduce((m, o) => Math.max(m, o.level), 0) + 2; return this.clipDuration === 0 ? null : ( diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index a3cedb9a0..8268a47d8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -321,9 +321,9 @@ export class CollectionFreeFormView extends CollectionSubView> => + getView = async (doc: Doc, options: DocFocusOptions): Promise> => new Promise>(res => { - if (doc.hidden && this._lightboxDoc !== doc) doc.hidden = false; + if (doc.hidden && this._lightboxDoc !== doc) options.didMove = !(doc.hidden = false); const findDoc = (finish: (dv: DocumentView) => void) => DocumentManager.Instance.AddViewRenderedCb(doc, dv => finish(dv)); findDoc(dv => res(dv)); }); diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx index f1fb68003..d105b04f7 100644 --- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx +++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx @@ -147,7 +147,7 @@ export class CollectionLinearView extends CollectionSubView() { switch (doc.layout) { case '': return this.getLinkUI(); case '': return this.getCurrentlyPlayingUI(); - case '': return ; + case '': return ; case '': return Doc.UserDoc().isBranchingMode ? : null; } diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index 989dd1db0..e57ef4871 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -19,6 +19,7 @@ import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocum import { DocumentView } from '../nodes/DocumentView'; import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; import { WebBox } from '../nodes/WebBox'; +import { VideoBox } from '../nodes/VideoBox'; ScriptingGlobals.add(function IsNoneSelected() { return SelectionManager.Views.length <= 0; @@ -390,14 +391,16 @@ ScriptingGlobals.add(function webForward(checkResult?: boolean) { } selected?.forward(); }); -ScriptingGlobals.add(function webBack(checkResult?: boolean) { +ScriptingGlobals.add(function webBack() { const selected = SelectionManager.Views.lastElement()?.ComponentView as WebBox; - if (checkResult) { - return selected?.back(checkResult) ? undefined : 'lightGray'; - } selected?.back(); }); +ScriptingGlobals.add(function videoSnapshot() { + const selected = SelectionManager.Views.lastElement()?.ComponentView as VideoBox; + selected?.Snapshot(); +}); + /** Schema * toggleSchemaPreview **/ diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 76cc010f6..5a55ca764 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -20,7 +20,7 @@ import { SidebarAnnos } from '../../SidebarAnnos'; import { CollectionFreeFormView } from '../../collections/collectionFreeForm'; import { AnchorMenu } from '../../pdf/AnchorMenu'; import { GPTPopup } from '../../pdf/GPTPopup/GPTPopup'; -import { DocumentView } from '../DocumentView'; +import { DocFocusOptions, DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { PinProps } from '../trails'; import './DataVizBox.scss'; @@ -228,8 +228,11 @@ export class DataVizBox extends ViewBoxAnnotatableComponent() { () => UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar') ); }; - getView = async (doc: Doc) => { - if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(); + getView = async (doc: Doc, options: DocFocusOptions) => { + if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) { + options.didMove = true; + this.toggleSidebar(); + } return new Promise>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); }; @computed get sidebarWidthPercent() { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 7f1e547e4..6cc61ec62 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -43,7 +43,6 @@ import { GestureOverlay } from '../GestureOverlay'; import { LightboxView } from '../LightboxView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { StyleProp } from '../StyleProvider'; -import { UndoStack } from '../UndoStack'; import { CollectionFreeFormDocumentView } from './CollectionFreeFormDocumentView'; import { DocumentContentsView, ObserverJsxParser } from './DocumentContentsView'; import { DocumentLinksButton } from './DocumentLinksButton'; @@ -119,7 +118,7 @@ export interface DocComponentView { restoreView?: (viewSpec: Doc) => boolean; scrollPreview?: (docView: DocumentView, doc: Doc, focusSpeed: number, options: DocFocusOptions) => Opt; // returns the duration of the focus brushView?: (view: { width: number; height: number; panX: number; panY: number }, transTime: number, holdTime: number) => void; // highlight a region of a view (used by freeforms) - getView?: (doc: Doc) => Promise>; // returns a nested DocumentView for the specified doc or undefined + getView?: (doc: Doc, options: DocFocusOptions) => Promise>; // returns a nested DocumentView for the specified doc or undefined addDocTab?: (doc: Doc, where: OpenWhere) => boolean; // determines how to add a document - used in following links to open the target ina local lightbox addDocument?: (doc: Doc | Doc[], annotationKey?: string) => boolean; // add a document (used only by collections) select?: (ctrlKey: boolean, shiftKey: boolean) => void; @@ -520,11 +519,7 @@ export class DocumentViewInternal extends DocComponent { if (DocumentView.LongPress) { - if (this.Document.undoIgnoreFields) { - runInAction(() => (UndoStack.HideInline = !UndoStack.HideInline)); - } else { - this._props.select(false); - } + this._props.select(false); } }, 1000); if (!GestureOverlay.DownDocView) GestureOverlay.DownDocView = this._props.DocumentView(); diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx index 41befbbfe..3575b21e4 100644 --- a/src/client/views/nodes/MapBox/MapBox.tsx +++ b/src/client/views/nodes/MapBox/MapBox.tsx @@ -27,7 +27,7 @@ import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocC import { SidebarAnnos } from '../../SidebarAnnos'; import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; import { Colors } from '../../global/globalEnums'; -import { DocumentView } from '../DocumentView'; +import { DocFocusOptions, DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; import { PinProps, PresBox } from '../trails'; @@ -504,8 +504,11 @@ export class MapBox extends ViewBoxAnnotatableComponent { - if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(); + getView = async (doc: Doc, options: DocFocusOptions) => { + if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) { + this.toggleSidebar(); + options.didMove = true; + } return new Promise>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); }; /* diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx index 8b22a1531..ea8496c99 100644 --- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx +++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx @@ -20,7 +20,7 @@ import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../../DocC import { SidebarAnnos } from '../../SidebarAnnos'; import { MarqueeOptionsMenu } from '../../collections/collectionFreeForm'; import { Colors } from '../../global/globalEnums'; -import { DocumentView } from '../DocumentView'; +import { DocFocusOptions, DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { MapAnchorMenu } from '../MapBox/MapAnchorMenu'; import { FormattedTextBox } from '../formattedText/FormattedTextBox'; @@ -374,8 +374,11 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent { - if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(); + getView = async (doc: Doc, options: DocFocusOptions) => { + if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) { + this.toggleSidebar(); + options.didMove = true; + } return new Promise>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); }; /* diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 55a459a5c..959d5d88d 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -224,8 +224,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent { - if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar(false); + getView = async (doc: Doc, options: DocFocusOptions) => { + if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) { + options.didMove = true; + this.toggleSidebar(false); + } return new Promise>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); }; diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss index ae923ad60..460155446 100644 --- a/src/client/views/nodes/VideoBox.scss +++ b/src/client/views/nodes/VideoBox.scss @@ -180,9 +180,9 @@ } } -video::-webkit-media-controls { - display: none !important; -} +// video::-webkit-media-controls { +// display: none !important; +// } input[type='range'] { -webkit-appearance: none; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index ce73d9f37..fb42286af 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -1,9 +1,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction, untracked } from 'mobx'; +import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import { basename } from 'path'; import * as React from 'react'; -import { Doc, StrListCast } from '../../../fields/Doc'; +import { Doc, Opt, StrListCast } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; import { ObjectField } from '../../../fields/ObjectField'; @@ -12,23 +12,20 @@ import { AudioField, ImageField, VideoField } from '../../../fields/URLField'; import { emptyFunction, formatTime, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; -import { Networking } from '../../Network'; import { DocumentManager } from '../../util/DocumentManager'; import { FollowLinkScript } from '../../util/LinkFollower'; import { LinkManager } from '../../util/LinkManager'; import { ReplayMovements } from '../../util/ReplayMovements'; -import { SelectionManager } from '../../util/SelectionManager'; -import { SnappingManager } from '../../util/SnappingManager'; import { undoBatch } from '../../util/UndoManager'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { CollectionStackedTimeline, TrimScope } from '../collections/CollectionStackedTimeline'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; -import { ViewBoxAnnotatableComponent, ViewBoxAnnotatableProps } from '../DocComponent'; +import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; import { AnchorMenu } from '../pdf/AnchorMenu'; import { StyleProp } from '../StyleProvider'; -import { DocFocusOptions, DocumentView, OpenWhere } from './DocumentView'; +import { DocFocusOptions, DocumentView } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { RecordingBox } from './RecordingBox'; import { PinProps, PresBox } from './trails'; @@ -40,7 +37,7 @@ import './VideoBox.scss'; * Supporting Components: CollectionStackedTimeline * * VideoBox is a node that supports the playback of video files in Dash. - * When a video file or YouTube video is importeed into Dash, it is immediately rendered as a VideoBox document. + * When a video file is importeed into Dash, it is immediately rendered as a VideoBox document. * CollectionStackedTimline handles AudioBox and VideoBox shared behavior, but VideoBox handles playing, pausing, etc because it contains
{ className={`tableBox-row ${this.columns[0]}`} onClick={e => this.tableRowClick(e, rowId)} style={{ - background: NumListCast(this.props.layoutDoc.dataViz_highlitedRows).includes(rowId) ? 'lightYellow' : NumListCast(this.props.layoutDoc.dataViz_selectedRows).includes(rowId) ? 'lightgrey' : '', + background: NumListCast(this._props.layoutDoc.dataViz_highlitedRows).includes(rowId) ? 'lightYellow' : NumListCast(this._props.layoutDoc.dataViz_selectedRows).includes(rowId) ? 'lightgrey' : '', }}> {this.columns.map(col => { - const colSelected = this.props.axes.length > 1 ? this.props.axes[0] == col || this.props.axes[1] == col : this.props.axes.length > 0 ? this.props.axes[0] == col : false; + const colSelected = this._props.axes.length > 1 ? this._props.axes[0] == col || this._props.axes[1] == col : this._props.axes.length > 0 ? this._props.axes[0] == col : false; return ( -
{this.props.records[rowId][col]}
+
{this._props.records[rowId][col]}