diff --git a/src/components/FunctionalArea/Modal/EditOverlayGroupModal/EditOverlayGroupModal.component.test.tsx b/src/components/FunctionalArea/Modal/EditOverlayGroupModal/EditOverlayGroupModal.component.test.tsx
index c96ff7ee872ec2911fd37fd8f1f921aadb310f3f..65884f0964738cd84d099bf4111fec7fcae71e1b 100644
--- a/src/components/FunctionalArea/Modal/EditOverlayGroupModal/EditOverlayGroupModal.component.test.tsx
+++ b/src/components/FunctionalArea/Modal/EditOverlayGroupModal/EditOverlayGroupModal.component.test.tsx
@@ -55,6 +55,7 @@ describe('EditOverlayModal - component', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
     });
 
@@ -76,6 +77,7 @@ describe('EditOverlayModal - component', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
     });
 
@@ -110,6 +112,7 @@ describe('EditOverlayModal - component', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
       overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
@@ -156,6 +159,7 @@ describe('EditOverlayModal - component', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
       overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
@@ -196,6 +200,7 @@ describe('EditOverlayModal - component', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
       overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
@@ -242,6 +247,7 @@ describe('EditOverlayModal - component', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
       overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
@@ -274,6 +280,7 @@ describe('EditOverlayModal - component', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
     });
 
diff --git a/src/components/FunctionalArea/Modal/EditOverlayGroupModal/hooks/useEditOverlayGroup.test.ts b/src/components/FunctionalArea/Modal/EditOverlayGroupModal/hooks/useEditOverlayGroup.test.ts
index 8f627f2cf21b441b9010cb1b1c0cabb98af9b387..8662528c237966f09cdeb5338b2084a223a34e07 100644
--- a/src/components/FunctionalArea/Modal/EditOverlayGroupModal/hooks/useEditOverlayGroup.test.ts
+++ b/src/components/FunctionalArea/Modal/EditOverlayGroupModal/hooks/useEditOverlayGroup.test.ts
@@ -30,6 +30,7 @@ describe('useEditOverlayGroup', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
     });
 
@@ -70,6 +71,7 @@ describe('useEditOverlayGroup', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
     });
 
@@ -113,6 +115,7 @@ describe('useEditOverlayGroup', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
     });
 
@@ -152,6 +155,7 @@ describe('useEditOverlayGroup', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
     });
 
@@ -192,6 +196,7 @@ describe('useEditOverlayGroup', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
     });
 
diff --git a/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx b/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx
index 484ce41b9ca6a374e0c5d10042134a29e388c302..f56bc6a710618fd795b84bfcb8bc0494259bbe80 100644
--- a/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx
+++ b/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx
@@ -57,6 +57,7 @@ describe('EditOverlayModal - component', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
     });
 
@@ -78,6 +79,7 @@ describe('EditOverlayModal - component', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
     });
 
@@ -112,6 +114,7 @@ describe('EditOverlayModal - component', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
       overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
@@ -151,6 +154,7 @@ describe('EditOverlayModal - component', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
       overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
@@ -191,6 +195,7 @@ describe('EditOverlayModal - component', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
       overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
@@ -237,6 +242,7 @@ describe('EditOverlayModal - component', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
       overlays: OVERLAYS_INITIAL_STATE_MOCK,
     });
@@ -267,6 +273,7 @@ describe('EditOverlayModal - component', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
     });
 
diff --git a/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts b/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts
index a0f6504ad1c95272b279f4341f2a90cd0c978649..f0a3fd8473d20a9b61213da2fc000cbe8f2aac06 100644
--- a/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts
+++ b/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts
@@ -29,6 +29,7 @@ describe('useEditOverlay', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
     });
 
@@ -69,6 +70,7 @@ describe('useEditOverlay', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
     });
 
@@ -112,6 +114,7 @@ describe('useEditOverlay', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
     });
 
@@ -152,6 +155,7 @@ describe('useEditOverlay', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
     });
 
@@ -192,6 +196,7 @@ describe('useEditOverlay', () => {
         errorReportState: {},
         layerFactoryState: { id: undefined },
         layerObjectFactoryState: undefined,
+        layerLineFactoryState: undefined,
       },
     });
 
diff --git a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.test.tsx b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.test.tsx
index 7bfed87c90040deabb9981e9480bc7fd5539d52a..3cf8590754fc1b8a41dac5e15f48b1da52c7c7c4 100644
--- a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.test.tsx
+++ b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.test.tsx
@@ -64,6 +64,7 @@ const renderComponent = (
         width: 1,
         height: 1,
       },
+      layerLineFactoryState: undefined,
     },
     models: {
       ...MODELS_DATA_MOCK_WITH_MAIN_MAP,
@@ -88,6 +89,7 @@ describe('LayerImageObjectEditFactoryModal - component', () => {
         ...layerImageFixture,
         glyph: null,
       },
+      layerLine: null,
     });
 
     expect(screen.getByText(/Glyph:/i)).toBeInTheDocument();
@@ -103,6 +105,7 @@ describe('LayerImageObjectEditFactoryModal - component', () => {
         ...layerImageFixture,
         glyph: null,
       },
+      layerLine: null,
     });
 
     const dropdown = screen.getByTestId('autocomplete');
@@ -121,6 +124,7 @@ describe('LayerImageObjectEditFactoryModal - component', () => {
         ...layerImageFixture,
         glyph: null,
       },
+      layerLine: null,
     });
 
     const dropdown = screen.getByTestId('autocomplete');
@@ -168,6 +172,7 @@ describe('LayerImageObjectEditFactoryModal - component', () => {
     renderComponent({
       activeAction: MAP_EDIT_ACTIONS.TRANSFORM_IMAGE,
       layerObject: glyphData,
+      layerLine: null,
     });
 
     const submitButton = screen.getByText(/Submit/i);
@@ -189,6 +194,7 @@ describe('LayerImageObjectEditFactoryModal - component', () => {
         ...layerImageFixture,
         glyph: null,
       },
+      layerLine: null,
     });
 
     store.dispatch({
diff --git a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectFactoryModal.component.test.tsx b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectFactoryModal.component.test.tsx
index b14ea618617053ad92f36e12f3470c836ad7f9fc..f2d498e0b5345787ecd18faee8e1d0a787c05a32 100644
--- a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectFactoryModal.component.test.tsx
+++ b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectFactoryModal.component.test.tsx
@@ -58,6 +58,7 @@ const renderComponent = (): { store: StoreType } => {
         width: 1,
         height: 1,
       },
+      layerLineFactoryState: undefined,
     },
     models: {
       ...MODELS_DATA_MOCK_WITH_MAIN_MAP,
diff --git a/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineEditFactoryModal.component.tsx b/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineEditFactoryModal.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..6924c0382e9cadf0ff906da90b5474141f5a0421
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineEditFactoryModal.component.tsx
@@ -0,0 +1,154 @@
+/* eslint-disable no-magic-numbers */
+import React, { useState } from 'react';
+import './LayerLineFactoryModal.styles.css';
+import { LoadingIndicator } from '@/shared/LoadingIndicator';
+import { Button } from '@/shared/Button';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { currentModelIdSelector } from '@/redux/models/models.selectors';
+import { Color } from '@/types/models';
+import { showToast } from '@/utils/showToast';
+import { closeModal } from '@/redux/modal/modal.slice';
+import { mapEditToolsSetLayerLine } from '@/redux/mapEditTools/mapEditTools.slice';
+import { SerializedError } from '@reduxjs/toolkit';
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
+import { useMapInstance } from '@/utils/context/mapInstanceContext';
+import { mapEditToolsLayerLineSelector } from '@/redux/mapEditTools/mapEditTools.selectors';
+import updateElement from '@/components/Map/MapViewer/utils/shapes/layer/utils/updateElement';
+import { updateLayerLine } from '@/redux/layers/layers.thunks';
+import { layerUpdateLine } from '@/redux/layers/layers.slice';
+import {
+  LayerLineFactoryForm,
+  LayerLineFactoryPayload,
+} from '@/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactory.types';
+import {
+  DEFAULT_ARROW_ANGLE,
+  DEFAULT_ARROW_LENGTH,
+  DEFAULT_ARROW_LINE_TYPE,
+} from '@/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactory.constants';
+import { LayerLineForm } from '@/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineForm.component';
+import { arrowTypesKeysSelector, lineTypesKeysSelector } from '@/redux/shapes/shapes.selectors';
+
+export const LayerLineEditFactoryModal: React.FC = () => {
+  const layerLine = useAppSelector(mapEditToolsLayerLineSelector);
+  const currentModelId = useAppSelector(currentModelIdSelector);
+  const dispatch = useAppDispatch();
+  const { mapInstance } = useMapInstance();
+  const lineTypes = useAppSelector(lineTypesKeysSelector).map(lineType => ({
+    id: lineType,
+    name: lineType,
+  }));
+  const arrowTypes = useAppSelector(arrowTypesKeysSelector).map(arrowType => ({
+    id: arrowType,
+    name: arrowType,
+  }));
+
+  if (!layerLine) {
+    throw new Error('No layer line object');
+  }
+
+  const [isSending, setIsSending] = useState<boolean>(false);
+  const [data, setData] = useState<LayerLineFactoryForm>({
+    color: layerLine.color,
+    lineType: layerLine.lineType,
+    width: layerLine.width,
+    startArrow: layerLine.startArrow.arrowType,
+    endArrow: layerLine.endArrow.arrowType,
+  });
+
+  const getDataToSend = (): LayerLineFactoryPayload => {
+    return {
+      color: data.color,
+      lineType: data.lineType,
+      width: data.width,
+      startArrow: {
+        arrowType: data.startArrow,
+        angle: DEFAULT_ARROW_ANGLE,
+        lineType: DEFAULT_ARROW_LINE_TYPE,
+        length: DEFAULT_ARROW_LENGTH,
+      },
+      endArrow: {
+        arrowType: data.endArrow,
+        angle: DEFAULT_ARROW_ANGLE,
+        lineType: DEFAULT_ARROW_LINE_TYPE,
+        length: DEFAULT_ARROW_LENGTH,
+      },
+      segments: layerLine.segments,
+      z: layerLine.z,
+    };
+  };
+
+  const handleSubmit = async (): Promise<void> => {
+    if (!layerLine) {
+      return;
+    }
+    try {
+      const updatedLayerLine = await dispatch(
+        updateLayerLine({
+          modelId: currentModelId,
+          layerId: layerLine.layer,
+          lineId: layerLine.id,
+          payload: getDataToSend(),
+        }),
+      ).unwrap();
+
+      if (!updatedLayerLine) {
+        showToast({
+          type: 'error',
+          message: 'An error occurred while editing the line.',
+        });
+        return;
+      }
+
+      dispatch(
+        layerUpdateLine({
+          modelId: currentModelId,
+          layerId: updatedLayerLine.layer,
+          layerLine: updatedLayerLine,
+        }),
+      );
+      dispatch(mapEditToolsSetLayerLine(updatedLayerLine));
+      updateElement(mapInstance, updatedLayerLine.layer, updatedLayerLine);
+      showToast({
+        type: 'success',
+        message: 'The line has been successfully updated.',
+      });
+      dispatch(closeModal());
+    } catch (error) {
+      const typedError = error as SerializedError;
+      showToast({
+        type: 'error',
+        message: typedError.message || 'An error occurred while editing the line.',
+      });
+    } finally {
+      setIsSending(false);
+    }
+  };
+
+  const changeValues = (value: string | number | Color, key: string): void => {
+    setData(prevData => ({ ...prevData, [key]: value }));
+  };
+
+  return (
+    <div className="relative flex w-[550px] flex-col gap-4 rounded-b-lg border border-t-[#E1E0E6] bg-white p-[24px]">
+      {isSending && (
+        <div className="c-layer-line-factory-modal-loader">
+          <LoadingIndicator width={44} height={44} />
+        </div>
+      )}
+      <LayerLineForm
+        onChange={changeValues}
+        data={data}
+        lineTypes={lineTypes}
+        arrowTypes={arrowTypes}
+      />
+      <hr />
+      <Button
+        type="button"
+        onClick={handleSubmit}
+        className="justify-center self-end justify-self-end text-base font-medium"
+      >
+        Submit
+      </Button>
+    </div>
+  );
+};
diff --git a/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactory.constants.ts b/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactory.constants.ts
new file mode 100644
index 0000000000000000000000000000000000000000..451a70008369003755c2d67f9a67b1a28b08e640
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactory.constants.ts
@@ -0,0 +1,13 @@
+export const MAX_LINE_WIDTH = 48;
+
+export const MIN_LINE_WIDTH = 1;
+
+export const DEFAULT_LINE_TYPE = 'SOLID';
+
+export const DEFAULT_ARROW = 'NONE';
+
+export const DEFAULT_ARROW_LENGTH = 15;
+
+export const DEFAULT_ARROW_ANGLE = 2.748893571891069;
+
+export const DEFAULT_ARROW_LINE_TYPE = 'SOLID';
diff --git a/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactory.types.ts b/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactory.types.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1282cbbace98d9e43afa96d67ecad57ef526e08f
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactory.types.ts
@@ -0,0 +1,29 @@
+import { Arrow, Color, Segment } from '@/types/models';
+
+export type LayerLineFactoryForm = {
+  color: Color;
+  lineType: string;
+  width: number;
+  startArrow: string;
+  endArrow: string;
+};
+
+export type LayerLineFactoryPayload = {
+  color: Color;
+  lineType: string;
+  width: number;
+  startArrow: Arrow;
+  endArrow: Arrow;
+  segments: Array<Segment>;
+  z: number;
+};
+
+export type LayerLineEditFactoryPayload = {
+  color: Color;
+  lineType: string;
+  width: number;
+  startArrow: Arrow;
+  endArrow: Arrow;
+  segments: Array<Segment>;
+  z: number;
+};
diff --git a/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactoryModal.component.tsx b/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactoryModal.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..aa68b84675a190c9659fbd54cf2b8c90f6514a0e
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactoryModal.component.tsx
@@ -0,0 +1,156 @@
+/* eslint-disable no-magic-numbers */
+import React, { useState } from 'react';
+import './LayerLineFactoryModal.styles.css';
+import { LoadingIndicator } from '@/shared/LoadingIndicator';
+import { Button } from '@/shared/Button';
+import { BLACK_COLOR } from '@/components/Map/MapViewer/MapViewer.constants';
+import { LayerLineForm } from '@/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineForm.component';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import {
+  layersDrawLayerSelector,
+  maxObjectZIndexForLayerSelector,
+} from '@/redux/layers/layers.selectors';
+import { currentModelIdSelector } from '@/redux/models/models.selectors';
+import { Color } from '@/types/models';
+import { layerLineFactoryStateSelector } from '@/redux/modal/modal.selector';
+import { addLayerLine } from '@/redux/layers/layers.thunks';
+import { showToast } from '@/utils/showToast';
+import { layerAddLine } from '@/redux/layers/layers.slice';
+import drawElementOnLayer from '@/components/Map/MapViewer/utils/shapes/layer/utils/drawElementOnLayer';
+import { closeModal } from '@/redux/modal/modal.slice';
+import { mapEditToolsSetActiveAction } from '@/redux/mapEditTools/mapEditTools.slice';
+import { SerializedError } from '@reduxjs/toolkit';
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
+import { useMapInstance } from '@/utils/context/mapInstanceContext';
+import {
+  LayerLineFactoryForm,
+  LayerLineFactoryPayload,
+} from '@/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactory.types';
+import { arrowTypesKeysSelector, lineTypesKeysSelector } from '@/redux/shapes/shapes.selectors';
+import {
+  DEFAULT_ARROW,
+  DEFAULT_ARROW_ANGLE,
+  DEFAULT_ARROW_LENGTH,
+  DEFAULT_ARROW_LINE_TYPE,
+  DEFAULT_LINE_TYPE,
+  MIN_LINE_WIDTH,
+} from '@/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactory.constants';
+
+export const LayerLineFactoryModal: React.FC = () => {
+  const drawLayer = useAppSelector(layersDrawLayerSelector);
+  const currentModelId = useAppSelector(currentModelIdSelector);
+  const layerLineFactoryState = useAppSelector(layerLineFactoryStateSelector);
+  const maxZIndex = useAppSelector(state => maxObjectZIndexForLayerSelector(state, drawLayer));
+  const dispatch = useAppDispatch();
+  const lineTypes = useAppSelector(lineTypesKeysSelector).map(lineType => ({
+    id: lineType,
+    name: lineType,
+  }));
+  const arrowTypes = useAppSelector(arrowTypesKeysSelector).map(arrowType => ({
+    id: arrowType,
+    name: arrowType,
+  }));
+  const { mapInstance } = useMapInstance();
+
+  const [isSending, setIsSending] = useState<boolean>(false);
+  const [data, setData] = useState<LayerLineFactoryForm>({
+    color: BLACK_COLOR,
+    lineType: DEFAULT_LINE_TYPE,
+    width: MIN_LINE_WIDTH,
+    startArrow: DEFAULT_ARROW,
+    endArrow: DEFAULT_ARROW,
+  });
+
+  const getDataToSend = (): LayerLineFactoryPayload => {
+    return {
+      color: data.color,
+      lineType: data.lineType,
+      width: data.width,
+      startArrow: {
+        arrowType: data.startArrow,
+        angle: DEFAULT_ARROW_ANGLE,
+        lineType: DEFAULT_ARROW_LINE_TYPE,
+        length: DEFAULT_ARROW_LENGTH,
+      },
+      endArrow: {
+        arrowType: data.endArrow,
+        angle: DEFAULT_ARROW_ANGLE,
+        lineType: DEFAULT_ARROW_LINE_TYPE,
+        length: DEFAULT_ARROW_LENGTH,
+      },
+      segments: layerLineFactoryState || [],
+      z: maxZIndex + 1,
+    };
+  };
+
+  const handleSubmit = async (): Promise<void> => {
+    if (!layerLineFactoryState || !drawLayer) {
+      return;
+    }
+    try {
+      const layerLine = await dispatch(
+        addLayerLine({
+          modelId: currentModelId,
+          layerId: drawLayer,
+          payload: getDataToSend(),
+        }),
+      ).unwrap();
+      if (!layerLine) {
+        showToast({
+          type: 'error',
+          message: 'An error occurred while adding a new line.',
+        });
+        return;
+      }
+      dispatch(layerAddLine({ modelId: currentModelId, layerId: drawLayer, layerLine }));
+      drawElementOnLayer({
+        mapInstance,
+        activeLayer: drawLayer,
+        object: layerLine,
+        drawFunctionKey: 'drawLine',
+      });
+      showToast({
+        type: 'success',
+        message: 'A new line has been successfully added.',
+      });
+      dispatch(closeModal());
+      dispatch(mapEditToolsSetActiveAction(null));
+    } catch (error) {
+      const typedError = error as SerializedError;
+      showToast({
+        type: 'error',
+        message: typedError.message || 'An error occurred while adding a new line.',
+      });
+    } finally {
+      setIsSending(false);
+    }
+  };
+
+  const changeValues = (value: string | number | Color, key: string): void => {
+    setData(prevData => ({ ...prevData, [key]: value }));
+  };
+
+  return (
+    <div className="relative flex w-[550px] flex-col gap-4 rounded-b-lg border border-t-[#E1E0E6] bg-white p-[24px]">
+      {isSending && (
+        <div className="c-layer-line-factory-modal-loader">
+          <LoadingIndicator width={44} height={44} />
+        </div>
+      )}
+      <LayerLineForm
+        onChange={changeValues}
+        data={data}
+        lineTypes={lineTypes}
+        arrowTypes={arrowTypes}
+      />
+      <hr />
+      <Button
+        type="button"
+        onClick={handleSubmit}
+        className="justify-center self-end justify-self-end text-base font-medium"
+      >
+        Submit
+      </Button>
+    </div>
+  );
+};
diff --git a/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactoryModal.styles.css b/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactoryModal.styles.css
new file mode 100644
index 0000000000000000000000000000000000000000..e6bb96a9607fbb5a71e5053fd9ef3b478d9cb15c
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactoryModal.styles.css
@@ -0,0 +1,12 @@
+.c-layer-line-factory-modal-loader {
+  width: 100%;
+  height: 100%;
+  margin-left: -24px;
+  margin-top: -24px;
+  background: #f9f9f980;
+  z-index: 1;
+  position: absolute;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
diff --git a/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineForm.component.tsx b/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineForm.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..f77f23c92a1b9091e3d2eed2383870d1e2af919f
--- /dev/null
+++ b/src/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineForm.component.tsx
@@ -0,0 +1,95 @@
+/* eslint-disable no-magic-numbers */
+import { ColorTilePicker } from '@/shared/ColorPicker/ColorTilePicker.component';
+import hexToRgbIntAlpha from '@/utils/convert/hexToRgbIntAlpha';
+import { Color } from '@/types/models';
+import { LayerLineFactoryForm } from '@/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactory.types';
+import { Select } from '@/shared/Select';
+import React from 'react';
+import { Input } from '@/shared/Input';
+import {
+  MAX_LINE_WIDTH,
+  MIN_LINE_WIDTH,
+} from '@/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactory.constants';
+
+type LayerLineFormProps = {
+  data: LayerLineFactoryForm;
+  lineTypes: Array<{ id: string; name: string }>;
+  arrowTypes: Array<{ id: string; name: string }>;
+  onChange: (value: number | string | Color, key: string) => void;
+};
+
+export const LayerLineForm = ({
+  data,
+  onChange,
+  lineTypes,
+  arrowTypes,
+}: LayerLineFormProps): React.JSX.Element => {
+  const onLineWidthChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
+    const value = Number(event.target.value);
+    let resultValue = value;
+    if (value < MIN_LINE_WIDTH) {
+      resultValue = MIN_LINE_WIDTH;
+    }
+    if (value > MAX_LINE_WIDTH) {
+      resultValue = MAX_LINE_WIDTH;
+    }
+    onChange(resultValue, 'width');
+  };
+
+  return (
+    <div className="grid grid-cols-3 gap-2">
+      <div>
+        <span>Color:</span>
+        <ColorTilePicker
+          initialColor={data.color}
+          colorChange={color => onChange(hexToRgbIntAlpha(color), 'color')}
+        />
+      </div>
+      <div>
+        <span>Line type:</span>
+        <Select
+          options={lineTypes}
+          selectedId={data.lineType}
+          listClassName="max-h-48"
+          testId="font-size-select"
+          onChange={value => onChange(value, 'lineType')}
+        />
+      </div>
+      <div>
+        <span>Line width:</span>
+        <Input
+          type="number"
+          name="line-width"
+          min={MIN_LINE_WIDTH}
+          max={MAX_LINE_WIDTH}
+          id="line-width"
+          value={data.width}
+          onChange={onLineWidthChange}
+          className="text-sm font-medium text-font-400"
+        />
+      </div>
+
+      <div>
+        <span>Start arrow:</span>
+        <Select
+          options={arrowTypes}
+          selectedId={data.startArrow}
+          listClassName="max-h-48"
+          testId="font-size-select"
+          onChange={value => onChange(value, 'startArrow')}
+        />
+      </div>
+
+      <div>
+        <span>End arrow:</span>
+        <Select
+          options={arrowTypes}
+          selectedId={data.endArrow}
+          listClassName="max-h-48"
+          testId="font-size-select"
+          onChange={value => onChange(value, 'endArrow')}
+        />
+      </div>
+    </div>
+  );
+};
diff --git a/src/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalFactoryModal.component.test.tsx b/src/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalFactoryModal.component.test.tsx
index 3fdb2ca207a8e35065ec7f31d146502759b3254d..c5ea45971b16b1b3c2d4ca4fcae92dcb901faec6 100644
--- a/src/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalFactoryModal.component.test.tsx
+++ b/src/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalFactoryModal.component.test.tsx
@@ -58,6 +58,7 @@ const renderComponent = (): { store: StoreType } => {
         width: 1,
         height: 1,
       },
+      layerLineFactoryState: undefined,
     },
     models: {
       ...MODELS_DATA_MOCK_WITH_MAIN_MAP,
diff --git a/src/components/FunctionalArea/Modal/LayerRectFactoryModal/LayerRectFactoryModal.component.test.tsx b/src/components/FunctionalArea/Modal/LayerRectFactoryModal/LayerRectFactoryModal.component.test.tsx
index 2e14dc505c4e18528e22c63192b2f3f12cfb2387..e06693abb844a3f7810a29e204926eef07d786c8 100644
--- a/src/components/FunctionalArea/Modal/LayerRectFactoryModal/LayerRectFactoryModal.component.test.tsx
+++ b/src/components/FunctionalArea/Modal/LayerRectFactoryModal/LayerRectFactoryModal.component.test.tsx
@@ -58,6 +58,7 @@ const renderComponent = (): { store: StoreType } => {
         width: 1,
         height: 1,
       },
+      layerLineFactoryState: undefined,
     },
     models: {
       ...MODELS_DATA_MOCK_WITH_MAIN_MAP,
diff --git a/src/components/FunctionalArea/Modal/LayerTextFactoryModal/LayerTextFactoryModal.component.test.tsx b/src/components/FunctionalArea/Modal/LayerTextFactoryModal/LayerTextFactoryModal.component.test.tsx
index a88c47d443f1da4db79b67ec19435314b3a27911..22d090f531916f40fae7ded0b5f87b241977aa7b 100644
--- a/src/components/FunctionalArea/Modal/LayerTextFactoryModal/LayerTextFactoryModal.component.test.tsx
+++ b/src/components/FunctionalArea/Modal/LayerTextFactoryModal/LayerTextFactoryModal.component.test.tsx
@@ -63,6 +63,7 @@ const renderComponent = (): { store: StoreType } => {
         width: 1,
         height: 1,
       },
+      layerLineFactoryState: undefined,
     },
     models: {
       ...MODELS_DATA_MOCK_WITH_MAIN_MAP,
diff --git a/src/components/FunctionalArea/Modal/Modal.component.tsx b/src/components/FunctionalArea/Modal/Modal.component.tsx
index 38a0141484f1cff230bdb4b206351ad05a121e8a..7a12dfea3e2161579b60d8b9426f46ee89665c6b 100644
--- a/src/components/FunctionalArea/Modal/Modal.component.tsx
+++ b/src/components/FunctionalArea/Modal/Modal.component.tsx
@@ -16,6 +16,8 @@ import { LayerRectFactoryModal } from '@/components/FunctionalArea/Modal/LayerRe
 import { LayerRectEditFactoryModal } from '@/components/FunctionalArea/Modal/LayerRectFactoryModal/LayerRectEditFactoryModal.component';
 import { LayerOvalFactoryModal } from '@/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalFactoryModal.component';
 import { LayerOvalEditFactoryModal } from '@/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalEditFactoryModal.component';
+import { LayerLineFactoryModal } from '@/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactoryModal.component';
+import { LayerLineEditFactoryModal } from '@/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineEditFactoryModal.component';
 import { EditOverlayModal } from './EditOverlayModal';
 import { LoginModal } from './LoginModal';
 import { ErrorReportModal } from './ErrorReportModal';
@@ -141,6 +143,16 @@ export const Modal = (): React.ReactNode => {
           <LayerOvalEditFactoryModal />
         </ModalLayout>
       )}
+      {isOpen && modalName === 'layer-line-factory' && (
+        <ModalLayout>
+          <LayerLineFactoryModal />
+        </ModalLayout>
+      )}
+      {isOpen && modalName === 'layer-line-edit-factory' && (
+        <ModalLayout>
+          <LayerLineEditFactoryModal />
+        </ModalLayout>
+      )}
     </>
   );
 };
