Home Reference Source Repository

magicad/magicad.js

  1. import base64 from '../base64/base64';
  2. import {
  3. _addAuthToken,
  4. _extendQModelOptions,
  5. _setDiagramImages,
  6. _getResourceQueryUrl,
  7. _replaceOptionsFromBase64EncodedUrl
  8. } from './magicad-fn';
  9. import OidcAuthService from '../auth/oidcauth';
  10. import UserManagerSettingsFactory from '../auth/oidc-clientsettings-factory';
  11. import SigninService from '../auth/signin';
  12. import X3DViewService from '../x3dviewservice/X3DViewService.js';
  13. import axios from 'axios';
  14. import utils from '../utils';
  15.  
  16. export default class MagiCAD {
  17. /**
  18. * @private
  19. * @param {*} fingerprintService
  20. * @param {*} diagramService
  21. * @param {*} ahuCalculationService
  22. * @param {*} signinService (optional) Could be created also with init() function
  23. * @param {*} x3dViewService (optional) Could be created also with init() function
  24. */
  25. constructor(fingerprintService, diagramService, ahuCalculationService, signinService, x3dViewService) {
  26. /**
  27. * @private
  28. */
  29. this.fingerprintService = fingerprintService;
  30. /**
  31. * @private
  32. */
  33. this.diagramService = diagramService;
  34. /**
  35. * @private
  36. */
  37. this.ahuCalculationService = ahuCalculationService;
  38. /**
  39. * @private
  40. */
  41. this.signinService = signinService;
  42. /**
  43. * @private
  44. */
  45. this.x3dViewService = x3dViewService;
  46. /**
  47. * @private
  48. */
  49. this.onFindOptimalSpeed = undefined;
  50. /**
  51. * @private
  52. */
  53. this.onGetDpTot = undefined;
  54. /**
  55. * @private
  56. */
  57. this.onLoad = undefined;
  58. /**
  59. * @private
  60. */
  61. this.onLoadError = undefined;
  62. /**
  63. * @private
  64. */
  65. this.onRenderX3D = undefined;
  66. }
  67.  
  68. /**
  69. * Initialize MagiCAD Widget SDK
  70. *
  71. * @param {object} options <pre>Example object:
  72. * {
  73. * client_id: 'your_client_id',
  74. * popup_redirect_uri: 'callback file url when using popup signin method'
  75. * redirect_uri: 'callback file url when using redirect signin method' // if given, popup_redirect_uri will be ignored browser redirection is being used instead of popup
  76. * post_logout_redirect_uri: 'callback file url to direct the user to after successful sign-out'
  77. * enableX3D: true, // default value is true and x3dom library will be loaded
  78. * onLoadUser: function(user) { console.log(user.username); }, // Set event handler to get signed in user if any exists e.g. case when page refreshed
  79. * onSignin: function(user) { console.log(user.username); }, // Set event handler to perform some action on user signin
  80. * onSignout: function() { console.log('user signed out'); }, // Set event handler to perform some action on user signout
  81. * onRenderX3D: function() { console.log('x3d rendered'); }, // Set event handler to perform some action after rendering x3d image
  82. * onGetDpTot function(result) { console.log(result); }, // Set event handler to perform some action with calculation result
  83. * onFindOptimalSpeed: function(result) { console.log(result); } // Set event handler to perform some action with calculation result
  84. * }
  85. * </pre>
  86. * @param {object} context (optional)
  87. */
  88. init(options, context) {
  89. // If not given already in constructor
  90. if (!this.signinService) {
  91. let factory = new UserManagerSettingsFactory(options);
  92. let oidcAuthService = new OidcAuthService(factory);
  93. this.signinService = new SigninService(oidcAuthService);
  94. }
  95. if (!this.signinService)
  96. throw "MagiCAD Widget SDK initialization failed!";
  97.  
  98. // Set X3DViewService
  99. if (options.enableX3D === undefined || options.enableX3D === null) {
  100. options.enableX3D = true; // default value if not given
  101. }
  102. // If not given already in contructor
  103. if (!this.x3dViewService)
  104. this.x3dViewService = options.enableX3D ? new X3DViewService() : undefined;
  105.  
  106. if (this.signinService) {
  107. if (typeof options.onLoadUser === 'function') {
  108. this.signinService && this.signinService.getUser()
  109. .then(user => {
  110. options.onLoadUser(user.profile);
  111. })
  112. .catch(err => {
  113. options.onLoadUser(null);
  114. });
  115. }
  116. if (typeof options.onSignin === 'function') {
  117. this.signinService.onSignin(options.onSignin);
  118. }
  119. if (typeof options.onSignout === 'function') {
  120. this.signinService.onSignout(options.onSignout);
  121. }
  122. }
  123.  
  124. if (typeof options.onLoad === 'function') {
  125. this.onLoad = options.onLoad;
  126. }
  127.  
  128. if (typeof options.onLoadError === 'function') {
  129. this.onLoadError = options.onLoadError;
  130. }
  131. if (typeof options.onRenderX3D === 'function') {
  132. this.onRenderX3D = options.onRenderX3D;
  133. }
  134. if (typeof options.onGetDpTot === 'function') {
  135. this.onGetDpTot = options.onGetDpTot;
  136. }
  137. if (typeof options.onFindOptimalSpeed === 'function') {
  138. this.onFindOptimalSpeed = options.onFindOptimalSpeed;
  139. }
  140.  
  141. if (typeof context === 'object') {
  142. context.MagiCAD = Object.assign(context.MagiCAD, this);
  143. context.MagiCAD.__proto__ = this.__proto__;
  144. }
  145. }
  146.  
  147. /**
  148. * Return information is user logged in.
  149. *
  150. * @return boolean value is used logged in
  151. */
  152. isLoggedIn() {
  153. return this.signinService && this.signinService.isLoggedIn();
  154. }
  155.  
  156. /**
  157. * Signin. Will open MagiCAD login popup.
  158. *
  159. * @return {Promise<void>}
  160. */
  161. signin() {
  162. return this.signinService && this.signinService.signin();
  163. }
  164.  
  165. /**
  166. * Signout current logged in user
  167. *
  168. * @return {Promise<void>}
  169. */
  170. signout() {
  171. return this.signinService && this.signinService.signout();
  172. }
  173.  
  174. /**
  175. * Return release info of MagiCAD Widget SDK in example Production 2.35.0
  176. */
  177. getReleaseInfo() {
  178. return `${systemconfig.ENVIRONMENT} ${systemconfig.RELEASENUMBER}`;
  179. }
  180.  
  181. /**
  182. * Load and initialize MagiCAD Cloud Javascript Library
  183. *
  184. * @param {object} options <pre>
  185. * {
  186. * productId: string,
  187. * variantQpdId: string,
  188. * articleNumber: string,
  189. * manufacturerId: string
  190. * }
  191. *
  192. * where manufacturerId and either:
  193. *
  194. * productId and variantQpdId, or
  195. * articleNumber
  196. *
  197. * is defined.
  198. * </pre>
  199. * @return {Promise<ProductData>} Successful response will contain product/variant data
  200. */
  201. load(options) {
  202. let userRequest = this.signinService && this.signinService.getUser(),
  203. fingerprintRequest = this.fingerprintService.getFingerprint();
  204. let promise = Promise.all([userRequest, fingerprintRequest]).then(([user, sessionId]) => {
  205. let baseProductUrl = systemconfig.APIURL + systemconfig.PRODUCTPATH;
  206. let productUrl;
  207. if (options.productId)
  208. productUrl = baseProductUrl + options.productId;
  209. else if (options.articleNumber && options.manufacturerId)
  210. productUrl = baseProductUrl + options.manufacturerId + '/' + encodeURI(options.articleNumber);
  211. if (options.logoContainerId)
  212. this.renderMagiCADLogo(options.logoContainerId);
  213.  
  214. return axios.get(productUrl).then((response) => {
  215. if (!response || response.status !== 200 || !response.data)
  216. return null;
  217.  
  218. // Finalize Attachments with auth tokens
  219. response.data.Attachments.forEach((val) => {
  220. val.Uri = _addAuthToken(user, sessionId, val.Uri, options.applicationId);
  221. });
  222. // Finalize DXF resources with auth tokens
  223. response.data.DxfUrl = _addAuthToken(user, sessionId, response.data.DxfUrl, options.applicationId);
  224. return response.data;
  225. }, (err) => {
  226. if (this.onLoadError)
  227. this.onLoadError(err);
  228. });
  229. });
  230. if (this.onLoad) {
  231. promise.then(this.onLoad, this.onLoadError);
  232. }
  233. return promise;
  234. }
  235.  
  236. /**
  237. * Return DXF query url
  238. *
  239. * @param {object} product The product object returned from MagiCAD.load() function
  240. * @param {object} options <pre>
  241. * {
  242. * QModelParameters: Optional QModelParameters of model, in format "L=100;D=25;W1=130...",
  243. * Filename: Optional file name and extension for the object to download, in format "example.dxf"
  244. * }
  245. * </pre>
  246. * @returns DXF url customized with given options. If invalid options object is provided, returns default DXF url, or null if no DXF URL exists
  247. */
  248. getCustomizedDxfQueryUrl(product, options){
  249. try{
  250. return _replaceOptionsFromBase64EncodedUrl(options, new URL(product.DxfUrl));
  251. }
  252. catch (e) {
  253. return null;
  254. }
  255. }
  256.  
  257. /**
  258. * Return dimension image query url
  259. *
  260. * @param {object} options <pre>
  261. * {
  262. * QModelId: Optional QModelId of model,
  263. * QModelParameters: Optional QModelParameters of model,
  264. * ViewMode: one value of { 0=Rendered, 1=DimensionLabels, 2=DimensionValues },
  265. * ViewPosition: one value of { 0=Default, 1=Front, 2=Right, 3=Left, 4=Top, 5=Bottom, 6=IsometricLeft, 7=IsometricRight }
  266. * }
  267. * @returns Dimension image url
  268. */
  269. getDimensionImageQueryUrl(options) {
  270. return _getResourceQueryUrl(options, systemconfig.DIMENSIONSIMAGEQUERYPATH);
  271. }
  272.  
  273. /**
  274. *
  275. * Return image query url
  276. *
  277. * @param {object} options <pre>
  278. * {
  279. * QModelId: Optional QModelId of model,
  280. * QModelParameters: Optional QModelParameters of model,
  281. * ViewPosition: one value of { 0=Default, 1=Front, 2=Right, 3=Left, 4=Top, 5=Bottom, 6=IsometricLeft, 7=IsometricRight }
  282. * }
  283. * @returns Image url
  284. */
  285. getImageQueryUrl(options) {
  286. return _getResourceQueryUrl(options, systemconfig.IMAGEQUERYPATH);
  287. }
  288.  
  289. /**
  290. *
  291. * Renders X3D Image container to given container
  292. *
  293. * @param {object} options <pre>
  294. * Basic example:
  295. *
  296. * {
  297. * x3dUri: location of x3d,
  298. * imageUri: location of image
  299. * containerId: identifier of the container for x3d,
  300. * }
  301. *
  302. * Or, to get 3D view with custom model parameters:
  303. * {
  304. * QModelId: the identifier of the 3D geometry (GUID format),
  305. * QModelParameters: Optional QModelParameters of model,
  306. * ViewMode: one value of { 0=Rendered, 1=DimensionLabels, 2=DimensionValues,
  307. * containerId: identifier of the container for x3d,
  308. * }
  309. *
  310. * Or, to get 3D view with product external reference and variant qpd id:
  311. * {
  312. * productId: the external reference of the product (GUID format)
  313. * variantQpdId: the qpd id of the specific variant,
  314. * containerId: identifier of the container for x3d
  315. * }
  316. *
  317. * Or, to get 3D view with custom level of detail (LOD):
  318. * {
  319. * QModelId: the identifier of the 3D geometry (GUID format),
  320. * QModelParameters: Optional QModelParameters of model,
  321. * LodLevel: one value of { 0=Preview, 1=MC LOD 200, 2=MC LOD 300, 3=MC LOD 350 },
  322. * containerId: identifier of the container for x3d,
  323. * }
  324. *
  325. * @param {boolean} update Update existing container with new image url
  326. * @return {Promise<void>} result as promise
  327. */
  328. renderX3D(options, update) {
  329. if (!this.x3dViewService) {
  330. return new Promise((resolve, reject) => {
  331. reject("Enable X3D in MagiCAD.init() function");
  332. });
  333. }
  334. let queryOptions = {
  335. containerId : (options || {}).containerId,
  336. imageUri : (options ||{}).imageUri,
  337. x3dUri : (options || {}).x3dUri
  338. };
  339. let queryObject = _extendQModelOptions(options);
  340. if (queryObject.QModelId) { // QModelId is set, override image and x3d
  341. queryOptions.x3dUri = systemconfig.APIURL + systemconfig.X3DQUERYPATH + base64.b64EncodeUnicode(JSON.stringify(queryObject));
  342. queryOptions.imageUri = systemconfig.APIURL + systemconfig.IMAGEQUERYPATH + base64.b64EncodeUnicode(JSON.stringify(queryObject));
  343. }
  344. else if (queryObject.variantQpdId && queryObject.productId) { // Product external reference and variant QpdId is set, override image and x3d
  345. queryOptions.x3dUri = systemconfig.APIURL +
  346. systemconfig.X3DBYQPDIDPATH
  347. .replace('{productId}', queryObject.productId)
  348. .replace('{encodedVariantQpdId}', base64.b64EncodeUnicode(queryObject.variantQpdId));
  349. queryOptions.imageUri = systemconfig.APIURL +
  350. systemconfig.IMAGEBYQPDIDPATH
  351. .replace('{productId}', queryObject.productId)
  352. .replace('{encodedVariantQpdId}', base64.b64EncodeUnicode(queryObject.variantQpdId));
  353. }
  354. return this.x3dViewService.loadX3D(queryOptions, update).then(result => {
  355. if (this.onRenderX3D) this.onRenderX3D();
  356. return result;
  357. });
  358.  
  359. }
  360.  
  361. /**
  362. * Render MagiCAD logo to container with specified identified
  363. *
  364. * @param {string} containerId Container identifier
  365. * @param {boolean} transparent Boolean value should transparent image be used
  366. */
  367. renderMagiCADLogo(containerId, transparent) {
  368. let container = document.getElementById(containerId);
  369. if (!container)
  370. return;
  371. let data = {
  372. ImageUrl: transparent ?
  373. systemconfig.MAGICLOUDLOGOTRANSPARENT : systemconfig.MAGICLOUDLOGO,
  374. Alt: 'Powered by MagiCAD',
  375. Title: 'Powered by MagiCAD'
  376. };
  377. container.innerHTML = `<img src="${data.ImageUrl}" alt="${data.Alt}" title="${data.Title}" />`;
  378. }
  379.  
  380. /**
  381. * Render MagiCAD logo to container with specified identified
  382. * @param {*} containerId Container identifier
  383. * @param {*} transparent Boolean value whether transparent image should be used
  384. * @deprecated Use renderMagiCADLogo instead
  385. */
  386. renderMagiCloudLogo(containerId, transparent) {
  387. this.renderMagiCADLogo(containerId, transparent);
  388. }
  389.  
  390. /**
  391. * Set specified diagram and bind click event to given elementId. Click event will add possible data to given dataElementId
  392. * @param {object} data Product data
  393. * @param {object} options <pre>Example:
  394. * {
  395. * type: diagramType,
  396. * elementId: 'el',
  397. * dataElementId: 'dataEl'
  398. * }
  399. * where diagramType is one of { Ventilation, Heating, Cooling, SupplyAir, ExtractAir, Radiator, Pump }
  400. * </pre>
  401. */
  402. setDiagram(data, options) {
  403. if (!options || !options.elementId || !options.type ||
  404. !data.Diagrams || !data.Diagrams[options.type])
  405. return;
  406.  
  407. let element = document.getElementById(options.elementId);
  408. if (!element)
  409. return;
  410.  
  411. element.innerHTML = '';
  412. let img = utils.createElement('img', {
  413. src: data.Diagrams[options.type].BaseUrl,
  414. alt: options.type
  415. });
  416. element.appendChild(img);
  417.  
  418. // Set diagram data if exists
  419. let hasData = data.Diagrams[options.type].HasData;
  420. if (hasData) {
  421. let baseUrl = data.Diagrams[options.type].BaseUrl;
  422. let dataElement = document.getElementById(options.dataElementId);
  423. if (!dataElement)
  424. return;
  425. if (options.operationPoint && options.operationPoint.x && options.operationPoint.y &&
  426. options.operationPoint.x >= 0 && options.operationPoint.y >= 0) {
  427.  
  428. let diagram = {
  429. URL: baseUrl,
  430. DataURL: hasData ? baseUrl + '/data' : null,
  431. operationPoint: options.operationPoint,
  432. HasData: hasData
  433. };
  434. _setDiagramImages(this.diagramService, img, dataElement, diagram, options.type);
  435. }
  436. let that = this;
  437. img.addEventListener('click', (event) => {
  438. let diagram = that.diagramService.getDiagram({
  439. target: img,
  440. data: {
  441. BaseURL: baseUrl,
  442. HasData: hasData
  443. },
  444. pageX: event.pageX,
  445. pageY: event.pageY
  446. });
  447. that.diagramService.getOperatingPoint(diagram).then(() => {
  448. _setDiagramImages(that.diagramService, img, dataElement, diagram, options.type);
  449. }, () => {
  450. // Failure when performing getOperatingPoint
  451. });
  452. });
  453. }
  454. }
  455.  
  456. /**
  457. * Get pressure drop of curve at specific flow.
  458. * @return Example {Succeed: true, Value: 27.870676}
  459. * @param {string} productId Product identifier (GUID)
  460. * @param {string} systemTypeId Value = {Unknown, AnyFluid, SupplyFluid, ReturnFluid, ColdWater, HotWater, FireHydrant, HotSupplyFluid, Sprinkler, Sewer, AnyAir, SupplyAir, ExtractAir, OutdoorSupply, OutdoorExhau}
  461. * @param {number} qv Specified flow
  462. * @param {number} fanSpeed Specified Fan Speed
  463. */
  464. getDpTot(productId, systemTypeId, qv, fanSpeed) {
  465. let promise = this.ahuCalculationService.getDpTot(productId, systemTypeId, qv, fanSpeed);
  466. if (this.onGetDpTot) {
  467. promise.then(this.onGetDpTot);
  468. }
  469. return promise;
  470. }
  471.  
  472. /**
  473. * Find suitable fanSpeed for given operation point.
  474. * @private
  475. * @return Example {PressureDrop: 107.4791, Succeed: true, Value: 6}
  476. * @param {string} productId Product identifier (GUID)
  477. * @param {string} systemTypeId Value = {Unknown, AnyFluid, SupplyFluid, ReturnFluid, ColdWater, HotWater, FireHydrant, HotSupplyFluid, Sprinkler, Sewer, AnyAir, SupplyAir, ExtractAir, OutdoorSupply, OutdoorExhau}
  478. * @param {number} qv Specified flow
  479. * @param {number} dpTot Pressure drop value
  480. */
  481. findOptimalSpeed(productId, systemTypeId, qv, dpTot) {
  482. let promise = this.ahuCalculationService.findOptimalSpeed(productId, systemTypeId, qv, dpTot);
  483. if (this.onFindOptimalSpeed) {
  484. promise.then(this.onFindOptimalSpeed);
  485. }
  486. return promise;
  487. }
  488. }