Reactor System
About 2 min
Reactor System
Reactors are used to respond to entity changes in real time and automatically perform actions.
Concepts
Reactors are an event-driven mechanism that can:
- Listen for entity add, modify, and delete operations
- Automatically respond to changes and perform associated actions
- Implement dependencies between entities, such as associative dimensions
Custom Reactor
Implement custom reaction logic through event listeners.
const { CadEventManager, CadEvents, Engine, CircleEnt, PolylineEnt } = vjcad;
class CircleBoundingBoxReactor {
constructor() {
this.enabled = true;
this.boundingLines = new Map(); // Store associated data
}
install() {
// Listen for entity addition
Engine.eventManager.on(CadEvents.EntityAdded, (args) => {
if (this.enabled && args.entity.type === 'CIRCLE') {
this.createBoundingBox(args.entity);
}
});
// Listen for entity modification
Engine.eventManager.on(CadEvents.EntityModified, (args) => {
if (this.enabled && args.entity.type === 'CIRCLE') {
this.updateBoundingBox(args.entity);
}
});
// Listen for entity deletion
Engine.eventManager.on(CadEvents.EntitiesErased, (args) => {
args.entities.forEach(entity => {
if (entity.type === 'CIRCLE') {
this.removeBoundingBox(entity);
}
});
});
}
createBoundingBox(circle) {
const r = circle.radius;
const cx = circle.center.x;
const cy = circle.center.y;
const rect = new PolylineEnt();
rect.setPoints([
[cx - r, cy - r],
[cx + r, cy - r],
[cx + r, cy + r],
[cx - r, cy + r]
]);
rect.isClosed = true;
rect.setDefaults();
rect.color = 3;
Engine.addEntities(rect);
this.boundingLines.set(circle.id, rect);
Engine.regen();
}
updateBoundingBox(circle) {
const rect = this.boundingLines.get(circle.id);
if (!rect) return;
const r = circle.radius;
const cx = circle.center.x;
const cy = circle.center.y;
rect.setPoints([
[cx - r, cy - r],
[cx + r, cy - r],
[cx + r, cy + r],
[cx - r, cy + r]
]);
Engine.regen();
}
removeBoundingBox(circle) {
const rect = this.boundingLines.get(circle.id);
if (rect) {
Engine.eraseEntities(rect);
this.boundingLines.delete(circle.id);
Engine.regen();
}
}
toggle() {
this.enabled = !this.enabled;
message.info(`Reactor ${this.enabled ? 'enabled' : 'disabled'}`);
}
}
// Install reactor
const reactor = new CircleBoundingBoxReactor();
reactor.install();Key Events
| Event | Description |
|---|---|
CadEvents.EntityAdded | Triggered after an entity is added |
CadEvents.EntityModified | Triggered after an entity is modified |
CadEvents.EntitiesErased | Triggered after entities are deleted (batch) |
Associative Dimension Reactor
Dimension entities have a built-in reactor mechanism. Use setSourceEntities() to establish association so that dimensions update automatically when the source entity moves.
const { LinearDimensionEnt, LineEnt, Point2D, Engine } = vjcad;
// Create line
const line = new LineEnt([0, 0], [100, 0]);
line.setDefaults();
Engine.addEntities(line);
// Create dimension
const dim = new LinearDimensionEnt(
new Point2D(0, 0),
new Point2D(100, 0),
new Point2D(50, 20),
0
);
dim.setDefaults();
Engine.addEntities(dim);
// Establish association (must be after addEntities)
dim.setSourceEntities(
line.id, -1, // Start-point source entity and segment index (-1 = entire line)
line.id, -1, // End-point source entity
'start', // Start endpoint type
'end' // End endpoint type
);
// Check association state
console.log("isAssociative:", dim.isAssociative);
// When the line moves, the dimension updates automatically
line.move([0, 0], [50, 0]);
Engine.regen();Endpoint Types
| Type | Description |
|---|---|
'start' | Start point |
'end' | End point |
'center' | Center point |
'midpoint' | Midpoint |
Precise Positioning
Use parameterT to specify the proportional position on the segment (0~1):
dim.setSourceEntities(
line.id, -1,
line.id, -1,
undefined, // Do not use pointType
undefined,
0.25, // startParameterT: at 1/4
0.75 // endParameterT: at 3/4
);Supported Dimension Types
LinearDimensionEnt- linear dimensionAlignedDimensionEnt- aligned dimension
Reactor Lifecycle Management
Enable/Disable Control
class MyReactor {
constructor() {
this.enabled = true;
}
toggle() {
this.enabled = !this.enabled;
}
}Data Management
Use Map to store association data:
class MyReactor {
constructor() {
this.relations = new Map(); // entityId -> relatedEntity
}
// Create association
onCreate(entity) {
const related = this.createRelated(entity);
this.relations.set(entity.id, related);
}
// Update association
onModify(entity) {
const related = this.relations.get(entity.id);
if (related) {
this.updateRelated(entity, related);
}
}
// Remove association
onDelete(entity) {
const related = this.relations.get(entity.id);
if (related) {
Engine.eraseEntities(related);
this.relations.delete(entity.id);
}
}
}Notes
- Associative dimensions must be set after
addEntities - Segment index
-1means the whole line - When using
parameterT, setpointTypetoundefined - After association, the dimension updates automatically when the source entity changes