I want to draw 2D floor plan on html page.
I have a data set looks like below.
Dataset
{
floor:{
"id" : 2,
rooms:[
{
"id" : 21,
"x" : 0.0,
"y" : 0.0,
"height" : 15,
"weight" : 20
}
.
.
.
]
}
}
I want to get a plan similar to the image below
And I want to add tooltip when hover on room.
Is there a library you can remend?
I want to draw 2D floor plan on html page.
I have a data set looks like below.
Dataset
{
floor:{
"id" : 2,
rooms:[
{
"id" : 21,
"x" : 0.0,
"y" : 0.0,
"height" : 15,
"weight" : 20
}
.
.
.
]
}
}
I want to get a plan similar to the image below
And I want to add tooltip when hover on room.
Is there a library you can remend?
Share Improve this question edited May 11, 2020 at 10:01 Aytekin asked May 4, 2020 at 23:47 AytekinAytekin 1771 gold badge1 silver badge15 bronze badges 2-
I don't think you need a library. You can quite easily draw SVG using coords. Another option is drawing on
<canvas>
, but in this case SVG is probably easier. – Robo Robok Commented May 4, 2020 at 23:50 - I would also favor SVG instead of Canvas. It will be easier to create the mouse hovers/popups in the DOM instead of having to create them in canvas. – Albert Skibinski Commented May 14, 2020 at 14:22
4 Answers
Reset to default 8 +25No library needed, draw the SVG shapes yourself, it is worth the investment.
Your main SVG elements are:
RECTangles: https://developer.mozilla/en-US/docs/Web/SVG/Element/rect
Groups: https://developer.mozilla/en-US/docs/Web/SVG/Element/g
Door openings are white rectangles layered on top.
Alternative is use PATHs
- https://developer.mozilla/en-US/docs/Web/SVG/Element/path
My advice: Draw 5 RECTangles first, after that learn PATH notation (drawing the same RECT shape)
Overlays are 'mouseover' EventListeners that show/hide (Group)SVG, just like you show/hide HTML Elements with JavaScript
Start with typing SVG in a JSFiddle or CodePen.
If you use VS-Code, add the SVG Preview extension: https://github./SimonSiefke/vscode-svg-preview
You will have a first draft within an hour.
Note: Your current dataset does not have/show coordinates, so drawing is all up to you.
You'll need more details in your data set. Here's code that produces the image you want... or something like it.
const dataSet = {
floor:{
"id" : 2,
rooms:[
{
"id" : 21,
"x" : 0.0,
"y" : 0.0,
"height" : 15,
"width" : 15,
"weight": 0.4,
"gap": 0.8,
"roomSize": 5,
"corridor": 2
}
]
}
}
const roomData = dataSet.floor.rooms[0]
const { id
, x
, y
, height
, width
, weight
, gap
, roomSize
, corridor
} = roomData
const areaWidth = width - roomSize - 2 * weight
const areaHeight = roomSize - weight
const area = areaWidth * areaHeight
const areas = {
room1: area
, room2: area
, room3: area - weight * areaWidth
, room4: (roomSize - 2* weight) * (roomSize - 2* weight)
}
let html = `<svg
version="1.1"
xmlns="http://www.w3/2000/svg"
viewBox="0 0 ${width} ${height}"
style={style}
>
<path
d="M ${x},${y}
h ${width - roomSize}
v ${height - roomSize}
h ${roomSize}
v ${roomSize}
h -${roomSize + 2 * weight}
v -${weight}
h ${weight}
v -${weight}
h ${weight}
v ${weight}
h ${roomSize - weight}
v -${roomSize - 2 * weight}
h -${roomSize - weight}
v ${roomSize - 3 * weight - gap}
h -${weight}
v -${height - 3 * weight - gap}
h -${width - roomSize - 2 * weight}
v ${roomSize - weight}
h ${width - roomSize - 2 * weight - corridor}
v ${ weight}
h -${width - roomSize - 2 * weight - corridor}
v ${roomSize - weight}
h ${width - roomSize - 2 * weight - corridor}
v ${ weight}
h -${width - roomSize - 2 * weight - corridor}
v ${roomSize - 2 * weight}
h ${width - roomSize - 2 * weight - corridor}
v ${weight}
H 0
z
"
/>
<rect
id="room1"
x="${weight}"
y="${weight}"
width="${width - roomSize - 2 * weight}"
height="${roomSize - weight}"
fill="#fee"
/>
<rect
id="room2"
x="${weight}"
y="${roomSize + weight}"
width="${width - roomSize - 2 * weight}"
height="${roomSize - weight}"
fill="#efe"
/>
<rect
id="room3"
x="${weight}"
y="${roomSize * 2 + weight}"
width="${width - roomSize - 2 * weight}"
height="${roomSize - 2 * weight}"
fill="#eef"
/>
<rect
id="room4"
x="${width - roomSize}"
y="${roomSize * 2 + weight}"
width="${roomSize - weight}"
height="${roomSize - 2 * weight}"
fill="#fef"
/>
</svg>
`
const svg = document.createElement("svg")
svg.innerHTML = html
document.body.appendChild(svg)
const showArea = (event) => {
const id = event.target.id
const area = Math.round(areas[id])
console.log("Area " + area + " square feet")
}
const rooms = [...document.querySelectorAll("rect")]
rooms.forEach(room => {
room.addEventListener("mouseenter", showArea, false)
})
The room area is shown in the Console rather than as an overlay, so you'll have to modify the code to show it as a tooltip.
I think you would need an SVG based solution, because SVGs are efficient when there are user interactions like clicks & mouseovers involved. to ha there are a couple of libraries. I would remend Raphael.js
Its been around for a while, its simple to set up and easy to use. There are also a couple of good starter books that help you learn the whole library in a day. Raphael JS, Raphael JS Starter
I think you can use D3.js, although I don't know if it will be an overkill for your usecase. D3.js is an awesome library to create data-driven documents, i.e when you have some custom data, and you want to use that data to manipulate the HTML DOM elements. It also supports dynamic runtime behaviour and animation.
- An easy quickstart for d3.js is https://www.dashingd3js./svg-basic-shapes-and-d3js.
- Freecodecamp tutorial
- Drawing Rectangle blocks using D3.js - https://bl.ocks/romsson/568e166d702b4a464347 (This example is a bit interactive).
- This example shows how to show Tooltips while creating a document with d3.js https://bl.ocks/d3noob/a22c42db65eb00d4e369