diff --git a/src/data/coords/circleCoords.ts b/src/data/coords/circleCoords.ts index 6209cd4293cf5784972a0f692ff7dc88da76921d..98e08477ddc56334a677f7acc6f03a28e98acd6b 100644 --- a/src/data/coords/circleCoords.ts +++ b/src/data/coords/circleCoords.ts @@ -14,7 +14,7 @@ export class CircleCoords implements Coords { return new paper.Rectangle(this.center.x - this.radius, this.center.y - this.radius, this.radius * 2, this.radius * 2); } - toPath(): paper.Path { + toRemovedPath(): paper.Path { return new paper.Path.Circle(this.center, this.radius); } diff --git a/src/data/coords/coords.tsx b/src/data/coords/coords.tsx index d198ca939c44e62e68d52472cd98b4a216b8900d..4169b90a954d68cc45d5d11d2138f4600c841b03 100644 --- a/src/data/coords/coords.tsx +++ b/src/data/coords/coords.tsx @@ -1,4 +1,5 @@ import * as paper from "paper"; +import {PathCoords} from "./pathCoords"; /** @@ -15,5 +16,6 @@ export interface Coords { /** * Un paper.Path representatif des coodonnées */ - toPath() : paper.Path; + toRemovedPath() : paper.Path; + } \ No newline at end of file diff --git a/src/data/coords/ellipseCoords.ts b/src/data/coords/ellipseCoords.ts index 0408a0528de8c745efbe87434db9a59bcbb99152..d2598f504bd2d36548beb8f91e7a71d31cf6701c 100644 --- a/src/data/coords/ellipseCoords.ts +++ b/src/data/coords/ellipseCoords.ts @@ -10,10 +10,10 @@ export class EllipseCoords implements Coords { } bounds(): paper.Rectangle { - return this.toPath().bounds; + return this.toRemovedPath().bounds; } - toPath(): paper.Path { + toRemovedPath(): paper.Path { let path = new paper.Path.Ellipse(new paper.Rectangle( new paper.Point(this.center.x - this.radiusX, this.center.y - this.radiusY), new paper.Size(2 * this.radiusX, 2 * this.radiusY) diff --git a/src/data/coords/pathCoords.ts b/src/data/coords/pathCoords.ts new file mode 100644 index 0000000000000000000000000000000000000000..60498098cd9ea4f5a82d72fffa57472bf89318fe --- /dev/null +++ b/src/data/coords/pathCoords.ts @@ -0,0 +1,40 @@ +import * as paper from "paper"; +import {Coords} from "./coords"; + +/** + * Distance en dessous de la quelle on considère que le path est fermé + */ +const CLOSING_DISTANCE = 10; + +/** + * Etend les types de paper avec un cercle (centre + rayon) + */ +export class PathCoords implements Coords { + + public constructor(public points : paper.Point[] = []) { + } + + bounds(): paper.Rectangle { + return this.toRemovedPath().bounds; + } + + toRemovedPath(): paper.Path { + let path = new paper.Path(); + path.remove(); + this.points.forEach((point) => { + path.add(point) + }) + return path; + } + + /** + * Indique si le masque est fermé (le dernier point est proche du premier) + */ + public isClosed() : boolean { + let path = this.toRemovedPath(); + return !path.isEmpty() + && (path.bounds.width > CLOSING_DISTANCE || path.bounds.height > CLOSING_DISTANCE) + && path.firstSegment.point.getDistance(path.lastSegment.point) < CLOSING_DISTANCE; + } + +} \ No newline at end of file diff --git a/src/data/coords/pathCoords.tsx b/src/data/coords/pathCoords.tsx deleted file mode 100644 index 78c0074d3c0a91862b67c0d6a1545793f22525ec..0000000000000000000000000000000000000000 --- a/src/data/coords/pathCoords.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import * as paper from "paper"; -import {Coords} from "./coords"; - -/** - * Distance en dessous de la quelle on considère que le path est fermé - */ -const CLOSING_DISTANCE = 10; - -/** - * Etend les types de paper avec un cercle (centre + rayon) - */ -export class PathCoords implements Coords { - - public constructor(public path : paper.Path) { - } - - bounds(): paper.Rectangle { - return this.path.bounds; - } - - toPath(): paper.Path { - const result = this.path.clone(); - result.remove(); - return result; - } - - /** - * Indique si le masque est fermé (le dernier point est proche du premier) - */ - public isClosed() : boolean { - return !this.path.isEmpty() - && (this.path.bounds.width > CLOSING_DISTANCE || this.path.bounds.height > CLOSING_DISTANCE) - && this.path.firstSegment.point.getDistance(this.path.lastSegment.point) < CLOSING_DISTANCE; - } - -} \ No newline at end of file diff --git a/src/data/coords/transform/toConvexHull.ts b/src/data/coords/transform/toConvexHull.ts new file mode 100644 index 0000000000000000000000000000000000000000..a3fc45a92449ffb07393a3501b6210c4c13f7203 --- /dev/null +++ b/src/data/coords/transform/toConvexHull.ts @@ -0,0 +1,90 @@ +import {PathCoords} from "../pathCoords"; +import {Transformation} from "./transformation"; + +enum Orientation { + Collinear = 0, + Clockwise = 1, + Counterclockwise= 2 +} + +/** + * Génère une coque convexe + * Jarvis’s Algorithm or Wrapping + * @see https://www.geeksforgeeks.org/convex-hull-set-1-jarviss-algorithm-or-wrapping/ + */ +export class ToConvexHull implements Transformation<PathCoords, PathCoords> { + + transform(pathCoords: PathCoords): PathCoords { + return new PathCoords(this.convexHull(pathCoords.points)); + } + + /** + * + * Prints convex hull of a set of n points. + */ + private convexHull(points : paper.Point[]) : paper.Point[] { + if (points.length < 3) { + return points; + } + + // Initialize Result + let hull = []; + + // Find the leftmost point + let startIndex = 0; + for (let i = 1; i < points.length; i++) { + if (points[i].x < points[startIndex].x) { + startIndex = i; + } + } + + // Start from leftmost point, keep moving + // counterclockwise until reach the start point + // again. This loop runs O(h) times where h is + // number of points in result or output. + let p = startIndex; + do { + + // Add current point to result + hull.push(points[p]); + + // Search for a point 'q' such that + // orientation(p, q, x) is counterclockwise + // for all points 'x'. The idea is to keep + // track of last visited most counterclock- + // wise point in q. If any point 'i' is more + // counterclock-wise than q, then update q. + let q = (p + 1) % points.length; + + for (let i = 0; i < points.length; i++) { + // If i is more counterclockwise than + // current q, then update q + if (this.orientation(points[p], points[i], points[q]) == Orientation.Counterclockwise) { + q = i; + } + } + + // Now q is the most counterclockwise with + // respect to p. Set p as q for next iteration, + // so that q is added to result 'hull' + p = q; + + } while (p != startIndex); // While we don't come to first point + + return hull; + } + + /** + * To find orientation of ordered triplet (p, q, r) + */ + private orientation(p : paper.Point, q : paper.Point, r : paper.Point) : Orientation { + let val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); + if (val == 0) { + return Orientation.Collinear; + } else if (val > 0) { + return Orientation.Clockwise; + } else { + return Orientation.Counterclockwise; + } + } +} \ No newline at end of file diff --git a/src/data/coords/transform/ellipseFitter.ts b/src/data/coords/transform/toEllipseFitter.ts similarity index 97% rename from src/data/coords/transform/ellipseFitter.ts rename to src/data/coords/transform/toEllipseFitter.ts index 7ce261be247ace7a43e00f3b115826e7c31d9ea3..d3a683b315375c717d860e597a456157c17d6683 100644 --- a/src/data/coords/transform/ellipseFitter.ts +++ b/src/data/coords/transform/toEllipseFitter.ts @@ -13,7 +13,7 @@ const HALFPI : number= 1.5707963267949; /** * Adaptation de EllipseFitter.java de ImageJ */ -export class EllipseFitter implements Transformation<PathCoords, Coords>{ +export class ToEllipseFitter implements Transformation<PathCoords, Coords>{ private bitCount : number = 0; private xsum : number = 0; @@ -54,7 +54,7 @@ export class EllipseFitter implements Transformation<PathCoords, Coords>{ let theta : number; - const path = from.toPath(); + const path = from.toRemovedPath(); let bounds = path.bounds; this.left = Math.round(bounds.x); this.top = Math.round(bounds.y); @@ -113,7 +113,7 @@ export class EllipseFitter implements Transformation<PathCoords, Coords>{ xCenter = this.left + xoffset + 0.5; yCenter = this.top + yoffset + 0.5; - return new EllipseCoords(new paper.Point(xCenter, yCenter), major / 2, minor / 2, -angle); + return new EllipseCoords(new paper.Point(xCenter, yCenter), major / 2, minor / 2, angle); } private computeSums (path : paper.Path) : void { diff --git a/src/data/coords/vectorCoords.ts b/src/data/coords/vectorCoords.ts index fa8c45da406337863ad406db07ecf51f7f8f8431..40025b1fe177ccbd57a741d45000850f6884a862 100644 --- a/src/data/coords/vectorCoords.ts +++ b/src/data/coords/vectorCoords.ts @@ -22,7 +22,7 @@ export class VectorCoords implements Coords { return this.end.subtract(this.start); } - toPath(): paper.Path { + toRemovedPath(): paper.Path { return new paper.Path.Line(this.start, this.end); } diff --git a/src/data/dataExporter.ts b/src/data/dataExporter.ts index 705d8a18bfe500a7fbf122a60fb6e57710d15f57..e9fd78e3e53f8b0712f4c9563274e72e337de524 100644 --- a/src/data/dataExporter.ts +++ b/src/data/dataExporter.ts @@ -2,9 +2,11 @@ * Utilitaire d'export des données */ import {LabData} from "../lab"; -import {EllipseFitter} from "./coords/transform/ellipseFitter"; +import {ToEllipseFitter} from "./coords/transform/toEllipseFitter"; import {Coords} from "./coords/coords"; import {MathUtils} from "../utils/mathUtils"; +import {ToConvexHull} from "./coords/transform/toConvexHull"; +import {PathCoords} from "./coords/pathCoords"; const ROUNDING_DECIMALS = 3; @@ -14,14 +16,11 @@ export class DataExporter { * Transforme un Path en CSV */ public exportPathAsXYCsv(coords : Coords, close : boolean) : string { - const path = coords.toPath(); - if(close) { - path.closePath(); - } + const path = coords.toRemovedPath(); let data = ""; - for (let i = 0; i < path.length; i++) { - let point = path.getPointAt(i); - data += Math.round(point.x) + "\t" + Math.round(point.y) + "\n"; + for (let i = 0; i < path.segments.length; i++) { + let segment = path.segments[i]; + data += Math.round(segment.point.x) + "\t" + Math.round(segment.point.y) + "\n"; } return data; } @@ -29,13 +28,14 @@ export class DataExporter { /** * Transforme un Path en CSV */ - public exportPathDescriptorsAsCsv(labData : LabData, coords : Coords) : string { - let path = coords.toPath(); + public exportPathDescriptorsAsCsv(labData : LabData, coords : PathCoords) : string { + let path = coords.toRemovedPath(); path.closePath(); let linearScale = labData.rulerCoords.distance() / labData.rulerTickCount; // pixels/cm let areaScale = Math.pow(linearScale, 2); - let fittingEllipse = new EllipseFitter().transform(coords); + let fittingEllipse = new ToEllipseFitter().transform(coords); + let convexHull = new ToConvexHull().transform(coords); let line = 1; let label = labData.filename; @@ -44,7 +44,7 @@ export class DataExporter { let circularity = 4 * Math.PI * area / Math.pow(perimeter, 2); let ar = fittingEllipse.getMajorAxis() / fittingEllipse.getMinorAxis(); let round = 4 * area / (Math.PI * fittingEllipse.getMajorAxis()); - let solid = "todo"; + let solid = area / (convexHull.toRemovedPath().area / areaScale); let headers : string[] = [ " ", "Label", "Area", "Perim.", "Circ.","AR","Round","Solidity"]; let data = [ line, @@ -54,7 +54,7 @@ export class DataExporter { MathUtils.round(circularity, ROUNDING_DECIMALS), MathUtils.round(ar, ROUNDING_DECIMALS), MathUtils.round(round, ROUNDING_DECIMALS), - solid, + MathUtils.round(solid, ROUNDING_DECIMALS), ] return headers.join(",") + "\n" + data.join(","); diff --git a/src/instruments/blobMask.ts b/src/instruments/blobMask.ts index 53d95742559a7d14e11c1da5b07f4b5a276c095b..f89847a77474d4afb96d96bb064b1b031a29cc59 100644 --- a/src/instruments/blobMask.ts +++ b/src/instruments/blobMask.ts @@ -2,22 +2,29 @@ import * as paper from "paper"; import {AbstractInstrument, Handle, Instrument} from "./instrument"; import {PathCoords} from "../data/coords/pathCoords"; import {DEBUG_MODE, Lab} from "../lab"; -import {EllipseFitter} from "../data/coords/transform/ellipseFitter"; +import {ToEllipseFitter} from "../data/coords/transform/toEllipseFitter"; +import {PaperUtils} from "../utils/paperUtils"; +import {ToConvexHull} from "../data/coords/transform/toConvexHull"; /** * Représente la boîte de Petri */ export class BlobMask extends AbstractInstrument<PathCoords> implements Instrument { + /** + * Garde l'état fermé ou pas + */ + private wasClosed: boolean = false; + /** * Appelé lorsque le tracé est fermé */ - public onClosed : () => void = () => {}; + public onClose : () => void = () => {}; /** * Appelé lorsque le tracé s'ouvre */ - public onOpened : () => void = () => {}; + public onOpen : () => void = () => {}; public constructor(protected lab : Lab, coords : PathCoords) { super(lab, coords, [ @@ -26,14 +33,38 @@ export class BlobMask extends AbstractInstrument<PathCoords> implements Instrume } drawIn(coords: PathCoords, group: paper.Group) { - let line = coords.path.clone(); + let line = coords.toRemovedPath(); group.addChild(line); + } + + /** + * Surcharge pour gérer l'état fermé ouvert du tracé + */ + refresh() { + super.refresh(); + let isClosed = this.coords.isClosed(); + if(!this.wasClosed && isClosed) { + this.onClose(); + + } else if(this.wasClosed && !isClosed) { + this.onOpen(); + } + this.wasClosed = isClosed; if(DEBUG_MODE) { - if(line.length > 10) { - const pathCoords = new PathCoords(line.clone()); - group.addChild(new EllipseFitter().transform(pathCoords).toPath()); + if(this.drawGroup.bounds.area > 10) { + let fittedEllipse = new ToEllipseFitter().transform(this.coords).toRemovedPath(); + fittedEllipse.strokeColor = new paper.Color("red"); + fittedEllipse.strokeWidth = PaperUtils.absoluteDimension(2); + fittedEllipse.dashArray = [10, 12]; + this.drawGroup.addChild(fittedEllipse); } + + let convexHull = new ToConvexHull().transform(this.coords).toRemovedPath(); + convexHull.strokeColor = new paper.Color("red"); + convexHull.strokeWidth = PaperUtils.absoluteDimension(2); + convexHull.dashArray = [10, 12]; + this.drawGroup.addChild(convexHull); } } @@ -44,10 +75,10 @@ export class BlobMask extends AbstractInstrument<PathCoords> implements Instrume locateHandle(coords: PathCoords, handle: Handle): paper.Point { if(handle.name == "startHandle") { - if(coords.path.isEmpty()) { + if(coords.points.length == 0) { return null; } else { - return coords.path.firstSegment.point; + return coords.points[0]; } } throw new Error("Unknown handle"); @@ -71,12 +102,8 @@ export class BlobMask extends AbstractInstrument<PathCoords> implements Instrume return true; } if(!this.coords.isClosed()) { // Une fois la boucle fermée, on ne peut plus ajouter de - this.coords.path.add(event.point) - if(this.coords.isClosed()) { - this.onClosed(); - } + this.coords.points.push(event.point) } - this.refresh(); return true; } @@ -95,7 +122,7 @@ export class BlobMask extends AbstractInstrument<PathCoords> implements Instrume * Supprime quelques derniers points */ public undo() { - this._undo(Math.max(this.coords.path.segments.length - 5, 0)); + this._undo(Math.max(this.coords.points.length - 5, 0)); } /** @@ -109,11 +136,7 @@ export class BlobMask extends AbstractInstrument<PathCoords> implements Instrume * En charge de la suppression */ private _undo(from : number) { - let wasClosed = this.coords.isClosed(); - this.coords.path.removeSegments(from); - if(wasClosed) { - this.onOpened(); - } + this.coords.points = this.coords.points.slice(0, from); this.refresh(); } diff --git a/src/instruments/instrument.ts b/src/instruments/instrument.ts index a1e4871498d3bf08b5d5cfffeebe8bd90f22b01c..bc1d9f953fdb7bbb1962f01ebe69745766cccf9a 100644 --- a/src/instruments/instrument.ts +++ b/src/instruments/instrument.ts @@ -1,7 +1,8 @@ import * as paper from "paper"; -import {Lab} from "../lab"; +import {DEBUG_MODE, Lab} from "../lab"; import {Coords} from "../data/coords/coords"; import {PaperUtils} from "../utils/paperUtils"; +import {ToEllipseFitter} from "../data/coords/transform/toEllipseFitter"; /** * Un instrument d'analyse @@ -59,7 +60,7 @@ export abstract class AbstractInstrument<C extends Coords> implements Instrument /** * Contient le dessin de l'instrument */ - private drawGroup : paper.Group = new paper.Group(); + protected drawGroup : paper.Group = new paper.Group(); protected constructor(protected lab : Lab, protected coords : C, protected handles : Handle[]) { } diff --git a/src/instruments/petriDish.ts b/src/instruments/petriDish.ts index 197e49b9d1ca2bd5f6f43b085790ecca9c7fc933..8095574dab34aa6d5d5add340fd70892a35ee285 100644 --- a/src/instruments/petriDish.ts +++ b/src/instruments/petriDish.ts @@ -18,7 +18,7 @@ export class PetriDish extends AbstractInstrument<EllipseCoords> implements Inst } drawIn(coords : EllipseCoords, group: paper.Group) { - group.addChild(coords.toPath()); + group.addChild(coords.toRemovedPath()); } onHandleMove(coords: EllipseCoords, handle: Handle, point: paper.Point, delta: paper.Point): void { diff --git a/src/lab.tsx b/src/lab.tsx index a24f7202f1e667ba8dbb740c880fcaad62e47a66..49c147881bc0f253cdedaf2534ad5b8c6a9ab667 100644 --- a/src/lab.tsx +++ b/src/lab.tsx @@ -18,10 +18,9 @@ import {EllipseCoords} from "./data/coords/ellipseCoords"; /** * Debug mode (ou pas) */ -export const DEBUG_MODE = false; +export const DEBUG_MODE = true; export interface LabData { - pictureSize : paper.Size, filename : string, @@ -144,7 +143,6 @@ export class Lab extends React.Component<{}> { let width = image.naturalWidth; let height = image.naturalHeight; this.data = { - pictureSize: new paper.Size(width, height), filename: filename, @@ -155,8 +153,7 @@ export class Lab extends React.Component<{}> { petriDishCoords: new EllipseCoords(new paper.Point(width / 2, height / 2), width * 0.75 / 2, width * 0.75 / 2, 0), - blobMaskCoords: new PathCoords(new paper.Path()), - + blobMaskCoords: new PathCoords(), }; // Le plus en dessous en premier @@ -258,9 +255,9 @@ export class Lab extends React.Component<{}> { * Appelé lorsque le zoom a changé */ private onZoomChanged() { - this.ruler.refresh(); - this.petriDish.refresh(); - this.blobMask.refresh(); + this.ruler?.refresh(); + this.petriDish?.refresh(); + this.blobMask?.refresh(); } render(): React.ReactNode { diff --git a/src/steps/downloadStep.tsx b/src/steps/downloadStep.tsx index 98fdc45c3385b02cdb59b009395314f911c26a62..4e76e0b11d7c25803a647b6e90ecf429829f732f 100644 --- a/src/steps/downloadStep.tsx +++ b/src/steps/downloadStep.tsx @@ -83,10 +83,8 @@ export class DownloadStep extends Step<DownloadStepState> { * Téléchargement des données du mask */ private downloadBlobMaskData() : void { - let path = new paper.Path(this.props.lab.data.blobMaskCoords.path.segments); - path.closed = true; // ferme le contour let data = this.dataExporter.exportPathAsXYCsv(this.props.lab.data.blobMaskCoords, true); - IoUtils.downloadData(this.state.petriDishDataFilename, "text/plain;charset=UTF-8", data); + IoUtils.downloadData(this.state.blobMaskDataFilename, "text/plain;charset=UTF-8", data); } /** @@ -100,7 +98,7 @@ export class DownloadStep extends Step<DownloadStepState> { renderingGroup.addChild(background) - let path = this.props.lab.data.blobMaskCoords.toPath(); + let path = this.props.lab.data.blobMaskCoords.toRemovedPath(); path.closed = true; path.fillColor = new paper.Color("white"); path.strokeColor = null; diff --git a/src/steps/drawBlobMaskStep.tsx b/src/steps/drawBlobMaskStep.tsx index 420681fa34db1b190892ad0c79ecb547339aeffa..858a293aa0763775fa9dcf6237a384b956a9d52e 100644 --- a/src/steps/drawBlobMaskStep.tsx +++ b/src/steps/drawBlobMaskStep.tsx @@ -1,6 +1,10 @@ import {Step, StepProps, StepState} from "./step"; import * as React from "react"; +import * as paper from "paper"; import {Alert, Button} from "react-bootstrap"; +import {IoUtils} from "../utils/ioUtils"; +import {DEBUG_MODE} from "../lab"; +import {StringUtils} from "../utils/stringUtils"; interface DrawBlobMaskStepState extends StepState { @@ -24,10 +28,10 @@ export class DrawBlobMaskStep extends Step<DrawBlobMaskStepState> { onActivation(): void { this.props.lab.blobMask.activate(); - this.props.lab.blobMask.onClosed = () => { + this.props.lab.blobMask.onClose = () => { this.setState({closed: true }); }; - this.props.lab.blobMask.onOpened = () => { + this.props.lab.blobMask.onOpen = () => { this.setState({closed: false }); }; this.props.lab.zoomOn( this.props.lab.data.petriDishCoords.bounds(), 0.05); @@ -37,6 +41,23 @@ export class DrawBlobMaskStep extends Step<DrawBlobMaskStepState> { this.props.lab.blobMask.deactivate(); } + loadData(): void { + IoUtils.openTextFile( + (text : string) => { + console.info("text loaded") + this.props.lab.data.blobMaskCoords.points = []; + let lines = StringUtils.splitLines(text); + lines.filter(line => line.trim().length > 0).forEach( + (line : string) => { + let [x, y] = line.split("\t"); + this.props.lab.data.blobMaskCoords.points.push(new paper.Point(Number(x), Number(y))); + } + ); + // this.props.lab.data.blobMaskCoords.points.push(this.props.lab.data.blobMaskCoords.points[0]); + this.props.lab.blobMask.refresh(); + }); + } + render() : React.ReactNode { return <div> <div> @@ -49,6 +70,13 @@ export class DrawBlobMaskStep extends Step<DrawBlobMaskStepState> { <Button className={"col-3"} variant={"success"} disabled={!this.state.active || !this.state.closed} onClick={this.terminate.bind(this)}> <span hidden={!this.state.closed}><i className="fa-solid fa-hands-clapping fa-beat-fade me-2"></i></span>Fini ! </Button> + {DEBUG_MODE ? + <Button className={"ms-2 col-4"} variant={"danger"} disabled={!this.state.active} + onClick={this.loadData.bind(this)}> + <i className="fa-solid fa-bug"></i> Charger XY + </Button> + : <></> + } </div> </div> } diff --git a/src/utils/ioUtils.ts b/src/utils/ioUtils.ts index 3266333ea588e0511b004e008f107e0c4eb58a8e..a955a0a6225eab1074f46a9b98358552e683d606 100644 --- a/src/utils/ioUtils.ts +++ b/src/utils/ioUtils.ts @@ -3,6 +3,29 @@ */ export class IoUtils { + /** + * Ouvre un chargement + */ + public static openTextFile(onTextLoad : (text: string) => void) : void { + let input : HTMLInputElement = document.createElement('input'); + input.type = 'file'; + input.accept = '.txt'; + input.onchange = (e: InputEvent) => { + // getting a hold of the file reference + var file = (e.target as HTMLInputElement).files[0]; + + // setting up the reader + let reader = new FileReader(); + reader.readAsText(file,'UTF-8'); + // here we tell the reader what to do when it's done reading... + reader.onload = readerEvent => { + onTextLoad(readerEvent.target.result as string); + } + + } + input.click(); + } + /** * Donne le nom de fichier sans extension */ diff --git a/src/utils/stringUtils.ts b/src/utils/stringUtils.ts new file mode 100644 index 0000000000000000000000000000000000000000..a0ab7287d09f10da8adae1f93464bae5ea503466 --- /dev/null +++ b/src/utils/stringUtils.ts @@ -0,0 +1,14 @@ +/** + * Utilitaires + */ +export class StringUtils { + + /** + * Découpe en multi-ligne + */ + public static splitLines(text: string) : string[] { + return text.split(/\r?\n/); + } + + +} \ No newline at end of file