var heatmaps = (function () { "use strict"; var tmpl = new Template(), mustache = new itsMustache(), render = mustache.render; function Heatmaps(target, data) { var events = new EventManager(), containers = {}, ads = [], index = getElementFromString(tmpl.index), closed = false; this.exit = exit; init(); function init() { if (!data.adsList) { // TODO: Do empty ads notice console.error("empty ads list") return; } if (!data.clicks) { data.clicks = []; } data.adsList.forEach(processAd); target.appendChild(index); } function processAd(ad) { var key = ad.data.width + "/" + ad.data.height, container = containers[key]; if (!container) { container = containers[key] = getElementFromString(tmpl.container); container.querySelector("h2").textContent = key; index.appendChild(container); } ads.push(new Ad(events, container, data, ad.id, ad.data)); } function exit() { if (closed) { return; } ads.forEach(function (ad) { ad.exit(); }); events.reset() removeChild(target, index); events = index = null; closed = true; } } function ReportItem(events, db, tgt, id, click, index) { var r = document.createElement("report-item"), ts = document.createElement("row"), uuid = document.createElement("row"), ttc = document.createElement("row"), d = new Date(click.ts * 1000), sk = db.Sub("activeRow", onRowUpdate), closed = false; this.exit = exit; ts.innerHTML = "" + d.toString() + ""; uuid.innerHTML = "UUID: " + click.uuid; ttc.innerHTML = "Time to click: " + click.ttc + " milliseconds"; events.add(r, "click", onClick, id); r.appendChild(ts); r.appendChild(uuid); r.appendChild(ttc); tgt.appendChild(r); function onClick(evt) { db.Put("activeRow", index); } function onRowUpdate(evt) { if (evt !== index) { r.classList.remove("active"); } else { r.classList.add("active"); } } function exit() { if (closed) { return; } db.Unsub("activeRow", sk); removeChild(tgt, r); closed = true; } } function Ad(events, tgt, req, id, data) { var item = getElementFromString(render(tmpl.item, data)), hm = item.querySelector(".heatmap"), img = item.querySelector("img"), rpt = item.querySelector("reporting"), db = psStore(), sk = db.Sub("activeRow", onRowUpdate), clicks = [], reportingItems = [], cm = null, expanded = false, activeRow = -1, closed = false; this.exit = exit; events.add(img, "load", onLoad, id); events.add(img, "error", onError, id); tgt.appendChild(item); function exit() { if (closed) { return; } db.Unsub("activeRow", sk); reportingItems.forEach(function (ri) { ri.exit(); }); events.removeByTag(id); removeChild(tgt, item); if (tgt.childNodes.length <= 1) { removeChild(tgt.parentNode, tgt); } closed = true; } function onLoad(evt) { // Declare ClickMap since our image has loaded cm = ClickMap.New(hm); if (!!req.clicks) { // Only perform this filter if request clicks are not null clicks = req.clicks.filter(isAd); } if (!clicks || clicks.length === 0) { item.classList.add("noClicks"); return; } cm.Load(clicks); clicks.forEach(function (t, i) { reportingItems.push(new ReportItem(events, db, rpt, id, t, i)); }); events.add(hm, "click", onClick, id); } function onError(evt) { console.error("Error!", evt); exit(); } function onClick(evt) { var x = evt.layerX, y = evt.layerY, match = cm.GetMatch(x, y); if (match > -1) { db.Put("activeRow", match); } if (!expanded) { expanded = true; item.style.height = item.getClientRects()[0].height + 300 + "px"; } else if (match === -1) { expanded = false; item.style.height = item.getClientRects()[0].height - 300 + "px"; } } function onRowUpdate(evt) { if (evt === activeRow && evt !== -1) { db.Put("activeRow", -1); return; } cm.SetActive(evt); activeRow = evt; } function isAd(click) { return click.adID === id; } } function Template() { var wh = 'style="height: {{ height }}px; width: {{ width }}px;"', img = '', rpt = '', canvas = ''; this.index = "
"; this.container = "

"; this.item = '' + img + canvas + rpt + ''; } function Exports() { this.Heatmaps = Heatmaps; } return new Exports(); })();