Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ea6d6a7
Fixed logic for calculating slope of slider
tlnguyen2009 Oct 22, 2025
8a5bcd2
Fixed the degree/radians option for slider angle input
tlnguyen2009 Oct 22, 2025
3fe5be8
Fix wrong animation with mechanism when slider angle equals 90 degree…
tlnguyen2009 Oct 25, 2025
eb8f6f2
Fixed: Mechanism with slider doesn't move or animate when hit play bu…
tlnguyen2009 Nov 2, 2025
a51b7d0
Fixed: Unexpected double blue path line for slider
tlnguyen2009 Nov 2, 2025
be163ac
Correct velocity calculations for angular velocity of a 4-bar link. D…
mwalsh001 Dec 1, 2025
0db0ef7
Angular velocity graph now displays the angular velocity of the curre…
mwalsh001 Dec 1, 2025
c18201d
Fixed "Download CSV button for angular velocity to download file for …
mwalsh001 Dec 1, 2025
6fd7940
Fixed sign issue for CD link, will need to be re-visited once loop se…
mwalsh001 Dec 1, 2025
d22118f
Show velocity for current link.
mwalsh001 Dec 8, 2025
3b9327f
Gets the current input speed of the mechanism from StateService to ca…
mwalsh001 Dec 8, 2025
cc159b5
Calculate link lengths through mechanism state and not manually to ge…
mwalsh001 Jan 26, 2026
7dce3d9
4-bar velocity calculations.
mwalsh001 Feb 20, 2026
1030bc8
4-bar velocity calculations.
mwalsh001 Mar 23, 2026
484eb4c
Link angular velocity and acceleration calculations and integration w…
mwalsh001 Mar 23, 2026
e871275
Initial slider-crank implementation.
mwalsh001 Mar 27, 2026
792f0fc
Merge branch 'main' into 235-integrate-velocity-and-acceleration-anal…
mwalsh001 Mar 27, 2026
e14fa91
Slider-crank angular velocity and acceleration.
mwalsh001 Apr 2, 2026
4ee16a4
Merge branch 'main' into Slider-move-in-a-wrong-path-when-changing-sl…
mwalsh001 Apr 2, 2026
42e026e
Merge branch 'Slider-move-in-a-wrong-path-when-changing-slider-angle'…
mwalsh001 Apr 2, 2026
725cef6
Slider-crank angular velocity and acceleration.
mwalsh001 Apr 2, 2026
6338069
Delete unused file.
mwalsh001 Apr 2, 2026
03cc2dc
Integrate kinematic values into side panel in place of "N/A" placehol…
mwalsh001 Apr 13, 2026
9792c67
Fixed issue with RPM speed not changing and CCW/CW.
mwalsh001 Apr 14, 2026
b402752
Merge branch 'main' into 235-integrate-velocity-and-acceleration-anal…
mwalsh001 Apr 14, 2026
29d67d9
Unmerged main - caused issues with data display of kinematics.
mwalsh001 Apr 14, 2026
517f2ee
Added back hex decoding for numeric fields during URL import without …
mwalsh001 Apr 14, 2026
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
88 changes: 86 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
"lodash": "^4.17.21",
"lz-string": "^1.5.0",
"material": "^0.7.5",
"math.js": "^1.1.46",
"mathjs": "^15.1.0",
"ng2-charts": "^5.0.4",
"papaparse": "^5.4.1",
"rxjs": "~7.8.0",
Expand Down
64 changes: 45 additions & 19 deletions src/app/components/Blocks/graph-section/graph-section.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ export class GraphSectionComponent implements OnInit, AfterViewInit, OnDestroy {

@ViewChild('graphCanvas', { static: true }) private graphCanvas!: ElementRef<HTMLCanvasElement>;
@ViewChild('overlayCanvas', { static: true }) private overlayCanvas!: ElementRef<HTMLCanvasElement>;



chart?: Chart;
showGrid = true;
showXCurve = true;
showYCurve = true;

private readonly destroy$ = new Subject<void>();

constructor(private readonly animationService: AnimationService, private interactionService: InteractionService) {}
Expand All @@ -73,10 +73,10 @@ export class GraphSectionComponent implements OnInit, AfterViewInit, OnDestroy {
}
private syncOverlayCanvas(): void {
if (!this.chart) return;

const chartCanvas = this.graphCanvas.nativeElement;
const overlay = this.overlayCanvas.nativeElement;

// Use the chart's display size, not internal resolution
const rect = chartCanvas.getBoundingClientRect();
overlay.width = rect.width;
Expand Down Expand Up @@ -106,7 +106,7 @@ export class GraphSectionComponent implements OnInit, AfterViewInit, OnDestroy {
animation: false,
hover: {
mode: 'index',
intersect: false
intersect: false
},
interaction: {
mode: 'index',
Expand Down Expand Up @@ -173,17 +173,17 @@ export class GraphSectionComponent implements OnInit, AfterViewInit, OnDestroy {

private get chartDatasets(): ChartDataset<'line'>[] {
const datasets: ChartDataset<'line'>[] = [];

// Add X data if enabled - always use first color
if (this.showXCurve && this.inputXData) {
const xDatasets = this.inputXData.map((dataset, index) => ({
...dataset,
borderColor: this.colorScheme.domain[0],
borderColor: this.colorScheme.domain[0],
backgroundColor: this.colorScheme.domain[0]
}));
datasets.push(...xDatasets);
}

// Add Y data if enabled - always use second color
if (this.showYCurve && this.inputYData) {
const yDatasets = this.inputYData.map((dataset, index) => ({
Expand All @@ -193,7 +193,7 @@ export class GraphSectionComponent implements OnInit, AfterViewInit, OnDestroy {
}));
datasets.push(...yDatasets);
}

return datasets;
}

Expand Down Expand Up @@ -226,17 +226,17 @@ export class GraphSectionComponent implements OnInit, AfterViewInit, OnDestroy {

private updateGraphAtStep(step: number): void {
if (!this.chart || !this.overlayCanvas) return;

const overlay = this.overlayCanvas.nativeElement;
const ctx = overlay.getContext('2d');
if (!ctx) return;

const xScale = this.chart.scales['x'];
const xPos = xScale.getPixelForValue(step);
if (xPos === undefined) return;

ctx.clearRect(0, 0, overlay.width, overlay.height);

ctx.beginPath();
ctx.moveTo(xPos, this.chart.chartArea.top);
ctx.lineTo(xPos, this.chart.chartArea.bottom);
Expand All @@ -248,7 +248,7 @@ export class GraphSectionComponent implements OnInit, AfterViewInit, OnDestroy {
onToggleGrid(event: Event): void {
const target = event.target as HTMLInputElement;
this.showGrid = target.checked;

if (this.chart) {
this.chart.destroy();
this.createChart();
Expand All @@ -266,9 +266,35 @@ export class GraphSectionComponent implements OnInit, AfterViewInit, OnDestroy {
}

downloadCSV(): void {
if (!this.inputLabels?.length || !this.inputXData?.length || !this.inputYData?.length) return;
console.log('downloadCSV clicked!', {
labels: this.inputLabels,
x: this.inputXData,
y: this.inputYData
});

if (!this.inputLabels?.length) {
alert('No data to export.');
return;
}

const hasX = this.inputXData.length;
const hasY = this.inputYData.length;

if (!hasX && !hasY) {
alert('No data to export.');
return;
}

const header = ['Time'];
if (hasX) {
header.push(this.inputXData[0].label ?? "X Data");
}
if (hasY) {
header.push(this.inputYData[0].label ?? "Y Data");
}

const rows: string[] = [header.join(',')];

const rows = ['Time,X Data,Y Data'];
const maxLength = Math.max(
this.inputLabels.length,
this.inputXData[0]?.data?.length || 0,
Expand All @@ -291,7 +317,7 @@ export class GraphSectionComponent implements OnInit, AfterViewInit, OnDestroy {
const canvas = this.chart.canvas;
const exportCanvas = document.createElement('canvas');
const ctx = exportCanvas.getContext('2d');

if (!ctx) return;

exportCanvas.width = canvas.width;
Expand All @@ -300,7 +326,7 @@ export class GraphSectionComponent implements OnInit, AfterViewInit, OnDestroy {
// White background
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, exportCanvas.width, exportCanvas.height);

// Temporarily hide vertical line
const currentStep = (this.chart as any).currentTimeStep;
delete (this.chart as any).currentTimeStep;
Expand Down Expand Up @@ -331,4 +357,4 @@ export class GraphSectionComponent implements OnInit, AfterViewInit, OnDestroy {
link.download = filename;
link.click();
}
}
}
Loading
Loading