From d8aa2feac3f48b4f693aed7a4a0f14b28fd29f5b Mon Sep 17 00:00:00 2001 From: Viktor Kovacs Date: Thu, 1 Apr 2021 15:04:17 +0200 Subject: [PATCH] Separate entities for url parameter handling. --- source/viewer/domviewer.js | 21 +++--- source/viewer/urlutils.js | 134 ++++++++++++++++++++++++++++++++++++ test/tests/urlutils_test.js | 43 ++++++++++++ tools/config.json | 3 +- tools/update_includes.py | 2 +- website/embed.html | 1 + website/index.html | 1 + website/o3dv/dialogs.js | 2 +- website/o3dv/embed.js | 2 +- website/o3dv/hashhandler.js | 39 ++--------- website/o3dv/utils.js | 17 ----- website/o3dv/website.js | 4 -- 12 files changed, 199 insertions(+), 70 deletions(-) create mode 100644 source/viewer/urlutils.js create mode 100644 test/tests/urlutils_test.js diff --git a/source/viewer/domviewer.js b/source/viewer/domviewer.js index 71adffe..45f9c90 100644 --- a/source/viewer/domviewer.js +++ b/source/viewer/domviewer.js @@ -47,25 +47,20 @@ OV.Init3DViewerElements = function () }, }); - let model = element.getAttribute ('model'); - if (!model) { + let modelParams = element.getAttribute ('model'); + if (!modelParams) { return; } - let modelUrls = model.split (','); - if (modelUrls.length === 0) { + let modelUrls = OV.UrlParamConverter.UrlParameterToModelUrls (modelParams); + if (modelUrls === null || modelUrls.length === 0) { return; } - let camera = element.getAttribute ('camera'); - if (camera) { - let cameraParams = camera.split (','); - if (cameraParams.length === 9) { - let camera = new OV.Camera ( - new OV.Coord3D (parseFloat (cameraParams[0]), parseFloat (cameraParams[1]), parseFloat (cameraParams[2])), - new OV.Coord3D (parseFloat (cameraParams[3]), parseFloat (cameraParams[4]), parseFloat (cameraParams[5])), - new OV.Coord3D (parseFloat (cameraParams[6]), parseFloat (cameraParams[7]), parseFloat (cameraParams[8])) - ); + let cameraParams = element.getAttribute ('camera'); + if (cameraParams) { + let camera = OV.UrlParamConverter.UrlParameterToCamera (cameraParams); + if (camera !== null) { viewer.SetCamera (camera); } } diff --git a/source/viewer/urlutils.js b/source/viewer/urlutils.js new file mode 100644 index 0000000..98c2587 --- /dev/null +++ b/source/viewer/urlutils.js @@ -0,0 +1,134 @@ +OV.UrlParamConverter = +{ + CameraToUrlParameter : function (camera) + { + if (camera === null) { + return null; + } + let precision = 5; + let cameraParameters = [ + camera.eye.x.toPrecision (precision), camera.eye.y.toPrecision (precision), camera.eye.z.toPrecision (precision), + camera.center.x.toPrecision (precision), camera.center.y.toPrecision (precision), camera.center.z.toPrecision (precision), + camera.up.x.toPrecision (precision), camera.up.y.toPrecision (precision), camera.up.z.toPrecision (precision) + ].join (','); + return cameraParameters; + }, + + UrlParameterToCamera : function (urlParam) + { + if (urlParam === null || urlParam.length === 0) { + return null; + } + let paramParts = urlParam.split (','); + if (paramParts.length !== 9) { + return null; + } + let camera = new OV.Camera ( + new OV.Coord3D (parseFloat (paramParts[0]), parseFloat (paramParts[1]), parseFloat (paramParts[2])), + new OV.Coord3D (parseFloat (paramParts[3]), parseFloat (paramParts[4]), parseFloat (paramParts[5])), + new OV.Coord3D (parseFloat (paramParts[6]), parseFloat (paramParts[7]), parseFloat (paramParts[8])) + ); + return camera; + }, + + ModelUrlsToUrlParameter : function (urls) + { + if (urls === null) { + return null; + } + return urls.join (','); + }, + + UrlParameterToModelUrls : function (urlParam) + { + if (urlParam === null || urlParam.length === 0) { + return null; + } + return urlParam.split (','); + } +}; + +OV.UrlParamBuilder = class +{ + constructor () + { + this.urlParams = ''; + } + + AddModelUrls (urls) + { + this.AddUrlPart ('model', OV.UrlParamConverter.ModelUrlsToUrlParameter (urls)); + return this; + } + + AddCamera (camera) + { + this.AddUrlPart ('camera', OV.UrlParamConverter.CameraToUrlParameter (camera)); + return this; + } + + AddUrlPart (keyword, urlPart) + { + if (keyword === null || urlPart === null) { + return; + } + if (this.urlParams.length > 0) { + this.urlParams += '$'; + } + this.urlParams += keyword + '=' + urlPart; + } + + GetUrlParams () + { + return this.urlParams; + } +}; + +OV.UrlParamParser = class +{ + constructor (urlParams) + { + this.urlParams = urlParams; + } + + GetModelUrls () + { + // detect legacy links + if (this.urlParams.indexOf ('=') === -1) { + return this.urlParams.split (','); + } + + let keywordParams = this.GetKeywordParams ('model'); + return OV.UrlParamConverter.UrlParameterToModelUrls (keywordParams); + } + + GetCamera () + { + let keywordParams = this.GetKeywordParams ('camera'); + return OV.UrlParamConverter.UrlParameterToCamera (keywordParams); + } + + GetKeywordParams (keyword) + { + if (this.urlParams === null || this.urlParams.length === 0) { + return null; + } + let keywordToken = keyword + '='; + let urlParts = this.urlParams.split ('$'); + for (let i = 0; i < urlParts.length; i++) { + let urlPart = urlParts[i]; + if (urlPart.startsWith (keywordToken)) { + return urlPart.substr (keywordToken.length); + } + } + return null; + } +}; + +OV.CreateUrlParameters = function (urls, camera) +{ + let builder = new OV.UrlParamBuilder (); + builder.AddModelUrls (urls); + builder.AddCamera (camera); + return builder.GetUrlParams (); +}; diff --git a/test/tests/urlutils_test.js b/test/tests/urlutils_test.js new file mode 100644 index 0000000..6ed14e0 --- /dev/null +++ b/test/tests/urlutils_test.js @@ -0,0 +1,43 @@ +var assert = require ('assert'); + +describe ('Url Utils', function () { + it ('Url builder', function () { + let modelUrls = ['a.txt', 'b.txt']; + let camera = new OV.Camera ( + new OV.Coord3D (1.0, 1.0, 1.0), + new OV.Coord3D (0.0, 0.0, 0.0), + new OV.Coord3D (0.0, 0.0, 1.0) + ); + let urlParams1 = new OV.UrlParamBuilder ().AddModelUrls (modelUrls).GetUrlParams (); + let urlParams2 = new OV.UrlParamBuilder ().AddCamera (camera).GetUrlParams (); + let urlParams3 = new OV.UrlParamBuilder ().AddModelUrls (modelUrls).AddCamera (camera).GetUrlParams (); + assert.strictEqual (urlParams1, 'model=a.txt,b.txt'); + assert.strictEqual (urlParams2, 'camera=1.0000,1.0000,1.0000,0.0000,0.0000,0.0000,0.0000,0.0000,1.0000'); + assert.strictEqual (urlParams3, 'model=a.txt,b.txt$camera=1.0000,1.0000,1.0000,0.0000,0.0000,0.0000,0.0000,0.0000,1.0000'); + }); + + it ('Url parser', function () { + let modelUrls = ['a.txt', 'b.txt']; + let camera = new OV.Camera ( + new OV.Coord3D (1.0, 1.0, 1.0), + new OV.Coord3D (0.0, 0.0, 0.0), + new OV.Coord3D (0.0, 0.0, 1.0) + ); + let urlParamsLegacy = 'a.txt,b.txt'; + let urlParams1 = 'model=a.txt,b.txt'; + let urlParams2 = 'camera=1.0000,1.0000,1.0000,0.0000,0.0000,0.0000,0.0000,0.0000,1.0000'; + let urlParams3 = 'model=a.txt,b.txt$camera=1.0000,1.0000,1.0000,0.0000,0.0000,0.0000,0.0000,0.0000,1.0000'; + let parserLegacy = new OV.UrlParamParser (urlParamsLegacy); + assert.deepStrictEqual (parserLegacy.GetModelUrls (), modelUrls); + assert.deepStrictEqual (parserLegacy.GetCamera (), null); + let parser1 = new OV.UrlParamParser (urlParams1); + assert.deepStrictEqual (parser1.GetModelUrls (), modelUrls); + assert.deepStrictEqual (parser1.GetCamera (), null); + let parser2 = new OV.UrlParamParser (urlParams2); + assert.deepStrictEqual (parser2.GetModelUrls (), null); + assert.deepStrictEqual (parser2.GetCamera (), camera); + let parser3 = new OV.UrlParamParser (urlParams3); + assert.deepStrictEqual (parser3.GetModelUrls (), modelUrls); + assert.deepStrictEqual (parser3.GetCamera (), camera); + }); +}); diff --git a/tools/config.json b/tools/config.json index 348826c..722cd6b 100644 --- a/tools/config.json +++ b/tools/config.json @@ -45,7 +45,8 @@ "source/viewer/domutils.js", "source/viewer/navigation.js", "source/viewer/viewer.js", - "source/viewer/domviewer.js" + "source/viewer/domviewer.js", + "source/viewer/urlutils.js" ], "website_files" : [ "website/o3dv/utils.js", diff --git a/tools/update_includes.py b/tools/update_includes.py index 842c25d..3288d41 100644 --- a/tools/update_includes.py +++ b/tools/update_includes.py @@ -19,7 +19,7 @@ def Main (argv): config = json.load (configJson) rootDir = os.path.abspath ('..') - for htmlFileName in ['index.html', 'embed.html', 'embed_selfhost.html']: + for htmlFileName in ['index.html', 'embed.html']: htmlFilePath = os.path.join (rootDir, 'website', htmlFileName) replacer = Tools.TokenReplacer (htmlFilePath, True) libFiles = Tools.CreateFileList (config['lib_files'], 'libs/', '../libs/') diff --git a/website/embed.html b/website/embed.html index 2a2ab88..1a3c815 100644 --- a/website/embed.html +++ b/website/embed.html @@ -59,6 +59,7 @@ + diff --git a/website/index.html b/website/index.html index 57696b5..064aa4d 100644 --- a/website/index.html +++ b/website/index.html @@ -59,6 +59,7 @@ + diff --git a/website/o3dv/dialogs.js b/website/o3dv/dialogs.js index 51970f4..a6acf52 100644 --- a/website/o3dv/dialogs.js +++ b/website/o3dv/dialogs.js @@ -319,7 +319,7 @@ OV.ShowEmbeddingDialog = function (importer, camera) embeddingCode += ''; embeddingCode += ''; diff --git a/website/o3dv/embed.js b/website/o3dv/embed.js index 1efcbcc..9659904 100644 --- a/website/o3dv/embed.js +++ b/website/o3dv/embed.js @@ -25,7 +25,7 @@ OV.Embed = class this.viewer.SetCamera (camera); } this.modelLoader.LoadFromUrlList (urls); - let hashParameters = OV.CreateHashParameters (urls, camera); + let hashParameters = OV.CreateUrlParameters (urls, null); let websiteUrl = this.parameters.websiteLinkDiv.attr ('href') + '#' + hashParameters; this.parameters.websiteLinkDiv.attr ('href', websiteUrl); } diff --git a/website/o3dv/hashhandler.js b/website/o3dv/hashhandler.js index 4714e6f..b7c9eaf 100644 --- a/website/o3dv/hashhandler.js +++ b/website/o3dv/hashhandler.js @@ -30,46 +30,21 @@ OV.HashHandler = class GetCameraFromHash () { - let parameters = this.GetFromHash ('camera'); - if (parameters === null) { - return null; - } - let splitted = parameters.split (','); - if (splitted.length !== 9) { - return null; - } - let camera = new OV.Camera ( - new OV.Coord3D (parseFloat (splitted[0]), parseFloat (splitted[1]), parseFloat (splitted[2])), - new OV.Coord3D (parseFloat (splitted[3]), parseFloat (splitted[4]), parseFloat (splitted[5])), - new OV.Coord3D (parseFloat (splitted[6]), parseFloat (splitted[7]), parseFloat (splitted[8])) - ); - return camera; + let parser = new OV.UrlParamParser (this.GetHash ()); + return parser.GetCamera (); } GetModelFilesFromHash () { - let hash = this.GetHash (); - if (hash.length === 0) { - return null; - } - - // detect legacy links - let modelKeyword = 'model'; - let keywordToken = modelKeyword + '='; - if (hash.indexOf (keywordToken) === -1) { - return hash.split (','); - } - - let fileList = this.GetFromHash (modelKeyword); - if (fileList === null) { - return null; - } - return fileList.split (','); + let parser = new OV.UrlParamParser (this.GetHash ()); + return parser.GetModelUrls (); } SetModelFilesToHash (files) { - this.SetHash ('model=' + files.join (',')); + let builder = new OV.UrlParamBuilder (); + builder.AddModelUrls (files); + this.SetHash (builder.GetUrlParams ()); } GetFromHash (keyword) diff --git a/website/o3dv/utils.js b/website/o3dv/utils.js index e1c3836..0e753f2 100644 --- a/website/o3dv/utils.js +++ b/website/o3dv/utils.js @@ -120,20 +120,3 @@ OV.CreateIconButton = function (iconName, hoverIconName, title, link) } return buttonLink; }; - -OV.CreateHashParameters = function (urls, camera) -{ - let hashParameters = ''; - let urlsHash = urls.join (','); - hashParameters += 'model=' + urlsHash; - if (camera !== null) { - let precision = 5; - let cameraHash = [ - camera.eye.x.toPrecision (precision), camera.eye.y.toPrecision (precision), camera.eye.z.toPrecision (precision), - camera.center.x.toPrecision (precision), camera.center.y.toPrecision (precision), camera.center.z.toPrecision (precision), - camera.up.x.toPrecision (precision), camera.up.y.toPrecision (precision), camera.up.z.toPrecision (precision) - ].join (','); - hashParameters += '$camera=' + cameraHash; - } - return hashParameters; -}; diff --git a/website/o3dv/website.js b/website/o3dv/website.js index bbf9cf3..8c14d64 100644 --- a/website/o3dv/website.js +++ b/website/o3dv/website.js @@ -181,10 +181,6 @@ OV.Website = class if (urls === null) { return; } - let camera = this.hashHandler.GetCameraFromHash (); - if (camera !== null) { - this.viewer.SetCamera (camera); - } this.LoadModelFromUrlList (urls); } else { this.ClearModel ();