new Base( [config] [, typeName])
Creates a new base item class instance.
Parameters:
| Name | Type | Argument | Description | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
config |
object |
<optional> |
An optional configuration object. |
||||||||||||
Properties of
|
|||||||||||||||
| Name | Type | Argument | Description |
|---|---|---|---|
name |
string |
<optional> |
An optional human-readable name for this item, defaults to class type. |
uuid |
string |
<optional> |
An optional universally unique identifier of this item, defaults to a new UUID. |
typeNameThis additional parameter is typically used by subclasses to pass in a default name without altering the config object.
Members
-
:string
className <readonly>
-
The name of the subclass for this object instance.
This name must match the name of this class within the
PD.Registry. Thus, the base implementation simply referencesthis.constructor.getClassName()to ensure that this is always the case even for subclasses. As a result, there is rarely any need to override this method.This property is used when copying, storing and exporting data for subclass instances to ensure that they are recreated as instances of the right class.
Type
- string
-
:string
displayName <readonly>
-
The name to display for this class within the user interface.
Type
- string
-
:string
iconName <readonly>
-
The name of the SVG icon to associate with this object instance.
This name should match the name of the icon associated with this class within the
PD.Registry. Thus, the default implementation simply referencesthis.constructor.getClassName()to ensure that this is always the case, even for subclasses. However, you can override this property if you want a different icon dependant on other properties of the class instance, as shown in the example below.Type
- string
Example
// Overriding the icon name. MyElements.Table = class extends PD.Base { /// ... get iconName() { if (this.hasRoundTop) return 'MyElements.Table.Round'; return this.constructor.getClassName(); }; /// ... }; -
:string
name
-
A human-readable name for this item instance.
Type
- string
-
:string
uuid
-
A universally unique identifier for the item instance.
Type
- string
-
:object
icon <static>
-
Stores a basic default icon to share with subclasses.
Icon information is stored as an object rather than a string so that an optional
viewBoxproperty can be included and, as an SVG iconcontentstring can sometimes be very large, it allows the icon to be passed around by reference or shared by more than one object without requiring multiple string copies.The
contentproperty stores the actual SVG geometry of the icon as a string. It is included as the contents of an SVG symbol element so can contain pretty well any graphic or shape elements.If included, the
viewBoxproperty gives the position and dimensions of the content within the SVG viewport, see the MDN viewBox page for more details. If not included, the viewBox defaults to '0 0 1000 1000'.Icon Design
You are free to design the icons for your classes in any way you wish. In fact, using a different style to that of the core framework classes may even help visually differentiate your elements. However, the following are some hints that are borne of experience that may help with your icons.
-
Using a relatively large view box dimension, such as 1000 x 1000, can actually help reduce the size of the final content string by giving you reasonable precision whilst reducing the number of decimal points within the output. If you rigorously snap points to a display grid and control the number of decimal places when exporting, you will be very surprised by the amount of difference this can make to the final string size.
-
When saving the SVG file, ensure to optimise the content and remove as much of the styling as you possibly can. You will notice that there are no 'fill' or 'stroke' attributes at all in the content element of the example below. This means that it will use the
currentColorand therefore automatically adapt to the host HTML element in which it sits. This means that the icon will respond to hover, active and selected state changes on buttons and menu items in the same way as text, and will invert properly when using dark mode. If you specify the color of 'fill' or 'stroke' attributes, they will be the colours of your icon regardless of context. -
When using different line widths with viewbox('0 0 1000 1000'), a value of 50px works very well as a major outline, 40px as a medium outline and 20px for internal detail. Anything less than 10px for very fine detail will likely be barely visible on high resolution screens.
-
If you want to test a class and have not yet created your own icon, you can still register the class by referencing one of the core element or component icons. Pretty well all of the core classes store their icon in a static
iconproperty. You can reference these directly using the class name, such asPD.Base.icon,BIM.Space.iconorBIM.Chairs.Dining.icon.
Type
- object
Examples
// Defining your own icon. MyComponents.Chair.GoldenThrone.icon = { viewBox: '0 0 1000 1000', content: `<path d="m500 72-445 211v16 436 211 445-211v-452-445-211z m-315 213-8 17 303 151-303 150 9 17 316-157 314 157 9-17-301-150 301-149-9-17-314 156-316-158z m0 55 395 188v388-395 188-395-188v-388-188.1z"/>` };// Reusing one of the core class icons. PD.Registry.registerClass(MyComponents.Chair.GoldenThrone, BIM.Chair.icon);
-
Methods
-
checkDynamicParameter(param, group [, host])
-
Provides an opportunity to dynamically limit the value and/or range of each parameter.
This method is called whenever a dynamic parameter is interactively changed. The
paramargument gives access to the parameter being changed whilst thegroupargument gives access to other parameters within the same parameter group.NOTE: Range validation in this method is not absolutely required, but doing so can prevent unnecessary model rebuilds due to out-of-range parameters being different from their previous values, even though the object's geometry will not actually change due to range constraints within the subclasses
rebuild()method. Thus, it is usually best to do them here so that someone's future airport model is not entirely rebuilt each time they try to set a too-large length in your custom door handle component.Parameters:
Name Type Argument Description paramPD.Parameter The parameter that is being interactively changed.
groupPD.ParamGroup The group that the dynamic parameter belongs to.
hostobject <optional>
For components only, the parent or host object that called this method.
Example
checkDynamicParameter(param, group, host) { switch (param.name) { case 'height': if (param.value < 1.0) param.value = 1.0; break; case 'width': case 'length': if (param.value < 100.0) param.value = 100.0; if (this.standardBedSize > 0) { // If not custom. group.setParameterValue('standardBedSize', 0); this.standardBedSize = 0; // Make it custom. } break; case 'standardBedSize': { const std_bed = this.getStandardBedSize(Math.round(param.value)); if (std_bed != null) { const [ width, length ] = (PD.DIMENSION.useImperial) ? std_bed.sizeImperial : std_bed.sizeMetric; this.width = PD.Utils.toNumber(width, this.width); group.setParameterValue('width', this.width); this.length = PD.Utils.toNumber(length, this.length); group.setParameterValue('length', this.length); } } break; } }; -
clone()
-
Creates a copy of this instance with different name and uuid.
Returns:
Returns a new instance with copied values.
- Type
- PD.Base | null
-
fromJSON(data)
-
Safely copy properties from a source object instance.
This method is used in different ways by the framework, but the main purpose is to copy data from simple POJO objects, typically ones that have been created using the
PD.Base#toJSONmethod and stores in a model file.It first checks for the presence of each property in the host object and performs a range-protected copy of that data if it exists. This allows for safely copying data from JSON objects loaded from a file, subclassed or superclass objects, or objects that may have been saved with an earlier version of the framework and may not contain the same properties as the current version.
Override this method in derived classes to handle additional properties unique to your new class, but make sure to call
super.fromJSON(data);at the very top of the overridden method. This will handle properties from the whole hierarchy of superclasses above yours. This means you only need to deal with the additional properties that your new class uses to regenerate itself, as shown in the example below.Parameters:
Name Type Description dataobject The source object instance containing data to copy.
Returns:
Returns this instance to support method chaining.
- Type
- PD.Base
Example
// Overriding this method. class MyElement extends PD.Element { /// ... fromJSON(data) { super.fromJSON(data); if ('myNewNumberProp' in data) { this.myNewNumberProp = PD.Utils.toNumber(data.myNewNumberProp, this.myNewNumberProp); } if ('myNewIntegerProp' in data) { this.myNewIntegerProp = PD.Utils.toInteger(data.myNewIntegerProp, this.myNewIntegerProp); } if ('myNewBooleanProp' in data) { this.myNewBooleanProp = PD.Utils.toBoolean(data.myNewBooleanProp, this.myNewBooleanProp); } if ('myNewVectorProp' in data) { PD.Utils.copyVector3(data.myNewVectorProp, this.myNewVectorProp); } if ('myNewColorProp' in data) { PD.Utils.copyColor(data.myNewColorProp, this.myNewColorProp); } return this; }; /// ... }; -
getDynamicParameters( [host])
-
Provides a list of dynamic parameter groups to the UI.
This list is typically requested by the front-end framework whenever something is selected in the model and used to generate DOM components that allow the user to interactively edit each parameter.
Override this method in any derived classes to specify your own custom parameters and parameter groups. The array must only contain
PD.ParamGroupobjects for it to display the parameters it contains, as shown in the example below.When the user modifies any a parameters, the
updateDynamicParameters()method on the owner is called. As long as thenameproperty of each parameter corresponds exactly to a property on the custom element, the default implementation of the update method can be used. This simply does some type and tolerance checking to see if the value has changed, before assigning the new value and calling therebuild()method on the element. If you need to use names other than property names, or need to do your own type and/or tolerance checking, then you will need to also override thePD.Base#updateDynamicParameters` method.Parameters:
Name Type Argument Description hostobject <optional>
For components only, the parent or host object that called this method.
Returns:
Returns an array of zero or more
PD.ParamGroupobjects.- Type
- Array
Example
getDynamicParameters(host) { return [ new PD.ParamGroup({ name: 'mainParams', title: 'Table Parameters', target: this, params: [ new PD.Parameter({ name: 'height', title: 'Table Height', value: this.height, paramType: PD.ParamType.SmallDistance, description: 'The height from floor level to the top of the table.' }), new PD.Parameter({ name: 'size', title: 'Table Top Size/Diameter', value: this.size, paramType: PD.ParamType.Distance, description: 'The size of the table top when not defined by a closed path.' }), new PD.Parameter({ name: 'thickness', title: 'Table Top Thickness', value: this.thickness, paramType: PD.ParamType.SmallDistance, description: 'The thickness of the table top surface.' }), new PD.Parameter({ name: 'offset', title: 'Offset From Path', value: this.offset, paramType: PD.ParamType.SmallDistance, description: 'The offset distance from the table path.' }), new PD.Parameter({ name: 'swapSides', title: 'Swap Sides', value: this.swapSides, paramType: PD.ParamType.Boolean, description: 'Reverse the direction of the table relative to its path.' }), new PD.Parameter({ name: 'isRound', title: 'Round Table', value: this.isRound, paramType: PD.ParamType.Boolean, description: 'Whether or not the table surface is round.' }), ] }), new PD.ParamGroup({ name: 'legParams', title: 'Leg Parameters', target: this, params: [ new PD.Parameter({ name: 'legCount', title: 'Number of Legs', value: this.legCount, paramType: PD.ParamType.Integer, description: 'The number of legs on the table.' }), new PD.Parameter({ name: 'legSize', title: 'Leg Size', value: this.legSize, paramType: PD.ParamType.SmallDistance, description: 'The thickness of each leg of the table.' }), new PD.Parameter({ name: 'legInset', title: 'Leg Edge Inset', value: this.legInset, paramType: PD.ParamType.SmallDistance, description: 'The inset distance of each leg from the table edge.' }), new PD.Parameter({ name: 'legOffset', title: 'Leg Edge Offset', value: this.legOffset, paramType: PD.ParamType.Fraction, description: 'The relative distance of the leg along each edge span.' }), new PD.Parameter({ name: 'legSpan', title: 'Max. Distance Between Legs', value: this.legSpan, paramType: PD.ParamType.Distance, description: 'The maximum distance between legs along each edge span.' }) ] }) ]; }; -
toJSON( [data])
-
Converts the object to a simple POJO for conversion to JSON.
This method is used to copy, store and save the data for this item instance, so the returned object must have all the properties required be able to rebuild this instance in its entirety when passed to the class constructor.
Override this method in derived classes to add additional properties, but make sure to call
data = super.toJSON(data);at the very top of the overridden method. This will add properties from the whole hierarchy of super classes above yours. This means you should then add only the additional properties that your new class needs to regenerate itself, as shown in the example below.Parameters:
Name Type Argument Description dataobject <optional>
An optional parent object to append this data to.
Returns:
Returns a Plain Old Javascript Object (POJO).
- Type
- object
Example
// Overriding this method. class MyElement extends PD.Element { /// ... toJSON(data) { data = super.toJSON(data); data.myNewNumberProp = this.myNewNumberProp; data.myNewIntegerProp = this.myNewIntegerProp; data.myNewBooleanProp = this.myNewBooleanProp; data.myNewVectorProp = this.myNewVectorProp.toArray(); data.myNewColorProp = this.myNewColorProp.toArray(); return data; }; /// ... }; -
updateDynamicParameters(param, group)
-
Sets the dynamic parameter value and returns true if it changed.
Most subclasses don't need to override this method as it automatically detects changes and rebuilds the element/component and model when required. However, if you do need to add your own custom logic or intercept the return value, please read the following examples carefully and use whichever best suits your needs.
NOTE: When overriding this method, you may not want to call
super.updateDynamicParameters(param, group)as the parent class may have added its own logic that may interfere with what you want to do. Instead, either use the staticPD.Base.updateDynamicParametersOnHostmethod to check if the value changed, or base it on the third example which replicates the code in that static method.Parameters:
Name Type Description paramPD.Parameter The dynamic parameter that changed.
groupPD.ParamGroup The group that the dynamic parameter belongs to.
Returns:
Returns true if the value actually changed.
- Type
- boolean
Examples
updateDynamicParameters(param, group) { /// When you want parent class to use its logic. if (super.updateDynamicParameters(param, group)) { if (param.name == 'i_am_special') this.doSomethingSpecial(); return true; } return false; };updateDynamicParameters(param, group) { /// When you don't want parent to handle parameter updates. if (PD.Base.updateDynamicParametersOnHost(param, group, this)) { /// Invalidate geometry. if (this.typeComponent) { ++this.typeComponent.updateIndex; } /// Rebuild element. this.hasChanged = true; this.update(); /// Only update site mesh. if (this.onlyUsesSiteMesh) { const level = this.level; if (level) { // Don't trigger whole level update. level.rebuildSiteMesh(); PD.GlobalActions.redrawAndUpdateSelection(); return false; } } return true; } return false; };updateDynamicParameters(param, group) { /// The following three lines of code replicate /// `PD.Base.updateDynamicParametersOnHost()`, which you can /// use if you need to access `target` without having to call /// `group.getTarget() || this` twice. const target = group.getTarget() || this; target.checkDynamicParameter(param, group, this); if (param.setValueOnHostIfDifferent(target, group, this)) { /// You can now use `target`. if (target.myOwnMeshThatIsUpdatedDuringRebuild) { /// Rebuild element. this.hasChanged = true; this.update(); /// If no level meshes or other elements are affected, /// simply update the target locally and return false. this.myOwnMeshThatIsUpdatedDuringRebuild.update(); /// Update selection meshes if the /// element's highlight geometry changed. PD.GlobalActions.updateSelectionMeshes(); return false; } return true; } return false; }; -
generateUUID() <static>
-
Generate a universally unique identifier (UUID) string.
Returns:
Returns a new UUID.
- Type
- string
-
getClassName() <static>
-
The name of this class within the
PD.Registry.This method is required as the name stored in a class's prototype constructor will often not be properly namespaced and/or globally accessible. This is because only the name between
classandextendskeywords is stored, and even this may end up being mangled during minification in a production build.In the example code shown below, the first constructor class name will be
LoungeChairand the second will be an empty string, whereas they should really beMyChairs.LoungeChairandClassrooms.ArtSpacerespectively in order to be instantiated outside their local scope and to avoid possible conflicts with other libraries.To enable automatic reflection, and ensure that the right name always refers to the right constructor, each registerable class is required to implement a static
getClassName()method that ensures proper global namespacing. The class must also implement aclassNameinstance property so that the class name can be retrieved from an instance. If the class derives fromPD.Base, this property is automatically generated as a getter that calls this static method on its constructor, so should work automatically even on derived classes. SeePD.Base.classNamefor details.NOTE: When creating and registering your own classes, please don't use the top-level
BIM.*orPD.*namespaces as these are reserved for core BIM and PD classes. You can extendBIM.*elements and components, but your custom class should not start with 'BIM.' ofPD..Returns:
Returns the registered name of this class.
- Type
- string
Example
// Why getClassName() is needed. MyChairs.LoungeChair = class LoungeChair extends BIM.Furnishing { /// ... static getClassName() { return 'MyChairs.LoungeChair'; }; /// ... }; Classrooms = { ... ArtSpace: class extends BIM.Space { /// --- static getClassName() { return 'Classrooms.ArtSpace'; }; /// --- }, ... }; -
getDisplayName() <static>
-
The name to display for this class within the user interface.
Returns:
Returns the display name.
- Type
- string
-
getParametersAsDataObject(parameters [, data]) <static>
-
Copies values for each parameter in the parameters object as properties on the given data object.
This method adds dynamic parameters to an object as key/value property pairs. If a dynamic parameter named
fredexists with a value of15, then a property of the same name will be added/set on the given object such thatdata.fred == 15.This method can be used in the
toJSON()method of custom entities to add persistent parameters when copy/pasting or saving model data.Parameters:
Name Type Argument Description parametersobject An object containing one or more named
PD.Parameterinstances.dataobject <optional>
An optional object to receive the parameter values as key/value properties. defaults to a new object.
Returns:
Returns the data object, or a new object if not given.
- Type
- object
-
makeUnique(instance) <static>
-
Changes the name and uuid of the instance to unique values.
This is used internally when creating duplicates of primitives, elements or components.
Parameters:
Name Type Description instancePD.Base The new instance to change.
Returns:
Returns the given instance.
- Type
- PD.Base
-
updateDynamicParametersOnHost(param, group, host) <protected, static>
-
Sets the dynamic parameter on the host and returns true if its value changed.
This is a static method that allows subclasses to check for parameter changes without invoking any logic that their parent class may have been added to the
updateDynamicParametersinstance method.Thus, when overriding the
updateDynamicParametersmethod, a subclass should check for changes using this static method rather than callingsuper.updateDynamicParameters(), as shown in the example below.Parameters:
Name Type Description paramPD.Parameter The dynamic parameter that changed.
groupPD.ParamGroup The group that the dynamic parameter belongs to.
hostPD.Base The host element or component being edited.
Returns:
Returns true if the value actually changed.
- Type
- boolean
Examples
class MyClass extends PD.Element { ... /// @override updateDynamicParameters(param, group) { if (PD.Base.updateDynamicParametersOnHost(param, group, this)) { if (param.name == 'i_am_special') this.doSomethingSpecial(); return true; } return false; }; ... };updateDynamicParameters(param, group) { /// The following three lines of code replicate /// `PD.Base.updateDynamicParametersOnHost()`, which you can /// use if you need to access `target` without having to call /// `group.getTarget()` twice. const target = group.getTarget() || this; target.checkDynamicParameter(param, group, this); if (param.setValueOnHostIfDifferent(target, group, this)) { /// You can now use `target`. if (target.myOwnMeshThatIsUpdatedDuringRebuild) { /// Rebuild element. this.hasChanged = true; this.update(); /// If no level meshes or other elements are affected, /// simply update the target locally and return false. this.myOwnMeshThatIsUpdatedDuringRebuild.update(); /// Update selection meshes if the /// element's highlight geometry changed. PD.GlobalActions.updateSelectionMeshes(); return false; } return true; } return false; }; -
updateParametersFromDataObject(data, parameters) <static>
-
Checks for a matching property on the given object for each parameter in the given parameters object, and sets their value.
This method sets dynamic parameters from an object with key/value property pairs. If a dynamic parameter named
fredexists with a value of15, and the given data object has a property with the same name (data.fred) with a value of 20, then the value of the dynamic parameter will be set such thatparameters.fred.value == 20.This may be used by the
fromJSON()method of custom entities to update persistent parameters when copy/pasting or reading model data.Parameters:
Name Type Description dataobject An object containing key/value properties.
parametersobject An object containing one or more named
PD.Parameterinstances.Returns:
Returns this instance to support method chaining.
- Type
- object