diff --git a/src/components/FunctionalArea/Modal/ModalLayout/ModalLayout.component.tsx b/src/components/FunctionalArea/Modal/ModalLayout/ModalLayout.component.tsx
index 41ceda61f5115424eb965c61c72649bf8cdddb7d..c17ccf0c6f8262eb7e6b9fc73432edadc2ac2183 100644
--- a/src/components/FunctionalArea/Modal/ModalLayout/ModalLayout.component.tsx
+++ b/src/components/FunctionalArea/Modal/ModalLayout/ModalLayout.component.tsx
@@ -34,6 +34,8 @@ export const ModalLayout = ({ children }: ModalLayoutProps): JSX.Element => {
             modalName === 'add-comment' && 'h-auto w-[400px]',
             modalName === 'error-report' && 'h-auto w-[800px]',
             modalName === 'layer-factory' && 'h-auto w-[400px]',
+            ['layer-line-factory', 'layer-line-edit-factory'].includes(modalName) &&
+              'h-auto w-[550] overflow-visible',
             ['layer-oval-factory', 'layer-oval-edit-factory'].includes(modalName) &&
               'h-auto w-[300px] overflow-visible',
             ['layer-rect-factory', 'layer-rect-edit-factory'].includes(modalName) &&
@@ -53,6 +55,8 @@ export const ModalLayout = ({ children }: ModalLayoutProps): JSX.Element => {
                 'layer-rect-edit-factory',
                 'layer-oval-factory',
                 'layer-oval-edit-factory',
+                'layer-line-factory',
+                'layer-line-edit-factory',
               ].includes(modalName) && 'rounded-t-lg',
             )}
           >
