diff --git a/client/editor.js b/client/editor.js index cd5ef474..b86acfee 100644 --- a/client/editor.js +++ b/client/editor.js @@ -14,6 +14,14 @@ const changeGlyph = (method, argument) => { }); } +const constructStage = (type) => { + const glyph = Session.get('editor.glyph'); + stage = new stages[type](glyph); + Session.set('editor.glyph', glyph); + stage._type = type; + stage.refresh(glyph); +} + this.getGlyph = (selector) => changeGlyph('getGlyph', selector); const incrementStage = (amount) => { @@ -21,10 +29,7 @@ const incrementStage = (amount) => { if (index < 0) return; const new_index = index + amount; if (new_index < 0 || new_index >= types.length) return; - const glyph = Session.get('editor.glyph'); - stage = new stages[types[new_index]](glyph); - stage._type = types[new_index]; - stage.refresh(glyph); + constructStage(types[new_index]); } const initialize = () => { @@ -46,7 +51,9 @@ const bindings = { Template.editor.events({ 'click svg .selectable': function(event) { // We avoid the arrow function here so that this is bound to the template. - stage.handleEvent(Session.get('editor.glyph'), event, this); + const glyph = Session.get('editor.glyph'); + stage.handleEvent(glyph, event, this); + Session.set('editor.glyph', glyph); } }); @@ -69,8 +76,7 @@ Tracker.autorun(() => { if (!last_glyph || glyph.character !== last_glyph.character) { let last_completed_stage = types[0]; types.map((x) => { if (glyph.stages[x]) last_completed_stage = x; }); - stage = new stages[last_completed_stage](glyph); - stage._type = last_completed_stage; + constructStage(last_completed_stage); } stage.refresh(glyph); last_glyph = glyph; diff --git a/client/lib/abstract.js b/client/lib/abstract.js index d9735150..27b913d3 100644 --- a/client/lib/abstract.js +++ b/client/lib/abstract.js @@ -2,10 +2,11 @@ if (this.stages !== undefined) throw new Error('Redifining stages global!'); this.stages = {}; stages.AbstractStage = class AbstractStage { - // Initialize this stage's internal state. The glyph may already include - // output from this stage. If the internal state can be initialized in such - // a way to achieve that output, it should be; doing so allows users to make - // some edits, switch to another glyph, and later resume where they left off. + // This method should fill in this stage's field in glyph.stages. The glyph + // may already have a value for this stage set. If so, this stage's internal + // state should be initialized in such a way to achieve that output, if that + // is possible; doing so allows users to make some edits, switch to another + // glyph, and then switch back and continue where they left off. constructor(glyph) { // Session variables the interface by which the stage interacts with UI: // - type - String type of this stage. @@ -27,8 +28,8 @@ stages.AbstractStage = class AbstractStage { this.colors = ['#0074D9', '#2ECC40', '#FFDC00', '#FF4136', '#7FDBFF', '#001F3F', '#39CCCC', '#3D9970', '#01FF70', '#FF851B']; } - // Update the stage's internal state and the editor.glyph Session variable - // based on the event. + // Update the stage's internal state and possibly update this stage's field + // in glyph.stages based on the event. handleEvent(glyph, event, template) { assert(false, 'handleEvent was not implemented!'); } diff --git a/client/lib/bridges.js b/client/lib/bridges.js index afdbbf30..def4d154 100644 --- a/client/lib/bridges.js +++ b/client/lib/bridges.js @@ -17,17 +17,16 @@ stages.bridges = class BridgesStage extends stages.AbstractStage { 'Connect each pair of points on the glyph outline such that ' + 'the segment connecting those points is part of some stroke ' + 'outline. Click on a bridge to drop it.'); - const bridges = stroke_extractor.getBridges(glyph); + const bridges = stroke_extractor.getBridges(glyph.stages.path); this.bridges = bridges.bridges; this.endpoints = []; bridges.endpoints.map( (path) => this.endpoints = this.endpoints.concat(path)); this.selected_point = undefined; - glyph.stages.strokes = glyph.stages.strokes || this.bridges; + glyph.stages.bridges = glyph.stages.bridges || this.bridges; } handleClickOnBridge(glyph, bridge) { glyph.stages.bridges = removeBridge(glyph.stages.bridges, bridge); - Session.set('editor.glyph', glyph); } handleClickOnPoint(glyph, point) { if (this.selected_point === undefined) { @@ -47,7 +46,6 @@ stages.bridges = class BridgesStage extends stages.AbstractStage { return; } glyph.stages.bridges.push(bridge); - Session.set('editor.glyph', glyph); } handleEvent(glyph, event, template) { if (template.x1 !== undefined) { @@ -87,7 +85,8 @@ stages.bridges = class BridgesStage extends stages.AbstractStage { stroke: color, } })); - const strokes = stroke_extractor.getStrokes(glyph); + const strokes = stroke_extractor.getStrokes( + glyph.stages.path, glyph.stages.bridges); const n = strokes.strokes.length; const message = `Extracted ${n} stroke${n == 1 ? '' : 's'}.`; Session.set('stage.status', strokes.log.concat([{message: message}])); diff --git a/client/lib/strokes.js b/client/lib/strokes.js index 84025b3c..da56aaf6 100644 --- a/client/lib/strokes.js +++ b/client/lib/strokes.js @@ -29,13 +29,15 @@ stages.strokes = class StrokesStage extends stages.AbstractStage { 'The final number of paths must agree with the stroke count ' + 'in the character metadata.'); const include = this.include = {}; - this.strokes = stroke_extractor.getStrokes(glyph).strokes; + this.strokes = stroke_extractor.getStrokes( + glyph.stages.path, glyph.stages.bridges).strokes; this.strokes.map((stroke) => include[stroke] = true); if (glyph.stages.strokes && glyph.stages.strokes.length > 0 && glyph.stages.strokes.filter((x) => !include[x]).length === 0) { this.strokes.map((stroke) => include[stroke] = false); glyph.stages.strokes.map((stroke) => include[stroke] = true); } + glyph.stages.strokes = this.strokes.filter((x) => this.include[x]); } handleEvent(glyph, event, template) { assert(this.include.hasOwnProperty(template.d)); diff --git a/lib/stroke_extractor.js b/lib/stroke_extractor.js index 8076b029..6ba67de6 100644 --- a/lib/stroke_extractor.js +++ b/lib/stroke_extractor.js @@ -354,9 +354,8 @@ if (this.stroke_extractor !== undefined) { } this.stroke_extractor = {}; -stroke_extractor.getBridges = (glyph, classifier) => { - assert(glyph.stages.path) - const paths = svg.convertSVGPathToPaths(glyph.stages.path); +stroke_extractor.getBridges = (path, classifier) => { + const paths = svg.convertSVGPathToPaths(path); const endpoints = []; for (let i = 0; i < paths.length; i++) { for (let j = 0; j < paths[i].length; j++) { @@ -368,10 +367,8 @@ stroke_extractor.getBridges = (glyph, classifier) => { return {endpoints: endpoints, bridges: bridges}; } -stroke_extractor.getStrokes = (glyph) => { - assert(glyph.stages.path) - assert(glyph.stages.bridges) - const paths = svg.convertSVGPathToPaths(glyph.stages.path); +stroke_extractor.getStrokes = (path, bridges) => { + const paths = svg.convertSVGPathToPaths(path); const endpoints = []; for (let i = 0; i < paths.length; i++) { for (let j = 0; j < paths[i].length; j++) { @@ -379,8 +376,7 @@ stroke_extractor.getStrokes = (glyph) => { } } const log = []; - const stroke_paths = extractStrokes( - paths, endpoints, glyph.stages.bridges, log); + const stroke_paths = extractStrokes(paths, endpoints, bridges, log); const strokes = stroke_paths.map((x) => svg.convertPathsToSVGPath([x])); return {log: log, strokes: strokes}; }