Embedding the editor (archived-oct-31-2021)

❗️

Archived document

You are looking at an archived document, the latest version can be found here.

Introduction

The editor app is the app where people can create their floor plans and interior designs. The scope of the editor is limited to one floor plan project. Think of a project as a house for a family with the possibility of multiple floor levels, bigger than a room and smaller than an apartment building. You can see a demo of the editor on the Floorplanner website.

This page explains how you can embed the editor app into your own HTML page.

Floorplanner Enterprise subscription

Before you start, make sure you have a Floorplanner Enterprise subscription and an API key. You need an API key to be able to log in as a certain user so you can load and save his/her floor plan projects. Have a look at the Floorplanner pricing page for more info about the Enterprise subscription.

Setup HTML & CSS

Let’s start with a minimal HTML page to embed the editor app. There are some placeholders present within square brackets, e.g. [AUTH_TOKEN], these must be replaced with actual values. You can scroll down to find more info about these placeholders. The scripts will take care or loading the latest version of the editor, including its stylesheets.

The editor app nests itself inside a target HTML node. In the HTML example below, this is done using a

with id="fp-editor-container". In this sample the editor will take up 1024px width and 880px height of the target div (#fp-editor-container). The height must be set explicitly, using min-height is not sufficient since a height: 100% within such element is not respected. The dimensions used in the example are the recommended minimum width and height attributes, you can go below this but in some cases, the editor needs at least this minimum amount of space.

<!DOCTYPE html>
    <html>
        <head>
          <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
          <meta content="initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
        </head>
        <body>
            <div id="fp-editor-container" style="width: 1024px; height: 880px;"></div>
            <script data-floorplanner-editor src="https://fp-editor-cdn.floorplanner.com/embed.js" crossorigin="anonymous"></script>
            <script type="text/javascript">
               initFPEditor({
                  projectId: [PROJECT_ID],
                  mountSelector: '#fp-editor-container',
                  user: {
                      id: "[USER_ID]",
                      auth_token: "[AUTH_TOKEN]",
                      permissions: ['save'],
                  },
                  language: 'en-US',
              }).then(api => (window.api = api));
            </script>
        </body>
    </html>

Placeholders

Within the HTML, the placeholders [USER_ID], [AUTH_TOKEN] and [PROJECT_ID] must be replaced with real values. Below this section, you can find out how to retrieve each individual component.

Replacing AUTH_TOKEN and USER_ID

User ID and Authentication tokens can be retrieved by making an API request with your API key (scroll to bottom to find it). The following is an example cURL request. Do not forget to replace [YOUR_API_KEY] with your actual API key:

curl --user [YOUR_API_KEY]:x https://floorplanner.com/api/v2/users/token.json

This will return json in the following format:

{
   "token" : "eyJ0eXAiOiJKV1QiLQL1bGciOiJIUzI1NiJ9.eyJhY3Rpb24abaJsb2dpbiIsIm1vZGVsIjoiVXNlciIsImlkIjoxMDMsImlhdCI6MTUyMTczMTIwMH0.juutj2LGAVDUAV103Cz_viPvIfcPcs6weIPl3eFtsdM",
   "user_id" : 1337
}

Within the HTML template, replace [AUTH_TOKEN] with the value of the token key inside the result JSON. Also replace [USER_ID] with the value of user_id inside the result JSON.

Replacing project_id

See the following API call to fetch all the projects you can access, their ID will be part of the JSON output: Projects#index. Replace the [PROJECT_ID] in the HTML template with any of these ID’s.

IMPORTANT: [PROJECT_ID] must be of type number, thus 123 and not "123".

Editor settings

The settings object can be used to customize certain parts of the editor, see the sample below:

var settings = {
    // Set the domain used for requests from the editor.
    // You can remove this setting when using the production environment.
    apiDomain: 'sandbox.floorplanner.com',

    // Toggles between metric and imperial measurement systems [true, false]
    useMetric: true,

    // A template offers a way to add consistent branding to floorplans and interior renders.
    // It's a collection of style and export settings which can be modified in the website.
    templateId: 160,

    // To use the branding styling and settings you will need to the set the brandingId property.
    // This can be a ID or the subdomain name of the branding. If it's a subdomain, be sure
    // to uses quotations around the value.
    brandingId: 1,
  
    // Type of editor with the kind property. These are the optional values:
    // 'spaceplanner', 'editor', 'viewer' and 'roomplanner'
    kind: 'editor',

    // User info
    user: {
        // The Floorplanner user id
        id: 1337,

        // Optional, this will set the default email address for the 2D & 3D exports
        email: '[email protected]',

        // An array of permissions:
        //    'save' shows the save button in the top bar
        //    'no-export' hides the 2D & 3D export buttons in the top bar
        //    'hide-email' hides the email field at the bottom of the export popup
        //    'no-back-to-dashboard' hides the Back to dashboard button in the sidebar
        //    'ntl' turns off the cooldown period for renders
        permissions: ['save', 'no-export'],

        // Authentication token to log in as a certain user
        auth_token: 'eyJ0eXAiOiJKV1QiLQL1bGciOiJIUzI1NiJ9.eyJhY3Rpb24abaJsb2dpbiIsIm1vZGVsIjoiVXNlciIsImlkIjoxMDMsImlhdCI6MTUyMTczMTIwMH0.juutj2LGAVDUAV103Cz_viPvIfcPcs6weIPl3eFtsdM'
    }
};

Unmounting the editor with React

If you are embedding the editor in a single-page webapp, you need to make sure you unmount the editor before you initialize it again.

ReactDOM.unmountComponentAtNode(document.getElementById('fp-editor-container'));

This will ensure that references to the editor are released and there will be just one instance after you initialize it again.

API methods

It possible to trigger certain actions inside the editor by calling methods on the editor API object. For example, this will trigger a save action:

fpEditor.save();

Methods and properties available on the editor API object are:

Method/PropertyDescription
save()Saves the current floor plan.
isDirtyReturns true if there are unsaved changes.
stateReturns the state of the Floorplan object (walls, items, areas..) displayed in the editor.
metaReturns metadata about areas and outer walls of the Floorplan object.
zoomIn()Zooms in.
zoomOut()Zooms out.
zoomAll()Zooms to fit the view.
dropItem(id, pos)Drops an item onto the plan. id is 40-character item id, pos is {x,y} where x and y are viewport coordinates. You can use MouseEvent.clientX and clientY there.
viewWrite-only. Should be either ‘2D’ or ‘3D’. Switches to the corresponding view.
designIdWrite-only. Given an id of the design of current project, loads that design into the view.
projectRead-only. Data about project, including floors and designs. Meant to be used to list project’s floors and designs and to switch betwen them (setting the /designId/ property).

You can also subscribe to following events:

PropertyDescription
onSaveThe function assigned to this property will be called whenever the plan was saved.
onUpdatedWill be called whenever internal state of the floorplan is updated. NB! The first update happens when the design is loaded.
onQuitWill be called whenever the editor is going to quit. NB! This handler replaces the default one, which sets window.location to ‘/dashboard’. So if your goal is to navigate the user to some other page, you have to do it in the body of the handler.
onExportWill be called whenever an export was requested. The assigned function will get a single input parameter, either “interior” or “floorplan”, indicating the type of the export.

Callback examples

How to assign an event handler:

fpEditor.onUpdated = (data) => console.log('floorplan updated', data);

Get list of products of unique products with count on each update:

fpEditor.onUpdated = (data) => {
    // Get all products from state and map the asset data
    var allProducts = data.state.items.map((item) => item.asset);

    // Get unique products with counts
    var uniqueProducts = [];
    for (i = 0; i < allProducts.length; i++) {
        var index = uniqueProducts.findIndex(
            (product) => product.id === allProducts[i].id
        );
        if (index >= 0) {
            uniqueProducts[index].count++;
        } else {
            uniqueProducts.push({...allProducts[i], count: 1});
        }
    }

    console.log('unique products', uniqueProducts);
};

Get product added and product removed:

var products = fpEditor.state.items;

fpEditor.onUpdated = (data) => {
    // Get changed item
    if (products.length < data.state.items.length) {
        console.log('product added', data.state.items[data.state.items.length - 1]);
    } else if (products.length > data.state.items.length) {
        var allProducts = products.map((product) => product.asset.id);
        var currentProducts = data.state.items.map((product) => product.asset.id);
        var removedProductIds = allProducts.filter((d) => !currentProducts.includes(d));
        var removedProducts = products.filter(
            (product) => removedProductIds.includes(product.asset.id)
        );

        console.log('product(s) removed', removedProducts);
    }

    // Update products array
    products = data.state.items;
};