0

I have a web page where the user creates simple drawings using various blocks, e.g. shapes representing furniture are drag and dropped onto a building floor plan. It uses Interact.js.

The blocks themselves can be dragged/moved, resized, added, inserted, deleted, merged, split, recoloured, font etc by the user - JavaScript acting on HTML and CSS.

I plan to save changes locally (for offline if needed) and back to the server for sharing with others who have access to this project. Undo/redo is nice to have too.

How to save modified diagrams (html & CSS)?

d586
  • 247
  • 2
  • 8

3 Answers3

2

Option 1:

document.getElementById('foo').innerHTML for the HTML.

For CSS you'd have to recursively traverse the whole DOM and match selectors on each element to the rules defined in each CSS file.

As described in the answer above, this will (most of the times) work for classes:

var classes = document.styleSheets[0].rules || document.styleSheets[0].cssRules;
for (var x = 0; x < classes.length; x++) {
    if (classes[x].selectorText == className) {
        (classes[x].cssText) ? alert(classes[x].cssText) : alert(classes[x].style.cssText);
    }
}

But this is a bad, error-prone solution.

Option 2:

What you need to do is have a data model that you edit, think of JSON looking like this:

[
    {type: 'circle', color: 'blue', x: 10, y: 15, children: [
        {type: 'line', color: 'red', x: 100, y: 0, children: []}
    ]},
    {type: 'square', color: 'greed', x: 100, y: 15, children: []}
]

Based on this you'd write a recursive function like this:

var foo = document.getElementById('foo'); // this is where you "draw" stuff

function draw(elements) {
    var i;
    for(i in elements) {
        drawElement(elements[i]);
        if(elements[i].children.length > 0) {
            draw(elements[i].children); 
        }  
    }
}

function drawElement(element) {
     var domElement = document.createElement("div");
     domElement.className = 'element ' + element.type + ' ' + element.color;
     domElement.style.left = element.x + 'px';
     domElement.style.top = element.y + 'px';
     foo.appendChild(domElement);
}

Now you need to define some CSS:

#foo {
    position: relative;
}

#foo .element {
    position: absolute;
}

#foo .element.square {
  ...
}

#foo .element.blue {
  background-color: blue;
}

Next, the "interactive" part. Whenever your user adds something to the "canvas" instead of directly manipulating the DOM you only add stuff to that JSON tree and then delete the old DOM and run draw again.

You can go with option 1 but that will be a lot harder. Read the comments in the answer I attached, you'll see there are a lot of browser inconsistencies and limitations.

Option 3: Working with a <canvas>, not the DOM is more manageable. Try looking into Fabric.js for example, it already handles "saving" and "initializing" from JSON and allows users to "draw" stuff to it.

Community
  • 1
  • 1
Sergiu Paraschiv
  • 9,929
  • 5
  • 36
  • 47
  • Thanks, For interactive part I use Interactive.js. I am thinking that the user could create a particular colour scheme/palette for a project then share it. – d586 May 18 '15 at 08:39
  • Then you'd use the same principle for defining color palettes and share the generated JSON. Each "color" would have a unique ID that you'd then add as a property to each element in the "DOM" JSON based on what the user selected. The main point is to separate the underlying data model from what's actually displayed on the UI. That way it's easier to "reproduce" everything on the UI from a "simple" set of commands and storing the underlying model is easy, it's just some JSON. – Sergiu Paraschiv May 18 '15 at 08:52
1

With jQuery you can use .html() method to retrive inner html of your container. But for css I think you should manually examine all properties of all objects you want to save to get similar approach.

So, for both, if you can modify the code that handles drawing operations, I think the simplest way would be catalog all actions that user can do and store it in a variable that enable you to reproduce all the process another time.

For example:

[
    ["drawBox", 200, 200, 400, 400, "#ff0000", "#0000ff"],
    ...
]

This approach will be also useful if you want to impement undo/redo functionalities in the future.

bitifet
  • 3,514
  • 15
  • 37
0

You should store that 'state' in db. you can use HTML5 SessionState to save rendered Page Content also you can store that in local storage of browser and sync local storage with db.

1SaeedSalehi
  • 364
  • 1
  • 8
  • 16