# HART Estate Widget

The package is designed to present 2D and 3D floor plans generated by the AI service [getfloorplan.com](https://getfloorplan.com).

# Table of Contents
- [Quick Start](#quick-start)
  - [Example vite.config.ts](#vite)
  - [Example index.html](#html)
  - [Example index.js](#javascript)
  - [Example index.sass](#sass)
- [Docs](#docs)
  - [Parameters](#parameters)
  - [REST API Object](#widget-object-from-the-rest-api)
- [Versioning](#versioning)
- [Copyright and License](#copyright-and-license)

# Quick Start

As a result, you will receive a website that can display various floor plans.

![node: ^18.0.0](https://img.shields.io/badge/nodeJS-^18.0.0-blue)

- Download NodeJS 18+
- Create a new project
```shell
npm init
```
- Download the required packages
```shell
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](https://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`

```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`

```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`

```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`

```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".

```json
{
  // 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
  "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
  // "scale" - Scale x1, x2, x0.5 button
  // "autoRotate" - Auto rotate enable/disable button
  "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,

  // Camera persective FOV
  "cameraFov": 75,

  // Panorama fade time in seconds
  "panoramaFadeTime": 0.5,

  // 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

```js
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](#quick-start)

This project is maintained under the [Semantic Versioning guidelines](https://semver.org).  

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](https://www.gnu.org/licenses/gpl-3.0-standalone.html).  

Project code and documentation copyright [hart-digital.com](https://hart-digital.com).  
All renders of floor plans copyright [getfloorplan.com](https://getfloorplan.com). 
