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 2 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>('surveys');
marcosantiagomuro marked this conversation as resolved.
Show resolved Hide resolved

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