@gjmcn/data-cube-html
v0.2.2
Published
DOM manipulation functions and methods for Data-Cube.
Downloads
10
Readme
DOM manipulation functions and methods for Data-Cube.
The module exports the function qa
. If the module is loaded in a <script>
tag, qa
is a global variable.
See the Data-Cube plugins page for further usage instructions.
Functions
# qa: qa(sel)
Returns an array of elements that match the CSS selector string sel
.
#
create: qa.create(elm, n = 1)
createSVG: qa.createSVG(elm, n = 1)
Create HTML or SVG elements.
elm
specifies the type of element to create, e.g. 'div'
or ['circle','rect']
.
n
specifies how many multiples of the elements in elm
to create. For example, qa.create('div', 2)
creates 2 divs, qa.createSVG(['circle','rect'], 3)
creates 6 elements: circle, rect, circle, rect, circle, rect.
Returns an array containing the new elements.
# fragment: qa.fragment(n = 1)
Returns an array of n
new document fragments.
Array Methods
Unlike standard Data-Cube methods, HTML methods do not convert the calling array to a cube. Also, HTML methods that return a new array, typically return a standard array rather than a cube.
# qa: Array.prototype.qa(sel)
Like the function qa
, but the returned array only includes elements that are descendents of at least one entry of the calling array.
#
insert: Array.prototype.insert(elm, n = 1, posn = 'end')
insertSVG: Array.prototype.insertSVG(elm, n = 1, posn = 'end')
Insert HTML or SVG elements as children of the elements in the calling array.
elm
specifies what to insert:
string: e.g.
'div'
, a new element of this type is created (or multiple elements ifn
is used) and inserted into the corresponding 'target element'.element: is inserted into the target element. If an entry of
elm
is an array of elements, all the elements are inserted into the corresponding target element.function: passed the corresponding entry of the calling array (the target element), the vector index of the entry and the calling array. The function should return an element or an array of elements; these are inserted into the target element.
n
is the number of elements to insert into the target element. n
is only used when elm
is a string.
posn
specifies where an element is to be inserted inside the target element:
'end'
(or omitted,undefined
ornull
): end.'start'
: start.otherwise: before
posn
(in this case,posn
should be a descendent of the target element).
All arguments are broadcast — i.e. each argument can be a singleton or have the same number of entries as the calling array.
Returns an array containing the new elements.
Notes:
insert
need not insert new elements; it can be used to move elements that are already in the document.Since multiple elements can be added to each target element, the vector indices of the target elements and the inserted elements may not correspond.
When
elm
is a function, it makes no difference whetherinsert
orinsertSVG
is called since theelm
function provides the elements to be inserted.
#
encode: Array.prototype.encode(x, r, c, p, i)
encodeSVG: Array.prototype.encodeSVG(x, r, c, p, i)
Encode x
as HTML or SVG. The calling array must contain a single element — into which the new elements are inserted.
x
is encoded hierarchically: rows → columns → pages → inner arrays, according to the arguments r
, c
, p
, i
respectively:
Each of
r
,c
,p
is a tag name or an array of tag names whose number of entries is equal to the length of the dimension ofx
being encoded.i
is a single tag name — i.e. the same tag name is used for all inner arrays.Omit any of
r
,c
,p
,i
(or pass a falsy value) to skip the corresponding dimension.
encode
and encodeSVG
return a 4-entry array with entries corresponding to the arguments r
, c
, p
, i
. Each entry is a cube containing new elements, or null
if the corresponding argument was not used.
Notes:
The returned cubes reflect the structure of
x
. For example, if a matrixm
is encoded as a table:let [trs, tds] = qa('#my-table').encode(m, 'tr', 'td');
trs
is a vector containing a<tr>
element for each row ofm
and with the same row keys and row label asm
(if they exist).tds
is a matrix of<td>
elements with the same shape asm
and the same row and column keys and labels.Omitted dimensions need not appear 'at the end'. The following example creates 4
<g>
elements, each containing a<text>
and a<circle>
:let y = [4, 3, 2].cube(); //4-by-3-by-2 let [gs, , elmts] = qa('#my-svg').encodeSVG(y, 'g', null, ['text', 'circle']);
elmts
has 4 rows, 1 column and 2 pages: the first page contains<text>
elements, the second contains<circle>
elements. (Note that the columns argument (c
) ofencodeSVG
isnull
, soelmts
is given a single column.)Encoding dimensions of length 1 can be useful. The following example creates 3
<p>
elements, each with a<span>
inside:let [ps, spans] = qa('#my-div').encode([6,7,8], 'p', 'span');
ps
andspans
are 3-entry vectors of<p>
and<span>
elements respectively.If inner arrays are encoded, the inner arrays of the result will match those of
x
— i.e. if cubes, they will have the same shape, keys and labels. (Note: if an 'inner array' ofx
is not an array, it is encoded as a single element).
#
expand: Array.prototype.expand(x, r, c, p)
expandSVG: Array.prototype.expandSVG(x, r, c, p)
The expand methods behave like the encode methods except that x
is the shape of a cube rather than an actual cube. For example:
let [trs, tds] = qa('#my-table').expand([4, 2], 'tr', 'td');
returns a vector of 4 tr
elements (trs
) and a 4-by-2 matrix of td
elements (tds
).
Expand methods cannot encode inner arrays. Hence, these methods do not take an i
argument and return a 3-entry array.
# remove: Array.prototype.remove()
Remove elements from the DOM.
Returns the calling array — i.e. the removed elements.
#
raise: Array.prototype.raise()
lower: Array.prototype.lower()
Move elements to be the last child (raise
) or the first child (lower
) of their parents.
Returns the calling array — i.e. the moved elements.
# children: Array.prototype.children()
Children of all entries in the calling array.
Returns a new array.
#
parent: Array.prototype.parent()
firstChild: Array.prototype.firstChild()
lastChild: Array.prototype.lastChild()
Get parent, first child or last child of each entry of the calling array.
Returns a new array.
#
attr: Array.prototype.attr(name)
style: Array.prototype.style(name)
Get attribute/style name
of each entry of the calling array.
Returns a new array.
Note: use the core Data-Cube method prop
to get a property of each element, e.g. x.prop('innerHTML')
.
#
$attr: Array.prototype.$attr(name, val)
$style: Array.prototype.$style(name, val)
For each entry, set attribute/style name
to val
.
val
is broadcast.
Returns the calling array.
Notes:
If
$attr
or$style
throws an error when attempting to set an attribute/style of an entry (e.g. because the entry isundefined
), any already-made changes will persist.Use $prop to set properties of elements, e.g.
x.$prop('innerHTML','hello')
.$attr
and$style
(and$prop
) are setters and hence, trigger updates. Note that update functions belong to an array, not the elements. For example:let paras = qa('p') .$after(() => console.log('paras changed')); paras.$style('color', 'red'); //prints 'paras changed' qa('p').$style('color', 'blue'); //qa('p') has no update functions
#
$$attr: Array.prototype.$$attr(name, f)
$$style: Array.prototype.$$style(name, f)
Set attribute/style name
using the function f
.
x.$$attr(name, f)
sets the attribute name
of each entry xi
to f(xi, x)
.
Note: the new values (the f(xi, x)
) are computed first, then the name
attributes/styles are set using $attr
/$style
.
Returns the calling array.
#
hasAttr: Array.prototype.hasAttr(name)
hasClass: Array.prototype.hasClass(name)
Returns a new array with Boolean entries. An entry is true
if the corresponding entry of the calling array has attribute/class name
.
#
removeAttr: Array.prototype.removeAttr(name)
addClass: Array.prototype.addClass(name)
removeClass: Array.prototype.removeClass(name)
Remove attribute name
, add class name
or remove class name
from each entry of the calling array.
name
is broadcast.
Returns the calling array.
Note: these methods cannot add or remove multiple classes or attributes from an element in a single call. For example, to add classes a
and b
to all elements of an array x
, addClass
must be called twice:
x.addClass('a').addClass('b');
Alternatively, set the class attribute (which removes any existing classes):
x.$attr('class', 'a b');
#
on: Array.prototype.on(type, listener, useCapture = false)
off: Array.prototype.off(type, listener, useCapture = false)
Add (on
) or remove (off
) event listener to each entry of the calling array.
type
is the event type, e.g. 'click'
.
listener
is the function to be called when the event occurs.
useCapture
indicates whether to use capture — see EventTarget.addEventListener for details.
All arguments are broadcast.
Returns the calling array.
Note: on
and off
call the native methods EventTarget.addEventListener and EventTarget.removeEventListener respectively. As with these methods, listener
can be an object implementing the EventListener
interface (rather than a function) and useCapture
can be an options object (rather than a Boolean).
# sketch: Array.prototype.sketch(width = 300, height = 150, scale)
sketch
creates a single canvas element. If the calling array is non-empty, the canvas is inserted into the first entry of the calling array (which should be an HTML element).
If scale
is truthy, the canvas is scaled to avoid blur:
the width and height styles are set to
width + 'px'
andheight + 'px'
respectivelythe width and height attributes are set to
width * devicePixelRatio
andheight * devicePixelRatio
respectivelythe scale of the returned context (see below) is set to
devicePixelRatio
(i.e.ctx.scale(devicePixelRatio, devicePixelRatio)
)
If scale
is falsy, the width and height attributes are set to width
and height
respectively; the width and height styles are not set.
sketch
returns a 2-entry array containing:
the canvas element — as a 1-entry array so that it can use Data-Cube methods
a 2d drawing context (a CanvasRenderingContext2D object)
The drawing context is not wrapped in an array, and can be used in the normal way. However, the context does have an additional (instance-level) loop
method; this is based on the data-cube loop method and enables array-oriented code to be used for drawing on the canvas. For example:
const [canvas, ctx] = qa('body').sketch();
//standard canvas code: 40-by-20 yellow rectangle at x=0, y=0
ctx.fillStyle = 'yellow';
ctx.fillRect(0, 0, 40, 20);
//array-oriented code: 3 rectangles with different colors, x-values and heights
const color = ['red', 'green', 'blue'],
x = [50, 100, 150],
y = 0,
width = 40,
height = [40, 60, 80];
ctx.loop(
['$fillStyle', color], //set fillStyle property
['fillRect', x, y, width, height] //call fillRect method
);
The behavior of loop
is well-suited to the state-based nature of the canvas. In the above example, loop
sets the fillStyle
to 'red'
and draws a rectangle using the first (or only) entries of x
, y
, width
and height
, then sets the fillStyle
to 'green'
and draws a rectangle using the second (or only) entries of x
, y
, width
and height
and so on.
loop
can be passed any number of arguments. To set a property, the first entry of the corresponding argument is the property name prefixed with '$'
(as with '$fillStyle'
in the example). If the first entry of an argument is a function (rather than a string property/method name), it is passed the context as its first argument; the other entries provide the additional arguments.
When called on a context, loop
returns a 1-entry cube containing the context. When called on an array, loop
iterates over entries of the calling array — so loop
can draw different things on different canvases. If the calling array is comprised of a single context, this is broadcast resulting in the same behavior as calling loop
on a context directly.
Event Properties
# me: Event.me
A 1-entry array containing the element that dispatched the event. This is simply Event.target
wrapped in an array so that it can be used with Data-Cube methods, e.g.
//remove a circle when it is clicked
qa('circle').on('click', evt => evt.me.remove());