d3-seating-chart
v2.1.0
Published
A simple but pleasant seating chart written using d3js
Downloads
103
Maintainers
Readme
D3 Seating Chart
A simple but pleasant seating chart written using d3js
Setup
Install
npm install d3-seating-chart
Attach to the SVG-
HTML
<svg id="x" width="640" height="480" xmlns="http://www.w3.org/2000/svg"></svg>
JS
import { D3SeatingChart } from './D3SeatingChart';
let d3sc = D3SeatingChart.attach(document.getElementById('x'));
2.1.0
Changes
- added
getClosestSeats
method
2.0.0
Breaking Changes
type="Board"
changed to attributeboard
- add
stage
attribute to stage element type="SeatingArea" name="main"
changed tozoom-control="main"
type="SeatingChartExpose" name="main"
change toseating-area zoom-target="main"
- public methods
getSeatingAreas
,getSeats
removed. useselectElement
, andselectElements
with a dom query selector - this library now implements seat selection logic instead of leaving that up to you
Changes
- added
registerSelectionChangeListener
method - added
select
,deselect
,lock
,unlock
methods - added
allowManualSelection
to config
Try It
Clone this repo. Run webpack -w
SVG Format
There are some rules the svg needs to follow to behave properly. Don't worry about positioning your svg perfectly in the center, this library will zoom/position the board so that it fills the svg dimensions with a margin.
To get the svg seen in the examples, I used http://editor.method.ac/
- Your svg should have a
g
element child with aboard
attribute. All objects that should be affected by transitions should go in here. - Your stage element should have a
stage
attribute. - Seating areas should have a
seating-area
attribute. - Seats should have a
seat
attribute. - Use zoom controls with
zoom-control="{targetName}"
andzoom-target="{targetName}"
<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">
<g board>
<rect stage height="80.38871" width="126.153836" y="206.825647" x="206.459768"/>
<rect zoom-control="right" height="80.175489" width="57.875103" y="205.119891" x="338.511515"/>
<rect zoom-control="main" height="95.687786" width="126.854046" y="105.769235" x="206.180359"/>
<rect zoom-control="left" height="79.962273" width="57.448662" y="205.119891" x="142.930951"/>
<g seating-area zoom-target="left">
<rect selected seat height="14.560438" width="13" y="206.529233" x="158.181482"/>
<rect locked seat height="14.560438" width="13" y="206.529233" x="172.049076"/>
<rect locked="reserved" seat height="14.560438" width="13" y="206.475552" x="185.969085"/>
...
</g>
<g seating-area zoom-target="right">
<rect seat height="14.560438" width="13" y="206.529233" x="354.251359"/>
<rect seat height="14.560438" width="13" y="206.529233" x="368.118954"/>
<rect seat height="14.560438" width="13" y="206.475552" x="382.038963"/>
...
</g>
<g seating-area zoom-target="main">
<rect seat class="reserved" height="14.560438" width="13" y="106.863558" x="207.345423"/>
<rect seat class="locked" height="14.560438" width="13" y="106.863558" x="221.213018"/>
<rect seat height="14.560438" width="13" y="106.809877" x="235.133027"/>
...
</g>
</g>
</svg>
Styling
This package doesn't do any styling. To style elements you should use plain ol' css.
body {
background-color: #1d74aa;
}
svg {
border: 1px solid #000;
}
[stage] {
fill: #000;
}
[zoom-control] {
cursor: pointer;
fill: transparent;
}
[seat] {
fill: #efefef;
}
[seat][locked] {
fill: #888888;
}
[seat][locked="reserved"] {
fill: #00bfff;
}
[seat][selected] {
fill: #ffe100;
}
[seat]:not([selected]):not([locked]):hover {
fill: #ffffff;
cursor: pointer;
}
Public Methods
goToBoard
Returns to the top view of seating areas.
document.getElementById('goToBoard').onclick = function() {
d3sc.goToBoard();
}
select(elementSelector, emitEvents = true)
Selects the given set of seats. Can be given a single element, an array of elements, or a dom query selector.
If the selection contains a seat that is locked
or reserved
and error will be thrown.
If the selected seats actually change, an event will be emitted.
d3sc.select(element1);
d3sc.select([element1, element2]);
d3sc.select('[seat="10"]');
deselect
Deselects the given set of seats. Can be given a single element, an array of elements, or a dom query selector. If the selected seats actually change, an event will be emitted.
d3sc.deselect(element1);
d3sc.deselect([element1, element2]);
d3sc.deselect('[seat="10"]');
deselectAll
Deselects all selected seats.
lock(elementSelector, class = '', emitEvents = true)
Locks the given set of seats. Can be given a single element, an array of elements, or a dom query selector.
If the selection contains seats that are already selected, the will be force locked and a change event will be emitted with the LockOverride
reason.
d3sc.lock(element1);
d3sc.lock([element1, element2]);
d3sc.lock('[seat="10"]');
d3sc.lock(element1, "reserved");
d3sc.lock([element1, element2], "reserved");
d3sc.lock('[seat="10"]', "reserved");
unlockAll(class = '')
Unlocks all locked seats. Given a class, only unlocks seats of that given class. e.g. unlockAll('reserved')
unlock
Unlocks the given set of seats. Can be given a single element, an array of elements, or a dom query selector.
d3sc.unlock(element1);
d3sc.unlock([element1, element2]);
d3sc.unlock('[seat="10"]');
selectElement
Given a dom query selector, returns the first element within the svg that matches the query selector. See d3js select
d3sc.selectElement('[seat="10"]');
selectElements
Given a dom query selector, returns the elements within the svg that matches the query selector. See d3js selectAll
d3sc.selectElements('[seat]');
refresh
Resets the position of items inside the csv. You should use this if the svg itself changes size.
window.onresize = function() {
d3sc.refresh();
}
zoom
Zooms into an element. Makes the element and it's direct children visible. Any element on the board that is not this element or one of it's direct children will be hidden.
d3sc.zoom(d3sc.selectElement('.the-best-chair')); // animates
d3sc.zoom(d3sc.selectElement('.the-best-chair'), false); // does not animate
canGoBack
All non Board zooms are remembered in a history chain. If you are not at the root level (Board) this will return true.
goBack
Will zoom to the last selection in history.
if(d3sc.canGoBack()) {
d3sc.goBack()
}
Config
When attaching D3SeatingChart
to an svg, an optional configuration can be passed in.
D3SeatingChart.attach(element, { ... config ... });
Options
| | Data Type | Default | Description |
|--------------|-----------|-------------------------------|-------------------------------------------------------------------------------------------------------|
| showBehavior | enum | ShowBehavior.DirectDecendants | Changes the show behavior for zooming. Possible values are All
, DirectDecendants
, AllDecendants
|
| allowManualSelection | boolean | true | Implements manual seat selection seen in the demo |
ShowBehavior
Changing the ShowBehavior
changes the elements that are shown/hidden when zoom is called. This does not affect pointer-events
.
import {D3SeatingChart, ShowBehavior, SelectionBehavior} from 'd3-seating-chart';
D3SeatingChart.attach(element, {
showBehavior: ShowBehavior.DirectDecendants,
allowManualSelection: true
});
To hide the seating area you can set it's fill color to transparent
.
[seating-area] {
cursor: pointer;
fill: transparent;
}
ShowAll
AllDecendants
Events
This package is built using d3js
which provides events for svg elements. You can use the selectElement
and selectElements
methods to get the
d3 elements themselves. With those, you can bind events using d3.
Elements that are not direct decendants of the zoomed element will have pointer-events
set to none
.
d3sc.getBoard().on('click', function() {});
d3sc.getElement('#myCustomEvent').on('click', function() {
console.log(this); // the element
});
d3sc.getElements('[seat]').on('click', function() {
console.log(this); // the element
});
However, there are some d3SeatingChart events.
zoom change
Register a callback listener for when the zoom is changed. This method returns an unregister function.
var unreg = d3sc.registerZoomChangeListener(() => {
console.log('should run once');
unreg();
});
d3sc.registerZoomChangeListener(() => {
console.log('should run everytime');
});
selection change
Register a callback listener for when the seat selection is changed. This method return an unregister function.
The SelectChangeEvent
sends the list of selected seats (not just the changes). It also sends the reason for the change.
If select
is used then the reason will be SelectionChanged
. If the selection has changed because a lock
was set,
then the reason will be LockOverride
. This is useful if updating locks/reservations can overwrite the users selection at
runtime- at which point the user should be notified in some way.
import { SelectionChangeEvent, SelectionChangeEventReason } from 'd3-seating-chart';
var unreg = d3sc.registerSelectionChangeListener((e: SelectionChangeEvent) => {
console.log('select evt should run once');
unreg();
});
d3sc.registerSelectionChangeListener((e: SelectionChangeEvent) => {
console.log(e.selection); // All current selections
if(e.reason === SelectionChangeEventReason.SelectionChanged) {
console.log('number of selected seats: ' + e.selection.length)
} else if (e.reason === SelectionChangeEventReason.LockOverride) {
alert('Some of the seats you had selected are now taken.');
}
});
Get Closest Seats
In some cases you may not want to give the user the option to select seats but auto assign them seats closest to the stage. This is used to prevent holes in the audience due to users giving themselves a one seat buffer between their group and others.
This method looks at the seating area in relation to the stage and determines if it's above, right of, below, or left of the stage.
With that it "knows" which seats are closest to the stage and automatically sorts them. This method will always return as many seats
it can match even if the amount of seats it finds does not equal the requested numSeats
. You should account for this in your implementation.
This method allows specifying whether to search for contiguous
seating, where it will attempt to only match adjacent seats. If not
enough adjacent seats are found, and scatterFallback
is set to true
, it will select the closest seats possible and ignore the
contiguous rule. If scatterFallback
is false
in this scenario, an empty array will be returned.
getClosestSeats(seatingArea, numSeats, contiguous = true, scatterFallback = true)
d3sc.select(d3sc.getClosestSeats('left', 3));
d3sc.select(d3sc.getClosestSeats('left', 3))
d3sc.select(d3sc.getClosestSeats('left', 3, false))
d3sc.select(d3sc.getClosestSeats('left', 5))
d3sc.select(d3sc.getClosestSeats('left', 8))