HART Estate Widget
The package is designed to present 2D and 3D floor plans generated by the AI service getfloorplan.com.
Table of Contents
Quick Start
As a result, you will receive a website that can display various floor plans.
- Download NodeJS 18+
- Create a new project
npm init
- Download the required packages
npm install -S hart-estate-widget@4.0.0 # GFP Widget package npm install -S -D vite # Vite bundler npm install -S -D sass-embedded # Sass style compiler
- Example structure of project
. ├── src │ ├── index.html │ ├── index.js │ ├── index.sass │ └── logo.png ├── package.json └── package-lock.json
- Copy-paste sample assets from below.
- Run with
rm -rf dist && npx vite
- Open browser at: http://localhost:1234/?id=73b833c3-072a-4ac2-9f5d-7f7ac3d1fc9c
The query
id
parameter accepts the UUID4 received from getfloorplan.com You can use these UUID4 for test purposes:
- Scandy style:
228ba1dd-64d3-4d33-bcd7-b4c670bed40e
- Boho style:
f9032373-bb2c-416e-b0ab-20b8fd24d482
- England style:
b21871a2-2d5b-4beb-817b-ed750eebab9a
- Neutral style:
e8553134-0457-488c-8d3e-611b0e2be4d4
- Modern style:
73b833c3-072a-4ac2-9f5d-7f7ac3d1fc9c
VITE
Insert the example into a file vite.config.ts
import { defineConfig } from 'vite';
export default defineConfig({
root: 'src',
build: { outDir: '../dist' },
server: { port: 1234, open: true },
});
HTML
Insert the example into a file src/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
<title>HART Estate Widget</title>
<script type="module" src="./index.js"></script>
<link rel="icon" href="./logo.png">
</head>
<body>
<div id="widget"></div>
</body>
</html>
JavaScript
Insert the example into a file src/index.js
import { Api } from 'hart-estate-widget/build/api.js'
const searchParams = new URLSearchParams(document.location.search);
const planId = searchParams.get('id');
const crmPlanId = searchParams.get('crmPlanId');
const baseUrl = 'https://backend.estate.hart-digital.com';
const loadData = async () => {
const {loadCrmWidgetData, loadWidgetData} = new Api(baseUrl);
return crmPlanId ? loadCrmWidgetData(crmPlanId) : loadWidgetData(planId);
};
const loadCreateWidget = async () => (await import('hart-estate-widget/build/createWidget.js')).createWidget;
const loadFovPlugin = async () => (await import('hart-estate-widget/build/plugins/FovPlugin.js')).FovPlugin;
const loadLogoUrl = async () => (await import('./logo.png')).default;
const loadStyle = async () => (await import('./index.sass')).default;
const loadDocument = async () => new Promise((resolve) => (window.onload = resolve));
const queue = [
loadData(),
loadCreateWidget(),
loadFovPlugin(),
loadLogoUrl(),
loadStyle(),
loadDocument(),
];
Promise.all(queue).then(([data, createWidget, FovPlugin, logoUrl]) => {
const options = {
baseUrl,
logoUrl,
logoLinkUrl: 'https://getfloorplan.com',
};
const plugins = [
new FovPlugin(2),
];
createWidget('#widget', data, options, plugins);
});
SASS
Insert the example into a file src/index.sass
*, *:before, *:after
-webkit-font-smoothing: antialiased
-moz-osx-font-smoothing: grayscale
font-family: 'Proxima Nova', sans-serif
text-decoration: none
font-weight: 400
color: #fff
outline: none
padding: 0
margin: 0
box-sizing: border-box
-webkit-box-sizing: border-box
html, body
width: 100%
height: 100%
#widget
width: 100%
height: 100%
overflow: hidden
Docs
Parameters:
Here you can see a list of accessible options and examples of usage. There are accessible values for each option below in the block "Types of Elements".
{
// Widget API base URL
"baseUrl": "https://backend.estate.hart-digital.com",
// Widget locale can be one of
// "en" - English language
// "ru" - Russian language
// "de" - German language
// "es" - Spanish language
// "ja" - Japanese language
// "nl" - Dutch language
"locale": "en",
// Overrides locale keys with custom text or translation
"localeOverrides": {
"rotate-plan": "Rotate plan",
"research-plan": "Research plan",
"create-points": "Create a point",
"delete-points": "Remove point",
"instructions-hint-text": "",
"ok": "Ok",
"ruler-ok": "Ok",
"made-by-template": "$0 $1",
"made-by-prefix": "made by",
"made-by-link": "https://getfloorplan.com/",
"made-by-text": "getfloorplan.com",
"style": "Style",
"floor": "$0 floor",
"floorNumberEndings": {
"1": "$0st",
"2": "$0nd",
"3": "$0d",
"rest": "$0th"
}
},
// Path/link to the logo
"logoUrl": "https://getfloorplan.com/img/logo.58f6cd11.svg",
// Link opened when logo is clicked
"logoLinkUrl": "https://getfloorplan.com",
// Widget color settings in CSS color formal like: "rgba(255, 255, 255, 0)", "#ABCDEF", etc...
// "main" - main color of buttons, elements
// "mainText" - text color for buttons, elements contrasting with the main color
"colors": {
"main": "#FFA900",
"mainText": "#413E3E"
},
// First opened tab
"primaryTab": "panorama",
// Available widget tabs array with order:
// "panorama" - Panorama 360 tab
// "rotation" - Isometric plan rotation tab
// "plan" - Original plan tab
"tabs": ["plan", "rotation", "panorama"],
// Controls in bottom bar, can be:
// "ruler" - Ruler enable/disable button (panorama tab only)
// "scale" - Scale x1, x2, x0.5 button (panorama tab only)
// "autoRotate" - Auto rotate enable/disable button (panorama tab only)
// "minusScale" - Scale minus button (panorama tab only)
// "plusScale" - Scale plus button (panorama tab only)
// "furnished" - Furnished / bareshell button (panorama tab only)
// "prevPanorama" - Prev panorama button (panorama tab only)
// "nextPanorama" - Next panorama button (panorama tab only)
// "2d" - 2D tab button
// "3d" - 3D tab button
// "360" - 360 tab button
// "isometry" - Isometry rotation arrows (rotation tab only)
// "floors" - Floors select with reverse order inside application frame
"controls": ["ruler", "scale", "autoRotate"],
// Enable/disable modal of instruction in 3D tour
"isInstructionsVisible": true,
// Enable/disable auto rotation in 3D tour
"isAutoRotate": false,
// Enable/disable device gyroscope for AR
"isGyroscopeEnabled": true,
// Show/hide fullscreen button
"isFullscreenButtonVisible": true,
// Show/hide current room type top label
"isRoomLabelVisible": false,
// Show next scale text or current
// true: next (current: 0.5, shows: 1x)
// false: current (current: 0.5, shows: 0.5x)
"isShowNextScaleText": false,
// Enable InteractiveRotationTab
// true: InteractiveRotationTab will show on interactive_top_view capability
// false: always use default RotationTab
"isInteractiveTabAvailable": true,
// Use multifloor map instead of default or topView
"isMultifloorMap": false,
// Automatic crop transparent part of images by rasterizer (may lag a bit)
"isNeedCropMultifloorMap": true,
// Precision of multifloor map crop
"multiFloorMapCropPrecision": 100,
// Move panorama control buttons to the application context
"isAbsolutePanoramaControls": false,
// Show prev/next room type labels on prev/next panorama buttons
"isShowLabelsOnPrevNext": true,
// Render links as div elements in UI layer
"isOverrideLinks": false,
// Enable room indexer button in rotation tab
"isRoomIndexerVisible": false,
// Show top view on rotation tab
"isShowTopViewOnRotationTab": true,
// Show left and right arrows in room scroll container
"isInteractiveScrollArrowsVisible": true,
// 'original' - use original_plan_img
// 'miniplan' - use miniplan_img
"2DTabBehavior": "miniplan",
// Show the "hide furniture" button with a separate switch
"isHiddenFurnitureSwitchVisible": true,
// Ruler font settings
"rulerFontSettings": {
"fontSize": "38px",
"fontWeight": "Bold",
"lineHeight": "1",
"fontFamily": "Roboto Flex",
"textAlign": "center",
"borderRadius": 55,
"scale": 1.5,
"width": 256,
"height": 128,
"textFillColor": "#0008",
"textHoverColor": "#000f",
"fillColor": "#fff8",
"hoverColor": "#fffa",
"feetsPositionY": 100,
"feetsPrecision": 2,
"feetsFormat": "$0 ft",
"useFeetsComma": true,
"metersPositionY": 50,
"metersPrecision": 2,
"metersFormat": "$0 m",
},
// Base camera persective FOV
"cameraFov": 75,
// Custom camera fovs by base FOV Scale
"cameraFovs": [
{ "text": "1x", "value": 1 },
{ "text": "2x", "value": 0.5 },
{ "text": "4x", "value": 0.25 },
{ "text": "0.5x", "value": 1.35 },
],
// Legacy camera fovs by scale texts (available: 0.5x, 1x, 2x)
"scales": ["1x", "2x", "0.5x"],
// Custom link icons
"linkIcons": {
"door": "https://site.com/door.png",
"doorHover": "https://site.com/door-hover.png",
"spot": "https://site.com/spot.png",
"spotHover": "https://site.com/spot-hover.png",
"stairUp": "https://site.com/stairUp.png",
"stairUpHover": "https://site.com/stairUp-hover.png",
"stairDown": "https://site.com/stairDown.png",
"stairDownHover": "https://site.com/stairDown-hover.png",
},
// Custom UI icons
"uiIcons": {
"tabs.2D": "https://site.com/2D.png",
"tabs.3D": "https://site.com/3D.png",
"tabs.360": "https://site.com/360.png",
"tabs.roomIndexer": "https://site.com/roomIndexer.png",
"room.kidroom": "https://site.com/kidroom.png",
"room.balcony": "https://site.com/balcony.png",
"room.gym": "https://site.com/gym.png",
"room.bathroom": "https://site.com/bathroom.png",
"room.bedroom": "https://site.com/bedroom.png",
"room.garage": "https://site.com/garage.png",
"room.hallway": "https://site.com/hallway.png",
"room.kitchen": "https://site.com/kitchen.png",
"room.office": "https://site.com/office.png",
"room.living": "https://site.com/living.png",
"room.storage": "https://site.com/storage.png",
"room.terrace": "https://site.com/terrace.png",
"room.toilet": "https://site.com/toilet.png",
"float.close": "https://site.com/close.png",
"float.extend": "https://site.com/extend.png",
"float.multiMap": "https://site.com/multiMap.png",
"float.shrink": "https://site.com/shrink.png",
"float.fullscreen": "https://site.com/fullscreen.png",
"instructions.move": "https://site.com/move.png",
"instructions.research": "https://site.com/research.png",
"instructions.createPoints": "https://site.com/createPoints.png",
"instructions.deletePoints": "https://site.com/deletePoints.png",
"controls.rulerOn": "https://site.com/rulerOn.png",
"controls.rulerOff": "https://site.com/rulerOff.png",
"controls.prevPanorama": "https://site.com/prevPanorama.png",
"controls.nextPanorama": "https://site.com/nextPanorama.png",
"controls.minusScale": "https://site.com/minusScale.png",
"controls.plusScale": "https://site.com/plusScale.png",
"controls.autoRotateOn": "https://site.com/autoRotateOn.png",
"controls.autoRotateOff": "https://site.com/autoRotateOff.png",
"controls.arrowLeft": "https://site.com/arrowLeft.png"
},
// Panorama fade time in seconds
"panoramaFadeTime": 0.5,
// Panorama miniplan type, use svg or original
"panoramaMiniplanType": "svg",
// Overrides for interactive opacity
"interactiveHoverOpacity": 0.65,
"interactiveActiveOpacity": 0.8,
// Camera sensitivity
"cameraHorizontalSensitivity": 1,
"cameraVerticalSensitivity": 1,
"mobileCameraHorizontalSensitivity": 2,
"mobileCameraVerticalSensitivity": 2,
// Widget external integrations
"integrations": {
// https://docs.sentry.io/platforms/javascript/configuration/options/
"sentry": {
"dsn": "https://1234567890abcdef@sentry.com/12345"
}
}
}
Widget object from the REST API
JSON object returned from backend
export default {
primary_variant: "<id>", // primary variant to open
variants: [ // all plan variants
{
variant_info: {
style_name: "<name>", // the name of the variant style
is_renovation: true, // is there a renovation in the plan
},
plan_id: "<uuid>", // variant service plan uuid
json: "<url>", // json url for additional plan data
assets_path: "<path>", // plan assets base url
capabilities: { /*...*/ }, // plan capabilities
rendering_settings: { /*...*/ }, // plan rendering settings
primary_floor: 0, // primary plan floor index
floors: [ // plan floors
{
original_plan_img: "<url>", // absolute path to original plan image
miniplan_img: "<url>", // absolute path to miniplan image
top_view: {
image_template: "<template>", // template for top view decoding
room_ids_template: "<template>", // template for top view mask decoding
items: ["<filename>"], // top view image names
},
isometric_view: {
image_template: "<template>", // template for isometric images decoding
room_ids_template: "<template>", // template for isometric images masks decoding
items: ["<filename>"], // isometric images names
},
panorama_view: {
template: "<template>", // template for panorama image decoding
scene_depth_template: "<template>", // template for panorama depth image decoding
primary_camera_point_id: "<id>", // primary plan camera id
},
location: { X: 0, Y: 0, Z: 0 }, // floor location
height: 280, // floor height
vertices: [ /*...*/ ], // plan vertices data
rooms: [ /*...*/ ], // plan rooms data
camera_points: [ /*...*/ ], // plan camera points data
walls: [ /*...*/ ], // plan walls data
doors: [ /*...*/ ], // plan doors data
stairs: [ /*...*/ ], // plan stairs data
portals: [ /*...*/ ], // plan portals data
apertures: [ /*...*/ ], // plan apertures data
decors: [ /*...*/ ], // plan decors data
object_pairs: [], // color pairs for furniture data
room_pairs: [], // color pairs for room data
plan_meta: { /*...*/ }, // plan metadata
},
],
},
],
};
Versioning
For the latest stable version refer to the latest up-to-date version in Quick Start
This project is maintained under the Semantic Versioning guidelines.
However, some versions are being developed for specific clients. We do not recommend using them, as changes in these versions are not documented and may affect your functionality.
Copyright and license
The project code is licensed under the GPLv3 license.
Project code and documentation copyright hart-digital.com. All renders of floor plans copyright getfloorplan.com.