A
A
Alexander Popov2019-03-09 06:28:45
JavaScript
Alexander Popov, 2019-03-09 06:28:45

What is the best way to store and present data?

Good day,
I am writing a document layout system for online publishing. The system is aimed at automatic rendering of text and images, first of all, the emphasis is on the output of text in columns with alignment on the left line, that is, verses.
All data is stored as JSON objects. The structure is built as follows: there is the concept of an object (entity), which can be either a text page or an image page. At the same time, a text page is designed to display text (it contains text and a lot of related parameters, including headings, indents, alignment, and more), although it may have a background behind it (for the convenience of creating documents). An illustration page is intended for cases where text is not needed at all, while such a page can have nested objects. Nested objects are no different from ordinary ones (rendering is performed by the same method), and, in turn, can have their own arrays of nested objects - there is no fundamental restriction on the level of nesting.
Each nested object has a size, coordinates, and corner radius.
At the same time, simplified markup (pseudo-HTML) is supported so that the user can quickly change coordinates and sizes right on the spot (if he does not want to do this by dragging with the mouse), and see what is where. The markup itself is stored as a text field on the parent object, and the child elements are <n pos="x, y" size="w,h" r="r">. Moreover, at the rendering stage, this markup is inserted into the generated HTML almost as is, after a series of processing with regular expressions, and putting down the necessary style properties.
Everything was quite simple and clear, until the turn came to the implementation of containers.
Containers are elements that provide the layout of the objects nested in them. At the same time, they themselves are not objects (according to the original plan). You can think of them as some kind of layout managers. They, by design, should also turn into plain HTML after processing. Two types of containers were conceived - rows and columns (<row> and <col>). However, a row cannot contain a nested row, and a column cannot contain a nested column. Nesting a column inside a row and vice versa is allowed.
Now I have a function that, after editing the child object (containers are not yet implemented at all), updates the parent's markup, finding the desired fragment and replacing it with a new one. By the way, an important note: the markup of child objects, if any, is not included in the markup of the parent - that is, the text markup "serves" only direct children (and containers).
Turning to containers, I need, firstly, to implement the creation of a container with a given number of cells (let it be image pages by default), change the type of an arbitrary cell, change the order of cells (movement), and change the dimensions of cells (everything is trivial here ). Also, you may need functions for extracting an object from all containers to the very top and placing an object in a specified container (with extraction from the current,
I started trying to implement it. Wrote a function that bypasses all the markup and builds a flat list of all containers (in case, so that later it would be easy to implement the "place in container" function with an arbitrary destination). At the same time, for each container, the list of its descendants is successfully saved, including the containers nested in it. The indexes of the beginning and end of the markup of this container are also stored in the line containing the markup of the current page.
Further, I had a number of questions, and I do not know in which direction it is better to move on.
1. With the current model, each change in the type of a cell inside a container from a container to a non-container will require adding or removing an element from the array of child objects, as well as replacing a piece of markup. At the same time, I would like to avoid a situation where the order of the elements will be violated (for example, such

<row split="1,1,1"><col split="1,1"><1><2></col><3><6></row><4><5>
). Therefore, it may be necessary to completely replace all the numbers in the markup and rebuild the array of objects to ensure the correct order.
2. With extraction and addition, the same problem of breaking the numbering and the need to rebuild occurs.
3. At the moment, I generally save the start and end indexes only for containers (although there is no problem when traversing the markup to save them for elements as well).
4. If you do not do any rebuilding, at least automatically, this will allow the user to move elements within the markup, keeping the document identical on the output (except, perhaps, the order of the layers overlay, but for this it is not a problem to introduce support for z-order, and implement through banal z-index). But right now I'm not so sure about the expediency of having such an opportunity. Given that the user does not see the array of objects on the page in its "real" order, having view markup <4><1><2><3>is a dubious advantage, I don't even know why it might be needed.
5. You can make containers objects - just handle them in a special way in the rendering cycle depending on their type (that is, there will be not 2 types of objects, but 4). This will allow, when changing the type, not to perform any manipulations with the array of child objects - but the problem with the numbering of objects when inserted into the container and removed from the container still remains.
6. You can get rid of numbering altogether, representing all objects as <obj pos="x,y" size="w,h" r="r">. This will immediately remove a lot of problems during development and debugging, and the user will be able to change the contents of the blocks without any buttons by cutting-paste markup fragments. Quite original, although not particularly visual and familiar, as for me.
7. Finally, you can not store markup at all: the parameters that are now stored as attributes can be stored directly in JSON (and so that it does not look "dirty", you can put them in a nested layout object, for example, that is, group them). As for the markup (so that the user can see how many elements he has and what coordinates they have) - you can generate it in general at runtime when loading the current page into the editor.
How would you solve this problem? I do not have much experience in building such serious systems, so I would like to ask for advice.
UPD: in the absence of containers in the system, the markup field would not be needed at all: it would be possible to display objects in a list (traditional or tiles in a special field horizontally in a row), or simply make a button "show all objects on the page" so that they stand out frames. But in the case of containers, and even though they can be nested into each other (in my opinion, this is more convenient than creating a new container in a regular object with dimensions of 100% by 100%) - it would be nice to give the user an understanding of who in whom it is invested. Although, again, you can solve this differently - for example, through a dynamically created path string (like a path in the OS file system, only for containers and objects), or even a small tree in a special field, the elements of which can be clicked.
UPD2: Actually, the whole complexity lies in the fact that I want to make the containers elements of the abstract tree (they can be nested in each other, and the elements must be nested in them), but at the same time I want the objects in my page, to which they belong were stored in a flat list - and even if I make containers objects for code convenience, I don't want to nest ordinary objects in them, removing them from the general list of page objects. It is this problem that a field with markup can solve: objects are stored in a flat array (except for those that have children already inside themselves, but these children are not represented in the current array), and containers are generally stored only in text markup, and they are not in JSON. If you put them in JSON, then it becomes more difficult. Descendants can be "put" into containers by specifying their indices in a flat list, for example. But how to nest containers into each other, again use indexes within a flat list of all containers? How to distinguish between these two types of indexes if they will form a single list? By adding some big number?
UPD3: The very essence of this visual editor is that I have to think a little like a humanist user (in order to understand the needs and requirements, and know what is visual and simple for a person and what is not), and a real user should think a little like a programmer ( to do everything quickly and efficiently, and not get confused in the hierarchy of objects, and also to choose the best implementation path when there are several options - after all, you can sometimes create one layout in 3-4 different ways with different nesting levels of containers and elements). Therefore, on the one hand, I would not like to take the approach that is used in traditional programs of this kind, such as Word, PowerPoint and analogues, when the entire implementation is completely hidden,

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Alexander Popov, 2019-03-10
@popov654

I answer myself: indeed, the easiest way turned out to be to store lists of integers in a separate field for each container. When deleting and adding, you just need to bypass all containers and adjust numbers that are greater than the desired value by one up or down.
In addition, in JS, removing an element from an array is done with one call to splice (), so with the "array rebuilding" I certainly turned down here.
Refused to markup, coordinate data is now stored in a nested layout object.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question