mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
Custom Maps: geo map and color backgrounds (#16020)
* Custom Maps: geo map and color background tabs blade component geo-map blade component and related script enhancements * Update css/js * style fixes * update db_schema.yaml * fix db_schema hand edit * ignore phpstan being wrong * Handle null * another possible null spot * Use standard file cache for custom map background images * Create map->image as jpeg so we can compress it * whitespace fix * Fix background cancel button when other type is selected than the saved type * Save and restore layer * Map must exist before creating static image * Don't show set as image button for Google and Bing. Bing gives an odd error, but Google won't work.
This commit is contained in:
@@ -11,15 +11,15 @@ class LocationController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$maps_api = Config::get('geoloc.api_key');
|
||||
$maps_config = ['tile_url' => Config::get('leaflet.tile_url', '{s}.tile.openstreetmap.org')];
|
||||
$data = [
|
||||
'maps_api' => $maps_api,
|
||||
'maps_engine' => $maps_api ? Config::get('geoloc.engine') : '',
|
||||
'maps_config' => $maps_config,
|
||||
'maps_config' => [
|
||||
'engine' => Config::get('geoloc.engine'),
|
||||
'api_key' => Config::get('geoloc.api_key'),
|
||||
'tile_url' => Config::get('leaflet.tile_url', '{s}.tile.openstreetmap.org'),
|
||||
],
|
||||
'graph_template' => '',
|
||||
];
|
||||
|
||||
$data['graph_template'] = '';
|
||||
Config::set('enable_lazy_load', false);
|
||||
$graph_array = [
|
||||
'type' => 'location_bits',
|
||||
|
@@ -29,7 +29,7 @@ use App\Http\Controllers\Controller;
|
||||
use App\Models\CustomMap;
|
||||
use App\Models\CustomMapBackground;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class CustomMapBackgroundController extends Controller
|
||||
{
|
||||
@@ -37,58 +37,89 @@ class CustomMapBackgroundController extends Controller
|
||||
{
|
||||
$this->authorize('view', $map);
|
||||
|
||||
$background = $this->checkImageCache($map);
|
||||
if ($background) {
|
||||
$path = Storage::disk('base')->path('html/images/custommap/background/' . $background);
|
||||
|
||||
return response()->file($path, [
|
||||
'Content-Type' => Storage::mimeType($background),
|
||||
]);
|
||||
if ($map->background_type !== 'image') {
|
||||
abort(404);
|
||||
}
|
||||
abort(404);
|
||||
|
||||
// explicitly use file cache
|
||||
try {
|
||||
$imageContent = Cache::driver('file')
|
||||
->remember($this->getCacheKey($map), new \DateInterval('P30D'), fn () => $map->background->background_image);
|
||||
} catch (\ErrorException $e) {
|
||||
// if cache fails, just load from database :(
|
||||
$imageContent = $map->background->background_image;
|
||||
}
|
||||
|
||||
if (empty($imageContent)) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
return response($imageContent, headers: [
|
||||
'Content-Type' => $map->background_data['mime'] ?? getimagesizefromstring($imageContent)['mime'] ?? 'image/jpeg',
|
||||
]);
|
||||
}
|
||||
|
||||
public function save(FormRequest $request, CustomMap $map)
|
||||
{
|
||||
$this->authorize('update', $map);
|
||||
$this->validate($request, [
|
||||
'type' => 'in:image,color,map,none',
|
||||
'image' => 'required_if:type,image|mimes:png,jpg,svg,gif',
|
||||
'color' => 'required_if:type,color|regex:/^#[0-9a-f]{6,8}$/',
|
||||
'lat' => 'required_if:type,map|numeric|between:-90,90',
|
||||
'lng' => 'required_if:type,map|numeric|between:-180,180',
|
||||
'zoom' => 'required_if:type,map|integer|between:0,19',
|
||||
'layer' => 'string|regex:/^[a-zA-Z]*$/',
|
||||
]);
|
||||
|
||||
if ($request->bgimage) {
|
||||
$map->background_suffix = $request->bgimage->extension();
|
||||
if (! $map->background) {
|
||||
$background = new CustomMapBackground;
|
||||
$background->background_image = $request->bgimage->getContent();
|
||||
$map->background()->save($background);
|
||||
} else {
|
||||
$map->background->background_image = $request->bgimage->getContent();
|
||||
$map->background->save();
|
||||
}
|
||||
$map->background_version++;
|
||||
$map->save();
|
||||
} elseif ($request->bgclear) {
|
||||
if ($map->background) {
|
||||
$map->background->delete();
|
||||
}
|
||||
$map->background_suffix = null;
|
||||
$map->save();
|
||||
}
|
||||
$map->background_type = $request->type;
|
||||
$this->updateBackgroundImage($map, $request);
|
||||
$map->background_data = array_merge($map->background_data ?? [], $request->only([
|
||||
'color',
|
||||
'lat',
|
||||
'lng',
|
||||
'zoom',
|
||||
'layer',
|
||||
]));
|
||||
|
||||
$map->save();
|
||||
|
||||
return response()->json([
|
||||
'bgimage' => $map->background_suffix ? true : false,
|
||||
'bgversion' => $map->background_version,
|
||||
'bgtype' => $map->background_type,
|
||||
'bgdata' => $map->getBackgroundConfig(),
|
||||
]);
|
||||
}
|
||||
|
||||
private function checkImageCache(CustomMap $map): ?string
|
||||
private function updateBackgroundImage(CustomMap $map, FormRequest $request): void
|
||||
{
|
||||
if (! $map->background_suffix) {
|
||||
return null;
|
||||
if ($map->background_type == 'image') {
|
||||
if ($request->image) {
|
||||
// if image type and we have image data (new image) save it
|
||||
$background = $map->background ?? new CustomMapBackground;
|
||||
$background->background_image = $request->image->getContent();
|
||||
$map->background()->save($background);
|
||||
Cache::driver('file')->forget($this->getCacheKey($map)); // clear old image cache if present
|
||||
$map->background_data = array_merge($map->background_data ?? [], [
|
||||
'version' => md5($background->background_image),
|
||||
'original_filename' => $request->image->getClientOriginalName(),
|
||||
'mime' => $request->image->getMimeType(),
|
||||
]);
|
||||
}
|
||||
} elseif ($map->getOriginal('background_type') == 'image') {
|
||||
// if no longer image, clean up. if there are multiple web servers, it will only clear from the local.
|
||||
Cache::driver('file')->forget($this->getCacheKey($map));
|
||||
$map->background()->delete();
|
||||
// remove image keys from background data
|
||||
$map->background_data = array_diff_key($map->background_data ?? [], [
|
||||
'version' => 1,
|
||||
'original_filename' => 1,
|
||||
'mime' => 1,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$imageName = $map->custom_map_id . '_' . $map->background_version . '.' . $map->background_suffix;
|
||||
if (Storage::disk('base')->missing('html/images/custommap/background/' . $imageName)) {
|
||||
Storage::disk('base')->put('html/images/custommap/background/' . $imageName, $map->background->background_image);
|
||||
}
|
||||
|
||||
return $imageName;
|
||||
private function getCacheKey(CustomMap $map): string
|
||||
{
|
||||
return 'custommap_background_' . $map->custom_map_id . ':' . ($map->background_data['version'] ?? '');
|
||||
}
|
||||
}
|
||||
|
@@ -59,7 +59,7 @@ class CustomMapController extends Controller
|
||||
'hide_overspeed' => 0,
|
||||
'font_size' => 14,
|
||||
],
|
||||
'background' => null,
|
||||
'background_type' => null,
|
||||
'map_conf' => [
|
||||
'height' => '800px',
|
||||
'width' => '1800px',
|
||||
@@ -98,15 +98,16 @@ class CustomMapController extends Controller
|
||||
$map_conf = $map->options;
|
||||
$map_conf['width'] = $map->width;
|
||||
$map_conf['height'] = $map->height;
|
||||
$data = [
|
||||
|
||||
return view('map.custom-view', [
|
||||
'edit' => false,
|
||||
'map_id' => $map->custom_map_id,
|
||||
'name' => $map->name,
|
||||
'menu_group' => $map->menu_group,
|
||||
'reverse_arrows' => $map->reverse_arrows,
|
||||
'legend' => $this->legendConfig($map),
|
||||
'background' => (bool) $map->background_suffix,
|
||||
'bgversion' => $map->background_version,
|
||||
'background_type' => $map->background_type,
|
||||
'background_config' => $map->getBackgroundConfig(),
|
||||
'page_refresh' => Config::get('page_refresh', 300),
|
||||
'map_conf' => $map_conf,
|
||||
'base_url' => Config::get('base_url'),
|
||||
@@ -115,9 +116,7 @@ class CustomMapController extends Controller
|
||||
'vmargin' => 20,
|
||||
'hmargin' => 20,
|
||||
'screenshot' => $screenshot,
|
||||
];
|
||||
|
||||
return view('map.custom-view', $data);
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(CustomMap $map): View
|
||||
@@ -133,8 +132,8 @@ class CustomMapController extends Controller
|
||||
'newedge_conf' => $map->newedgeconfig,
|
||||
'newnode_conf' => $map->newnodeconfig,
|
||||
'map_conf' => $map->options,
|
||||
'background' => (bool) $map->background_suffix,
|
||||
'bgversion' => $map->background_version,
|
||||
'background_type' => $map->background_type,
|
||||
'background_config' => $map->getBackgroundConfig(),
|
||||
'edit' => true,
|
||||
'vmargin' => 20,
|
||||
'hmargin' => 20,
|
||||
|
@@ -38,6 +38,7 @@ class CustomMap extends BaseModel
|
||||
'options' => 'array',
|
||||
'newnodeconfig' => 'array',
|
||||
'newedgeconfig' => 'array',
|
||||
'background_data' => 'array',
|
||||
];
|
||||
protected $fillable = [
|
||||
'name',
|
||||
@@ -53,8 +54,8 @@ class CustomMap extends BaseModel
|
||||
'legend_font_size',
|
||||
'legend_hide_invalid',
|
||||
'legend_hide_overspeed',
|
||||
'background_suffix',
|
||||
'background_version',
|
||||
'background_type',
|
||||
'background_data',
|
||||
];
|
||||
|
||||
// default values for attributes
|
||||
@@ -62,9 +63,23 @@ class CustomMap extends BaseModel
|
||||
'options' => '{"interaction":{"dragNodes":false,"dragView":false,"zoomView":false},"manipulation":{"enabled":false},"physics":{"enabled":false}}',
|
||||
'newnodeconfig' => '{"borderWidth":1,"color":{"border":"#2B7CE9","background":"#D2E5FF"},"font":{"color":"#343434","size":14,"face":"arial"},"icon":[],"label":true,"shape":"box","size":25}',
|
||||
'newedgeconfig' => '{"arrows":{"to":{"enabled":true}},"smooth":{"type":"dynamic"},"font":{"color":"#343434","size":12,"face":"arial"},"label":true}',
|
||||
'background_version' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
* Get background data intended to be passed to javascript to configure the background
|
||||
*/
|
||||
public function getBackgroundConfig(): array
|
||||
{
|
||||
$config = $this->background_data ?? [];
|
||||
$config['engine'] = \LibreNMS\Config::get('geoloc.engine');
|
||||
$config['api_key'] = \LibreNMS\Config::get('geoloc.api_key');
|
||||
$config['tile_url'] = \LibreNMS\Config::get('leaflet.tile_url');
|
||||
/* @phpstan-ignore-next-line seems to think version is not in array 100% of the time... which is wrong */
|
||||
$config['image_url'] = route('maps.custom.background', ['map' => $this->custom_map_id]) . '?version=' . ($config['version'] ?? 0);
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function hasAccess(): bool
|
||||
{
|
||||
return false; // TODO calculate based on device access
|
||||
|
@@ -31,6 +31,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
class CustomMapBackground extends BaseModel
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $primaryKey = 'custom_map_background_id';
|
||||
|
||||
public function map(): BelongsTo
|
||||
|
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
// check for existence if migration fails
|
||||
if (! Schema::hasColumn('custom_maps', 'background_data')) {
|
||||
Schema::table('custom_maps', function (Blueprint $table) {
|
||||
$table->string('background_type', 16)->default('none');
|
||||
$table->text('background_data')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
// migrate data
|
||||
DB::table('custom_maps')->select(['custom_map_id', 'background_suffix', 'background_version'])->get()->map(function ($map) {
|
||||
if ($map->background_suffix) {
|
||||
DB::table('custom_maps')->where('custom_map_id', $map->custom_map_id)->update([
|
||||
'background_type' => 'image',
|
||||
'background_data' => json_encode([
|
||||
'suffix' => $map->background_suffix,
|
||||
'version' => $map->background_version,
|
||||
]),
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
// migrate data
|
||||
DB::table('custom_maps')->select(['custom_map_id', 'background_type', 'background_data'])->get()->map(function ($map) {
|
||||
if ($map->background_type == 'image' && $map->background_data) {
|
||||
$data = json_decode($map->background_data, true);
|
||||
DB::table('custom_maps')->where('custom_map_id', $map->custom_map_id)->update([
|
||||
'background_suffix' => $data['suffix'],
|
||||
'background_version' => $data['version'],
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
Schema::table('custom_maps', function (Blueprint $table) {
|
||||
$table->dropColumn(['background_type', 'background_data']);
|
||||
});
|
||||
}
|
||||
};
|
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('custom_maps', function (Blueprint $table) {
|
||||
$table->dropColumn(['background_suffix', 'background_version']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('custom_maps', function (Blueprint $table) {
|
||||
$table->string('background_suffix', 10)->nullable()->after('legend_hide_overspeed');
|
||||
$table->integer('background_version')->unsigned()->after('background_suffix');
|
||||
});
|
||||
}
|
||||
};
|
3
html/css/L.Control.Locate.min.css
vendored
3
html/css/L.Control.Locate.min.css
vendored
@@ -1,2 +1 @@
|
||||
.leaflet-control-locate a{font-size:1.4em;color:#444;cursor:pointer}.leaflet-control-locate.active a{color:#2074B6}.leaflet-control-locate.active.following a{color:#FC8428}.leafet-control-locate-location circle{animation:leaflet-control-locate-throb 4s ease infinite}@keyframes leaflet-control-locate-throb{0%{r:9;stroke-width:1}50%{r:7;stroke-width:3}100%{r:9;stroke-width:1}}
|
||||
/*# sourceMappingURL=L.Control.Locate.min.css.map */
|
||||
.leaflet-control-locate a{cursor:pointer}.leaflet-control-locate a .leaflet-control-locate-location-arrow{display:inline-block;width:16px;height:16px;margin:7px;background-image:url('data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="black" d="M445 4 29 195c-48 23-32 93 19 93h176v176c0 51 70 67 93 19L508 67c16-38-25-79-63-63z"/></svg>')}.leaflet-control-locate a .leaflet-control-locate-spinner{display:inline-block;width:16px;height:16px;margin:7px;background-image:url('data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="black" d="M304 48a48 48 0 1 1-96 0 48 48 0 0 1 96 0zm-48 368a48 48 0 1 0 0 96 48 48 0 0 0 0-96zm208-208a48 48 0 1 0 0 96 48 48 0 0 0 0-96zM96 256a48 48 0 1 0-96 0 48 48 0 0 0 96 0zm13 99a48 48 0 1 0 0 96 48 48 0 0 0 0-96zm294 0a48 48 0 1 0 0 96 48 48 0 0 0 0-96zM109 61a48 48 0 1 0 0 96 48 48 0 0 0 0-96z"/></svg>');animation:leaflet-control-locate-spin 2s linear infinite}.leaflet-control-locate.active a .leaflet-control-locate-location-arrow{background-image:url('data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="rgb(32, 116, 182)" d="M445 4 29 195c-48 23-32 93 19 93h176v176c0 51 70 67 93 19L508 67c16-38-25-79-63-63z"/></svg>')}.leaflet-control-locate.following a .leaflet-control-locate-location-arrow{background-image:url('data:image/svg+xml;charset=UTF-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="rgb(252, 132, 40)" d="M445 4 29 195c-48 23-32 93 19 93h176v176c0 51 70 67 93 19L508 67c16-38-25-79-63-63z"/></svg>')}.leaflet-touch .leaflet-bar .leaflet-locate-text-active{width:100%;max-width:200px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;padding:0 10px}.leaflet-touch .leaflet-bar .leaflet-locate-text-active .leaflet-locate-icon{padding:0 5px 0 0}.leaflet-control-locate-location circle{animation:leaflet-control-locate-throb 4s ease infinite}@keyframes leaflet-control-locate-throb{0%{stroke-width:1}50%{stroke-width:3;transform:scale(0.8, 0.8)}100%{stroke-width:1}}@keyframes leaflet-control-locate-spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}/*# sourceMappingURL=L.Control.Locate.min.css.map */
|
||||
|
@@ -1,7 +1 @@
|
||||
{
|
||||
"version": 3,
|
||||
"mappings": "AAEE,yBAAE,CACA,SAAS,CAAE,KAAK,CAChB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,OAAO,CAGf,gCAAE,CACA,KAAK,CAAE,OAAO,CAEhB,0CAAc,CACZ,KAAK,CAAE,OAAO,CAKpB,sCAAuC,CACrC,SAAS,CAAE,6CAA6C,CAG1D,uCAIC,CAHG,EAAG,CAAE,CAAC,CAAE,CAAC,CAAE,YAAY,CAAE,CAAC,CAC3B,GAAI,CAAE,CAAC,CAAE,CAAC,CAAE,YAAY,CAAE,CAAC,CAC5B,IAAK,CAAE,CAAC,CAAE,CAAC,CAAE,YAAY,CAAE,CAAC",
|
||||
"sources": ["../src/L.Control.Locate.scss"],
|
||||
"names": [],
|
||||
"file": "L.Control.Locate.min.css"
|
||||
}
|
||||
{"version":3,"sourceRoot":"","sources":["../src/L.Control.Locate.scss"],"names":[],"mappings":"AASE,0BACE,eAEA,iEACE,qBACA,WACA,YACA,WACA,0OAGF,0DACE,qBACA,WACA,YACA,WACA,6bACA,yDAIJ,wEACE,sPAGF,2EACE,sPAIJ,wDACE,WACA,gBACA,uBACA,mBACA,gBACA,eAEA,6EACE,kBAIJ,wCACE,wDAGF,wCACE,GACE,eAGF,IACE,eACA,0BAGF,KACE,gBAIJ,uCACE,GACE,uBAGF,KACE","file":"L.Control.Locate.min.css"}
|
File diff suppressed because one or more lines are too long
@@ -25,6 +25,10 @@
|
||||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
/* Prevents IE11 from highlighting tiles in blue */
|
||||
.leaflet-tile::selection {
|
||||
background: transparent;
|
||||
}
|
||||
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
|
||||
.leaflet-safari .leaflet-tile {
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
@@ -41,7 +45,10 @@
|
||||
}
|
||||
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
|
||||
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
|
||||
.leaflet-container .leaflet-overlay-pane svg,
|
||||
.leaflet-container .leaflet-overlay-pane svg {
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
}
|
||||
.leaflet-container .leaflet-marker-pane img,
|
||||
.leaflet-container .leaflet-shadow-pane img,
|
||||
.leaflet-container .leaflet-tile-pane img,
|
||||
@@ -49,8 +56,15 @@
|
||||
.leaflet-container .leaflet-tile {
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
width: auto;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.leaflet-container img.leaflet-tile {
|
||||
/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */
|
||||
mix-blend-mode: plus-lighter;
|
||||
}
|
||||
|
||||
.leaflet-container.leaflet-touch-zoom {
|
||||
-ms-touch-action: pan-x pan-y;
|
||||
touch-action: pan-x pan-y;
|
||||
@@ -162,9 +176,6 @@
|
||||
|
||||
/* zoom and fade animations */
|
||||
|
||||
.leaflet-fade-anim .leaflet-tile {
|
||||
will-change: opacity;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-popup {
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
@@ -179,9 +190,10 @@
|
||||
-ms-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
svg.leaflet-zoom-animated {
|
||||
will-change: transform;
|
||||
}
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
@@ -237,7 +249,8 @@
|
||||
|
||||
.leaflet-marker-icon.leaflet-interactive,
|
||||
.leaflet-image-layer.leaflet-interactive,
|
||||
.leaflet-pane > svg path.leaflet-interactive {
|
||||
.leaflet-pane > svg path.leaflet-interactive,
|
||||
svg.leaflet-image-layer.leaflet-interactive path {
|
||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
||||
pointer-events: auto;
|
||||
}
|
||||
@@ -246,14 +259,11 @@
|
||||
|
||||
.leaflet-container {
|
||||
background: #ddd;
|
||||
outline: 0;
|
||||
outline-offset: 1px;
|
||||
}
|
||||
.leaflet-container a {
|
||||
color: #0078A8;
|
||||
}
|
||||
.leaflet-container a.leaflet-active {
|
||||
outline: 2px solid orange;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
border: 2px dotted #38f;
|
||||
background: rgba(255,255,255,0.5);
|
||||
@@ -262,7 +272,10 @@
|
||||
|
||||
/* general typography */
|
||||
.leaflet-container {
|
||||
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
|
||||
@@ -272,8 +285,7 @@
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-bar a:hover {
|
||||
.leaflet-bar a {
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ccc;
|
||||
width: 26px;
|
||||
@@ -290,7 +302,8 @@
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
}
|
||||
.leaflet-bar a:hover {
|
||||
.leaflet-bar a:hover,
|
||||
.leaflet-bar a:focus {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.leaflet-bar a:first-child {
|
||||
@@ -380,6 +393,8 @@
|
||||
}
|
||||
.leaflet-control-layers label {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
font-size: 1.08333em;
|
||||
}
|
||||
.leaflet-control-layers-separator {
|
||||
height: 0;
|
||||
@@ -388,7 +403,7 @@
|
||||
}
|
||||
|
||||
/* Default icon URLs */
|
||||
.leaflet-default-icon-path {
|
||||
.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */
|
||||
background-image: url(images/marker-icon.png);
|
||||
}
|
||||
|
||||
@@ -397,23 +412,27 @@
|
||||
|
||||
.leaflet-container .leaflet-control-attribution {
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
margin: 0;
|
||||
}
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale-line {
|
||||
padding: 0 5px;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.leaflet-control-attribution a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.leaflet-control-attribution a:hover {
|
||||
.leaflet-control-attribution a:hover,
|
||||
.leaflet-control-attribution a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.leaflet-container .leaflet-control-attribution,
|
||||
.leaflet-container .leaflet-control-scale {
|
||||
font-size: 11px;
|
||||
.leaflet-attribution-flag {
|
||||
display: inline !important;
|
||||
vertical-align: baseline !important;
|
||||
width: 1em;
|
||||
height: 0.6669em;
|
||||
}
|
||||
.leaflet-left .leaflet-control-scale {
|
||||
margin-left: 5px;
|
||||
@@ -426,14 +445,11 @@
|
||||
border-top: none;
|
||||
line-height: 1.1;
|
||||
padding: 2px 5px 1px;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
text-shadow: 1px 1px #fff;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child) {
|
||||
border-top: 2px solid #777;
|
||||
@@ -469,17 +485,22 @@
|
||||
border-radius: 12px;
|
||||
}
|
||||
.leaflet-popup-content {
|
||||
margin: 13px 19px;
|
||||
line-height: 1.4;
|
||||
margin: 13px 24px 13px 20px;
|
||||
line-height: 1.3;
|
||||
font-size: 13px;
|
||||
font-size: 1.08333em;
|
||||
min-height: 1px;
|
||||
}
|
||||
.leaflet-popup-content p {
|
||||
margin: 18px 0;
|
||||
margin: 17px 0;
|
||||
margin: 1.3em 0;
|
||||
}
|
||||
.leaflet-popup-tip-container {
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-top: -1px;
|
||||
margin-left: -20px;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
@@ -490,6 +511,7 @@
|
||||
padding: 1px;
|
||||
|
||||
margin: -10px auto 0;
|
||||
pointer-events: auto;
|
||||
|
||||
-webkit-transform: rotate(45deg);
|
||||
-moz-transform: rotate(45deg);
|
||||
@@ -506,28 +528,25 @@
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 4px 4px 0 0;
|
||||
border: none;
|
||||
text-align: center;
|
||||
width: 18px;
|
||||
height: 14px;
|
||||
font: 16px/14px Tahoma, Verdana, sans-serif;
|
||||
color: #c3c3c3;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font: 16px/24px Tahoma, Verdana, sans-serif;
|
||||
color: #757575;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
background: transparent;
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button:hover {
|
||||
color: #999;
|
||||
.leaflet-container a.leaflet-popup-close-button:hover,
|
||||
.leaflet-container a.leaflet-popup-close-button:focus {
|
||||
color: #585858;
|
||||
}
|
||||
.leaflet-popup-scrolled {
|
||||
overflow: auto;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper {
|
||||
zoom: 1;
|
||||
-ms-zoom: 1;
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
width: 24px;
|
||||
@@ -536,9 +555,6 @@
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
|
||||
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip-container {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-control-zoom,
|
||||
.leaflet-oldie .leaflet-control-layers,
|
||||
@@ -573,7 +589,7 @@
|
||||
pointer-events: none;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-tooltip.leaflet-clickable {
|
||||
.leaflet-tooltip.leaflet-interactive {
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
}
|
||||
@@ -633,3 +649,13 @@
|
||||
margin-left: -12px;
|
||||
border-right-color: #fff;
|
||||
}
|
||||
|
||||
/* Printing */
|
||||
|
||||
@media print {
|
||||
/* Prevent printers from removing background-images of controls. */
|
||||
.leaflet-control {
|
||||
-webkit-print-color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
388
html/js/leaflet-image.js
Normal file
388
html/js/leaflet-image.js
Normal file
@@ -0,0 +1,388 @@
|
||||
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.leafletImage = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||||
/* global L */
|
||||
|
||||
var queue = require('d3-queue').queue;
|
||||
|
||||
var cacheBusterDate = +new Date();
|
||||
|
||||
// leaflet-image
|
||||
module.exports = function leafletImage(map, callback) {
|
||||
|
||||
var hasMapbox = !!L.mapbox;
|
||||
|
||||
var dimensions = map.getSize(),
|
||||
layerQueue = new queue(1);
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = dimensions.x;
|
||||
canvas.height = dimensions.y;
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
// dummy canvas image when loadTile get 404 error
|
||||
// and layer don't have errorTileUrl
|
||||
var dummycanvas = document.createElement('canvas');
|
||||
dummycanvas.width = 1;
|
||||
dummycanvas.height = 1;
|
||||
var dummyctx = dummycanvas.getContext('2d');
|
||||
dummyctx.fillStyle = 'rgba(0,0,0,0)';
|
||||
dummyctx.fillRect(0, 0, 1, 1);
|
||||
|
||||
// layers are drawn in the same order as they are composed in the DOM:
|
||||
// tiles, paths, and then markers
|
||||
map.eachLayer(drawTileLayer);
|
||||
map.eachLayer(drawEsriDynamicLayer);
|
||||
|
||||
if (map._pathRoot) {
|
||||
layerQueue.defer(handlePathRoot, map._pathRoot);
|
||||
} else if (map._panes) {
|
||||
var firstCanvas = map._panes.overlayPane.getElementsByTagName('canvas').item(0);
|
||||
if (firstCanvas) { layerQueue.defer(handlePathRoot, firstCanvas); }
|
||||
}
|
||||
map.eachLayer(drawMarkerLayer);
|
||||
layerQueue.awaitAll(layersDone);
|
||||
|
||||
function drawTileLayer(l) {
|
||||
if (l instanceof L.TileLayer) layerQueue.defer(handleTileLayer, l);
|
||||
else if (l._heat) layerQueue.defer(handlePathRoot, l._canvas);
|
||||
}
|
||||
|
||||
function drawMarkerLayer(l) {
|
||||
if (l instanceof L.Marker && l.options.icon instanceof L.Icon) {
|
||||
layerQueue.defer(handleMarkerLayer, l);
|
||||
}
|
||||
}
|
||||
|
||||
function drawEsriDynamicLayer(l) {
|
||||
if (!L.esri) return;
|
||||
|
||||
if (l instanceof L.esri.DynamicMapLayer) {
|
||||
layerQueue.defer(handleEsriDymamicLayer, l);
|
||||
}
|
||||
}
|
||||
|
||||
function done() {
|
||||
callback(null, canvas);
|
||||
}
|
||||
|
||||
function layersDone(err, layers) {
|
||||
if (err) throw err;
|
||||
layers.forEach(function (layer) {
|
||||
if (layer && layer.canvas) {
|
||||
ctx.drawImage(layer.canvas, 0, 0);
|
||||
}
|
||||
});
|
||||
done();
|
||||
}
|
||||
|
||||
function handleTileLayer(layer, callback) {
|
||||
// `L.TileLayer.Canvas` was removed in leaflet 1.0
|
||||
var isCanvasLayer = (L.TileLayer.Canvas && layer instanceof L.TileLayer.Canvas),
|
||||
canvas = document.createElement('canvas');
|
||||
|
||||
canvas.width = dimensions.x;
|
||||
canvas.height = dimensions.y;
|
||||
|
||||
var ctx = canvas.getContext('2d'),
|
||||
bounds = map.getPixelBounds(),
|
||||
zoom = map.getZoom(),
|
||||
tileSize = layer.options.tileSize;
|
||||
|
||||
if (zoom > layer.options.maxZoom ||
|
||||
zoom < layer.options.minZoom ||
|
||||
// mapbox.tileLayer
|
||||
(hasMapbox &&
|
||||
layer instanceof L.mapbox.tileLayer && !layer.options.tiles)) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
var tileBounds = L.bounds(
|
||||
bounds.min.divideBy(tileSize)._floor(),
|
||||
bounds.max.divideBy(tileSize)._floor()),
|
||||
tiles = [],
|
||||
j, i,
|
||||
tileQueue = new queue(1);
|
||||
|
||||
for (j = tileBounds.min.y; j <= tileBounds.max.y; j++) {
|
||||
for (i = tileBounds.min.x; i <= tileBounds.max.x; i++) {
|
||||
tiles.push(new L.Point(i, j));
|
||||
}
|
||||
}
|
||||
|
||||
tiles.forEach(function (tilePoint) {
|
||||
var originalTilePoint = tilePoint.clone();
|
||||
|
||||
if (layer._adjustTilePoint) {
|
||||
layer._adjustTilePoint(tilePoint);
|
||||
}
|
||||
|
||||
var tilePos = originalTilePoint
|
||||
.scaleBy(new L.Point(tileSize, tileSize))
|
||||
.subtract(bounds.min);
|
||||
|
||||
if (tilePoint.y >= 0) {
|
||||
if (isCanvasLayer) {
|
||||
var tile = layer._tiles[tilePoint.x + ':' + tilePoint.y];
|
||||
tileQueue.defer(canvasTile, tile, tilePos, tileSize);
|
||||
} else {
|
||||
var url = addCacheString(layer.getTileUrl(tilePoint));
|
||||
tileQueue.defer(loadTile, url, tilePos, tileSize);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tileQueue.awaitAll(tileQueueFinish);
|
||||
|
||||
function canvasTile(tile, tilePos, tileSize, callback) {
|
||||
callback(null, {
|
||||
img: tile,
|
||||
pos: tilePos,
|
||||
size: tileSize
|
||||
});
|
||||
}
|
||||
|
||||
function loadTile(url, tilePos, tileSize, callback) {
|
||||
var im = new Image();
|
||||
im.crossOrigin = '';
|
||||
im.onload = function () {
|
||||
callback(null, {
|
||||
img: this,
|
||||
pos: tilePos,
|
||||
size: tileSize
|
||||
});
|
||||
};
|
||||
im.onerror = function (e) {
|
||||
// use canvas instead of errorTileUrl if errorTileUrl get 404
|
||||
if (layer.options.errorTileUrl != '' && e.target.errorCheck === undefined) {
|
||||
e.target.errorCheck = true;
|
||||
e.target.src = layer.options.errorTileUrl;
|
||||
} else {
|
||||
callback(null, {
|
||||
img: dummycanvas,
|
||||
pos: tilePos,
|
||||
size: tileSize
|
||||
});
|
||||
}
|
||||
};
|
||||
im.src = url;
|
||||
}
|
||||
|
||||
function tileQueueFinish(err, data) {
|
||||
data.forEach(drawTile);
|
||||
callback(null, { canvas: canvas });
|
||||
}
|
||||
|
||||
function drawTile(d) {
|
||||
ctx.drawImage(d.img, Math.floor(d.pos.x), Math.floor(d.pos.y),
|
||||
d.size, d.size);
|
||||
}
|
||||
}
|
||||
|
||||
function handlePathRoot(root, callback) {
|
||||
var bounds = map.getPixelBounds(),
|
||||
origin = map.getPixelOrigin(),
|
||||
canvas = document.createElement('canvas');
|
||||
canvas.width = dimensions.x;
|
||||
canvas.height = dimensions.y;
|
||||
var ctx = canvas.getContext('2d');
|
||||
var pos = L.DomUtil.getPosition(root).subtract(bounds.min).add(origin);
|
||||
try {
|
||||
ctx.drawImage(root, pos.x, pos.y, canvas.width - (pos.x * 2), canvas.height - (pos.y * 2));
|
||||
callback(null, {
|
||||
canvas: canvas
|
||||
});
|
||||
} catch(e) {
|
||||
console.error('Element could not be drawn on canvas', root); // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
|
||||
function handleMarkerLayer(marker, callback) {
|
||||
var canvas = document.createElement('canvas'),
|
||||
ctx = canvas.getContext('2d'),
|
||||
pixelBounds = map.getPixelBounds(),
|
||||
minPoint = new L.Point(pixelBounds.min.x, pixelBounds.min.y),
|
||||
pixelPoint = map.project(marker.getLatLng()),
|
||||
isBase64 = /^data\:/.test(marker._icon.src),
|
||||
url = isBase64 ? marker._icon.src : addCacheString(marker._icon.src),
|
||||
im = new Image(),
|
||||
options = marker.options.icon.options,
|
||||
size = options.iconSize,
|
||||
pos = pixelPoint.subtract(minPoint),
|
||||
anchor = L.point(options.iconAnchor || size && size.divideBy(2, true));
|
||||
|
||||
if (size instanceof L.Point) size = [size.x, size.y];
|
||||
|
||||
var x = Math.round(pos.x - size[0] + anchor.x),
|
||||
y = Math.round(pos.y - anchor.y);
|
||||
|
||||
canvas.width = dimensions.x;
|
||||
canvas.height = dimensions.y;
|
||||
im.crossOrigin = '';
|
||||
|
||||
im.onload = function () {
|
||||
ctx.drawImage(this, x, y, size[0], size[1]);
|
||||
callback(null, {
|
||||
canvas: canvas
|
||||
});
|
||||
};
|
||||
|
||||
im.src = url;
|
||||
|
||||
if (isBase64) im.onload();
|
||||
}
|
||||
|
||||
function handleEsriDymamicLayer(dynamicLayer, callback) {
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = dimensions.x;
|
||||
canvas.height = dimensions.y;
|
||||
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
var im = new Image();
|
||||
im.crossOrigin = '';
|
||||
im.src = addCacheString(dynamicLayer._currentImage._image.src);
|
||||
|
||||
im.onload = function() {
|
||||
ctx.drawImage(im, 0, 0);
|
||||
callback(null, {
|
||||
canvas: canvas
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function addCacheString(url) {
|
||||
// If it's a data URL we don't want to touch this.
|
||||
if (isDataURL(url) || url.indexOf('mapbox.com/styles/v1') !== -1) {
|
||||
return url;
|
||||
}
|
||||
return url + ((url.match(/\?/)) ? '&' : '?') + 'cache=' + cacheBusterDate;
|
||||
}
|
||||
|
||||
function isDataURL(url) {
|
||||
var dataURLRegex = /^\s*data:([a-z]+\/[a-z]+(;[a-z\-]+\=[a-z\-]+)?)?(;base64)?,[a-z0-9\!\$\&\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i;
|
||||
return !!url.match(dataURLRegex);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
},{"d3-queue":2}],2:[function(require,module,exports){
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
||||
(factory((global.d3_queue = global.d3_queue || {})));
|
||||
}(this, function (exports) { 'use strict';
|
||||
|
||||
var version = "2.0.3";
|
||||
|
||||
var slice = [].slice;
|
||||
|
||||
var noabort = {};
|
||||
|
||||
function Queue(size) {
|
||||
if (!(size >= 1)) throw new Error;
|
||||
this._size = size;
|
||||
this._call =
|
||||
this._error = null;
|
||||
this._tasks = [];
|
||||
this._data = [];
|
||||
this._waiting =
|
||||
this._active =
|
||||
this._ended =
|
||||
this._start = 0; // inside a synchronous task callback?
|
||||
}
|
||||
|
||||
Queue.prototype = queue.prototype = {
|
||||
constructor: Queue,
|
||||
defer: function(callback) {
|
||||
if (typeof callback !== "function" || this._call) throw new Error;
|
||||
if (this._error != null) return this;
|
||||
var t = slice.call(arguments, 1);
|
||||
t.push(callback);
|
||||
++this._waiting, this._tasks.push(t);
|
||||
poke(this);
|
||||
return this;
|
||||
},
|
||||
abort: function() {
|
||||
if (this._error == null) abort(this, new Error("abort"));
|
||||
return this;
|
||||
},
|
||||
await: function(callback) {
|
||||
if (typeof callback !== "function" || this._call) throw new Error;
|
||||
this._call = function(error, results) { callback.apply(null, [error].concat(results)); };
|
||||
maybeNotify(this);
|
||||
return this;
|
||||
},
|
||||
awaitAll: function(callback) {
|
||||
if (typeof callback !== "function" || this._call) throw new Error;
|
||||
this._call = callback;
|
||||
maybeNotify(this);
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
function poke(q) {
|
||||
if (!q._start) try { start(q); } // let the current task complete
|
||||
catch (e) { if (q._tasks[q._ended + q._active - 1]) abort(q, e); } // task errored synchronously
|
||||
}
|
||||
|
||||
function start(q) {
|
||||
while (q._start = q._waiting && q._active < q._size) {
|
||||
var i = q._ended + q._active,
|
||||
t = q._tasks[i],
|
||||
j = t.length - 1,
|
||||
c = t[j];
|
||||
t[j] = end(q, i);
|
||||
--q._waiting, ++q._active;
|
||||
t = c.apply(null, t);
|
||||
if (!q._tasks[i]) continue; // task finished synchronously
|
||||
q._tasks[i] = t || noabort;
|
||||
}
|
||||
}
|
||||
|
||||
function end(q, i) {
|
||||
return function(e, r) {
|
||||
if (!q._tasks[i]) return; // ignore multiple callbacks
|
||||
--q._active, ++q._ended;
|
||||
q._tasks[i] = null;
|
||||
if (q._error != null) return; // ignore secondary errors
|
||||
if (e != null) {
|
||||
abort(q, e);
|
||||
} else {
|
||||
q._data[i] = r;
|
||||
if (q._waiting) poke(q);
|
||||
else maybeNotify(q);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function abort(q, e) {
|
||||
var i = q._tasks.length, t;
|
||||
q._error = e; // ignore active callbacks
|
||||
q._data = undefined; // allow gc
|
||||
q._waiting = NaN; // prevent starting
|
||||
|
||||
while (--i >= 0) {
|
||||
if (t = q._tasks[i]) {
|
||||
q._tasks[i] = null;
|
||||
if (t.abort) try { t.abort(); }
|
||||
catch (e) { /* ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
q._active = NaN; // allow notification
|
||||
maybeNotify(q);
|
||||
}
|
||||
|
||||
function maybeNotify(q) {
|
||||
if (!q._active && q._call) q._call(q._error, q._data);
|
||||
}
|
||||
|
||||
function queue(concurrency) {
|
||||
return new Queue(arguments.length ? +concurrency : Infinity);
|
||||
}
|
||||
|
||||
exports.version = version;
|
||||
exports.queue = queue;
|
||||
|
||||
}));
|
||||
},{}]},{},[1])(1)
|
||||
});
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,3 +1,5 @@
|
||||
window.maps = {};
|
||||
|
||||
function override_config(event, state, tmp_this) {
|
||||
event.preventDefault();
|
||||
var $this = tmp_this;
|
||||
@@ -285,18 +287,28 @@ function loadjs(filename, func){
|
||||
}
|
||||
}
|
||||
|
||||
function init_map(id, engine, api_key, config) {
|
||||
var leaflet = L.map(id);
|
||||
var baseMaps = {};
|
||||
leaflet.setView([0, 0], 15);
|
||||
function init_map(id, config = {}) {
|
||||
let leaflet = get_map(id)
|
||||
if (leaflet) {
|
||||
// return existing map
|
||||
return leaflet;
|
||||
}
|
||||
|
||||
if (engine === 'google') {
|
||||
loadjs('https://maps.googleapis.com/maps/api/js?key=' + api_key, function () {
|
||||
leaflet = L.map(id, {
|
||||
preferCanvas: true,
|
||||
zoom: config.zoom !== undefined ? config.zoom : 3,
|
||||
center: (config.lat !== undefined && config.lng !== undefined) ? [config.lat, config.lng] : [40,-20]
|
||||
});
|
||||
window.maps[id] = leaflet;
|
||||
let baseMaps = {};
|
||||
|
||||
if (config.engine === 'google' && config.api_key) {
|
||||
loadjs('https://maps.googleapis.com/maps/api/js?key=' + config.api_key, function () {
|
||||
loadjs('js/Leaflet.GoogleMutant.js', function () {
|
||||
var roads = L.gridLayer.googleMutant({
|
||||
const roads = L.gridLayer.googleMutant({
|
||||
type: 'roadmap' // valid values are 'roadmap', 'satellite', 'terrain' and 'hybrid'
|
||||
});
|
||||
var satellite = L.gridLayer.googleMutant({
|
||||
const satellite = L.gridLayer.googleMutant({
|
||||
type: 'satellite'
|
||||
});
|
||||
|
||||
@@ -304,18 +316,19 @@ function init_map(id, engine, api_key, config) {
|
||||
"Streets": roads,
|
||||
"Satellite": satellite
|
||||
};
|
||||
L.control.layers(baseMaps, null, {position: 'bottomleft'}).addTo(leaflet);
|
||||
roads.addTo(leaflet);
|
||||
leaflet.layerControl = L.control.layers(baseMaps, null, {position: 'bottomleft'}).addTo(leaflet);
|
||||
(config.layer in baseMaps ? baseMaps[config.layer] : roads).addTo(leaflet);
|
||||
leaflet.layerControl._container.style.display = (config.readonly ? 'none' : 'block');
|
||||
});
|
||||
});
|
||||
} else if (engine === 'bing') {
|
||||
} else if (config.engine === 'bing' && config.api_key) {
|
||||
loadjs('js/leaflet-bing-layer.min.js', function () {
|
||||
var roads = L.tileLayer.bing({
|
||||
bingMapsKey: api_key,
|
||||
const roads = L.tileLayer.bing({
|
||||
bingMapsKey: config.api_key,
|
||||
imagerySet: 'RoadOnDemand'
|
||||
});
|
||||
var satellite = L.tileLayer.bing({
|
||||
bingMapsKey: api_key,
|
||||
const satellite = L.tileLayer.bing({
|
||||
bingMapsKey: config.api_key,
|
||||
imagerySet: 'AerialWithLabelsOnDemand'
|
||||
});
|
||||
|
||||
@@ -323,23 +336,26 @@ function init_map(id, engine, api_key, config) {
|
||||
"Streets": roads,
|
||||
"Satellite": satellite
|
||||
};
|
||||
L.control.layers(baseMaps, null, {position: 'bottomleft'}).addTo(leaflet);
|
||||
roads.addTo(leaflet);
|
||||
leaflet.layerControl = L.control.layers(baseMaps, null, {position: 'bottomleft'}).addTo(leaflet);
|
||||
(config.layer in baseMaps ? baseMaps[config.layer] : roads).addTo(leaflet);
|
||||
leaflet.layerControl._container.style.display = (config.readonly ? 'none' : 'block');
|
||||
});
|
||||
} else if (engine === 'mapquest') {
|
||||
loadjs('https://www.mapquestapi.com/sdk/leaflet/v2.2/mq-map.js?key=' + api_key, function () {
|
||||
var roads = MQ.mapLayer();
|
||||
var satellite = MQ.hybridLayer();
|
||||
} else if (config.engine === 'mapquest' && config.api_key) {
|
||||
loadjs('https://www.mapquestapi.com/sdk/leaflet/v2.2/mq-map.js?key=' + config.api_key, function () {
|
||||
const roads = MQ.mapLayer();
|
||||
const satellite = MQ.hybridLayer();
|
||||
|
||||
baseMaps = {
|
||||
"Streets": roads,
|
||||
"Satellite": satellite
|
||||
};
|
||||
L.control.layers(baseMaps, null, {position: 'bottomleft'}).addTo(leaflet);
|
||||
roads.addTo(leaflet);
|
||||
leaflet.layerControl = L.control.layers(baseMaps, null, {position: 'bottomleft'}).addTo(leaflet);
|
||||
(config.layer in baseMaps ? baseMaps[config.layer] : roads).addTo(leaflet);
|
||||
leaflet.layerControl._container.style.display = (config.readonly ? 'none' : 'block');
|
||||
});
|
||||
} else {
|
||||
var osm = L.tileLayer('//' + config.tile_url + '/{z}/{x}/{y}.png', {
|
||||
const tile_url = config.tile_url ? config.tile_url : '{s}.tile.openstreetmap.org';
|
||||
const osm = L.tileLayer('//' + tile_url + '/{z}/{x}/{y}.png', {
|
||||
maxZoom: 19,
|
||||
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
});
|
||||
@@ -352,20 +368,79 @@ function init_map(id, engine, api_key, config) {
|
||||
// "OpenStreetMap": osm,
|
||||
// "Satellite": esri
|
||||
// };
|
||||
// L.control.layers(baseMaps, null, {position: 'bottomleft'}).addTo(leaflet);
|
||||
// leaflet.layerControl = L.control.layers(baseMaps, null, {position: 'bottomleft'}).addTo(leaflet);
|
||||
osm.addTo(leaflet);
|
||||
}
|
||||
|
||||
if (location.protocol === 'https:') {
|
||||
// disable all interaction
|
||||
if (config.readonly === true) {
|
||||
disable_map_interaction(leaflet)
|
||||
} else if (location.protocol === 'https:') {
|
||||
// can't request location permission without https
|
||||
L.control.locate().addTo(leaflet);
|
||||
leaflet.locateControl = L.control.locate().addTo(leaflet);
|
||||
}
|
||||
|
||||
return leaflet;
|
||||
}
|
||||
|
||||
function get_map(id) {
|
||||
if (window.maps) {
|
||||
return window.maps[id];
|
||||
}
|
||||
}
|
||||
|
||||
function destroy_map(id) {
|
||||
const leaflet = get_map(id);
|
||||
if(id in window.maps) {
|
||||
leaflet.off();
|
||||
leaflet._container.classList.remove('leaflet-container', 'leaflet-touch', 'leaflet-retina', 'leaflet-fade-anim');
|
||||
leaflet.remove();
|
||||
delete window.maps[id];
|
||||
}
|
||||
}
|
||||
|
||||
function disable_map_interaction(leaflet) {
|
||||
leaflet.zoomControl?.remove();
|
||||
delete leaflet.zoomControl;
|
||||
leaflet.locateControl?.stop();
|
||||
leaflet.locateControl?.remove();
|
||||
delete leaflet.locateControl;
|
||||
if (leaflet.layerControl) {
|
||||
leaflet.layerControl._container.style.display = 'none';
|
||||
}
|
||||
leaflet.dragging.disable();
|
||||
leaflet.touchZoom.disable();
|
||||
leaflet.doubleClickZoom.disable();
|
||||
leaflet.scrollWheelZoom.disable();
|
||||
leaflet.boxZoom.disable();
|
||||
leaflet.keyboard.disable();
|
||||
leaflet.tap?.disable();
|
||||
leaflet._container.style.cursor = 'default';
|
||||
}
|
||||
|
||||
function enable_map_interaction(leaflet) {
|
||||
if (! leaflet.zoomControl) {
|
||||
leaflet.zoomControl = L.control.zoom().addTo(leaflet);
|
||||
}
|
||||
if (location.protocol === 'https:' && ! leaflet.locateControl) {
|
||||
// can't request location permission without https
|
||||
leaflet.locateControl = L.control.locate().addTo(leaflet);
|
||||
}
|
||||
if (leaflet.layerControl) {
|
||||
leaflet.layerControl._container.style.display = 'block';
|
||||
}
|
||||
leaflet.dragging.enable();
|
||||
leaflet.touchZoom.enable();
|
||||
leaflet.doubleClickZoom.enable();
|
||||
leaflet.scrollWheelZoom.enable();
|
||||
leaflet.boxZoom.enable();
|
||||
leaflet.keyboard.enable();
|
||||
leaflet.tap?.enable();
|
||||
leaflet._container.style.cursor = 'pointer';
|
||||
}
|
||||
|
||||
function init_map_marker(leaflet, latlng) {
|
||||
var marker = L.marker(latlng);
|
||||
let marker = L.marker(latlng);
|
||||
marker.addTo(leaflet);
|
||||
leaflet.setView(latlng);
|
||||
|
||||
@@ -381,6 +456,33 @@ function init_map_marker(leaflet, latlng) {
|
||||
return marker;
|
||||
}
|
||||
|
||||
function setCustomMapBackground(id, type, data) {
|
||||
let image = '';
|
||||
let color = '';
|
||||
|
||||
if(type === 'image') {
|
||||
image = `url(${data.image_url})`;
|
||||
} else if(type === 'color') {
|
||||
color = data.color;
|
||||
}
|
||||
$(`#${id} .vis-network canvas`)
|
||||
.css('background-image', image)
|
||||
.css('background-size', 'cover')
|
||||
.css('background-color', color);
|
||||
|
||||
const mapBackgroundId = `${id}-bg-geo-map`;
|
||||
if (type === 'map') {
|
||||
$(`#${id}-bg-geo-map`).show();
|
||||
let config = data;
|
||||
config['readonly'] = true;
|
||||
init_map(mapBackgroundId, config)
|
||||
.setView(L.latLng(data.lat, data.lng), data.zoom);
|
||||
} else {
|
||||
// destroy the map if it exists
|
||||
destroy_map(mapBackgroundId)
|
||||
}
|
||||
}
|
||||
|
||||
function update_location(id, latlng, callback) {
|
||||
$.ajax({
|
||||
method: 'PATCH',
|
||||
|
@@ -2,15 +2,15 @@
|
||||
"/js/app.js": "/js/app.js?id=1ecd9b13d60fe23a9729684f4d9dc663",
|
||||
"/js/manifest.js": "/js/manifest.js?id=2eb19d92c19953027907b72ff5963ebb",
|
||||
"/css/vendor.css": "/css/vendor.css?id=d520734ded0ec75b0a572aa8db1c2161",
|
||||
"/css/app.css": "/css/app.css?id=61739943d1d595fd4afe2157f24f0316",
|
||||
"/css/app.css": "/css/app.css?id=30306ab2ec735e188cf480f67548406b",
|
||||
"/js/vendor.js": "/js/vendor.js?id=3b22b85b4e5a64e37dd954c0b147b3f3",
|
||||
"/js/lang/de.js": "/js/lang/de.js?id=9a6f9c23a4b209504cce12ce85315a3c",
|
||||
"/js/lang/en.js": "/js/lang/en.js?id=43cfd926c2a415bdbb2e59676ab29875",
|
||||
"/js/lang/fr.js": "/js/lang/fr.js?id=d9dd782bb64e09dcca29d784c0417779",
|
||||
"/js/lang/it.js": "/js/lang/it.js?id=40ad82368018e52347e3808571866e69",
|
||||
"/js/lang/de.js": "/js/lang/de.js?id=f80b2c49bd4d1587d4747d189c566ffa",
|
||||
"/js/lang/en.js": "/js/lang/en.js?id=cece9b44445c5e2d9d1d819a6b37ec74",
|
||||
"/js/lang/fr.js": "/js/lang/fr.js?id=7e43fd1965beef315f0b416fd8607231",
|
||||
"/js/lang/it.js": "/js/lang/it.js?id=7827375adf92766a477291c48fa1b360",
|
||||
"/js/lang/ru.js": "/js/lang/ru.js?id=f6b7c078755312a0907c4f983991cc52",
|
||||
"/js/lang/sr.js": "/js/lang/sr.js?id=388e38b41f63e35175061e849bf0d8e5",
|
||||
"/js/lang/uk.js": "/js/lang/uk.js?id=85ef43c7afe57a42b774f3cbae5a77e5",
|
||||
"/js/lang/zh-CN.js": "/js/lang/zh-CN.js?id=6fdbd03cdf6b4868de1d3b5b557e5e13",
|
||||
"/js/lang/zh-CN.js": "/js/lang/zh-CN.js?id=13d99410e49647e05664cd14056c2473",
|
||||
"/js/lang/zh-TW.js": "/js/lang/zh-TW.js?id=2cf0d871ec12cbd5ccb746b983d127df"
|
||||
}
|
||||
|
@@ -22,6 +22,10 @@ return [
|
||||
'bg' => [
|
||||
'title' => 'Set Background',
|
||||
'background' => 'Background',
|
||||
'color' => 'Color',
|
||||
'image' => 'Image',
|
||||
'map' => 'Map',
|
||||
'none' => 'None',
|
||||
'clear_bg' => 'Clear BG',
|
||||
'clear_background' => 'Clear Background',
|
||||
'keep_background' => 'Keep Background',
|
||||
@@ -29,6 +33,13 @@ return [
|
||||
'save_errors' => 'Save failed due to the following errors:',
|
||||
'save_error' => 'Save failed. Server returned error response code: :code',
|
||||
'save' => 'Save Background',
|
||||
'lat' => 'Latitude',
|
||||
'lng' => 'Longitude',
|
||||
'zoom' => 'Zoom',
|
||||
'adjust_map' => 'Adjust Map',
|
||||
'adjust_map_finish' => 'Done Adjusting Map',
|
||||
'as_image' => 'Set as Image',
|
||||
'as_image_hint' => 'Setting the map as an image background will be static, but have improved performance and work without connection to the map tile server',
|
||||
],
|
||||
'map' => [
|
||||
'settings_title' => 'Map Settings',
|
||||
|
@@ -530,14 +530,14 @@ custom_maps:
|
||||
- { Field: legend_font_size, Type: smallint, 'Null': false, Extra: '', Default: '14' }
|
||||
- { Field: legend_hide_invalid, Type: tinyint, 'Null': false, Extra: '', Default: '0' }
|
||||
- { Field: legend_hide_overspeed, Type: tinyint, 'Null': false, Extra: '', Default: '0' }
|
||||
- { Field: background_suffix, Type: varchar(10), 'Null': true, Extra: '' }
|
||||
- { Field: background_version, Type: 'int unsigned', 'Null': false, Extra: '' }
|
||||
- { Field: options, Type: longtext, 'Null': true, Extra: '' }
|
||||
- { Field: newnodeconfig, Type: longtext, 'Null': false, Extra: '' }
|
||||
- { Field: newedgeconfig, Type: longtext, 'Null': false, Extra: '' }
|
||||
- { Field: created_at, Type: timestamp, 'Null': true, Extra: '' }
|
||||
- { Field: updated_at, Type: timestamp, 'Null': true, Extra: '' }
|
||||
- { Field: menu_group, Type: varchar(100), 'Null': true, Extra: '' }
|
||||
- { Field: background_type, Type: varchar(16), 'Null': false, Extra: '', Default: 'none' }
|
||||
- { Field: background_data, Type: 'text', 'Null': true, Extra: '' }
|
||||
Indexes:
|
||||
PRIMARY: { Name: PRIMARY, Columns: [custom_map_id], Unique: true, Type: BTREE }
|
||||
custom_map_backgrounds:
|
||||
|
306
package-lock.json
generated
306
package-lock.json
generated
@@ -82,21 +82,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/core": {
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz",
|
||||
"integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz",
|
||||
"integrity": "sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
"@babel/code-frame": "^7.24.2",
|
||||
"@babel/generator": "^7.24.4",
|
||||
"@babel/generator": "^7.24.5",
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-module-transforms": "^7.23.3",
|
||||
"@babel/helpers": "^7.24.4",
|
||||
"@babel/parser": "^7.24.4",
|
||||
"@babel/helper-module-transforms": "^7.24.5",
|
||||
"@babel/helpers": "^7.24.5",
|
||||
"@babel/parser": "^7.24.5",
|
||||
"@babel/template": "^7.24.0",
|
||||
"@babel/traverse": "^7.24.1",
|
||||
"@babel/types": "^7.24.0",
|
||||
"@babel/traverse": "^7.24.5",
|
||||
"@babel/types": "^7.24.5",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"debug": "^4.1.0",
|
||||
"gensync": "^1.0.0-beta.2",
|
||||
@@ -121,12 +121,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz",
|
||||
"integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz",
|
||||
"integrity": "sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.24.0",
|
||||
"@babel/types": "^7.24.5",
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.25",
|
||||
"jsesc": "^2.5.1"
|
||||
@@ -185,19 +185,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-create-class-features-plugin": {
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz",
|
||||
"integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.5.tgz",
|
||||
"integrity": "sha512-uRc4Cv8UQWnE4NXlYTIIdM7wfFkOqlFztcC/gVXDKohKoVB3OyonfelUBaJzSwpBntZ2KYGF/9S7asCHsXwW6g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": "^7.22.5",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-member-expression-to-functions": "^7.23.0",
|
||||
"@babel/helper-member-expression-to-functions": "^7.24.5",
|
||||
"@babel/helper-optimise-call-expression": "^7.22.5",
|
||||
"@babel/helper-replace-supers": "^7.24.1",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/helper-split-export-declaration": "^7.24.5",
|
||||
"semver": "^6.3.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -293,12 +293,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-member-expression-to-functions": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz",
|
||||
"integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.5.tgz",
|
||||
"integrity": "sha512-4owRteeihKWKamtqg4JmWSsEZU445xpFRXPEwp44HbgbxdWlUV1b4Agg4lkA806Lil5XM/e+FJyS0vj5T6vmcA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.23.0"
|
||||
"@babel/types": "^7.24.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -317,16 +317,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-module-transforms": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz",
|
||||
"integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz",
|
||||
"integrity": "sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-module-imports": "^7.22.15",
|
||||
"@babel/helper-simple-access": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/helper-validator-identifier": "^7.22.20"
|
||||
"@babel/helper-module-imports": "^7.24.3",
|
||||
"@babel/helper-simple-access": "^7.24.5",
|
||||
"@babel/helper-split-export-declaration": "^7.24.5",
|
||||
"@babel/helper-validator-identifier": "^7.24.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -348,9 +348,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-plugin-utils": {
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz",
|
||||
"integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz",
|
||||
"integrity": "sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -391,12 +391,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-simple-access": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz",
|
||||
"integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz",
|
||||
"integrity": "sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5"
|
||||
"@babel/types": "^7.24.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -415,12 +415,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-split-export-declaration": {
|
||||
"version": "7.22.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
|
||||
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz",
|
||||
"integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5"
|
||||
"@babel/types": "^7.24.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -436,9 +436,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz",
|
||||
"integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -454,40 +454,40 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-wrap-function": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz",
|
||||
"integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.5.tgz",
|
||||
"integrity": "sha512-/xxzuNvgRl4/HLNKvnFwdhdgN3cpLxgLROeLDl83Yx0AJ1SGvq1ak0OszTOjDfiB8Vx03eJbeDWh9r+jCCWttw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-function-name": "^7.22.5",
|
||||
"@babel/template": "^7.22.15",
|
||||
"@babel/types": "^7.22.19"
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/template": "^7.24.0",
|
||||
"@babel/types": "^7.24.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helpers": {
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz",
|
||||
"integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz",
|
||||
"integrity": "sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.24.0",
|
||||
"@babel/traverse": "^7.24.1",
|
||||
"@babel/types": "^7.24.0"
|
||||
"@babel/traverse": "^7.24.5",
|
||||
"@babel/types": "^7.24.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight": {
|
||||
"version": "7.24.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz",
|
||||
"integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz",
|
||||
"integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"@babel/helper-validator-identifier": "^7.24.5",
|
||||
"chalk": "^2.4.2",
|
||||
"js-tokens": "^4.0.0",
|
||||
"picocolors": "^1.0.0"
|
||||
@@ -559,9 +559,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz",
|
||||
"integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz",
|
||||
"integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==",
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
@@ -570,13 +570,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": {
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz",
|
||||
"integrity": "sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.5.tgz",
|
||||
"integrity": "sha512-LdXRi1wEMTrHVR4Zc9F8OewC3vdm5h4QB6L71zy6StmYeqGi1b3ttIO8UC+BfZKcH9jdr4aI249rBkm+3+YvHw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -966,12 +966,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-block-scoping": {
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz",
|
||||
"integrity": "sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.5.tgz",
|
||||
"integrity": "sha512-sMfBc3OxghjC95BkYrYocHL3NaOplrcaunblzwXhGmlPwpmfsxr4vK+mBBt49r+S240vahmv+kUxkeKgs+haCw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1014,18 +1014,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-classes": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz",
|
||||
"integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.5.tgz",
|
||||
"integrity": "sha512-gWkLP25DFj2dwe9Ck8uwMOpko4YsqyfZJrOmqqcegeDYEbp7rmn4U6UQZNj08UF6MaX39XenSpKRCvpDRBtZ7Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": "^7.22.5",
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-plugin-utils": "^7.24.5",
|
||||
"@babel/helper-replace-supers": "^7.24.1",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/helper-split-export-declaration": "^7.24.5",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1052,12 +1052,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-destructuring": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz",
|
||||
"integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.5.tgz",
|
||||
"integrity": "sha512-SZuuLyfxvsm+Ah57I/i1HVjveBENYK9ue8MJ7qkc7ndoNjqquJiElzA7f5yaAXjyW2hKojosOTAQQRX50bPSVg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1371,15 +1371,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-object-rest-spread": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.1.tgz",
|
||||
"integrity": "sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.5.tgz",
|
||||
"integrity": "sha512-7EauQHszLGM3ay7a161tTQH7fj+3vVM/gThlz5HpFtnygTxjrlvoeq7MPVA1Vy9Q555OB8SnAOsMkLShNkkrHA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-plugin-utils": "^7.24.5",
|
||||
"@babel/plugin-syntax-object-rest-spread": "^7.8.3",
|
||||
"@babel/plugin-transform-parameters": "^7.24.1"
|
||||
"@babel/plugin-transform-parameters": "^7.24.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1421,12 +1421,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-optional-chaining": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.1.tgz",
|
||||
"integrity": "sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.5.tgz",
|
||||
"integrity": "sha512-xWCkmwKT+ihmA6l7SSTpk8e4qQl/274iNbSKRRS8mpqFR32ksy36+a+LWY8OXCCEefF8WFlnOHVsaDI2231wBg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-plugin-utils": "^7.24.5",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
|
||||
"@babel/plugin-syntax-optional-chaining": "^7.8.3"
|
||||
},
|
||||
@@ -1438,12 +1438,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-parameters": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz",
|
||||
"integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.5.tgz",
|
||||
"integrity": "sha512-9Co00MqZ2aoky+4j2jhofErthm6QVLKbpQrvz20c3CH9KQCLHyNB+t2ya4/UrRpQGR+Wrwjg9foopoeSdnHOkA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1469,14 +1469,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-private-property-in-object": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.1.tgz",
|
||||
"integrity": "sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.5.tgz",
|
||||
"integrity": "sha512-JM4MHZqnWR04jPMujQDTBVRnqxpLLpx2tkn7iPn+Hmsc0Gnb79yvRWOkvqFOx3Z7P7VxiRIR22c4eGSNj87OBQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": "^7.22.5",
|
||||
"@babel/helper-create-class-features-plugin": "^7.24.1",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-create-class-features-plugin": "^7.24.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.5",
|
||||
"@babel/plugin-syntax-private-property-in-object": "^7.14.5"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1623,12 +1623,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-typeof-symbol": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz",
|
||||
"integrity": "sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.5.tgz",
|
||||
"integrity": "sha512-UTGnhYVZtTAjdwOTzT+sCyXmTn8AhaxOS/MjG9REclZ6ULHWF9KoCZur0HSGU7hk8PdBFKKbYe6+gqdXWz84Jg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.24.0"
|
||||
"@babel/helper-plugin-utils": "^7.24.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1701,16 +1701,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/preset-env": {
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.4.tgz",
|
||||
"integrity": "sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.5.tgz",
|
||||
"integrity": "sha512-UGK2ifKtcC8i5AI4cH+sbLLuLc2ktYSFJgBAXorKAsHUZmrQ1q6aQ6i3BvU24wWs2AAKqQB6kq3N9V9Gw1HiMQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.24.4",
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-plugin-utils": "^7.24.5",
|
||||
"@babel/helper-validator-option": "^7.23.5",
|
||||
"@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.4",
|
||||
"@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.5",
|
||||
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.1",
|
||||
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.1",
|
||||
"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.1",
|
||||
@@ -1737,12 +1737,12 @@
|
||||
"@babel/plugin-transform-async-generator-functions": "^7.24.3",
|
||||
"@babel/plugin-transform-async-to-generator": "^7.24.1",
|
||||
"@babel/plugin-transform-block-scoped-functions": "^7.24.1",
|
||||
"@babel/plugin-transform-block-scoping": "^7.24.4",
|
||||
"@babel/plugin-transform-block-scoping": "^7.24.5",
|
||||
"@babel/plugin-transform-class-properties": "^7.24.1",
|
||||
"@babel/plugin-transform-class-static-block": "^7.24.4",
|
||||
"@babel/plugin-transform-classes": "^7.24.1",
|
||||
"@babel/plugin-transform-classes": "^7.24.5",
|
||||
"@babel/plugin-transform-computed-properties": "^7.24.1",
|
||||
"@babel/plugin-transform-destructuring": "^7.24.1",
|
||||
"@babel/plugin-transform-destructuring": "^7.24.5",
|
||||
"@babel/plugin-transform-dotall-regex": "^7.24.1",
|
||||
"@babel/plugin-transform-duplicate-keys": "^7.24.1",
|
||||
"@babel/plugin-transform-dynamic-import": "^7.24.1",
|
||||
@@ -1762,13 +1762,13 @@
|
||||
"@babel/plugin-transform-new-target": "^7.24.1",
|
||||
"@babel/plugin-transform-nullish-coalescing-operator": "^7.24.1",
|
||||
"@babel/plugin-transform-numeric-separator": "^7.24.1",
|
||||
"@babel/plugin-transform-object-rest-spread": "^7.24.1",
|
||||
"@babel/plugin-transform-object-rest-spread": "^7.24.5",
|
||||
"@babel/plugin-transform-object-super": "^7.24.1",
|
||||
"@babel/plugin-transform-optional-catch-binding": "^7.24.1",
|
||||
"@babel/plugin-transform-optional-chaining": "^7.24.1",
|
||||
"@babel/plugin-transform-parameters": "^7.24.1",
|
||||
"@babel/plugin-transform-optional-chaining": "^7.24.5",
|
||||
"@babel/plugin-transform-parameters": "^7.24.5",
|
||||
"@babel/plugin-transform-private-methods": "^7.24.1",
|
||||
"@babel/plugin-transform-private-property-in-object": "^7.24.1",
|
||||
"@babel/plugin-transform-private-property-in-object": "^7.24.5",
|
||||
"@babel/plugin-transform-property-literals": "^7.24.1",
|
||||
"@babel/plugin-transform-regenerator": "^7.24.1",
|
||||
"@babel/plugin-transform-reserved-words": "^7.24.1",
|
||||
@@ -1776,7 +1776,7 @@
|
||||
"@babel/plugin-transform-spread": "^7.24.1",
|
||||
"@babel/plugin-transform-sticky-regex": "^7.24.1",
|
||||
"@babel/plugin-transform-template-literals": "^7.24.1",
|
||||
"@babel/plugin-transform-typeof-symbol": "^7.24.1",
|
||||
"@babel/plugin-transform-typeof-symbol": "^7.24.5",
|
||||
"@babel/plugin-transform-unicode-escapes": "^7.24.1",
|
||||
"@babel/plugin-transform-unicode-property-regex": "^7.24.1",
|
||||
"@babel/plugin-transform-unicode-regex": "^7.24.1",
|
||||
@@ -1825,9 +1825,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.24.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz",
|
||||
"integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz",
|
||||
"integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
},
|
||||
@@ -1850,19 +1850,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse": {
|
||||
"version": "7.24.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz",
|
||||
"integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz",
|
||||
"integrity": "sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.24.1",
|
||||
"@babel/generator": "^7.24.1",
|
||||
"@babel/code-frame": "^7.24.2",
|
||||
"@babel/generator": "^7.24.5",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-hoist-variables": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/parser": "^7.24.1",
|
||||
"@babel/types": "^7.24.0",
|
||||
"@babel/helper-split-export-declaration": "^7.24.5",
|
||||
"@babel/parser": "^7.24.5",
|
||||
"@babel/types": "^7.24.5",
|
||||
"debug": "^4.3.1",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
@@ -1871,13 +1871,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz",
|
||||
"integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==",
|
||||
"version": "7.24.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz",
|
||||
"integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.23.4",
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"@babel/helper-string-parser": "^7.24.1",
|
||||
"@babel/helper-validator-identifier": "^7.24.5",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -3460,9 +3460,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001612",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz",
|
||||
"integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==",
|
||||
"version": "1.0.30001614",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001614.tgz",
|
||||
"integrity": "sha512-jmZQ1VpmlRwHgdP1/uiKzgiAuGOfLEJsYFP4+GBou/QQ4U6IOJCB4NP1c+1p9RGLpwObcT94jA5/uO+F1vBbog==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -4465,9 +4465,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.4.748",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.748.tgz",
|
||||
"integrity": "sha512-VWqjOlPZn70UZ8FTKUOkUvBLeTQ0xpty66qV0yJcAGY2/CthI4xyW9aEozRVtuwv3Kpf5xTesmJUcPwuJmgP4A==",
|
||||
"version": "1.4.751",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.751.tgz",
|
||||
"integrity": "sha512-2DEPi++qa89SMGRhufWTiLmzqyuGmNF3SK4+PQetW1JKiZdEpF4XQonJXJCzyuYSA6mauiMhbyVhqYAP45Hvfw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/elliptic": {
|
||||
@@ -4538,9 +4538,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/envinfo": {
|
||||
"version": "7.12.0",
|
||||
"resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.12.0.tgz",
|
||||
"integrity": "sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg==",
|
||||
"version": "7.13.0",
|
||||
"resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz",
|
||||
"integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"envinfo": "dist/cli.js"
|
||||
@@ -4580,9 +4580,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/es-module-lexer": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz",
|
||||
"integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==",
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.2.tgz",
|
||||
"integrity": "sha512-l60ETUTmLqbVbVHv1J4/qj+M8nq7AwMzEcg3kmJDt9dCNrTk+yHcYFf/Kw75pMDwd9mPcIGCG5LcS20SxYRzFA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/es6-object-assign": {
|
||||
@@ -7094,9 +7094,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/path-scurry/node_modules/lru-cache": {
|
||||
"version": "10.2.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz",
|
||||
"integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==",
|
||||
"version": "10.2.2",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz",
|
||||
"integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "14 || >=16.14"
|
||||
@@ -9226,9 +9226,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss/node_modules/yaml": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz",
|
||||
"integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==",
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz",
|
||||
"integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
@@ -9247,9 +9247,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.30.4",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.30.4.tgz",
|
||||
"integrity": "sha512-xRdd0v64a8mFK9bnsKVdoNP9GQIKUAaJPTaqEQDL4w/J8WaW4sWXXoMZ+6SimPkfT5bElreXf8m9HnmPc3E1BQ==",
|
||||
"version": "5.31.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.31.0.tgz",
|
||||
"integrity": "sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.3",
|
||||
@@ -10279,9 +10279,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.16.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
|
||||
"integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
|
||||
"version": "8.17.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz",
|
||||
"integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
|
33
resources/views/components/geo-map.blade.php
Normal file
33
resources/views/components/geo-map.blade.php
Normal file
@@ -0,0 +1,33 @@
|
||||
@props([
|
||||
'id' => 'geo-map',
|
||||
'init' => true,
|
||||
'width' => '200px',
|
||||
'height' => '100px',
|
||||
'lat' => null,
|
||||
'lng' => null,
|
||||
'zoom' => null,
|
||||
'layer' => null,
|
||||
'readonly' => false,
|
||||
'config' => [],
|
||||
])
|
||||
|
||||
@php
|
||||
$config['readonly'] = $readonly;
|
||||
$config['lat'] = $lat ?? $config['lat'] ?? 40;
|
||||
$config['lng'] = $lng ?? $config['lng'] ?? 40;
|
||||
$config['zoom'] = $zoom ?? $config['zoom'] ?? 3;
|
||||
$config['layer'] = $layer ?? $config['layer'] ?? null;
|
||||
$config['engine'] ??= \LibreNMS\Config::get('geoloc.engine');
|
||||
$config['api_key'] ??= \LibreNMS\Config::get('geoloc.api_key');
|
||||
$config['tile_url'] ??= \LibreNMS\Config::get('leaflet.tile_url', '{s}.tile.openstreetmap.org');
|
||||
@endphp
|
||||
|
||||
<div id="{{ $id }}" style="width: {{ $width }};height: {{ $height }}" {{ $attributes }}></div>
|
||||
|
||||
@if($init)
|
||||
<script>
|
||||
loadjs('js/leaflet.js', function () {
|
||||
init_map(@json($id), @json($config))
|
||||
})
|
||||
</script>
|
||||
@endif
|
12
resources/views/components/input.blade.php
Normal file
12
resources/views/components/input.blade.php
Normal file
@@ -0,0 +1,12 @@
|
||||
@props([
|
||||
'id',
|
||||
'label' => null,
|
||||
'value' => null,
|
||||
'type' => 'text',
|
||||
])
|
||||
|
||||
<label for="{{ $id }}" class="tw-block tw-mb-1 tw-mt-2 tw-font-medium tw-text-gray-900 dark:tw-text-white">{{ $label }}</label>
|
||||
<input type="{{ $type }}"
|
||||
id="{{ $id }}"
|
||||
{{ $attributes->merge(['class' => 'tw-mb-2 tw-bg-gray-50 tw-border tw-border-gray-300 tw-text-gray-900 tw-rounded-lg focus:tw-ring-blue-500 focus:tw-border-blue-500 tw-block tw-w-full tw-p-2.5 dark:tw-bg-gray-700 dark:tw-border-gray-600 dark:tw-placeholder-gray-400 dark:tw-text-white dark:tw-focus:ring-blue-500 dark:tw-focus:border-blue-500']) }}
|
||||
/>
|
16
resources/views/components/tab.blade.php
Normal file
16
resources/views/components/tab.blade.php
Normal file
@@ -0,0 +1,16 @@
|
||||
@props(['name', 'value' => null])
|
||||
|
||||
<div x-data="{
|
||||
id: '',
|
||||
name: {{ Js::from($name) }},
|
||||
value: {{ Js::from($value ?: $name) }}
|
||||
}"
|
||||
x-show="value === activeTab"
|
||||
role="tabpanel"
|
||||
:aria-labelledby="`tab-${id}`"
|
||||
:id="`tab-panel-${id}`"
|
||||
x-init="id = registerTab(name, value)"
|
||||
{{ $attributes }}
|
||||
>
|
||||
{{ $slot }}
|
||||
</div>
|
41
resources/views/components/tabs.blade.php
Normal file
41
resources/views/components/tabs.blade.php
Normal file
@@ -0,0 +1,41 @@
|
||||
@props(['active' => ''])
|
||||
|
||||
<div x-data="{
|
||||
activeTab: '{{ $active }}',
|
||||
tabs: [],
|
||||
registerTab(name, value) {
|
||||
this.tabs.push({name: name, value: value});
|
||||
if (! this.activeTab) {
|
||||
this.changeTab(value)
|
||||
}
|
||||
|
||||
return this.tabs.length;
|
||||
},
|
||||
changeTab(tabValue) {
|
||||
this.activeTab = tabValue;
|
||||
this.$dispatch('tab-change', tabValue);
|
||||
}
|
||||
}"
|
||||
{{ $attributes }}
|
||||
>
|
||||
<ul role="tablist" class="tw-flex tw-flex-wrap -tw-mb-px tw-list-none tw-text-center tw-text-gray-500 dark:tw-text-gray-400">
|
||||
<template x-for="(tab, index) in tabs" :key="index">
|
||||
<li class="tw-me-2"
|
||||
@click="changeTab(tab.value)"
|
||||
:id="`tab-${index + 1}`"
|
||||
role="tab"
|
||||
:aria-selected="(tab.value === activeTab).toString()"
|
||||
:aria-controls="`tab-panel-${index + 1}`"
|
||||
>
|
||||
<div
|
||||
x-text="tab.name"
|
||||
class="tw-inline-block tw-p-3 tw-border-b-2 tw-rounded-t-lg tw-cursor-pointer"
|
||||
:class="tab.value === activeTab ? 'tw-text-blue-600 tw-border-blue-600 active dark:tw-text-blue-500 dark:tw-border-blue-500' : 'tw-border-transparent hover:tw-text-gray-600 hover:tw-border-gray-300 dark:hover:tw-text-gray-300'"
|
||||
></div>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
<div x-ref="tabs">
|
||||
{{ $slot }}
|
||||
</div>
|
||||
</div>
|
@@ -76,7 +76,7 @@
|
||||
});
|
||||
var ajax_url = "{{ url('/ajax') }}";
|
||||
</script>
|
||||
<script src="{{ asset('js/librenms.js?ver=14042024') }}"></script>
|
||||
<script src="{{ asset('js/librenms.js?ver=12052024') }}"></script>
|
||||
<script type="text/javascript" src="{{ asset('js/overlib_mini.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ asset('js/flasher.min.js?ver=0.6.1') }}"></script>
|
||||
<script type="text/javascript" src="{{ asset('js/toastr.min.js?ver=05072021') }}"></script>
|
||||
|
@@ -149,7 +149,7 @@
|
||||
|
||||
if (locationMap === null) {
|
||||
config = {{ Js::from($maps_config) }}
|
||||
locationMap = init_map('location-edit-map', '{{ $maps_engine }}', '{{ $maps_api }}', config);
|
||||
locationMap = init_map('location-edit-map', config);
|
||||
locationMarker = init_map_marker(locationMap, location);
|
||||
}
|
||||
|
||||
|
@@ -1,118 +1,199 @@
|
||||
<div class="modal fade" id="bgModal" tabindex="-1" role="dialog" aria-labelledby="bgModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-content" x-data="backgroundModalData()" x-init="resetBackground">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="bgModalLabel">{{ __('map.custom.edit.bg.title') }}</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="well well-lg">
|
||||
<div class="form-group row" id="mapBackgroundRow">
|
||||
<label for="selectbackground" class="col-sm-3 control-label">{{ __('map.custom.edit.bg.background') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input id="mapBackgroundSelect" type="file" name="selectbackground" accept="image/png,image/jpeg,image/svg+xml,image/gif" class="form-control" onchange="mapChangeBackground();">
|
||||
<button id="mapBackgroundCancel" type="button" name="cancelbackground" class="btn btn-primary" onclick="mapChangeBackgroundCancel();" style="display:none">{{ __('Cancel') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row" id="mapBackgroundClearRow">
|
||||
<label for="clearbackground" class="col-sm-3 control-label">{{ __('map.custom.edit.bg.clear_bg') }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="hidden" id="mapBackgroundClearVal">
|
||||
<button id="mapBackgroundClear" type="button" name="clearbackground" class="btn btn-primary" onclick="mapClearBackground();">{{ __('map.custom.edit.bg.clear_background') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-sm-12" id="savebg-alert">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-body tw-p-10">
|
||||
<x-tabs class="tw-text-2xl" @tab-change="type=$event.detail" x-effect="activeTab = type">
|
||||
<x-tab value="image" name="{{ __('map.custom.edit.bg.image') }}" class="tw-mt-10">
|
||||
<x-input id="bgimage"
|
||||
x-ref="bgimage"
|
||||
type="file"
|
||||
label="{{ __('map.custom.edit.bg.background') }}"
|
||||
accept="image/png,image/jpeg,image/svg+xml,image/gif"
|
||||
x-show="!image"
|
||||
x-on:change="setImage($event)"></x-input>
|
||||
<div x-show="image">
|
||||
<span x-text="image"></span>
|
||||
<button type="button" class="btn btn-danger" @click="clearImage">{{ __('map.custom.edit.bg.clear_background') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</x-tab>
|
||||
<x-tab value="color" name="{{ __('map.custom.edit.bg.color') }}" class="tw-mt-10">
|
||||
<x-input id="bg-color" type="color" x-model="color"
|
||||
class="tw-cursor-pointer tw-h-24 tw-w-48"
|
||||
></x-input>
|
||||
</x-tab>
|
||||
<x-tab value="map" name="{{ __('map.custom.edit.bg.map') }}" class="tw-mt-5">
|
||||
<x-input id="bg-lat" label="{{ __('map.custom.edit.bg.lat') }}" x-model="lat"></x-input>
|
||||
<x-input id="bg-lng" label="{{ __('map.custom.edit.bg.lng') }}" x-model="lng"></x-input>
|
||||
<x-input id="bg-zoom" label="{{ __('map.custom.edit.bg.zoom') }}" x-model="zoom"></x-input>
|
||||
<button type="button" class="btn btn-primary tw-mt-2" @click="adjustMap">{{ __('map.custom.edit.bg.adjust_map') }}</button>
|
||||
<button type="button" class="btn btn-primary tw-mt-2" @click="setMapAsImage" title="{{ __('map.custom.edit.bg.as_image_hint') }}" :disabled="saving_map_as_image" x-show="show_image_export">
|
||||
<i class="fa-solid fa-circle-notch fa-spin" x-show="saving_map_as_image"></i>
|
||||
{{ __('map.custom.edit.bg.as_image') }}
|
||||
</button>
|
||||
</x-tab>
|
||||
<x-tab value="none" name="{{ __('map.custom.edit.bg.none') }}"></x-tab>
|
||||
</x-tabs>
|
||||
<div x-show="error">
|
||||
<div class="tw-text-red-600" x-text="error"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<center>
|
||||
<button type=button value="save" id="map-savebgButton" class="btn btn-primary" onclick="saveMapBackground()">{{ __('Save') }}</button>
|
||||
<button type=button value="cancel" id="map-cancelbgButton" class="btn btn-primary" onclick="editMapBackgroundCancel()">{{ __('Cancel') }}</button>
|
||||
</center>
|
||||
<button type=button class="btn btn-primary" @click="saveBackground">{{ __('Save') }}</button>
|
||||
<button type=button class="btn btn-default" @click="closeBackgroundModal">{{ __('Cancel') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function mapChangeBackground() {
|
||||
$("#mapBackgroundCancel").show();
|
||||
}
|
||||
function backgroundModalData() {
|
||||
return {
|
||||
initial_data: {{ Js::from($background_config) }},
|
||||
initial_type: {{ Js::from($background_type) }},
|
||||
type: 'none',
|
||||
color: null,
|
||||
lat: null,
|
||||
lng: null,
|
||||
zoom: null,
|
||||
layer: null,
|
||||
image: null,
|
||||
show_image_export: true,
|
||||
image_content: null,
|
||||
saving_map_as_image: false,
|
||||
error: '',
|
||||
resetBackground() {
|
||||
this.type = this.initial_type;
|
||||
this.color = 'color' in this.initial_data ? this.initial_data.color : '#badaee';
|
||||
this.lat = 'lat' in this.initial_data ? this.initial_data.lat : 40;
|
||||
this.lng = 'lng' in this.initial_data ? this.initial_data.lng : -20;
|
||||
this.zoom = 'zoom' in this.initial_data ? this.initial_data.zoom : 3;
|
||||
this.layer = 'layer' in this.initial_data ? this.initial_data.layer : null;
|
||||
this.image = this.initial_data['original_filename'];
|
||||
this.image_content = null;
|
||||
this.show_image_export = (! 'engine' in this.initial_data) || ! ['google', 'bing'].includes(this.initial_data['engine']);
|
||||
this.error = '';
|
||||
|
||||
function mapChangeBackgroundCancel() {
|
||||
$("#mapBackgroundCancel").hide();
|
||||
$("#mapBackgroundSelect").val(null);
|
||||
}
|
||||
setCustomMapBackground('custom-map', this.type, this.initial_data);
|
||||
// stop map interaction
|
||||
document.getElementById('custom-map-bg-geo-map').style.zIndex = '1';
|
||||
const leaflet = get_map('custom-map-bg-geo-map');
|
||||
if (leaflet) {
|
||||
disable_map_interaction(leaflet)
|
||||
leaflet.off('zoomend');
|
||||
leaflet.off('moveend');
|
||||
leaflet.off('baselayerchange');
|
||||
leaflet.setView(L.latLng(this.lat, this.lng), this.zoom);
|
||||
}
|
||||
},
|
||||
setImage(event) {
|
||||
this.image_content = event.target.files[0];
|
||||
},
|
||||
clearImage() {
|
||||
this.image = null;
|
||||
this.image_content = null;
|
||||
},
|
||||
setMapAsImage() {
|
||||
setCustomMapBackground('custom-map', this.type, this.initial_data);
|
||||
this.saving_map_as_image = true;
|
||||
leafletImage(get_map('custom-map-bg-geo-map'), (err, canvas) => {
|
||||
if (! canvas) {
|
||||
this.error = err;
|
||||
return;
|
||||
}
|
||||
|
||||
function mapClearBackground() {
|
||||
if($('#mapBackgroundClearVal').val()) {
|
||||
$('#mapBackgroundClear').text('{{ __('map.custom.edit.bg.clear_background') }}');
|
||||
$('#mapBackgroundClearVal').val('');
|
||||
} else {
|
||||
$('#mapBackgroundClear').text('{{ __('map.custom.edit.bg.keep_background') }}');
|
||||
$('#mapBackgroundClearVal').val('clear');
|
||||
this.type = 'image';
|
||||
this.image = 'geo-map.jpg';
|
||||
canvas.toBlob((blob) => this.image_content = blob, 'image/jpeg', 0.5);
|
||||
|
||||
this.saving_map_as_image = false;
|
||||
});
|
||||
},
|
||||
saveBackground() {
|
||||
if (this.type === 'image' && ! this.image_content) {
|
||||
// change to none type when saving bg image with no file
|
||||
// helps with mental work flow of clicking clear image -> save.
|
||||
this.type = 'none';
|
||||
}
|
||||
|
||||
let fd = new FormData();
|
||||
fd.append('type', this.type);
|
||||
if (this.type === 'color') {
|
||||
fd.append('color', this.color);
|
||||
} else if (this.type === 'image') {
|
||||
fd.append('image', this.image_content, this.image);
|
||||
}
|
||||
if (this.type === 'map' || this.image === 'geo-map.png') {
|
||||
// include map data when we converted a map to a static image
|
||||
fd.append('lat', this.lat);
|
||||
fd.append('lng', this.lng);
|
||||
fd.append('zoom', this.zoom);
|
||||
fd.append('layer', this.layer);
|
||||
}
|
||||
|
||||
fetch({{ Js::from(route('maps.custom.background.save', ['map' => $map_id])) }}, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'X-CSRF-TOKEN': document.head.querySelector('meta[name=\'csrf-token\']').content
|
||||
},
|
||||
body: fd
|
||||
}).then((response) => {
|
||||
if (response.status === 413) {
|
||||
this.error = response.statusText;
|
||||
return;
|
||||
}
|
||||
|
||||
response.json().then(data => {
|
||||
if (data.message) {
|
||||
this.error = data.message;
|
||||
} else {
|
||||
setCustomMapBackground('custom-map', data.bgtype, data.bgdata);
|
||||
this.initial_type = data.bgtype;
|
||||
this.initial_data = data.bgdata;
|
||||
|
||||
// update jquery code
|
||||
if (bgtype) {
|
||||
bgtype = data.bgtype;
|
||||
}
|
||||
if (bgdata) {
|
||||
bgdata = data.bgdata;
|
||||
}
|
||||
|
||||
this.closeBackgroundModal();
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
this.error = 'Ooops! Something went wrong!'
|
||||
});
|
||||
},
|
||||
adjustMap() {
|
||||
let leaflet = init_map('custom-map-bg-geo-map', this.initial_data);
|
||||
let adjustValues = () => {
|
||||
const center = leaflet.getCenter();
|
||||
this.lat = center.lat;
|
||||
this.lng = center.lng;
|
||||
this.zoom = leaflet.getZoom();
|
||||
}
|
||||
let layerChange = (event) => {this.layer = event.name};
|
||||
leaflet._container.style.zIndex = '3';
|
||||
enable_map_interaction(leaflet);
|
||||
leaflet.on({
|
||||
zoomend: adjustValues,
|
||||
moveend: adjustValues,
|
||||
baselayerchange: layerChange,
|
||||
});
|
||||
startBackgroundMapAdjust();
|
||||
$('#bgModal').modal('hide');
|
||||
},
|
||||
closeBackgroundModal() {
|
||||
$('#bgModal').modal('hide');
|
||||
this.resetBackground();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function editMapBackgroundCancel() {
|
||||
$('#mapBackgroundClear').text('{{ __('map.custom.edit.bg.clear_background') }}');
|
||||
$('#mapBackgroundClearVal').val('');
|
||||
$("#mapBackgroundCancel").hide();
|
||||
$("#mapBackgroundSelect").val(null);
|
||||
$('#bgModal').modal('hide');
|
||||
}
|
||||
|
||||
function saveMapBackground() {
|
||||
$("#map-savebgButton").attr('disabled','disabled');
|
||||
$("#savebg-alert").text('{{ __('map.custom.edit.bg.saving') }}');
|
||||
$("#savebg-alert").attr("class", "col-sm-12 alert alert-info");
|
||||
|
||||
var clearbackground = $('#mapBackgroundClearVal').val() ? 1 : 0;
|
||||
var newbackground = $('#mapBackgroundSelect').prop('files').length ? $('#mapBackgroundSelect').prop('files')[0] : '';
|
||||
|
||||
var url = '{{ route('maps.custom.background.save', ['map' => $map_id]) }}';
|
||||
var fd = new FormData();
|
||||
fd.append('bgclear', clearbackground);
|
||||
fd.append('bgimage', newbackground);
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
data: fd,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
type: 'POST'
|
||||
}).done(function (data, status, resp) {
|
||||
canvas = $("#custom-map").children()[0].canvas;
|
||||
if(data['bgimage']) {
|
||||
$(canvas).css('background-image','url({{ route('maps.custom.background', ['map' => $map_id]) }}?ver=' + data['bgversion'] + ')').css('background-size', 'cover');
|
||||
bgimage = true;
|
||||
} else {
|
||||
$(canvas).css('background-image','');
|
||||
bgimage = false;
|
||||
}
|
||||
$("#savebg-alert").attr("class", "col-sm-12");
|
||||
$("#savebg-alert").text("");
|
||||
editMapBackgroundCancel();
|
||||
}).fail(function (resp, status, error) {
|
||||
var data = resp.responseJSON;
|
||||
if (data['message']) {
|
||||
let alert_content = $("#savebg-alert");
|
||||
alert_content.text(data['message']);
|
||||
alert_content.attr("class", "col-sm-12 alert alert-danger");
|
||||
} else {
|
||||
let alert_content = $("#savebg-alert");
|
||||
alert_content.text('{{ __('map.custom.edit.bg.save_error', ['code' => '?']) }}'.replace('?', resp.status));
|
||||
alert_content.attr("class", "col-sm-12 alert alert-danger");
|
||||
}
|
||||
}).always(function (resp, status, error) {
|
||||
$("#map-savebgButton").removeAttr('disabled');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
@@ -13,10 +13,11 @@
|
||||
<div class="container-fluid">
|
||||
<div class="row" id="control-row">
|
||||
<div class="col-md-5">
|
||||
<button type=button value="mapedit" id="map-editButton" class="btn btn-primary" onclick="editMapSettings();">{{ __('map.custom.edit.map.edit') }}</button>
|
||||
<button type=button value="mapbg" id="map-bgButton" class="btn btn-primary" onclick="editMapBackground();">{{ __('map.custom.edit.bg.title') }}</button>
|
||||
<button type=button value="editnodedefaults" id="map-nodeDefaultsButton" class="btn btn-primary" onclick="editNodeDefaults();">{{ __('map.custom.edit.node.edit_defaults') }}</button>
|
||||
<button type=button value="editedgedefaults" id="map-edgeDefaultsButton" class="btn btn-primary" onclick="editEdgeDefaults();">{{ __('map.custom.edit.edge.edit_defaults') }}</button>
|
||||
<button type=button value="mapedit" id="map-editButton" class="btn btn-primary" onclick="editMapSettings()">{{ __('map.custom.edit.map.edit') }}</button>
|
||||
<button type=button value="mapbg" id="map-bgButton" class="btn btn-primary" onclick="editMapBackground()">{{ __('map.custom.edit.bg.title') }}</button>
|
||||
<button type=button value="mapbg" id="map-bgEndAdjustButton" class="btn btn-primary" onclick="endBackgroundMapAdjust()" style="display:none">{{ __('map.custom.edit.bg.adjust_map_finish') }}</button>
|
||||
<button type=button value="editnodedefaults" id="map-nodeDefaultsButton" class="btn btn-primary" onclick="editNodeDefaults()">{{ __('map.custom.edit.node.edit_defaults') }}</button>
|
||||
<button type=button value="editedgedefaults" id="map-edgeDefaultsButton" class="btn btn-primary" onclick="editEdgeDefaults()">{{ __('map.custom.edit.edge.edit_defaults') }}</button>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<center>
|
||||
@@ -41,9 +42,15 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<center>
|
||||
<div id="custom-map"></div>
|
||||
</center>
|
||||
<div id="map-container">
|
||||
<div id="custom-map"></div>
|
||||
<x-geo-map id="custom-map-bg-geo-map"
|
||||
:init="$background_type == 'map'"
|
||||
:width="$map_conf['width']"
|
||||
:height="$map_conf['height']"
|
||||
:config="$background_config"
|
||||
readonly
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -51,11 +58,35 @@
|
||||
|
||||
@section('javascript')
|
||||
<script type="text/javascript" src="{{ asset('js/vis.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ asset('js/leaflet.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ asset('js/L.Control.Locate.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ asset('js/leaflet-image.js') }}"></script>
|
||||
@endsection
|
||||
|
||||
@push('styles')
|
||||
<style>
|
||||
#map-container {
|
||||
display: grid;
|
||||
grid-template: 1fr / 1fr;
|
||||
place-items: center;
|
||||
}
|
||||
#custom-map {
|
||||
grid-column: 1 / 1;
|
||||
grid-row: 1 / 1;
|
||||
z-index: 2;
|
||||
}
|
||||
#custom-map-bg-geo-map {
|
||||
grid-column: 1 / 1;
|
||||
grid-row: 1 / 1;
|
||||
z-index: 1;
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('scripts')
|
||||
<script type="text/javascript">
|
||||
var bgimage = {{ $background ? "true" : "false" }};
|
||||
var bgtype = {{ Js::from($background_type) }};
|
||||
var bgdata = {{ Js::from($background_config) }};
|
||||
var network;
|
||||
var network_height;
|
||||
var network_width;
|
||||
@@ -64,6 +95,7 @@
|
||||
var edge_nodes_map = [];
|
||||
var node_device_map = {};
|
||||
var custom_image_base = "{{ $base_url }}images/custommap/icons/";
|
||||
var network_options = {{ Js::from($map_conf) }}
|
||||
|
||||
function edgeNodesRemove(nm_id, edgeid) {
|
||||
// Remove old item from map if it exists
|
||||
@@ -195,7 +227,7 @@
|
||||
network_edges.flush();
|
||||
|
||||
var container = document.getElementById('custom-map');
|
||||
var options = {!! json_encode($map_conf) !!};
|
||||
var options = network_options;
|
||||
|
||||
// Set up the triggers for adding and editing map items
|
||||
options['manipulation']['addNode'] = function (data, callback) {
|
||||
@@ -280,17 +312,15 @@
|
||||
};
|
||||
|
||||
network = new vis.Network(container, {nodes: network_nodes, edges: network_edges, stabilize: true}, options);
|
||||
|
||||
// width/height might be % get values in pixels
|
||||
network_height = $($(container).children(".vis-network")[0]).height();
|
||||
network_width = $($(container).children(".vis-network")[0]).width();
|
||||
var centreY = parseInt(network_height / 2);
|
||||
var centreX = parseInt(network_width / 2);
|
||||
|
||||
var centreY = Math.round(network_height / 2);
|
||||
var centreX = Math.round(network_width / 2);
|
||||
network.moveTo({position: {x: centreX, y: centreY}, scale: 1});
|
||||
|
||||
if(bgimage) {
|
||||
canvas = $("#custom-map").children()[0].canvas;
|
||||
$(canvas).css('background-image','url({{ route('maps.custom.background', ['map' => $map_id]) }}?ver={{$bgversion}})').css('background-size', 'cover');
|
||||
}
|
||||
setCustomMapBackground('custom-map', bgtype, bgdata);
|
||||
|
||||
network.on('doubleClick', function (properties) {
|
||||
edge_id = null;
|
||||
@@ -453,6 +483,11 @@
|
||||
reverse_arrows = parseInt(data.reverse_arrows);
|
||||
redrawLegend();
|
||||
|
||||
// update dimensions
|
||||
network_options.width = data.width;
|
||||
network_options.height = data.height;
|
||||
$("#custom-map-bg-geo-map").css('width', data.width).css('height', data.height);
|
||||
|
||||
// Re-create the network because network.setSize() blanks out the map
|
||||
CreateNetwork();
|
||||
|
||||
@@ -529,15 +564,7 @@
|
||||
}
|
||||
|
||||
function editMapBackground() {
|
||||
$("#mapBackgroundCancel").hide();
|
||||
$("#mapBackgroundSelect").val(null);
|
||||
|
||||
if($("#custom-map").children()[0].canvas.style.backgroundImage) {
|
||||
$("#mapBackgroundClearRow").show();
|
||||
} else {
|
||||
$("#mapBackgroundClearRow").hide();
|
||||
}
|
||||
$('#bgModal').modal({backdrop: 'static', keyboard: false}, 'show');
|
||||
$('#bgModal').modal('show');
|
||||
}
|
||||
|
||||
function nodeStyleChange() {
|
||||
@@ -1192,6 +1219,23 @@
|
||||
}).observe(targetNode, {attributes: false, childList: true, subtree: false});
|
||||
}
|
||||
|
||||
function startBackgroundMapAdjust() {
|
||||
$('#map-editButton,#map-nodeDefaultsButton,#map-edgeDefaultsButton,#map-bgButton').hide();
|
||||
$('#map-bgEndAdjustButton').show();
|
||||
}
|
||||
|
||||
function endBackgroundMapAdjust() {
|
||||
$('#map-editButton,#map-nodeDefaultsButton,#map-edgeDefaultsButton,#map-bgButton').show();
|
||||
$('#map-bgEndAdjustButton').hide();
|
||||
|
||||
document.getElementById('custom-map-bg-geo-map').style.zIndex = '1';
|
||||
const leaflet = get_map('custom-map-bg-geo-map');
|
||||
if (leaflet) {
|
||||
disable_map_interaction(leaflet)
|
||||
}
|
||||
editMapBackground();
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
init_select2('#devicesearch', 'device', {limit: 100}, '', '{{ __('map.custom.edit.node.device_select') }}', {dropdownParent: $('#nodeModal')});
|
||||
$("#devicesearch").on("select2:select", nodeDeviceSelect);
|
||||
|
@@ -11,9 +11,16 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<center>
|
||||
<div id="map-container">
|
||||
<div id="custom-map"></div>
|
||||
</center>
|
||||
<x-geo-map id="custom-map-bg-geo-map"
|
||||
:init="$background_type == 'map'"
|
||||
:width="$map_conf['width']"
|
||||
:height="$map_conf['height']"
|
||||
:config="$background_config"
|
||||
readonly
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -21,11 +28,34 @@
|
||||
|
||||
@section('javascript')
|
||||
<script type="text/javascript" src="{{ asset('js/vis.min.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ asset('js/leaflet.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ asset('js/L.Control.Locate.min.js') }}"></script>
|
||||
@endsection
|
||||
|
||||
@push('styles')
|
||||
<style>
|
||||
#map-container {
|
||||
display: grid;
|
||||
grid-template: 1fr / 1fr;
|
||||
place-items: center;
|
||||
}
|
||||
#custom-map {
|
||||
grid-column: 1 / 1;
|
||||
grid-row: 1 / 1;
|
||||
z-index: 2;
|
||||
}
|
||||
#custom-map-bg-geo-map {
|
||||
grid-column: 1 / 1;
|
||||
grid-row: 1 / 1;
|
||||
z-index: 1;
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@section('scripts')
|
||||
<script type="text/javascript">
|
||||
var bgimage = {{ $background ? "true" : "false" }};
|
||||
var bgtype = {{ Js::from($background_type) }};
|
||||
var bgdata = {{ Js::from($background_config) }};
|
||||
var screenshot = {{ $screenshot ? "true" : "false" }};
|
||||
var reverse_arrows = {{$reverse_arrows}};
|
||||
var legend = @json($legend);
|
||||
@@ -38,6 +68,7 @@
|
||||
var node_device_map = {};
|
||||
var node_link_map = {};
|
||||
var custom_image_base = "{{ $base_url }}images/custommap/icons/";
|
||||
var network_options = {{ Js::from($map_conf) }};
|
||||
|
||||
function legendPctColour(pct) {
|
||||
if (pct < 0) {
|
||||
@@ -99,20 +130,16 @@
|
||||
network_edges.flush();
|
||||
|
||||
var container = document.getElementById('custom-map');
|
||||
var options = {!! json_encode($map_conf) !!};
|
||||
network = new vis.Network(container, {nodes: network_nodes, edges: network_edges, stabilize: true}, network_options);
|
||||
|
||||
network = new vis.Network(container, {nodes: network_nodes, edges: network_edges, stabilize: true}, options);
|
||||
// width/height might be % get values in pixels
|
||||
network_height = $($(container).children(".vis-network")[0]).height();
|
||||
network_width = $($(container).children(".vis-network")[0]).width();
|
||||
var centreY = parseInt(network_height / 2);
|
||||
var centreX = parseInt(network_width / 2);
|
||||
|
||||
var centreY = Math.round(network_height / 2);
|
||||
var centreX = Math.round(network_width / 2);
|
||||
network.moveTo({position: {x: centreX, y: centreY}, scale: 1});
|
||||
|
||||
if(bgimage) {
|
||||
canvas = $("#custom-map").children()[0].canvas;
|
||||
$(canvas).css('background-image','url({{ route('maps.custom.background', ['map' => $map_id]) }}?ver={{$bgversion}})').css('background-size', 'cover');
|
||||
}
|
||||
setCustomMapBackground('custom-map', bgtype, bgdata);
|
||||
|
||||
network.on('doubleClick', function (properties) {
|
||||
edge_id = null;
|
||||
|
Reference in New Issue
Block a user