Skip to content
This repository has been archived by the owner on May 4, 2024. It is now read-only.

90 plot survey #111

Merged
merged 4 commits into from
Nov 9, 2023
Merged
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
6 changes: 4 additions & 2 deletions backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import { RCService } from './conditions/rc.service';
import { DB_GROUPD_CONFIG, DB_LIRAMAP_CONFIG } from './database';
import { RoadController } from './roads/road.controller';
import { RoadService } from './roads/road.service';
import { SurveyService } from './surveys/survey.service';
import { SurveyController } from './surveys/survey.controller';

const database = (config: any, name: string) => {
return KnexModule.forRootAsync(
Expand All @@ -35,7 +37,7 @@ const database = (config: any, name: string) => {
serveRoot: '/images/',
}),
],
controllers: [AppController, RCController, RoadController],
providers: [AppService, ConfigService, RCService, RoadService],
controllers: [AppController, RCController, RoadController, SurveyController],
providers: [AppService, ConfigService, RCService, RoadService, SurveyService],
})
export class AppModule {}
10 changes: 10 additions & 0 deletions backend/src/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ export interface Condition {
value: number;
}

/**
* Type of answer from backend for the conditions of a survey.
*/
export interface SurveyConditions {
type: number;
value: number;
distance_survey: number;
}

/**
* The OSM id of a way.
*/
Expand Down Expand Up @@ -55,6 +64,7 @@ export enum ImageType {
* The measurement types.
*/
export enum MeasurementType {
Crack = 0,
Rutting = 1,
MacroTexture = 2,
LaneMarking = 3,
Expand Down
17 changes: 17 additions & 0 deletions backend/src/surveys/survey.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Controller, Get, Query } from '@nestjs/common';

import { SurveyConditions } from 'src/models';
import { SurveyService } from './survey.service';

@Controller('conditions')
export class SurveyController {
constructor(private readonly service: SurveyService) {}

@Get('surveys')
getWayConditions(
@Query() query: { surveyId: string },
): Promise<SurveyConditions[]> {
const { surveyId } = query;
return this.service.getSurveyConditions(surveyId);
}
}
35 changes: 35 additions & 0 deletions backend/src/surveys/survey.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Injectable } from '@nestjs/common';
import { InjectConnection, Knex } from 'nestjs-knex';
import { Measurement } from '../tables';
import { MeasurementType, SurveyConditions } from '../models';

@Injectable()
export class SurveyService {
constructor(
@InjectConnection('group-d') private readonly knex_group_d: Knex,
) {}

/**
* Query the data for a survey given his ID
*/
async getSurveyConditions(surveyId: string): Promise<SurveyConditions[]> {
return (
await Measurement(this.knex_group_d)
.select('type_index', 'value', 'distance_survey')
.where('fk_survey_id', surveyId)
.orderBy('distance_survey', 'asc')
).map(
(value: {
type_index: string;
value: number;
distance_survey: number;
}) => {
return {
type: MeasurementType[value.type_index],
value: value.value,
distance_survey: value.distance_survey,
};
},
);
}
}
6 changes: 3 additions & 3 deletions backend/src/tables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,17 @@ export interface IMeasurement {
timestamp: Date;
}

export const Measurement = (k: Knex) => k.from<IImage>('measurement');
export const Measurement = (k: Knex) => k.from<IMeasurement>('measurement');

export interface ISurvey {
id?: number;
section_geom: Geometry;
timestamp: Date;
/** The Dynatest id of the survey or null */
/** The Dynatest id of the surveys or null */
survey_id: number;
}

export const Survey = (k: Knex) => k.from<IImage>('survey');
export const Survey = (k: Knex) => k.from<ISurvey>('survey');

