Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 24 additions & 9 deletions src/com/lushprojects/circuitjs1/client/Scope.java
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,10 @@ class Scope {
Canvas imageCanvas;
Context2d imageContext;
int alphaCounter =0;
// XY-plot trail persistence (wall-clock ms). 0 = instant erase (no trail).
int trailPersistence = 200;
static final int DEFAULT_TRAIL_PERSISTENCE = 200;
long lastTrailTime;
// scopeTimeStep to check if sim timestep has changed from previous value when redrawing
double scopeTimeStep;
double scale[]; // Max value to scale the display to show - indexed for each value of UNITS - e.g. UNITS_V, UNITS_A etc.
Expand Down Expand Up @@ -1054,17 +1058,25 @@ void draw2d(Graphics g) {
g.context.translate(rect.x, rect.y);
g.clipRect(0, 0, rect.width, rect.height);

alphaCounter++;

if (alphaCounter>2) {
// fade out plot
alphaCounter=0;
imageContext.setGlobalAlpha(0.01);
if (app.isPrintable()) {
// Wall-clock-based exponential fade. alpha = 1 - exp(-elapsed/persistence)
// makes the trail look the same across simulation speeds: at 60fps a 200ms
// persistence drops a pixel by 1-exp(-16/200) = 7.7% per frame; at 30fps
// the same persistence drops by 1-exp(-33/200) = 15% per frame, so total
// decay over a fixed wall-clock interval is constant.
long now = System.currentTimeMillis();
long elapsed = (lastTrailTime == 0) ? 16 : (now - lastTrailTime);
lastTrailTime = now;
double fadeAlpha;
if (trailPersistence <= 0)
fadeAlpha = 1.0; // instant erase = no trail
else
fadeAlpha = 1.0 - Math.exp(-elapsed / (double) trailPersistence);
if (fadeAlpha > 0) {
imageContext.setGlobalAlpha(fadeAlpha);
if (app.isPrintable())
imageContext.setFillStyle("#ffffff");
} else {
else
imageContext.setFillStyle("#000000");
}
imageContext.fillRect(0,0,rect.width,rect.height);
imageContext.setGlobalAlpha(1.0);
}
Expand Down Expand Up @@ -2211,6 +2223,8 @@ void dumpXml(Document doc, Element root) {

if (text != null)
xmlElm.setAttribute("x", text);
if (trailPersistence != DEFAULT_TRAIL_PERSISTENCE)
XMLSerializer.dumpAttr(xmlElm, "tp", trailPersistence);
}

void undumpXml(XMLDeserializer xml) {
Expand All @@ -2226,6 +2240,7 @@ void undumpXml(XMLDeserializer xml) {
position = xml.parseIntAttr("p", 0);
manDivisions = xml.parseIntAttr("md", 8);
text = xml.parseStringAttr("x", (String)null);
trailPersistence = xml.parseIntAttr("tp", DEFAULT_TRAIL_PERSISTENCE);
// Read trigger settings from parent <o> element before iterating children,
// because parseChildElement() changes the XML context to child <p> elements
int xmlTriggerMode = xml.parseIntAttr("triggerMode", TRIGGER_FREERUN);
Expand Down
26 changes: 24 additions & 2 deletions src/com/lushprojects/circuitjs1/client/ScopePropertiesDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ public class ScopePropertiesDialog extends Dialog implements ValueChangeHandler<
CheckBox elmInfoBox;
TextBox labelTextBox, manualScaleTextBox, divisionsTextBox;
Button applyButton, scaleUpButton, scaleDownButton;
Scrollbar speedBar,positionBar;
Scrollbar speedBar, positionBar, trailBar;
Label trailLabel;
Scope scope;
Grid grid, vScaleGrid, hScaleGrid;
int nx, ny;
Expand Down Expand Up @@ -518,6 +519,20 @@ public void onClick(ClickEvent event) {
viBox.addValueChangeHandler(this);
addItemToGrid(grid, xyBox = new ScopeCheckBox(Locale.LS("Plot X/Y"), "plotxy"));
xyBox.addValueChangeHandler(this);
Grid trailGrid = new Grid(1, 3);
trailGrid.setWidget(0, 0, new Label(Locale.LS("Trail Persistence (ms)")));
// Range 0..2000 ms; step 50; 0 = instant erase (no trail)
trailBar = new Scrollbar(Scrollbar.HORIZONTAL, scope.trailPersistence, 1, 0, 2050, new Command() {
public void execute() {
scope.trailPersistence = trailBar.getValue();
setTrailLabel();
}
});
trailGrid.setWidget(0, 1, trailBar);
trailLabel = new Label("");
trailGrid.setWidget(0, 2, trailLabel);
fp.add(trailGrid);
setTrailLabel();
if (transistor) {
addItemToGrid(grid, vceIcBox = new ScopeCheckBox(Locale.LS("Show Vce vs Ic"), "showvcevsic"));
vceIcBox.addValueChangeHandler(this);
Expand Down Expand Up @@ -625,7 +640,14 @@ void updateRowVisibility() {
void setScopeSpeedLabel() {
scopeSpeedLabel.setText(CircuitElm.getUnitText(scope.calcGridStepX(), "s")+"/div");
}


void setTrailLabel() {
if (scope.trailPersistence <= 0)
trailLabel.setText(Locale.LS("none"));
else
trailLabel.setText(scope.trailPersistence + " ms");
}

void addItemToGrid(Grid g, FocusWidget scb) {
g.setWidget(ny, nx, scb);
if (++nx >= grid.getColumnCount()) {
Expand Down
Loading