From 5c575eb079d58aea127f9d0af54e13f1991e6901 Mon Sep 17 00:00:00 2001 From: stackdump Date: Thu, 23 Nov 2023 23:32:44 -0600 Subject: [PATCH] add color to snapshot --- model.ts | 28 +++++++++++++++++++--------- package-lock.json | 4 ++-- package.json | 2 +- snapshot.ts | 25 ++++++++++++++++++------- 4 files changed, 40 insertions(+), 19 deletions(-) diff --git a/model.ts b/model.ts index 44e4efd..7ac308c 100644 --- a/model.ts +++ b/model.ts @@ -88,6 +88,9 @@ export interface Result { out: Vector; ok: boolean; role: string; + inhibited?: boolean; + overflow?: boolean; + underflow?: boolean; } export interface Model { @@ -268,19 +271,25 @@ export function newModel({schema, declaration, type}: ModelOptions): Model { return ok; } - function vectorAdd(state: Vector, delta: Vector, multiple: number): { out: Vector; ok: boolean } { + function vectorAdd(state: Vector, delta: Vector, multiple: number): { + out: Vector; ok: boolean; overflow: boolean; underflow: boolean; + } { + let overflow = false; + let underflow = false; const cap = capacityVector(); const out: Vector = []; let ok = true; for (const i in state) { out[i] = (state[i] + (delta[i] || 0) * multiple); if (out[i] < 0) { + underflow = true; ok = false; // underflow: contains negative } else if (cap[i] > 0 && cap[i] - out[i] < 0) { + overflow = true; ok = false; // overflow: exceeds capacity } } - return {out, ok}; + return {out, ok, overflow, underflow}; } function guardFails(state: Vector, action: string, multiple: number) { @@ -300,11 +309,12 @@ export function newModel({schema, declaration, type}: ModelOptions): Model { function testFire(state: Vector, action: string, multiple: number): Result { const t = def.transitions.get(action); - if (!t || guardFails(state, action, multiple)) { - return {out: [], ok: false, role: t?.role?.label || "unknown"}; + const inhibited = guardFails(state, action, multiple); + if (!t || inhibited) { + return {out: [], ok: false, role: t?.role?.label || "unknown", inhibited}; } - const res = vectorAdd(state, t.delta, multiple); - return {out: res.out, ok: res.ok, role: t.role.label}; + const {out, ok,underflow, overflow} = vectorAdd(state, t.delta, multiple); + return {out, ok, role: t.role.label, inhibited, overflow, underflow}; } function fire(state: Vector, action: string, multiple: number, resolve?: (res: Result) => void, reject?: (res: Result) => void): Result { @@ -324,7 +334,7 @@ export function newModel({schema, declaration, type}: ModelOptions): Model { elementaryOutputs++; } } - res = {...res, ok: !failsHardCap && elementaryOutputs < 2 }; + res = {...res, ok: !failsHardCap && elementaryOutputs < 2, overflow: failsHardCap }; break; case ModelType.workflow: let wfOutputs = 0; @@ -339,7 +349,7 @@ export function newModel({schema, declaration, type}: ModelOptions): Model { wfOut[i] = res.out[i]; } // NOTE: ignore negative values } - res = {...res, out: wfOut, ok: !failsWfCap && wfOutputs < 2 }; + res = {...res, out: wfOut, ok: !failsWfCap && wfOutputs < 2, overflow: failsWfCap }; break; } if (res.ok) { @@ -399,7 +409,7 @@ export function newModel({schema, declaration, type}: ModelOptions): Model { if (outStates <= 1) { res.ok = true; } - return { out, ok: res.ok, role: res.role }; + return { out, ok: res.ok, role: res.role, inhibited: res.inhibited }; } if (declaration) { diff --git a/package-lock.json b/package-lock.json index 6ebb7c5..ec51c8c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@pflow-dev/metamodel", - "version": "0.3.4", + "version": "0.4.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@pflow-dev/metamodel", - "version": "0.3.4", + "version": "0.4.0", "license": "MIT", "devDependencies": { "@babel/core": "^7.14.3", diff --git a/package.json b/package.json index 8055281..f349743 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@pflow-dev/metamodel", - "version": "0.3.4", + "version": "0.4.0", "main": "/index.js", "types": "/index.d.ts", "description": "create workflows and petriNets with a DSL", diff --git a/snapshot.ts b/snapshot.ts index 7d545f5..7ebb971 100644 --- a/snapshot.ts +++ b/snapshot.ts @@ -1,4 +1,4 @@ -import {Model, Place, Transition} from "./model"; +import {Model, Place, Transition, Vector} from "./model"; const tokenTemplate = ({p, tokens}: { p: Place; tokens: number }) => { if (tokens === 0) { @@ -32,12 +32,13 @@ interface ArcParams { const arcTemplate = ({stroke, markerEnd, weight, x1, y1, x2, y2, midX, offsetX, midY, offsetY}: ArcParams) => `` + `${weight}`; + const transitionTemplate = ({fill, stroke, t}: { fill: string; stroke: string; t: Transition }) => `` + `${t.label}`; -const placeTemplate = ({p}: { p: Place }) => +const placeTemplate = ({p, tokens}: { p: Place; tokens: number }) => `` + - `${tokenTemplate({p, tokens: p.initial})}` + + `${tokenTemplate({p, tokens})}` + `${p.label}`; const template = ({ page, @@ -92,15 +93,25 @@ function getArcPoints( type HashChar = "#" | "%32"; -export function snapshot(model: Model, options?: { hashChar?: HashChar }) { +export function snapshot(model: Model, options?: { state?: Vector; hashChar?: HashChar }) { + const state = options?.state; const hashChar = options?.hashChar ? options.hashChar : "#"; // use "%32" for data URI - const {transitions, places} = model.def; const page = model.getSize(); // FIXME: port from other repo let transitionTags = ""; transitions.forEach((t) => { + function getFill() { + const res = model.testFire(state, t.label, 1); + if (res.ok) { + return "#62fa75"; + } + if (res.inhibited) { + return "#fab5b0"; + } + return "#ffffff"; + } transitionTags += transitionTemplate({ - fill: "white", + fill: getFill(), // "white", // TODO: colorize model stroke: "black", t, }); @@ -108,7 +119,7 @@ export function snapshot(model: Model, options?: { hashChar?: HashChar }) { const placeIndex: Array = []; let placeTags = ""; places.forEach((p) => { - placeTags += placeTemplate({p: p}); + placeTags += placeTemplate({p: p, tokens: state? state[p.offset] : p.initial}); placeIndex[p.offset] = p; }); let arcTags = "";