magicad/magicad.js
import base64 from '../base64/base64';
import {
_addAuthToken,
_extendQModelOptions,
_setDiagramImages,
_getResourceQueryUrl,
_replaceOptionsFromBase64EncodedUrl
} from './magicad-fn';
import OidcAuthService from '../auth/oidcauth';
import UserManagerSettingsFactory from '../auth/oidc-clientsettings-factory';
import SigninService from '../auth/signin';
import X3DViewService from '../x3dviewservice/X3DViewService.js';
import axios from 'axios';
import utils from '../utils';
export default class MagiCAD {
/**
* @private
* @param {*} fingerprintService
* @param {*} diagramService
* @param {*} ahuCalculationService
* @param {*} signinService (optional) Could be created also with init() function
* @param {*} x3dViewService (optional) Could be created also with init() function
*/
constructor(fingerprintService, diagramService, ahuCalculationService, signinService, x3dViewService) {
/**
* @private
*/
this.fingerprintService = fingerprintService;
/**
* @private
*/
this.diagramService = diagramService;
/**
* @private
*/
this.ahuCalculationService = ahuCalculationService;
/**
* @private
*/
this.signinService = signinService;
/**
* @private
*/
this.x3dViewService = x3dViewService;
/**
* @private
*/
this.onFindOptimalSpeed = undefined;
/**
* @private
*/
this.onGetDpTot = undefined;
/**
* @private
*/
this.onLoad = undefined;
/**
* @private
*/
this.onLoadError = undefined;
/**
* @private
*/
this.onRenderX3D = undefined;
}
/**
* Initialize MagiCAD Widget SDK
*
* @param {object} options <pre>Example object:
* {
* client_id: 'your_client_id',
* popup_redirect_uri: 'callback file url when using popup signin method'
* 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
* post_logout_redirect_uri: 'callback file url to direct the user to after successful sign-out'
* enableX3D: true, // default value is true and x3dom library will be loaded
* onLoadUser: function(user) { console.log(user.username); }, // Set event handler to get signed in user if any exists e.g. case when page refreshed
* onSignin: function(user) { console.log(user.username); }, // Set event handler to perform some action on user signin
* onSignout: function() { console.log('user signed out'); }, // Set event handler to perform some action on user signout
* onRenderX3D: function() { console.log('x3d rendered'); }, // Set event handler to perform some action after rendering x3d image
* onGetDpTot function(result) { console.log(result); }, // Set event handler to perform some action with calculation result
* onFindOptimalSpeed: function(result) { console.log(result); } // Set event handler to perform some action with calculation result
* }
* </pre>
* @param {object} context (optional)
*/
init(options, context) {
// If not given already in constructor
if (!this.signinService) {
let factory = new UserManagerSettingsFactory(options);
let oidcAuthService = new OidcAuthService(factory);
this.signinService = new SigninService(oidcAuthService);
}
if (!this.signinService)
throw "MagiCAD Widget SDK initialization failed!";
// Set X3DViewService
if (options.enableX3D === undefined || options.enableX3D === null) {
options.enableX3D = true; // default value if not given
}
// If not given already in contructor
if (!this.x3dViewService)
this.x3dViewService = options.enableX3D ? new X3DViewService() : undefined;
if (this.signinService) {
if (typeof options.onLoadUser === 'function') {
this.signinService && this.signinService.getUser()
.then(user => {
options.onLoadUser(user.profile);
})
.catch(err => {
options.onLoadUser(null);
});
}
if (typeof options.onSignin === 'function') {
this.signinService.onSignin(options.onSignin);
}
if (typeof options.onSignout === 'function') {
this.signinService.onSignout(options.onSignout);
}
}
if (typeof options.onLoad === 'function') {
this.onLoad = options.onLoad;
}
if (typeof options.onLoadError === 'function') {
this.onLoadError = options.onLoadError;
}
if (typeof options.onRenderX3D === 'function') {
this.onRenderX3D = options.onRenderX3D;
}
if (typeof options.onGetDpTot === 'function') {
this.onGetDpTot = options.onGetDpTot;
}
if (typeof options.onFindOptimalSpeed === 'function') {
this.onFindOptimalSpeed = options.onFindOptimalSpeed;
}
if (typeof context === 'object') {
context.MagiCAD = Object.assign(context.MagiCAD, this);
context.MagiCAD.__proto__ = this.__proto__;
}
}
/**
* Return information is user logged in.
*
* @return boolean value is used logged in
*/
isLoggedIn() {
return this.signinService && this.signinService.isLoggedIn();
}
/**
* Signin. Will open MagiCAD login popup.
*
* @return {Promise<void>}
*/
signin() {
return this.signinService && this.signinService.signin();
}
/**
* Signout current logged in user
*
* @return {Promise<void>}
*/
signout() {
return this.signinService && this.signinService.signout();
}
/**
* Return release info of MagiCAD Widget SDK in example Production 2.35.0
*/
getReleaseInfo() {
return `${systemconfig.ENVIRONMENT} ${systemconfig.RELEASENUMBER}`;
}
/**
* Load and initialize MagiCAD Cloud Javascript Library
*
* @param {object} options <pre>
* {
* productId: string,
* variantQpdId: string,
* articleNumber: string,
* manufacturerId: string
* }
*
* where manufacturerId and either:
*
* productId and variantQpdId, or
* articleNumber
*
* is defined.
* </pre>
* @return {Promise<ProductData>} Successful response will contain product/variant data
*/
load(options) {
let userRequest = this.signinService && this.signinService.getUser(),
fingerprintRequest = this.fingerprintService.getFingerprint();
let promise = Promise.all([userRequest, fingerprintRequest]).then(([user, sessionId]) => {
let baseProductUrl = systemconfig.APIURL + systemconfig.PRODUCTPATH;
let productUrl;
if (options.productId)
productUrl = baseProductUrl + options.productId;
else if (options.articleNumber && options.manufacturerId)
productUrl = baseProductUrl + options.manufacturerId + '/' + encodeURI(options.articleNumber);
if (options.logoContainerId)
this.renderMagiCADLogo(options.logoContainerId);
return axios.get(productUrl).then((response) => {
if (!response || response.status !== 200 || !response.data)
return null;
// Finalize Attachments with auth tokens
response.data.Attachments.forEach((val) => {
val.Uri = _addAuthToken(user, sessionId, val.Uri, options.applicationId);
});
// Finalize DXF resources with auth tokens
response.data.DxfUrl = _addAuthToken(user, sessionId, response.data.DxfUrl, options.applicationId);
return response.data;
}, (err) => {
if (this.onLoadError)
this.onLoadError(err);
});
});
if (this.onLoad) {
promise.then(this.onLoad, this.onLoadError);
}
return promise;
}
/**
* Return DXF query url
*
* @param {object} product The product object returned from MagiCAD.load() function
* @param {object} options <pre>
* {
* QModelParameters: Optional QModelParameters of model, in format "L=100;D=25;W1=130...",
* Filename: Optional file name and extension for the object to download, in format "example.dxf"
* }
* </pre>
* @returns DXF url customized with given options. If invalid options object is provided, returns default DXF url, or null if no DXF URL exists
*/
getCustomizedDxfQueryUrl(product, options){
try{
return _replaceOptionsFromBase64EncodedUrl(options, new URL(product.DxfUrl));
}
catch (e) {
return null;
}
}
/**
* Return dimension image query url
*
* @param {object} options <pre>
* {
* QModelId: Optional QModelId of model,
* QModelParameters: Optional QModelParameters of model,
* ViewMode: one value of { 0=Rendered, 1=DimensionLabels, 2=DimensionValues },
* ViewPosition: one value of { 0=Default, 1=Front, 2=Right, 3=Left, 4=Top, 5=Bottom, 6=IsometricLeft, 7=IsometricRight }
* }
* @returns Dimension image url
*/
getDimensionImageQueryUrl(options) {
return _getResourceQueryUrl(options, systemconfig.DIMENSIONSIMAGEQUERYPATH);
}
/**
*
* Return image query url
*
* @param {object} options <pre>
* {
* QModelId: Optional QModelId of model,
* QModelParameters: Optional QModelParameters of model,
* ViewPosition: one value of { 0=Default, 1=Front, 2=Right, 3=Left, 4=Top, 5=Bottom, 6=IsometricLeft, 7=IsometricRight }
* }
* @returns Image url
*/
getImageQueryUrl(options) {
return _getResourceQueryUrl(options, systemconfig.IMAGEQUERYPATH);
}
/**
*
* Renders X3D Image container to given container
*
* @param {object} options <pre>
* Basic example:
*
* {
* x3dUri: location of x3d,
* imageUri: location of image
* containerId: identifier of the container for x3d,
* }
*
* Or, to get 3D view with custom model parameters:
* {
* QModelId: the identifier of the 3D geometry (GUID format),
* QModelParameters: Optional QModelParameters of model,
* ViewMode: one value of { 0=Rendered, 1=DimensionLabels, 2=DimensionValues,
* containerId: identifier of the container for x3d,
* }
*
* Or, to get 3D view with product external reference and variant qpd id:
* {
* productId: the external reference of the product (GUID format)
* variantQpdId: the qpd id of the specific variant,
* containerId: identifier of the container for x3d
* }
*
* Or, to get 3D view with custom level of detail (LOD):
* {
* QModelId: the identifier of the 3D geometry (GUID format),
* QModelParameters: Optional QModelParameters of model,
* LodLevel: one value of { 0=Preview, 1=MC LOD 200, 2=MC LOD 300, 3=MC LOD 350 },
* containerId: identifier of the container for x3d,
* }
*
* @param {boolean} update Update existing container with new image url
* @return {Promise<void>} result as promise
*/
renderX3D(options, update) {
if (!this.x3dViewService) {
return new Promise((resolve, reject) => {
reject("Enable X3D in MagiCAD.init() function");
});
}
let queryOptions = {
containerId : (options || {}).containerId,
imageUri : (options ||{}).imageUri,
x3dUri : (options || {}).x3dUri
};
let queryObject = _extendQModelOptions(options);
if (queryObject.QModelId) { // QModelId is set, override image and x3d
queryOptions.x3dUri = systemconfig.APIURL + systemconfig.X3DQUERYPATH + base64.b64EncodeUnicode(JSON.stringify(queryObject));
queryOptions.imageUri = systemconfig.APIURL + systemconfig.IMAGEQUERYPATH + base64.b64EncodeUnicode(JSON.stringify(queryObject));
}
else if (queryObject.variantQpdId && queryObject.productId) { // Product external reference and variant QpdId is set, override image and x3d
queryOptions.x3dUri = systemconfig.APIURL +
systemconfig.X3DBYQPDIDPATH
.replace('{productId}', queryObject.productId)
.replace('{encodedVariantQpdId}', base64.b64EncodeUnicode(queryObject.variantQpdId));
queryOptions.imageUri = systemconfig.APIURL +
systemconfig.IMAGEBYQPDIDPATH
.replace('{productId}', queryObject.productId)
.replace('{encodedVariantQpdId}', base64.b64EncodeUnicode(queryObject.variantQpdId));
}
return this.x3dViewService.loadX3D(queryOptions, update).then(result => {
if (this.onRenderX3D) this.onRenderX3D();
return result;
});
}
/**
* Render MagiCAD logo to container with specified identified
*
* @param {string} containerId Container identifier
* @param {boolean} transparent Boolean value should transparent image be used
*/
renderMagiCADLogo(containerId, transparent) {
let container = document.getElementById(containerId);
if (!container)
return;
let data = {
ImageUrl: transparent ?
systemconfig.MAGICLOUDLOGOTRANSPARENT : systemconfig.MAGICLOUDLOGO,
Alt: 'Powered by MagiCAD',
Title: 'Powered by MagiCAD'
};
container.innerHTML = `<img src="${data.ImageUrl}" alt="${data.Alt}" title="${data.Title}" />`;
}
/**
* Render MagiCAD logo to container with specified identified
* @param {*} containerId Container identifier
* @param {*} transparent Boolean value whether transparent image should be used
* @deprecated Use renderMagiCADLogo instead
*/
renderMagiCloudLogo(containerId, transparent) {
this.renderMagiCADLogo(containerId, transparent);
}
/**
* Set specified diagram and bind click event to given elementId. Click event will add possible data to given dataElementId
* @param {object} data Product data
* @param {object} options <pre>Example:
* {
* type: diagramType,
* elementId: 'el',
* dataElementId: 'dataEl'
* }
* where diagramType is one of { Ventilation, Heating, Cooling, SupplyAir, ExtractAir, Radiator, Pump }
* </pre>
*/
setDiagram(data, options) {
if (!options || !options.elementId || !options.type ||
!data.Diagrams || !data.Diagrams[options.type])
return;
let element = document.getElementById(options.elementId);
if (!element)
return;
element.innerHTML = '';
let img = utils.createElement('img', {
src: data.Diagrams[options.type].BaseUrl,
alt: options.type
});
element.appendChild(img);
// Set diagram data if exists
let hasData = data.Diagrams[options.type].HasData;
if (hasData) {
let baseUrl = data.Diagrams[options.type].BaseUrl;
let dataElement = document.getElementById(options.dataElementId);
if (!dataElement)
return;
if (options.operationPoint && options.operationPoint.x && options.operationPoint.y &&
options.operationPoint.x >= 0 && options.operationPoint.y >= 0) {
let diagram = {
URL: baseUrl,
DataURL: hasData ? baseUrl + '/data' : null,
operationPoint: options.operationPoint,
HasData: hasData
};
_setDiagramImages(this.diagramService, img, dataElement, diagram, options.type);
}
let that = this;
img.addEventListener('click', (event) => {
let diagram = that.diagramService.getDiagram({
target: img,
data: {
BaseURL: baseUrl,
HasData: hasData
},
pageX: event.pageX,
pageY: event.pageY
});
that.diagramService.getOperatingPoint(diagram).then(() => {
_setDiagramImages(that.diagramService, img, dataElement, diagram, options.type);
}, () => {
// Failure when performing getOperatingPoint
});
});
}
}
/**
* Get pressure drop of curve at specific flow.
* @return Example {Succeed: true, Value: 27.870676}
* @param {string} productId Product identifier (GUID)
* @param {string} systemTypeId Value = {Unknown, AnyFluid, SupplyFluid, ReturnFluid, ColdWater, HotWater, FireHydrant, HotSupplyFluid, Sprinkler, Sewer, AnyAir, SupplyAir, ExtractAir, OutdoorSupply, OutdoorExhau}
* @param {number} qv Specified flow
* @param {number} fanSpeed Specified Fan Speed
*/
getDpTot(productId, systemTypeId, qv, fanSpeed) {
let promise = this.ahuCalculationService.getDpTot(productId, systemTypeId, qv, fanSpeed);
if (this.onGetDpTot) {
promise.then(this.onGetDpTot);
}
return promise;
}
/**
* Find suitable fanSpeed for given operation point.
* @private
* @return Example {PressureDrop: 107.4791, Succeed: true, Value: 6}
* @param {string} productId Product identifier (GUID)
* @param {string} systemTypeId Value = {Unknown, AnyFluid, SupplyFluid, ReturnFluid, ColdWater, HotWater, FireHydrant, HotSupplyFluid, Sprinkler, Sewer, AnyAir, SupplyAir, ExtractAir, OutdoorSupply, OutdoorExhau}
* @param {number} qv Specified flow
* @param {number} dpTot Pressure drop value
*/
findOptimalSpeed(productId, systemTypeId, qv, dpTot) {
let promise = this.ahuCalculationService.findOptimalSpeed(productId, systemTypeId, qv, dpTot);
if (this.onFindOptimalSpeed) {
promise.then(this.onFindOptimalSpeed);
}
return promise;
}
}