export interface IWay {
id?: number;
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ const App: FC = () => {
<Routes>
<Route index element={<Navigate to="/map" replace />} />
<Route path="/map" element={<Main />} />
<Route path="/road-details" element={<Inspect />} />
<Route path="/inspect" element={<Inspect />} />
<Route path="/inspect/:type" element={<Inspect />} />
<Route path="/inspect/:type/:id" element={<Inspect />} />
</Routes>
</Router>
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/Components/Map/Roads.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const Roads: React.FC<Props> = ({ roads, onSelectedRoad }) => {
onClick={(position) => {
console.log(road, position);
// TODO: remove when possible to select a road
navigate('/road-details');
navigate('/inspect');

if (onSelectedRoad) {
onSelectedRoad(road, position);
Expand Down
135 changes: 83 additions & 52 deletions frontend/src/Components/RoadDetails/ConditionsGraph.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FC, useEffect, useMemo, useRef } from 'react';
import { FC, useEffect, useMemo, useRef, useState } from 'react';
import {
ActiveElement,
CategoryScale,
Expand All @@ -11,12 +11,15 @@ import {
LinearScale,
LineElement,
PointElement,
ScaleChartOptions,
Title,
Tooltip,
} from 'chart.js';
import 'chart.js/auto';
import { Scatter } from 'react-chartjs-2';
import zoomPlugin from 'chartjs-plugin-zoom';
import { ConditionsGraphData } from '../../models/conditions';
import { DeepPartial } from 'chart.js/dist/types/utils';

Chart.register(
CategoryScale,
Expand All @@ -29,7 +32,13 @@ Chart.register(
zoomPlugin,
);

const options = (minAndMax: number[]): ChartOptions<'scatter'> => ({
/**
* this function sets the viewing option for the chart graph
**/
const options = (
data?: ConditionsGraphData[],
scales?: DeepPartial<ScaleChartOptions<'scatter'>>,
): ChartOptions<'scatter'> => ({
responsive: true,
maintainAspectRatio: false,
plugins: {
Expand All @@ -45,8 +54,11 @@ const options = (minAndMax: number[]): ChartOptions<'scatter'> => ({
// modifierKey: 'ctrl',
},
limits: {
x: { min: 0, max: 100, minRange: 20 },
y: { min: 0, max: 10 },
x: {
min: data ? Math.min(...data.map((item) => item.minX)) : 0,
max: data ? Math.max(...data.map((item) => item.maxX)) : 100,
minRange: 20,
},
},
zoom: {
// vv drag to zoom option could be a solution vv
Expand All @@ -64,66 +76,84 @@ const options = (minAndMax: number[]): ChartOptions<'scatter'> => ({
},
},
},
scales: {
x: {
title: {
display: true,
text: 'distance (m)',
},
ticks: {
stepSize: 10,
callback: (tick: string | number) =>
Math.round(parseFloat(tick.toString())),
},
},
//TODO will be a variable passed from parent
KPI: {
type: 'linear',
position: 'left',
display: 'auto',
min: Math.floor(minAndMax[0]),
max: Math.ceil(minAndMax[1]),
title: {
display: true,
text: 'KPI',
},
},
DI: {
type: 'linear',
position: 'right',
display: 'auto',
min: Math.floor(minAndMax[2]),
max: Math.ceil(minAndMax[3]),
title: {
display: true,
text: 'DI',
},
},
},
scales: scales,
});

interface Props {
data: ChartData<'scatter', number[], number> | undefined;
minAndMax: number[];
data?: ConditionsGraphData[];
}

/**
* The Graph displaying the road parameter data in the Inspect Page
* @author Muro
* @author Muro, Kerbourc'h
*/
const ConditionsGraph: FC<Props> = ({ data, minAndMax }) => {
const ref = useRef<Chart<'scatter', number[], number>>(null);
const ConditionsGraph: FC<Props> = ({ data }) => {
const ref = useRef<Chart<'scatter', { x: number; y: number }[]>>(null);
const [graphLines, setGraphLines] =
useState<ChartData<'scatter', { x: number; y: number }[]>>();

useEffect(() => {
if (ref.current === null) return;
const chart = ref.current;
chart.update();
}, [ref, data]);

useEffect(() => {
if (data === undefined) {
setGraphLines(undefined);
return;
}
setGraphLines({
//type: 'scatter',
datasets: data.map((item) => {
return {
showLine: true,
label: item.type,
borderColor: 'rgb(255, 99, 132)',
borderWidth: 2,
fill: false,
data: item.dataValues,
yAxisID: item.type,
};
}),
});
}, [data]);

// attach events to the graph options
const graphOptions: ChartOptions<'scatter'> = useMemo(
() => ({
...options(minAndMax),
const graphOptions: ChartOptions<'scatter'> = useMemo(() => {
const scales: DeepPartial<ScaleChartOptions<'scatter'>> = {
scales: {
x: {
title: {
display: true,
text: 'distance (m)',
},
ticks: {
stepSize: 10,
callback: (tick: string | number) =>
Math.round(parseFloat(tick.toString())),
},
},
},
};

data?.forEach((item) => {
if (scales.scales === undefined) return;
scales.scales[item.type] = {
type: 'linear',
position: 'left',
display: 'auto',
min: item.minY - 1,
max: item.maxY + 1,
title: {
display: true,
text: item.type,
},
};
});

return {
...options(data, scales.scales),
onClick: (
event: ChartEvent,
elts: ActiveElement[],
Expand All @@ -134,13 +164,14 @@ const ConditionsGraph: FC<Props> = ({ data, minAndMax }) => {
const pointIndex = elt.index;
console.log(pointIndex, event, elts);
},
}),
[minAndMax],
);
};
}, [data]);

return (
<div className="road-conditions-graph">
{data && <Scatter ref={ref} data={data} options={graphOptions} />}
{data && graphLines && (
<Scatter ref={ref} data={graphLines} options={graphOptions} />
)}
</div>
);
};
Expand Down
Loading