Ongedaan maken en geschiedenis
graph.history is een registratie van wat het canvas bevat en laat zien — wat er is binnengebracht, wat eruit is gehaald, wat verborgen is – en een manier om iets daarvan terug te halen.
Het is geen registratie van elke mutatie die de bibliotheek kan uitvoeren. De gegevens van een knooppunt zijn eigendom van u backend, zodat de bibliotheek niet zal aanbieden een veld terug te draaien dat niet door de bibliotheek is geschreven. Wat het kan spreken want dat is de samenstelling, en dat is ook waar een analist over redeneert: er zijn twaalf knooppunten aangekomen, drie ging, vijf zijn verborgen.
Woordenschat, hieronder consistent gebruikt
- entry: één omkeerbaar iets dat is gebeurd, als één rij in het menu
- kind: welke van de zes soorten invoer het is
- span: het aaneengesloten blok vanaf het nieuwste item tot het blok waarop u hebt geklikt
- persisted: een invoer die de consument heeft doorgeschreven naar een backend
- sealed: een aanhoudende verwijdering — vermeld, nooit teruggedraaid
De zes soorten
Een gesloten geheel. Alles wat de bibliotheek registreert, is er één van, en niets anders wordt vastgelegd.
| Soort | Wat het is | Hoe het omgekeerd is |
|---|---|---|
pivot | Eén opname — zie Pivots & verrijking | De garantie voor de run wordt geschrapt, en alles waar niets anders voor instaat, gaat |
delete | Een door de gebruiker geïnitieerde verwijdering van knooppunten of randen | De elementen komen terug, herkomst en al |
visibility | Een duurzaam verbergen of zichtbaar maken (queryEngine.excludeNode / includeNode) | De andere |
create | Een knooppunt of rand die met de hand is getekend | Het element verdwijnt, tenzij iets anders ervoor instaat |
removal | Een graph.removeBySource(source)-oproep | Wat overblijft komt terug, en wat achterblijft krijgt de bron terug |
group | Een groep die met de hand is gemaakt, hernoemd of verwijderd (zie Vereenvoudigen) | De handgemaakte groepen gaan terug naar hoe ze waren; er wordt geen knooppunt toegevoegd of verwijderd |
Met opzet niet opgenomen:
- Bewerkingen van eigenschappen. Backend-status, zoals hierboven.
onBeforeNodeEditCommitis waar jij het implementeren van uw eigen. - Filter- en legendastatus. Instellingen met hun eigen Clear in plaats van handelingen. Het filter Het formulier is live van toepassing bij elke toetsaanslag, dus typen
domainzou zes invoeren opleveren. - Notities. Geschreven tekst, dichter bij een bewerking dan bij grafiekcompositie.
graph.hideNode(). Het wordt gewist de volgende keer dat filters opnieuw worden afgeleid, dus een vermelding ervoor zou iets ongedaan maken dat zichzelf al had teruggedraaid.excludeNodeis de huid die overleeft, en degene die wordt opgenomen.- Een groep openen, een knooppunt eruit halen, een vereenvoudigingsregel omschakelen. Een manier van kijken, zoals de filters.
Programmatische mutaties — graph.addNode(), graph.removeNode() — zijn ook geen vermeldingen. Alleen een gebaar is, plus graph.removeBySource(), en dat is hoe een applicatie de analist een actie 'verwijder wat deze bron heeft gebracht', en graph.simplify.groupNodes(), renameGroup() en ungroup(), de oproepen achter de groepsgebaren.
Ongedaan maken is aaneengesloten
Als je op de rij drie naar beneden richt, worden die drie ongedaan gemaakt, als één dataBatchChanged en één opnieuw renderen. Er is geen manier om één oude invoer op zichzelf terug te draaien: een stapel waarvan het midden kan zijn uitgetrokken beschrijft niet langer hoe de grafiek zo is geworden.
Voor "die provider heeft rommel geretourneerd, laat het vallen en bewaar de rest", gebruik graph.removeBySource(source). Het laat het bewijs van één bron vallen en verwijdert alleen wat niets anders staat garant voor, dus een knooppunt dat ook een tweede run heeft gevonden, overleeft, één claim lichter. Het is een vooruit bewerking, geregistreerd als een nieuwe invoer in plaats van terugspoelen.
Die vermelding wordt opgenomen wanneer de bron ergens voor instond, zelfs als elk element bleef omdat een andere bron er ook voor instaat: de claim is hoe dan ook verdwenen, en de ruzie luidt Niets verliet het canvas. Als u het ongedaan maakt, wordt de waarde van elk element precies hersteld zoals het was, dus de run-invoer eronder is nog steeds intact en de volgende Undo neemt die run terug.
Opnieuw is strikt lineair en elke nieuwe actie maakt deze leeg. Een run die ongedaan werd gemaakt en toen gestrand door later werk is weg; om het terug te krijgen, betekent dat het draaipunt opnieuw moet worden uitgevoerd.
Van de bovenste balk
Elk van de twee knoppen in de koptekst is een gesplitste knop: het pictogram stapt één keer, de cursor opent de geschiedenis. Ctrl+Z en Ctrl+Shift+Z (⌘Z en ⌘⇧Z op macOS) bereiken dezelfde twee stappen zonder de koptekst, en vallen door naar de eigen tekst van de browser ongedaan maken terwijl een tekstveld heeft focus. Beide knoppen werken in de modus full en light, waar de koptekst staat, en UI.history: { enabled: false } neemt ze, de vervolgkeuzelijst en de twee snelkoppelingen weg voor a het rijden door de consument wordt ongedaan gemaakt vanuit zijn eigen chroom — graph.history gaat hoe dan ook door met opnemen.
De vervolgkeuzelijst is één lijst van beide knoppen, de nieuwste bovenaan, met een nu lijn erdoor it: de rijen erboven zijn ongedaan gemaakt, de rijen eronder zijn wat nog ongedaan kan worden gemaakt. Klik op een rij en de lijn loopt er voorbij, wat in beide richtingen hetzelfde gebaar is.
Elke rij draagt het pictogram van zijn soort, het label en het aantal stappen dat een klik erop aflegt. Dat nummer is het nummer dat in de voettekst staat, dus de lijst en de voettekst kunnen het niet oneens zijn. De voettekst vermeldt het exacte netto-effect voordat er iets wordt vastgelegd. Pijltjestoetsen richten, Enter reist, Escape sluit.
Het canvas antwoordt ook
Als u over een rij ** beweegt, voorspelt u de verandering op het canvas**, en verandert niets anders: de elementen de klik zou de afvoer verwijderen waar ze staan, de knooppunten die hij ermee zou verbergen, en wat het ook terug zou brengen, het is omlijnd waar het zou landen — een knooppunt dat niet in de grafiek voorkomt nog niet vastgehouden, getekend als een ring op de positie waar hij vandaan kwam. Dat laatste deel is het grootste deel van wat een opnieuw uitvoeren heeft om te zeggen, en de reden waarom een voorspelling geen hoogtepunt is: niets wijkt af om de markering te maken elementen vallen op, omdat de vraag is wat er zou veranderen, en niet welke elementen een rij benoemt.
De contouren zijn geen gissingen. Een ongedaan maken noteert waar elk element stond toen het van de grond werd gehaald canvas, en een herhaling plaatst het daar terug - dus wat de voorspelling tekent, is waar de klik terechtkomt dingen. Een draaipunt herhaalt de ruwe gegevens van de provider, die dus geen coördinaten bevatten zonder dat zou een inname ergens anders verspreid terugkomen.
preview() retourneert hetzelfde als gegevens, onder forecast, en graph.showForecast(…) / graph.clearForecast() schilder het — dus de gebruikersinterface voor de geschiedenis van een consument, of iets anders wil vragen "wat als", krijgt de canvastaal gratis.
Bewerkingen die naar een backend worden geschreven
Alleen de consument kan weten dat een bewerking naar een backend is geschreven, dus alleen de consument kan dat zeggen. onBeforeNodeCreate, onBeforeEdgeCreate en onBeforeDelete elk accepteer persisted op basis van hun beslissing:
callbacks: {
onBeforeNodeCreate: async (ctx) => {
const values = await ctx.promptData({ fields: [{ key: 'value', label: 'Value', type: 'text' }] })
if (!values) return false
const saved = await myBackend.create(values)
return { accept: true, id: saved.uuid, data: values, persisted: true }
},
}Ongedaan maken levert geen compenserend schrijven op, dus wat het met een dergelijke invoer doet, hangt af van de manier waarop het schrijven ging.
Een aanhoudende creatie keert nog steeds om. Het canvas verliest iets dat de backend behoudt, namelijk een opnieuw ophalen wordt ongedaan gemaakt, zodat het item wordt gemarkeerd als saved in plaats van achtergehouden en de voettekst telt vóór de klik: Undoes 2 steps · 1 item saved upstream.
Een aanhoudende verwijdering is verzegeld: deze wordt vermeld, omdat deze deel uitmaakt van hoe het canvas is verkregen op deze manier, maar nooit omgekeerd. Als je het herstelt, wordt er een knooppunt teruggeplaatst dat de backend niet meer heeft, en niets op het doek achteraf zou dat zeggen. Een overspanning met daarin één gaat er liever overheen dan er bij te stoppen, en zegt dat eerst: Undoes 2 of 3 · 1 saved item kept.
const [newest] = graph.history.entries()
newest.persisted // the consumer wrote it through
newest.sealed // …and it was a deletion, so undo will not take it backOverslaan werkt omdat elk item de specifieke elementen benoemt die het heeft aangeraakt, dus die zijn er niet staatsverschillen om uit de orde te komen. Dat is ook de reden dat de zes soorten gesloten zijn en een consument kan zelf geen invoer opnemen: een willekeurige callback in de stapel zou halverwege kunnen gooien door een periode heen, en de geschiedenis zou het op geen enkele manier kunnen weten.
Een inname terugnemen
Als u een opname ** ongedaan maakt, worden de kandidaten** opnieuw gefaseerd, zodat de rijen teruggaan in het beoordelingsvenster, waar waar ze vandaan kwamen, het venster gaat weer open als de inname het had gesloten, eerdere afwijzingen gelden nog steeds, en er wordt geen provider gebeld. Dat laatste deel is het punt: het alternatief is het opnieuw ophalen van twee duizend correlaties via een API met beperkte snelheid om een fout van twee seconden geleden te herstellen.
Ze komen ongemerkt terug in plaats van nog steeds gemarkeerd. Terugrennen is om er doorheen te gaan het goed te doen, niet om dezelfde twaalf met één klik opnieuw te landen.
Een run die zonder beoordeling is beland, zoals een draai met één klik vanuit het contextmenu of een provider die autoIngest instelt, kwam uit geen enkel paneel, dus als u dit ongedaan maakt, worden alleen de knooppunten verwijderd.
Dit gebeurt alleen als de ingest nog steeds de nieuwste invoer is. Als er al iets is sindsdien is gebeurd, verwijdert ongedaan maken de knooppunten en verschijnt er geen venster: een venster dat zichzelf weer tot leven wekt later werk zou erger zijn dan het opknappen.
Wat het bevat
Dertig inzendingen, de oudste uitgezet. De uitzetting is het begrijpen waard, want dat is het niet symmetrisch: het verliest de mogelijkheid om een oude run te herstellen, en niet om er één te verwijderen. De herkomst leeft van de elementen zelf, dus graph.removeBySource(pivotId) reikt nog steeds een run die de geschiedenis is vergeten.
De geschiedenis is alleen sessie. Het overleeft een herlaadbeurt niet. Het herstellen van een eerdere staat van een hele grafiek is een ander kenmerk, en deze niet.
Het besturen ervan
graph.history.entries() // what can be undone, newest first — the order the menu renders
graph.history.redoable() // what has been undone and can be redone, newest first
graph.history.canUndo()
graph.history.canRedo()
graph.history.undo() // the newest entry
graph.history.undo(entryId) // the span from the newest through that entry
graph.history.redo(entryId) // and back again
graph.history.preview(entryId) // what that span would do, before doing it
graph.history.on(history => …) // every change to either direction; returns a disposer
graph.history.clear() // forget everything; the canvas is left as it isDe id is van een pivot-invoer is runId, dus een PivotRunOutcome draagt al het handvat naar zijn eigen rij:
const outcome = await graph.pivots.run('correlations', graph.getSelectedNodes())
// …later
graph.history.undo(outcome.runId)preview(entryId, direction?) is een opmerking waard. Het vat de inzendingen niet samen – het speelt de reeks opnieuw af tegen een kopie van de staat van de grafiek, via dezelfde code met de klik commit, en diffs het resultaat:
const { entries, skipped, canvasOnly, nodes, edges, effect, forecast } = graph.history.preview(entryId)
// entries the span, newest first
// skipped the sealed ones inside it, which will be left alone
// canvasOnly the ones it reverses that the backend keeps a copy of
// nodes the elements it would touch that are on the canvas now
// effect { nodesRemoved, nodesRestored, edgesRemoved, edgesRestored, nodesHidden, nodesShown }
// forecast the same change as something to paint: { removing, hiding, touching, arriving }
graph.showForecast(forecast) // …and take it back down with graph.clearForecast()Omdat het eerder gespeeld dan beschreven wordt, komen de lastige gevallen voor niets naar voren: a verbergen geannuleerd door een latere zichtbaar maken van netten naar nul en zegt dat, en een knooppunt ook een tweede draaipunt waarvoor instaat, wordt niet als vertrek geteld.
Herkomst, en waarom verwijdering het onthoudt
Elk knooppunt en elke rand draagt de reeks bronnen die ervoor instaan: 'seed' voor gegevens die geladen, de ID van een draaipunt voor alles wat het heeft meegebracht, en 'manual' voor alles wat met de hand is getekend. EEN ingesteld in plaats van een scalair, omdat twee overlappende draaipunten op één knooppunt normaal zijn.
Bij een verwijdering moet daarom de bevestiging van elk element worden onthouden, en niet alleen de gegevens ervan. Zonder dat: een run voegt er twaalf toe, de analist verwijdert er drie, maakt de verwijdering ongedaan, en de drie komen terug als vermiste weeskinderen; maak de run daarna ongedaan en laat ze vervolgens op het canvas achter zonder dat er iets is om ze uit te leggen. Hiermee wordt de verwijdering ongedaan gemaakt en de run vertrekt precies wat was er vroeger.
Eén gevolg dat de moeite waard is om te weten wanneer u een upgrade uitvoert: een handmatig gemaakt knooppunt rapporteert ['manual'] van getSources(), niet ['seed']. Dat maakt graph.removeBySource('manual') bereik handgetekend werk, en wat het ongedaan maken van een creatie mogelijk maakt, verwijdert het element alleen als er niets is anders staat er nog steeds voor in.