First steps VC network link
This commit is contained in:
parent
5ad265cbc8
commit
a313f00755
|
@ -231,6 +231,7 @@ define('DONUT_GRAPH', 17);
|
||||||
define('BARS_GRAPH', 18);
|
define('BARS_GRAPH', 18);
|
||||||
define('CLOCK', 19);
|
define('CLOCK', 19);
|
||||||
define('COLOR_CLOUD', 20);
|
define('COLOR_CLOUD', 20);
|
||||||
|
define('NETWORK_LINK', 21);
|
||||||
// Some styles.
|
// Some styles.
|
||||||
define('MIN_WIDTH', 300);
|
define('MIN_WIDTH', 300);
|
||||||
define('MIN_HEIGHT', 120);
|
define('MIN_HEIGHT', 120);
|
||||||
|
|
|
@ -1308,6 +1308,7 @@ function visual_map_editor_print_toolbox()
|
||||||
visual_map_print_button_editor('box_item', __('Box'), 'left', false, 'box_item_min', true);
|
visual_map_print_button_editor('box_item', __('Box'), 'left', false, 'box_item_min', true);
|
||||||
visual_map_print_button_editor('line_item', __('Line'), 'left', false, 'line_item_min', true);
|
visual_map_print_button_editor('line_item', __('Line'), 'left', false, 'line_item_min', true);
|
||||||
visual_map_print_button_editor('color_cloud', __('Color cloud'), 'left', false, 'color_cloud_min', true);
|
visual_map_print_button_editor('color_cloud', __('Color cloud'), 'left', false, 'color_cloud_min', true);
|
||||||
|
visual_map_print_button_editor('network_link', __('Network link'), 'left', false, 'network_link_min', true);
|
||||||
if (defined('METACONSOLE')) {
|
if (defined('METACONSOLE')) {
|
||||||
echo '<a href="javascript:" class="tip"><img src="'.$config['homeurl_static'].'/images/tip.png" data-title="The data displayed in editor mode is not real" data-use_title_for_force_title="1"
|
echo '<a href="javascript:" class="tip"><img src="'.$config['homeurl_static'].'/images/tip.png" data-title="The data displayed in editor mode is not real" data-use_title_for_force_title="1"
|
||||||
class="forced_title" alt="The data displayed in editor mode is not real"></a>';
|
class="forced_title" alt="The data displayed in editor mode is not real"></a>';
|
||||||
|
|
|
@ -345,6 +345,9 @@ final class Container extends Model
|
||||||
case COLOR_CLOUD:
|
case COLOR_CLOUD:
|
||||||
return Items\ColorCloud::class;
|
return Items\ColorCloud::class;
|
||||||
|
|
||||||
|
case NETWORK_LINK:
|
||||||
|
return Items\NetworkLink::class;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return Item::class;
|
return Item::class;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,507 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Models\VisualConsole\Items;
|
||||||
|
use Models\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model of a line item of the Visual Console.
|
||||||
|
*/
|
||||||
|
final class NetworkLink extends Model
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the received data structure to ensure if we can extract the
|
||||||
|
* values required to build the model.
|
||||||
|
*
|
||||||
|
* @param array $data Input data.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws \InvalidArgumentException If any input value is considered
|
||||||
|
* invalid.
|
||||||
|
*
|
||||||
|
* @overrides Model->validateData.
|
||||||
|
*/
|
||||||
|
protected function validateData(array $data): void
|
||||||
|
{
|
||||||
|
if (isset($data['id']) === false
|
||||||
|
|| \is_numeric($data['id']) === false
|
||||||
|
) {
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
|
'the Id property is required and should be integer'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($data['type']) === false
|
||||||
|
|| \is_numeric($data['type']) === false
|
||||||
|
) {
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
|
'the Id property is required and should be integer'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a valid representation of the model.
|
||||||
|
*
|
||||||
|
* @param array $data Input data.
|
||||||
|
*
|
||||||
|
* @return array Data structure representing the model.
|
||||||
|
*
|
||||||
|
* @overrides Model->decode.
|
||||||
|
*/
|
||||||
|
protected function decode(array $data): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => (int) $data['id'],
|
||||||
|
'type' => NETWORK_LINK,
|
||||||
|
'startX' => static::extractStartX($data),
|
||||||
|
'startY' => static::extractStartY($data),
|
||||||
|
'endX' => static::extractEndX($data),
|
||||||
|
'endY' => static::extractEndY($data),
|
||||||
|
'isOnTop' => static::extractIsOnTop($data),
|
||||||
|
'borderWidth' => static::extractBorderWidth($data),
|
||||||
|
'borderColor' => static::extractBorderColor($data),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract a x axis value.
|
||||||
|
*
|
||||||
|
* @param array $data Unknown input data structure.
|
||||||
|
*
|
||||||
|
* @return integer Valid x axis of the start position of the line.
|
||||||
|
*/
|
||||||
|
private static function extractStartX(array $data): int
|
||||||
|
{
|
||||||
|
return static::parseIntOr(
|
||||||
|
static::issetInArray($data, ['startX', 'pos_x']),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract a y axis value.
|
||||||
|
*
|
||||||
|
* @param array $data Unknown input data structure.
|
||||||
|
*
|
||||||
|
* @return integer Valid y axis of the start position of the line.
|
||||||
|
*/
|
||||||
|
private static function extractStartY(array $data): int
|
||||||
|
{
|
||||||
|
return static::parseIntOr(
|
||||||
|
static::issetInArray($data, ['startY', 'pos_y']),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract a x axis value.
|
||||||
|
*
|
||||||
|
* @param array $data Unknown input data structure.
|
||||||
|
*
|
||||||
|
* @return integer Valid x axis of the end position of the line.
|
||||||
|
*/
|
||||||
|
private static function extractEndX(array $data): int
|
||||||
|
{
|
||||||
|
return static::parseIntOr(
|
||||||
|
static::issetInArray($data, ['endX', 'width']),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract a y axis value.
|
||||||
|
*
|
||||||
|
* @param array $data Unknown input data structure.
|
||||||
|
*
|
||||||
|
* @return integer Valid y axis of the end position of the line.
|
||||||
|
*/
|
||||||
|
private static function extractEndY(array $data): int
|
||||||
|
{
|
||||||
|
return static::parseIntOr(
|
||||||
|
static::issetInArray($data, ['endY', 'height']),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract a conditional value which tells if the item has visual priority.
|
||||||
|
*
|
||||||
|
* @param array $data Unknown input data structure.
|
||||||
|
*
|
||||||
|
* @return boolean If the item is on top or not.
|
||||||
|
*/
|
||||||
|
private static function extractIsOnTop(array $data): bool
|
||||||
|
{
|
||||||
|
return static::parseBool(
|
||||||
|
static::issetInArray($data, ['isOnTop', 'show_on_top'])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract a border width value.
|
||||||
|
*
|
||||||
|
* @param array $data Unknown input data structure.
|
||||||
|
*
|
||||||
|
* @return integer Valid border width. 0 by default and minimum value.
|
||||||
|
*/
|
||||||
|
private static function extractBorderWidth(array $data): int
|
||||||
|
{
|
||||||
|
$borderWidth = static::parseIntOr(
|
||||||
|
static::issetInArray($data, ['borderWidth', 'border_width']),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
return ($borderWidth >= 0) ? $borderWidth : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract a border color value.
|
||||||
|
*
|
||||||
|
* @param array $data Unknown input data structure.
|
||||||
|
*
|
||||||
|
* @return mixed String representing the border color (not empty) or null.
|
||||||
|
*/
|
||||||
|
private static function extractBorderColor(array $data)
|
||||||
|
{
|
||||||
|
return static::notEmptyStringOr(
|
||||||
|
static::issetInArray($data, ['borderColor', 'border_color']),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain a vc item data structure from the database using a filter.
|
||||||
|
*
|
||||||
|
* @param array $filter Filter of the Visual Console Item.
|
||||||
|
*
|
||||||
|
* @return array The Visual Console line data structure stored into the DB.
|
||||||
|
* @throws \Exception When the data cannot be retrieved from the DB.
|
||||||
|
*
|
||||||
|
* @override Model::fetchDataFromDB.
|
||||||
|
*/
|
||||||
|
protected static function fetchDataFromDB(
|
||||||
|
array $filter,
|
||||||
|
?float $ratio=0
|
||||||
|
): array {
|
||||||
|
// Due to this DB call, this function cannot be unit tested without
|
||||||
|
// a proper mock.
|
||||||
|
$row = \db_get_row_filter('tlayout_data', $filter);
|
||||||
|
|
||||||
|
if ($row === false) {
|
||||||
|
throw new \Exception('error fetching the data from the DB');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ratio != 0) {
|
||||||
|
$row['width'] = ($row['width'] * $ratio);
|
||||||
|
$row['height'] = ($row['height'] * $ratio);
|
||||||
|
$row['pos_x'] = ($row['pos_x'] * $ratio);
|
||||||
|
$row['pos_y'] = ($row['pos_y'] * $ratio);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a valid representation of a record in database.
|
||||||
|
*
|
||||||
|
* @param array $data Input data.
|
||||||
|
*
|
||||||
|
* @return array Data structure representing a record in database.
|
||||||
|
*
|
||||||
|
* @overrides Model::encode.
|
||||||
|
*/
|
||||||
|
protected function encode(array $data): array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
$result['type'] = NETWORK_LINK;
|
||||||
|
|
||||||
|
$id = static::getId($data);
|
||||||
|
if ($id) {
|
||||||
|
$result['id'] = $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$layoutId = static::getIdLayout($data);
|
||||||
|
if ($layoutId > 0) {
|
||||||
|
$result['id_layout'] = $layoutId;
|
||||||
|
}
|
||||||
|
|
||||||
|
$startX = static::parseIntOr(
|
||||||
|
static::issetInArray($data, ['pos_x', 'startX']),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
if ($startX !== null) {
|
||||||
|
$result['pos_x'] = $startX;
|
||||||
|
}
|
||||||
|
|
||||||
|
$startY = static::parseIntOr(
|
||||||
|
static::issetInArray($data, ['pos_y', 'startY']),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
if ($startY !== null) {
|
||||||
|
$result['pos_y'] = $startY;
|
||||||
|
}
|
||||||
|
|
||||||
|
$endX = static::parseIntOr(
|
||||||
|
static::issetInArray($data, ['width', 'endX']),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
if ($endX !== null) {
|
||||||
|
$result['width'] = $endX;
|
||||||
|
}
|
||||||
|
|
||||||
|
$endY = static::parseIntOr(
|
||||||
|
static::issetInArray($data, ['height', 'endY']),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
if ($endY !== null) {
|
||||||
|
$result['height'] = $endY;
|
||||||
|
}
|
||||||
|
|
||||||
|
$borderWidth = static::getBorderWidth($data);
|
||||||
|
if ($borderWidth !== null) {
|
||||||
|
if ($borderWidth < 1) {
|
||||||
|
$borderWidth = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result['border_width'] = $borderWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
$borderColor = static::extractBorderColor($data);
|
||||||
|
if ($borderColor !== null) {
|
||||||
|
$result['border_color'] = $borderColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
$showOnTop = static::issetInArray(
|
||||||
|
$data,
|
||||||
|
[
|
||||||
|
'isOnTop',
|
||||||
|
'show_on_top',
|
||||||
|
'showOnTop',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
if ($showOnTop !== null) {
|
||||||
|
$result['show_on_top'] = static::parseBool($showOnTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract item id.
|
||||||
|
*
|
||||||
|
* @param array $data Unknown input data structure.
|
||||||
|
*
|
||||||
|
* @return integer Item id. 0 by default.
|
||||||
|
*/
|
||||||
|
private static function getId(array $data): int
|
||||||
|
{
|
||||||
|
return static::parseIntOr(
|
||||||
|
static::issetInArray($data, ['id', 'itemId']),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract layout id.
|
||||||
|
*
|
||||||
|
* @param array $data Unknown input data structure.
|
||||||
|
*
|
||||||
|
* @return integer Item id. 0 by default.
|
||||||
|
*/
|
||||||
|
private static function getIdLayout(array $data): int
|
||||||
|
{
|
||||||
|
return static::parseIntOr(
|
||||||
|
static::issetInArray($data, ['id_layout', 'idLayout', 'layoutId']),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract item width.
|
||||||
|
*
|
||||||
|
* @param array $data Unknown input data structure.
|
||||||
|
*
|
||||||
|
* @return integer Item width. 0 by default.
|
||||||
|
*/
|
||||||
|
private static function getWidth(array $data)
|
||||||
|
{
|
||||||
|
return static::parseIntOr(
|
||||||
|
static::issetInArray($data, ['width', 'endX']),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract item height.
|
||||||
|
*
|
||||||
|
* @param array $data Unknown input data structure.
|
||||||
|
*
|
||||||
|
* @return integer Item height. 0 by default.
|
||||||
|
*/
|
||||||
|
private static function getHeight(array $data)
|
||||||
|
{
|
||||||
|
return static::parseIntOr(
|
||||||
|
static::issetInArray($data, ['height', 'endY']),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract a border width value.
|
||||||
|
*
|
||||||
|
* @param array $data Unknown input data structure.
|
||||||
|
*
|
||||||
|
* @return integer Valid border width.
|
||||||
|
*/
|
||||||
|
private static function getBorderWidth(array $data)
|
||||||
|
{
|
||||||
|
return static::parseIntOr(
|
||||||
|
static::issetInArray($data, ['border_width', 'borderWidth']),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert or update an item in the database
|
||||||
|
*
|
||||||
|
* @param array $data Unknown input data structure.
|
||||||
|
*
|
||||||
|
* @return integer The modeled element data structure stored into the DB.
|
||||||
|
*
|
||||||
|
* @overrides Model::save.
|
||||||
|
*/
|
||||||
|
public function save(array $data=[]): int
|
||||||
|
{
|
||||||
|
if (empty($data) === false) {
|
||||||
|
if (empty($data['id']) === true) {
|
||||||
|
// Insert.
|
||||||
|
$save = static::encode($data);
|
||||||
|
$result = \db_process_sql_insert('tlayout_data', $save);
|
||||||
|
if ($result !== false) {
|
||||||
|
$item = static::fromDB(['id' => $result]);
|
||||||
|
$item->setData($item->toArray());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Update.
|
||||||
|
$dataModelEncode = $this->encode($this->toArray());
|
||||||
|
$dataEncode = $this->encode($data);
|
||||||
|
|
||||||
|
$save = array_merge($dataModelEncode, $dataEncode);
|
||||||
|
|
||||||
|
$result = \db_process_sql_update(
|
||||||
|
'tlayout_data',
|
||||||
|
$save,
|
||||||
|
['id' => $save['id']]
|
||||||
|
);
|
||||||
|
// Invalidate the item's cache.
|
||||||
|
if ($result !== false && $result > 0) {
|
||||||
|
$item = static::fromDB(['id' => $save['id']]);
|
||||||
|
// Update the model.
|
||||||
|
if (empty($item) === false) {
|
||||||
|
$this->setData($item->toArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a line in the database
|
||||||
|
*
|
||||||
|
* @param integer $itemId Identifier of the Item.
|
||||||
|
*
|
||||||
|
* @return boolean The modeled element data structure stored into the DB.
|
||||||
|
*
|
||||||
|
* @overrides Model::delete.
|
||||||
|
*/
|
||||||
|
public function delete(int $itemId): bool
|
||||||
|
{
|
||||||
|
$result = db_process_sql_delete(
|
||||||
|
'tlayout_data',
|
||||||
|
['id' => $itemId]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (bool) $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates inputs for form (global, common).
|
||||||
|
*
|
||||||
|
* @param array $values Default values.
|
||||||
|
*
|
||||||
|
* @return array Of inputs.
|
||||||
|
*/
|
||||||
|
public static function getFormInputs(array $values): array
|
||||||
|
{
|
||||||
|
$inputs = [];
|
||||||
|
|
||||||
|
if ($values['tabSelected'] === 'specific') {
|
||||||
|
// Width.
|
||||||
|
if ($values['borderWidth'] < 1) {
|
||||||
|
$values['borderWidth'] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$inputs[] = [
|
||||||
|
'label' => __('Width'),
|
||||||
|
'arguments' => [
|
||||||
|
'name' => 'borderWidth',
|
||||||
|
'type' => 'number',
|
||||||
|
'value' => $values['borderWidth'],
|
||||||
|
'return' => true,
|
||||||
|
'min' => 1,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Color.
|
||||||
|
$inputs[] = [
|
||||||
|
'label' => __('Color'),
|
||||||
|
'arguments' => [
|
||||||
|
'wrapper' => 'div',
|
||||||
|
'name' => 'borderColor',
|
||||||
|
'type' => 'color',
|
||||||
|
'value' => $values['borderColor'],
|
||||||
|
'return' => true,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Show on top.
|
||||||
|
$inputs[] = [
|
||||||
|
'label' => __('Show on top'),
|
||||||
|
'arguments' => [
|
||||||
|
'name' => 'isOnTop',
|
||||||
|
'id' => 'isOnTop',
|
||||||
|
'type' => 'switch',
|
||||||
|
'value' => $values['isOnTop'],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $inputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -280,6 +280,11 @@ if ($pure === false) {
|
||||||
__('Color cloud'),
|
__('Color cloud'),
|
||||||
'color_cloud_min link-create-item'
|
'color_cloud_min link-create-item'
|
||||||
);
|
);
|
||||||
|
visual_map_print_button_editor_refactor(
|
||||||
|
'NETWORK_LINK',
|
||||||
|
__('Network link'),
|
||||||
|
'network_link_min link-create-item'
|
||||||
|
);
|
||||||
enterprise_include_once('include/functions_visual_map_editor.php');
|
enterprise_include_once('include/functions_visual_map_editor.php');
|
||||||
enterprise_hook(
|
enterprise_hook(
|
||||||
'enterprise_visual_map_editor_print_toolbox_refactor'
|
'enterprise_visual_map_editor_print_toolbox_refactor'
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"trailingComma": "none",
|
||||||
|
"singleQuote": false,
|
||||||
|
"arrowParens": "avoid"
|
||||||
|
}
|
|
@ -46,7 +46,8 @@ export const enum ItemType {
|
||||||
DONUT_GRAPH = 17,
|
DONUT_GRAPH = 17,
|
||||||
BARS_GRAPH = 18,
|
BARS_GRAPH = 18,
|
||||||
CLOCK = 19,
|
CLOCK = 19,
|
||||||
COLOR_CLOUD = 20
|
COLOR_CLOUD = 20,
|
||||||
|
NETWORK_LINK = 21
|
||||||
}
|
}
|
||||||
|
|
||||||
// Base item properties. This interface should be extended by the item implementations.
|
// Base item properties. This interface should be extended by the item implementations.
|
||||||
|
@ -208,6 +209,9 @@ export function titleItem(id: number): string {
|
||||||
case ItemType.COLOR_CLOUD:
|
case ItemType.COLOR_CLOUD:
|
||||||
title = t("Color cloud");
|
title = t("Color cloud");
|
||||||
break;
|
break;
|
||||||
|
case ItemType.NETWORK_LINK:
|
||||||
|
title = t("Network link");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
title = t("Item");
|
title = t("Item");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -20,6 +20,7 @@ import Item, {
|
||||||
import StaticGraph, { staticGraphPropsDecoder } from "./items/StaticGraph";
|
import StaticGraph, { staticGraphPropsDecoder } from "./items/StaticGraph";
|
||||||
import Icon, { iconPropsDecoder } from "./items/Icon";
|
import Icon, { iconPropsDecoder } from "./items/Icon";
|
||||||
import ColorCloud, { colorCloudPropsDecoder } from "./items/ColorCloud";
|
import ColorCloud, { colorCloudPropsDecoder } from "./items/ColorCloud";
|
||||||
|
import NetworkLink, { networkLinkPropsDecoder } from "./items/NetworkLink";
|
||||||
import Group, { groupPropsDecoder } from "./items/Group";
|
import Group, { groupPropsDecoder } from "./items/Group";
|
||||||
import Clock, { clockPropsDecoder } from "./items/Clock";
|
import Clock, { clockPropsDecoder } from "./items/Clock";
|
||||||
import Box, { boxPropsDecoder } from "./items/Box";
|
import Box, { boxPropsDecoder } from "./items/Box";
|
||||||
|
@ -82,6 +83,8 @@ function itemInstanceFrom(data: AnyObject) {
|
||||||
return new Clock(clockPropsDecoder(data), meta);
|
return new Clock(clockPropsDecoder(data), meta);
|
||||||
case ItemType.COLOR_CLOUD:
|
case ItemType.COLOR_CLOUD:
|
||||||
return new ColorCloud(colorCloudPropsDecoder(data), meta);
|
return new ColorCloud(colorCloudPropsDecoder(data), meta);
|
||||||
|
case ItemType.NETWORK_LINK:
|
||||||
|
return new NetworkLink(networkLinkPropsDecoder(data), meta);
|
||||||
default:
|
default:
|
||||||
throw new TypeError("item not found");
|
throw new TypeError("item not found");
|
||||||
}
|
}
|
||||||
|
@ -130,6 +133,8 @@ function decodeProps(data: AnyObject) {
|
||||||
return clockPropsDecoder(data);
|
return clockPropsDecoder(data);
|
||||||
case ItemType.COLOR_CLOUD:
|
case ItemType.COLOR_CLOUD:
|
||||||
return colorCloudPropsDecoder(data);
|
return colorCloudPropsDecoder(data);
|
||||||
|
case ItemType.NETWORK_LINK:
|
||||||
|
return networkLinkPropsDecoder(data);
|
||||||
default:
|
default:
|
||||||
throw new TypeError("decoder not found");
|
throw new TypeError("decoder not found");
|
||||||
}
|
}
|
||||||
|
@ -973,7 +978,8 @@ export default class VisualConsole {
|
||||||
[ItemType.DONUT_GRAPH]: DonutGraph,
|
[ItemType.DONUT_GRAPH]: DonutGraph,
|
||||||
[ItemType.BARS_GRAPH]: BarsGraph,
|
[ItemType.BARS_GRAPH]: BarsGraph,
|
||||||
[ItemType.CLOCK]: Clock,
|
[ItemType.CLOCK]: Clock,
|
||||||
[ItemType.COLOR_CLOUD]: ColorCloud
|
[ItemType.COLOR_CLOUD]: ColorCloud,
|
||||||
|
[ItemType.NETWORK_LINK]: NetworkLink
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,530 @@
|
||||||
|
import { AnyObject, Position, Size, ItemMeta } from "../lib/types";
|
||||||
|
import {
|
||||||
|
parseIntOr,
|
||||||
|
notEmptyStringOr,
|
||||||
|
debounce,
|
||||||
|
addMovementListener
|
||||||
|
} from "../lib";
|
||||||
|
import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
|
||||||
|
import TypedEvent, { Listener, Disposable } from "../lib/TypedEvent";
|
||||||
|
|
||||||
|
interface NetworkLinkProps extends ItemProps {
|
||||||
|
// Overrided properties.
|
||||||
|
readonly type: ItemType.NETWORK_LINK;
|
||||||
|
label: null;
|
||||||
|
isLinkEnabled: false;
|
||||||
|
parentId: null;
|
||||||
|
aclGroupId: null;
|
||||||
|
// Custom properties.
|
||||||
|
startPosition: Position;
|
||||||
|
endPosition: Position;
|
||||||
|
lineWidth: number;
|
||||||
|
color: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a valid typed object from a raw object.
|
||||||
|
* This will allow us to ensure the type safety.
|
||||||
|
*
|
||||||
|
* @param data Raw object.
|
||||||
|
* @return An object representing the item props.
|
||||||
|
* @throws Will throw a TypeError if some property
|
||||||
|
* is missing from the raw object or have an invalid type.
|
||||||
|
*/
|
||||||
|
export function networkLinkPropsDecoder(
|
||||||
|
data: AnyObject
|
||||||
|
): NetworkLinkProps | never {
|
||||||
|
const props: NetworkLinkProps = {
|
||||||
|
...itemBasePropsDecoder({ ...data, width: 1, height: 1 }), // Object spread. It will merge the properties of the two objects.
|
||||||
|
type: ItemType.NETWORK_LINK,
|
||||||
|
label: null,
|
||||||
|
isLinkEnabled: false,
|
||||||
|
parentId: null,
|
||||||
|
aclGroupId: null,
|
||||||
|
// Initialize Position & Size.
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
// Custom properties.
|
||||||
|
startPosition: {
|
||||||
|
x: parseIntOr(data.startX, 0),
|
||||||
|
y: parseIntOr(data.startY, 0)
|
||||||
|
},
|
||||||
|
endPosition: {
|
||||||
|
x: parseIntOr(data.endX, 0),
|
||||||
|
y: parseIntOr(data.endY, 0)
|
||||||
|
},
|
||||||
|
lineWidth: parseIntOr(data.lineWidth || data.borderWidth, 1),
|
||||||
|
color: notEmptyStringOr(data.borderColor || data.color, null)
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to enhance the props with the extracted size and position
|
||||||
|
* of the box cause there are missing at the props update. A better
|
||||||
|
* solution would be overriding the props setter to do it there, but
|
||||||
|
* the language doesn't allow it while targetting ES5.
|
||||||
|
* TODO: We need to figure out a more consistent solution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return {
|
||||||
|
...props,
|
||||||
|
// Enhance the props extracting the box size and position.
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||||
|
...NetworkLink.extractBoxSizeAndPosition(
|
||||||
|
props.startPosition,
|
||||||
|
props.endPosition
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const svgNS = "http://www.w3.org/2000/svg";
|
||||||
|
|
||||||
|
export interface NetworkLinkMovedEvent {
|
||||||
|
item: NetworkLink;
|
||||||
|
startPosition: NetworkLinkProps["startPosition"];
|
||||||
|
endPosition: NetworkLinkProps["endPosition"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class NetworkLink extends Item<NetworkLinkProps> {
|
||||||
|
private circleRadius = 8;
|
||||||
|
// To control if the line movement is enabled.
|
||||||
|
private moveMode: boolean = false;
|
||||||
|
// To control if the line is moving.
|
||||||
|
private isMoving: boolean = false;
|
||||||
|
|
||||||
|
// Event manager for moved events.
|
||||||
|
private readonly lineMovedEventManager = new TypedEvent<
|
||||||
|
NetworkLinkMovedEvent
|
||||||
|
>();
|
||||||
|
// List of references to clean the event listeners.
|
||||||
|
private readonly lineMovedEventDisposables: Disposable[] = [];
|
||||||
|
|
||||||
|
// This function will only run the 2nd arg function after the time
|
||||||
|
// of the first arg have passed after its last execution.
|
||||||
|
private debouncedStartPositionMovementSave = debounce(
|
||||||
|
500, // ms.
|
||||||
|
(x: Position["x"], y: Position["y"]) => {
|
||||||
|
this.isMoving = false;
|
||||||
|
const startPosition = { x, y };
|
||||||
|
// Emit the movement event.
|
||||||
|
this.lineMovedEventManager.emit({
|
||||||
|
item: this,
|
||||||
|
startPosition,
|
||||||
|
endPosition: this.props.endPosition
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// This property will store the function
|
||||||
|
// to clean the movement listener.
|
||||||
|
private removeStartPositionMovement: Function | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the movement funtionality for the start position.
|
||||||
|
* @param element Element to move inside its container.
|
||||||
|
*/
|
||||||
|
private initStartPositionMovementListener(
|
||||||
|
element: HTMLElement,
|
||||||
|
container: HTMLElement
|
||||||
|
): void {
|
||||||
|
this.removeStartPositionMovement = addMovementListener(
|
||||||
|
element,
|
||||||
|
(x: Position["x"], y: Position["y"]) => {
|
||||||
|
// Calculate the center of the circle.
|
||||||
|
x += this.circleRadius;
|
||||||
|
y += this.circleRadius;
|
||||||
|
|
||||||
|
const startPosition = { x, y };
|
||||||
|
|
||||||
|
this.isMoving = true;
|
||||||
|
this.props = {
|
||||||
|
...this.props,
|
||||||
|
startPosition
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run the end function.
|
||||||
|
this.debouncedStartPositionMovementSave(x, y);
|
||||||
|
},
|
||||||
|
container
|
||||||
|
);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Stop the movement fun
|
||||||
|
*/
|
||||||
|
private stopStartPositionMovementListener(): void {
|
||||||
|
if (this.removeStartPositionMovement) {
|
||||||
|
this.removeStartPositionMovement();
|
||||||
|
this.removeStartPositionMovement = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function will only run the 2nd arg function after the time
|
||||||
|
// of the first arg have passed after its last execution.
|
||||||
|
private debouncedEndPositionMovementSave = debounce(
|
||||||
|
500, // ms.
|
||||||
|
(x: Position["x"], y: Position["y"]) => {
|
||||||
|
this.isMoving = false;
|
||||||
|
const endPosition = { x, y };
|
||||||
|
// Emit the movement event.
|
||||||
|
this.lineMovedEventManager.emit({
|
||||||
|
item: this,
|
||||||
|
endPosition,
|
||||||
|
startPosition: this.props.startPosition
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// This property will store the function
|
||||||
|
// to clean the movement listener.
|
||||||
|
private removeEndPositionMovement: Function | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End the movement funtionality for the end position.
|
||||||
|
* @param element Element to move inside its container.
|
||||||
|
*/
|
||||||
|
private initEndPositionMovementListener(
|
||||||
|
element: HTMLElement,
|
||||||
|
container: HTMLElement
|
||||||
|
): void {
|
||||||
|
this.removeEndPositionMovement = addMovementListener(
|
||||||
|
element,
|
||||||
|
(x: Position["x"], y: Position["y"]) => {
|
||||||
|
// Calculate the center of the circle.
|
||||||
|
x += this.circleRadius;
|
||||||
|
y += this.circleRadius;
|
||||||
|
|
||||||
|
this.isMoving = true;
|
||||||
|
this.props = {
|
||||||
|
...this.props,
|
||||||
|
endPosition: { x, y }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run the end function.
|
||||||
|
this.debouncedEndPositionMovementSave(x, y);
|
||||||
|
},
|
||||||
|
container
|
||||||
|
);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Stop the movement function.
|
||||||
|
*/
|
||||||
|
private stopEndPositionMovementListener(): void {
|
||||||
|
if (this.removeEndPositionMovement) {
|
||||||
|
this.removeEndPositionMovement();
|
||||||
|
this.removeEndPositionMovement = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
public constructor(props: NetworkLinkProps, meta: ItemMeta) {
|
||||||
|
/*
|
||||||
|
* We need to override the constructor cause we need to obtain the
|
||||||
|
* box size and position from the start and finish points of the line.
|
||||||
|
*/
|
||||||
|
super(
|
||||||
|
{
|
||||||
|
...props,
|
||||||
|
...NetworkLink.extractBoxSizeAndPosition(
|
||||||
|
props.startPosition,
|
||||||
|
props.endPosition
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...meta
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
this.moveMode = meta.editMode;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classic and protected version of the setter of the `props` property.
|
||||||
|
* Useful to override it from children classes.
|
||||||
|
* @param newProps
|
||||||
|
* @override Item.setProps
|
||||||
|
*/
|
||||||
|
public setProps(newProps: NetworkLinkProps) {
|
||||||
|
super.setProps({
|
||||||
|
...newProps,
|
||||||
|
...NetworkLink.extractBoxSizeAndPosition(
|
||||||
|
newProps.startPosition,
|
||||||
|
newProps.endPosition
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classic and protected version of the setter of the `meta` property.
|
||||||
|
* Useful to override it from children classes.
|
||||||
|
* @param newMetadata
|
||||||
|
* @override Item.setMeta
|
||||||
|
*/
|
||||||
|
public setMeta(newMetadata: ItemMeta) {
|
||||||
|
this.moveMode = newMetadata.editMode;
|
||||||
|
super.setMeta({
|
||||||
|
...newMetadata,
|
||||||
|
lineMode: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* To create the item's DOM representation.
|
||||||
|
* @return Item.
|
||||||
|
*/
|
||||||
|
protected createDomElement(): HTMLElement {
|
||||||
|
const element: HTMLDivElement = document.createElement("div");
|
||||||
|
element.className = "line";
|
||||||
|
|
||||||
|
const {
|
||||||
|
x, // Box x
|
||||||
|
y, // Box y
|
||||||
|
width, // Box width
|
||||||
|
height, // Box height
|
||||||
|
lineWidth, // NetworkLink thickness
|
||||||
|
startPosition, // NetworkLink start position
|
||||||
|
endPosition, // NetworkLink end position
|
||||||
|
color // NetworkLink color
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
const x1 = startPosition.x - x + lineWidth / 2;
|
||||||
|
const y1 = startPosition.y - y + lineWidth / 2;
|
||||||
|
const x2 = endPosition.x - x + lineWidth / 2;
|
||||||
|
const y2 = endPosition.y - y + lineWidth / 2;
|
||||||
|
|
||||||
|
// SVG container.
|
||||||
|
const svg = document.createElementNS(svgNS, "svg");
|
||||||
|
// Set SVG size.
|
||||||
|
svg.setAttribute("width", `${width + lineWidth}`);
|
||||||
|
svg.setAttribute("height", `${height + lineWidth}`);
|
||||||
|
const line = document.createElementNS(svgNS, "line");
|
||||||
|
line.setAttribute("x1", `${x1}`);
|
||||||
|
line.setAttribute("y1", `${y1}`);
|
||||||
|
line.setAttribute("x2", `${x2}`);
|
||||||
|
line.setAttribute("y2", `${y2}`);
|
||||||
|
line.setAttribute("stroke", color || "black");
|
||||||
|
line.setAttribute("stroke-width", `${lineWidth}`);
|
||||||
|
|
||||||
|
svg.append(line);
|
||||||
|
element.append(svg);
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updateDomElement(element: HTMLElement): void {
|
||||||
|
const {
|
||||||
|
x, // Box x
|
||||||
|
y, // Box y
|
||||||
|
width, // Box width
|
||||||
|
height, // Box height
|
||||||
|
lineWidth, // NetworkLink thickness
|
||||||
|
startPosition, // NetworkLink start position
|
||||||
|
endPosition, // NetworkLink end position
|
||||||
|
color // NetworkLink color
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
const x1 = startPosition.x - x + lineWidth / 2;
|
||||||
|
const y1 = startPosition.y - y + lineWidth / 2;
|
||||||
|
const x2 = endPosition.x - x + lineWidth / 2;
|
||||||
|
const y2 = endPosition.y - y + lineWidth / 2;
|
||||||
|
|
||||||
|
const svgs = element.getElementsByTagName("svg");
|
||||||
|
|
||||||
|
if (svgs.length > 0) {
|
||||||
|
const svg = svgs.item(0);
|
||||||
|
|
||||||
|
if (svg != null) {
|
||||||
|
// Set SVG size.
|
||||||
|
svg.setAttribute("width", `${width + lineWidth}`);
|
||||||
|
svg.setAttribute("height", `${height + lineWidth}`);
|
||||||
|
|
||||||
|
const lines = svg.getElementsByTagNameNS(svgNS, "line");
|
||||||
|
|
||||||
|
if (lines.length > 0) {
|
||||||
|
const line = lines.item(0);
|
||||||
|
|
||||||
|
if (line != null) {
|
||||||
|
line.setAttribute("x1", `${x1}`);
|
||||||
|
line.setAttribute("y1", `${y1}`);
|
||||||
|
line.setAttribute("x2", `${x2}`);
|
||||||
|
line.setAttribute("y2", `${y2}`);
|
||||||
|
line.setAttribute("stroke", color || "black");
|
||||||
|
line.setAttribute("stroke-width", `${lineWidth}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.moveMode) {
|
||||||
|
const startIsLeft = startPosition.x - endPosition.x <= 0;
|
||||||
|
const startIsTop = startPosition.y - endPosition.y <= 0;
|
||||||
|
|
||||||
|
let startCircle: HTMLElement = document.createElement("div");
|
||||||
|
let endCircle: HTMLElement = document.createElement("div");
|
||||||
|
|
||||||
|
if (this.isMoving) {
|
||||||
|
const circlesStart = element.getElementsByClassName(
|
||||||
|
"visual-console-item-line-circle-start"
|
||||||
|
);
|
||||||
|
if (circlesStart.length > 0) {
|
||||||
|
const circle = circlesStart.item(0) as HTMLElement;
|
||||||
|
if (circle) startCircle = circle;
|
||||||
|
}
|
||||||
|
const circlesEnd = element.getElementsByClassName(
|
||||||
|
"visual-console-item-line-circle-end"
|
||||||
|
);
|
||||||
|
if (circlesEnd.length > 0) {
|
||||||
|
const circle = circlesEnd.item(0) as HTMLElement;
|
||||||
|
if (circle) endCircle = circle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
startCircle.classList.add(
|
||||||
|
"visual-console-item-line-circle",
|
||||||
|
"visual-console-item-line-circle-start"
|
||||||
|
);
|
||||||
|
startCircle.style.width = `${this.circleRadius * 2}px`;
|
||||||
|
startCircle.style.height = `${this.circleRadius * 2}px`;
|
||||||
|
startCircle.style.borderRadius = "50%";
|
||||||
|
startCircle.style.backgroundColor = `${color}`;
|
||||||
|
startCircle.style.position = "absolute";
|
||||||
|
startCircle.style.left = startIsLeft
|
||||||
|
? `-${this.circleRadius}px`
|
||||||
|
: `${width + lineWidth - this.circleRadius}px`;
|
||||||
|
startCircle.style.top = startIsTop
|
||||||
|
? `-${this.circleRadius}px`
|
||||||
|
: `${height + lineWidth - this.circleRadius}px`;
|
||||||
|
|
||||||
|
endCircle.classList.add(
|
||||||
|
"visual-console-item-line-circle",
|
||||||
|
"visual-console-item-line-circle-end"
|
||||||
|
);
|
||||||
|
endCircle.style.width = `${this.circleRadius * 2}px`;
|
||||||
|
endCircle.style.height = `${this.circleRadius * 2}px`;
|
||||||
|
endCircle.style.borderRadius = "50%";
|
||||||
|
endCircle.style.backgroundColor = `${color}`;
|
||||||
|
endCircle.style.position = "absolute";
|
||||||
|
endCircle.style.left = startIsLeft
|
||||||
|
? `${width + lineWidth - 8}px`
|
||||||
|
: `-${this.circleRadius}px`;
|
||||||
|
endCircle.style.top = startIsTop
|
||||||
|
? `${height + lineWidth - this.circleRadius}px`
|
||||||
|
: `-${this.circleRadius}px`;
|
||||||
|
|
||||||
|
if (element.parentElement !== null) {
|
||||||
|
const circles = element.parentElement.getElementsByClassName(
|
||||||
|
"visual-console-item-line-circle"
|
||||||
|
);
|
||||||
|
while (circles.length > 0) {
|
||||||
|
const circle = circles.item(0);
|
||||||
|
if (circle) circle.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
element.parentElement.appendChild(startCircle);
|
||||||
|
element.parentElement.appendChild(endCircle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init the movement listeners.
|
||||||
|
this.initStartPositionMovementListener(startCircle, this.elementRef
|
||||||
|
.parentElement as HTMLElement);
|
||||||
|
this.initEndPositionMovementListener(endCircle, this.elementRef
|
||||||
|
.parentElement as HTMLElement);
|
||||||
|
} else if (!this.moveMode) {
|
||||||
|
this.stopStartPositionMovementListener();
|
||||||
|
// Remove circles.
|
||||||
|
if (element.parentElement !== null) {
|
||||||
|
const circles = element.parentElement.getElementsByClassName(
|
||||||
|
"visual-console-item-line-circle"
|
||||||
|
);
|
||||||
|
|
||||||
|
while (circles.length > 0) {
|
||||||
|
const circle = circles.item(0);
|
||||||
|
if (circle) circle.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.stopStartPositionMovementListener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the size and position of the box from
|
||||||
|
* the start and the finish of the line.
|
||||||
|
* @param props Item properties.
|
||||||
|
*/
|
||||||
|
public static extractBoxSizeAndPosition(
|
||||||
|
startPosition: Position,
|
||||||
|
endPosition: Position
|
||||||
|
): Size & Position {
|
||||||
|
return {
|
||||||
|
width: Math.abs(startPosition.x - endPosition.x),
|
||||||
|
height: Math.abs(startPosition.y - endPosition.y),
|
||||||
|
x: Math.min(startPosition.x, endPosition.x),
|
||||||
|
y: Math.min(startPosition.y, endPosition.y)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the position into the properties and move the DOM container.
|
||||||
|
* @param x Horizontal axis position.
|
||||||
|
* @param y Vertical axis position.
|
||||||
|
* @override item function
|
||||||
|
*/
|
||||||
|
public move(x: number, y: number): void {
|
||||||
|
super.moveElement(x, y);
|
||||||
|
const startIsLeft =
|
||||||
|
this.props.startPosition.x - this.props.endPosition.x <= 0;
|
||||||
|
const startIsTop =
|
||||||
|
this.props.startPosition.y - this.props.endPosition.y <= 0;
|
||||||
|
|
||||||
|
const start = {
|
||||||
|
x: startIsLeft ? x : this.props.width + x,
|
||||||
|
y: startIsTop ? y : this.props.height + y
|
||||||
|
};
|
||||||
|
|
||||||
|
const end = {
|
||||||
|
x: startIsLeft ? this.props.width + x : x,
|
||||||
|
y: startIsTop ? this.props.height + y : y
|
||||||
|
};
|
||||||
|
|
||||||
|
this.props = {
|
||||||
|
...this.props,
|
||||||
|
startPosition: start,
|
||||||
|
endPosition: end
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To remove the event listeners and the elements from the DOM.
|
||||||
|
* @override Item.remove
|
||||||
|
*/
|
||||||
|
public remove(): void {
|
||||||
|
// Clear the item's event listeners.
|
||||||
|
this.stopStartPositionMovementListener();
|
||||||
|
// Call the parent's .remove()
|
||||||
|
super.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To add an event handler to the movement of visual console elements.
|
||||||
|
* @param listener Function which is going to be executed when a linked console is moved.
|
||||||
|
*
|
||||||
|
* @override Item.onMoved
|
||||||
|
*/
|
||||||
|
public onNetworkLinkMovementFinished(
|
||||||
|
listener: Listener<NetworkLinkMovedEvent>
|
||||||
|
): Disposable {
|
||||||
|
/*
|
||||||
|
* The '.on' function returns a function which will clean the event
|
||||||
|
* listener when executed. We store all the 'dispose' functions to
|
||||||
|
* call them when the item should be cleared.
|
||||||
|
*/
|
||||||
|
const disposable = this.lineMovedEventManager.on(listener);
|
||||||
|
this.lineMovedEventDisposables.push(disposable);
|
||||||
|
|
||||||
|
return disposable;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue