blob: a99ced432873ae05a75233eceea9afe67f2fe8ea [file] [log] [blame]
<!-- The <canvas-layers-sk> custom element declaration.
This is a utility element that is used around another element, which places
layers of multiple canvas elements directly over it element. Useful for
drawing annotations, crosshairs, etc. over an image or canvas.
The canvas listens for the builtin event "resize" on window, and also for
the custom event "partial-resize" also on window. You can send a
"partial-resize" custom event to window to trigger the canvas layers to check
the size of the image and resize appropriately.
If the subject is an image, this element will also listen for its load event
and resize if the image changes.
Initially sk-canvas-layers tries to find a child img node to use as the subject
but if none is found, you must call changeSubject(element) before it will work.
Attributes:
layers - A JSON serialized array of layer names. There will be one canvas
for each name. Call canvas(name) to get the underlying canvas object.
Note that the order in layers determines the DOM order, with the last
member of layers being the last DOM canvas, which, for example, will
be the only canvas to get 'click' events because it will be on top.
Events:
canvas-update - Triggered when the underlying image has changed.
canvas-layers-updated - Triggered when the templating has finished
and the canvases are in place.
Methods:
canvas(name) - Returns the canvas object for the layer 'name'. See
the layers attribute.
changeSubject(element) - Used to replace the subject element after creation.
Opted for this instead of putting an observer on the subjectId because query
selectors can erroneously match deleted elements.
subject() - return the current subject element.
-->
<link rel="import" href="/res/imp/bower_components/polymer/polymer.html">
<dom-module id="canvas-layers-sk">
<style>
:host {
display: inline-block;
position: relative;
}
canvas {
position: absolute;
top: 0;
left: 0;
}
</style>
<template>
<content></content>
<template is="dom-repeat" items="{{ layers }}" as="layer">
<canvas id$="{{ id }}-{{ layer }}" width=500 height=500>
</template>
</template>
</dom-module>
<script>
Polymer({
is: "canvas-layers-sk",
properties: {
layers: {
type: Array,
value: function() { return []; },
reflectToAttribute: false,
},
},
ready: function() {
// _subject is the element which this stack of layers is drawn on top of.
this._subject = $$$('#img', this);
if (!this._subject) {
// if the subject cannot be identified by the 'img' id, look for any img element.
this._subject = $$$('img', this);
}
this._imageLoadedBound = this._imageLoaded.bind(this);
if (this._subject) {
this._subject.addEventListener('load', this._imageLoadedBound );
}
this.addEventListener('dom-change', this._imageLoadedBound);
this.addEventListener('dom-change', this._domChanged.bind(this));
this._resizing = false;
window.addEventListener('resize', function() {
if (this._resizing == true) {
return;
}
this._resizing = true;
window.requestAnimationFrame(function(){
this._resizing = false;
this._imageLoaded();
}.bind(this));
}.bind(this));
window.addEventListener('partial-resize', function() {
this._imageLoaded();
}.bind(this));
this._imageLoaded();
},
changeSubject(element) {
this._subject = element;
this._domChanged();
},
_domChanged: function() {
this.dispatchEvent(new CustomEvent('canvas-layers-updated', { bubbles: true }));
},
_imageLoaded: function() {
// What I really want here is to know the size of _subject after the #rendered div has decided
// whether or not it will have scrollbars, but to know that I must first make all other
// canvases irrelevant to the overflow of that div's content.
$$('canvas', this).forEach(function(c) {
if (c !== this._subject) {
c.width = 1;
c.height = 1;
}
}.bind(this));
// now, only _subject is affecting the presense of scrollbars on #rendered and
// getComputedStyle is correct.
let strW = window.getComputedStyle(this._subject, null).width;
let strH = window.getComputedStyle(this._subject, null).height;
let detail = {
width: parseFloat(strW.substring(0, strW.length-2)),
height: parseFloat(strH.substring(0, strH.length-2)),
};
$$('canvas', this).forEach(function(c) {
if (c !== this._subject) {
c.width = detail.width;
c.height = detail.height;
c.dispatchEvent(new CustomEvent("canvas-update", { detail: detail, bubbles: true }));
}
}.bind(this));
},
canvas: function(name) {
return $$$("#" + this.id + "-" + name, this);
},
subject: function() {
return this._subject;
},
});
</script>