feat: 后端全量更新 - 含所有本次需求
- Contract.php: 返回合约账户余额(balance_contract) - My.php: 地址管理增加BTC/ETH - AppContract.php: 一键平仓(closeall) - AppProxy.php: 代理专属注册链接 + 分级权限(L1/L2) - site.php: 手续费减半(0.018→0.009) - agent_permission_setup.sql: 代理权限SQL - crypto_news_crawler.py: 新闻自动采集脚本
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
Default CSS for the Data inspector
|
||||
see also: DataInspector.js, DataInspector.html
|
||||
*/
|
||||
|
||||
/*
|
||||
Grey color palette
|
||||
https://www.google.com/design/spec/style/color.html
|
||||
/* #FAFAFA; /* Grey 50 */
|
||||
/* #F5F5F5; /* Grey 100 */
|
||||
/* #EEEEEE; /* Grey 200 */
|
||||
/* #E0E0E0; /* Grey 300 */
|
||||
/* #BDBDBD; /* Grey 400 */
|
||||
/* #9E9E9E; /* Grey 500 */
|
||||
/* #757575; /* Grey 600 */
|
||||
/* #616161; /* Grey 700 */
|
||||
/* #424242; /* Grey 800 */
|
||||
/* #212121; /* Grey 900 */
|
||||
|
||||
.inspector {
|
||||
display: inline-block;
|
||||
font: bold 14px helvetica, sans-serif;
|
||||
background-color: #212121; /* Grey 900 */
|
||||
color: #F5F5F5; /* Grey 100 */
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.inspector table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 2px;
|
||||
}
|
||||
|
||||
.inspector td, th {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.inspector input, .inspector textarea {
|
||||
background-color: #424242; /* Grey 800 */
|
||||
color: #F5F5F5; /* Grey 100 */
|
||||
font: bold 12px helvetica, sans-serif;
|
||||
border: 0px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.inspector input:disabled, .inspector textarea:disabled {
|
||||
background-color: #BDBDBD; /* Grey 400 */
|
||||
color: #616161; /* Grey 700 */
|
||||
}
|
||||
|
||||
.inspector select {
|
||||
background-color: #424242;
|
||||
}
|
||||
|
||||
.inspector td {
|
||||
color: #F5F5F5;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,718 @@
|
||||
"use strict";
|
||||
/*
|
||||
* Copyright (C) 1998-2020 by Northwoods Software Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
This class implements an inspector for GoJS model data objects.
|
||||
The constructor takes three arguments:
|
||||
{string} divid a string referencing the HTML ID of the to-be inspector's div.
|
||||
{Diagram} diagram a reference to a GoJS Diagram.
|
||||
{Object} options An optional JS Object describing options for the inspector.
|
||||
|
||||
Options:
|
||||
inspectSelection {boolean} Default true, whether to automatically show and populate the Inspector
|
||||
with the currently selected Diagram Part. If set to false, the inspector won't show anything
|
||||
until you call Inspector.inspectObject(object) with a Part or JavaScript object as the argument.
|
||||
includesOwnProperties {boolean} Default true, whether to list all properties currently on the inspected data object.
|
||||
properties {Object} An object of string:Object pairs representing propertyName:propertyOptions.
|
||||
Can be used to include or exclude additional properties.
|
||||
propertyModified function(propertyName, newValue) a callback
|
||||
multipleSelection {boolean} Default false, whether to allow multiple selection and change the properties of all the selected instead of
|
||||
the single first object
|
||||
showAllProperties {boolean} Default false, whether properties that are shown with multipleSelection use the intersect of the properties when false or the union when true
|
||||
only affects if multipleSelection is true
|
||||
showSize {number} Defaults 0, shows how many nodes are showed when selecting multiple nodes
|
||||
when its lower than 1, it shows all nodes
|
||||
|
||||
Options for properties:
|
||||
show: {boolean|function} a boolean value to show or hide the property from the inspector, or a predicate function to show conditionally.
|
||||
readOnly: {boolean|function} whether or not the property is read-only
|
||||
type: {string} a string describing the data type. Supported values: "string|number|boolean|color|arrayofnumber|point|rect|size|spot|margin|select"
|
||||
defaultValue: {*} a default value for the property. Defaults to the empty string.
|
||||
choices: {Array|function} when type == "select", the Array of choices to use or a function that returns the Array of choices.
|
||||
|
||||
Example usage of Inspector:
|
||||
|
||||
var inspector = new Inspector("myInspector", myDiagram,
|
||||
{
|
||||
includesOwnProperties: false,
|
||||
properties: {
|
||||
"key": { show: Inspector.showIfPresent, readOnly: true },
|
||||
"comments": { show: Inspector.showIfNode },
|
||||
"LinkComments": { show: Inspector.showIfLink },
|
||||
"chosen": { show: Inspector.showIfNode, type: "checkbox" },
|
||||
"state": { show: Inspector.showIfNode, type: "select", choices: ["Stopped", "Parked", "Moving"] }
|
||||
}
|
||||
});
|
||||
|
||||
This is the basic HTML Structure that the Inspector creates within the given DIV element:
|
||||
|
||||
<div id="divid" class="inspector">
|
||||
<tr>
|
||||
<td>propertyName</td>
|
||||
<td><input value=propertyValue /></td>
|
||||
</tr>
|
||||
...
|
||||
</div>
|
||||
|
||||
*/
|
||||
function Inspector(divid, diagram, options) {
|
||||
var mainDiv = document.getElementById(divid);
|
||||
mainDiv.className = "inspector";
|
||||
mainDiv.innerHTML = "";
|
||||
this._div = mainDiv;
|
||||
this._diagram = diagram;
|
||||
this._inspectedProperties = {};
|
||||
this._multipleProperties = {};
|
||||
|
||||
// Either a GoJS Part or a simple data object, such as Model.modelData
|
||||
this.inspectedObject = null;
|
||||
|
||||
// Inspector options defaults:
|
||||
this.includesOwnProperties = true;
|
||||
this.declaredProperties = {};
|
||||
this.inspectsSelection = true;
|
||||
this.propertyModified = null;
|
||||
this.multipleSelection = false;
|
||||
this.showAllProperties = false;
|
||||
this.showSize = 0;
|
||||
|
||||
if (options !== undefined) {
|
||||
if (options["includesOwnProperties"] !== undefined) this.includesOwnProperties = options["includesOwnProperties"];
|
||||
if (options["properties"] !== undefined) this.declaredProperties = options["properties"];
|
||||
if (options["inspectSelection"] !== undefined) this.inspectsSelection = options["inspectSelection"];
|
||||
if (options["propertyModified"] !== undefined) this.propertyModified = options["propertyModified"];
|
||||
if (options['multipleSelection'] !== undefined) this.multipleSelection = options['multipleSelection'];
|
||||
if (options['showAllProperties'] !== undefined) this.showAllProperties = options['showAllProperties'];
|
||||
if (options['showSize'] !== undefined) this.showSize = options['showSize'];
|
||||
}
|
||||
|
||||
var self = this;
|
||||
diagram.addModelChangedListener(function(e) {
|
||||
if (e.isTransactionFinished) self.inspectObject();
|
||||
});
|
||||
if (this.inspectsSelection) {
|
||||
diagram.addDiagramListener("ChangedSelection", function(e) { self.inspectObject(); });
|
||||
}
|
||||
}
|
||||
|
||||
// Some static predicates to use with the "show" property.
|
||||
Inspector.showIfNode = function(part) { return part instanceof go.Node };
|
||||
Inspector.showIfLink = function(part) { return part instanceof go.Link };
|
||||
Inspector.showIfGroup = function(part) { return part instanceof go.Group };
|
||||
|
||||
// Only show the property if its present. Useful for "key" which will be shown on Nodes and Groups, but normally not on Links
|
||||
Inspector.showIfPresent = function(data, propname) {
|
||||
if (data instanceof go.Part) data = data.data;
|
||||
return typeof data === "object" && data[propname] !== undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the HTML state of this Inspector given the properties of the {@link #inspectedObject}.
|
||||
* @param {Object} object is an optional argument, used when {@link #inspectSelection} is false to
|
||||
* set {@link #inspectedObject} and show and edit that object's properties.
|
||||
*/
|
||||
Inspector.prototype.inspectObject = function(object) {
|
||||
var inspectedObject = null;
|
||||
var inspectedObjects = null;
|
||||
if (object === null) return;
|
||||
if (object === undefined) {
|
||||
if (this.inspectsSelection) {
|
||||
if (this.multipleSelection) { // gets the selection if multiple selection is true
|
||||
inspectedObjects = this._diagram.selection;
|
||||
} else { // otherwise grab the first object
|
||||
inspectedObject = this._diagram.selection.first();
|
||||
}
|
||||
} else { // if there is a single inspected object
|
||||
inspectedObject = this.inspectedObject;
|
||||
}
|
||||
} else { // if object was passed in as a parameter
|
||||
inspectedObject = object;
|
||||
}
|
||||
if (inspectedObjects && inspectedObjects.count === 1) {
|
||||
inspectedObject = inspectedObjects.first();
|
||||
}
|
||||
if (inspectedObjects && inspectedObjects.count <= 1) {
|
||||
inspectedObjects = null;
|
||||
}
|
||||
|
||||
// single object or no objects
|
||||
if (!inspectedObjects || !this.multipleSelection) {
|
||||
if (inspectedObject === null || this.inspectedObject === inspectedObject) {
|
||||
this.inspectedObject = inspectedObject;
|
||||
this.updateAllHTML();
|
||||
return;
|
||||
}
|
||||
|
||||
this.inspectedObject = inspectedObject;
|
||||
if (this.inspectObject === null) return;
|
||||
var mainDiv = this._div;
|
||||
mainDiv.innerHTML = '';
|
||||
|
||||
// use either the Part.data or the object itself (for model.modelData)
|
||||
var data = (inspectedObject instanceof go.Part) ? inspectedObject.data : inspectedObject;
|
||||
if (!data) return;
|
||||
// Build table:
|
||||
var table = document.createElement('table');
|
||||
var tbody = document.createElement('tbody');
|
||||
this._inspectedProperties = {};
|
||||
this.tabIndex = 0;
|
||||
var declaredProperties = this.declaredProperties;
|
||||
|
||||
// Go through all the properties passed in to the inspector and show them, if appropriate:
|
||||
for (var name in declaredProperties) {
|
||||
var desc = declaredProperties[name];
|
||||
if (!this.canShowProperty(name, desc, inspectedObject)) continue;
|
||||
var val = this.findValue(name, desc, data);
|
||||
tbody.appendChild(this.buildPropertyRow(name, val));
|
||||
}
|
||||
// Go through all the properties on the model data and show them, if appropriate:
|
||||
if (this.includesOwnProperties) {
|
||||
for (var k in data) {
|
||||
if (k === '__gohashid') continue; // skip internal GoJS hash property
|
||||
if (this._inspectedProperties[k]) continue; // already exists
|
||||
if (declaredProperties[k] && !this.canShowProperty(k, declaredProperties[k], inspectedObject)) continue;
|
||||
tbody.appendChild(this.buildPropertyRow(k, data[k]));
|
||||
}
|
||||
}
|
||||
|
||||
table.appendChild(tbody);
|
||||
mainDiv.appendChild(table);
|
||||
} else { // multiple objects selected
|
||||
var mainDiv = this._div;
|
||||
mainDiv.innerHTML = '';
|
||||
var shared = new go.Map(); // for properties that the nodes have in common
|
||||
var properties = new go.Map(); // for adding properties
|
||||
var all = new go.Map(); // used later to prevent changing properties when unneeded
|
||||
var it = inspectedObjects.iterator;
|
||||
// Build table:
|
||||
var table = document.createElement('table');
|
||||
var tbody = document.createElement('tbody');
|
||||
this._inspectedProperties = {};
|
||||
this.tabIndex = 0;
|
||||
var declaredProperties = this.declaredProperties;
|
||||
it.next();
|
||||
inspectedObject = it.value;
|
||||
this.inspectedObject = inspectedObject;
|
||||
var data = (inspectedObject instanceof go.Part) ? inspectedObject.data : inspectedObject;
|
||||
if (data) { // initial pass to set shared and all
|
||||
// Go through all the properties passed in to the inspector and add them to the map, if appropriate:
|
||||
for (var name in declaredProperties) {
|
||||
var desc = declaredProperties[name];
|
||||
if (!this.canShowProperty(name, desc, inspectedObject)) continue;
|
||||
var val = this.findValue(name, desc, data);
|
||||
if (val === '' && desc && desc.type === 'checkbox') {
|
||||
shared.add(name, false);
|
||||
all.add(name, false);
|
||||
} else {
|
||||
shared.add(name, val);
|
||||
all.add(name, val);
|
||||
}
|
||||
}
|
||||
// Go through all the properties on the model data and add them to the map, if appropriate:
|
||||
if (this.includesOwnProperties) {
|
||||
for (var k in data) {
|
||||
if (k === '__gohashid') continue; // skip internal GoJS hash property
|
||||
if (this._inspectedProperties[k]) continue; // already exists
|
||||
if (declaredProperties[k] && !this.canShowProperty(k, declaredProperties[k], inspectedObject)) continue;
|
||||
shared.add(k, data[k]);
|
||||
all.add(k, data[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
var nodecount = 2;
|
||||
while (it.next() && (this.showSize < 1 || nodecount <= this.showSize)) { // grabs all the properties from the other selected objects
|
||||
properties.clear();
|
||||
inspectedObject = it.value;
|
||||
if (inspectedObject) {
|
||||
// use either the Part.data or the object itself (for model.modelData)
|
||||
data = (inspectedObject instanceof go.Part) ? inspectedObject.data : inspectedObject;
|
||||
if (data) {
|
||||
// Go through all the properties passed in to the inspector and add them to properties to add, if appropriate:
|
||||
for (var name in declaredProperties) {
|
||||
var desc = declaredProperties[name];
|
||||
if (!this.canShowProperty(name, desc, inspectedObject)) continue;
|
||||
var val = this.findValue(name, desc, data);
|
||||
if (val === '' && desc && desc.type === 'checkbox') {
|
||||
properties.add(name, false);
|
||||
} else {
|
||||
properties.add(name, val);
|
||||
}
|
||||
}
|
||||
// Go through all the properties on the model data and add them to properties to add, if appropriate:
|
||||
if (this.includesOwnProperties) {
|
||||
for (var k in data) {
|
||||
if (k === '__gohashid') continue; // skip internal GoJS hash property
|
||||
if (this._inspectedProperties[k]) continue; // already exists
|
||||
if (declaredProperties[k] && !this.canShowProperty(k, declaredProperties[k], inspectedObject)) continue;
|
||||
properties.add(k, data[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!this.showAllProperties) {
|
||||
// Cleans up shared map with properties that aren't shared between the selected objects
|
||||
// Also adds properties to the add and shared maps if applicable
|
||||
var addIt = shared.iterator;
|
||||
var toRemove = [];
|
||||
while (addIt.next()) {
|
||||
if (properties.has(addIt.key)) {
|
||||
var newVal = all.get(addIt.key) + '|' + properties.get(addIt.key);
|
||||
all.set(addIt.key, newVal);
|
||||
if ((declaredProperties[addIt.key] && declaredProperties[addIt.key].type !== 'color'
|
||||
&& declaredProperties[addIt.key].type !== 'checkbox' && declaredProperties[addIt.key].type !== 'select')
|
||||
|| !declaredProperties[addIt.key]) { // for non-string properties i.e color
|
||||
newVal = shared.get(addIt.key) + '|' + properties.get(addIt.key);
|
||||
shared.set(addIt.key, newVal);
|
||||
}
|
||||
} else { // toRemove array since addIt is still iterating
|
||||
toRemove.push(addIt.key);
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < toRemove.length; i++) { // removes anything that doesn't showAllPropertiess
|
||||
shared.remove(toRemove[i]);
|
||||
all.remove(toRemove[i]);
|
||||
}
|
||||
} else {
|
||||
// Adds missing properties to all with the correct amount of seperators
|
||||
var addIt = properties.iterator;
|
||||
while (addIt.next()) {
|
||||
if (all.has(addIt.key)) {
|
||||
if ((declaredProperties[addIt.key] && declaredProperties[addIt.key].type !== 'color'
|
||||
&& declaredProperties[addIt.key].type !== 'checkbox' && declaredProperties[addIt.key].type !== 'select')
|
||||
|| !declaredProperties[addIt.key]) { // for non-string properties i.e color
|
||||
var newVal = all.get(addIt.key) + '|' + properties.get(addIt.key);
|
||||
all.set(addIt.key, newVal);
|
||||
}
|
||||
} else {
|
||||
var newVal = '';
|
||||
for (var i = 0; i < nodecount - 1; i++) newVal += '|';
|
||||
newVal += properties.get(addIt.key);
|
||||
all.set(addIt.key, newVal);
|
||||
}
|
||||
}
|
||||
// Adds bars in case properties is not in all
|
||||
addIt = all.iterator;
|
||||
while (addIt.next()) {
|
||||
if (!properties.has(addIt.key)) {
|
||||
if ((declaredProperties[addIt.key] && declaredProperties[addIt.key].type !== 'color'
|
||||
&& declaredProperties[addIt.key].type !== 'checkbox' && declaredProperties[addIt.key].type !== 'select')
|
||||
|| !declaredProperties[addIt.key]) { // for non-string properties i.e color
|
||||
var newVal = all.get(addIt.key) + '|';
|
||||
all.set(addIt.key, newVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nodecount++;
|
||||
}
|
||||
// builds the table property rows and sets multipleProperties to help with updateall
|
||||
var mapIt;
|
||||
if (!this.showAllProperties) mapIt = shared.iterator;
|
||||
else mapIt = all.iterator;
|
||||
while (mapIt.next()) {
|
||||
tbody.appendChild(this.buildPropertyRow(mapIt.key, mapIt.value)); // shows the properties that are allowed
|
||||
}
|
||||
table.appendChild(tbody);
|
||||
mainDiv.appendChild(table);
|
||||
var allIt = all.iterator;
|
||||
while (allIt.next()) {
|
||||
this._multipleProperties[allIt.key] = allIt.value; // used for updateall to know which properties to change
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* This predicate should be false if the given property should not be shown.
|
||||
* Normally it only checks the value of "show" on the property descriptor.
|
||||
* The default value is true.
|
||||
* @param {string} propertyName the property name
|
||||
* @param {Object} propertyDesc the property descriptor
|
||||
* @param {Object} inspectedObject the data object
|
||||
* @return {boolean} whether a particular property should be shown in this Inspector
|
||||
*/
|
||||
Inspector.prototype.canShowProperty = function(propertyName, propertyDesc, inspectedObject) {
|
||||
if (propertyDesc.show === false) return false;
|
||||
// if "show" is a predicate, make sure it passes or do not show this property
|
||||
if (typeof propertyDesc.show === "function") return propertyDesc.show(inspectedObject, propertyName);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* This predicate should be false if the given property should not be editable by the user.
|
||||
* Normally it only checks the value of "readOnly" on the property descriptor.
|
||||
* The default value is true.
|
||||
* @param {string} propertyName the property name
|
||||
* @param {Object} propertyDesc the property descriptor
|
||||
* @param {Object} inspectedObject the data object
|
||||
* @return {boolean} whether a particular property should be shown in this Inspector
|
||||
*/
|
||||
Inspector.prototype.canEditProperty = function(propertyName, propertyDesc, inspectedObject) {
|
||||
if (this._diagram.isReadOnly || this._diagram.isModelReadOnly) return false;
|
||||
// assume property values that are functions of Objects cannot be edited
|
||||
var data = (inspectedObject instanceof go.Part) ? inspectedObject.data : inspectedObject;
|
||||
var valtype = typeof data[propertyName];
|
||||
if (valtype === "function") return false;
|
||||
if (propertyDesc) {
|
||||
if (propertyDesc.readOnly === true) return false;
|
||||
// if "readOnly" is a predicate, make sure it passes or do not show this property
|
||||
if (typeof propertyDesc.readOnly === "function") return !propertyDesc.readOnly(inspectedObject, propertyName);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @param {any} propName
|
||||
* @param {any} propDesc
|
||||
* @param {any} data
|
||||
* @return {any}
|
||||
*/
|
||||
Inspector.prototype.findValue = function(propName, propDesc, data) {
|
||||
var val = '';
|
||||
if (propDesc && propDesc.defaultValue !== undefined) val = propDesc.defaultValue;
|
||||
if (data[propName] !== undefined) val = data[propName];
|
||||
if (val === undefined) return '';
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* This sets this._inspectedProperties[propertyName] and creates the HTML table row:
|
||||
* <tr>
|
||||
* <td>propertyName</td>
|
||||
* <td><input value=propertyValue /></td>
|
||||
* </tr>
|
||||
* @param {string} propertyName the property name
|
||||
* @param {*} propertyValue the property value
|
||||
* @return the table row
|
||||
*/
|
||||
Inspector.prototype.buildPropertyRow = function(propertyName, propertyValue) {
|
||||
var mainDiv = this._div;
|
||||
var tr = document.createElement("tr");
|
||||
|
||||
var td1 = document.createElement("td");
|
||||
td1.textContent = propertyName;
|
||||
tr.appendChild(td1);
|
||||
|
||||
var td2 = document.createElement("td");
|
||||
var decProp = this.declaredProperties[propertyName];
|
||||
var input = null;
|
||||
var self = this;
|
||||
function updateall() { self.updateAllProperties(); }
|
||||
|
||||
if (decProp && decProp.type === "select") {
|
||||
input = document.createElement("select");
|
||||
this.updateSelect(decProp, input, propertyName, propertyValue);
|
||||
input.addEventListener("change", updateall);
|
||||
} else {
|
||||
input = document.createElement("input");
|
||||
|
||||
input.value = this.convertToString(propertyValue);
|
||||
if (decProp) {
|
||||
var t = decProp.type;
|
||||
if (t !== 'string' && t !== 'number' && t !== 'boolean' &&
|
||||
t !== 'arrayofnumber' && t !== 'point' && t !== 'size' &&
|
||||
t !== 'rect' && t !== 'spot' && t !== 'margin') {
|
||||
input.setAttribute("type", decProp.type);
|
||||
}
|
||||
if (decProp.type === "color") {
|
||||
if (input.type === "color") {
|
||||
input.value = this.convertToColor(propertyValue);
|
||||
input.addEventListener("change", updateall);
|
||||
}
|
||||
} if (decProp.type === "checkbox") {
|
||||
input.checked = !!propertyValue;
|
||||
input.addEventListener("change", updateall);
|
||||
}
|
||||
}
|
||||
if (input.type !== "color") input.addEventListener("blur", updateall);
|
||||
}
|
||||
|
||||
if (input) {
|
||||
input.tabIndex = this.tabIndex++;
|
||||
input.disabled = !this.canEditProperty(propertyName, decProp, this.inspectedObject);
|
||||
td2.appendChild(input);
|
||||
}
|
||||
tr.appendChild(td2);
|
||||
|
||||
this._inspectedProperties[propertyName] = input;
|
||||
return tr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* HTML5 color input will only take hex,
|
||||
* so var HTML5 canvas convert the color into hex format.
|
||||
* This converts "rgb(255, 0, 0)" into "#FF0000", etc.
|
||||
* @param {string} propertyValue
|
||||
* @return {string}
|
||||
*/
|
||||
Inspector.prototype.convertToColor = function(propertyValue) {
|
||||
var ctx = document.createElement("canvas").getContext("2d");
|
||||
ctx.fillStyle = propertyValue;
|
||||
return ctx.fillStyle;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @param {string}
|
||||
* @return {Array.<number>}
|
||||
*/
|
||||
Inspector.prototype.convertToArrayOfNumber = function(propertyValue) {
|
||||
if (propertyValue === "null") return null;
|
||||
var split = propertyValue.split(' ');
|
||||
var arr = [];
|
||||
for (var i = 0; i < split.length; i++) {
|
||||
var str = split[i];
|
||||
if (!str) continue;
|
||||
arr.push(parseFloat(str));
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @param {*}
|
||||
* @return {string}
|
||||
*/
|
||||
Inspector.prototype.convertToString = function(x) {
|
||||
if (x === undefined) return "undefined";
|
||||
if (x === null) return "null";
|
||||
if (x instanceof go.Point) return go.Point.stringify(x);
|
||||
if (x instanceof go.Size) return go.Size.stringify(x);
|
||||
if (x instanceof go.Rect) return go.Rect.stringify(x);
|
||||
if (x instanceof go.Spot) return go.Spot.stringify(x);
|
||||
if (x instanceof go.Margin) return go.Margin.stringify(x);
|
||||
if (x instanceof go.List) return this.convertToString(x.toArray());
|
||||
if (Array.isArray(x)) {
|
||||
var str = "";
|
||||
for (var i = 0; i < x.length; i++) {
|
||||
if (i > 0) str += " ";
|
||||
var v = x[i];
|
||||
str += this.convertToString(v);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
return x.toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* Update all of the HTML in this Inspector.
|
||||
*/
|
||||
Inspector.prototype.updateAllHTML = function() {
|
||||
var inspectedProps = this._inspectedProperties;
|
||||
var diagram = this._diagram;
|
||||
var isPart = this.inspectedObject instanceof go.Part;
|
||||
var data = isPart ? this.inspectedObject.data : this.inspectedObject;
|
||||
if (!data) { // clear out all of the fields
|
||||
for (var name in inspectedProps) {
|
||||
var input = inspectedProps[name];
|
||||
if (input instanceof HTMLSelectElement) {
|
||||
input.innerHTML = "";
|
||||
} else if (input.type === "color") {
|
||||
input.value = "#000000";
|
||||
} else if (input.type === "checkbox") {
|
||||
input.checked = false;
|
||||
} else {
|
||||
input.value = "";
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
for (var name in inspectedProps) {
|
||||
var input = inspectedProps[name];
|
||||
var propertyValue = data[name];
|
||||
if (input instanceof HTMLSelectElement) {
|
||||
var decProp = this.declaredProperties[name];
|
||||
this.updateSelect(decProp, input, name, propertyValue);
|
||||
} else if (input.type === "color") {
|
||||
input.value = this.convertToColor(propertyValue);
|
||||
} else if (input.type === "checkbox") {
|
||||
input.checked = !!propertyValue;
|
||||
} else {
|
||||
input.value = this.convertToString(propertyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* Update an HTMLSelectElement with an appropriate list of choices, given the propertyName
|
||||
*/
|
||||
Inspector.prototype.updateSelect = function(decProp, select, propertyName, propertyValue) {
|
||||
select.innerHTML = ""; // clear out anything that was there
|
||||
var choices = decProp.choices;
|
||||
if (typeof choices === "function") choices = choices(this.inspectedObject, propertyName);
|
||||
if (!Array.isArray(choices)) choices = [];
|
||||
decProp.choicesArray = choices; // remember list of actual choice values (not strings)
|
||||
for (var i = 0; i < choices.length; i++) {
|
||||
var choice = choices[i];
|
||||
var opt = document.createElement("option");
|
||||
opt.text = this.convertToString(choice);
|
||||
select.add(opt, null);
|
||||
}
|
||||
select.value = this.convertToString(propertyValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* Update all of the data properties of {@link #inspectedObject} according to the
|
||||
* current values held in the HTML input elements.
|
||||
*/
|
||||
Inspector.prototype.updateAllProperties = function() {
|
||||
var inspectedProps = this._inspectedProperties;
|
||||
var diagram = this._diagram;
|
||||
if (diagram.selection.count === 1 || !this.multipleSelection) { // single object update
|
||||
var isPart = this.inspectedObject instanceof go.Part;
|
||||
var data = isPart ? this.inspectedObject.data : this.inspectedObject;
|
||||
if (!data) return; // must not try to update data when there's no data!
|
||||
|
||||
diagram.startTransaction('set all properties');
|
||||
for (var name in inspectedProps) {
|
||||
var input = inspectedProps[name];
|
||||
var value = input.value;
|
||||
|
||||
// don't update "readOnly" data properties
|
||||
var decProp = this.declaredProperties[name];
|
||||
if (!this.canEditProperty(name, decProp, this.inspectedObject)) continue;
|
||||
|
||||
// If it's a boolean, or if its previous value was boolean,
|
||||
// parse the value to be a boolean and then update the input.value to match
|
||||
var type = '';
|
||||
if (decProp !== undefined && decProp.type !== undefined) {
|
||||
type = decProp.type;
|
||||
}
|
||||
if (type === '') {
|
||||
var oldval = data[name];
|
||||
if (typeof oldval === 'boolean') type = 'boolean'; // infer boolean
|
||||
else if (typeof oldval === 'number') type = 'number';
|
||||
else if (oldval instanceof go.Point) type = 'point';
|
||||
else if (oldval instanceof go.Size) type = 'size';
|
||||
else if (oldval instanceof go.Rect) type = 'rect';
|
||||
else if (oldval instanceof go.Spot) type = 'spot';
|
||||
else if (oldval instanceof go.Margin) type = 'margin';
|
||||
}
|
||||
|
||||
// convert to specific type, if needed
|
||||
switch (type) {
|
||||
case 'boolean': value = !(value === false || value === 'false' || value === '0'); break;
|
||||
case 'number': value = parseFloat(value); break;
|
||||
case 'arrayofnumber': value = this.convertToArrayOfNumber(value); break;
|
||||
case 'point': value = go.Point.parse(value); break;
|
||||
case 'size': value = go.Size.parse(value); break;
|
||||
case 'rect': value = go.Rect.parse(value); break;
|
||||
case 'spot': value = go.Spot.parse(value); break;
|
||||
case 'margin': value = go.Margin.parse(value); break;
|
||||
case 'checkbox': value = input.checked; break;
|
||||
case 'select': value = decProp.choicesArray[input.selectedIndex]; break;
|
||||
}
|
||||
|
||||
// in case parsed to be different, such as in the case of boolean values,
|
||||
// the value shown should match the actual value
|
||||
input.value = value;
|
||||
|
||||
// modify the data object in an undo-able fashion
|
||||
diagram.model.setDataProperty(data, name, value);
|
||||
|
||||
// notify any listener
|
||||
if (this.propertyModified !== null) this.propertyModified(name, value, this);
|
||||
}
|
||||
diagram.commitTransaction('set all properties');
|
||||
} else { // selection object update
|
||||
diagram.startTransaction('set all properties');
|
||||
for (var name in inspectedProps) {
|
||||
var input = inspectedProps[name];
|
||||
var value = input.value;
|
||||
var arr1 = value.split('|');
|
||||
var arr2 = [];
|
||||
if (this._multipleProperties[name]) {
|
||||
// don't split if it is union and its checkbox type
|
||||
if (this.declaredProperties[name] && this.declaredProperties[name].type === 'checkbox' && this.showAllProperties) {
|
||||
arr2.push(this._multipleProperties[name]);
|
||||
} else {
|
||||
arr2 = this._multipleProperties[name].toString().split('|');
|
||||
}
|
||||
}
|
||||
var it = diagram.selection.iterator;
|
||||
var change = false;
|
||||
if (this.declaredProperties[name] && this.declaredProperties[name].type === 'checkbox') change = true; // always change checkbox
|
||||
if (arr1.length < arr2.length // i.e Alpha|Beta -> Alpha procs the change
|
||||
&& (!this.declaredProperties[name] // from and to links
|
||||
|| !(this.declaredProperties[name] // do not change color checkbox and choices due to them always having less
|
||||
&& (this.declaredProperties[name].type === 'color' || this.declaredProperties[name].type === 'checkbox' || this.declaredProperties[name].type === 'choices')))) {
|
||||
change = true;
|
||||
} else { // standard detection in change in properties
|
||||
for (var j = 0; j < arr1.length && j < arr2.length; j++) {
|
||||
if (!(arr1[j] === arr2[j])
|
||||
&& !(this.declaredProperties[name] && this.declaredProperties[name].type === 'color' && arr1[j].toLowerCase() === arr2[j].toLowerCase())) {
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (change) { // only change properties it needs to change instead all of them
|
||||
for (var i = 0; i < diagram.selection.count; i++) {
|
||||
it.next();
|
||||
var isPart = it.value instanceof go.Part;
|
||||
var data = isPart ? it.value.data : it.value;
|
||||
|
||||
if (data) { // ignores the selected node if there is no data
|
||||
if (i < arr1.length) value = arr1[i];
|
||||
else value = arr1[0];
|
||||
|
||||
// don't update "readOnly" data properties
|
||||
var decProp = this.declaredProperties[name];
|
||||
if (!this.canEditProperty(name, decProp, it.value)) continue;
|
||||
|
||||
// If it's a boolean, or if its previous value was boolean,
|
||||
// parse the value to be a boolean and then update the input.value to match
|
||||
var type = '';
|
||||
if (decProp !== undefined && decProp.type !== undefined) {
|
||||
type = decProp.type;
|
||||
}
|
||||
if (type === '') {
|
||||
var oldval = data[name];
|
||||
if (typeof oldval === 'boolean') type = 'boolean'; // infer boolean
|
||||
else if (typeof oldval === 'number') type = 'number';
|
||||
else if (oldval instanceof go.Point) type = 'point';
|
||||
else if (oldval instanceof go.Size) type = 'size';
|
||||
else if (oldval instanceof go.Rect) type = 'rect';
|
||||
else if (oldval instanceof go.Spot) type = 'spot';
|
||||
else if (oldval instanceof go.Margin) type = 'margin';
|
||||
}
|
||||
|
||||
// convert to specific type, if needed
|
||||
switch (type) {
|
||||
case 'boolean': value = !(value === false || value === 'false' || value === '0'); break;
|
||||
case 'number': value = parseFloat(value); break;
|
||||
case 'arrayofnumber': value = this.convertToArrayOfNumber(value); break;
|
||||
case 'point': value = go.Point.parse(value); break;
|
||||
case 'size': value = go.Size.parse(value); break;
|
||||
case 'rect': value = go.Rect.parse(value); break;
|
||||
case 'spot': value = go.Spot.parse(value); break;
|
||||
case 'margin': value = go.Margin.parse(value); break;
|
||||
case 'checkbox': value = input.checked; break;
|
||||
case 'select': value = decProp.choicesArray[input.selectedIndex]; break;
|
||||
}
|
||||
|
||||
// in case parsed to be different, such as in the case of boolean values,
|
||||
// the value shown should match the actual value
|
||||
input.value = value;
|
||||
|
||||
// modify the data object in an undo-able fashion
|
||||
diagram.model.setDataProperty(data, name, value);
|
||||
|
||||
// notify any listener
|
||||
if (this.propertyModified !== null) this.propertyModified(name, value, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
diagram.commitTransaction('set all properties');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright (C) 1998-2020 by Northwoods Software Corporation
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Floorplanner app-specific tweaks to the basic Data Inspector class
|
||||
*/
|
||||
|
||||
function tweakInspectorForFloorplanner(inspector) {
|
||||
|
||||
inspector.declaredProperties =
|
||||
{
|
||||
"key": { show: false },
|
||||
"shape": { show: false },
|
||||
"caption": { show: false },
|
||||
"loc": { show: false },
|
||||
"geo": { show: false },
|
||||
"doorOpeningHeight": { show: false },
|
||||
"type": { show: Inspector.showIfPresent, readOnly: true },
|
||||
"category": { show: false },
|
||||
"isGroup": { show: false },
|
||||
"startpoint": { show: false },
|
||||
"endpoint": { show: false },
|
||||
"smpt1": { show: false },
|
||||
"smpt2": { show: false },
|
||||
"empt1": { show: false },
|
||||
"empt2": { show: false },
|
||||
"swing": { show: false },
|
||||
"area": { show: Inspector.showIfPresent, readOnly: true },
|
||||
"name": { show: Inspector.showIfPresent },
|
||||
"boundaryWalls": { show: false },
|
||||
"holes": { show: false },
|
||||
"angle": { show: false },
|
||||
"group": { show: false },
|
||||
"notes": { show: Inspector.showIfPresent },
|
||||
"color": { show: function (part) { return Inspector.showIfPresent && !part.data.usesTexture && (part.category === '' || part.category === 'MultiPurposeNode') }, type: 'color' },
|
||||
"stroke": { show: false, type: 'color' },
|
||||
"text": { show: Inspector.showIfPresent },
|
||||
"height": { show: function (part) { return part.category === "" || part.category === "MultiPurposeNode"; } },
|
||||
"width": { show: function (part) { return part.category === "" || part.category === "MultiPurposeNode"; } },
|
||||
"thickness": { show: function (part) { return part.category === "WallGroup" && !part.data.isDivider; } },
|
||||
"isDivider": { show: false },
|
||||
"showLabel": { show: Inspector.showIfPresent, type: 'checkbox' },
|
||||
"floorImage": { show: false },
|
||||
"showFlooringOptions": { show: false },
|
||||
"labelAlignment": { show: false },
|
||||
"texture": { show: false },
|
||||
"textures": { show: false },
|
||||
"showTextureOptions": { show: false },
|
||||
"usesTexture": { show: Inspector.showIfPresent, type: 'checkbox' }
|
||||
};
|
||||
|
||||
// this is tangentially related to inspector
|
||||
// when a node is double clicked on, show the inspector (if it is not shown)
|
||||
myFloorplan.nodeTemplateMap.iterator.each(function (kvp) {
|
||||
let template = kvp.value;
|
||||
template.doubleClick = function () {
|
||||
geHideShowWindow('ge-inspector-window', true);
|
||||
}
|
||||
myFloorplan.nodeTemplateMap.add(kvp.key, template);
|
||||
});
|
||||
|
||||
myFloorplan.groupTemplateMap.iterator.each(function (kvp) {
|
||||
let template = kvp.value;
|
||||
template.doubleClick = function () {
|
||||
geHideShowWindow('ge-inspector-window', true);
|
||||
}
|
||||
myFloorplan.groupTemplateMap.add(kvp.key, template);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Override changes include
|
||||
* - Convert raw measurement numbers to units (cm, m, ft, in)
|
||||
**/
|
||||
Inspector.prototype.buildPropertyRow = function (propertyName, propertyValue) {
|
||||
var mainDiv = this._div;
|
||||
var tr = document.createElement("tr");
|
||||
|
||||
var td1 = document.createElement("td");
|
||||
td1.textContent = propertyName;
|
||||
tr.appendChild(td1);
|
||||
|
||||
var td2 = document.createElement("td");
|
||||
var decProp = this.declaredProperties[propertyName];
|
||||
var input = null;
|
||||
var self = this;
|
||||
function updateall() { self.updateAllProperties(); }
|
||||
|
||||
if (decProp && decProp.type === "select") {
|
||||
input = document.createElement("select");
|
||||
this.updateSelect(decProp, input, propertyName, propertyValue);
|
||||
input.addEventListener("change", updateall);
|
||||
}
|
||||
|
||||
else {
|
||||
input = document.createElement("input");
|
||||
var doModify = true;
|
||||
// if height | width, convert to units (cm, m, ft, in)
|
||||
if (propertyName === "height" || propertyName === "width" || propertyName === "thickness" || propertyName === "length" || propertyName === "area") {
|
||||
propertyValue = myFloorplan.convertPixelsToUnits(propertyValue);
|
||||
if (propertyName === "area") {
|
||||
// units squared, must convert twice
|
||||
propertyValue = myFloorplan.convertPixelsToUnits(propertyValue);
|
||||
propertyValue = propertyValue.toFixed(2);
|
||||
}
|
||||
input.className = "unitsInput"; // this ensures values in these inputs are updated when units change
|
||||
if (isNaN(propertyValue) || propertyValue <= 0) {
|
||||
doModify = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (doModify) {
|
||||
input.value = this.convertToString(propertyValue);
|
||||
}
|
||||
|
||||
if (decProp) {
|
||||
var t = decProp.type;
|
||||
if (t !== 'string' && t !== 'number' && t !== 'boolean' &&
|
||||
t !== 'arrayofnumber' && t !== 'point' && t !== 'size' &&
|
||||
t !== 'rect' && t !== 'spot' && t !== 'margin') {
|
||||
input.setAttribute("type", decProp.type);
|
||||
}
|
||||
if (decProp.type === "color") {
|
||||
if (input.type === "color") {
|
||||
input.value = this.convertToColor(propertyValue);
|
||||
input.addEventListener("change", updateall);
|
||||
}
|
||||
} if (decProp.type === "checkbox") {
|
||||
input.checked = !!propertyValue;
|
||||
input.addEventListener("change", updateall);
|
||||
}
|
||||
}
|
||||
if (input.type !== "color") input.addEventListener("blur", updateall);
|
||||
}
|
||||
|
||||
if (input) {
|
||||
input.tabIndex = this.tabIndex++;
|
||||
input.disabled = !this.canEditProperty(propertyName, decProp, this.inspectedObject);
|
||||
td2.appendChild(input);
|
||||
}
|
||||
tr.appendChild(td2);
|
||||
|
||||
// maybe need a units tag
|
||||
if (input && propertyName === "height" || propertyName === "width" || propertyName === "thickness" || propertyName === "length" || propertyName === "area") {
|
||||
var input2 = document.createElement("input");
|
||||
input2.value = myFloorplan.model.modelData.unitsAbbreviation;
|
||||
input2.disabled = true;
|
||||
input2.className = "unitsBox";
|
||||
if (propertyName === "area") {
|
||||
input2.value += String.fromCharCode(178);
|
||||
}
|
||||
td2.appendChild(input2);
|
||||
}
|
||||
|
||||
this._inspectedProperties[propertyName] = input;
|
||||
return tr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override changes include
|
||||
* - Convert raw measurement numbers to units (cm, m, ft, in)
|
||||
*/
|
||||
Inspector.prototype.updateAllHTML = function () {
|
||||
var inspectedProps = this._inspectedProperties;
|
||||
var diagram = this._diagram;
|
||||
var isPart = this.inspectedObject instanceof go.Part;
|
||||
if (this.inspectedObject instanceof go.Node) {
|
||||
const node = this.inspectedObject;
|
||||
if (node.category !== 'RoomNode') {
|
||||
node.updateTargetBindings();
|
||||
node.updateAdornments();
|
||||
}
|
||||
}
|
||||
var data = isPart ? this.inspectedObject.data : this.inspectedObject;
|
||||
if (!data) { // clear out all of the fields
|
||||
for (var name in inspectedProps) {
|
||||
var input = inspectedProps[name];
|
||||
var table = input.parentNode.parentNode.parentNode;
|
||||
if (table) {
|
||||
table.innerHTML = "No node selected";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (var name in inspectedProps) {
|
||||
var input = inspectedProps[name];
|
||||
var propertyValue = data[name];
|
||||
// if height | width, convert to units (cm, m, ft, in)
|
||||
if (name === "height" || name === "width" || name === "thickness" || name === "length" || name === "area") {
|
||||
propertyValue = myFloorplan.convertPixelsToUnits(propertyValue);
|
||||
if (name === "area") {
|
||||
// units squared, must convert twice
|
||||
propertyValue = myFloorplan.convertPixelsToUnits(propertyValue);
|
||||
propertyValue = propertyValue.toFixed(2);
|
||||
}
|
||||
input.value = propertyValue;
|
||||
}
|
||||
else if (input instanceof HTMLSelectElement) {
|
||||
var decProp = this.declaredProperties[name];
|
||||
this.updateSelect(decProp, input, name, propertyValue);
|
||||
} else if (input.type === "color") {
|
||||
input.value = this.convertToColor(propertyValue);
|
||||
} else if (input.type === "checkbox") {
|
||||
input.checked = !!propertyValue;
|
||||
} else {
|
||||
input.value = this.convertToString(propertyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override changes include
|
||||
* - Convert units measurements to raw units (cm, m, ft, in to document units)
|
||||
*/
|
||||
Inspector.prototype.updateAllProperties = function () {
|
||||
var inspectedProps = this._inspectedProperties;
|
||||
var diagram = this._diagram;
|
||||
if (diagram.selection.count === 1 || !this.multipleSelection) { // single object update
|
||||
var isPart = this.inspectedObject instanceof go.Part;
|
||||
var data = isPart ? this.inspectedObject.data : this.inspectedObject;
|
||||
if (!data) return; // must not try to update data when there's no data!
|
||||
|
||||
diagram.startTransaction('set all properties');
|
||||
for (var name in inspectedProps) {
|
||||
var input = inspectedProps[name];
|
||||
var value = input.value;
|
||||
|
||||
// don't update "readOnly" data properties
|
||||
var decProp = this.declaredProperties[name];
|
||||
if (!this.canEditProperty(name, decProp, this.inspectedObject)) continue;
|
||||
|
||||
// If it's a boolean, or if its previous value was boolean,
|
||||
// parse the value to be a boolean and then update the input.value to match
|
||||
var type = '';
|
||||
if (decProp !== undefined && decProp.type !== undefined) {
|
||||
type = decProp.type;
|
||||
}
|
||||
if (type === '') {
|
||||
var oldval = data[name];
|
||||
if (typeof oldval === 'boolean') type = 'boolean'; // infer boolean
|
||||
else if (typeof oldval === 'number') type = 'number';
|
||||
else if (oldval instanceof go.Point) type = 'point';
|
||||
else if (oldval instanceof go.Size) type = 'size';
|
||||
else if (oldval instanceof go.Rect) type = 'rect';
|
||||
else if (oldval instanceof go.Spot) type = 'spot';
|
||||
else if (oldval instanceof go.Margin) type = 'margin';
|
||||
}
|
||||
|
||||
// convert to specific type, if needed
|
||||
switch (type) {
|
||||
case 'boolean': value = !(value === false || value === 'false' || value === '0'); break;
|
||||
case 'number': value = parseFloat(value); break;
|
||||
case 'arrayofnumber': value = this.convertToArrayOfNumber(value); break;
|
||||
case 'point': value = go.Point.parse(value); break;
|
||||
case 'size': value = go.Size.parse(value); break;
|
||||
case 'rect': value = go.Rect.parse(value); break;
|
||||
case 'spot': value = go.Spot.parse(value); break;
|
||||
case 'margin': value = go.Margin.parse(value); break;
|
||||
case 'checkbox': value = input.checked; break;
|
||||
case 'select': value = decProp.choicesArray[input.selectedIndex]; break;
|
||||
}
|
||||
|
||||
// if height | width, convert to units (cm, m, ft, in)
|
||||
if (input && name === "height" || name === "width" || name === "thickness" || name === "length" || name === "area") {
|
||||
value = myFloorplan.convertUnitsToPixels(value);
|
||||
if (name === "area") {
|
||||
// units squared, must convert twice
|
||||
value = myFloorplan.convertUnitsToPixels(value);
|
||||
value = propertyValue.toFixed(2);
|
||||
}
|
||||
if (isNaN(parseFloat(value)) || parseFloat(value) <= 0) {
|
||||
var oldVal = this.inspectedObject.data[name];
|
||||
value = oldVal;
|
||||
}
|
||||
}
|
||||
|
||||
// in case parsed to be different, such as in the case of boolean values,
|
||||
// the value shown should match the actual value
|
||||
input.value = value;
|
||||
|
||||
// modify the data object in an undo-able fashion
|
||||
diagram.model.setDataProperty(data, name, value);
|
||||
|
||||
if (this.inspectedObject.category === 'WallGroup') {
|
||||
var wall = this.inspectedObject;
|
||||
var wrt = myFloorplan.toolManager.mouseDownTools.elt(3);
|
||||
wrt.performMiteringOnWall(wall);
|
||||
var set = new go.Set(); set.add(wall);
|
||||
myFloorplan.updateAllRoomBoundaries(set);
|
||||
}
|
||||
|
||||
// notify any listener
|
||||
if (this.propertyModified !== null) this.propertyModified(name, value, this);
|
||||
}
|
||||
|
||||
diagram.commitTransaction('set all properties');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*-- set border box on all elements inside the grid*/
|
||||
.grid-container * {box-sizing: border-box;}
|
||||
|
||||
.row:before, .row::after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
[class*='col-'] {
|
||||
float: left;
|
||||
min-height: 1px;
|
||||
width: 16.66%;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.col-1 {width: 100%;}
|
||||
.col-2 {width: 50%;}
|
||||
.col-3 {width: 33.33%;}
|
||||
.col-4 {width: 25%;}
|
||||
.col-5 {width: 20%;}
|
||||
.col-6 {width: 16.66%;}
|
||||
|
||||
input{
|
||||
padding: 0px;
|
||||
border: 1px solid gray;
|
||||
}
|
||||
.unitsBox{ /*A special input that displays units*/
|
||||
text-align: center;
|
||||
width: 20px;
|
||||
border: 1px solid gray;
|
||||
border-left: 0px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#wallThicknessInput, #gridSizeInput, #unitsConversionFactorInput {
|
||||
width: 50px;
|
||||
float: left;
|
||||
border-right: 0px;
|
||||
}
|
||||
#gridSizeInput, #unitsConversionFactorInput {
|
||||
margin-left: 10%;
|
||||
}
|
||||
#wallThicknesshUnitsInput, #gridSizeUnitsInput{
|
||||
float: left;
|
||||
}
|
||||
|
||||
.unitsInput {
|
||||
float: left;
|
||||
border-right: 0px;
|
||||
}
|
||||
|
||||
#optionsWindow {
|
||||
height: unset;
|
||||
width: unset;
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* goeditor-setup.js
|
||||
* Called before init() events in every goeditor app
|
||||
* Initializes the diagrams, palettes, GoCloudStorage, and the Inspector
|
||||
* You may need to edit or override things in your own code
|
||||
* DO NOT edit this file -- make app-specific overrides or custom changes in your own code
|
||||
* DO NOT delete or rename this file
|
||||
*/
|
||||
|
||||
function setupEditorApplication(diagramsCount, palettesCount, pathToStorage, diagramsType) {
|
||||
|
||||
if (diagramsType === null || !diagramsType) {
|
||||
diagramsType = go.Diagram;
|
||||
}
|
||||
|
||||
// GoCloudStorage helpers
|
||||
var isAutoSavingCheckbox = document.getElementById("isAutoSavingCheckbox");
|
||||
var isAutoSavingP = document.getElementById("isAutoSavingP");
|
||||
|
||||
// choose new storage service; then, update the current storage span with the correct picture of the current storage service being used
|
||||
updateCurrentStorageSpan = function () {
|
||||
storageManager.selectStorageService().then(function (storage) {
|
||||
var span = document.getElementById("currentStorageSpan");
|
||||
span.innerHTML = "";
|
||||
var imageSrc = storageManager.getStorageIconPath(storage.className);
|
||||
var img = document.createElement("img");
|
||||
img.src = imageSrc;
|
||||
img.style.width = "20px"; img.style.height = "20px"; img.style.float = "left";
|
||||
span.appendChild(img);
|
||||
storage.isAutoSaving = isAutoSavingCheckbox.checked;
|
||||
updateAutoSaveVisibility();
|
||||
});
|
||||
}
|
||||
|
||||
isAutoSavingCheckbox.addEventListener("change", function () {
|
||||
storageManager.storages.iterator.each(function (storage) {
|
||||
storage.isAutoSaving = isAutoSavingCheckbox.checked;
|
||||
});
|
||||
// update the title to reflect the save
|
||||
var currentFile = document.getElementById("ge-filename");
|
||||
var currentFileTitle = currentFile.innerText;
|
||||
if (currentFileTitle[currentFileTitle.length - 1] == "*" && storageManager.currentStorage.currentDiagramFile.name != null) {
|
||||
currentFile.innerText = currentFileTitle.substr(0, currentFileTitle.length - 1);
|
||||
storageManager.currentStorage.save();
|
||||
}
|
||||
});
|
||||
|
||||
// update the title on page to reflect newly loaded diagram title
|
||||
updateTitle = function () {
|
||||
var currentFile = document.getElementById("ge-filename");
|
||||
if (storageManager.currentStorage.currentDiagramFile.path !== null) {
|
||||
var storage = storageManager.currentStorage;
|
||||
if (storage.currentDiagramFile.path) currentFile.innerHTML = storage.currentDiagramFile.path;
|
||||
else currentFile.innerHTML = storage.currentDiagramFile.name;
|
||||
}
|
||||
else {
|
||||
currentFile.innerHTML = "Untitled";
|
||||
storageTag.innerHTML = "Unsaved";
|
||||
}
|
||||
}
|
||||
|
||||
// can only use the auto save checkbox if the file is already saved to the current storage service
|
||||
updateAutoSaveVisibility = function () {
|
||||
var cdf = storageManager.currentStorage.currentDiagramFile;
|
||||
isAutoSavingP.style.visibility = (cdf.name === null) ? "hidden" : "visible";
|
||||
}
|
||||
|
||||
/*
|
||||
* Promise handler for core functions
|
||||
* @param {String} action Accepted values: Load, Delete, New, Save
|
||||
*/
|
||||
handlePromise = function (action) {
|
||||
|
||||
function handleFileData(action, fileData) {
|
||||
var words = [];
|
||||
switch (action) {
|
||||
case 'Load': words = ['Loaded', 'from']; break;
|
||||
case 'Delete': words = ['Deleted', 'from']; break;
|
||||
case 'New': words = ['Created', 'at']; break;
|
||||
case 'Save': words = ['Saved', 'to']; break;
|
||||
case 'SaveAs': words = ['Saved', 'to']; break;
|
||||
}
|
||||
var storageServiceName = storageManager.currentStorage.serviceName;
|
||||
if (fileData.id && fileData.name && fileData.path) storageManager.showMessage(words[0] + ' ' + fileData.name + ' (file ID ' + fileData.id + ') ' +
|
||||
words[1] + ' path ' + fileData.path + " in " + storageServiceName, 1.5);
|
||||
else console.log(fileData); // may have an explanation for why fileData isn't complete
|
||||
updateTitle();
|
||||
updateAutoSaveVisibility();
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case 'Load': storageManager.load().then(function (fileData) {
|
||||
handleFileData(action, fileData);
|
||||
}); break;
|
||||
case 'Delete': storageManager.remove().then(function (fileData) {
|
||||
handleFileData(action, fileData);
|
||||
}); break;
|
||||
case 'New':
|
||||
var saveBefore = false;
|
||||
var currentFile = document.getElementById("ge-filename");
|
||||
// only prompt to save current changes iff there is some modified state
|
||||
var currentFileTitle = currentFile.innerText;
|
||||
if (currentFileTitle.substr(currentFileTitle.length - 1, 1) === "*") {
|
||||
saveBefore = true;
|
||||
}
|
||||
storageManager.create(saveBefore).then(function (fileData) {
|
||||
handleFileData(action, fileData);
|
||||
});
|
||||
break;
|
||||
case 'SaveAs': storageManager.save().then(function (fileData) {
|
||||
handleFileData(action, fileData);
|
||||
}); break;
|
||||
case 'Save': storageManager.save(false).then(function (fileData) {
|
||||
handleFileData(action, fileData);
|
||||
}); break;
|
||||
}
|
||||
}
|
||||
|
||||
// Small, generic helper functions
|
||||
refreshDraggableWindows = function () {
|
||||
jQuery(".gt-menu").draggable({ handle: ".gt-handle", stack: ".gt-menu", containment: 'window', scroll: false });
|
||||
}
|
||||
|
||||
|
||||
// makes images of each diagram
|
||||
makeDiagramImage = function () {
|
||||
for (var i = 0; i < diagrams.length; i++) {
|
||||
var diagram = diagrams[i];
|
||||
var imgdata = diagram.makeImageData({ maxSize: new go.Size(Infinity, Infinity), scale: 2, padding: 10, background: diagram.div.style.background });
|
||||
var a = document.createElement("a");
|
||||
var filename = document.getElementById("ge-filename").innerText;
|
||||
filename.split('.');
|
||||
filename = filename[0];
|
||||
a.download = filename;
|
||||
a.href = imgdata;
|
||||
a.target = "_blank";
|
||||
a.click();
|
||||
}
|
||||
}
|
||||
|
||||
// make SVG files of each diagram
|
||||
makeDiagramSvg = function () {
|
||||
for (var i = 0; i < diagrams.length; i++) {
|
||||
var diagram = diagrams[i];
|
||||
var svgDataEl = diagram.makeSVG();
|
||||
var s = new XMLSerializer();
|
||||
var svgData = s.serializeToString(svgDataEl);
|
||||
var svgBlob = new Blob([svgData], { type: "image/svg+xml;charset=utf-8" });
|
||||
var svgUrl = URL.createObjectURL(svgBlob);
|
||||
var downloadLink = document.createElement("a");
|
||||
downloadLink.href = svgUrl;
|
||||
var filename = document.getElementById("ge-filename").innerText;
|
||||
filename = filename.split('.');
|
||||
filename = filename[0];
|
||||
downloadLink.download = filename + ".svg";
|
||||
document.body.appendChild(downloadLink);
|
||||
downloadLink.click();
|
||||
document.body.removeChild(downloadLink);
|
||||
}
|
||||
}
|
||||
|
||||
$ = go.GraphObject.make; // for conciseness in defining templates
|
||||
|
||||
|
||||
// build diagrams
|
||||
diagrams = [];
|
||||
overviews = [];
|
||||
for (var i = 0; i < diagramsCount; i++) {
|
||||
var diagram = new diagramsType("ge-diagram-" + i); // create a Diagram for the DIV HTML element
|
||||
diagram.undoManager.isEnabled = true;
|
||||
// When diagram is modified, change title to include a *
|
||||
diagram.addChangedListener(function (e) {
|
||||
// maybe update the file header
|
||||
var currentFile = document.getElementById("ge-filename");
|
||||
if (isAutoSavingCheckbox.checked && storageManager.currentStorage.currentDiagramFile.name != null) return;
|
||||
if (currentFile) {
|
||||
var idx = currentFile.textContent.indexOf("*");
|
||||
if (e.diagram.isModified) {
|
||||
if (idx < 0) currentFile.textContent = currentFile.textContent + "*";
|
||||
}
|
||||
else {
|
||||
if (idx >= 0) currentFile.textContent = currentFile.textContent.substr(0, idx);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
diagrams[i] = diagram;
|
||||
|
||||
// make an overview for each diagram
|
||||
var overview = $(go.Overview, "ge-overview-" + i, { observed: diagram });
|
||||
overviews[i] = overview;
|
||||
}
|
||||
|
||||
// if there are no diagrams, there will be no overviews, so do not list that option in View menu
|
||||
if (diagramsCount < 1) {
|
||||
var viewOverviewsOption = document.getElementById("ge-viewoption-overviews");
|
||||
viewOverviewsOption.parentNode.removeChild(viewOverviewsOption);
|
||||
}
|
||||
|
||||
// build palette(s)
|
||||
palettes = [];
|
||||
for (var i = 0; i < palettesCount; i++) {
|
||||
var palette = $(go.Palette, "ge-palette-" + i);
|
||||
palettes[i] = palette;
|
||||
}
|
||||
|
||||
|
||||
// Go Cloud Storage stuff
|
||||
defaultModel = null; // change this if you want -- so GoCloudStorage documentation
|
||||
|
||||
var iconsDir = pathToStorage + "/goCloudStorageIcons/";
|
||||
gls = new gcs.GoLocalStorage(diagrams, defaultModel, iconsDir);
|
||||
god = new gcs.GoOneDrive(diagrams, 'f9b171a6-a12e-48c1-b86c-814ed40fcdd1', defaultModel, iconsDir);
|
||||
ggd = new gcs.GoGoogleDrive(diagrams, '16225373139-n24vtg7konuetna3ofbmfcaj2infhgmg.apps.googleusercontent.com', 'AIzaSyDBj43lBLpYMMVKw4aN_pvuRg7_XMVGf18', defaultModel, iconsDir);
|
||||
gdb = new gcs.GoDropBox(diagrams, '3sm2ko6q7u1gbix', defaultModel, iconsDir);
|
||||
storages = [gls, god, ggd, gdb];
|
||||
storageManager = new gcs.GoCloudStorageManager(storages, iconsDir);
|
||||
|
||||
var span = document.getElementById("currentStorageSpan");
|
||||
span.innerHTML = "";
|
||||
var imageSrc = storageManager.getStorageIconPath(storageManager.currentStorage.className);
|
||||
var img = document.createElement("img");
|
||||
img.src = imageSrc;
|
||||
img.style.width = "20px"; img.style.height = "20px"; img.style.float = "left";
|
||||
span.appendChild(img);
|
||||
|
||||
|
||||
document.getElementById('file-input').accept = ".csv";
|
||||
|
||||
storageManager.currentStorage.isAutoSaving = isAutoSavingCheckbox.checked;
|
||||
|
||||
// enable hotkeys
|
||||
document.body.addEventListener("keydown", function (e) {
|
||||
var keynum = e.which;
|
||||
if (e.ctrlKey) {
|
||||
e.preventDefault();
|
||||
switch (keynum) {
|
||||
case 83: handlePromise('Save'); break; // ctrl + s
|
||||
case 79: handlePromise('Load'); break; // ctrl + o
|
||||
case 68: handlePromise('New'); break; // ctrl + d
|
||||
case 82: handlePromise('Delete'); break; // ctrl + r
|
||||
case 80: geHideShowWindow('ge-palettes-window'); break;
|
||||
case 69: geHideShowWindow('ge-overviews-window'); break; // ctrl + e
|
||||
case 73: geHideShowWindow('ge-inspector-window'); break; // ctrl + i
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateAutoSaveVisibility();
|
||||
|
||||
// Format the inspector for your specific needs. You may need to edit the DataInspector class
|
||||
inspector = new Inspector('ge-inspector', diagrams[0],
|
||||
{
|
||||
includesOwnProperties: true,
|
||||
}
|
||||
);
|
||||
|
||||
geHideShowWindow = function (id, doShow) {
|
||||
var geWindow = document.getElementById(id);
|
||||
var vis = null;
|
||||
if (doShow === undefined) vis = geWindow.style.visibility === "visible" ? "hidden" : "visible";
|
||||
else if (doShow) vis = "visible";
|
||||
else vis = "hidden";
|
||||
|
||||
var pn = null;
|
||||
if (geWindow.parentNode.classList.contains("ge-menu")) {
|
||||
pn = geWindow.parentNode;
|
||||
}
|
||||
if (pn) {
|
||||
pn.style.visibility = vis;
|
||||
}
|
||||
geWindow.style.visibility = vis;
|
||||
}
|
||||
|
||||
function makeGCSWindowsDraggable() {
|
||||
// special -- make sure all gcs windows are draggable via jQuery UI classes
|
||||
// do so by wrapping the filepicker divs in a draggable ge-window div -- with a handle
|
||||
var gcsWindows = document.getElementsByClassName("goCustomFilepicker");
|
||||
gcsWindows = [].slice.call(gcsWindows);
|
||||
var gcsManagerMenu = document.getElementById("goCloudStorageManagerMenu");
|
||||
gcsWindows.push(gcsManagerMenu);
|
||||
for (var i = 0; i < gcsWindows.length; i++) {
|
||||
var gcsWindow = gcsWindows[i];
|
||||
|
||||
// possibly delete pre-existing window
|
||||
var id = "ge-" + gcsWindow.id + "-window";
|
||||
var windowParent = document.getElementById(id);
|
||||
if (windowParent !== null && windowParent !== undefined) {
|
||||
windowParent.parentNode.removeChild(windowParent);
|
||||
}
|
||||
|
||||
// construct window wrapper for gcs menu
|
||||
windowParent = document.createElement("div");
|
||||
windowParent.id = id;
|
||||
windowParent.classList.add("ge-draggable");
|
||||
windowParent.classList.add("ui-draggable");
|
||||
windowParent.classList.add("ge-menu");
|
||||
windowParent.style.visibility = "hidden";
|
||||
|
||||
|
||||
var handle = document.createElement("div");
|
||||
handle.id = id + "-handle";
|
||||
handle.classList.add("ge-handle");
|
||||
handle.classList.add("ui-draggable-handle");
|
||||
handle.innerText = "Storage";
|
||||
var button = document.createElement("button");
|
||||
button.id = id + "-close";
|
||||
button.innerText = "X";
|
||||
button.classList.add("ge-clickable");
|
||||
button.classList.add("ge-window-button");
|
||||
button.onclick = function () {
|
||||
var ci = this.id.indexOf("-close");
|
||||
var wpid = this.id.substring(0, ci);
|
||||
var windowParent = document.getElementById(wpid);
|
||||
geHideShowWindow(windowParent.id);
|
||||
for (var i = 0; i < windowParent.children.length; i++) {
|
||||
var child = windowParent.children[i];
|
||||
if (!child.classList.contains("ge-handle")) {
|
||||
child.style.visibility = windowParent.style.visibility;
|
||||
}
|
||||
}
|
||||
}
|
||||
handle.appendChild(button);
|
||||
|
||||
windowParent.appendChild(handle);
|
||||
|
||||
windowParent.appendChild(gcsWindow);
|
||||
document.body.appendChild(windowParent);
|
||||
|
||||
var observer = new MutationObserver(styleChangedCallback);
|
||||
observer.observe(gcsWindow, {
|
||||
attributes: true,
|
||||
attributeFilter: ['style'],
|
||||
});
|
||||
|
||||
function styleChangedCallback(mutations) {
|
||||
var newVis = mutations[0].target.style.visibility;
|
||||
var pn = mutations[0].target.parentNode;
|
||||
pn.style.visibility = newVis;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
JQUERY(function () {
|
||||
var draggables = document.getElementsByClassName("ge-draggable");
|
||||
for (var i = 0; i < draggables.length; i++) {
|
||||
var draggable = draggables[i];
|
||||
var id = "#" + draggable.id; var hid = id + "-handle";
|
||||
JQUERY(id).draggable({ handle: hid, stack: ".ge-draggable", containment: "window", scroll: false });
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
makeGCSWindowsDraggable();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* goeditor.css
|
||||
* Used for the goeditor framework
|
||||
* DO NOT edit this file. Use a custom CSS file for app-specific style changes
|
||||
* DO NOT delete or rename this file
|
||||
*/
|
||||
|
||||
|
||||
/********************************************** MAIN CONTENT STYLING ***********************************************/
|
||||
body {font-family: Arial; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none;}
|
||||
canvas:focus {outline:0;} /*don't outline palette and diagram when they are focused*/
|
||||
p, h1,h2,h3,h4,h5,h6{cursor: default}
|
||||
/*Style placeholder text to be black on all browsers*/
|
||||
::-webkit-input-placeholder { color: black; }
|
||||
::-moz-placeholder { color: black; }
|
||||
:-ms-input-placeholder { color: black; }
|
||||
/************************************************************* NAV BAR STYLING *************************************************/
|
||||
|
||||
nav {background: linear-gradient(#efefef ,#bbbbbb ); padding: 5px;}
|
||||
|
||||
nav ul { /*file menus and tool menus*/
|
||||
list-style: none;
|
||||
position: relative;
|
||||
display: flex;
|
||||
margin: 0; padding: 0;
|
||||
}
|
||||
|
||||
nav ul li { /*menu tabs*/
|
||||
float: left;
|
||||
transition-property: background;
|
||||
transition-duration: 0.3s;
|
||||
}
|
||||
nav ul li:hover {
|
||||
transition-delay: 0.1s, 0.1s;
|
||||
background: #4f5964;
|
||||
}
|
||||
|
||||
nav ul li a { /*menu tabs text*/
|
||||
display: block;
|
||||
padding-left: 25px; padding-right: 25px; padding-top: 2px;
|
||||
color: #757575; text-decoration: none;
|
||||
transition-property: background, color;
|
||||
transition-duration: 0.4s, 0.4s;
|
||||
}
|
||||
nav ul li:hover a {color: #fff;}
|
||||
|
||||
nav ul ul { /*drop down menus, general*/
|
||||
display: block;
|
||||
z-index: 20; /*in front of everything, even .draggables*/
|
||||
visibility: hidden; opacity: 0;
|
||||
transition-property: opacity;
|
||||
transition-duration: 0.3s;
|
||||
background: #5f6975; padding: 0;
|
||||
position: absolute; top: 100%;
|
||||
width: max-content;
|
||||
/* width: 220%; /*band aid fix for menu width -- TODO*/
|
||||
}
|
||||
nav ul li:hover > ul { /*drop down menus, visible*/
|
||||
visibility: visible; opacity: 1;
|
||||
transition-delay: 0.1s;
|
||||
}
|
||||
|
||||
nav ul ul li { /*drop down menu items*/
|
||||
border-top: 1px solid #6b727c;
|
||||
border-bottom: 1px solid #575f6a;
|
||||
position: relative; float: none;
|
||||
}
|
||||
nav ul ul li a { /*drown down menu items text*/
|
||||
padding: 5px;
|
||||
transition-property: background;
|
||||
transition-duration: 0.1s;
|
||||
}
|
||||
nav ul ul li a:hover {
|
||||
background: #4b545f;
|
||||
transition-delay: 0.1s;
|
||||
}
|
||||
|
||||
nav ul ul ul { /*drop down submenu (import from)*/
|
||||
left: 100%; top:0;
|
||||
}
|
||||
|
||||
nav p { /* grid input area, wall width area, and 'Tools' all wrapped in <p> tag*/
|
||||
float: left;
|
||||
margin-bottom: 0px;
|
||||
margin-top: 3px;
|
||||
padding-left: 25px;
|
||||
padding-right: 25px;
|
||||
color: #4b545f;
|
||||
}
|
||||
nav p.ge-shortcut {
|
||||
font-size: 9pt;
|
||||
float: right;
|
||||
color: #efefef;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#ge-header {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#ge-filename {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#ge-filemenus {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.ge-menu {
|
||||
z-index: 100;
|
||||
background: white;
|
||||
width: 400px;
|
||||
max-width: 500px;
|
||||
border: 1px solid black;
|
||||
top: 25%;
|
||||
left: 40%;
|
||||
position: absolute;
|
||||
box-shadow: 10px 10px 5px #888888;
|
||||
text-align: center;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.ge-handle * {
|
||||
padding: 2px;
|
||||
margin: 0;
|
||||
margin-bottom: 10px;
|
||||
background: gray;
|
||||
color: white;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.ge-scrollable {
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.ge-clickable {
|
||||
cursor: pointer;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.ge-clickable.ge-selected {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.ge-button {
|
||||
background-color: #4CAF50;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
margin: 4px 2px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#ge-datas-div {
|
||||
margin: 10px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.ge-data-option-div {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.ge-data-option-div span {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.ge-build-event-property-div, .ge-build-range-property-div {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.ge-build-event-property-div button, .ge-build-range-property-div button {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.ge-build-event-property-div select, .ge-build-event-property-div input, .ge-build-range-property-div label, .ge-build-range-property-div button,
|
||||
.ge-edit-timeline-property-div input, .ge-edit-timeline-property-div label {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.ge-replace-event-data-checkbox-div {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.ge-clickable {cursor: pointer;}
|
||||
|
||||
label > input{ /* HIDE RADIO */
|
||||
visibility: hidden; /* Makes input not-clickable */
|
||||
position: absolute; /* Remove input from document flow */
|
||||
}
|
||||
label > input + img{ /* IMAGE STYLES */
|
||||
cursor:pointer;
|
||||
border:2px solid transparent;
|
||||
}
|
||||
label > input:checked + img{ /* (RADIO CHECKED) IMAGE STYLES */
|
||||
border:2px solid #f00;
|
||||
}
|
||||
|
||||
#ge-footer {
|
||||
background: linear-gradient(#efefef ,#bbbbbb);
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#ge-palettes-window {
|
||||
height: inherit;
|
||||
top:12%;
|
||||
left:.5%;
|
||||
}
|
||||
|
||||
#ge-overviews-window {
|
||||
height: inherit;
|
||||
top: 12%;
|
||||
left: 87.5%;
|
||||
}
|
||||
|
||||
/********************************** DRAGGABLE WINDOWS GENERAL **************/
|
||||
|
||||
.ge-draggable {
|
||||
border: 1px solid gray;
|
||||
background-color: #e2e2e2;
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
width: 300px;
|
||||
height: unset;
|
||||
z-index: 10;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ge-handle {
|
||||
background-color: #4b545f;
|
||||
text-align: center;
|
||||
font: bold 12px sans-serif;
|
||||
color: white;
|
||||
cursor: move;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ge-window-button{
|
||||
float: right;
|
||||
border: none;
|
||||
font: bold 12px sans-serif;
|
||||
padding-bottom: 0; padding-top: 0;
|
||||
padding-left: 10px; padding-right: 10px;
|
||||
}
|
||||
|
||||
/* jQuery UI specific stylings */
|
||||
|
||||
.ui-accordion .ui-accordion-content, .ui-accordion .ui-accordion-icons {padding: 0px;}
|
||||
.ui-widget * { outline: none; }
|
||||
.ui-widget-content { border: none; }
|
||||
|
||||
/* Inspector window */
|
||||
|
||||
#ge-inspector-window {
|
||||
height: unset;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#ge-inspector {
|
||||
height: inherit; width: inherit;
|
||||
}
|
||||
|
||||
/****** GO CLOUD STORAGE STYLINGS OVERRIDES ***/
|
||||
|
||||
.ge-menu .goCustomFilepicker {
|
||||
width: -webkit-fill-available;
|
||||
height: unset;
|
||||
top: auto; left: auto;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ge-menu #goCloudStorageManagerMenu {
|
||||
width: unset;
|
||||
top: auto; left: auto;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#ge-goCloudStorageManagerMenu-window {
|
||||
height: auto;
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 742 B |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,512 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Floorplanner (Typescript)</title>
|
||||
<meta name="description" content="" />
|
||||
<!-- Copyright 1998-2020 by Northwoods Software Corporation. -->
|
||||
<meta charset="UTF-8">
|
||||
|
||||
<!-- Local JS -->
|
||||
<!-- GoJS -->
|
||||
<script src="../../release/go.js"></script>
|
||||
<!-- GoEditor framework basic setup -->
|
||||
<script src="./goeditor-setup.js"></script>
|
||||
<!-- Base Data Inspector class -->
|
||||
<script src="./DataInspector.js"></script>
|
||||
<!-- Floorplanner specific tweaks to Data Inspector class -->
|
||||
<script src="./floorplanner-datainspector-overrides.js"></script>
|
||||
|
||||
<!-- Go Cloud Storage Classes -->
|
||||
<script src="../../projects/storage/lib/gcs.js"></script>
|
||||
|
||||
<!-- CDN's for GoCloud Storage subclasses -->
|
||||
<script src="https://apis.google.com/js/api.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropbox.js/2.5.7/Dropbox-sdk.min.js"></script>
|
||||
<script src="https://js.live.net/v7.2/OneDrive.js"></script>
|
||||
<script type="text/javascript" src="https://www.dropbox.com/static/api/2/dropins.js" id="dropboxjs" data-app-key="3sm2ko6q7u1gbix"></script>
|
||||
|
||||
<!-- GoFloorPlanner bundle -->
|
||||
<script src="./lib/gfp.js"></script>
|
||||
|
||||
<!-- jQuery / UI JS -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/jquery-ui.min.js"></script>
|
||||
|
||||
<!-- CSS for GoCloudStorage/Manager -->
|
||||
<link rel="stylesheet" type="text/css" href="../../projects/storage/samples/GoCloudStorageUI.css" />
|
||||
|
||||
<!-- jQuery UI CSS -->
|
||||
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/themes/smoothness/jquery-ui.css" />
|
||||
|
||||
<!-- CSS for this app -->
|
||||
<link rel="stylesheet" type="text/css" href="./goeditor.css" />
|
||||
<link rel="stylesheet" type="text/css" href="./floorplanner.css" />
|
||||
|
||||
<script>
|
||||
|
||||
JQUERY = $;
|
||||
|
||||
function init() {
|
||||
|
||||
Floorplan = gfp.Floorplan;
|
||||
FloorplanPalette = gfp.FloorplanPalette;
|
||||
WallBuildingTool = gfp.WallBuildingTool;
|
||||
WallReshapingTool = gfp.WallReshapingTool;
|
||||
|
||||
// Do not remove this function call! This sets up your editor
|
||||
setupEditorApplication(1, 2, "../../projects/storage", Floorplan);
|
||||
|
||||
// replace generic palettes with FloorplanPalettes
|
||||
myFloorplan = diagrams[0];
|
||||
palettes[0].div = null;
|
||||
palettes[1].div = null;
|
||||
|
||||
furniturePalette = new FloorplanPalette("ge-palette-0", myFloorplan);
|
||||
furniturePalette.model = new go.GraphLinksModel(myFloorplan.makeDefaultFurniturePaletteNodeData());
|
||||
palettes[0] = furniturePalette;
|
||||
|
||||
wallPartsPalette = new FloorplanPalette("ge-palette-1", myFloorplan);
|
||||
wallPartsPalette.model = new go.GraphLinksModel(myFloorplan.makeDefaultWallpartsPaletteNodeData());
|
||||
palettes[1] = wallPartsPalette;
|
||||
|
||||
// set default model for all Cloud Storage subclasses
|
||||
for (i in storages) {
|
||||
var storage = storages[i];
|
||||
var dm = JSON.stringify({
|
||||
"class": "GraphLinksModel",
|
||||
"copiesKey": false,
|
||||
"modelData": { "units": "meters", "unitsAbbreviation": "m", "unitsConversionFactor": 0.02, "gridSize": 10, "wallThickness": 10, "preferences": { "showWallGuidelines": true, "showWallLengths": true, "showWallAngles": true, "showOnlySmallWallAngles": true, "showGrid": true, "gridSnap": true } },
|
||||
"nodeDataArray": [],
|
||||
"linkDataArray": []
|
||||
});
|
||||
storage.defaultModel = dm;
|
||||
}
|
||||
|
||||
// listen if the model of the Floorplan changes completely -- if so, there has been a load event, and we must update walls / rooms
|
||||
myFloorplan.addDiagramListener("InitialLayoutCompleted", function (e) {
|
||||
|
||||
// update units, grid size, units / px, showGrid, and preferences from the loading model's modelData
|
||||
var unitsForm = document.getElementById('unitsForm');
|
||||
var gridSizeInput = document.getElementById('gridSizeInput');
|
||||
var showGridCheckbox = document.getElementById('showGridCheckbox');
|
||||
var gridSnapCheckbox = document.getElementById('gridSnapCheckbox');
|
||||
var showWallGuidelinesCheckbox = document.getElementById('wallGuidelinesCheckbox');
|
||||
var showWallLengthsCheckbox = document.getElementById('wallLengthsCheckbox');
|
||||
var showWallAnglesCheckbox = document.getElementById('wallAnglesCheckbox');
|
||||
var showOnlySmallWallAnglesCheckbox = document.getElementById('onlySmallWallAnglesCheckbox');
|
||||
|
||||
var unitsConversionFactorInput = document.getElementById('unitsConversionFactorInput');
|
||||
|
||||
var fp = e.diagram;
|
||||
var md = fp.model.modelData;
|
||||
var units = md.units;
|
||||
// if (units === undefined) return;
|
||||
var unitsRadioChecked = document.getElementById(units);
|
||||
unitsRadioChecked.checked = true;
|
||||
var gridSize = md.gridSize;
|
||||
gridSize = fp.convertPixelsToUnits(gridSize);
|
||||
gridSizeInput.value = gridSize;
|
||||
fp.changeGridSize(gridSizeInput);
|
||||
var unitsConversionFactor = md.unitsConversionFactor;
|
||||
unitsConversionFactorInput.value = unitsConversionFactor;
|
||||
fp.changeUnitsConversionFactor(unitsConversionFactorInput, gridSizeInput);
|
||||
fp.changeUnits(unitsForm);
|
||||
|
||||
var showGrid = md.preferences.showGrid;
|
||||
var gridSnap = md.preferences.gridSnap;
|
||||
var showWallGuidelines = md.preferences.showWallGuidelines;
|
||||
var showWallLengths = md.preferences.showWallLengths;
|
||||
var showWallAngles = md.preferences.showWallAngles;
|
||||
var showOnlySmallWallAngles = md.preferences.showOnlySmallWallAngles;
|
||||
|
||||
showGridCheckbox.checked = showGrid;
|
||||
gridSnapCheckbox.checked = gridSnap;
|
||||
showWallGuidelinesCheckbox.checked = showWallGuidelines;
|
||||
showWallLengthsCheckbox.checked = showWallLengths;
|
||||
showWallAnglesCheckbox.checked = showWallAngles;
|
||||
showOnlySmallWallAnglesCheckbox = showOnlySmallWallAngles;
|
||||
|
||||
fp.checkboxChanged('showGridCheckbox');
|
||||
fp.checkboxChanged('gridSnapCheckbox');
|
||||
fp.checkboxChanged('wallGuidelinesCheckbox');
|
||||
fp.checkboxChanged('wallLengthsCheckbox');
|
||||
fp.checkboxChanged('wallAnglesCheckbox');
|
||||
fp.checkboxChanged('onlySmallWallAnglesCheckbox');
|
||||
|
||||
// update walls and rooms geometries
|
||||
fp.nodes.iterator.each(function (n) {
|
||||
if (n.category === "WallGroup") {
|
||||
fp.updateWall(n);
|
||||
}
|
||||
|
||||
if (n.category === "RoomNode") {
|
||||
fp.updateRoom(n);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// Update the tools buttons so the tool in use is highlighted
|
||||
updateButtons = function (func, el) {
|
||||
func.call(myFloorplan);
|
||||
var toolButtons = document.getElementsByClassName('toolButtons');
|
||||
for (var i = 0; i < toolButtons.length; i++) {
|
||||
var tb = toolButtons[i];
|
||||
if (tb === el) {
|
||||
tb.style.background = "#4b545f";
|
||||
tb.style.color = "white";
|
||||
}
|
||||
else {
|
||||
tb.style.background = "rgb(221, 221, 221)";
|
||||
tb.style.color = "black";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JQUERY(function () {
|
||||
JQUERY("#ge-palettes-container").accordion({
|
||||
heightStyle: "content",
|
||||
activate: function (event, ui) {
|
||||
for (var i = 0; i < palettes.length; i++) {
|
||||
var palette = palettes[i];
|
||||
palette.requestUpdate();
|
||||
}
|
||||
}
|
||||
});
|
||||
//JQUERY("#ge-overviews-container").accordion();
|
||||
var draggables = document.getElementsByClassName("ge-draggable");
|
||||
for (var i = 0; i < draggables.length; i++) {
|
||||
var draggable = draggables[i];
|
||||
var id = "#" + draggable.id; var hid = id + "-handle";
|
||||
// When a window is dragged, its height is set. this is bad. unset height / maybe width after dragging
|
||||
JQUERY(id).draggable({
|
||||
handle: hid, stack: ".ge-draggable", containment: "parent", scroll: false, stop: function (event) {
|
||||
this.style.height = "unset";
|
||||
var did = event.target.id;
|
||||
// only unset width for inspector and options menu, whose widths are dependent on contents
|
||||
if (did === 'ge-inspector-window' || did === 'optionsWindow') {
|
||||
this.style.width = "unset";
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}); // end jQuery
|
||||
|
||||
// add options window hotkey (other hotkeys are defined in goeditor-setup.js)
|
||||
document.body.addEventListener("keydown", function (e) {
|
||||
var keynum = e.which;
|
||||
if (e.ctrlKey) {
|
||||
e.preventDefault();
|
||||
switch (keynum) {
|
||||
case 66: geHideShowWindow('optionsWindow'); break; // ctrl + b
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// function to tweal inspector for app-specific stuff is in floorplanner-datainspector-overrides.js
|
||||
tweakInspectorForFloorplanner(inspector);
|
||||
|
||||
var defaultModelTextarea = document.getElementById('defaultModelTextarea');
|
||||
var defaultModelString = defaultModelTextarea.value;
|
||||
var defaultModelJson = JSON.parse(defaultModelString);
|
||||
myFloorplan.model = go.Model.fromJson(defaultModelJson);
|
||||
|
||||
} // end init
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="init();">
|
||||
<div>
|
||||
|
||||
<nav>
|
||||
|
||||
<span id="currentStorageSpan"></span>
|
||||
<ul id="ge-filemenus">
|
||||
<li>
|
||||
<a href="#">File</a>
|
||||
<ul>
|
||||
<li><a href="#" onclick="handlePromise('New')">New <p class="ge-shortcut">(Ctrl + D)</p></a></li>
|
||||
<li><a href="#" onclick="handlePromise('Load')">Open... <p class="ge-shortcut">(Ctrl + O)</p></a></li>
|
||||
<li><a href="#" onclick="handlePromise('Save')">Save <p class="ge-shortcut">(Ctrl + S)</p></a></li>
|
||||
<li><a href="#" onclick="handlePromise('SaveAs')">Save As...</a></li>
|
||||
<li><a href="#" onclick="handlePromise('Delete')">Remove... <p class="ge-shortcut">(Ctrl + R)</p></a></li>
|
||||
<li><a href="#" onclick="makeDiagramImage()">Export PNG</a></li>
|
||||
<li><a href="#" onclick="makeDiagramSvg()">Export SVG</a></li>
|
||||
<li><a href="#" onclick="updateCurrentStorageSpan()">Change Storage Service</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">View</a>
|
||||
<ul>
|
||||
<li id="ge-viewoption-palettes"><a href="#" onclick="geHideShowWindow('ge-palettes-window', true)" id="ge-palettes-windows-button">Palettes
|
||||
<p class="ge-shortcut"> (Ctrl + P)</p></a></li>
|
||||
<li id="ge-viewoption-overviews"><a href="#" onclick="geHideShowWindow('ge-overviews-window', true)" id="ge-overview-windows-button">Overview
|
||||
<p class="ge-shortcut"> (Ctrl + E)</p></a></li>
|
||||
<li id="ge-viewoption-inspector"><a href="#" onclick="geHideShowWindow('ge-inspector-window', true)" id="ge-inspector-windows-button">Inspector
|
||||
<p class="ge-shortcut"> (Ctrl + I)</p></a></li>
|
||||
<li id="ge-viewoption-options"><a href="#" onclick="geHideShowWindow('optionsWindow', true)" id="optionsWindow-button">Options<p
|
||||
class="ge-shortcut">(Ctrl + B)</p></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div id="toolButtonsDiv" style="float: left;">
|
||||
<button class="toolButtons" onclick="updateButtons(myFloorplan.enableWallBuilding, this)">Build Walls</button>
|
||||
<button class="toolButtons" onclick="updateButtons(myFloorplan.enableDividerBuilding, this)">Build Room
|
||||
Dividers</button>
|
||||
<button class="toolButtons" onclick="updateButtons(myFloorplan.disableWallBuilding, this)">Select</button>
|
||||
</div>
|
||||
|
||||
<p id="isAutoSavingP"><input type="checkbox" id="isAutoSavingCheckbox" unchecked /> <label for="isAutoSavingCheckbox">Autosave
|
||||
Enabled</label></p>
|
||||
|
||||
<p id="ge-header">GoFloorPlanner</p>
|
||||
<div id="ge-filename">(Unsaved file)</div>
|
||||
</nav>
|
||||
|
||||
<input type="file" id="file-input" style="display: none;" />
|
||||
|
||||
<div id="ge-diagrams-container" style="display: flex;">
|
||||
<div id="ge-diagram-0" style="height: 800px; width: 100%; background: #DAE4E4; border: 1px solid black; "></div>
|
||||
</div>
|
||||
|
||||
<div id="ge-palettes-window" style="visibility: visible" class="ge-draggable ui-draggable">
|
||||
<div id="ge-palettes-window-handle" class="ge-handle ui-draggable-handle">Palettes<button id="ge-palettes-window-close"
|
||||
class="ge-window-button ge-clickable" onclick="geHideShowWindow('ge-palettes-window')">X</button></div>
|
||||
<div id="ge-palettes-container">
|
||||
<h3>Furniture</h3>
|
||||
<div>
|
||||
<div id="ge-palette-0" style="height: 500px; background: lightgray; border: 1px solid black; "></div>
|
||||
</div>
|
||||
<h3>Wall Parts</h3>
|
||||
<div>
|
||||
<div id="ge-palette-1" style="height: 500px; background: lightgray; border: 1px solid black; "></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="ge-overviews-window" style="visibility: visible" class="ge-draggable ui-draggable">
|
||||
<div id="ge-overviews-window-handle" class="ge-handle ui-draggable-handle">Overview<button id="ge-overviews-window-close"
|
||||
class="ge-window-button ge-clickable" onclick="geHideShowWindow('ge-overviews-window')">X</button></div>
|
||||
<!--<div id="ge-overviews-container">
|
||||
<h3> Overview</h3><div> -->
|
||||
<div id="ge-overview-0" style="height: 200px; background: white; border: 1px solid black; "></div>
|
||||
</div>
|
||||
<!--</div> -->
|
||||
</div>
|
||||
|
||||
<div id="ge-inspector-window" style="visibility: visible" class="ge-draggable ui-draggable">
|
||||
<div id="ge-inspector-window-handle" class="ge-handle ui-draggable-handle">Properties<button id="ge-inspector-window-close"
|
||||
class="ge-window-button ge-clickable" onclick="geHideShowWindow('ge-inspector-window')">X</button></div>
|
||||
<div id="ge-inspector" class="inspector"></div>
|
||||
</div>
|
||||
|
||||
<div id="optionsWindow" style="visibility: hidden;" class="ge-draggable ui-draggable">
|
||||
<div id="optionsWindow-handle" class="ge-handle ui-draggable-handle">Options <button id="optionsWindowClose" class="windowButtons ge-window-button ge-clickable"
|
||||
onclick="geHideShowWindow('optionsWindow')">X</button></div>
|
||||
Units
|
||||
<div id="unitsRow" class="row data">
|
||||
<form id="unitsForm" onchange="myFloorplan.changeUnits(this)">
|
||||
<div class="col-4">
|
||||
<input type="radio" name="units" id="centimeters" />cm
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<input type="radio" name="units" id="meters" checked /> m
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<input type="radio" name="units" id="inches" />in
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<input type="radio" name="units" id="feet" />ft
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
Grid
|
||||
<div id="gridRow" class="row">
|
||||
<div class="col-2">
|
||||
<label for="gridSizeInput" style="float: left;">Grid size</label>
|
||||
<input id="gridSizeInput" placeholder="" class="unitsInput" onchange="myFloorplan.changeGridSize(this)" value="20" />
|
||||
<input id="gridSizeUnitsInput" class="unitsBox" value="cm" disabled />
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<input type="checkbox" id="showGridCheckbox" onchange="myFloorplan.checkboxChanged('showGridCheckbox')" checked />Show
|
||||
Grid
|
||||
</div>
|
||||
</div>
|
||||
<div id="gridRow" class="row">
|
||||
<div class="col-1">
|
||||
<label for="unitsConversionFactorInput" style="float: left;">Units/1px (at scale 100%)</label>
|
||||
<input id="unitsConversionFactorInput" placeholder="" onchange="myFloorplan.changeUnitsConversionFactor(this, document.getElementById('gridSizeInput'))"
|
||||
class="unitsInput" value=".02" />
|
||||
<input id="" class="unitsBox" value="cm" disabled />
|
||||
</div>
|
||||
</div>
|
||||
Preferences
|
||||
<div id="miscRow" class="row data">
|
||||
<div class="col-1">
|
||||
<input type="checkbox" id="gridSnapCheckbox" onchange="myFloorplan.checkboxChanged('gridSnapCheckbox')" checked />Grid
|
||||
Snap
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<input type="checkbox" id="wallGuidelinesCheckbox" onchange="myFloorplan.checkboxChanged('wallGuidelinesCheckbox')"
|
||||
checked /> Show Wall Guidelines
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<input type="checkbox" id="wallLengthsCheckbox" onchange="myFloorplan.checkboxChanged('wallLengthsCheckbox')"
|
||||
checked /> Show Wall Lengths
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<input type="checkbox" id="wallAnglesCheckbox" onchange="myFloorplan.checkboxChanged('wallAnglesCheckbox')"
|
||||
checked /> Show Wall Angles
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<input type="checkbox" id="onlySmallWallAnglesCheckbox" onchange="myFloorplan.checkboxChanged('onlySmallWallAnglesCheckbox')"
|
||||
checked /> Show Only Non-Reflex Wall Angles
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="ge-footer">
|
||||
<span>Built with the <a href="https://gojs.net">GoJS Diagramming Library</a>, by <a href="https://nwoods.com">
|
||||
Northwoods Software</a>.</span>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
This Floorplanner extension of GoJS makes use of multiple classes to allow for users to build, edit, save, and load
|
||||
feature-rich Floorplans.
|
||||
To start, build walls (press the 'Build Walls') button to activate the WallBuildingTool, or drag furniture from
|
||||
Palettes onto the Floorplan area.
|
||||
When you have an area enclosed by walls, you can create a room there by dragging the floor area node from the Wall
|
||||
Parts palette, or by right-clicking
|
||||
within your enclosed area and clicking 'Make Room'.
|
||||
</p>
|
||||
<p>
|
||||
You may also define areas with dividers, which allow one to specify different floor types without the need for wall
|
||||
boundaries. This is useful if you want to have multiple
|
||||
types of flooring within a single room, or want to define an area of floor that has no walls.
|
||||
</p>
|
||||
<p>
|
||||
This extension uses the following Floorplanner-specific files:
|
||||
<ul>
|
||||
<li><a href="./src/Floorplan.ts">Floorplan.ts</a> - A special kind of <a href="../../api/symbols/Diagram.html">Diagram</a>
|
||||
with listeners, properties, and methods that help with floorplanning </li>
|
||||
<li><a href="./src/FloorplanPalette.ts">FloorplanPalette.ts</a> - A special kind of <a href="../../api/symbols/Palette.html">Palette</a>
|
||||
linked with a specific instance of Floorplan </li>
|
||||
<li><a href="./src/WallBuildingTool.ts">WallBuildingTool.ts</a> - For constructing new walls / dividers. This
|
||||
works in conjunction with WallReshapingTool </li>
|
||||
<li><a href="./src/WallReshapingTool.ts">WallReshapingTool.ts</a> - For reshaping walls / dividers from their
|
||||
endpoints </li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
Additionally, this sample makes use of the <a href="../../intro/storage.html">GoCloudStorage</a> library, which
|
||||
allows users to save / load diagram files to / from LocalStorage, Google Drive, Microsoft OneDrive, and Dropbox.
|
||||
</p>
|
||||
<p>
|
||||
To modify this extension, one must modify the .ts source files (in this project's 'src' directory'), then run <code>npm run build</code>
|
||||
from the project's main directory. This will output a new
|
||||
<code>gfp.js</code> bundle that can be used.
|
||||
</p>
|
||||
|
||||
<textarea style='visibility: hidden;' id='defaultModelTextarea'>
|
||||
|
||||
{ "class": "GraphLinksModel",
|
||||
"copiesKey": false,
|
||||
"modelData": {"units":"meters", "unitsAbbreviation":"m", "unitsConversionFactor":0.02, "gridSize":10, "wallThickness":10, "preferences":{"showWallGuidelines":true, "showWallLengths":true, "showWallAngles":true, "showOnlySmallWallAngles":true, "showGrid":true, "gridSnap":true}},
|
||||
"nodeDataArray": [
|
||||
{"key":"wall6", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-910, "y":-320}, "endpoint":{"class":"go.Point", "x":-773, "y":-320}, "smpt1":{"class":"go.Point", "x":-905, "y":-315}, "smpt2":{"class":"go.Point", "x":-915, "y":-325}, "empt1":{"class":"go.Point", "x":-778, "y":-315}, "empt2":{"class":"go.Point", "x":-773, "y":-325}, "thickness":10, "isGroup":true, "notes":"", "isDivider":false},
|
||||
{"key":"wall5", "category":"WallGroup", "caption":"Wall", "type":"Wall", "startpoint":{"class":"go.Point", "x":-490, "y":-97.6667}, "endpoint":{"class":"go.Point", "x":-490, "y":-320}, "smpt1":{"class":"go.Point", "x":-485, "y":-97.6667}, "smpt2":{"class":"go.Point", "x":-495, "y":-102.6667}, "empt1":{"class":"go.Point", "x":-485, "y":-315}, "empt2":{"class":"go.Point", "x":-495, "y":-315}, "thickness":10, "color":"lightgray", "isGroup":true, "notes":"", "isDivider":false},
|
||||
{"key":"wall11", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-490, "y":-320}, "endpoint":{"class":"go.Point", "x":-120, "y":-320}, "smpt1":{"class":"go.Point", "x":-485, "y":-315}, "smpt2":{"class":"go.Point", "x":-490, "y":-325}, "empt1":{"class":"go.Point", "x":-125, "y":-315}, "empt2":{"class":"go.Point", "x":-124.99646446609407, "y":-325}, "thickness":10, "isGroup":true, "notes":"", "isDivider":false},
|
||||
{"key":"wall12", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-773, "y":-178.66666793823242}, "endpoint":{"class":"go.Point", "x":-631, "y":-178.66666793823242}, "smpt1":{"class":"go.Point", "x":-768, "y":-173.66666793823242}, "smpt2":{"class":"go.Point", "x":-768, "y":-183.66666793823242}, "empt1":{"class":"go.Point", "x":-636, "y":-173.66666793823242}, "empt2":{"class":"go.Point", "x":-636, "y":-183.66666793823242}, "thickness":10, "isGroup":true, "notes":"", "isDivider":false},
|
||||
{"key":"wall13", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-631, "y":-97.6667}, "endpoint":{"class":"go.Point", "x":-490, "y":-97.6667}, "smpt1":{"class":"go.Point", "x":-636, "y":-92.6667}, "smpt2":{"class":"go.Point", "x":-626, "y":-102.6667}, "empt1":{"class":"go.Point", "x":-490.0025, "y":-92.6667}, "empt2":{"class":"go.Point", "x":-495, "y":-102.6667}, "thickness":10, "isGroup":true, "notes":"", "isDivider":false},
|
||||
{"key":"wall2", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-773, "y":-320}, "endpoint":{"class":"go.Point", "x":-631, "y":-320}, "smpt1":{"class":"go.Point", "x":-768, "y":-315}, "smpt2":{"class":"go.Point", "x":-773, "y":-325}, "empt1":{"class":"go.Point", "x":-636, "y":-315}, "empt2":{"class":"go.Point", "x":-631, "y":-325}, "thickness":10, "isGroup":true, "notes":"", "isDivider":false},
|
||||
{"key":"wall14", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-631, "y":-320}, "endpoint":{"class":"go.Point", "x":-490, "y":-320}, "smpt1":{"class":"go.Point", "x":-626, "y":-315}, "smpt2":{"class":"go.Point", "x":-631, "y":-325}, "empt1":{"class":"go.Point", "x":-495, "y":-315}, "empt2":{"class":"go.Point", "x":-490, "y":-325}, "thickness":10, "isGroup":true, "notes":"", "isDivider":false},
|
||||
{"key":"wall10", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-631, "y":-320}, "endpoint":{"class":"go.Point", "x":-631, "y":-178.66666793823242}, "smpt1":{"class":"go.Point", "x":-636, "y":-315}, "smpt2":{"class":"go.Point", "x":-626, "y":-315}, "empt1":{"class":"go.Point", "x":-636, "y":-183.66666793823242}, "empt2":{"class":"go.Point", "x":-626, "y":-178.66666793823242}, "thickness":10, "isGroup":true, "notes":"", "isDivider":false},
|
||||
{"key":"wall15", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-631, "y":-178.66666793823242}, "endpoint":{"class":"go.Point", "x":-631, "y":-97.6667}, "smpt1":{"class":"go.Point", "x":-636, "y":-173.66666793823242}, "smpt2":{"class":"go.Point", "x":-626, "y":-178.66666793823242}, "empt1":{"class":"go.Point", "x":-636, "y":-92.6667}, "empt2":{"class":"go.Point", "x":-626, "y":-102.6667}, "thickness":10, "isGroup":true, "notes":"", "isDivider":false},
|
||||
{"key":"wall8", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-773, "y":-10}, "endpoint":{"class":"go.Point", "x":-773, "y":-178.66666793823242}, "smpt1":{"class":"go.Point", "x":-768, "y":-10}, "smpt2":{"class":"go.Point", "x":-778, "y":-10}, "empt1":{"class":"go.Point", "x":-768, "y":-173.66666793823242}, "empt2":{"class":"go.Point", "x":-778, "y":-178.66666793823242}, "thickness":10, "isGroup":true, "notes":""},
|
||||
{"key":"wall9", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-773, "y":-178.66666793823242}, "endpoint":{"class":"go.Point", "x":-773, "y":-320}, "smpt1":{"class":"go.Point", "x":-768, "y":-183.66666793823242}, "smpt2":{"class":"go.Point", "x":-778, "y":-178.66666793823242}, "empt1":{"class":"go.Point", "x":-768, "y":-315}, "empt2":{"class":"go.Point", "x":-778, "y":-315}, "thickness":10, "isGroup":true, "notes":""},
|
||||
{"key":"wall16", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-120, "y":200}, "endpoint":{"class":"go.Point", "x":-670.32, "y":200}, "smpt1":{"class":"go.Point", "x":-125, "y":195}, "smpt2":{"class":"go.Point", "x":-124.99646446609407, "y":205}, "empt1":{"class":"go.Point", "x":-665.32, "y":195}, "empt2":{"class":"go.Point", "x":-670.32, "y":205}, "thickness":10, "isGroup":true, "notes":"", "isDivider":false},
|
||||
{"key":"wall18", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-120, "y":-320}, "endpoint":{"class":"go.Point", "x":-120, "y":10}, "smpt1":{"class":"go.Point", "x":-125, "y":-315}, "smpt2":{"class":"go.Point", "x":-115, "y":-314.99646446609404}, "empt1":{"class":"go.Point", "x":-125, "y":0}, "empt2":{"class":"go.Point", "x":-115, "y":10}, "thickness":10, "isGroup":true, "notes":"", "isDivider":false},
|
||||
{"key":"wall19", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-120, "y":10}, "endpoint":{"class":"go.Point", "x":-120, "y":200}, "smpt1":{"class":"go.Point", "x":-125, "y":20}, "smpt2":{"class":"go.Point", "x":-115, "y":10}, "empt1":{"class":"go.Point", "x":-125, "y":195}, "empt2":{"class":"go.Point", "x":-115, "y":194.99646446609407}, "thickness":10, "isGroup":true, "notes":"", "isDivider":false},
|
||||
{"key":"wall4", "category":"WallGroup", "caption":"Divider", "type":"Divider", "startpoint":{"class":"go.Point", "x":-120, "y":-320}, "endpoint":{"class":"go.Point", "x":100, "y":-100}, "smpt1":{"class":"go.Point", "x":-115, "y":-314.99646446609404}, "smpt2":{"class":"go.Point", "x":-124.99646446609407, "y":-325}, "empt1":{"class":"go.Point", "x":99.9975, "y":-99.99896446609407}, "empt2":{"class":"go.Point", "x":100.0025, "y":-100.00103553390593}, "thickness":0.005, "color":"lightgray", "isGroup":true, "notes":"", "isDivider":true},
|
||||
{"key":"wall25", "category":"WallGroup", "caption":"Divider", "type":"Divider", "startpoint":{"class":"go.Point", "x":-120, "y":200}, "endpoint":{"class":"go.Point", "x":100, "y":-20}, "smpt1":{"class":"go.Point", "x":-124.99646446609407, "y":205}, "smpt2":{"class":"go.Point", "x":-115, "y":194.99646446609407}, "empt1":{"class":"go.Point", "x":100.0025, "y":-19.99896446609407}, "empt2":{"class":"go.Point", "x":99.9975, "y":-20.00103553390593}, "thickness":0.005, "color":"lightgray", "isGroup":true, "notes":"", "isDivider":true},
|
||||
{"key":"wall22", "category":"WallGroup", "caption":"Divider", "type":"Divider", "startpoint":{"class":"go.Point", "x":-490, "y":-97.6667}, "endpoint":{"class":"go.Point", "x":-490, "y":10}, "smpt1":{"class":"go.Point", "x":-490.0025, "y":-92.6667}, "smpt2":{"class":"go.Point", "x":-489.9975, "y":-97.6667}, "empt1":{"class":"go.Point", "x":-490.0025, "y":0}, "empt2":{"class":"go.Point", "x":-489.9975, "y":0}, "thickness":0.005, "color":"lightgray", "isGroup":true, "notes":"", "isDivider":true},
|
||||
{"key":"wall23", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"#d3d3d3", "startpoint":{"class":"go.Point", "x":-670.32, "y":10}, "endpoint":{"class":"go.Point", "x":-490, "y":10}, "smpt1":{"class":"go.Point", "x":-665.32, "y":20}, "smpt2":{"class":"go.Point", "x":-675.32, "y":0}, "empt1":{"class":"go.Point", "x":-490, "y":20}, "empt2":{"class":"go.Point", "x":-490.0025, "y":0}, "thickness":20, "isGroup":true, "notes":""},
|
||||
{"key":"wall26", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"#d3d3d3", "startpoint":{"class":"go.Point", "x":-490, "y":10}, "endpoint":{"class":"go.Point", "x":-120, "y":10}, "smpt1":{"class":"go.Point", "x":-490, "y":20}, "smpt2":{"class":"go.Point", "x":-489.9975, "y":0}, "empt1":{"class":"go.Point", "x":-125, "y":20}, "empt2":{"class":"go.Point", "x":-125, "y":0}, "thickness":20, "isGroup":true, "notes":""},
|
||||
{"key":"Room", "category":"RoomNode", "name":"Patio", "boundaryWalls":[ [ "wall4",1 ],[ "wall18",2 ],[ "wall19",2 ],[ "wall25",2 ],[ "wall29",1 ] ], "holes":[], "floorImage":"./images/textures/floor6.jpg", "showLabel":true, "showFlooringOptions":true, "loc":{"class":"go.Point", "x":-115, "y":-314.99646446609404}, "area":63423.27973184812, "labelAlignment":{"class":"go.Spot", "x":0.5, "y":0.5, "offsetX":-5.103470996432179, "offsetY":-64.0326718168821}},
|
||||
{"key":"Room2", "category":"RoomNode", "name":"Living Room", "boundaryWalls":[ [ "wall23",1 ],[ "wall21",1 ],[ "wall20",1 ],[ "wall16",1 ],[ "wall19",1 ],[ "wall26",1 ] ], "holes":[], "floorImage":"./images/textures/floor7.jpg", "showLabel":true, "showFlooringOptions":true, "loc":{"class":"go.Point", "x":-665.32, "y":20}, "area":94556, "labelAlignment":{"class":"go.Spot", "x":0.5, "y":0.5, "offsetX":-181.9269405923115, "offsetY":49.07812025216799}},
|
||||
{"key":"Room3", "category":"RoomNode", "name":"Hallway", "boundaryWalls":[ [ "wall12",1 ],[ "wall8",1 ],[ "wall8",2 ],[ "wall9",2 ],[ "wall6",1 ],[ "wall7",2 ],[ "wall17",2 ],[ "wall21",2 ],[ "wall23",2 ],[ "wall22",1 ],[ "wall13",1 ],[ "wall15",1 ] ], "holes":[], "floorImage":"images/textures/floor1.jpg", "showLabel":true, "showFlooringOptions":true, "loc":{"class":"go.Point", "x":-905, "y":-315}, "area":91348.35030109668, "labelAlignment":{"class":"go.Spot", "x":0.5, "y":0.5, "offsetX":52.650999571264606, "offsetY":67.99831835696534}},
|
||||
{"key":"Room4", "category":"RoomNode", "name":"Kitchen / Dining Room", "boundaryWalls":[ [ "wall11",1 ],[ "wall5",1 ],[ "wall22",2 ],[ "wall26",2 ],[ "wall18",1 ] ], "holes":[], "floorImage":"./images/textures/floor4.jpg", "showLabel":true, "showFlooringOptions":true, "loc":{"class":"go.Point", "x":-489.9975, "y":-315}, "area":113888.08933324998, "labelAlignment":{"class":"go.Spot", "x":0.5, "y":0.5, "offsetX":-80.49751952755344, "offsetY":29.97379349825087}},
|
||||
{"key":"Room5", "category":"RoomNode", "name":"Bathroom", "boundaryWalls":[ [ "wall14",1 ],[ "wall10",2 ],[ "wall15",2 ],[ "wall13",2 ],[ "wall5",2 ] ], "holes":[], "floorImage":"./images/textures/floor5.jpg", "showLabel":true, "showFlooringOptions":true, "loc":{"class":"go.Point", "x":-626, "y":-315}, "area":27815.6623},
|
||||
{"key":"Room6", "category":"RoomNode", "name":"Laundry Room", "boundaryWalls":[ [ "wall2",1 ],[ "wall9",1 ],[ "wall12",2 ],[ "wall10",1 ] ], "holes":[], "floorImage":"./images/textures/floor5.jpg", "showLabel":true, "showFlooringOptions":true, "loc":{"class":"go.Point", "x":-768, "y":-315}, "area":17335.99983215332, "labelAlignment":{"class":"go.Spot", "x":0.5, "y":0.5, "offsetX":19.00442716769237, "offsetY":27.642803153007236}},
|
||||
{"key":"door", "category":"DoorNode", "caption":"Door", "type":"Door", "length":40, "doorOpeningHeight":10, "swing":"left", "notes":"", "loc":"-876.8531037797546 -320", "group":"wall6", "angle":180},
|
||||
{"key":"door2", "category":"DoorNode", "caption":"Door", "type":"Door", "length":40, "doorOpeningHeight":10, "swing":"left", "notes":"", "loc":"-697.8658953341261 -178.66666793823242", "group":"wall12"},
|
||||
{"key":"door3", "category":"DoorNode", "caption":"Door", "type":"Door", "length":40, "doorOpeningHeight":10, "swing":"right", "notes":"", "loc":"-631 -248.59768600237845", "group":"wall10", "angle":270},
|
||||
{"key":"door4", "category":"DoorNode", "caption":"Door", "type":"Door", "length":40, "doorOpeningHeight":10, "swing":"left", "notes":"", "loc":"-557.5153168347209 -97.6667", "group":"wall13"},
|
||||
{"key":"door5", "category":"DoorNode", "caption":"Door", "type":"Door", "length":40, "doorOpeningHeight":10, "swing":"left", "notes":"", "loc":"-120 -50.50422651153826", "group":"wall18", "angle":90},
|
||||
{"key":"door6", "category":"DoorNode", "caption":"Door", "type":"Door", "length":50, "doorOpeningHeight":20, "swing":"right", "notes":"", "loc":"-236.61674968371233 10", "group":"wall26", "angle":180, "color":"#000000"},
|
||||
{"category":"WindowNode", "key":"window", "color":"white", "caption":"Window", "type":"Window", "shape":"Rectangle", "height":10, "length":60, "notes":"", "loc":"-705 -320", "group":"wall2"},
|
||||
{"category":"WindowNode", "key":"window2", "color":"white", "caption":"Window", "type":"Window", "shape":"Rectangle", "height":10, "length":60, "notes":"", "loc":"-559 -320", "group":"wall14"},
|
||||
{"key":"door7", "category":"DoorNode", "caption":"Door", "type":"Door", "length":50, "doorOpeningHeight":20, "swing":"left", "notes":"", "loc":"-596 10", "group":"wall23", "angle":180, "color":"#000000"},
|
||||
{"key":"wall3", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-670.32, "y":200}, "endpoint":{"class":"go.Point", "x":-910, "y":200}, "smpt1":{"class":"go.Point", "x":-675.32, "y":195}, "smpt2":{"class":"go.Point", "x":-670.32, "y":205}, "empt1":{"class":"go.Point", "x":-905, "y":195}, "empt2":{"class":"go.Point", "x":-915, "y":205}, "thickness":10, "isGroup":true, "notes":""},
|
||||
{"key":"wall17", "category":"WallGroup", "caption":"Wall", "type":"Wall", "startpoint":{"class":"go.Point", "x":-910, "y":69.39500000000001}, "endpoint":{"class":"go.Point", "x":-670.32, "y":69.39500000000001}, "smpt1":{"class":"go.Point", "x":-905, "y":74.39500000000001}, "smpt2":{"class":"go.Point", "x":-905, "y":64.39500000000001}, "empt1":{"class":"go.Point", "x":-675.32, "y":74.39500000000001}, "empt2":{"class":"go.Point", "x":-675.32, "y":64.39500000000001}, "thickness":10, "color":"lightgray", "isGroup":true, "notes":"", "isDivider":false},
|
||||
{"key":"wall20", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-670.32, "y":200}, "endpoint":{"class":"go.Point", "x":-670.32, "y":69.39500000000001}, "smpt1":{"class":"go.Point", "x":-665.32, "y":195}, "smpt2":{"class":"go.Point", "x":-675.32, "y":195}, "empt1":{"class":"go.Point", "x":-665.32, "y":69.39500000000001}, "empt2":{"class":"go.Point", "x":-675.32, "y":74.39500000000001}, "thickness":10, "isGroup":true, "notes":"", "isDivider":false},
|
||||
{"key":"wall21", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-670.32, "y":69.39500000000001}, "endpoint":{"class":"go.Point", "x":-670.32, "y":10}, "smpt1":{"class":"go.Point", "x":-665.32, "y":69.39500000000001}, "smpt2":{"class":"go.Point", "x":-675.32, "y":64.39500000000001}, "empt1":{"class":"go.Point", "x":-665.32, "y":20}, "empt2":{"class":"go.Point", "x":-675.32, "y":0}, "thickness":10, "isGroup":true, "notes":"", "isDivider":false},
|
||||
{"key":"wall7", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-910, "y":-320}, "endpoint":{"class":"go.Point", "x":-910, "y":69.39500000000001}, "smpt1":{"class":"go.Point", "x":-915, "y":-325}, "smpt2":{"class":"go.Point", "x":-905, "y":-315}, "empt1":{"class":"go.Point", "x":-915, "y":69.39500000000001}, "empt2":{"class":"go.Point", "x":-905, "y":64.39500000000001}, "thickness":10, "isGroup":true, "notes":"", "isDivider":false},
|
||||
{"key":"wall27", "category":"WallGroup", "caption":"Wall", "type":"Wall", "color":"lightgray", "startpoint":{"class":"go.Point", "x":-910, "y":69.39500000000001}, "endpoint":{"class":"go.Point", "x":-910, "y":200}, "smpt1":{"class":"go.Point", "x":-915, "y":69.39500000000001}, "smpt2":{"class":"go.Point", "x":-905, "y":74.39500000000001}, "empt1":{"class":"go.Point", "x":-915, "y":205}, "empt2":{"class":"go.Point", "x":-905, "y":195}, "thickness":10, "isGroup":true, "notes":"", "isDivider":false},
|
||||
{"key":"Room7", "category":"RoomNode", "name":"Spare Bedroom", "boundaryWalls":[ [ "wall17",1 ],[ "wall27",2 ],[ "wall3",1 ],[ "wall20",2 ] ], "holes":[], "floorImage":"./images/textures/floor2.jpg", "showLabel":true, "showFlooringOptions":true, "loc":{"class":"go.Point", "x":-905, "y":74.39500000000001}, "area":27700.556399999972, "labelAlignment":{"class":"go.Spot", "x":0.5, "y":0.5, "offsetX":-31.098153547132597, "offsetY":29.370478350070243}},
|
||||
{"key":"sofaMedium", "color":"#ffffff", "stroke":"#000000", "caption":"Sofa", "type":"Sofa", "geo":"F1 M0 0 L80 0 80 40 0 40 0 0 M10 35 L10 10 M0 0 Q8 0 10 10 M0 40 Q40 15 80 40 M70 10 Q72 0 80 0 M70 10 L70 35", "height":45, "width":90, "notes":"", "texture":"./images/textures/fabric3.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "fabric1.jpg","fabric2.jpg","fabric3.jpg" ], "loc":"-470 58", "angle":180, "group":-47},
|
||||
{"key":"sofaMedium2", "color":"#ffffff", "stroke":"#000000", "caption":"Sofa", "type":"Sofa", "geo":"F1 M0 0 L80 0 80 40 0 40 0 0 M10 35 L10 10 M0 0 Q8 0 10 10 M0 40 Q40 15 80 40 M70 10 Q72 0 80 0 M70 10 L70 35", "height":45, "width":90, "notes":"", "texture":"./images/textures/fabric3.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "fabric1.jpg","fabric2.jpg","fabric3.jpg" ], "loc":"-360 60", "angle":180, "group":-47},
|
||||
{"key":"armChair", "color":"purple", "stroke":"#000000", "caption":"Arm Chair", "type":"Arm Chair", "geo":"F1 M0 0 L40 0 40 40 0 40 0 0 M10 30 L10 10 M0 0 Q8 0 10 10 M0 40 Q20 15 40 40 M30 10 Q32 0 40 0 M30 10 L30 30", "width":45, "height":45, "notes":"", "texture":"fabric1.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "fabric1.jpg","fabric2.jpg","fabric3.jpg" ], "loc":"-600 110", "angle":90},
|
||||
{"key":"armChair2", "color":"purple", "stroke":"#000000", "caption":"Arm Chair", "type":"Arm Chair", "geo":"F1 M0 0 L40 0 40 40 0 40 0 0 M10 30 L10 10 M0 0 Q8 0 10 10 M0 40 Q20 15 40 40 M30 10 Q32 0 40 0 M30 10 L30 30", "width":45, "height":45, "notes":"", "texture":"fabric1.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "fabric1.jpg","fabric2.jpg","fabric3.jpg" ], "loc":"-220 110", "angle":270},
|
||||
{"isGroup":true, "key":-47, "caption":"Group", "notes":""},
|
||||
{"category":"MultiPurposeNode", "showLabel": true, "key":"MultiPurposeNode", "caption":"Multi Purpose Node", "color":"#000000", "stroke":"#000000", "name":"Writable Node", "type":"Writable Node", "shape":"Rectangle", "text":"TV", "width":175, "height":30, "notes":"", "texture":"granite1.jpg", "usesTexture":false, "showTextureOptions":true, "textures":[ "wood1.jpg","wood2.jpg","granite1.jpg","porcelain1.jpg","steel1.jpg" ], "loc":"-400 171.5"},
|
||||
{"category":"MultiPurposeNode", "showLabel": true, "key":"MultiPurposeNode2", "caption":"Multi Purpose Node", "color":"#ffffff", "stroke":"#000000", "name":"Writable Node", "type":"Writable Node", "shape":"Rectangle", "text":"Coffee Table", "width":194, "height":36, "notes":"", "texture":"./images/textures/wood2.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "wood1.jpg","wood2.jpg","granite1.jpg","porcelain1.jpg","steel1.jpg" ], "loc":"-410 110"},
|
||||
{"key":"diningTable", "color":"#ffffff", "stroke":"#000000", "caption":"Dining Table", "type":"Dining Table", "geo":"F1 M 0 0 L 0 100 200 100 200 0 0 0 M 25 0 L 25 -10 75 -10 75 0 M 125 0 L 125 -10 175 -10 175 0 M 200 25 L 210 25 210 75 200 75 M 125 100 L 125 110 L 175 110 L 175 100 M 25 100 L 25 110 75 110 75 100 M 0 75 -10 75 -10 25 0 25", "width":150, "height":75, "notes":"", "texture":"./images/textures/floor3.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "wood1.jpg","wood2.jpg","floor3.jpg","granite1.jpg","porcelain1.jpg","steel2.jpg" ], "loc":"-270 -70"},
|
||||
{"category":"MultiPurposeNode", "showLabel": true, "key":"MultiPurposeNode3", "caption":"Multi Purpose Node", "color":"#ffffff", "stroke":"#000000", "name":"Writable Node", "type":"Writable Node", "shape":"Rectangle", "text":"Island", "width":150, "height":50, "notes":"", "texture":"granite1.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "wood1.jpg","wood2.jpg","granite1.jpg","porcelain1.jpg","steel1.jpg" ], "loc":"-310 -180"},
|
||||
{"key":"stove", "color":"#ffffff", "stroke":"#000000", "caption":"Stove", "type":"Stove", "geo":"F1 M 0 0 L 0 100 100 100 100 0 0 0M 30 15 A 15 15 180 1 0 30.01 15M 30 20 A 10 10 180 1 0 30.01 20M 30 25 A 5 5 180 1 0 30.01 25M 70 15 A 15 15 180 1 0 70.01 15M 70 20 A 10 10 180 1 0 70.01 20M 70 25 A 5 5 180 1 0 70.01 25M 30 55 A 15 15 180 1 0 30.01 55M 30 60 A 10 10 180 1 0 30.01 60M 30 65 A 5 5 180 1 0 30.01 65M 70 55 A 15 15 180 1 0 70.01 55M 70 60 A 10 10 180 1 0 70.01 60M 70 65 A 5 5 180 1 0 70.01 65", "width":50, "height":50, "notes":"", "texture":"plaster1.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "steel1.jpg","porcelain1.jpg","copper1.jpg","plaster1.jpg" ], "loc":"-390 -280"},
|
||||
{"key":"toilet", "color":"#ffffff", "stroke":"#000000", "caption":"Toilet", "type":"Toilet", "geo":"F1 M0 0 L25 0 25 10 0 10 0 0 M20 10 L20 15 5 15 5 10 20 10 M5 15 Q0 15 0 25 Q0 40 12.5 40 Q25 40 25 25 Q25 15 20 15", "width":25, "height":35, "notes":"", "texture":"porcelain1.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "copper1.jpg","steel1.jpg","porcelain1.jpg" ], "loc":"-590 -270"},
|
||||
{"key":"shower", "color":"#ffffff", "stroke":"#000000", "caption":"Shower/Tub", "type":"Shower/Tub", "geo":"F1 M0 0 L40 0 40 60 0 60 0 0 M35 15 L35 55 5 55 5 15 Q5 5 20 5 Q35 5 35 15 M22.5 20 A2.5 2.5 180 1 1 22.5 19.99", "width":45, "height":75, "notes":"", "texture":"copper1.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "copper1.jpg","steel1.jpg","porcelain1.jpg" ], "loc":"-520 -260"},
|
||||
{"key":"doubleSink", "color":"#ffffff", "stroke":"#000000", "caption":"Double Sink", "type":"Double Sink", "geo":"F1 M0 0 L75 0 75 40 0 40 0 0 M5 7.5 L35 7.5 35 35 5 35 5 7.5 M44 7.5 L70 7.5 70 35 40 35 40 9M15 21.25 A5 5 180 1 0 15 21.24 M50 21.25 A 5 5 180 1 0 50 21.24 M40.5 3.75 A3 3 180 1 1 40.5 3.74M40.5 3.75 L50.5 13.75 47.5 16.5 37.5 6.75 M32.5 3.75 A 1 1 180 1 1 32.5 3.74 M 27.5 4.25 L 27.5 3.25 30.5 3.25M 30.5 4.25 L 27.5 4.25 M44.5 3.75 A 1 1 180 1 1 44.5 3.74 M 44.35 3.25 L 47.5 3.25 47.5 4.25 M 44.35 4.25 L 47.5 4.25", "height":27, "width":52, "notes":"", "texture":"steel2.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "copper1.jpg","steel1.jpg","steel2.jpg","porcelain1.jpg" ], "loc":"-520 -180", "angle":90},
|
||||
{"key":"sink", "color":"#ffffff", "stroke":"#000000", "caption":"Sink", "type":"Sink", "geo":"F1 M0 0 L40 0 40 40 0 40 0 0z M5 7.5 L18.5 7.5 M 21.5 7.5 L35 7.5 35 35 5 35 5 7.5 M 15 21.25 A 5 5 180 1 0 15 21.24M23 3.75 A 3 3 180 1 1 23 3.74 M21.5 6.25 L 21.5 12.5 18.5 12.5 18.5 6.25 M15 3.75 A 1 1 180 1 1 15 3.74M 10 4.25 L 10 3.25 13 3.25 M 13 4.25 L 10 4.25 M27 3.75 A 1 1 180 1 1 27 3.74 M 26.85 3.25 L 30 3.25 30 4.25 M 26.85 4.25 L 30 4.25", "width":27, "height":27, "notes":"", "texture":"steel1.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "copper1.jpg","steel1.jpg","steel2.jpg","porcelain1.jpg" ], "loc":"-750 -240", "angle":270},
|
||||
{"category":"MultiPurposeNode", "showLabel": true, "key":"MultiPurposeNode4", "caption":"Multi Purpose Node", "color":"#ffffff", "stroke":"#000000", "name":"Writable Node", "type":"Writable Node", "shape":"Rectangle", "text":"Washer", "width":50, "height":50, "notes":"", "texture":"./images/textures/porcelain1.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "wood1.jpg","wood2.jpg","granite1.jpg","porcelain1.jpg","steel1.jpg" ], "loc":"-740 -290"},
|
||||
{"category":"MultiPurposeNode", "showLabel": true, "key":"MultiPurposeNode42", "caption":"Multi Purpose Node", "color":"#ffffff", "stroke":"#000000", "name":"Writable Node", "type":"Writable Node", "shape":"Rectangle", "text":"Dryer", "width":50, "height":50, "notes":"", "texture":"./images/textures/porcelain1.jpg", "usesTexture":true, "showTextureOptions":false, "textures":[ "wood1.jpg","wood2.jpg","granite1.jpg","porcelain1.jpg","steel1.jpg" ], "loc":"-680 -290"},
|
||||
{"key":"staircase", "color":"#ffffff", "stroke":"#000000", "caption":"Staircase", "type":"Staircase", "geo":"F1 M0 0 L 0 100 250 100 250 0 0 0 M25 100 L 25 0 M 50 100 L 50 0 M 75 100 L 75 0M 100 100 L 100 0 M 125 100 L 125 0 M 150 100 L 150 0 M 175 100 L 175 0 M 200 100 L 200 0 M 225 100 L 225 0", "width":125, "height":50, "notes":"", "texture":"./images/textures/wood1.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "wood1.jpg","floor1.jpg","wood2.jpg","steel2.jpg","floor2.jpg" ], "loc":"-810 -240", "angle":270},
|
||||
{"key":"roundTable", "color":"#ffffff", "stroke":"#000000", "caption":"Round Table", "type":"Round Table", "shape":"Ellipse", "width":50, "height":50, "notes":"", "texture":"wood1.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "wood1.jpg","wood2.jpg","floor3.jpg","granite1.jpg","porcelain1.jpg" ], "loc":"-710 30"},
|
||||
{"key":"door8", "category":"DoorNode", "caption":"Door", "type":"Door", "length":40, "doorOpeningHeight":10, "swing":"left", "notes":"", "loc":"-818.1830255911889 69.39500000000001", "group":"wall17", "angle":180},
|
||||
{"key":"door9", "category":"DoorNode", "caption":"Door", "type":"Door", "length":40, "doorOpeningHeight":10, "swing":"left", "notes":"", "loc":"-120 146.01328150307734", "group":"wall19", "angle":90},
|
||||
{"category":"WindowNode", "key":"window3", "color":"white", "caption":"Window", "type":"Window", "shape":"Rectangle", "height":10, "length":60, "notes":"", "loc":"-120 79.59151279559444", "group":"wall19", "angle":90},
|
||||
{"category":"WindowNode", "key":"window4", "color":"white", "caption":"Window", "type":"Window", "shape":"Rectangle", "height":10, "length":60, "notes":"", "loc":"-178 -320", "group":"wall11"},
|
||||
{"category":"WindowNode", "key":"window5", "color":"white", "caption":"Window", "type":"Window", "shape":"Rectangle", "height":10, "length":60, "notes":"", "loc":"-358 -320", "group":"wall11"},
|
||||
{"category":"MultiPurposeNode", "showLabel": true, "key":"MultiPurposeNode5", "caption":"Multi Purpose Node", "color":"#ffffff", "stroke":"#000000", "name":"Writable Node", "type":"Writable Node", "shape":"Rectangle", "text":"Fridge", "width":50, "height":50, "notes":"", "texture":"./images/textures/steel1.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "wood1.jpg","wood2.jpg","granite1.jpg","porcelain1.jpg","steel1.jpg" ], "loc":"-450 -280"},
|
||||
{"category":"MultiPurposeNode", "showLabel": true, "key":"MultiPurposeNode52", "caption":"Multi Purpose Node", "color":"#ffffff", "stroke":"#000000", "name":"Writable Node", "type":"Writable Node", "shape":"Rectangle", "text":"Counter", "width":219, "height":50, "notes":"", "texture":"./images/textures/wood2.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "wood1.jpg","wood2.jpg","granite1.jpg","porcelain1.jpg","steel1.jpg" ], "loc":"-245.5 -280"},
|
||||
{"key":"bed", "color":"#ffffff", "stroke":"#000000", "caption":"Bed", "type":"Bed", "geo":"F1 M0 0 L40 0 40 60 0 60 0 0 M 7.5 2.5 L32.5 2.5 32.5 17.5 7.5 17.5 7.5 2.5 M0 20 L40 20 M0 25 L40 25", "width":76.2, "height":101.6, "notes":"", "texture":"./images/textures/fabric2.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "fabric1.jpg","fabric2.jpg","fabric3.jpg" ], "loc":"-720 130"},
|
||||
{"category":"MultiPurposeNode", "key":"MultiPurposeNode6", "caption":"Multi Purpose Node", "color":"#ffffff", "stroke":"#000000", "name":"Writable Node", "type":"Writable Node", "shape":"Rectangle", "text":"Dresser", "width":60, "height":60, "notes":"", "texture":"./images/textures/wood2.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "wood1.jpg","wood2.jpg","granite1.jpg","porcelain1.jpg","steel1.jpg" ], "loc":"-870 110"},
|
||||
{"category":"WindowNode", "key":"window6", "color":"white", "caption":"Window", "type":"Window", "shape":"Rectangle", "height":10, "length":60, "notes":"", "loc":"-910 141.13616240146848", "group":"wall27", "angle":90},
|
||||
{"category":"WindowNode", "key":"window7", "color":"white", "caption":"Window", "type":"Window", "shape":"Rectangle", "height":10, "length":60, "notes":"", "loc":"-815.2749163157326 -320", "group":"wall6"},
|
||||
{"category":"WindowNode", "key":"window8", "color":"white", "caption":"Window", "type":"Window", "shape":"Rectangle", "height":10, "length":60, "notes":"", "loc":"-910 -226", "group":"wall7", "angle":90},
|
||||
{"category":"WindowNode", "key":"window9", "color":"white", "caption":"Window", "type":"Window", "shape":"Rectangle", "height":10, "length":60, "notes":"", "loc":"-910 -72", "group":"wall7", "angle":90},
|
||||
{"key":"door10", "category":"DoorNode", "caption":"Door", "type":"Door", "length":40, "doorOpeningHeight":10, "swing":"right", "notes":"", "loc":"-120 -90.50422651153826", "group":"wall18", "angle":90},
|
||||
{"category":"WindowNode", "key":"window10", "color":"white", "caption":"Window", "type":"Window", "shape":"Rectangle", "height":10, "length":60, "notes":"", "loc":"-120 -239", "group":"wall18", "angle":90},
|
||||
{"category":"MultiPurposeNode", "showLabel": true, "key":"MultiPurposeNode7", "caption":"Multi Purpose Node", "color":"#ffffff", "stroke":"#000000", "name":"Writable Node", "type":"Writable Node", "shape":"Rectangle", "text":"Bookshelf", "width":36, "height":125, "notes":"", "texture":"./images/textures/wood1.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "wood1.jpg","wood2.jpg","granite1.jpg","porcelain1.jpg","steel1.jpg" ], "loc":"-880 -30"},
|
||||
{"key":"roundTable2", "color":"#ffffff", "stroke":"#000000", "caption":"Round Table", "type":"Round Table", "shape":"Ellipse", "width":61, "height":61, "notes":"", "texture":"./images/textures/wood1.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "wood1.jpg","wood2.jpg","floor3.jpg","granite1.jpg","porcelain1.jpg" ], "loc":"-80 -230"},
|
||||
{"key":"roundTable22", "color":"#ffffff", "stroke":"#000000", "caption":"Round Table", "type":"Round Table", "shape":"Ellipse", "width":61, "height":61, "notes":"", "texture":"./images/textures/wood1.jpg", "usesTexture":true, "showTextureOptions":true, "textures":[ "wood1.jpg","wood2.jpg","floor3.jpg","granite1.jpg","porcelain1.jpg" ], "loc":"-70 50"},
|
||||
{"category":"WindowNode", "key":"window11", "color":"white", "caption":"Window", "type":"Window", "shape":"Rectangle", "height":10, "length":60, "notes":"", "loc":"-551 200", "group":"wall16", "angle":180},
|
||||
{"category":"WindowNode", "key":"window112", "color":"white", "caption":"Window", "type":"Window", "shape":"Rectangle", "height":10, "length":60, "notes":"", "loc":"-267.661267681676 200", "group":"wall16", "angle":180},
|
||||
{"key":"wall29", "category":"WallGroup", "caption":"Divider", "type":"Divider", "color":"lightgray", "startpoint":{"class":"go.Point", "x":100, "y":-100}, "endpoint":{"class":"go.Point", "x":100, "y":-20}, "smpt1":{"class":"go.Point", "x":99.9975, "y":-99.99896446609407}, "smpt2":{"class":"go.Point", "x":100.0025, "y":-100.00103553390593}, "empt1":{"class":"go.Point", "x":99.9975, "y":-20.00103553390593}, "empt2":{"class":"go.Point", "x":100.0025, "y":-19.99896446609407}, "thickness":0.005, "isGroup":true, "notes":"", "isDivider":true}
|
||||
],
|
||||
"linkDataArray": []}
|
||||
|
||||
</textarea>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,45 @@
|
||||
const child_process = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Part 1: Build webpack bundle
|
||||
console.log("Building gfp.js");
|
||||
try {
|
||||
console.log("Compiling typescript...");
|
||||
child_process.execSync("tsc");
|
||||
console.log("Running webpack...");
|
||||
child_process.execSync("webpack");
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
|
||||
// Part 2: Build d.ts file
|
||||
console.log("Building gfp.d.ts");
|
||||
try {
|
||||
// Concat all d.ts files in src into one big gcs.d.ts file
|
||||
var files = fs.readdirSync(path.join(__dirname, 'src'));
|
||||
var dtsFileData = "";
|
||||
for (var i in files) {
|
||||
var file = files[i];
|
||||
if (file.includes(".d.ts")) {
|
||||
var fileData = '';
|
||||
var lines = fs.readFileSync(path.join(__dirname, 'src', file), 'utf-8').split('\n');
|
||||
for (var j in lines) {
|
||||
var line = lines[j];
|
||||
if (line.substr(0, 6) !== "import") {
|
||||
fileData += line;
|
||||
}
|
||||
}
|
||||
dtsFileData += fileData;
|
||||
}
|
||||
}
|
||||
fs.writeFileSync('./lib/' + 'gfp.d.ts', dtsFileData);
|
||||
// Remove all individual d.ts files in src
|
||||
for (var i in files) {
|
||||
var file = files[i];
|
||||
if (file.includes('.d.ts') || file.includes('.js')) {
|
||||
fs.unlinkSync(path.join(__dirname, 'src', file));
|
||||
}
|
||||
}
|
||||
} catch (e) { console.log(e); }
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "floorplannertssample",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"devDependencies": {
|
||||
"awesome-typescript-loader": "^5.2.1",
|
||||
"concat": "^1.0.3",
|
||||
"dts-bundle": "^0.7.3",
|
||||
"dts-webpack-plugin": "0.0.9",
|
||||
"dtsbundler-webpack-plugin": "^1.0.0",
|
||||
"sweepline2": "^0.2.1",
|
||||
"typedoc": "^0.17.8",
|
||||
"webpack": "^4.44.1",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"webpack-node-externals": "^2.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.0",
|
||||
"child_process": "^1.0.2",
|
||||
"concatenate": "0.0.2",
|
||||
"del": "^5.1.0",
|
||||
"fs-extra": "9.0.1",
|
||||
"gojs": "^2.1.21",
|
||||
"grunt": "^1.2.1",
|
||||
"inquirer": "^7.3.3",
|
||||
"mkdirp": "^1.0.4",
|
||||
"py": "0.0.0",
|
||||
"replace-in-file": "^6.1.0",
|
||||
"request": "^2.88.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"run-sequence": "^2.2.1",
|
||||
"ts-loader": "^8.0.2",
|
||||
"tslint": "^6.1.3",
|
||||
"typedoc-default-themes": "^0.10.2",
|
||||
"typescript": "^3.9.7",
|
||||
"uglifyjs-webpack-plugin": "^2.2.0",
|
||||
"yargs": "^15.4.1"
|
||||
},
|
||||
"directories": {
|
||||
"lib": "lib"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node npm-gfp-build.js",
|
||||
"dts": "node npm-gfp-dts.js"
|
||||
},
|
||||
"author": "Northwoods Software"
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 1998-2020 by Northwoods Software Corporation
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* FloorplanPalette Class
|
||||
* A FloorplanPalette is a Palette with special rules
|
||||
*/
|
||||
|
||||
import * as go from 'gojs';
|
||||
import { Floorplan } from './Floorplan.js';
|
||||
|
||||
export class FloorplanPalette extends go.Palette {
|
||||
|
||||
constructor(div: HTMLDivElement | string, floorplan: Floorplan/*, nodeDataArray: Array<any>*/) {
|
||||
super(div);
|
||||
|
||||
const $ = go.GraphObject.make;
|
||||
this.contentAlignment = go.Spot.Center;
|
||||
this.nodeTemplateMap = floorplan.nodeTemplateMap;
|
||||
|
||||
// palette also contains "floor" nodes -- nodes of particular floor types that can be dragged and dropped into wall-enclosed areas to create Room Nodes
|
||||
this.nodeTemplateMap.add('FloorNode',
|
||||
$(go.Node, 'Auto',
|
||||
$(go.Shape, { fill: makeFloorBrush(null), desiredSize: new go.Size(100, 100) },
|
||||
new go.Binding('fill', 'floorImage', function(src) {
|
||||
return makeFloorBrush(src);
|
||||
})
|
||||
),
|
||||
$(go.TextBlock, 'Drag me out to a wall-enclosed space to create a room', { desiredSize: new go.Size(90, NaN) },
|
||||
new go.Binding('visible', '', function(node: go.Node) {
|
||||
if (node.diagram instanceof go.Palette) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}).ofObject()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
this.toolManager.contextMenuTool.isEnabled = false;
|
||||
|
||||
// add this new FloorplanPalette to the "palettes" field of its associated Floorplan
|
||||
floorplan.palettes.push(this);
|
||||
|
||||
} // end FloorplanPalette constructor
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a Pattern brush for floor nodes
|
||||
* @param src The relative path of the image to use for the pattern brush. If this is not specified, a default path is tried
|
||||
*/
|
||||
function makeFloorBrush(src: string | null) {
|
||||
const $ = go.GraphObject.make;
|
||||
if (src === null || src === undefined) { src = 'images/textures/floor1.jpg'; }
|
||||
const floorImage = new Image();
|
||||
floorImage.src = src;
|
||||
return $(go.Brush, 'Pattern', { pattern: floorImage });
|
||||
}
|
||||
|
||||
// export = FloorplanPalette;
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (C) 1998-2020 by Northwoods Software Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
import * as go from 'gojs';
|
||||
|
||||
// A custom Tool for moving a label on a Node
|
||||
export class NodeLabelDraggingTool extends go.Tool {
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends Tool
|
||||
* @class
|
||||
* This tool only works when the Node has a label (any GraphObject) marked with
|
||||
* { _isNodeLabel: true } that is positioned in a Spot Panel.
|
||||
* It works by modifying that label's GraphObject.alignment property to have an
|
||||
* offset from the center of the panel.
|
||||
*/
|
||||
|
||||
private label: go.GraphObject | null;
|
||||
private _offset: go.Point;
|
||||
private _originalAlignment: go.Spot | null;
|
||||
private _originalCenter: go.Point | null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.name = 'NodeLabelDragging';
|
||||
|
||||
/** @type {GraphObject} */
|
||||
this.label = null;
|
||||
/** @type {Point} */
|
||||
this._offset = new go.Point(); // of the mouse relative to the center of the label object
|
||||
/** @type {go.Spot} */
|
||||
this._originalAlignment = null;
|
||||
/** @type {Point} */
|
||||
this._originalCenter = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This tool can only start if the mouse has moved enough so that it is not a click,
|
||||
* and if the mouse down point is on a GraphObject "label" in a Spot Panel,
|
||||
* as determined by findLabel().
|
||||
* @this {NodeLabelDraggingTool}
|
||||
* @return {boolean}
|
||||
*/
|
||||
public canStart(): boolean {
|
||||
if (!go.Tool.prototype.canStart.call(this)) return false;
|
||||
const diagram = this.diagram;
|
||||
if (diagram === null) return false;
|
||||
// require left button & that it has moved far enough away from the mouse down point, so it isn't a click
|
||||
const e = diagram.lastInput;
|
||||
if (!e.left) return false;
|
||||
if (!this.isBeyondDragSize()) return false;
|
||||
|
||||
return this.findLabel() !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* From the GraphObject at the mouse point, search up the visual tree until we get to
|
||||
* an object that has the "_isNodeLabel" property set to true, that is in a Spot Panel,
|
||||
* and that is not the first element of that Panel (i.e. not the main element of the panel).
|
||||
* @this {NodeLabelDraggingTool}
|
||||
* @return {GraphObject} This returns null if no such label is at the mouse down point.
|
||||
*/
|
||||
public findLabel(): go.GraphObject | null {
|
||||
const diagram = this.diagram;
|
||||
const e = diagram.firstInput;
|
||||
let elt = diagram.findObjectAt(e.documentPoint, null, null);
|
||||
|
||||
if (elt === null || !(elt.part instanceof go.Node)) return null;
|
||||
if (elt.part instanceof go.Node) {
|
||||
elt.part.isSelected = true;
|
||||
}
|
||||
while (elt.panel !== null) {
|
||||
if ((elt as any)._isNodeLabel && elt.panel.type === go.Panel.Spot && elt.panel.findMainElement() !== elt) return elt;
|
||||
elt = elt.panel;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a transaction, call findLabel and remember it as the "label" property,
|
||||
* and remember the original value for the label's alignment property.
|
||||
* @this {NodeLabelDraggingTool}
|
||||
*/
|
||||
public doActivate(): void {
|
||||
this.startTransaction('Shifted Label');
|
||||
this.label = this.findLabel();
|
||||
if (this.label !== null) {
|
||||
// compute the offset of the mouse-down point relative to the center of the label
|
||||
this._offset = this.diagram.firstInput.documentPoint.copy().subtract(this.label.getDocumentPoint(go.Spot.Center));
|
||||
this._originalAlignment = this.label.alignment.copy();
|
||||
if (this.label !== null && this.label.panel !== null) {
|
||||
const main = this.label.panel.findMainElement();
|
||||
if (main !== null) {
|
||||
this._originalCenter = main.getDocumentPoint(go.Spot.Center);
|
||||
}
|
||||
}
|
||||
}
|
||||
go.Tool.prototype.doActivate.call(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop any ongoing transaction.
|
||||
* @this {NodeLabelDraggingTool}
|
||||
*/
|
||||
public doDeactivate(): void {
|
||||
go.Tool.prototype.doDeactivate.call(this);
|
||||
this.stopTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear any reference to a label element.
|
||||
* @this {NodeLabelDraggingTool}
|
||||
*/
|
||||
public doStop(): void {
|
||||
this.label = null;
|
||||
go.Tool.prototype.doStop.call(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the label's original value for GraphObject.alignment.
|
||||
* @this {NodeLabelDraggingTool}
|
||||
*/
|
||||
public doCancel(): void {
|
||||
if (this.label !== null && this._originalAlignment !== null) {
|
||||
// this.label.alignment = this._originalAlignment;
|
||||
const node: go.Node = this.label.part as go.Node;
|
||||
this.diagram.model.set(node.data, 'labelAlignment', this._originalAlignment);
|
||||
}
|
||||
go.Tool.prototype.doCancel.call(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* During the drag, call updateAlignment in order to set the GraphObject.alignment of the label.
|
||||
* @this {NodeLabelDraggingTool}
|
||||
*/
|
||||
public doMouseMove(): void {
|
||||
if (!this.isActive) return;
|
||||
this.updateAlignment();
|
||||
}
|
||||
|
||||
/**
|
||||
* At the end of the drag, update the alignment of the label and finish the tool,
|
||||
* completing a transaction.
|
||||
* @this {NodeLabelDraggingTool}
|
||||
*/
|
||||
public doMouseUp(): void {
|
||||
if (!this.isActive) return;
|
||||
this.updateAlignment();
|
||||
this.transactionResult = 'Shifted Label';
|
||||
this.stopTool();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the label's GraphObject.alignment as an absolute offset from the center of the Spot Panel
|
||||
* that the label is in.
|
||||
* @this {NodeLabelDraggingTool}
|
||||
*/
|
||||
public updateAlignment(): void {
|
||||
if (this.label === null) return;
|
||||
const last = this.diagram.lastInput.documentPoint;
|
||||
const cntr = this._originalCenter;
|
||||
if (cntr !== null) {
|
||||
const align: go.Spot = new go.Spot(0.5, 0.5, last.x - this._offset.x - cntr.x, last.y - this._offset.y - cntr.y);
|
||||
// this.label.alignment = new go.Spot(0.5, 0.5, last.x - this._offset.x - cntr.x, last.y - this._offset.y - cntr.y);
|
||||
|
||||
const node: go.Node = this.label.part as go.Node;
|
||||
this.diagram.model.set(node.data, 'labelAlignment', align);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// export = NodeLabelDraggingTool;
|
||||
@@ -0,0 +1,197 @@
|
||||
/**
|
||||
* Copyright (C) 1998-2020 by Northwoods Software Corporation
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* FLOOR PLANNER - WALL BUILDING TOOL
|
||||
* Used to construct new Walls in a Floorplan with mouse clicking / mouse point
|
||||
*/
|
||||
|
||||
import * as go from 'gojs';
|
||||
import { Floorplan } from './Floorplan.js';
|
||||
import { WallReshapingTool } from './WallReshapingTool.js';
|
||||
|
||||
export class WallBuildingTool extends go.Tool {
|
||||
|
||||
private _startPoint: go.Point | null;
|
||||
private _endPoint: go.Point | null;
|
||||
private _wallReshapingTool: WallReshapingTool | null;
|
||||
private _buildingWall: go.Group | null = null; // the wall being built
|
||||
// whether or not the "wall" we're building is really just a room / floor divider (not a physical wall)
|
||||
private _isBuildingDivider: boolean = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = 'WallBuilding';
|
||||
this._startPoint = null;
|
||||
this._endPoint = null;
|
||||
this._wallReshapingTool = null;
|
||||
this._isBuildingDivider = false;
|
||||
}
|
||||
|
||||
// Get / set the current startPoint
|
||||
get startPoint(): go.Point | null { return this._startPoint; }
|
||||
set startPoint(value: go.Point | null) { this._startPoint = value; }
|
||||
|
||||
// Get / set the current endPoint
|
||||
get endPoint(): go.Point | null { return this._endPoint; }
|
||||
set endPoint(value: go.Point | null) { this._endPoint = value; }
|
||||
|
||||
// Get / set the floorplan's WallReshapingTool
|
||||
get wallReshapingTool(): WallReshapingTool | null { return this._wallReshapingTool; }
|
||||
set wallReshapingTool(value: WallReshapingTool | null) { this._wallReshapingTool = value; }
|
||||
|
||||
// Get / set the wall being built
|
||||
get buildingWall(): go.Group | null { return this._buildingWall; }
|
||||
set buildingWall(value: go.Group | null) { this._buildingWall = value; }
|
||||
|
||||
// Get / set whether or not we're actually building a room / floor divider, not a wall
|
||||
get isBuildingDivider(): boolean { return this._isBuildingDivider; }
|
||||
set isBuildingDivider(value: boolean) { this._isBuildingDivider = value; }
|
||||
|
||||
/**
|
||||
* Start wall building transaction.
|
||||
* If the mouse point is inside a wall or near a wall endpoint, snap to that wall or endpoint
|
||||
*/
|
||||
public doActivate(): void {
|
||||
this.endPoint = null;
|
||||
this.startTransaction(this.name);
|
||||
this.diagram.isMouseCaptured = true;
|
||||
const tool = this;
|
||||
const fp: Floorplan = tool.diagram as Floorplan;
|
||||
|
||||
let clickPt: go.Point = tool.diagram.lastInput.documentPoint;
|
||||
let isSnapped: boolean = false;
|
||||
// if the clickPt is inside some other wall's geometry, project it onto that wall's segment
|
||||
const walls: go.Iterator<go.Group> = fp.findNodesByExample({ category: 'WallGroup' }) as go.Iterator<go.Group>;
|
||||
walls.iterator.each(function(w: go.Group) {
|
||||
if (fp.isPointInWall(w, clickPt)) {
|
||||
// don't check if you're inside the wall you're building, you obviously are
|
||||
if (tool.buildingWall === null) {
|
||||
const snapPt: go.Point = clickPt.projectOntoLineSegmentPoint(w.data.startpoint, w.data.endpoint);
|
||||
clickPt = snapPt;
|
||||
isSnapped = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// if the click point is close to another wall's start/endpoint, use that as the startpoint of the new wall
|
||||
walls.iterator.each(function(w: go.Group) {
|
||||
const sp: go.Point = w.data.startpoint; const ep: go.Point = w.data.endpoint;
|
||||
const distSp: number = Math.sqrt(sp.distanceSquaredPoint(clickPt));
|
||||
// TODO probably need a better "closeness" metric than just a raw number -- it could be an optional parameter?
|
||||
if (distSp < 15) {
|
||||
clickPt = sp;
|
||||
isSnapped = true;
|
||||
}
|
||||
const distEp: number = Math.sqrt(ep.distanceSquaredPoint(clickPt));
|
||||
if (distEp < 15) {
|
||||
clickPt = ep;
|
||||
isSnapped = true;
|
||||
}
|
||||
});
|
||||
|
||||
// assign startpoint based on grid (iff startpoint was not determined by another wall's endpoint)
|
||||
if (true) {
|
||||
let gs: number = fp.model.modelData.gridSize;
|
||||
if (!(tool.diagram.toolManager.draggingTool.isGridSnapEnabled) || isSnapped) gs = .0001;
|
||||
const newx: number = gs * Math.round(clickPt.x / gs);
|
||||
const newy: number = gs * Math.round(clickPt.y / gs);
|
||||
clickPt = new go.Point(newx, newy);
|
||||
}
|
||||
|
||||
this.startPoint = clickPt;
|
||||
|
||||
this.wallReshapingTool = fp.toolManager.mouseDownTools.elt(3) as WallReshapingTool;
|
||||
// Default functionality:
|
||||
this.isActive = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add wall data to Floorplan and begin reshaping the new wall
|
||||
*/
|
||||
public doMouseDown(): void {
|
||||
const diagram: go.Diagram = this.diagram;
|
||||
const tool = this;
|
||||
tool.diagram.currentCursor = 'crosshair';
|
||||
const data = {
|
||||
key: 'wall', category: 'WallGroup', caption: tool.isBuildingDivider ? 'Divider' : 'Wall', type: tool.isBuildingDivider ? 'Divider' : 'Wall',
|
||||
startpoint: tool.startPoint, endpoint: tool.startPoint, smpt1: tool.startPoint, smpt2: tool.startPoint, empt1: tool.startPoint, empt2: tool.startPoint,
|
||||
thickness: tool._isBuildingDivider ? .005 : parseFloat(diagram.model.modelData.wallThickness), color: 'lightgray', isGroup: true, notes: '',
|
||||
isDivider: tool.isBuildingDivider
|
||||
};
|
||||
this.diagram.model.addNodeData(data);
|
||||
const wall: go.Group = diagram.findPartForKey(data.key) as go.Group;
|
||||
this.buildingWall = wall;
|
||||
const fp: Floorplan = diagram as Floorplan;
|
||||
fp.updateWall(wall);
|
||||
const part: go.Part | null = diagram.findPartForData(data);
|
||||
if (part === null) return;
|
||||
// set the TransactionResult before raising event, in case it changes the result or cancels the tool
|
||||
tool.transactionResult = tool.name;
|
||||
diagram.raiseDiagramEvent('PartCreated', part);
|
||||
|
||||
if (tool.wallReshapingTool === null) return;
|
||||
// start the wallReshapingTool, tell it what wall it's reshaping (more accurately, the shape that will have the reshape handle)
|
||||
tool.wallReshapingTool.isEnabled = true;
|
||||
diagram.select(part);
|
||||
tool.wallReshapingTool.isBuilding = true;
|
||||
tool.wallReshapingTool.adornedShape = part.findObject('SHAPE') as go.Shape;
|
||||
tool.wallReshapingTool.doActivate();
|
||||
}
|
||||
|
||||
/**
|
||||
* If user presses Esc key, cancel the wall building
|
||||
*/
|
||||
public doKeyDown(): void {
|
||||
const fp: Floorplan = this.diagram as Floorplan;
|
||||
const e: go.InputEvent = fp.lastInput;
|
||||
if (e.key === 'Esc') {
|
||||
const wall: go.Group = fp.selection.first() as go.Group;
|
||||
fp.remove(wall);
|
||||
fp.pointNodes.iterator.each(function(node) { fp.remove(node); });
|
||||
fp.dimensionLinks.iterator.each(function(link) { fp.remove(link); });
|
||||
fp.pointNodes.clear();
|
||||
fp.dimensionLinks.clear();
|
||||
this.doDeactivate();
|
||||
}
|
||||
go.Tool.prototype.doKeyDown.call(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* When the mouse moves, reshape the wall
|
||||
*/
|
||||
public doMouseMove(): void {
|
||||
if (this.wallReshapingTool === null) return;
|
||||
this.diagram.currentCursor = 'crosshair';
|
||||
this.wallReshapingTool.doMouseMove();
|
||||
}
|
||||
|
||||
/**
|
||||
* End transaction, update wall dimensions and geometries (mitering?)
|
||||
*/
|
||||
public doDeactivate(): void {
|
||||
const diagram: go.Diagram = this.diagram;
|
||||
this.buildingWall = null;
|
||||
this.diagram.currentCursor = '';
|
||||
this.diagram.isMouseCaptured = false;
|
||||
|
||||
if (this.wallReshapingTool !== null) {
|
||||
this.wallReshapingTool.isEnabled = false;
|
||||
this.wallReshapingTool.adornedShape = null;
|
||||
this.wallReshapingTool.doMouseUp(); // perform mitering
|
||||
this.wallReshapingTool.doDeactivate();
|
||||
this.wallReshapingTool.isBuilding = false;
|
||||
}
|
||||
|
||||
const fp: Floorplan = diagram as Floorplan;
|
||||
fp.updateWallDimensions();
|
||||
|
||||
this.stopTransaction();
|
||||
|
||||
this.isActive = false; // Default functionality
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// export = WallBuildingTool;
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (C) 1998-2020 by Northwoods Software Corporation
|
||||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
import * as Floorplan from './Floorplan.js';
|
||||
import * as FloorplanPalette from './FloorplanPalette.js';
|
||||
import * as WallBuildingTool from './WallBuildingTool.js';
|
||||
import * as WallReshapingTool from './WallReshapingTool.js';
|
||||
|
||||
module.exports = {
|
||||
Floorplan: require('./Floorplan').Floorplan,
|
||||
FloorplanPalette: require('./FloorplanPalette').FloorplanPalette,
|
||||
WallBuildingTool: require('./WallBuildingTool').WallBuildingTool,
|
||||
WallReshapingTool: require('./WallReshapingTool').WallReshapingTool
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"removeComments": true,
|
||||
"stripInternal": true,
|
||||
"declaration": true,
|
||||
"declarationDir": "./src/",
|
||||
"strict": true
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*.ts"
|
||||
],
|
||||
"exclude": [],
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var webpack = require('webpack');
|
||||
//const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
"gfp": './src/floorplannerFiles', // webpack floorplanner bundle
|
||||
},
|
||||
target: 'web',
|
||||
devtool: "source-map",
|
||||
resolve: {
|
||||
extensions: [".tsx", ".js", ".ts"]
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'lib'),
|
||||
filename: 'gfp.js',
|
||||
libraryTarget: 'window',
|
||||
library: 'gfp'
|
||||
},
|
||||
optimization: {
|
||||
minimize: false
|
||||
},
|
||||
externals: [
|
||||
{
|
||||
'gojs': 'go'
|
||||
}
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new webpack.BannerPlugin("Copyright (C) 1998-2020 by Northwoods Software Corporation. All Rights Reserved.")
|
||||
////new UglifyJSPlugin({ sourceMap: true })
|
||||
]
|
||||
};
|
||||