diff --git a/src/components/Map/Drawer/LayersDrawer/LayerDrawerLayerContextMenu.component.tsx b/src/components/Map/Drawer/LayersDrawer/LayerDrawerLayerContextMenu.component.tsx
index ce8ca33db689e416cd95a0a280bbab3d16f3b011..70d06f0f016136e0ab8248a8f4d52a70c69b352f 100644
--- a/src/components/Map/Drawer/LayersDrawer/LayerDrawerLayerContextMenu.component.tsx
+++ b/src/components/Map/Drawer/LayersDrawer/LayerDrawerLayerContextMenu.component.tsx
@@ -9,6 +9,7 @@ type LayerDrawerLayerContextMenuProps = {
   addText: () => void;
   addRect: () => void;
   addOval: () => void;
+  addLine: () => void;
 };
 
 export const LayerDrawerLayerContextMenu = ({
@@ -18,6 +19,7 @@ export const LayerDrawerLayerContextMenu = ({
   addText,
   addRect,
   addOval,
+  addLine,
 }: LayerDrawerLayerContextMenuProps): JSX.Element => {
   const [menuVisible, setMenuVisible] = useState(false);
   const menuRef = useRef<HTMLUListElement>(null);
@@ -78,6 +80,10 @@ export const LayerDrawerLayerContextMenu = ({
             setMenuVisible(false);
             addOval();
           }}
+          addLine={() => {
+            setMenuVisible(false);
+            addLine();
+          }}
         />
       )}
     </div>
diff --git a/src/components/Map/Drawer/LayersDrawer/LayersDrawer.component.tsx b/src/components/Map/Drawer/LayersDrawer/LayersDrawer.component.tsx
index 6ae1ccf145b49caee0717a02fb7cf9c07a36bf47..cdd055f9b81e20e10e0d42d68c94b9f829b083a2 100644
--- a/src/components/Map/Drawer/LayersDrawer/LayersDrawer.component.tsx
+++ b/src/components/Map/Drawer/LayersDrawer/LayersDrawer.component.tsx
@@ -44,7 +44,8 @@ export const LayersDrawer = (): JSX.Element => {
       document.getElementById(`layer-image-item-${mapEditToolsLayerObject.id}`) ||
       document.getElementById(`layer-text-item-${mapEditToolsLayerObject.id}`) ||
       document.getElementById(`layer-rect-item-${mapEditToolsLayerObject.id}`) ||
-      document.getElementById(`layer-oval-item-${mapEditToolsLayerObject.id}`);
+      document.getElementById(`layer-oval-item-${mapEditToolsLayerObject.id}`) ||
+      document.getElementById(`layer-line-item-${mapEditToolsLayerObject.id}`);
     if (!layerObjectElement) {
       return;
     }
diff --git a/src/components/Map/Drawer/LayersDrawer/LayersDrawerLayer.component.tsx b/src/components/Map/Drawer/LayersDrawer/LayersDrawerLayer.component.tsx
index be3043a3f9f7102480e9f851213cd1c8a515d042..ab63317bff62adde5d1771982e99631fb5e1af94 100644
--- a/src/components/Map/Drawer/LayersDrawer/LayersDrawerLayer.component.tsx
+++ b/src/components/Map/Drawer/LayersDrawer/LayersDrawerLayer.component.tsx
@@ -75,6 +75,11 @@ export const LayersDrawerLayer = ({ layerDetails }: LayersDrawerLayerProps): JSX
     dispatch(mapEditToolsSetActiveAction(MAP_EDIT_ACTIONS.ADD_OVAL));
   };
 
+  const addLine = (): void => {
+    dispatch(setDrawLayer({ modelId: currentModelId, layerId: layerDetails.id }));
+    dispatch(mapEditToolsSetActiveAction(MAP_EDIT_ACTIONS.ADD_LINE));
+  };
+
   const rejectRemove = (): void => {
     setIsModalOpen(false);
   };
@@ -194,6 +199,7 @@ export const LayersDrawerLayer = ({ layerDetails }: LayersDrawerLayerProps): JSX
           addText={addText}
           addRect={addRect}
           addOval={addOval}
+          addLine={addLine}
           moveToFront={moveToFront}
           moveToBack={moveToBack}
           moveAboveDiagram={moveAboveDiagram}
diff --git a/src/components/Map/Drawer/LayersDrawer/LayersDrawerLayerActions.component.tsx b/src/components/Map/Drawer/LayersDrawer/LayersDrawerLayerActions.component.tsx
index f97407df423724c26c77a449d3a1d137a9a98ea6..42c670fe49da2d2d95864e78c4dca53c41973f01 100644
--- a/src/components/Map/Drawer/LayersDrawer/LayersDrawerLayerActions.component.tsx
+++ b/src/components/Map/Drawer/LayersDrawer/LayersDrawerLayerActions.component.tsx
@@ -17,6 +17,7 @@ type LayersDrawerLayerActionsProps = {
   addText: () => void;
   addRect: () => void;
   addOval: () => void;
+  addLine: () => void;
   moveToFront: () => void;
   moveToBack: () => void;
   moveAboveDiagram: () => void;
@@ -35,6 +36,7 @@ export const LayersDrawerLayerActions = ({
   addText,
   addRect,
   addOval,
+  addLine,
   moveToFront,
   moveToBack,
   moveAboveDiagram,
@@ -95,6 +97,7 @@ export const LayersDrawerLayerActions = ({
                 addText={addText}
                 addRect={addRect}
                 addOval={addOval}
+                addLine={addLine}
               />
             </>
           )}
diff --git a/src/components/Map/Drawer/LayersDrawer/LayersDrawerLayerContextMenuItems.component.tsx b/src/components/Map/Drawer/LayersDrawer/LayersDrawerLayerContextMenuItems.component.tsx
index 4871ce703503751caa289fab31874da465ec162c..af6fa9a756ff186142ece11ac27bf0b6f415c99a 100644
--- a/src/components/Map/Drawer/LayersDrawer/LayersDrawerLayerContextMenuItems.component.tsx
+++ b/src/components/Map/Drawer/LayersDrawer/LayersDrawerLayerContextMenuItems.component.tsx
@@ -8,6 +8,7 @@ type LayerDrawerLayerContextMenuProps = {
   addText: () => void;
   addRect: () => void;
   addOval: () => void;
+  addLine: () => void;
 };
 
 export const LayerDrawerLayerContextMenuItems = forwardRef<
@@ -22,6 +23,7 @@ export const LayerDrawerLayerContextMenuItems = forwardRef<
       addText,
       addRect,
       addOval,
+      addLine,
     }: LayerDrawerLayerContextMenuProps,
     ref,
   ): JSX.Element => {
@@ -72,6 +74,16 @@ export const LayerDrawerLayerContextMenuItems = forwardRef<
           <Icon name="oval" />
           <span>Add oval</span>
         </li>
+        <li
+          className="flex min-h-[24px] cursor-pointer gap-3 px-4 py-1 hover:bg-gray-200"
+          tabIndex={0}
+          onClick={addLine}
+          onKeyDown={handleKeyPress}
+          role="menuitem"
+        >
+          <Icon name="line" />
+          <span>Add line</span>
+        </li>
         <li
           className="flex min-h-[24px] cursor-pointer gap-3 px-4 py-1 hover:bg-gray-200"
           tabIndex={0}
diff --git a/src/components/Map/Drawer/LayersDrawer/LayersDrawerLineItem.component.tsx b/src/components/Map/Drawer/LayersDrawer/LayersDrawerLineItem.component.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..9751eab9d01b24e2edb10860d27f95ea7b6896bb
--- /dev/null
+++ b/src/components/Map/Drawer/LayersDrawer/LayersDrawerLineItem.component.tsx
@@ -0,0 +1,80 @@
+import React, { JSX, useMemo } from 'react';
+import { LayerLine } from '@/types/models';
+import { Icon } from '@/shared/Icon';
+import { LayersDrawerObjectActions } from '@/components/Map/Drawer/LayersDrawer/LayersDrawerObjectActions.component';
+import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
+import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import { mapEditToolsLayerObjectSelector } from '@/redux/mapEditTools/mapEditTools.selectors';
+import { hasPrivilegeToWriteProjectSelector } from '@/redux/user/user.selectors';
+import { mapEditToolsSetLayerLine } from '@/redux/mapEditTools/mapEditTools.slice';
+
+interface LayersDrawerOvalItemProps {
+  layerLine: LayerLine;
+  moveToFront: () => void;
+  moveToBack: () => void;
+  removeObject: () => void;
+  centerObject: () => void;
+  editObject: () => void;
+  isLayerVisible: boolean;
+  isLayerActive: boolean;
+}
+
+export const LayersDrawerLineItem = ({
+  layerLine,
+  moveToFront,
+  moveToBack,
+  removeObject,
+  centerObject,
+  editObject,
+  isLayerVisible,
+  isLayerActive,
+}: LayersDrawerOvalItemProps): JSX.Element | null => {
+  const dispatch = useAppDispatch();
+  const activeLayerObject = useAppSelector(mapEditToolsLayerObjectSelector);
+  const hasPrivilegeToWriteProject = useAppSelector(hasPrivilegeToWriteProjectSelector);
+
+  const showActions = useMemo(() => {
+    return activeLayerObject?.id === layerLine.id;
+  }, [activeLayerObject?.id, layerLine.id]);
+
+  const canSelectItem = useMemo(() => {
+    return isLayerVisible && isLayerActive && hasPrivilegeToWriteProject;
+  }, [isLayerVisible, isLayerActive, hasPrivilegeToWriteProject]);
+
+  const selectItem = useMemo(() => {
+    return (): void => {
+      if (canSelectItem) {
+        dispatch(mapEditToolsSetLayerLine(layerLine));
+      }
+    };
+  }, [canSelectItem, dispatch, layerLine]);
+
+  const handleKeyPress = (): void => {};
+
+  return (
+    <div
+      className="flex min-h-[24px] items-center justify-between gap-2"
+      id={`layer-line-item-${layerLine.id}`}
+    >
+      <div
+        className={`flex gap-2 ${canSelectItem ? 'cursor-pointer' : 'cursor-default'}`}
+        onClick={selectItem}
+        tabIndex={0}
+        onKeyDown={handleKeyPress}
+        role="button"
+      >
+        <Icon name="line" className="shrink-0" />
+        <span className="truncate">line - {layerLine.id}</span>
+      </div>
+      {showActions && (
+        <LayersDrawerObjectActions
+          moveToFront={moveToFront}
+          moveToBack={moveToBack}
+          removeObject={removeObject}
+          centerObject={centerObject}
+          editObject={editObject}
+        />
+      )}
+    </div>
+  );
+};
diff --git a/src/components/Map/Drawer/LayersDrawer/LayersDrawerObjectsList.component.tsx b/src/components/Map/Drawer/LayersDrawer/LayersDrawerObjectsList.component.tsx
index c5386ec4820f047075c05a02782737ff444a5a19..494aac6c9bc12bd542976282eb64e5ecb827f35b 100644
--- a/src/components/Map/Drawer/LayersDrawer/LayersDrawerObjectsList.component.tsx
+++ b/src/components/Map/Drawer/LayersDrawer/LayersDrawerObjectsList.component.tsx
@@ -11,20 +11,24 @@ import { LayersDrawerTextItem } from '@/components/Map/Drawer/LayersDrawer/Layer
 import QuestionModal from '@/components/FunctionalArea/Modal/QuestionModal/QustionModal.component';
 import {
   removeLayerImage,
+  removeLayerLine,
   removeLayerOval,
   removeLayerRect,
   removeLayerText,
   updateLayerImageObject,
+  updateLayerLine,
   updateLayerOval,
   updateLayerRect,
   updateLayerText,
 } from '@/redux/layers/layers.thunks';
 import {
   layerDeleteImage,
+  layerDeleteLine,
   layerDeleteOval,
   layerDeleteRect,
   layerDeleteText,
   layerUpdateImage,
+  layerUpdateLine,
   layerUpdateOval,
   layerUpdateRect,
   layerUpdateText,
@@ -32,11 +36,14 @@ import {
 import removeElementFromLayer from '@/components/Map/MapViewer/utils/shapes/layer/utils/removeElementFromLayer';
 import { showToast } from '@/utils/showToast';
 import { SerializedError } from '@reduxjs/toolkit';
-import { LayerImage, LayerOval, LayerRect, LayerText } from '@/types/models';
+import { LayerImage, LayerLine, LayerOval, LayerRect, LayerText } from '@/types/models';
 import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
 import { useMapInstance } from '@/utils/context/mapInstanceContext';
 import { mapModelIdSelector } from '@/redux/map/map.selectors';
-import { mapEditToolsSetLayerObject } from '@/redux/mapEditTools/mapEditTools.slice';
+import {
+  mapEditToolsSetLayerLine,
+  mapEditToolsSetLayerObject,
+} from '@/redux/mapEditTools/mapEditTools.slice';
 import updateElement from '@/components/Map/MapViewer/utils/shapes/layer/utils/updateElement';
 import { useSetBounds } from '@/utils/map/useSetBounds';
 import { mapEditToolsLayerObjectSelector } from '@/redux/mapEditTools/mapEditTools.selectors';
@@ -44,12 +51,16 @@ import { usePointToProjection } from '@/utils/map/usePointToProjection';
 import { Coordinate } from 'ol/coordinate';
 import {
   openLayerImageObjectEditFactoryModal,
+  openLayerLineEditFactoryModal,
   openLayerOvalEditFactoryModal,
   openLayerRectEditFactoryModal,
   openLayerTextEditFactoryModal,
 } from '@/redux/modal/modal.slice';
 import { LayersDrawerRectItem } from '@/components/Map/Drawer/LayersDrawer/LayerDrawerRectItem.component';
 import { LayersDrawerOvalItem } from '@/components/Map/Drawer/LayersDrawer/LayersDrawerOvalItem.component';
+import { LayersDrawerLineItem } from '@/components/Map/Drawer/LayersDrawer/LayersDrawerLineItem.component';
+import { LayerLineEditFactoryPayload } from '@/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactory.types';
+import getLayerLineBoundingBoxCoords from '@/components/Map/MapViewer/utils/shapes/layer/utils/getLayerLineBoundingBoxCoords';
 
 interface LayersDrawerObjectsListProps {
   layerId: number;
@@ -78,6 +89,11 @@ const removeObjectConfig = {
     successMessage: 'The layer oval has been successfully removed.',
     errorMessage: 'An error occurred while removing the layer oval.',
   },
+  line: {
+    question: 'Are you sure you want to remove the line?',
+    successMessage: 'The layer line has been successfully removed.',
+    errorMessage: 'An error occurred while removing the layer line.',
+  },
 };
 
 export const LayersDrawerObjectsList = ({
@@ -89,19 +105,21 @@ export const LayersDrawerObjectsList = ({
   const maxZIndex = useAppSelector(state => maxObjectZIndexForLayerSelector(state, layerId));
   const minZIndex = useAppSelector(state => minObjectZIndexForLayerSelector(state, layerId));
   const layer = useAppSelector(state => layerByIdSelector(state, layerId));
-  const mapEditToolsLayerImageObject = useAppSelector(mapEditToolsLayerObjectSelector);
+  const mapEditToolsLayerObject = useAppSelector(mapEditToolsLayerObjectSelector);
   const [removeModalState, setRemoveModalState] = useState<
-    undefined | 'text' | 'image' | 'rect' | 'oval'
+    undefined | 'text' | 'image' | 'rect' | 'oval' | 'line'
   >(undefined);
   const [layerObjectToRemove, setLayerObjectToRemove] = useState<
-    LayerImage | LayerText | LayerRect | LayerOval | null
+    LayerImage | LayerText | LayerRect | LayerOval | LayerLine | null
   >(null);
   const dispatch = useAppDispatch();
   const setBounds = useSetBounds();
   const pointToProjection = usePointToProjection();
   const { mapInstance } = useMapInstance();
 
-  const removeObject = (layerObject: LayerImage | LayerText | LayerRect | LayerOval): void => {
+  const removeObject = (
+    layerObject: LayerImage | LayerText | LayerRect | LayerOval | LayerLine,
+  ): void => {
     setLayerObjectToRemove(layerObject);
     if ('glyph' in layerObject) {
       setRemoveModalState('image');
@@ -109,6 +127,8 @@ export const LayersDrawerObjectsList = ({
       setRemoveModalState('text');
     } else if ('fillColor' in layerObject && 'borderColor' in layerObject) {
       setRemoveModalState('rect');
+    } else if ('segments' in layerObject) {
+      setRemoveModalState('line');
     } else {
       setRemoveModalState('oval');
     }
@@ -169,7 +189,7 @@ export const LayersDrawerObjectsList = ({
             rectId: layerObjectToRemove.id,
           }),
         );
-      } else {
+      } else if (removeModalState === 'oval') {
         await dispatch(
           removeLayerOval({
             modelId: currentModelId,
@@ -184,6 +204,21 @@ export const LayersDrawerObjectsList = ({
             ovalId: layerObjectToRemove.id,
           }),
         );
+      } else {
+        await dispatch(
+          removeLayerLine({
+            modelId: currentModelId,
+            layerId: layerObjectToRemove.layer,
+            lineId: layerObjectToRemove.id,
+          }),
+        ).unwrap();
+        dispatch(
+          layerDeleteLine({
+            modelId: currentModelId,
+            layerId: layerObjectToRemove.layer,
+            lineId: layerObjectToRemove.id,
+          }),
+        );
       }
       removeElementFromLayer({
         mapInstance,
@@ -359,8 +394,53 @@ export const LayersDrawerObjectsList = ({
     await updateOvalZIndex({ zIndex: minZIndex - 1, layerOval });
   };
 
+  const updateLineZIndex = async ({
+    zIndex,
+    layerLine,
+  }: {
+    zIndex: number;
+    layerLine: LayerLine;
+  }): Promise<void> => {
+    const payload = {
+      color: layerLine.color,
+      lineType: layerLine.lineType,
+      width: layerLine.width,
+      startArrow: layerLine.startArrow,
+      endArrow: layerLine.endArrow,
+      segments: layerLine.segments,
+      z: zIndex,
+    } as LayerLineEditFactoryPayload;
+    const newLayerLine = await dispatch(
+      updateLayerLine({
+        modelId: currentModelId,
+        layerId: layerLine.layer,
+        lineId: layerLine.id,
+        payload,
+      }),
+    ).unwrap();
+    if (newLayerLine) {
+      dispatch(
+        layerUpdateLine({
+          modelId: currentModelId,
+          layerId: newLayerLine.layer,
+          layerLine: newLayerLine,
+        }),
+      );
+      dispatch(mapEditToolsSetLayerLine(newLayerLine));
+      updateElement(mapInstance, newLayerLine.layer, newLayerLine);
+    }
+  };
+
+  const moveLineToFront = async (layerLine: LayerLine): Promise<void> => {
+    await updateLineZIndex({ zIndex: maxZIndex + 1, layerLine });
+  };
+
+  const moveLineToBack = async (layerLine: LayerLine): Promise<void> => {
+    await updateLineZIndex({ zIndex: minZIndex - 1, layerLine });
+  };
+
   const centerObject = (layerObject: LayerImage | LayerText | LayerRect | LayerOval): void => {
-    if (mapEditToolsLayerImageObject && mapEditToolsLayerImageObject.id === layerObject.id) {
+    if (mapEditToolsLayerObject && mapEditToolsLayerObject.id === layerObject.id) {
       const point1 = pointToProjection({ x: layerObject.x, y: layerObject.y });
       const point2 = pointToProjection({
         x: layerObject.x + layerObject.width,
@@ -370,6 +450,16 @@ export const LayersDrawerObjectsList = ({
     }
   };
 
+  const centerLayerLineObject = (layerLine: LayerLine): void => {
+    if (mapEditToolsLayerObject && mapEditToolsLayerObject.id === layerLine.id) {
+      const coordinates = getLayerLineBoundingBoxCoords({
+        segments: layerLine.segments,
+        pointToProjection,
+      });
+      setBounds(coordinates);
+    }
+  };
+
   const editImage = (): void => {
     dispatch(openLayerImageObjectEditFactoryModal());
   };
@@ -386,6 +476,10 @@ export const LayersDrawerObjectsList = ({
     dispatch(openLayerOvalEditFactoryModal());
   };
 
+  const editLine = (): void => {
+    dispatch(openLayerLineEditFactoryModal());
+  };
+
   if (!layer) {
     return null;
   }
@@ -454,6 +548,19 @@ export const LayersDrawerObjectsList = ({
           isLayerActive={isLayerActive}
         />
       ))}
+      {Object.values(layer.lines).map(layerLine => (
+        <LayersDrawerLineItem
+          layerLine={layerLine}
+          key={layerLine.id}
+          moveToFront={() => moveLineToFront(layerLine)}
+          moveToBack={() => moveLineToBack(layerLine)}
+          removeObject={() => removeObject(layerLine)}
+          centerObject={() => centerLayerLineObject(layerLine)}
+          editObject={() => editLine()}
+          isLayerVisible={isLayerVisible}
+          isLayerActive={isLayerActive}
+        />
+      ))}
     </div>
   );
 };
diff --git a/src/components/Map/MapViewer/MapViewer.constants.ts b/src/components/Map/MapViewer/MapViewer.constants.ts
index 7334a70e8c4d09aba29843987f42c7f9fbd2b992..d3b61ac55070d8def3759b93918e262aad6a9b7e 100644
--- a/src/components/Map/MapViewer/MapViewer.constants.ts
+++ b/src/components/Map/MapViewer/MapViewer.constants.ts
@@ -22,13 +22,13 @@ export const COMPARTMENT_SBO_TERM = 'SBO:0000290';
 
 export const ION_CHANNEL_SBO_TERM = 'SBO:0000284';
 
-export const HOMODIMER_INFO_BOX_WIDTH = 25;
+export const HOMODIMER_INFO_BOX_WIDTH = 40;
 
-export const HOMODIMER_INFO_BOX_HEIGHT = 15;
+export const HOMODIMER_INFO_BOX_HEIGHT = 18;
 
-export const ACTIVITY_INFO_BOX_WIDTH = 35;
+export const ACTIVITY_INFO_BOX_WIDTH = 40;
 
-export const ACTIVITY_INFO_BOX_HEIGHT = 15;
+export const ACTIVITY_INFO_BOX_HEIGHT = 18;
 
 export const TEXT_CUTOFF_SCALE = 0.34;
 export const OUTLINE_CUTOFF_SCALE = 0.18;
@@ -73,6 +73,7 @@ export const LAYER_ELEMENT_TYPES = {
   RECT: 'RECT',
   LINE: 'LINE',
   ARROW: 'ARROW',
+  IMAGE: 'IMAGE',
 };
 
 export const COMPARTMENT_SQUARE_POINTS: Array<ShapeRelAbs | ShapeRelAbsBezierPoint> = [
diff --git a/src/components/Map/MapViewer/utils/config/additionalLayers/useOlMapAdditionalLayers.ts b/src/components/Map/MapViewer/utils/config/additionalLayers/useOlMapAdditionalLayers.ts
index 0d31cdb6452766c70efae6c4459a5d0b38d6446f..3e0e2dc6b350f98933f8e0eca1ca95fc017803a0 100644
--- a/src/components/Map/MapViewer/utils/config/additionalLayers/useOlMapAdditionalLayers.ts
+++ b/src/components/Map/MapViewer/utils/config/additionalLayers/useOlMapAdditionalLayers.ts
@@ -24,7 +24,8 @@ import { useAppSelector } from '@/redux/hooks/useAppSelector';
 import { mapDataSizeSelector } from '@/redux/map/map.selectors';
 import {
   mapEditToolsActiveActionSelector,
-  mapEditToolsLayerObjectSelector,
+  mapEditToolsLayerLineSelector,
+  mapEditToolsLayerNonLineObjectSelector,
 } from '@/redux/mapEditTools/mapEditTools.selectors';
 import { MAP_EDIT_ACTIONS } from '@/redux/mapEditTools/mapEditTools.constants';
 import getDrawBoundingBoxInteraction from '@/components/Map/MapViewer/utils/shapes/layer/interaction/getDrawBoundingBoxInteraction';
@@ -36,6 +37,7 @@ import {
 import { Extent } from 'ol/extent';
 import {
   mapEditToolsSetActiveAction,
+  mapEditToolsSetLayerLine,
   mapEditToolsSetLayerObject,
 } from '@/redux/mapEditTools/mapEditTools.slice';
 import getTransformInteraction from '@/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformInteraction';
@@ -43,6 +45,9 @@ import { useWebSocketEntityUpdatesContext } from '@/utils/websocket-entity-updat
 import processMessage from '@/components/Map/MapViewer/utils/websocket/processMessage';
 import { hasPrivilegeToWriteProjectSelector } from '@/redux/user/user.selectors';
 import getDrawOvalInteraction from '@/components/Map/MapViewer/utils/shapes/layer/interaction/getDrawOvalInteraction';
+import getDrawLineInteraction from '@/components/Map/MapViewer/utils/shapes/layer/interaction/getDrawLineInteraction';
+import getModifyLineInteraction from '@/components/Map/MapViewer/utils/shapes/layer/interaction/getModifyLineInteraction';
+import { LAYER_ELEMENT_TYPES } from '@/components/Map/MapViewer/MapViewer.constants';
 
 export const useOlMapAdditionalLayers = (mapInstance: MapInstance): void => {
   const activeAction = useAppSelector(mapEditToolsActiveActionSelector);
@@ -57,7 +62,8 @@ export const useOlMapAdditionalLayers = (mapInstance: MapInstance): void => {
   const prevActiveLayersRef = useRef<number[]>([]);
   const drawLayer = useAppSelector(layersDrawLayerSelector);
   const hasPrivilegeToWriteProject = useAppSelector(hasPrivilegeToWriteProjectSelector);
-  const mapEditToolsLayerObject = useAppSelector(mapEditToolsLayerObjectSelector);
+  const mapEditToolsLayerNonLineObject = useAppSelector(mapEditToolsLayerNonLineObjectSelector);
+  const mapEditToolsLayerLine = useAppSelector(mapEditToolsLayerLineSelector);
 
   const lineTypes = useSelector(lineTypesSelector);
   const arrowTypes = useSelector(arrowTypesSelector);
@@ -70,8 +76,10 @@ export const useOlMapAdditionalLayers = (mapInstance: MapInstance): void => {
     >(),
   );
   const featuresToTransformRef = useRef<Collection<Feature<Geometry>>>(new Collection());
+  const linesFeaturesToSelectRef = useRef<Collection<Feature<Geometry>>>(new Collection());
+  const modifyFeaturesRef = useRef<Collection<Feature<Geometry>>>(new Collection());
 
-  const getLayerFeatures = (vectorLayer: VectorLayer): Feature<Geometry>[] => {
+  const getLayerFeaturesToTransform = (vectorLayer: VectorLayer): Feature<Geometry>[] => {
     const features: Array<Feature<Geometry>> = [];
     features.push(...vectorLayer.get('imagesFeatures'));
     features.push(...vectorLayer.get('rectsFeatures'));
@@ -79,6 +87,11 @@ export const useOlMapAdditionalLayers = (mapInstance: MapInstance): void => {
     features.push(...vectorLayer.get('ovalsFeatures'));
     return features;
   };
+  const getLayerFeaturesToModify = (vectorLayer: VectorLayer): Feature<Geometry>[] => {
+    const features: Array<Feature<Geometry>> = [];
+    features.push(...vectorLayer.get('linesFeatures'));
+    return features;
+  };
 
   const { lastJsonMessage } = useWebSocketEntityUpdatesContext();
 
@@ -132,6 +145,10 @@ export const useOlMapAdditionalLayers = (mapInstance: MapInstance): void => {
     return getDrawOvalInteraction(mapSize, dispatch, restrictionExtent);
   }, [mapSize, dispatch, restrictionExtent]);
 
+  const drawLineInteraction = useMemo(() => {
+    return getDrawLineInteraction({ mapSize, dispatch, restrictionExtent });
+  }, [mapSize, dispatch, restrictionExtent]);
+
   const drawRectInteraction = useMemo(() => {
     if (!mapSize || !dispatch) {
       return null;
@@ -174,8 +191,10 @@ export const useOlMapAdditionalLayers = (mapInstance: MapInstance): void => {
         });
         const { vectorLayer } = additionalLayer;
         if (!layerState.details.locked) {
-          const features = getLayerFeatures(vectorLayer);
+          const features = getLayerFeaturesToTransform(vectorLayer);
           featuresToTransformRef.current.extend(features);
+          const modifyFeatures = getLayerFeaturesToModify(vectorLayer);
+          linesFeaturesToSelectRef.current.extend(modifyFeatures);
         }
         vectorLayersRef.current.set(layerId, vectorLayer);
         mapInstance?.addLayer(vectorLayer);
@@ -207,6 +226,20 @@ export const useOlMapAdditionalLayers = (mapInstance: MapInstance): void => {
     transformRef.current = transformInteraction;
   }, [transformInteraction]);
 
+  const modifyLineInteraction = useMemo(() => {
+    if (!currentModelId) {
+      return null;
+    }
+    return getModifyLineInteraction({
+      mapSize,
+      dispatch,
+      modelId: currentModelId,
+      featuresToSelectCollection: linesFeaturesToSelectRef.current,
+      modifyFeatures: modifyFeaturesRef.current,
+      restrictionExtent,
+    });
+  }, [currentModelId, mapSize, dispatch, restrictionExtent]);
+
   useEffect(() => {
     vectorLayersRef.current.forEach(layer => {
       const layerId = layer.get('id');
@@ -226,18 +259,34 @@ export const useOlMapAdditionalLayers = (mapInstance: MapInstance): void => {
     }
   }, [layersVisibilityForCurrentModel, transformInteraction]);
 
-  // Selecting feature using the layers panel
+  useEffect(() => {
+    if (!modifyLineInteraction) {
+      return;
+    }
+    const { select } = modifyLineInteraction;
+    const selectedFeature = select.getFeatures().item(0);
+    if (!selectedFeature) {
+      return;
+    }
+    if (!layersVisibilityForCurrentModel[selectedFeature.get('layer')]) {
+      modifyFeaturesRef.current.clear();
+      select.getFeatures().clear();
+      dispatch(mapEditToolsSetLayerLine(null));
+    }
+  }, [dispatch, layersVisibilityForCurrentModel, modifyLineInteraction]);
+
+  // Selecting non line feature using the layers panel
   useEffect(() => {
     if (!transformRef.current) {
       return;
     }
     const transformFeatures = transformRef.current.getFeatures();
     if (
-      mapEditToolsLayerObject &&
+      mapEditToolsLayerNonLineObject &&
       (!transformFeatures.getLength() ||
-        transformFeatures.item(0).getId() !== mapEditToolsLayerObject.id)
+        transformFeatures.item(0).getId() !== mapEditToolsLayerNonLineObject.id)
     ) {
-      const layer = vectorLayersRef.current.get(mapEditToolsLayerObject.layer);
+      const layer = vectorLayersRef.current.get(mapEditToolsLayerNonLineObject.layer);
       if (!layer) {
         return;
       }
@@ -245,13 +294,42 @@ export const useOlMapAdditionalLayers = (mapInstance: MapInstance): void => {
       if (!source) {
         return;
       }
-      const feature = source.getFeatureById(mapEditToolsLayerObject.id);
+      const feature = source.getFeatureById(mapEditToolsLayerNonLineObject.id);
       if (!feature) {
         return;
       }
+      modifyFeaturesRef.current.clear();
+      modifyLineInteraction?.select.getFeatures().clear();
       transformRef.current.setSelection(new Collection<Feature>([feature]));
     }
-  }, [mapEditToolsLayerObject]);
+  }, [mapEditToolsLayerNonLineObject, modifyLineInteraction]);
+
+  // Selecting line feature using the layers panel
+  useEffect(() => {
+    const modifyFeatures = modifyFeaturesRef.current;
+    if (
+      mapEditToolsLayerLine &&
+      (!modifyFeatures.getLength() || modifyFeatures.item(0).getId() !== mapEditToolsLayerLine.id)
+    ) {
+      const layer = vectorLayersRef.current.get(mapEditToolsLayerLine.layer);
+      if (!layer) {
+        return;
+      }
+      const source = layer.getSource();
+      if (!source) {
+        return;
+      }
+      const feature = source.getFeatureById(mapEditToolsLayerLine.id);
+      if (!feature) {
+        return;
+      }
+      transformRef.current?.setSelection(new Collection<Feature>());
+      modifyFeatures.clear();
+      modifyFeatures.push(feature);
+      modifyLineInteraction?.select.getFeatures().clear();
+      modifyLineInteraction?.select.getFeatures().push(feature);
+    }
+  }, [mapEditToolsLayerLine, modifyLineInteraction]);
 
   useEffect(() => {
     const activeVectorLayers = [...vectorLayersRef.current.values()].filter(layer => {
@@ -263,10 +341,26 @@ export const useOlMapAdditionalLayers = (mapInstance: MapInstance): void => {
     }
     const removeFeatureHandler = (): void => {
       transformInteraction?.setSelection(new Collection<Feature>());
+      modifyFeaturesRef.current.clear();
+      modifyLineInteraction?.select.getFeatures().clear();
+      dispatch(mapEditToolsSetLayerLine(null));
     };
     const addFeatureHandler = (event: VectorSourceEvent): void => {
       const newFeature = event.feature;
-      if (newFeature) {
+      if (!newFeature) {
+        return;
+      }
+      const elementType = newFeature.get('elementType');
+      if (elementType === LAYER_ELEMENT_TYPES.LINE) {
+        linesFeaturesToSelectRef.current.push(newFeature);
+      } else if (
+        [
+          LAYER_ELEMENT_TYPES.RECT,
+          LAYER_ELEMENT_TYPES.TEXT,
+          LAYER_ELEMENT_TYPES.OVAL,
+          LAYER_ELEMENT_TYPES.IMAGE,
+        ].includes(elementType)
+      ) {
         featuresToTransformRef.current.push(newFeature);
       }
     };
@@ -284,7 +378,7 @@ export const useOlMapAdditionalLayers = (mapInstance: MapInstance): void => {
         source?.un('addfeature', addFeatureHandler);
       });
     };
-  }, [activeLayers, transformInteraction]);
+  }, [activeLayers, transformInteraction, modifyLineInteraction, dispatch]);
 
   // update transform features after change active layers (lock)
   useEffect(() => {
@@ -295,7 +389,7 @@ export const useOlMapAdditionalLayers = (mapInstance: MapInstance): void => {
       removedLayers.forEach(layer => {
         const removedLayer = vectorLayersRef.current.get(layer);
         if (removedLayer) {
-          const features = getLayerFeatures(removedLayer);
+          const features = getLayerFeaturesToTransform(removedLayer);
           features.forEach((feature: Feature) => {
             featuresToTransformRef.current.remove(feature);
           });
@@ -306,7 +400,7 @@ export const useOlMapAdditionalLayers = (mapInstance: MapInstance): void => {
       addedLayers.forEach(layer => {
         const addedLayer = vectorLayersRef.current.get(layer);
         if (addedLayer) {
-          const features = getLayerFeatures(addedLayer);
+          const features = getLayerFeaturesToTransform(addedLayer);
           featuresToTransformRef.current.extend(features);
         }
       });
@@ -337,6 +431,34 @@ export const useOlMapAdditionalLayers = (mapInstance: MapInstance): void => {
     transformInteraction,
   ]);
 
+  useEffect(() => {
+    if (
+      !modifyLineInteraction ||
+      !activeLayers.length ||
+      !hasPrivilegeToWriteProject ||
+      activeAction
+    ) {
+      return () => {};
+    }
+    const { modify, snap, select } = modifyLineInteraction;
+    mapInstance?.addInteraction(modify);
+    mapInstance?.addInteraction(snap);
+    mapInstance?.addInteraction(select);
+    return () => {
+      dispatch(mapEditToolsSetLayerObject(null));
+      mapInstance?.removeInteraction(modify);
+      mapInstance?.removeInteraction(snap);
+      mapInstance?.removeInteraction(select);
+    };
+  }, [
+    activeAction,
+    activeLayers,
+    dispatch,
+    hasPrivilegeToWriteProject,
+    mapInstance,
+    modifyLineInteraction,
+  ]);
+
   useEffect(() => {
     if (!drawImageInteraction || !hasPrivilegeToWriteProject) {
       return;
@@ -418,4 +540,22 @@ export const useOlMapAdditionalLayers = (mapInstance: MapInstance): void => {
     mapInstance,
     hasPrivilegeToWriteProject,
   ]);
+
+  useEffect(() => {
+    if (!drawLineInteraction || !hasPrivilegeToWriteProject) {
+      return;
+    }
+    mapInstance?.removeInteraction(drawLineInteraction);
+    if (!drawLayer || activeAction !== MAP_EDIT_ACTIONS.ADD_LINE) {
+      return;
+    }
+    mapInstance?.addInteraction(drawLineInteraction);
+  }, [
+    activeAction,
+    drawLayer,
+    currentModelId,
+    drawLineInteraction,
+    mapInstance,
+    hasPrivilegeToWriteProject,
+  ]);
 };
diff --git a/src/components/Map/MapViewer/utils/listeners/onPointerMove.test.ts b/src/components/Map/MapViewer/utils/listeners/onPointerMove.test.ts
index db8737b1a2cb77c716a60f8cb3a2754949ef843b..b0882e7fc5602b988fdc451fefabd185b2c6e9ff 100644
--- a/src/components/Map/MapViewer/utils/listeners/onPointerMove.test.ts
+++ b/src/components/Map/MapViewer/utils/listeners/onPointerMove.test.ts
@@ -18,6 +18,10 @@ const MAP_INSTANCE_BASE_MOCK = {
   forEachFeatureAtPixel: (): void => {},
 };
 
+const showPointerMoveOnLine = (): boolean => {
+  return false;
+};
+
 describe('onPointerMove - util', () => {
   describe('when event dragging', () => {
     const target = document.createElement('div');
@@ -27,7 +31,9 @@ describe('onPointerMove - util', () => {
     } as unknown as Map;
 
     it('should return nothing and not modify target', () => {
-      expect(onPointerMove(mapInstance, EVENT_DRAGGING_MOCK)).toBe(undefined);
+      expect(onPointerMove(mapInstance, EVENT_DRAGGING_MOCK, showPointerMoveOnLine)).toBe(
+        undefined,
+      );
       expect((mapInstance as any).getTarget().style.cursor).toBe('');
     });
   });
@@ -41,7 +47,7 @@ describe('onPointerMove - util', () => {
     } as unknown as Map;
 
     it('should return nothing and modify target', () => {
-      expect(onPointerMove(mapInstance, EVENT_MOCK)).toBe(undefined);
+      expect(onPointerMove(mapInstance, EVENT_MOCK, showPointerMoveOnLine)).toBe(undefined);
       expect((mapInstance as any).getTarget().style.cursor).toBe('pointer');
     });
   });
@@ -54,7 +60,7 @@ describe('onPointerMove - util', () => {
     } as unknown as Map;
 
     it('should return nothing and not modify target', () => {
-      expect(onPointerMove(mapInstance, EVENT_MOCK)).toBe(undefined);
+      expect(onPointerMove(mapInstance, EVENT_MOCK, showPointerMoveOnLine)).toBe(undefined);
       expect((mapInstance as any).getTarget()).toBe(TARGET_STRING);
     });
   });
@@ -68,7 +74,7 @@ describe('onPointerMove - util', () => {
     } as unknown as Map;
 
     it('should return nothing and not modify target', () => {
-      expect(onPointerMove(mapInstance, EVENT_MOCK)).toBe(undefined);
+      expect(onPointerMove(mapInstance, EVENT_MOCK, showPointerMoveOnLine)).toBe(undefined);
       expect((mapInstance as any).getTarget().style.cursor).toBe('');
     });
   });
diff --git a/src/components/Map/MapViewer/utils/listeners/onPointerMove.ts b/src/components/Map/MapViewer/utils/listeners/onPointerMove.ts
index 868c3f3359df5e457e793f4ae6e676d6adf16442..bdaca7f2055da1d68a8871954dbd28a5285854bc 100644
--- a/src/components/Map/MapViewer/utils/listeners/onPointerMove.ts
+++ b/src/components/Map/MapViewer/utils/listeners/onPointerMove.ts
@@ -1,13 +1,14 @@
 import { PIN_ICON_ANY } from '@/constants/features';
 import { Map } from 'ol';
 import MapBrowserEvent from 'ol/MapBrowserEvent';
+import { LAYER_ELEMENT_TYPES } from '@/components/Map/MapViewer/MapViewer.constants';
 
 const isTargetHTMLElement = (target: string | HTMLElement | undefined): target is HTMLElement =>
   !!target && typeof target !== 'string' && 'style' in target;
 
 /* prettier-ignore */
 export const onPointerMove =
-    (mapInstance: Map, event: MapBrowserEvent<PointerEvent>): void => {
+    (mapInstance: Map, event: MapBrowserEvent<PointerEvent>, showPointerMoveOnLine: (layerId: number) => boolean): void => {
       if (event.dragging) {
         return;
       }
@@ -15,12 +16,16 @@ export const onPointerMove =
       const pixel = mapInstance.getEventPixel(event.originalEvent);
       const feature = mapInstance.forEachFeatureAtPixel(pixel, firstFeature => {
         const isPinIcon = PIN_ICON_ANY.includes(firstFeature.get('type'));
-        if (!isPinIcon) {
-          return undefined;
+        const isLayerLine = LAYER_ELEMENT_TYPES.LINE=== firstFeature.get('elementType');
+        if (isPinIcon) {
+          return firstFeature;
         }
 
-        return firstFeature;
-      });
+        if(isLayerLine && showPointerMoveOnLine(firstFeature.get('layer'))) {
+          return firstFeature;
+        }
+        return undefined;
+      }, {hitTolerance: 3});
 
       const target = mapInstance.getTarget();
       if (isTargetHTMLElement(target)) {
diff --git a/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.ts b/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.ts
index d231ca5b1c74e872a5a7f67cf976b1b2d367cfea..a4f17310c74258efe744d1e077b63f2efa55ed3d 100644
--- a/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.ts
+++ b/src/components/Map/MapViewer/utils/listeners/useOlMapListeners.ts
@@ -21,6 +21,11 @@ import { onPointerMove } from '@/components/Map/MapViewer/utils/listeners/onPoin
 import { View } from 'ol';
 import { isMapEditToolsActiveSelector } from '@/redux/mapEditTools/mapEditTools.selectors';
 import { useAppSelector } from '@/redux/hooks/useAppSelector';
+import {
+  layersActiveLayersSelector,
+  layersVisibilityForCurrentModelSelector,
+} from '@/redux/layers/layers.selectors';
+import { hasPrivilegeToWriteProjectSelector } from '@/redux/user/user.selectors';
 
 interface UseOlMapListenersInput {
   view: View;
@@ -34,11 +39,24 @@ export const useOlMapListeners = ({ view, mapInstance }: UseOlMapListenersInput)
   const modelElementsForCurrentModel = useSelector(modelElementsForCurrentModelSelector);
   const newReactionsForCurrentModel = useSelector(newReactionsForCurrentModelSelector);
   const isMapEditToolsActive = useSelector(isMapEditToolsActiveSelector);
+  const activeLayers = useSelector(layersActiveLayersSelector);
+  const layersVisibilityForCurrentModel = useSelector(layersVisibilityForCurrentModelSelector);
+  const hasPrivilegeToWriteProject = useAppSelector(hasPrivilegeToWriteProjectSelector);
   const openedDrawer = useAppSelector(openedDrawerSelector);
   const isLayersDrawerOpen = useMemo(() => {
     return openedDrawer === 'layers';
   }, [openedDrawer]);
 
+  const showPointerMoveOnLine = useMemo(() => {
+    return (layerId: number): boolean => {
+      return (
+        hasPrivilegeToWriteProject &&
+        activeLayers.includes(layerId) &&
+        layersVisibilityForCurrentModel[layerId]
+      );
+    };
+  }, [activeLayers, hasPrivilegeToWriteProject, layersVisibilityForCurrentModel]);
+
   const dispatch = useAppDispatch();
   const coordinate = useRef<Coordinate>([]);
   const pixel = useRef<Pixel>([]);
@@ -91,11 +109,13 @@ export const useOlMapListeners = ({ view, mapInstance }: UseOlMapListenersInput)
       return;
     }
 
-    const key = mapInstance.on('pointermove', event => onPointerMove(mapInstance, event));
+    const key = mapInstance.on('pointermove', event =>
+      onPointerMove(mapInstance, event, showPointerMoveOnLine),
+    );
 
     // eslint-disable-next-line consistent-return
     return () => unByKey(key);
-  }, [mapInstance]);
+  }, [mapInstance, showPointerMoveOnLine]);
 
   useEffect(() => {
     if (!mapInstance || isMapEditToolsActive || isLayersDrawerOpen) {
diff --git a/src/components/Map/MapViewer/utils/shapes/elements/BaseMultiPolygon.ts b/src/components/Map/MapViewer/utils/shapes/elements/BaseMultiPolygon.ts
index 6a7691b280d423b7af4c7e7916d71fd0d31da7f6..f67101decaafc394965ed2124770f03ae56f1dee 100644
--- a/src/components/Map/MapViewer/utils/shapes/elements/BaseMultiPolygon.ts
+++ b/src/components/Map/MapViewer/utils/shapes/elements/BaseMultiPolygon.ts
@@ -213,7 +213,7 @@ export default abstract class BaseMultiPolygon {
         text: this.text,
         fontSize: this.fontSize,
         color: rgbToHex(this.fontColor),
-        zIndex: this.zIndex,
+        zIndex: this.overlaysVisible ? this.zIndex + 1 : this.zIndex,
         horizontalAlign: this.nameHorizontalAlign,
       });
       textStyle.setGeometry(textPolygon);
diff --git a/src/components/Map/MapViewer/utils/shapes/elements/CompartmentPathway.ts b/src/components/Map/MapViewer/utils/shapes/elements/CompartmentPathway.ts
index c2365a6c59d75412e6a31dfc46aa583578fdaed2..c8c2b071a800efa8ec4638a4793df12afa95c897 100644
--- a/src/components/Map/MapViewer/utils/shapes/elements/CompartmentPathway.ts
+++ b/src/components/Map/MapViewer/utils/shapes/elements/CompartmentPathway.ts
@@ -5,7 +5,6 @@ import { HorizontalAlign, VerticalAlign } from '@/components/Map/MapViewer/MapVi
 import {
   BLACK_COLOR,
   MAP_ELEMENT_TYPES,
-  TRANSPARENT_COLOR,
   WHITE_COLOR,
 } from '@/components/Map/MapViewer/MapViewer.constants';
 import Polygon from 'ol/geom/Polygon';
@@ -176,7 +175,7 @@ export default class CompartmentPathway extends BaseMultiPolygon {
       getStyle({
         geometry: compartmentPolygon,
         borderColor: this.borderColor,
-        fillColor: this.overlaysVisible ? TRANSPARENT_COLOR : { ...this.fillColor, alpha: 9 },
+        fillColor: this.overlaysVisible ? WHITE_COLOR : { ...this.fillColor, alpha: 9 },
         lineWidth: this.outerWidth,
         zIndex: this.zIndex,
       }),
diff --git a/src/components/Map/MapViewer/utils/shapes/elements/MapElement.ts b/src/components/Map/MapViewer/utils/shapes/elements/MapElement.ts
index 0de94d27ba3aa9c63eab9a97df2fda6ffd2a3b07..33ccf1c171ae700b9b2b01bf69e1f2dea6aa1e4d 100644
--- a/src/components/Map/MapViewer/utils/shapes/elements/MapElement.ts
+++ b/src/components/Map/MapViewer/utils/shapes/elements/MapElement.ts
@@ -432,7 +432,7 @@ export default class MapElement extends BaseMultiPolygon {
       const elementStyle = getStyle({
         geometry: elementPolygon,
         borderColor: this.borderColor,
-        fillColor: this.overlaysVisible ? TRANSPARENT_COLOR : this.fillColor,
+        fillColor: this.overlaysVisible ? WHITE_COLOR : this.fillColor,
         lineWidth: this.lineWidth,
         lineDash: this.lineDash,
         zIndex: this.zIndex,
@@ -482,7 +482,7 @@ export default class MapElement extends BaseMultiPolygon {
         geometry: polygon,
         borderColor: color,
         fillColor: color,
-        zIndex: this.zIndex,
+        zIndex: this.zIndex + 1,
       });
       polygon.set(
         'strokeStyle',
diff --git a/src/components/Map/MapViewer/utils/shapes/elements/getArrowFeature.ts b/src/components/Map/MapViewer/utils/shapes/elements/getArrowFeature.ts
index 0ccc40a259d2f788024db99b370e3fccbb0447e0..5bc1afe6eb274f2351f18240c197e6dba85eef23 100644
--- a/src/components/Map/MapViewer/utils/shapes/elements/getArrowFeature.ts
+++ b/src/components/Map/MapViewer/utils/shapes/elements/getArrowFeature.ts
@@ -5,12 +5,13 @@ import { MultiPolygon } from 'ol/geom';
 import { Arrow, Color } from '@/types/models';
 import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
 import Polygon from 'ol/geom/Polygon';
-import { WHITE_COLOR } from '@/components/Map/MapViewer/MapViewer.constants';
+import { LAYER_ELEMENT_TYPES, WHITE_COLOR } from '@/components/Map/MapViewer/MapViewer.constants';
 import { ArrowTypeDict } from '@/redux/shapes/shapes.types';
 import getShapePolygon from '@/components/Map/MapViewer/utils/shapes/elements/getShapePolygon';
 import getStyle from '@/components/Map/MapViewer/utils/shapes/style/getStyle';
 import getStroke from '@/components/Map/MapViewer/utils/shapes/style/getStroke';
 import { rgbToHex } from '@/components/Map/MapViewer/utils/shapes/style/rgbToHex';
+import { Stroke } from 'ol/style';
 
 export default function getArrowFeature({
   arrowTypes,
@@ -32,12 +33,14 @@ export default function getArrowFeature({
   lineWidth: number;
   color: Color;
   pointToProjection: UsePointToProjectionResult;
-}): undefined | Feature<MultiPolygon> {
+}):
+  | undefined
+  | { feature: Feature<MultiPolygon>; styles: Array<{ style: Style; strokeStyle: Stroke }> } {
   const arrowShapes = arrowTypes[arrow.arrowType];
   if (!arrowShapes) {
     return undefined;
   }
-  const arrowStyles: Array<Style> = [];
+  const styles: Array<{ style: Style; strokeStyle: Stroke }> = [];
   const arrowPolygons: Array<Polygon> = [];
   arrowShapes.forEach(shape => {
     const arrowPolygon = getShapePolygon({
@@ -55,22 +58,22 @@ export default function getArrowFeature({
       fillColor: shape.fill === false ? WHITE_COLOR : color,
       lineWidth,
     });
-    arrowPolygon.set(
-      'strokeStyle',
-      getStroke({
-        color: rgbToHex(color),
-        width: lineWidth,
-      }),
-    );
+    const strokeStyle = getStroke({
+      color: rgbToHex(color),
+      width: lineWidth,
+    });
     arrowPolygon.rotate(rotation, pointToProjection({ x, y }));
-    arrowStyles.push(style);
+    styles.push({
+      style,
+      strokeStyle,
+    });
     arrowPolygons.push(arrowPolygon);
   });
+
   const arrowFeature = new Feature({
     geometry: new MultiPolygon(arrowPolygons),
-    style: arrowStyles,
+    elementType: LAYER_ELEMENT_TYPES.ARROW,
     zIndex,
   });
-  arrowFeature.setStyle(arrowStyles);
-  return arrowFeature;
+  return { feature: arrowFeature, styles };
 }
diff --git a/src/components/Map/MapViewer/utils/shapes/layer/Layer.test.ts b/src/components/Map/MapViewer/utils/shapes/layer/Layer.test.ts
index ac3a96791e3e7b7d220dec4035bca46cc87ceab5..16d29e66a2910aab2020e82db93b2413694ab66e 100644
--- a/src/components/Map/MapViewer/utils/shapes/layer/Layer.test.ts
+++ b/src/components/Map/MapViewer/utils/shapes/layer/Layer.test.ts
@@ -83,9 +83,9 @@ describe('Layer', () => {
           borderColor: BLACK_COLOR,
         },
       },
-      lines: [
-        {
-          id: 120899,
+      lines: {
+        1: {
+          id: 1,
           width: 5.0,
           color: {
             alpha: 255,
@@ -113,8 +113,9 @@ describe('Layer', () => {
             length: 15.0,
           },
           lineType: 'SOLID',
+          layer: 1,
         },
-      ],
+      },
       images: {
         1: {
           id: 1,
diff --git a/src/components/Map/MapViewer/utils/shapes/layer/Layer.ts b/src/components/Map/MapViewer/utils/shapes/layer/Layer.ts
index 77075f320769409ee5dd79f52aff2dcfe6556d3e..3ce823db113da7a3fae7f96b0ace94f4f69f5cc9 100644
--- a/src/components/Map/MapViewer/utils/shapes/layer/Layer.ts
+++ b/src/components/Map/MapViewer/utils/shapes/layer/Layer.ts
@@ -1,7 +1,7 @@
 /* eslint-disable no-magic-numbers */
 import {
   LayerImage as LayerImageModel,
-  LayerLine,
+  LayerLine as LayerLineModel,
   LayerOval as LayerOvalModel,
   LayerRect as LayerRectModel,
   LayerText as LayerTextModel,
@@ -14,31 +14,21 @@ import Polygon from 'ol/geom/Polygon';
 import VectorSource from 'ol/source/Vector';
 import VectorLayer from 'ol/layer/Vector';
 import { HorizontalAlign, VerticalAlign } from '@/components/Map/MapViewer/MapViewer.types';
-import { FeatureLike } from 'ol/Feature';
-import Style from 'ol/style/Style';
 import { ArrowTypeDict, LineTypeDict } from '@/redux/shapes/shapes.types';
-import {
-  LAYER_ELEMENT_TYPES,
-  LAYER_TYPE,
-  REACTION_ELEMENT_CUTOFF_SCALE,
-} from '@/components/Map/MapViewer/MapViewer.constants';
-import { Stroke } from 'ol/style';
+import { LAYER_TYPE } from '@/components/Map/MapViewer/MapViewer.constants';
 import { MapSize } from '@/redux/map/map.types';
-import getScaledElementStyle from '@/components/Map/MapViewer/utils/shapes/style/getScaledElementStyle';
-import getArrowFeature from '@/components/Map/MapViewer/utils/shapes/elements/getArrowFeature';
-import getRotation from '@/components/Map/MapViewer/utils/shapes/coords/getRotation';
-import getStyle from '@/components/Map/MapViewer/utils/shapes/style/getStyle';
 import LayerText from '@/components/Map/MapViewer/utils/shapes/layer/elements/LayerText';
 import LayerImage from '@/components/Map/MapViewer/utils/shapes/layer/elements/LayerImage';
 import LayerRect from '@/components/Map/MapViewer/utils/shapes/layer/elements/LayerRect';
 import LayerOval from '@/components/Map/MapViewer/utils/shapes/layer/elements/LayerOval';
+import LayerLine from '@/components/Map/MapViewer/utils/shapes/layer/elements/LayerLine';
 
 export interface LayerProps {
   zIndex: number;
   texts: { [key: string]: LayerTextModel };
   rects: { [key: string]: LayerRectModel };
   ovals: { [key: string]: LayerOvalModel };
-  lines: Array<LayerLine>;
+  lines: { [key: string]: LayerLineModel };
   images: { [key: string]: LayerImageModel };
   visible: boolean;
   layerId: number;
@@ -58,7 +48,7 @@ export default class Layer {
 
   ovals: { [key: string]: LayerOvalModel };
 
-  lines: Array<LayerLine>;
+  lines: { [key: string]: LayerLineModel };
 
   images: { [key: string]: LayerImageModel };
 
@@ -94,6 +84,12 @@ export default class Layer {
     pointToProjection,
   }: LayerProps) {
     this.vectorSource = new VectorSource({});
+    this.vectorLayer = new VectorLayer({
+      zIndex,
+      visible,
+      updateWhileAnimating: true,
+      updateWhileInteracting: true,
+    });
 
     this.texts = texts;
     this.rects = rects;
@@ -123,22 +119,17 @@ export default class Layer {
     this.vectorSource.addFeatures(linesFeatures);
     this.vectorSource.addFeatures(arrowsFeatures);
 
-    this.vectorLayer = new VectorLayer({
-      zIndex,
-      source: this.vectorSource,
-      visible,
-      updateWhileAnimating: true,
-      updateWhileInteracting: true,
-    });
+    this.vectorLayer.setSource(this.vectorSource);
     this.vectorLayer.set('type', LAYER_TYPE.ADDITIONAL_LAYER);
-
     this.vectorLayer.set('id', layerId);
     this.vectorLayer.set('imagesFeatures', imagesFeatures);
     this.vectorLayer.set('textsFeatures', textsFeatures);
     this.vectorLayer.set('rectsFeatures', rectsFeatures);
     this.vectorLayer.set('ovalsFeatures', ovalsFeatures);
+    this.vectorLayer.set('linesFeatures', linesFeatures);
     this.vectorLayer.set('drawImage', this.drawImage.bind(this));
     this.vectorLayer.set('drawText', this.drawText.bind(this));
+    this.vectorLayer.set('drawLine', this.drawLine.bind(this));
     this.vectorLayer.set('drawOval', this.drawOval.bind(this));
     this.vectorLayer.set('drawRect', this.drawRect.bind(this));
   }
@@ -244,100 +235,53 @@ export default class Layer {
     arrowsFeatures: Array<Feature<MultiPolygon>>;
   } => {
     const linesFeatures: Array<Feature<LineString>> = [];
-    const arrowsFeatures: Array<Feature<MultiPolygon>> = [];
-
-    this.lines.forEach(line => {
-      const points = line.segments
-        .map((segment, index) => {
-          if (index === 0) {
-            return [
-              this.pointToProjection({ x: segment.x1, y: segment.y1 }),
-              this.pointToProjection({ x: segment.x2, y: segment.y2 }),
-            ];
-          }
-          return [this.pointToProjection({ x: segment.x2, y: segment.y2 })];
-        })
-        .flat();
-
-      if (line.startArrow.arrowType !== 'NONE') {
-        const firstSegment = line.segments[0];
-        const startArrowRotation = getRotation(
-          [firstSegment.x1, firstSegment.y1],
-          [firstSegment.x2, firstSegment.y2],
-        );
-        const shortenedX1 = firstSegment.x1 + line.startArrow.length * Math.cos(startArrowRotation);
-        const shortenedY1 = firstSegment.y1 - line.startArrow.length * Math.sin(startArrowRotation);
-        points[0] = this.pointToProjection({ x: shortenedX1, y: shortenedY1 });
-
-        const startArrowFeature = getArrowFeature({
-          arrowTypes: this.arrowTypes,
-          arrow: line.startArrow,
-          x: shortenedX1,
-          y: shortenedY1,
-          zIndex: line.z,
-          rotation: startArrowRotation,
-          lineWidth: line.width,
-          color: line.color,
-          pointToProjection: this.pointToProjection,
-        });
-        if (startArrowFeature) {
-          startArrowFeature.set('elementType', LAYER_ELEMENT_TYPES.ARROW);
-          startArrowFeature.set('lineWidth', line.width);
-          startArrowFeature.setStyle(this.getStyle.bind(this));
-          arrowsFeatures.push(startArrowFeature);
-        }
-      }
-
-      if (line.endArrow.arrowType !== 'NONE') {
-        const lastSegment = line.segments[line.segments.length - 1];
-        const endArrowRotation = getRotation(
-          [lastSegment.x1, lastSegment.y1],
-          [lastSegment.x2, lastSegment.y2],
-        );
-        const shortenedX2 = lastSegment.x2 - line.endArrow.length * Math.cos(endArrowRotation);
-        const shortenedY2 = lastSegment.y2 - line.endArrow.length * Math.sin(endArrowRotation);
-        points[points.length - 1] = this.pointToProjection({ x: shortenedX2, y: shortenedY2 });
-
-        const endArrowFeature = getArrowFeature({
-          arrowTypes: this.arrowTypes,
-          arrow: line.endArrow,
-          x: shortenedX2,
-          y: shortenedY2,
-          zIndex: line.z,
-          rotation: endArrowRotation,
-          lineWidth: line.width,
-          color: line.color,
-          pointToProjection: this.pointToProjection,
-        });
-        if (endArrowFeature) {
-          endArrowFeature.set('elementType', LAYER_ELEMENT_TYPES.ARROW);
-          endArrowFeature.setStyle(this.getStyle.bind(this));
-          arrowsFeatures.push(endArrowFeature);
-        }
-      }
-
-      const lineString = new LineString(points);
-
-      const lineDash = this.lineTypes[line.lineType] || [];
-      const lineStyle = getStyle({
-        geometry: lineString,
-        borderColor: line.color,
-        lineWidth: line.width,
-        lineDash,
-        zIndex: line.z,
-      });
-      const lineFeature = new Feature<LineString>({
-        geometry: lineString,
-        style: lineStyle,
-        lineWidth: line.width,
-        elementType: LAYER_ELEMENT_TYPES.LINE,
-      });
-      lineFeature.setStyle(this.getStyle.bind(this));
+    const linesArrowsFeatures: Array<Feature<MultiPolygon>> = [];
+    Object.values(this.lines).forEach(line => {
+      const { lineFeature, arrowsFeatures } = this.getLineFeature(line);
       linesFeatures.push(lineFeature);
+      linesArrowsFeatures.push(...arrowsFeatures);
+    });
+    return {
+      linesFeatures,
+      arrowsFeatures: linesArrowsFeatures,
+    };
+  };
+
+  private getLineFeature = (
+    line: LayerLineModel,
+  ): {
+    lineFeature: Feature<LineString>;
+    arrowsFeatures: Array<Feature<MultiPolygon>>;
+  } => {
+    const lineObject = new LayerLine({
+      layerLine: line,
+      layer: this.layerId,
+      lineTypes: this.lineTypes,
+      arrowTypes: this.arrowTypes,
+      pointToProjection: this.pointToProjection,
+      vectorSource: this.vectorSource,
+      mapInstance: this.mapInstance,
+      mapSize: this.mapSize,
     });
-    return { linesFeatures, arrowsFeatures };
+    const arrowsFeatures: Array<Feature<MultiPolygon>> = [];
+    if (lineObject.startArrowFeature) {
+      arrowsFeatures.push(lineObject.startArrowFeature);
+    }
+    if (lineObject.endArrowFeature) {
+      arrowsFeatures.push(lineObject.endArrowFeature);
+    }
+    return {
+      lineFeature: lineObject.lineFeature,
+      arrowsFeatures,
+    };
   };
 
+  private drawLine(line: LayerLineModel): void {
+    const { lineFeature, arrowsFeatures } = this.getLineFeature(line);
+    this.vectorSource.addFeature(lineFeature);
+    this.vectorSource.addFeatures(arrowsFeatures);
+  }
+
   private getImagesFeatures(): Feature<Polygon>[] {
     return Object.values(this.images).map(image => {
       return this.getGlyphFeature(image);
@@ -369,38 +313,4 @@ export default class Layer {
     });
     return glyph.feature;
   }
-
-  protected getStyle(feature: FeatureLike, resolution: number): Style | Array<Style> | void {
-    const styles: Array<Style> = [];
-    const maxZoom = this.mapInstance?.getView().get('originalMaxZoom');
-    const minResolution = this.mapInstance?.getView().getResolutionForZoom(maxZoom);
-    const style = feature.get('style');
-    if (!minResolution || !style) {
-      return [];
-    }
-
-    const scale = minResolution / resolution;
-    let strokeStyle: Stroke | undefined;
-    const type = feature.get('elementType');
-
-    if (type === LAYER_ELEMENT_TYPES.ARROW && scale <= REACTION_ELEMENT_CUTOFF_SCALE) {
-      return [];
-    }
-
-    const stylesToProcess: Array<Style> = [];
-    if (style instanceof Style) {
-      stylesToProcess.push(style);
-    } else if (Array.isArray(style)) {
-      stylesToProcess.push(...style);
-    }
-    stylesToProcess.forEach(singleStyle => {
-      const styleGeometry = singleStyle.getGeometry();
-      if (styleGeometry instanceof Polygon || styleGeometry instanceof LineString) {
-        strokeStyle = styleGeometry.get('strokeStyle');
-      }
-      styles.push(getScaledElementStyle(singleStyle, strokeStyle, scale));
-    });
-
-    return styles;
-  }
 }
diff --git a/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerImage.ts b/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerImage.ts
index b7d306bb6f8f1456d337080ab1b9a3f4a5db62bc..b7656701f72f80ed954d56a25bba16a7585aa714 100644
--- a/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerImage.ts
+++ b/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerImage.ts
@@ -8,6 +8,7 @@ import { updateLayerImageObject } from '@/redux/layers/layers.thunks';
 import { layerUpdateImage } from '@/redux/layers/layers.slice';
 import { mapEditToolsSetLayerObject } from '@/redux/mapEditTools/mapEditTools.slice';
 import { BoundingBox } from '@/components/Map/MapViewer/MapViewer.types';
+import { LAYER_ELEMENT_TYPES } from '@/components/Map/MapViewer/MapViewer.constants';
 
 export type LayerImageProps = {
   elementId: number;
@@ -55,6 +56,7 @@ export default class LayerImage extends Glyph {
     this.feature.set('getObjectData', this.getData.bind(this));
     this.feature.set('save', this.save.bind(this));
     this.feature.set('layer', layer);
+    this.feature.set('elementType', LAYER_ELEMENT_TYPES.IMAGE);
   }
 
   private async save({
diff --git a/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerLine.ts b/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerLine.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a7278a9415e63b1fe48df6b7a43b795e84f52239
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerLine.ts
@@ -0,0 +1,358 @@
+/* eslint-disable no-magic-numbers */
+import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
+import Style from 'ol/style/Style';
+import { Feature } from 'ol';
+import { FeatureLike } from 'ol/Feature';
+import { MapInstance } from '@/types/map';
+import { Arrow, Color, LayerLine as LayerLineModel, Segment } from '@/types/models';
+import getStyle from '@/components/Map/MapViewer/utils/shapes/style/getStyle';
+import getScaledElementStyle from '@/components/Map/MapViewer/utils/shapes/style/getScaledElementStyle';
+import { Stroke } from 'ol/style';
+import { MapSize } from '@/redux/map/map.types';
+import { Coordinate } from 'ol/coordinate';
+import { LAYER_ELEMENT_TYPES } from '@/components/Map/MapViewer/MapViewer.constants';
+import { LineString, MultiPolygon } from 'ol/geom';
+import getRotation from '@/components/Map/MapViewer/utils/shapes/coords/getRotation';
+import { ArrowTypeDict, LineTypeDict } from '@/redux/shapes/shapes.types';
+import getStroke from '@/components/Map/MapViewer/utils/shapes/style/getStroke';
+import { rgbToHex } from '@/components/Map/MapViewer/utils/shapes/style/rgbToHex';
+import getArrowFeature from '@/components/Map/MapViewer/utils/shapes/elements/getArrowFeature';
+import { updateLayerLine } from '@/redux/layers/layers.thunks';
+import { store } from '@/redux/store';
+import { mapEditToolsSetLayerLine } from '@/redux/mapEditTools/mapEditTools.slice';
+import { layerUpdateLine } from '@/redux/layers/layers.slice';
+import VectorSource from 'ol/source/Vector';
+import Polygon from 'ol/geom/Polygon';
+
+export interface LayerLineProps {
+  layerLine: LayerLineModel;
+  layer: number;
+  lineTypes: LineTypeDict;
+  arrowTypes: ArrowTypeDict;
+  pointToProjection: UsePointToProjectionResult;
+  vectorSource: VectorSource<Feature<Polygon> | Feature<LineString> | Feature<MultiPolygon>>;
+  mapInstance: MapInstance;
+  mapSize: MapSize;
+}
+
+export default class LayerLine {
+  elementId: number;
+
+  segments: Array<Segment>;
+
+  startArrow: Arrow;
+
+  endArrow: Arrow;
+
+  lineType: string;
+
+  layer: number;
+
+  zIndex: number;
+
+  color: Color;
+
+  lineWidth: number;
+
+  lineTypes: LineTypeDict;
+
+  arrowTypes: ArrowTypeDict;
+
+  points: Coordinate[] = [];
+
+  styles: Array<{ style: Style; strokeStyle: Stroke }> = [];
+
+  strokeStyle: Stroke = new Stroke();
+
+  lineString: LineString = new LineString([]);
+
+  lineFeature: Feature<LineString> = new Feature();
+
+  startArrowFeature: Feature<MultiPolygon> | undefined;
+
+  endArrowFeature: Feature<MultiPolygon> | undefined;
+
+  vectorSource: VectorSource<Feature<Polygon> | Feature<LineString> | Feature<MultiPolygon>>;
+
+  mapSize: MapSize;
+
+  pointToProjection: UsePointToProjectionResult;
+
+  minResolution: number;
+
+  constructor({
+    layerLine,
+    layer,
+    lineTypes,
+    arrowTypes,
+    pointToProjection,
+    vectorSource,
+    mapInstance,
+    mapSize,
+  }: LayerLineProps) {
+    this.elementId = layerLine.id;
+    this.segments = layerLine.segments;
+    this.startArrow = layerLine.startArrow;
+    this.endArrow = layerLine.endArrow;
+    this.lineType = layerLine.lineType;
+    this.layer = layer;
+    this.zIndex = layerLine.z;
+    this.color = layerLine.color;
+    this.lineWidth = layerLine.width;
+    this.lineTypes = lineTypes;
+    this.arrowTypes = arrowTypes;
+    this.vectorSource = vectorSource;
+    this.pointToProjection = pointToProjection;
+    this.mapSize = mapSize;
+
+    const maxZoom = mapInstance?.getView().get('originalMaxZoom');
+    this.minResolution = mapInstance?.getView().getResolutionForZoom(maxZoom) || 1;
+
+    this.drawLayerLine();
+
+    this.lineFeature = new Feature<LineString>({
+      geometry: this.lineString,
+      elementType: LAYER_ELEMENT_TYPES.LINE,
+      layer: this.layer,
+    });
+
+    this.lineFeature.setId(this.elementId);
+    this.lineFeature.set('getObjectData', this.getData.bind(this));
+    this.lineFeature.set('setCoordinates', this.setCoordinates.bind(this));
+    this.lineFeature.set('updateElement', this.updateElement.bind(this));
+    this.lineFeature.set('drawLayerLine', this.drawLayerLine.bind(this));
+    this.lineFeature.set('save', this.save.bind(this));
+    this.lineFeature.setStyle(this.getStyle.bind(this));
+  }
+
+  private getData(): LayerLineModel {
+    return {
+      id: this.elementId,
+      startArrow: this.startArrow,
+      endArrow: this.endArrow,
+      z: this.zIndex,
+      width: this.lineWidth,
+      lineType: this.lineType,
+      color: this.color,
+      segments: this.segments,
+      layer: this.layer,
+    };
+  }
+
+  private setLinePoints(): void {
+    this.points = this.segments
+      .map((segment, index) => {
+        if (index === 0) {
+          return [
+            this.pointToProjection({ x: segment.x1, y: segment.y1 }),
+            this.pointToProjection({ x: segment.x2, y: segment.y2 }),
+          ];
+        }
+        return [this.pointToProjection({ x: segment.x2, y: segment.y2 })];
+      })
+      .flat();
+  }
+
+  private drawStartArrow(): void {
+    if (this.startArrow.arrowType !== 'NONE') {
+      const firstSegment = this.segments[0];
+      const startArrowRotation = getRotation(
+        [firstSegment.x2, firstSegment.y2],
+        [firstSegment.x1, firstSegment.y1],
+      );
+      const shortenedX1 = firstSegment.x1 - this.startArrow.length * Math.cos(startArrowRotation);
+      const shortenedY1 = firstSegment.y1 + this.startArrow.length * Math.sin(startArrowRotation);
+      this.points[0] = this.pointToProjection({ x: shortenedX1, y: shortenedY1 });
+
+      const arrowFeature = getArrowFeature({
+        arrowTypes: this.arrowTypes,
+        arrow: this.startArrow,
+        x: shortenedX1,
+        y: shortenedY1,
+        zIndex: this.zIndex,
+        rotation: startArrowRotation,
+        lineWidth: this.lineWidth,
+        color: this.color,
+        pointToProjection: this.pointToProjection,
+      });
+      if (arrowFeature) {
+        const { feature, styles } = arrowFeature;
+        feature.setId(`start_arrow_${this.elementId}`);
+        feature.set('type', LAYER_ELEMENT_TYPES.ARROW);
+        feature.set('lineWidth', this.lineWidth);
+        feature.setStyle(this.getStyle.bind(this));
+        this.styles.push(...styles);
+        this.startArrowFeature = feature;
+      }
+    } else {
+      this.startArrowFeature = undefined;
+    }
+  }
+
+  private drawEndArrow(): void {
+    if (this.endArrow.arrowType !== 'NONE') {
+      const lastSegment = this.segments.at(-1);
+      if (!lastSegment) {
+        return;
+      }
+      const endArrowRotation = getRotation(
+        [lastSegment.x1, lastSegment.y1],
+        [lastSegment.x2, lastSegment.y2],
+      );
+      const shortenedX2 = lastSegment.x2 - this.endArrow.length * Math.cos(endArrowRotation);
+      const shortenedY2 = lastSegment.y2 + this.endArrow.length * Math.sin(endArrowRotation);
+      this.points[this.points.length - 1] = this.pointToProjection({
+        x: shortenedX2,
+        y: shortenedY2,
+      });
+
+      const arrowFeature = getArrowFeature({
+        arrowTypes: this.arrowTypes,
+        arrow: this.endArrow,
+        x: shortenedX2,
+        y: shortenedY2,
+        zIndex: this.zIndex,
+        rotation: endArrowRotation,
+        lineWidth: this.lineWidth,
+        color: this.color,
+        pointToProjection: this.pointToProjection,
+      });
+      if (arrowFeature) {
+        const { feature, styles } = arrowFeature;
+        feature.setId(`end_arrow_${this.elementId}`);
+        feature.set('type', LAYER_ELEMENT_TYPES.ARROW);
+        feature.setStyle(this.getStyle.bind(this));
+        this.styles.push(...styles);
+        this.endArrowFeature = feature;
+      }
+    } else {
+      this.endArrowFeature = undefined;
+    }
+  }
+
+  private drawLineString(): void {
+    this.lineString = new LineString(this.points);
+  }
+
+  private setLineStyles(): void {
+    const lineDash = this.lineTypes[this.lineType] || [];
+    const lineStrokeStyle = getStroke({
+      color: rgbToHex(this.color),
+      width: this.lineWidth,
+      lineDash,
+    });
+    const lineStyle = getStyle({
+      geometry: this.lineString,
+      borderColor: this.color,
+      lineWidth: this.lineWidth,
+      lineDash,
+      zIndex: this.zIndex,
+    });
+    this.styles.push({
+      style: lineStyle,
+      strokeStyle: lineStrokeStyle,
+    });
+  }
+
+  private drawLayerLine(): void {
+    this.startArrowFeature = undefined;
+    this.endArrowFeature = undefined;
+    this.styles = [];
+    this.setLinePoints();
+    this.drawStartArrow();
+    this.drawEndArrow();
+    this.drawLineString();
+    this.setLineStyles();
+    this.lineFeature.setGeometry(this.lineString);
+    this.lineFeature.changed();
+  }
+
+  private updateElement(layerLine: LayerLineModel): void {
+    this.elementId = layerLine.id;
+    this.startArrow = layerLine.startArrow;
+    this.endArrow = layerLine.endArrow;
+    this.zIndex = layerLine.z;
+    this.lineWidth = layerLine.width;
+    this.lineType = layerLine.lineType;
+    this.color = layerLine.color;
+    this.segments = layerLine.segments;
+
+    this.drawLayerLine();
+    if (
+      this.startArrowFeature &&
+      !this.vectorSource.getFeatureById(`start_arrow_${this.elementId}`)
+    ) {
+      this.vectorSource.addFeature(this.startArrowFeature);
+    }
+    if (this.endArrowFeature && !this.vectorSource.getFeatureById(`end_arrow_${this.elementId}`)) {
+      this.vectorSource.addFeature(this.endArrowFeature);
+    }
+  }
+
+  private async save({
+    modelId,
+    segments,
+    firstPoint,
+    lastPoint,
+  }: {
+    modelId: number;
+    segments: Array<Segment>;
+    firstPoint: Coordinate;
+    lastPoint: Coordinate;
+  }): Promise<void> {
+    const firstSegment = segments.at(0);
+    const lastSegment = segments.at(-1);
+    const firstCurrentSegment = this.segments.at(0);
+    const lastCurrentSegment = this.segments.at(-1);
+    const firstCurrentPoint = this.points.at(0);
+    const lastCurrentPoint = this.points.at(-1);
+    if (
+      firstCurrentPoint &&
+      firstSegment &&
+      firstCurrentSegment &&
+      firstPoint[0] === firstCurrentPoint[0] &&
+      firstPoint[1] === firstCurrentPoint[1]
+    ) {
+      firstSegment.x1 = firstCurrentSegment.x1;
+      firstSegment.y1 = firstCurrentSegment.y1;
+    }
+    if (
+      lastCurrentPoint &&
+      lastSegment &&
+      lastCurrentSegment &&
+      lastPoint[0] === lastCurrentPoint[0] &&
+      lastPoint[1] === lastCurrentPoint[1]
+    ) {
+      lastSegment.x2 = lastCurrentSegment.x2;
+      lastSegment.y2 = lastCurrentSegment.y2;
+    }
+    const { dispatch } = store;
+    const layerLine = await dispatch(
+      updateLayerLine({
+        modelId,
+        layerId: this.layer,
+        lineId: this.elementId,
+        payload: { ...this.getData(), segments },
+      }),
+    ).unwrap();
+    if (layerLine) {
+      dispatch(layerUpdateLine({ modelId, layerId: this.layer, layerLine }));
+      dispatch(mapEditToolsSetLayerLine(layerLine));
+      this.updateElement(layerLine);
+    }
+  }
+
+  private setCoordinates(coords: Coordinate[]): void {
+    const lineString = this.lineFeature.getGeometry();
+    if (lineString) {
+      lineString.setCoordinates(coords);
+    }
+  }
+
+  protected getStyle(_: FeatureLike, resolution: number): Style | Array<Style> | void {
+    const scale = this.minResolution / resolution;
+    return this.styles.map(({ style, strokeStyle }) => {
+      return getScaledElementStyle(style, strokeStyle, scale);
+    });
+  }
+}
diff --git a/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerRect.ts b/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerRect.ts
index 8796afc221851b9a7a8b2065261d00a388f9527c..09bcb573b208cc4d8edb46820722a59b02de8504 100644
--- a/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerRect.ts
+++ b/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerRect.ts
@@ -19,6 +19,7 @@ import { updateLayerRect } from '@/redux/layers/layers.thunks';
 import { layerUpdateRect } from '@/redux/layers/layers.slice';
 import { mapEditToolsSetLayerObject } from '@/redux/mapEditTools/mapEditTools.slice';
 import getBoundingBoxPolygon from '@/components/Map/MapViewer/utils/shapes/elements/getBoundingBoxPolygon';
+import { LAYER_ELEMENT_TYPES } from '@/components/Map/MapViewer/MapViewer.constants';
 
 export interface LayerRectProps {
   elementId: number;
@@ -115,6 +116,7 @@ export default class LayerRect {
     this.feature = new Feature({
       geometry: this.polygon,
       layer,
+      elementType: LAYER_ELEMENT_TYPES.RECT,
     });
     this.feature.setId(this.elementId);
     this.feature.set('getObjectData', this.getData.bind(this));
diff --git a/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerText.ts b/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerText.ts
index 41662941aa751c9470a216be0987f7db566cd385..d831c7dabb687f5aed711526ccf0f2709b0d2aae 100644
--- a/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerText.ts
+++ b/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerText.ts
@@ -6,7 +6,10 @@ import { Feature } from 'ol';
 import { FeatureLike } from 'ol/Feature';
 import { MapInstance } from '@/types/map';
 import { Color, LayerText as LayerTextModel } from '@/types/models';
-import { TEXT_CUTOFF_SCALE } from '@/components/Map/MapViewer/MapViewer.constants';
+import {
+  LAYER_ELEMENT_TYPES,
+  TEXT_CUTOFF_SCALE,
+} from '@/components/Map/MapViewer/MapViewer.constants';
 import {
   BoundingBox,
   HorizontalAlign,
@@ -165,6 +168,7 @@ export default class LayerText {
         }
         return 1;
       },
+      elementType: LAYER_ELEMENT_TYPES.TEXT,
       layer,
     });
     this.feature.setId(this.elementId);
diff --git a/src/components/Map/MapViewer/utils/shapes/layer/interaction/getDrawLineInteraction.ts b/src/components/Map/MapViewer/utils/shapes/layer/interaction/getDrawLineInteraction.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cfc0679d491e7ef96303a61538371acb5b4c2e62
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/shapes/layer/interaction/getDrawLineInteraction.ts
@@ -0,0 +1,66 @@
+/* eslint-disable no-magic-numbers */
+import Draw from 'ol/interaction/Draw';
+import { LineString } from 'ol/geom';
+import { MapSize } from '@/redux/map/map.types';
+import { AppDispatch } from '@/redux/store';
+import { openLayerLineFactoryModal } from '@/redux/modal/modal.slice';
+import SimpleGeometry from 'ol/geom/SimpleGeometry';
+import { Coordinate } from 'ol/coordinate';
+import { Extent } from 'ol/extent';
+import getLineSegmentsFromCoords from '@/components/Map/MapViewer/utils/shapes/layer/utils/getLineSegmentsFromCoords';
+import { never } from 'ol/events/condition';
+
+export default function getDrawLineInteraction({
+  mapSize,
+  dispatch,
+  restrictionExtent,
+}: {
+  mapSize: MapSize;
+  dispatch: AppDispatch;
+  restrictionExtent: Extent;
+}): Draw {
+  const drawLineInteraction = new Draw({
+    type: 'LineString',
+    freehand: false,
+    condition: (mapBrowserEvent): boolean => {
+      const coords = mapBrowserEvent.coordinate;
+      return (
+        coords[0] >= restrictionExtent[0] &&
+        coords[0] <= restrictionExtent[2] &&
+        coords[1] >= restrictionExtent[1] &&
+        coords[1] <= restrictionExtent[3]
+      );
+    },
+    freehandCondition: never,
+    geometryFunction: (coordinates, geom): SimpleGeometry => {
+      let geometry = geom;
+      if (!geom) {
+        geometry = new LineString([]);
+      }
+      if (!coordinates.length) {
+        geometry.setCoordinates(coordinates);
+        return geometry;
+      }
+      const lastCoordinate = coordinates.at(-1) as Coordinate;
+      const lastCoordinateX = Math.min(
+        restrictionExtent[2],
+        Math.max(restrictionExtent[0], lastCoordinate[0]),
+      );
+      const lastCoordinateY = Math.min(
+        restrictionExtent[3],
+        Math.max(restrictionExtent[1], lastCoordinate[1]),
+      );
+      coordinates.splice(coordinates.length - 1, 1, [lastCoordinateX, lastCoordinateY]);
+      geometry.setCoordinates(coordinates);
+      return geometry;
+    },
+  });
+
+  drawLineInteraction.on('drawend', event => {
+    const coords = (event.feature.getGeometry() as LineString).getCoordinates();
+    const segments = getLineSegmentsFromCoords({ mapSize, coords });
+    dispatch(openLayerLineFactoryModal(segments));
+  });
+
+  return drawLineInteraction;
+}
diff --git a/src/components/Map/MapViewer/utils/shapes/layer/interaction/getModifyLineInteraction.ts b/src/components/Map/MapViewer/utils/shapes/layer/interaction/getModifyLineInteraction.ts
new file mode 100644
index 0000000000000000000000000000000000000000..70aea4f95719527bd849778e5eeaa3ab48cdc200
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/shapes/layer/interaction/getModifyLineInteraction.ts
@@ -0,0 +1,140 @@
+/* eslint-disable no-magic-numbers */
+import { Select, Snap } from 'ol/interaction';
+import { Collection, Feature } from 'ol';
+import { Geometry, LineString } from 'ol/geom';
+import getLineSegmentsFromCoords from '@/components/Map/MapViewer/utils/shapes/layer/utils/getLineSegmentsFromCoords';
+import { MapSize } from '@/redux/map/map.types';
+import { SelectEvent } from 'ol/interaction/Select';
+import { AppDispatch } from '@/redux/store';
+import { mapEditToolsSetLayerLine } from '@/redux/mapEditTools/mapEditTools.slice';
+import { openDrawer } from '@/redux/drawer/drawer.slice';
+import { Extent } from 'ol/extent';
+import ModifyFeature from 'ol-ext/interaction/ModifyFeature';
+import BaseEvent from 'ol/events/Event';
+import { Coordinate } from 'ol/coordinate';
+
+function includesFeature(featuresCollection: Collection<Feature>, searchFeature: Feature): boolean {
+  const foundFeature = featuresCollection.getArray().find(feature => {
+    return feature.getId() === searchFeature.getId();
+  });
+  return Boolean(foundFeature);
+}
+
+export default function getModifyLineInteraction({
+  mapSize,
+  dispatch,
+  modelId,
+  featuresToSelectCollection,
+  modifyFeatures,
+  restrictionExtent,
+}: {
+  mapSize: MapSize;
+  modelId: number;
+  dispatch: AppDispatch;
+  featuresToSelectCollection: Collection<Feature<Geometry>>;
+  modifyFeatures: Collection<Feature<Geometry>>;
+  restrictionExtent: Extent;
+}): { modify: ModifyFeature; snap: Snap; select: Select } {
+  const snap = new Snap({
+    features: featuresToSelectCollection,
+    pixelTolerance: 5,
+    edge: false,
+  });
+  const modify = new ModifyFeature({
+    features: modifyFeatures,
+    pixelTolerance: 10,
+  });
+  const select = new Select({
+    hitTolerance: 3,
+    filter: (feature): boolean => {
+      return includesFeature(featuresToSelectCollection, feature);
+    },
+  });
+
+  select.on('select', (event: SelectEvent) => {
+    modifyFeatures.clear();
+    if (!event.selected.length) {
+      dispatch(mapEditToolsSetLayerLine(null));
+      return;
+    }
+    const selected = event.selected[0];
+    modifyFeatures.push(selected);
+    const getObjectData = selected.get('getObjectData');
+    if (getObjectData && getObjectData instanceof Function) {
+      const objectData = getObjectData();
+      dispatch(mapEditToolsSetLayerLine(objectData));
+      dispatch(openDrawer('layers'));
+    }
+  });
+
+  modify.on('modifying', (event: Event | BaseEvent) => {
+    const transformEvent = event as unknown as { features: Array<Feature>; coordinate: Coordinate };
+    const { features, coordinate } = transformEvent;
+    if (!features.length) {
+      return;
+    }
+    const feature = features[0];
+    const geometry = feature.getGeometry();
+    if (!geometry || !(geometry instanceof LineString)) {
+      return;
+    }
+
+    const [x, y] = coordinate;
+    const coords = geometry.getCoordinates();
+    let vertexIndex = -1;
+    coords.forEach((pt: number[], index: number) => {
+      if (pt[0] === x || pt[1] === y) {
+        vertexIndex = index;
+      }
+    });
+    if (vertexIndex === -1) {
+      return;
+    }
+    const [minX, minY, maxX, maxY] = restrictionExtent;
+    const correctedX = Math.max(minX, Math.min(maxX, x));
+    const correctedY = Math.max(minY, Math.min(maxY, y));
+    if (correctedX !== x || correctedY !== y) {
+      coords[vertexIndex] = [correctedX, correctedY];
+      const setCoordinates = feature.get('setCoordinates');
+      if (setCoordinates instanceof Function) {
+        setCoordinates(coords);
+      }
+    }
+  });
+
+  modify.on('modifyend', (event: Event | BaseEvent) => {
+    const transformEvent = event as unknown as { features: Array<Feature> };
+    if (!transformEvent.features.length) {
+      return;
+    }
+    const feature = transformEvent.features[0];
+    if (!feature) {
+      return;
+    }
+    const geometry = feature.getGeometry();
+    if (!geometry) {
+      return;
+    }
+    const coords = (geometry as LineString).getCoordinates();
+    const firstPoint = coords.at(0);
+    const lastPoint = coords.at(-1);
+    if (!firstPoint || !lastPoint) {
+      return;
+    }
+    const segments = getLineSegmentsFromCoords({ mapSize, coords });
+
+    const save = feature.get('save');
+    const drawLayerLine = feature.get('drawLayerLine');
+    if (save instanceof Function) {
+      try {
+        save({ modelId, segments, firstPoint, lastPoint });
+      } catch {
+        if (drawLayerLine instanceof Function) {
+          drawLayerLine();
+        }
+      }
+    }
+  });
+
+  return { modify, snap, select };
+}
diff --git a/src/components/Map/MapViewer/utils/shapes/layer/utils/drawElementOnLayer.ts b/src/components/Map/MapViewer/utils/shapes/layer/utils/drawElementOnLayer.ts
index 8bd57e6404619a9cfbbe717ab729ab05c737300d..7cde56cb0d77a28d1c192230772b14f0d333b87b 100644
--- a/src/components/Map/MapViewer/utils/shapes/layer/utils/drawElementOnLayer.ts
+++ b/src/components/Map/MapViewer/utils/shapes/layer/utils/drawElementOnLayer.ts
@@ -1,4 +1,4 @@
-import { LayerImage, LayerOval, LayerRect, LayerText } from '@/types/models';
+import { LayerImage, LayerLine, LayerOval, LayerRect, LayerText } from '@/types/models';
 import { MapInstance } from '@/types/map';
 
 export default function drawElementOnLayer({
@@ -9,7 +9,7 @@ export default function drawElementOnLayer({
 }: {
   mapInstance: MapInstance;
   activeLayer: number;
-  object: LayerImage | LayerText | LayerRect | LayerOval;
+  object: LayerImage | LayerText | LayerRect | LayerOval | LayerLine;
   drawFunctionKey: string;
 }): void {
   mapInstance?.getAllLayers().forEach(layer => {
diff --git a/src/components/Map/MapViewer/utils/shapes/layer/utils/getLayerLineBoundingBoxCoords.ts b/src/components/Map/MapViewer/utils/shapes/layer/utils/getLayerLineBoundingBoxCoords.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9bffaf638a1e711e457d3c32d5c172dedaa35316
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/shapes/layer/utils/getLayerLineBoundingBoxCoords.ts
@@ -0,0 +1,48 @@
+import { Coordinate } from 'ol/coordinate';
+import { Segment } from '@/types/models';
+import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
+
+export default function getLayerLineBoundingBoxCoords({
+  segments,
+  pointToProjection,
+}: {
+  segments: Array<Segment>;
+  pointToProjection: UsePointToProjectionResult;
+}): Coordinate[] {
+  let minX = Infinity;
+  let minY = Infinity;
+  let maxX = -Infinity;
+  let maxY = -Infinity;
+  segments.forEach(segment => {
+    if (segment.x1 < minX) {
+      minX = segment.x1;
+    }
+    if (segment.x2 < minX) {
+      minX = segment.x2;
+    }
+    if (segment.y1 < minY) {
+      minY = segment.y1;
+    }
+    if (segment.y2 < minY) {
+      minY = segment.y2;
+    }
+    if (segment.x1 > maxX) {
+      maxX = segment.x1;
+    }
+    if (segment.x2 > maxX) {
+      maxX = segment.x2;
+    }
+    if (segment.y1 > maxY) {
+      maxY = segment.y1;
+    }
+    if (segment.y2 > maxY) {
+      maxY = segment.y2;
+    }
+  });
+  const point1 = pointToProjection({ x: minX, y: minY });
+  const point2 = pointToProjection({
+    x: maxX,
+    y: maxY,
+  });
+  return [point1, point2];
+}
diff --git a/src/components/Map/MapViewer/utils/shapes/layer/utils/getLineSegmentsFromCoords.ts b/src/components/Map/MapViewer/utils/shapes/layer/utils/getLineSegmentsFromCoords.ts
new file mode 100644
index 0000000000000000000000000000000000000000..410e376e675d8ca2b4bf0810f2b3f4571a8294dd
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/shapes/layer/utils/getLineSegmentsFromCoords.ts
@@ -0,0 +1,36 @@
+/* eslint-disable no-magic-numbers */
+import { MapSize } from '@/redux/map/map.types';
+import { Coordinate } from 'ol/coordinate';
+import { Segment } from '@/types/models';
+import { toLonLat } from 'ol/proj';
+import { latLngToPoint } from '@/utils/map/latLngToPoint';
+
+export default function getLineSegmentsFromCoords({
+  mapSize,
+  coords,
+}: {
+  mapSize: MapSize;
+  coords: Coordinate[];
+}): Array<Segment> {
+  const segments: Array<Segment> = [];
+  let x1: number | undefined;
+  let y1: number | undefined;
+  coords.forEach(pointCoords => {
+    const [startLng, startLat] = toLonLat([pointCoords[0], pointCoords[1]]);
+    const point = latLngToPoint([startLat, startLng], mapSize);
+    if (x1 && y1) {
+      if (x1 === point.x && y1 === point.y) {
+        return;
+      }
+      segments.push({
+        x1,
+        y1,
+        x2: point.x,
+        y2: point.y,
+      });
+    }
+    x1 = point.x;
+    y1 = point.y;
+  });
+  return segments;
+}
diff --git a/src/components/Map/MapViewer/utils/shapes/layer/utils/updateElement.ts b/src/components/Map/MapViewer/utils/shapes/layer/utils/updateElement.ts
index 0e8e010c5e021b026b563566aeab872279d678b9..855568436aee6e164c1dc192e02c61647686e090 100644
--- a/src/components/Map/MapViewer/utils/shapes/layer/utils/updateElement.ts
+++ b/src/components/Map/MapViewer/utils/shapes/layer/utils/updateElement.ts
@@ -1,11 +1,11 @@
 import VectorSource from 'ol/source/Vector';
-import { LayerImage, LayerOval, LayerRect, LayerText } from '@/types/models';
+import { LayerImage, LayerOval, LayerRect, LayerText, LayerLine } from '@/types/models';
 import { MapInstance } from '@/types/map';
 
 export default function updateElement(
   mapInstance: MapInstance,
   layerId: number,
-  layerObject: LayerImage | LayerText | LayerRect | LayerOval,
+  layerObject: LayerImage | LayerText | LayerRect | LayerOval | LayerLine,
 ): void {
   mapInstance?.getAllLayers().forEach(layer => {
     if (layer.get('id') === layerId) {
diff --git a/src/components/Map/MapViewer/utils/shapes/reaction/Reaction.ts b/src/components/Map/MapViewer/utils/shapes/reaction/Reaction.ts
index e868e8a6bf0479ba05984fa1788deca3717854c0..cffa68c0ab6281b8665ba74c402f19976fb680d3 100644
--- a/src/components/Map/MapViewer/utils/shapes/reaction/Reaction.ts
+++ b/src/components/Map/MapViewer/utils/shapes/reaction/Reaction.ts
@@ -23,9 +23,9 @@ import { rgbToHex } from '@/components/Map/MapViewer/utils/shapes/style/rgbToHex
 import getStyle from '@/components/Map/MapViewer/utils/shapes/style/getStyle';
 import getLineSegments from '@/components/Map/MapViewer/utils/shapes/coords/getLineSegments';
 import getRotation from '@/components/Map/MapViewer/utils/shapes/coords/getRotation';
-import getArrowFeature from '@/components/Map/MapViewer/utils/shapes/elements/getArrowFeature';
 import getShapePolygon from '@/components/Map/MapViewer/utils/shapes/elements/getShapePolygon';
 import getTextStyle from '@/components/Map/MapViewer/utils/shapes/text/getTextStyle';
+import getReactionArrowFeature from '@/components/Map/MapViewer/utils/shapes/reaction/getReactionArrowFeature';
 
 export interface ReactionProps {
   id: number;
@@ -163,7 +163,7 @@ export default class Reaction {
       const shortenedX1 = firstSegment.x1 - line.startArrow.length * Math.cos(startArrowRotation);
       const shortenedY1 = firstSegment.y1 + line.startArrow.length * Math.sin(startArrowRotation);
       points[0] = this.pointToProjection({ x: shortenedX1, y: shortenedY1 });
-      const startArrowFeature = getArrowFeature({
+      const startArrowFeature = getReactionArrowFeature({
         arrowTypes: this.arrowTypes,
         arrow: line.startArrow,
         x: shortenedX1,
@@ -190,7 +190,7 @@ export default class Reaction {
       const shortenedX2 = lastSegment.x2 - line.endArrow.length * Math.cos(endArrowRotation);
       const shortenedY2 = lastSegment.y2 + line.endArrow.length * Math.sin(endArrowRotation);
       points[points.length - 1] = this.pointToProjection({ x: shortenedX2, y: shortenedY2 });
-      const endArrowFeature = getArrowFeature({
+      const endArrowFeature = getReactionArrowFeature({
         arrowTypes: this.arrowTypes,
         arrow: line.endArrow,
         x: shortenedX2,
diff --git a/src/components/Map/MapViewer/utils/shapes/elements/getArrowFeature.test.ts b/src/components/Map/MapViewer/utils/shapes/reaction/getReactionArrowFeature.test.ts
similarity index 89%
rename from src/components/Map/MapViewer/utils/shapes/elements/getArrowFeature.test.ts
rename to src/components/Map/MapViewer/utils/shapes/reaction/getReactionArrowFeature.test.ts
index 970241b9fde38f5d87c9e4b511e890e7f3663938..5bf581e179017ed919a8e03fd32aa0f4e2414c39 100644
--- a/src/components/Map/MapViewer/utils/shapes/elements/getArrowFeature.test.ts
+++ b/src/components/Map/MapViewer/utils/shapes/reaction/getReactionArrowFeature.test.ts
@@ -6,12 +6,12 @@ import { BLACK_COLOR } from '@/components/Map/MapViewer/MapViewer.constants';
 import { ArrowTypeDict } from '@/redux/shapes/shapes.types';
 import getShapePolygon from '@/components/Map/MapViewer/utils/shapes/elements/getShapePolygon';
 import getStyle from '@/components/Map/MapViewer/utils/shapes/style/getStyle';
-import getArrowFeature from '@/components/Map/MapViewer/utils/shapes/elements/getArrowFeature';
+import getReactionArrowFeature from '@/components/Map/MapViewer/utils/shapes/reaction/getReactionArrowFeature';
 
 jest.mock('../style/getStyle');
-jest.mock('./getShapePolygon');
+jest.mock('../elements/getShapePolygon');
 
-describe('getArrowFeature', () => {
+describe('getReactionArrowFeature', () => {
   const props = {
     arrowTypes: {
       FULL: [
@@ -105,18 +105,18 @@ describe('getArrowFeature', () => {
   });
 
   it('should return arrow feature', () => {
-    const arrowFeature = getArrowFeature(props);
+    const arrowFeature = getReactionArrowFeature(props);
 
     expect(arrowFeature).toBeInstanceOf(Feature<MultiPolygon>);
   });
 
   it('should handle missing arrowType in props', () => {
     const invalidProps = { ...props, arrowTypes: {} };
-    expect(() => getArrowFeature(invalidProps)).not.toThrow();
+    expect(() => getReactionArrowFeature(invalidProps)).not.toThrow();
   });
 
   it('should call getStyle', () => {
-    getArrowFeature(props);
+    getReactionArrowFeature(props);
     expect(getStyle).toBeCalled();
   });
 });
diff --git a/src/components/Map/MapViewer/utils/shapes/reaction/getReactionArrowFeature.ts b/src/components/Map/MapViewer/utils/shapes/reaction/getReactionArrowFeature.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f34a2261a580c493a4b388ef77ff30c08926d9bb
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/shapes/reaction/getReactionArrowFeature.ts
@@ -0,0 +1,76 @@
+/* eslint-disable no-magic-numbers */
+import Style from 'ol/style/Style';
+import { Feature } from 'ol';
+import { MultiPolygon } from 'ol/geom';
+import { Arrow, Color } from '@/types/models';
+import { UsePointToProjectionResult } from '@/utils/map/usePointToProjection';
+import Polygon from 'ol/geom/Polygon';
+import { WHITE_COLOR } from '@/components/Map/MapViewer/MapViewer.constants';
+import { ArrowTypeDict } from '@/redux/shapes/shapes.types';
+import getShapePolygon from '@/components/Map/MapViewer/utils/shapes/elements/getShapePolygon';
+import getStyle from '@/components/Map/MapViewer/utils/shapes/style/getStyle';
+import getStroke from '@/components/Map/MapViewer/utils/shapes/style/getStroke';
+import { rgbToHex } from '@/components/Map/MapViewer/utils/shapes/style/rgbToHex';
+
+export default function getReactionArrowFeature({
+  arrowTypes,
+  arrow,
+  x,
+  y,
+  zIndex,
+  rotation,
+  lineWidth,
+  color,
+  pointToProjection,
+}: {
+  arrowTypes: ArrowTypeDict;
+  arrow: Arrow;
+  x: number;
+  y: number;
+  zIndex: number;
+  rotation: number;
+  lineWidth: number;
+  color: Color;
+  pointToProjection: UsePointToProjectionResult;
+}): undefined | Feature<MultiPolygon> {
+  const arrowShapes = arrowTypes[arrow.arrowType];
+  if (!arrowShapes) {
+    return undefined;
+  }
+  const arrowStyles: Array<Style> = [];
+  const arrowPolygons: Array<Polygon> = [];
+  arrowShapes.forEach(shape => {
+    const arrowPolygon = getShapePolygon({
+      shape,
+      x,
+      y: y - arrow.length / 2,
+      width: arrow.length,
+      height: arrow.length,
+      pointToProjection,
+    });
+    const style = getStyle({
+      geometry: arrowPolygon,
+      zIndex,
+      borderColor: color,
+      fillColor: shape.fill === false ? WHITE_COLOR : color,
+      lineWidth,
+    });
+    arrowPolygon.set(
+      'strokeStyle',
+      getStroke({
+        color: rgbToHex(color),
+        width: lineWidth,
+      }),
+    );
+    arrowPolygon.rotate(rotation, pointToProjection({ x, y }));
+    arrowStyles.push(style);
+    arrowPolygons.push(arrowPolygon);
+  });
+  const arrowFeature = new Feature({
+    geometry: new MultiPolygon(arrowPolygons),
+    style: arrowStyles,
+    zIndex,
+  });
+  arrowFeature.setStyle(arrowStyles);
+  return arrowFeature;
+}
diff --git a/src/components/Map/MapViewer/utils/websocket/processLayerLine.ts b/src/components/Map/MapViewer/utils/websocket/processLayerLine.ts
new file mode 100644
index 0000000000000000000000000000000000000000..76c07f8ba88b6016db56b26fe406d4ee7342c9aa
--- /dev/null
+++ b/src/components/Map/MapViewer/utils/websocket/processLayerLine.ts
@@ -0,0 +1,53 @@
+import { WebSocketEntityUpdateInterface } from '@/utils/websocket-entity-updates/webSocketEntityUpdates.types';
+import { store } from '@/redux/store';
+import { ENTITY_OPERATION_TYPES } from '@/utils/websocket-entity-updates/webSocketEntityUpdates.constants';
+import { MapInstance } from '@/types/map';
+import drawElementOnLayer from '@/components/Map/MapViewer/utils/shapes/layer/utils/drawElementOnLayer';
+import { getLayerLine } from '@/redux/layers/layers.thunks';
+import updateElement from '@/components/Map/MapViewer/utils/shapes/layer/utils/updateElement';
+import { layerDeleteLine } from '@/redux/layers/layers.slice';
+import removeElementFromLayer from '@/components/Map/MapViewer/utils/shapes/layer/utils/removeElementFromLayer';
+
+export default async function processLayerLine({
+  data,
+  mapInstance,
+}: {
+  data: WebSocketEntityUpdateInterface;
+  mapInstance: MapInstance;
+}): Promise<void> {
+  const { dispatch } = store;
+  if (
+    data.type === ENTITY_OPERATION_TYPES.ENTITY_CREATED ||
+    data.type === ENTITY_OPERATION_TYPES.ENTITY_UPDATED
+  ) {
+    const resultLine = await dispatch(
+      getLayerLine({
+        modelId: data.mapId,
+        layerId: data.layerId,
+        lineId: data.entityId,
+      }),
+    ).unwrap();
+    if (!resultLine) {
+      return;
+    }
+    if (data.type === ENTITY_OPERATION_TYPES.ENTITY_CREATED) {
+      drawElementOnLayer({
+        mapInstance,
+        activeLayer: data.layerId,
+        object: resultLine,
+        drawFunctionKey: 'drawLine',
+      });
+    } else {
+      updateElement(mapInstance, data.layerId, resultLine);
+    }
+  } else if (data.type === ENTITY_OPERATION_TYPES.ENTITY_DELETED) {
+    dispatch(
+      layerDeleteLine({
+        modelId: data.mapId,
+        layerId: data.layerId,
+        lineId: data.entityId,
+      }),
+    );
+    removeElementFromLayer({ mapInstance, layerId: data.layerId, featureId: data.entityId });
+  }
+}
diff --git a/src/components/Map/MapViewer/utils/websocket/processMessage.ts b/src/components/Map/MapViewer/utils/websocket/processMessage.ts
index 6d1396031b1407fb1701695ab630da0505076428..cac113c5bf80f97e63f0735244c2d633c99f02b0 100644
--- a/src/components/Map/MapViewer/utils/websocket/processMessage.ts
+++ b/src/components/Map/MapViewer/utils/websocket/processMessage.ts
@@ -6,6 +6,7 @@ import processLayerText from '@/components/Map/MapViewer/utils/websocket/process
 import processLayerOval from '@/components/Map/MapViewer/utils/websocket/processLayerOval';
 import processLayer from '@/components/Map/MapViewer/utils/websocket/processLayer';
 import processLayerRect from '@/components/Map/MapViewer/utils/websocket/processLayerRect';
+import processLayerLine from '@/components/Map/MapViewer/utils/websocket/processLayerLine';
 
 export default async function processMessage({
   jsonMessage,
@@ -24,6 +25,8 @@ export default async function processMessage({
       await processLayerOval({ data: jsonMessage, mapInstance });
     } else if (jsonMessage.entityType === ENTITY_TYPES.LAYER_RECTANGLE) {
       await processLayerRect({ data: jsonMessage, mapInstance });
+    } else if (jsonMessage.entityType === ENTITY_TYPES.LAYER_LINE) {
+      await processLayerLine({ data: jsonMessage, mapInstance });
     } else if (jsonMessage.entityType === ENTITY_TYPES.LAYER) {
       await processLayer({ data: jsonMessage, mapInstance });
     }
diff --git a/src/models/fixtures/layerLinesFixture.ts b/src/models/fixtures/layerLinesFixture.ts
index fc15d3c2d364031d896d8803f30cad37d997f8fd..45e9645bf39552aad1eaf2cccc72b82b2cd23d3d 100644
--- a/src/models/fixtures/layerLinesFixture.ts
+++ b/src/models/fixtures/layerLinesFixture.ts
@@ -6,5 +6,5 @@ import { layerLineSchema } from '@/models/layerLineSchema';
 
 export const layerLinesFixture = createFixture(pageableSchema(layerLineSchema), {
   seed: ZOD_SEED,
-  array: { min: 3, max: 3 },
+  array: { min: 1, max: 1 },
 });
diff --git a/src/models/layerLineSchema.ts b/src/models/layerLineSchema.ts
index e454f9302cae6a7f0ccec85aa087a0bf8413aa43..94401eeb1ecf231ab22a901317fb703da92dbc12 100644
--- a/src/models/layerLineSchema.ts
+++ b/src/models/layerLineSchema.ts
@@ -12,4 +12,5 @@ export const layerLineSchema = z.object({
   startArrow: arrowSchema,
   endArrow: arrowSchema,
   lineType: z.string(),
+  layer: z.number(),
 });
diff --git a/src/redux/apiPath.ts b/src/redux/apiPath.ts
index b9c58c3cbb653e0d60e53b047597c273542f715b..6700df2845933450cc09f188b4616c32a00894c1 100644
--- a/src/redux/apiPath.ts
+++ b/src/redux/apiPath.ts
@@ -84,6 +84,14 @@ export const apiPath = {
     `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/texts/${textId}`,
   removeLayerText: (modelId: number, layerId: number, textId: number | string): string =>
     `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/texts/${textId}`,
+  addLayerLine: (modelId: number, layerId: number): string =>
+    `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/lines/`,
+  getLayerLine: (modelId: number, layerId: number, lineId: number | string): string =>
+    `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/lines/${lineId}`,
+  updateLayerLine: (modelId: number, layerId: number, lineId: number | string): string =>
+    `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/lines/${lineId}`,
+  removeLayerLine: (modelId: number, layerId: number, lineId: number | string): string =>
+    `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/lines/${lineId}`,
   getLayer: (modelId: number, layerId: number): string =>
     `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}`,
   getGlyphImage: (glyphId: number): string =>
diff --git a/src/redux/layers/layers.reducers.test.ts b/src/redux/layers/layers.reducers.test.ts
index d72e8c4ff1ade3c5b038045f146c07342647f254..2621883394cd95cc9ce62952c3b1d0bef4c42bb2 100644
--- a/src/redux/layers/layers.reducers.test.ts
+++ b/src/redux/layers/layers.reducers.test.ts
@@ -48,7 +48,7 @@ const layersState: LayersState = {
           texts: {},
           rects: {},
           ovals: {},
-          lines: [],
+          lines: {},
           images: {},
         },
       },
@@ -104,7 +104,7 @@ describe('layers reducer', () => {
           texts: { [layerTextsFixture.content[0].id]: layerTextsFixture.content[0] },
           rects: { [layerRectsFixture.content[0].id]: layerRectsFixture.content[0] },
           ovals: { [layerOvalsFixture.content[0].id]: layerOvalsFixture.content[0] },
-          lines: layerLinesFixture.content,
+          lines: { [layerLinesFixture.content[0].id]: layerLinesFixture.content[0] },
           images: { [layerImagesFixture.content[0].id]: layerImagesFixture.content[0] },
         },
       },
@@ -170,7 +170,7 @@ describe('layers reducer', () => {
             texts: { [layerTextsFixture.content[0].id]: layerTextsFixture.content[0] },
             rects: { [layerRectsFixture.content[0].id]: layerRectsFixture.content[0] },
             ovals: { [layerOvalsFixture.content[0].id]: layerOvalsFixture.content[0] },
-            lines: layerLinesFixture.content,
+            lines: { [layerLinesFixture.content[0].id]: layerLinesFixture.content[0] },
             images: { [layerImagesFixture.content[0].id]: layerImagesFixture.content[0] },
           },
         },
diff --git a/src/redux/layers/layers.reducers.ts b/src/redux/layers/layers.reducers.ts
index e8ba229c4c781bc2ed7650313f91cf1fc7813723..5518433130fb3122d6ddeb78d1836be587bc3682 100644
--- a/src/redux/layers/layers.reducers.ts
+++ b/src/redux/layers/layers.reducers.ts
@@ -12,9 +12,10 @@ import {
   LAYERS_STATE_INITIAL_LAYER_MOCK,
 } from '@/redux/layers/layers.mock';
 import { DEFAULT_ERROR } from '@/constants/errors';
-import { LayerImage, LayerOval, LayerRect, LayerText } from '@/types/models';
+import { LayerImage, LayerLine, LayerOval, LayerRect, LayerText } from '@/types/models';
 import setLayerRect from '@/redux/layers/utils/setLayerRect';
 import setLayerOval from '@/redux/layers/utils/setLayerOval';
+import setLayerLine from '@/redux/layers/utils/setLayerLine';
 
 export const getLayersForModelReducer = (builder: ActionReducerMapBuilder<LayersState>): void => {
   builder.addCase(getLayersForModel.pending, (state, action) => {
@@ -68,7 +69,7 @@ export const getLayerReducer = (builder: ActionReducerMapBuilder<LayersState>):
       images: {},
       ovals: {},
       rects: {},
-      lines: [],
+      lines: {},
     };
     data.layersVisibility[layerId] = updatedLayerDetails.visible;
     if (!updatedLayerDetails.locked) {
@@ -366,3 +367,43 @@ export const layerDeleteOvalReducer = (
   }
   delete layer.ovals[ovalId];
 };
+
+export const layerAddLineReducer = (
+  state: LayersState,
+  action: PayloadAction<{ modelId: number; layerId: number; layerLine: LayerLine }>,
+): void => {
+  const { modelId, layerId, layerLine } = action.payload;
+  const { data } = state[modelId];
+  if (!data) {
+    return;
+  }
+  setLayerLine({ layerId, layers: data.layers, layerLine });
+};
+
+export const layerUpdateLineReducer = (
+  state: LayersState,
+  action: PayloadAction<{ modelId: number; layerId: number; layerLine: LayerLine }>,
+): void => {
+  const { modelId, layerId, layerLine } = action.payload;
+  const { data } = state[modelId];
+  if (!data) {
+    return;
+  }
+  setLayerLine({ layerId, layers: data.layers, layerLine });
+};
+
+export const layerDeleteLineReducer = (
+  state: LayersState,
+  action: PayloadAction<{ modelId: number; layerId: number; lineId: number }>,
+): void => {
+  const { modelId, layerId, lineId } = action.payload;
+  const { data } = state[modelId];
+  if (!data) {
+    return;
+  }
+  const layer = data.layers[layerId];
+  if (!layer) {
+    return;
+  }
+  delete layer.lines[lineId];
+};
diff --git a/src/redux/layers/layers.selectors.ts b/src/redux/layers/layers.selectors.ts
index 45b91bd9c11d458852bc6b900260272a29e1799c..ca915e9ff6b05116867d9e508be442eb1dd8e68a 100644
--- a/src/redux/layers/layers.selectors.ts
+++ b/src/redux/layers/layers.selectors.ts
@@ -136,7 +136,7 @@ export const maxObjectZIndexForLayerSelector = createSelector(
     const textsMaxZ = getMaxZFromItems(Object.values(foundLayer.texts));
     const rectsMaxZ = getMaxZFromItems(Object.values(foundLayer.rects));
     const ovalsMaxZ = getMaxZFromItems(Object.values(foundLayer.ovals));
-    const linesMaxZ = getMaxZFromItems(foundLayer.lines);
+    const linesMaxZ = getMaxZFromItems(Object.values(foundLayer.lines));
     const imagesMaxZ = getMaxZFromItems(Object.values(foundLayer.images));
 
     return Math.max(textsMaxZ, rectsMaxZ, ovalsMaxZ, linesMaxZ, imagesMaxZ);
@@ -159,7 +159,7 @@ export const minObjectZIndexForLayerSelector = createSelector(
     const textsMinZ = getMinZFromItems(Object.values(foundLayer.texts));
     const rectsMinZ = getMinZFromItems(Object.values(foundLayer.rects));
     const ovalsMinZ = getMinZFromItems(Object.values(foundLayer.ovals));
-    const linesMinZ = getMinZFromItems(foundLayer.lines);
+    const linesMinZ = getMinZFromItems(Object.values(foundLayer.lines));
     const imagesMinZ = getMinZFromItems(Object.values(foundLayer.images));
 
     return Math.min(textsMinZ, rectsMinZ, ovalsMinZ, linesMinZ, imagesMinZ);
diff --git a/src/redux/layers/layers.slice.ts b/src/redux/layers/layers.slice.ts
index 243b6ab7dfb6d9da15e3a50d80c0fba6ad24e012..9eb890b0ba9b97f4ae1a5fe66588a90a6ec72697 100644
--- a/src/redux/layers/layers.slice.ts
+++ b/src/redux/layers/layers.slice.ts
@@ -22,6 +22,9 @@ import {
   layerDeleteReducer,
   layerUpdateOvalReducer,
   layerDeleteOvalReducer,
+  layerAddLineReducer,
+  layerUpdateLineReducer,
+  layerDeleteLineReducer,
 } from '@/redux/layers/layers.reducers';
 
 export const layersSlice = createSlice({
@@ -45,6 +48,9 @@ export const layersSlice = createSlice({
     layerAddOval: layerAddOvalReducer,
     layerUpdateOval: layerUpdateOvalReducer,
     layerDeleteOval: layerDeleteOvalReducer,
+    layerAddLine: layerAddLineReducer,
+    layerUpdateLine: layerUpdateLineReducer,
+    layerDeleteLine: layerDeleteLineReducer,
   },
   extraReducers: builder => {
     getLayersForModelReducer(builder);
@@ -72,6 +78,9 @@ export const {
   layerAddOval,
   layerUpdateOval,
   layerDeleteOval,
+  layerAddLine,
+  layerUpdateLine,
+  layerDeleteLine,
 } = layersSlice.actions;
 
 export default layersSlice.reducer;
diff --git a/src/redux/layers/layers.thunks.test.ts b/src/redux/layers/layers.thunks.test.ts
index 3894b5a635979f7e922d3732e3ac12fd27be9ffe..5d2154d2ffa1c27a5ea383bb9803a2c319a1728b 100644
--- a/src/redux/layers/layers.thunks.test.ts
+++ b/src/redux/layers/layers.thunks.test.ts
@@ -76,7 +76,9 @@ describe('layers thunks', () => {
             ovals: {
               [layerOvalsFixture.content[0].id]: layerOvalsFixture.content[0],
             },
-            lines: layerLinesFixture.content,
+            lines: {
+              [layerLinesFixture.content[0].id]: layerLinesFixture.content[0],
+            },
             images: {
               [layerImagesFixture.content[0].id]: layerImagesFixture.content[0],
             },
diff --git a/src/redux/layers/layers.thunks.ts b/src/redux/layers/layers.thunks.ts
index d26c624deb8f7d5089fcbb2ce160920ce10fda29..62ec14324368aeacc5ef1523a479f43f71ef29b1 100644
--- a/src/redux/layers/layers.thunks.ts
+++ b/src/redux/layers/layers.thunks.ts
@@ -1,7 +1,16 @@
 /* eslint-disable no-magic-numbers */
 import { z as zod } from 'zod';
 import { apiPath } from '@/redux/apiPath';
-import { Color, Layer, LayerImage, LayerOval, LayerRect, Layers, LayerText } from '@/types/models';
+import {
+  Color,
+  Layer,
+  LayerImage,
+  LayerLine,
+  LayerOval,
+  LayerRect,
+  Layers,
+  LayerText,
+} from '@/types/models';
 import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema';
 import { createAsyncThunk } from '@reduxjs/toolkit';
 import { ThunkConfig } from '@/types/store';
@@ -30,6 +39,10 @@ import {
 } from '@/components/Map/MapViewer/MapViewer.types';
 import { LayerRectFactoryForm } from '@/components/FunctionalArea/Modal/LayerRectFactoryModal/LayerRectFactory.types';
 import { LayerOvalFactoryForm } from '@/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalFactory.types';
+import {
+  LayerLineEditFactoryPayload,
+  LayerLineFactoryPayload,
+} from '@/components/FunctionalArea/Modal/LayerLineFactoryModal/LayerLineFactory.types';
 
 export const getLayer = createAsyncThunk<
   Layer | null,
@@ -73,7 +86,7 @@ export const getLayersForModel = createAsyncThunk<
           texts: arrayToKeyValue(textsResponse.data.content as Array<LayerText>, 'id'),
           rects: arrayToKeyValue(rectsResponse.data.content as Array<LayerRect>, 'id'),
           ovals: arrayToKeyValue(ovalsResponse.data.content as Array<LayerOval>, 'id'),
-          lines: linesResponse.data.content,
+          lines: arrayToKeyValue(linesResponse.data.content as Array<LayerLine>, 'id'),
           images: arrayToKeyValue(imagesResponse.data.content as Array<LayerImage>, 'id'),
         };
       }),
@@ -83,7 +96,7 @@ export const getLayersForModel = createAsyncThunk<
         zod.array(layerTextSchema).safeParse(Object.values(layer.texts)).success &&
         zod.array(layerRectSchema).safeParse(Object.values(layer.rects)).success &&
         zod.array(layerOvalSchema).safeParse(Object.values(layer.ovals)).success &&
-        zod.array(layerLineSchema).safeParse(layer.lines).success &&
+        zod.array(layerLineSchema).safeParse(Object.values(layer.lines)).success &&
         zod.array(layerImageSchema).safeParse(Object.values(layer.images)).success
       );
     });
@@ -600,3 +613,84 @@ export const removeLayerOval = createAsyncThunk<
     return Promise.reject(getError({ error }));
   }
 });
+
+export const getLayerLine = createAsyncThunk<
+  LayerLine | null,
+  {
+    modelId: number;
+    layerId: number;
+    lineId: number;
+  },
+  ThunkConfig
+>('layers/getLayerLine', async ({ modelId, layerId, lineId }) => {
+  try {
+    const { data } = await axiosInstanceNewAPI.get<LayerLine>(
+      apiPath.getLayerLine(modelId, layerId, lineId),
+    );
+    const isDataValid = validateDataUsingZodSchema(data, layerLineSchema);
+
+    return isDataValid ? data : null;
+  } catch (error) {
+    return Promise.reject(getError({ error }));
+  }
+});
+
+export const addLayerLine = createAsyncThunk<
+  LayerLine | null,
+  {
+    modelId: number;
+    layerId: number;
+    payload: LayerLineFactoryPayload;
+  },
+  ThunkConfig
+>('layers/addLayerLine', async ({ modelId, layerId, payload }) => {
+  try {
+    const { data } = await axiosInstanceNewAPI.post<LayerLine>(
+      apiPath.addLayerLine(modelId, layerId),
+      payload,
+    );
+    const isDataValid = validateDataUsingZodSchema(data, layerLineSchema);
+
+    return isDataValid ? data : null;
+  } catch (error) {
+    return Promise.reject(getError({ error }));
+  }
+});
+
+export const updateLayerLine = createAsyncThunk<
+  LayerLine | null,
+  {
+    modelId: number;
+    layerId: number;
+    lineId: number;
+    payload: LayerLineEditFactoryPayload;
+  },
+  ThunkConfig
+>('layers/updateLayerLine', async ({ modelId, layerId, lineId, payload }) => {
+  try {
+    const { data } = await axiosInstanceNewAPI.put<LayerLine>(
+      apiPath.updateLayerLine(modelId, layerId, lineId),
+      payload,
+    );
+    const isDataValid = validateDataUsingZodSchema(data, layerLineSchema);
+    if (isDataValid) {
+      return data;
+    }
+    return null;
+  } catch (error) {
+    return Promise.reject(getError({ error }));
+  }
+});
+
+export const removeLayerLine = createAsyncThunk<
+  null,
+  { modelId: number; layerId: number; lineId: number },
+  ThunkConfig
+>('layers/removeLayerLine', async ({ modelId, layerId, lineId }) => {
+  try {
+    await axiosInstanceNewAPI.delete<void>(apiPath.removeLayerLine(modelId, layerId, lineId));
+    return null;
+  } catch (error) {
+    return Promise.reject(getError({ error }));
+  }
+});
diff --git a/src/redux/layers/layers.types.ts b/src/redux/layers/layers.types.ts
index fef1836e434a5a3ef451a162d508c844e99f5eb5..dfa1cb464656af14981b772796645ce179275241 100644
--- a/src/redux/layers/layers.types.ts
+++ b/src/redux/layers/layers.types.ts
@@ -23,7 +23,7 @@ export type LayerState = {
   texts: { [key: string]: LayerText };
   rects: { [key: string]: LayerRect };
   ovals: { [key: string]: LayerOval };
-  lines: LayerLine[];
+  lines: { [key: string]: LayerLine };
   images: { [key: string]: LayerImage };
 };
 
diff --git a/src/redux/layers/utils/setLayerLine.ts b/src/redux/layers/utils/setLayerLine.ts
new file mode 100644
index 0000000000000000000000000000000000000000..983f0b1e79041d4f6392ac002fc39e139d3cab1e
--- /dev/null
+++ b/src/redux/layers/utils/setLayerLine.ts
@@ -0,0 +1,18 @@
+import { LayerLine } from '@/types/models';
+import { LayersDictState } from '@/redux/layers/layers.types';
+
+export default function setLayerLine({
+  layerId,
+  layers,
+  layerLine,
+}: {
+  layerId: number;
+  layers: LayersDictState;
+  layerLine: LayerLine;
+}): void {
+  const layer = layers[layerId];
+  if (!layer) {
+    return;
+  }
+  layer.lines[layerLine.id] = layerLine;
+}
diff --git a/src/redux/mapEditTools/mapEditTools.constants.ts b/src/redux/mapEditTools/mapEditTools.constants.ts
index d94ae83d709e3a7004adf7e7fbdccdf70dcb3a42..8f9fe3293873500d0fb593e88a1c63930b203d47 100644
--- a/src/redux/mapEditTools/mapEditTools.constants.ts
+++ b/src/redux/mapEditTools/mapEditTools.constants.ts
@@ -3,5 +3,6 @@ export const MAP_EDIT_ACTIONS = {
   ADD_TEXT: 'ADD_TEXT',
   ADD_RECT: 'ADD_RECT',
   ADD_OVAL: 'ADD_OVAL',
+  ADD_LINE: 'ADD_LINE',
   TRANSFORM_IMAGE: 'TRANSFORM_IMAGE',
 } as const;
diff --git a/src/redux/mapEditTools/mapEditTools.mock.ts b/src/redux/mapEditTools/mapEditTools.mock.ts
index fbbacec71b385a8f9ee7060ddce4c290a1ba4cd0..86269f24977aff0a8bcae7f264f2144058afaa73 100644
--- a/src/redux/mapEditTools/mapEditTools.mock.ts
+++ b/src/redux/mapEditTools/mapEditTools.mock.ts
@@ -3,4 +3,5 @@ import { MapEditToolsState } from '@/redux/mapEditTools/mapEditTools.types';
 export const MAP_EDIT_TOOLS_STATE_INITIAL_MOCK: MapEditToolsState = {
   activeAction: null,
   layerObject: null,
+  layerLine: null,
 };
diff --git a/src/redux/mapEditTools/mapEditTools.reducers.ts b/src/redux/mapEditTools/mapEditTools.reducers.ts
index 98c871a5bcfa1b5eb99ced56a21a7236d6eaf620..5f4429d5ce95441b05d55cebc5af66f361b67702 100644
--- a/src/redux/mapEditTools/mapEditTools.reducers.ts
+++ b/src/redux/mapEditTools/mapEditTools.reducers.ts
@@ -2,7 +2,7 @@
 import { PayloadAction } from '@reduxjs/toolkit';
 import { MAP_EDIT_ACTIONS } from '@/redux/mapEditTools/mapEditTools.constants';
 import { MapEditToolsState } from '@/redux/mapEditTools/mapEditTools.types';
-import { LayerImage, LayerOval, LayerRect, LayerText } from '@/types/models';
+import { LayerImage, LayerLine, LayerOval, LayerRect, LayerText } from '@/types/models';
 
 export const mapEditToolsSetActiveActionReducer = (
   state: MapEditToolsState,
@@ -17,3 +17,10 @@ export const mapEditToolsSetLayerObjectReducer = (
 ): void => {
   state.layerObject = action.payload;
 };
+
+export const mapEditToolsSetLayerLineReducer = (
+  state: MapEditToolsState,
+  action: PayloadAction<LayerLine | null>,
+): void => {
+  state.layerLine = action.payload;
+};
diff --git a/src/redux/mapEditTools/mapEditTools.selectors.ts b/src/redux/mapEditTools/mapEditTools.selectors.ts
index d3ea7d128e91a479e9cdbf8311d0d7892da37a84..b6f278a2bd8937da73ee0255df6962f83ef8633a 100644
--- a/src/redux/mapEditTools/mapEditTools.selectors.ts
+++ b/src/redux/mapEditTools/mapEditTools.selectors.ts
@@ -10,6 +10,16 @@ export const mapEditToolsActiveActionSelector = createSelector(
 );
 
 export const mapEditToolsLayerObjectSelector = createSelector(
+  mapEditToolsSelector,
+  state => state.layerObject || state.layerLine,
+);
+
+export const mapEditToolsLayerLineSelector = createSelector(
+  mapEditToolsSelector,
+  state => state.layerLine,
+);
+
+export const mapEditToolsLayerNonLineObjectSelector = createSelector(
   mapEditToolsSelector,
   state => state.layerObject,
 );
diff --git a/src/redux/mapEditTools/mapEditTools.slice.ts b/src/redux/mapEditTools/mapEditTools.slice.ts
index 2db0001c938bc11f5469fb5addfc167d639680c3..243ad763e6db68619d9d82f399b6421a9a94ad7d 100644
--- a/src/redux/mapEditTools/mapEditTools.slice.ts
+++ b/src/redux/mapEditTools/mapEditTools.slice.ts
@@ -2,6 +2,7 @@ import { createSlice } from '@reduxjs/toolkit';
 import { MAP_EDIT_TOOLS_STATE_INITIAL_MOCK } from '@/redux/mapEditTools/mapEditTools.mock';
 import {
   mapEditToolsSetActiveActionReducer,
+  mapEditToolsSetLayerLineReducer,
   mapEditToolsSetLayerObjectReducer,
 } from '@/redux/mapEditTools/mapEditTools.reducers';
 
@@ -11,9 +12,11 @@ export const layersSlice = createSlice({
   reducers: {
     mapEditToolsSetActiveAction: mapEditToolsSetActiveActionReducer,
     mapEditToolsSetLayerObject: mapEditToolsSetLayerObjectReducer,
+    mapEditToolsSetLayerLine: mapEditToolsSetLayerLineReducer,
   },
 });
 
-export const { mapEditToolsSetActiveAction, mapEditToolsSetLayerObject } = layersSlice.actions;
+export const { mapEditToolsSetActiveAction, mapEditToolsSetLayerObject, mapEditToolsSetLayerLine } =
+  layersSlice.actions;
 
 export default layersSlice.reducer;
diff --git a/src/redux/mapEditTools/mapEditTools.types.ts b/src/redux/mapEditTools/mapEditTools.types.ts
index 50f2b0f4273929e3e465af2935babd5f10bf9a9a..1455362209ab9a5dd425150d53de397e997bf54b 100644
--- a/src/redux/mapEditTools/mapEditTools.types.ts
+++ b/src/redux/mapEditTools/mapEditTools.types.ts
@@ -1,7 +1,8 @@
 import { MAP_EDIT_ACTIONS } from '@/redux/mapEditTools/mapEditTools.constants';
-import { LayerImage, LayerOval, LayerRect, LayerText } from '@/types/models';
+import { LayerImage, LayerLine, LayerOval, LayerRect, LayerText } from '@/types/models';
 
 export type MapEditToolsState = {
   activeAction: keyof typeof MAP_EDIT_ACTIONS | null;
   layerObject: LayerImage | LayerText | LayerRect | LayerOval | null;
+  layerLine: LayerLine | null;
 };
diff --git a/src/redux/modal/modal.constants.ts b/src/redux/modal/modal.constants.ts
index e1bd16d6813dfa4e230cf419468277e7fbb82f15..f7c1f14675c999e764d2e293f12fca2428a96857 100644
--- a/src/redux/modal/modal.constants.ts
+++ b/src/redux/modal/modal.constants.ts
@@ -16,4 +16,5 @@ export const MODAL_INITIAL_STATE: ModalState = {
   errorReportState: {},
   layerFactoryState: { id: undefined },
   layerObjectFactoryState: undefined,
+  layerLineFactoryState: undefined,
 };
diff --git a/src/redux/modal/modal.mock.ts b/src/redux/modal/modal.mock.ts
index 26872d50cd57e6ff2f045d743f768115f47dfcd9..fef3c594d63b0dc5a34277acac5c0e58ce374e05 100644
--- a/src/redux/modal/modal.mock.ts
+++ b/src/redux/modal/modal.mock.ts
@@ -16,4 +16,5 @@ export const MODAL_INITIAL_STATE_MOCK: ModalState = {
   errorReportState: {},
   layerFactoryState: { id: undefined },
   layerObjectFactoryState: undefined,
+  layerLineFactoryState: undefined,
 };
diff --git a/src/redux/modal/modal.reducers.ts b/src/redux/modal/modal.reducers.ts
index 0dda3081ad656ab53db3a1e41c87abd34d21a89b..fd22c266bb0f2021959184df4e12664082fd6f74 100644
--- a/src/redux/modal/modal.reducers.ts
+++ b/src/redux/modal/modal.reducers.ts
@@ -2,6 +2,7 @@ import { ModalName } from '@/types/modal';
 import { PayloadAction } from '@reduxjs/toolkit';
 import { ErrorData } from '@/utils/error-report/ErrorData';
 import { BoundingBox } from '@/components/Map/MapViewer/MapViewer.types';
+import { Segment } from '@/types/models';
 import {
   ModalState,
   OpenEditOverlayGroupModalAction,
@@ -217,3 +218,19 @@ export const openLayerOvalEditFactoryModalReducer = (state: ModalState): void =>
   state.modalName = 'layer-oval-edit-factory';
   state.modalTitle = 'Edit oval';
 };
+
+export const openLayerLineFactoryModalReducer = (
+  state: ModalState,
+  action: PayloadAction<Array<Segment>>,
+): void => {
+  state.layerLineFactoryState = action.payload;
+  state.modalName = 'layer-line-factory';
+  state.modalTitle = 'Add line';
+  state.isOpen = true;
+};
+
+export const openLayerLineEditFactoryModalReducer = (state: ModalState): void => {
+  state.isOpen = true;
+  state.modalName = 'layer-line-edit-factory';
+  state.modalTitle = 'Edit line';
+};
diff --git a/src/redux/modal/modal.selector.ts b/src/redux/modal/modal.selector.ts
index 7c5224193cac110b864fd44f76095ee0511086c9..4265eca2f381d72f3c17ea44dc2b7a66eab38fdc 100644
--- a/src/redux/modal/modal.selector.ts
+++ b/src/redux/modal/modal.selector.ts
@@ -40,3 +40,8 @@ export const layerObjectFactoryStateSelector = createSelector(
   modalSelector,
   modal => modal.layerObjectFactoryState,
 );
+
+export const layerLineFactoryStateSelector = createSelector(
+  modalSelector,
+  modal => modal.layerLineFactoryState,
+);
diff --git a/src/redux/modal/modal.slice.ts b/src/redux/modal/modal.slice.ts
index 1618ce0d702553a83f77530b49a29503d12df4d7..13fa58579a233896fdd865910086fd6cbc249de0 100644
--- a/src/redux/modal/modal.slice.ts
+++ b/src/redux/modal/modal.slice.ts
@@ -26,6 +26,8 @@ import {
   openLayerOvalFactoryModalReducer,
   openEditOverlayGroupModalReducer,
   openLayerOvalEditFactoryModalReducer,
+  openLayerLineFactoryModalReducer,
+  openLayerLineEditFactoryModalReducer,
 } from './modal.reducers';
 
 const modalSlice = createSlice({
@@ -57,6 +59,8 @@ const modalSlice = createSlice({
     openLayerRectEditFactoryModal: openLayerRectEditFactoryModalReducer,
     openLayerOvalFactoryModal: openLayerOvalFactoryModalReducer,
     openLayerOvalEditFactoryModal: openLayerOvalEditFactoryModalReducer,
+    openLayerLineFactoryModal: openLayerLineFactoryModalReducer,
+    openLayerLineEditFactoryModal: openLayerLineEditFactoryModalReducer,
   },
 });
 
@@ -86,6 +90,8 @@ export const {
   openLayerRectEditFactoryModal,
   openLayerOvalFactoryModal,
   openLayerOvalEditFactoryModal,
+  openLayerLineFactoryModal,
+  openLayerLineEditFactoryModal,
 } = modalSlice.actions;
 
 export default modalSlice.reducer;
diff --git a/src/redux/modal/modal.types.ts b/src/redux/modal/modal.types.ts
index a558bfaba7b998c90a0eb8a26f48eb394ef8fb8e..ab98a156feb3c3caf7e0b7086f85beb59ff13005 100644
--- a/src/redux/modal/modal.types.ts
+++ b/src/redux/modal/modal.types.ts
@@ -1,5 +1,5 @@
 import { ModalName } from '@/types/modal';
-import { MapOverlay, OverlayGroup } from '@/types/models';
+import { MapOverlay, OverlayGroup, Segment } from '@/types/models';
 import { PayloadAction } from '@reduxjs/toolkit';
 import { ErrorData } from '@/utils/error-report/ErrorData';
 import { BoundingBox } from '@/components/Map/MapViewer/MapViewer.types';
@@ -25,6 +25,8 @@ export type LayerFactoryState = {
 
 export type LayerObjectFactoryBoundingBoxState = BoundingBox | undefined;
 
+export type LayerLineFactoryState = Array<Segment> | undefined;
+
 export interface ModalState {
   isOpen: boolean;
   modalName: ModalName;
@@ -36,6 +38,7 @@ export interface ModalState {
   editOverlayGroupState: EditOverlayGroupState;
   layerFactoryState: LayerFactoryState;
   layerObjectFactoryState: LayerObjectFactoryBoundingBoxState;
+  layerLineFactoryState: LayerLineFactoryState;
 }
 
 export type OpenEditOverlayModalPayload = MapOverlay;
diff --git a/src/redux/shapes/shapes.selectors.ts b/src/redux/shapes/shapes.selectors.ts
index d23c9a97d97a744f6150d30757d2706dbeaa6a96..9768c2a555b8038eb264f0c61dcfda8b1626cf6d 100644
--- a/src/redux/shapes/shapes.selectors.ts
+++ b/src/redux/shapes/shapes.selectors.ts
@@ -18,6 +18,10 @@ export const lineTypesSelector = createSelector(
   shapes => shapes.lineTypesState.data || {},
 );
 
+export const lineTypesKeysSelector = createSelector(shapesSelector, shapes =>
+  Object.keys(shapes.lineTypesState?.data || {}),
+);
+
 export const lineTypesLoadingSelector = createSelector(
   shapesSelector,
   shapes => shapes.lineTypesState.loading,
@@ -28,6 +32,10 @@ export const arrowTypesSelector = createSelector(
   shapes => shapes.arrowTypesState.data || {},
 );
 
+export const arrowTypesKeysSelector = createSelector(shapesSelector, shapes =>
+  Object.keys(shapes.arrowTypesState?.data || {}),
+);
+
 export const arrowTypesLoadingSelector = createSelector(
   shapesSelector,
   shapes => shapes.arrowTypesState.loading,
diff --git a/src/shared/Icon/Icon.component.tsx b/src/shared/Icon/Icon.component.tsx
index 8f8459af7ccb83a7f3acc3ee2b741e3cd2ac5157..a4c7753ebdd4b362037c2d6f8ebbc7bb279c3a6c 100644
--- a/src/shared/Icon/Icon.component.tsx
+++ b/src/shared/Icon/Icon.component.tsx
@@ -37,6 +37,7 @@ import { LayerArrowUpIcon } from '@/shared/Icon/Icons/LayerArrowUpIcon';
 import { LayerArrowDownIcon } from '@/shared/Icon/Icons/LayerArrowDownIcon';
 import { RectangleIcon } from '@/shared/Icon/Icons/RectangleIcon';
 import { OvalIcon } from '@/shared/Icon/Icons/OvalIcon';
+import { LineIcon } from '@/shared/Icon/Icons/LineIcon';
 import { LocationIcon } from './Icons/LocationIcon';
 import { MaginfierZoomInIcon } from './Icons/MagnifierZoomIn';
 import { MaginfierZoomOutIcon } from './Icons/MagnifierZoomOut';
@@ -97,6 +98,7 @@ const icons: Record<IconTypes, IconComponentType> = {
   'layer-arrow-down': LayerArrowDownIcon,
   rectangle: RectangleIcon,
   oval: OvalIcon,
+  line: LineIcon,
 } as const;
 
 export const Icon = ({ name, className = '', ...rest }: IconProps): JSX.Element => {
diff --git a/src/shared/Icon/Icons/LineIcon.tsx b/src/shared/Icon/Icons/LineIcon.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..6d535b99ce7e462bb7628d4db20e1a064683a9fa
--- /dev/null
+++ b/src/shared/Icon/Icons/LineIcon.tsx
@@ -0,0 +1,35 @@
+interface LineIconProps {
+  className?: string;
+}
+
+export const LineIcon = ({ className }: LineIconProps): JSX.Element => (
+  <svg
+    width="20"
+    height="20"
+    viewBox="0 0 200 200"
+    xmlns="http://www.w3.org/2000/svg"
+    className={className}
+  >
+    <defs>
+      <marker
+        id="arrow"
+        markerWidth="10"
+        markerHeight="10"
+        refX="5"
+        refY="5"
+        orient="auto"
+        markerUnits="strokeWidth"
+      >
+        <path d="M 0 0 L 10 5 L 0 10 z" fill="black" />
+      </marker>
+    </defs>
+    <polyline
+      points="20,180 80,100 140,140 180,40"
+      stroke="black"
+      strokeWidth="8"
+      fill="none"
+      strokeLinejoin="round"
+      markerEnd="url(#arrow)"
+    />
+  </svg>
+);
diff --git a/src/types/iconTypes.ts b/src/types/iconTypes.ts
index 57cd7d668c407da83bb3851a4037784862eddff0..0e587285da682a4b306bd0fdb97ff1a677b85cb3 100644
--- a/src/types/iconTypes.ts
+++ b/src/types/iconTypes.ts
@@ -43,6 +43,7 @@ export type IconTypes =
   | 'layer-arrow-up'
   | 'layer-arrow-down'
   | 'rectangle'
-  | 'oval';
+  | 'oval'
+  | 'line';
 
 export type IconComponentType = ({ className }: { className: string }) => JSX.Element;
diff --git a/src/types/modal.ts b/src/types/modal.ts
index 5efc956488c8a9902f2f2b1a9c66b477942d27ec..0a98faa94d02f5687a4a12d9305561c05a0c748f 100644
--- a/src/types/modal.ts
+++ b/src/types/modal.ts
@@ -21,4 +21,6 @@ export type ModalName =
   | 'layer-rect-factory'
   | 'layer-rect-edit-factory'
   | 'layer-oval-factory'
-  | 'layer-oval-edit-factory';
+  | 'layer-oval-edit-factory'
+  | 'layer-line-factory'
+  | 'layer-line-edit-factory';